Home | History | Annotate | Download | only in variations
      1 // Copyright 2013 The Chromium Authors. All rights reserved.
      2 // Use of this source code is governed by a BSD-style license that can be
      3 // found in the LICENSE file.
      4 
      5 #include "chrome/browser/metrics/variations/variations_http_header_provider.h"
      6 
      7 #include <string>
      8 
      9 #include "base/base64.h"
     10 #include "base/message_loop/message_loop.h"
     11 #include "base/metrics/field_trial.h"
     12 #include "base/run_loop.h"
     13 #include "chrome/common/metrics/proto/chrome_experiments.pb.h"
     14 #include "components/variations/entropy_provider.h"
     15 #include "components/variations/variations_associated_data.h"
     16 #include "net/http/http_request_headers.h"
     17 #include "testing/gtest/include/gtest/gtest.h"
     18 #include "url/gurl.h"
     19 
     20 namespace chrome_variations {
     21 
     22 namespace {
     23 
     24 // Decodes the variations header and extracts the variation ids.
     25 bool ExtractVariationIds(const std::string& variations,
     26                          std::set<VariationID>* variation_ids,
     27                          std::set<VariationID>* trigger_ids) {
     28   std::string serialized_proto;
     29   if (!base::Base64Decode(variations, &serialized_proto))
     30     return false;
     31   metrics::ChromeVariations proto;
     32   if (!proto.ParseFromString(serialized_proto))
     33     return false;
     34   for (int i = 0; i < proto.variation_id_size(); ++i)
     35     variation_ids->insert(proto.variation_id(i));
     36   for (int i = 0; i < proto.trigger_variation_id_size(); ++i)
     37     trigger_ids->insert(proto.trigger_variation_id(i));
     38   return true;
     39 }
     40 
     41 scoped_refptr<base::FieldTrial> CreateTrialAndAssociateId(
     42     const std::string& trial_name,
     43     const std::string& default_group_name,
     44     IDCollectionKey key,
     45     VariationID id) {
     46   scoped_refptr<base::FieldTrial> trial(
     47       base::FieldTrialList::CreateFieldTrial(trial_name, default_group_name));
     48 
     49   chrome_variations::AssociateGoogleVariationID(key, trial->trial_name(),
     50                                                 trial->group_name(), id);
     51 
     52   return trial;
     53 }
     54 
     55 }  // namespace
     56 
     57 class VariationsHttpHeaderProviderTest : public ::testing::Test {
     58  public:
     59   VariationsHttpHeaderProviderTest() {}
     60 
     61   virtual ~VariationsHttpHeaderProviderTest() {}
     62 
     63   virtual void TearDown() OVERRIDE {
     64     testing::ClearAllVariationIDs();
     65   }
     66 };
     67 
     68 TEST_F(VariationsHttpHeaderProviderTest, ShouldAppendHeaders) {
     69   struct {
     70     const char* url;
     71     bool should_append_headers;
     72   } cases[] = {
     73     { "http://google.com", true },
     74     { "http://www.google.com", true },
     75     { "http://m.google.com", true },
     76     { "http://google.ca", true },
     77     { "https://google.ca", true },
     78     { "http://google.co.uk", true },
     79     { "http://google.co.uk:8080/", true },
     80     { "http://www.google.co.uk:8080/", true },
     81     { "http://google", false },
     82 
     83     { "http://youtube.com", true },
     84     { "http://www.youtube.com", true },
     85     { "http://www.youtube.ca", true },
     86     { "http://www.youtube.co.uk:8080/", true },
     87     { "https://www.youtube.com", true },
     88     { "http://youtube", false },
     89 
     90     { "http://www.yahoo.com", false },
     91 
     92     { "http://ad.doubleclick.net", true },
     93     { "https://a.b.c.doubleclick.net", true },
     94     { "https://a.b.c.doubleclick.net:8081", true },
     95     { "http://www.doubleclick.com", true },
     96     { "http://www.doubleclick.org", false },
     97     { "http://www.doubleclick.net.com", false },
     98     { "https://www.doubleclick.net.com", false },
     99 
    100     { "http://ad.googlesyndication.com", true },
    101     { "https://a.b.c.googlesyndication.com", true },
    102     { "https://a.b.c.googlesyndication.com:8080", true },
    103     { "http://www.doubleclick.edu", false },
    104     { "http://www.googlesyndication.com.edu", false },
    105     { "https://www.googlesyndication.com.com", false },
    106 
    107     { "http://www.googleadservices.com", true },
    108     { "http://www.googleadservices.com:8080", true },
    109     { "https://www.googleadservices.com", true },
    110     { "https://www.internal.googleadservices.com", true },
    111     { "https://www2.googleadservices.com", true },
    112     { "https://www.googleadservices.org", false },
    113     { "https://www.googleadservices.com.co.uk", false },
    114 
    115     { "http://WWW.ANDROID.COM", true },
    116     { "http://www.android.com", true },
    117     { "http://www.doubleclick.com", true },
    118     { "http://www.doubleclick.net", true },
    119     { "http://www.ggpht.com", true },
    120     { "http://www.googleadservices.com", true },
    121     { "http://www.googleapis.com", true },
    122     { "http://www.googlesyndication.com", true },
    123     { "http://www.googleusercontent.com", true },
    124     { "http://www.googlevideo.com", true },
    125     { "http://ssl.gstatic.com", true },
    126     { "http://www.gstatic.com", true },
    127     { "http://www.ytimg.com", true },
    128     { "http://wwwytimg.com", false },
    129     { "http://ytimg.com", false },
    130 
    131     { "http://www.android.org", false },
    132     { "http://www.doubleclick.org", false },
    133     { "http://www.doubleclick.net", true },
    134     { "http://www.ggpht.org", false },
    135     { "http://www.googleadservices.org", false },
    136     { "http://www.googleapis.org", false },
    137     { "http://www.googlesyndication.org", false },
    138     { "http://www.googleusercontent.org", false },
    139     { "http://www.googlevideo.org", false },
    140     { "http://ssl.gstatic.org", false },
    141     { "http://www.gstatic.org", false },
    142     { "http://www.ytimg.org", false },
    143 
    144     { "http://a.b.android.com", true },
    145     { "http://a.b.doubleclick.com", true },
    146     { "http://a.b.doubleclick.net", true },
    147     { "http://a.b.ggpht.com", true },
    148     { "http://a.b.googleadservices.com", true },
    149     { "http://a.b.googleapis.com", true },
    150     { "http://a.b.googlesyndication.com", true },
    151     { "http://a.b.googleusercontent.com", true },
    152     { "http://a.b.googlevideo.com", true },
    153     { "http://ssl.gstatic.com", true },
    154     { "http://a.b.gstatic.com", true },
    155     { "http://a.b.ytimg.com", true },
    156 
    157   };
    158 
    159   for (size_t i = 0; i < ARRAYSIZE_UNSAFE(cases); ++i) {
    160     const GURL url(cases[i].url);
    161     EXPECT_EQ(cases[i].should_append_headers,
    162               VariationsHttpHeaderProvider::ShouldAppendHeaders(url)) << url;
    163   }
    164 }
    165 
    166 TEST_F(VariationsHttpHeaderProviderTest, SetDefaultVariationIds_Valid) {
    167   base::MessageLoop loop;
    168   VariationsHttpHeaderProvider provider;
    169   GURL url("http://www.google.com");
    170   net::HttpRequestHeaders headers;
    171   std::string variations;
    172 
    173   // Valid experiment ids.
    174   EXPECT_TRUE(provider.SetDefaultVariationIds("12,456,t789"));
    175   provider.InitVariationIDsCacheIfNeeded();
    176   provider.AppendHeaders(url, false, false, &headers);
    177   EXPECT_TRUE(headers.HasHeader("X-Client-Data"));
    178   headers.GetHeader("X-Client-Data", &variations);
    179   std::set<VariationID> variation_ids;
    180   std::set<VariationID> trigger_ids;
    181   ASSERT_TRUE(ExtractVariationIds(variations, &variation_ids, &trigger_ids));
    182   EXPECT_TRUE(variation_ids.find(12) != variation_ids.end());
    183   EXPECT_TRUE(variation_ids.find(456) != variation_ids.end());
    184   EXPECT_TRUE(trigger_ids.find(789) != trigger_ids.end());
    185   EXPECT_FALSE(variation_ids.find(789) != variation_ids.end());
    186 }
    187 
    188 TEST_F(VariationsHttpHeaderProviderTest, SetDefaultVariationIds_Invalid) {
    189   base::MessageLoop loop;
    190   VariationsHttpHeaderProvider provider;
    191   GURL url("http://www.google.com");
    192   net::HttpRequestHeaders headers;
    193 
    194   // Invalid experiment ids.
    195   EXPECT_FALSE(provider.SetDefaultVariationIds("abcd12,456"));
    196   provider.InitVariationIDsCacheIfNeeded();
    197   provider.AppendHeaders(url, false, false, &headers);
    198   EXPECT_FALSE(headers.HasHeader("X-Client-Data"));
    199 
    200   // Invalid trigger experiment id
    201   EXPECT_FALSE(provider.SetDefaultVariationIds("12,tabc456"));
    202   provider.InitVariationIDsCacheIfNeeded();
    203   provider.AppendHeaders(url, false, false, &headers);
    204   EXPECT_FALSE(headers.HasHeader("X-Client-Data"));
    205 }
    206 
    207 TEST_F(VariationsHttpHeaderProviderTest, OnFieldTrialGroupFinalized) {
    208   base::MessageLoop loop;
    209   base::FieldTrialList field_trial_list(
    210       new metrics::SHA1EntropyProvider("test"));
    211   VariationsHttpHeaderProvider provider;
    212   provider.InitVariationIDsCacheIfNeeded();
    213 
    214   const std::string default_name = "default";
    215   scoped_refptr<base::FieldTrial> trial_1(CreateTrialAndAssociateId(
    216       "t1", default_name, GOOGLE_WEB_PROPERTIES, 123));
    217 
    218   ASSERT_EQ(default_name, trial_1->group_name());
    219 
    220   scoped_refptr<base::FieldTrial> trial_2(CreateTrialAndAssociateId(
    221       "t2", default_name, GOOGLE_WEB_PROPERTIES_TRIGGER, 456));
    222 
    223   ASSERT_EQ(default_name, trial_2->group_name());
    224 
    225   // Run the message loop to make sure OnFieldTrialGroupFinalized is called for
    226   // the two field trials.
    227   base::RunLoop().RunUntilIdle();
    228 
    229   GURL url("http://www.google.com");
    230   net::HttpRequestHeaders headers;
    231   provider.AppendHeaders(url, false, false, &headers);
    232   std::string variations;
    233   headers.GetHeader("X-Client-Data", &variations);
    234 
    235   std::set<VariationID> variation_ids;
    236   std::set<VariationID> trigger_ids;
    237   ASSERT_TRUE(ExtractVariationIds(variations, &variation_ids, &trigger_ids));
    238   EXPECT_TRUE(variation_ids.find(123) != variation_ids.end());
    239   EXPECT_TRUE(trigger_ids.find(456) != trigger_ids.end());
    240 }
    241 
    242 }  // namespace chrome_variations
    243