Home | History | Annotate | Download | only in variations
      1 // Copyright (c) 2012 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_service.h"
      6 
      7 #include <vector>
      8 
      9 #include "base/base64.h"
     10 #include "base/prefs/testing_pref_service.h"
     11 #include "base/sha1.h"
     12 #include "base/strings/string_number_conversions.h"
     13 #include "base/strings/string_util.h"
     14 #include "chrome/browser/web_resource/resource_request_allowed_notifier_test_util.h"
     15 #include "chrome/common/pref_names.h"
     16 #include "chrome/test/base/testing_browser_process.h"
     17 #include "chrome/test/base/testing_pref_service_syncable.h"
     18 #include "components/variations/proto/study.pb.h"
     19 #include "components/variations/proto/variations_seed.pb.h"
     20 #include "content/public/test/test_browser_thread.h"
     21 #include "net/base/url_util.h"
     22 #include "net/http/http_response_headers.h"
     23 #include "net/http/http_status_code.h"
     24 #include "net/url_request/test_url_fetcher_factory.h"
     25 #include "testing/gtest/include/gtest/gtest.h"
     26 
     27 #if defined(OS_CHROMEOS)
     28 #include "chrome/browser/chromeos/settings/cros_settings.h"
     29 #include "chrome/browser/chromeos/settings/device_settings_service.h"
     30 #include "chrome/browser/chromeos/settings/stub_cros_settings_provider.h"
     31 #endif
     32 
     33 namespace chrome_variations {
     34 
     35 namespace {
     36 
     37 // A test class used to validate expected functionality in VariationsService.
     38 class TestVariationsService : public VariationsService {
     39  public:
     40   TestVariationsService(TestRequestAllowedNotifier* test_notifier,
     41                         PrefService* local_state)
     42       : VariationsService(test_notifier, local_state, NULL),
     43         intercepts_fetch_(true),
     44         fetch_attempted_(false),
     45         seed_stored_(false) {
     46     // Set this so StartRepeatedVariationsSeedFetch can be called in tests.
     47     SetCreateTrialsFromSeedCalledForTesting(true);
     48   }
     49 
     50   virtual ~TestVariationsService() {
     51   }
     52 
     53   void set_intercepts_fetch(bool value) {
     54     intercepts_fetch_ = value;
     55   }
     56 
     57   bool fetch_attempted() const { return fetch_attempted_; }
     58 
     59   bool seed_stored() const { return seed_stored_; }
     60 
     61   virtual void DoActualFetch() OVERRIDE {
     62     if (intercepts_fetch_) {
     63       fetch_attempted_ = true;
     64       return;
     65     }
     66 
     67     VariationsService::DoActualFetch();
     68   }
     69 
     70  protected:
     71   virtual void StoreSeed(const std::string& seed_data,
     72                          const std::string& seed_signature,
     73                          const base::Time& date_fetched) OVERRIDE {
     74     seed_stored_ = true;
     75   }
     76 
     77  private:
     78   bool intercepts_fetch_;
     79   bool fetch_attempted_;
     80   bool seed_stored_;
     81 
     82   DISALLOW_COPY_AND_ASSIGN(TestVariationsService);
     83 };
     84 
     85 // Populates |seed| with simple test data. The resulting seed will contain one
     86 // study called "test", which contains one experiment called "abc" with
     87 // probability weight 100. |seed|'s study field will be cleared before adding
     88 // the new study.
     89 VariationsSeed CreateTestSeed() {
     90   VariationsSeed seed;
     91   Study* study = seed.add_study();
     92   study->set_name("test");
     93   study->set_default_experiment_name("abc");
     94   Study_Experiment* experiment = study->add_experiment();
     95   experiment->set_name("abc");
     96   experiment->set_probability_weight(100);
     97   seed.set_serial_number("123");
     98   return seed;
     99 }
    100 
    101 // Serializes |seed| to protobuf binary format.
    102 std::string SerializeSeed(const VariationsSeed& seed) {
    103   std::string serialized_seed;
    104   seed.SerializeToString(&serialized_seed);
    105   return serialized_seed;
    106 }
    107 
    108 // Simulates a variations service response by setting a date header and the
    109 // specified HTTP |response_code| on |fetcher|.
    110 void SimulateServerResponse(int response_code, net::TestURLFetcher* fetcher) {
    111   ASSERT_TRUE(fetcher);
    112   scoped_refptr<net::HttpResponseHeaders> headers(
    113       new net::HttpResponseHeaders("date:Wed, 13 Feb 2013 00:25:24 GMT\0\0"));
    114   fetcher->set_response_headers(headers);
    115   fetcher->set_response_code(response_code);
    116 }
    117 
    118 }  // namespace
    119 
    120 class VariationsServiceTest : public ::testing::Test {
    121  protected:
    122   VariationsServiceTest() {}
    123 
    124  private:
    125 #if defined(OS_CHROMEOS)
    126   // Not used directly. Initializes CrosSettings for testing.
    127   chromeos::ScopedTestDeviceSettingsService test_device_settings_service_;
    128   chromeos::ScopedTestCrosSettings test_cros_settings_;
    129 #endif
    130 
    131   DISALLOW_COPY_AND_ASSIGN(VariationsServiceTest);
    132 };
    133 
    134 #if !defined(OS_CHROMEOS)
    135 TEST_F(VariationsServiceTest, VariationsURLIsValid) {
    136 #if defined(OS_ANDROID)
    137   // Android uses profile prefs as the PrefService to generate the URL.
    138   TestingPrefServiceSyncable prefs;
    139   VariationsService::RegisterProfilePrefs(prefs.registry());
    140 #else
    141   TestingPrefServiceSimple prefs;
    142   VariationsService::RegisterPrefs(prefs.registry());
    143 #endif
    144   const std::string default_variations_url =
    145       VariationsService::GetDefaultVariationsServerURLForTesting();
    146 
    147   std::string value;
    148   GURL url = VariationsService::GetVariationsServerURL(&prefs);
    149   EXPECT_TRUE(StartsWithASCII(url.spec(), default_variations_url, true));
    150   EXPECT_FALSE(net::GetValueForKeyInQuery(url, "restrict", &value));
    151 
    152   prefs.SetString(prefs::kVariationsRestrictParameter, "restricted");
    153   url = VariationsService::GetVariationsServerURL(&prefs);
    154   EXPECT_TRUE(StartsWithASCII(url.spec(), default_variations_url, true));
    155   EXPECT_TRUE(net::GetValueForKeyInQuery(url, "restrict", &value));
    156   EXPECT_EQ("restricted", value);
    157 }
    158 #else
    159 class VariationsServiceTestChromeOS : public VariationsServiceTest {
    160  protected:
    161   VariationsServiceTestChromeOS() {}
    162 
    163   virtual void SetUp() OVERRIDE {
    164     cros_settings_ = chromeos::CrosSettings::Get();
    165     DCHECK(cros_settings_ != NULL);
    166     // Remove the real DeviceSettingsProvider and replace it with a stub that
    167     // allows modifications in a test.
    168     device_settings_provider_ = cros_settings_->GetProvider(
    169         chromeos::kReportDeviceVersionInfo);
    170     EXPECT_TRUE(device_settings_provider_ != NULL);
    171     EXPECT_TRUE(cros_settings_->RemoveSettingsProvider(
    172         device_settings_provider_));
    173     cros_settings_->AddSettingsProvider(&stub_settings_provider_);
    174   }
    175 
    176   virtual void TearDown() OVERRIDE {
    177     // Restore the real DeviceSettingsProvider.
    178     EXPECT_TRUE(
    179         cros_settings_->RemoveSettingsProvider(&stub_settings_provider_));
    180     cros_settings_->AddSettingsProvider(device_settings_provider_);
    181   }
    182 
    183   void SetVariationsRestrictParameterPolicyValue(std::string value) {
    184     cros_settings_->SetString(chromeos::kVariationsRestrictParameter, value);
    185   }
    186 
    187  private:
    188   chromeos::CrosSettings* cros_settings_;
    189   chromeos::StubCrosSettingsProvider stub_settings_provider_;
    190   chromeos::CrosSettingsProvider* device_settings_provider_;
    191 
    192   DISALLOW_COPY_AND_ASSIGN(VariationsServiceTestChromeOS);
    193 };
    194 
    195 TEST_F(VariationsServiceTestChromeOS, VariationsURLIsValid) {
    196   TestingPrefServiceSimple prefs;
    197   VariationsService::RegisterPrefs(prefs.registry());
    198   const std::string default_variations_url =
    199       VariationsService::GetDefaultVariationsServerURLForTesting();
    200 
    201   std::string value;
    202   GURL url = VariationsService::GetVariationsServerURL(&prefs);
    203   EXPECT_TRUE(StartsWithASCII(url.spec(), default_variations_url, true));
    204   EXPECT_FALSE(net::GetValueForKeyInQuery(url, "restrict", &value));
    205 
    206   SetVariationsRestrictParameterPolicyValue("restricted");
    207   url = VariationsService::GetVariationsServerURL(&prefs);
    208   EXPECT_TRUE(StartsWithASCII(url.spec(), default_variations_url, true));
    209   EXPECT_TRUE(net::GetValueForKeyInQuery(url, "restrict", &value));
    210   EXPECT_EQ("restricted", value);
    211 }
    212 #endif
    213 
    214 TEST_F(VariationsServiceTest, VariationsURLHasOSNameParam) {
    215   TestingPrefServiceSimple prefs;
    216   VariationsService::RegisterPrefs(prefs.registry());
    217   const GURL url = VariationsService::GetVariationsServerURL(&prefs);
    218 
    219   std::string value;
    220   EXPECT_TRUE(net::GetValueForKeyInQuery(url, "osname", &value));
    221   EXPECT_FALSE(value.empty());
    222 }
    223 
    224 TEST_F(VariationsServiceTest, RequestsInitiallyNotAllowed) {
    225   base::MessageLoopForUI message_loop;
    226   content::TestBrowserThread ui_thread(content::BrowserThread::UI,
    227                                        &message_loop);
    228   TestingPrefServiceSimple prefs;
    229   VariationsService::RegisterPrefs(prefs.registry());
    230 
    231   // Pass ownership to TestVariationsService, but keep a weak pointer to
    232   // manipulate it for this test.
    233   TestRequestAllowedNotifier* test_notifier = new TestRequestAllowedNotifier;
    234   TestVariationsService test_service(test_notifier, &prefs);
    235 
    236   // Force the notifier to initially disallow requests.
    237   test_notifier->SetRequestsAllowedOverride(false);
    238   test_service.StartRepeatedVariationsSeedFetch();
    239   EXPECT_FALSE(test_service.fetch_attempted());
    240 
    241   test_notifier->NotifyObserver();
    242   EXPECT_TRUE(test_service.fetch_attempted());
    243 }
    244 
    245 TEST_F(VariationsServiceTest, RequestsInitiallyAllowed) {
    246   base::MessageLoopForUI message_loop;
    247   content::TestBrowserThread ui_thread(content::BrowserThread::UI,
    248                                        &message_loop);
    249   TestingPrefServiceSimple prefs;
    250   VariationsService::RegisterPrefs(prefs.registry());
    251 
    252   // Pass ownership to TestVariationsService, but keep a weak pointer to
    253   // manipulate it for this test.
    254   TestRequestAllowedNotifier* test_notifier = new TestRequestAllowedNotifier;
    255   TestVariationsService test_service(test_notifier, &prefs);
    256 
    257   test_notifier->SetRequestsAllowedOverride(true);
    258   test_service.StartRepeatedVariationsSeedFetch();
    259   EXPECT_TRUE(test_service.fetch_attempted());
    260 }
    261 
    262 TEST_F(VariationsServiceTest, SeedStoredWhenOKStatus) {
    263   base::MessageLoop message_loop;
    264   content::TestBrowserThread io_thread(content::BrowserThread::IO,
    265                                        &message_loop);
    266   TestingPrefServiceSimple prefs;
    267   VariationsService::RegisterPrefs(prefs.registry());
    268 
    269   TestVariationsService service(new TestRequestAllowedNotifier, &prefs);
    270   service.set_intercepts_fetch(false);
    271 
    272   net::TestURLFetcherFactory factory;
    273   service.DoActualFetch();
    274 
    275   net::TestURLFetcher* fetcher = factory.GetFetcherByID(0);
    276   SimulateServerResponse(net::HTTP_OK, fetcher);
    277   fetcher->SetResponseString(SerializeSeed(CreateTestSeed()));
    278 
    279   EXPECT_FALSE(service.seed_stored());
    280   service.OnURLFetchComplete(fetcher);
    281   EXPECT_TRUE(service.seed_stored());
    282 }
    283 
    284 TEST_F(VariationsServiceTest, SeedNotStoredWhenNonOKStatus) {
    285   const int non_ok_status_codes[] = {
    286     net::HTTP_NO_CONTENT,
    287     net::HTTP_NOT_MODIFIED,
    288     net::HTTP_NOT_FOUND,
    289     net::HTTP_INTERNAL_SERVER_ERROR,
    290     net::HTTP_SERVICE_UNAVAILABLE,
    291   };
    292 
    293   base::MessageLoop message_loop;
    294   content::TestBrowserThread io_thread(content::BrowserThread::IO,
    295                                        &message_loop);
    296   TestingPrefServiceSimple prefs;
    297   VariationsService::RegisterPrefs(prefs.registry());
    298 
    299   VariationsService service(new TestRequestAllowedNotifier, &prefs, NULL);
    300   for (size_t i = 0; i < arraysize(non_ok_status_codes); ++i) {
    301     net::TestURLFetcherFactory factory;
    302     service.DoActualFetch();
    303     EXPECT_TRUE(prefs.FindPreference(prefs::kVariationsSeed)->IsDefaultValue());
    304 
    305     net::TestURLFetcher* fetcher = factory.GetFetcherByID(0);
    306     SimulateServerResponse(non_ok_status_codes[i], fetcher);
    307     service.OnURLFetchComplete(fetcher);
    308 
    309     EXPECT_TRUE(prefs.FindPreference(prefs::kVariationsSeed)->IsDefaultValue());
    310   }
    311 }
    312 
    313 TEST_F(VariationsServiceTest, SeedDateUpdatedOn304Status) {
    314   base::MessageLoop message_loop;
    315   content::TestBrowserThread io_thread(content::BrowserThread::IO,
    316                                        &message_loop);
    317   TestingPrefServiceSimple prefs;
    318   VariationsService::RegisterPrefs(prefs.registry());
    319 
    320   VariationsService service(new TestRequestAllowedNotifier, &prefs, NULL);
    321   net::TestURLFetcherFactory factory;
    322   service.DoActualFetch();
    323   EXPECT_TRUE(
    324       prefs.FindPreference(prefs::kVariationsSeedDate)->IsDefaultValue());
    325 
    326   net::TestURLFetcher* fetcher = factory.GetFetcherByID(0);
    327   SimulateServerResponse(net::HTTP_NOT_MODIFIED, fetcher);
    328   service.OnURLFetchComplete(fetcher);
    329   EXPECT_FALSE(
    330       prefs.FindPreference(prefs::kVariationsSeedDate)->IsDefaultValue());
    331 }
    332 
    333 }  // namespace chrome_variations
    334