• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 "components/variations/proto/study.pb.h"
18 #include "components/variations/proto/variations_seed.pb.h"
19 #include "content/public/test/test_browser_thread.h"
20 #include "net/base/url_util.h"
21 #include "net/http/http_response_headers.h"
22 #include "net/http/http_status_code.h"
23 #include "net/url_request/test_url_fetcher_factory.h"
24 #include "testing/gtest/include/gtest/gtest.h"
25 
26 #if defined(OS_CHROMEOS)
27 #include "chrome/browser/chromeos/settings/cros_settings.h"
28 #include "chrome/browser/chromeos/settings/device_settings_service.h"
29 #include "chrome/browser/chromeos/settings/stub_cros_settings_provider.h"
30 #endif
31 
32 namespace chrome_variations {
33 
34 namespace {
35 
36 // A test class used to validate expected functionality in VariationsService.
37 class TestVariationsService : public VariationsService {
38  public:
TestVariationsService(TestRequestAllowedNotifier * test_notifier,PrefService * local_state)39   TestVariationsService(TestRequestAllowedNotifier* test_notifier,
40                         PrefService* local_state)
41       : VariationsService(test_notifier, local_state),
42         fetch_attempted_(false) {
43     // Set this so StartRepeatedVariationsSeedFetch can be called in tests.
44     SetCreateTrialsFromSeedCalledForTesting(true);
45   }
46 
~TestVariationsService()47   virtual ~TestVariationsService() {
48   }
49 
fetch_attempted() const50   bool fetch_attempted() const { return fetch_attempted_; }
51 
52  protected:
DoActualFetch()53   virtual void DoActualFetch() OVERRIDE {
54     fetch_attempted_ = true;
55   }
56 
57  private:
58   bool fetch_attempted_;
59 
60   DISALLOW_COPY_AND_ASSIGN(TestVariationsService);
61 };
62 
63 // Populates |seed| with simple test data. The resulting seed will contain one
64 // study called "test", which contains one experiment called "abc" with
65 // probability weight 100. |seed|'s study field will be cleared before adding
66 // the new study.
CreateTestSeed()67 VariationsSeed CreateTestSeed() {
68   VariationsSeed seed;
69   Study* study = seed.add_study();
70   study->set_name("test");
71   study->set_default_experiment_name("abc");
72   Study_Experiment* experiment = study->add_experiment();
73   experiment->set_name("abc");
74   experiment->set_probability_weight(100);
75   seed.set_serial_number("123");
76   return seed;
77 }
78 
79 // Serializes |seed| to protobuf binary format.
SerializeSeed(const VariationsSeed & seed)80 std::string SerializeSeed(const VariationsSeed& seed) {
81   std::string serialized_seed;
82   seed.SerializeToString(&serialized_seed);
83   return serialized_seed;
84 }
85 
86 // Serializes |seed| to base64-encoded protobuf binary format.
SerializeSeedBase64(const VariationsSeed & seed,std::string * hash)87 std::string SerializeSeedBase64(const VariationsSeed& seed, std::string* hash) {
88   std::string serialized_seed = SerializeSeed(seed);
89   if (hash != NULL) {
90     std::string sha1 = base::SHA1HashString(serialized_seed);
91     *hash = base::HexEncode(sha1.data(), sha1.size());
92   }
93   std::string base64_serialized_seed;
94   base::Base64Encode(serialized_seed, &base64_serialized_seed);
95   return base64_serialized_seed;
96 }
97 
98 // Simulates a variations service response by setting a date header and the
99 // specified HTTP |response_code| on |fetcher|.
SimulateServerResponse(int response_code,net::TestURLFetcher * fetcher)100 void SimulateServerResponse(int response_code, net::TestURLFetcher* fetcher) {
101   ASSERT_TRUE(fetcher);
102   scoped_refptr<net::HttpResponseHeaders> headers(
103       new net::HttpResponseHeaders("date:Wed, 13 Feb 2013 00:25:24 GMT\0\0"));
104   fetcher->set_response_headers(headers);
105   fetcher->set_response_code(response_code);
106 }
107 
108 }  // namespace
109 
110 class VariationsServiceTest : public ::testing::Test {
111  protected:
VariationsServiceTest()112   VariationsServiceTest() {}
113 
114  private:
115 #if defined(OS_CHROMEOS)
116   // Not used directly. Initializes CrosSettings for testing.
117   chromeos::ScopedTestDeviceSettingsService test_device_settings_service_;
118   chromeos::ScopedTestCrosSettings test_cros_settings_;
119 #endif
120 
121   DISALLOW_COPY_AND_ASSIGN(VariationsServiceTest);
122 };
123 
124 #if !defined(OS_CHROMEOS)
TEST_F(VariationsServiceTest,VariationsURLIsValid)125 TEST_F(VariationsServiceTest, VariationsURLIsValid) {
126   TestingPrefServiceSimple prefs;
127   VariationsService::RegisterPrefs(prefs.registry());
128   const std::string default_variations_url =
129       VariationsService::GetDefaultVariationsServerURLForTesting();
130 
131   std::string value;
132   GURL url = VariationsService::GetVariationsServerURL(&prefs);
133   EXPECT_TRUE(StartsWithASCII(url.spec(), default_variations_url, true));
134   EXPECT_FALSE(net::GetValueForKeyInQuery(url, "restrict", &value));
135 
136   prefs.SetString(prefs::kVariationsRestrictParameter, "restricted");
137   url = VariationsService::GetVariationsServerURL(&prefs);
138   EXPECT_TRUE(StartsWithASCII(url.spec(), default_variations_url, true));
139   EXPECT_TRUE(net::GetValueForKeyInQuery(url, "restrict", &value));
140   EXPECT_EQ("restricted", value);
141 }
142 #else
143 class VariationsServiceTestChromeOS : public VariationsServiceTest {
144  protected:
VariationsServiceTestChromeOS()145   VariationsServiceTestChromeOS() {}
146 
SetUp()147   virtual void SetUp() OVERRIDE {
148     cros_settings_ = chromeos::CrosSettings::Get();
149     DCHECK(cros_settings_ != NULL);
150     // Remove the real DeviceSettingsProvider and replace it with a stub that
151     // allows modifications in a test.
152     device_settings_provider_ = cros_settings_->GetProvider(
153         chromeos::kReportDeviceVersionInfo);
154     EXPECT_TRUE(device_settings_provider_ != NULL);
155     EXPECT_TRUE(cros_settings_->RemoveSettingsProvider(
156         device_settings_provider_));
157     cros_settings_->AddSettingsProvider(&stub_settings_provider_);
158   }
159 
TearDown()160   virtual void TearDown() OVERRIDE {
161     // Restore the real DeviceSettingsProvider.
162     EXPECT_TRUE(
163         cros_settings_->RemoveSettingsProvider(&stub_settings_provider_));
164     cros_settings_->AddSettingsProvider(device_settings_provider_);
165   }
166 
SetVariationsRestrictParameterPolicyValue(std::string value)167   void SetVariationsRestrictParameterPolicyValue(std::string value) {
168     cros_settings_->SetString(chromeos::kVariationsRestrictParameter, value);
169   }
170 
171  private:
172   chromeos::CrosSettings* cros_settings_;
173   chromeos::StubCrosSettingsProvider stub_settings_provider_;
174   chromeos::CrosSettingsProvider* device_settings_provider_;
175 
176   DISALLOW_COPY_AND_ASSIGN(VariationsServiceTestChromeOS);
177 };
178 
TEST_F(VariationsServiceTestChromeOS,VariationsURLIsValid)179 TEST_F(VariationsServiceTestChromeOS, VariationsURLIsValid) {
180   TestingPrefServiceSimple prefs;
181   VariationsService::RegisterPrefs(prefs.registry());
182   const std::string default_variations_url =
183       VariationsService::GetDefaultVariationsServerURLForTesting();
184 
185   std::string value;
186   GURL url = VariationsService::GetVariationsServerURL(&prefs);
187   EXPECT_TRUE(StartsWithASCII(url.spec(), default_variations_url, true));
188   EXPECT_FALSE(net::GetValueForKeyInQuery(url, "restrict", &value));
189 
190   SetVariationsRestrictParameterPolicyValue("restricted");
191   url = VariationsService::GetVariationsServerURL(&prefs);
192   EXPECT_TRUE(StartsWithASCII(url.spec(), default_variations_url, true));
193   EXPECT_TRUE(net::GetValueForKeyInQuery(url, "restrict", &value));
194   EXPECT_EQ("restricted", value);
195 }
196 #endif
197 
TEST_F(VariationsServiceTest,VariationsURLHasOSNameParam)198 TEST_F(VariationsServiceTest, VariationsURLHasOSNameParam) {
199   TestingPrefServiceSimple prefs;
200   VariationsService::RegisterPrefs(prefs.registry());
201   const GURL url = VariationsService::GetVariationsServerURL(&prefs);
202 
203   std::string value;
204   EXPECT_TRUE(net::GetValueForKeyInQuery(url, "osname", &value));
205   EXPECT_FALSE(value.empty());
206 }
207 
TEST_F(VariationsServiceTest,LoadSeed)208 TEST_F(VariationsServiceTest, LoadSeed) {
209   // Store good seed data to test if loading from prefs works.
210   const VariationsSeed seed = CreateTestSeed();
211   std::string seed_hash;
212   const std::string base64_seed = SerializeSeedBase64(seed, &seed_hash);
213 
214   TestingPrefServiceSimple prefs;
215   VariationsService::RegisterPrefs(prefs.registry());
216   prefs.SetString(prefs::kVariationsSeed, base64_seed);
217 
218   TestVariationsService variations_service(new TestRequestAllowedNotifier,
219                                            &prefs);
220   VariationsSeed loaded_seed;
221   // Check that loading a seed without a hash pref set works correctly.
222   EXPECT_TRUE(variations_service.LoadVariationsSeedFromPref(&loaded_seed));
223 
224   // Check that the loaded data is the same as the original.
225   EXPECT_EQ(SerializeSeed(seed), SerializeSeed(loaded_seed));
226   // Make sure the pref hasn't been changed.
227   EXPECT_FALSE(prefs.FindPreference(prefs::kVariationsSeed)->IsDefaultValue());
228   EXPECT_EQ(base64_seed, prefs.GetString(prefs::kVariationsSeed));
229 
230   // Check that loading a seed with the correct hash works.
231   prefs.SetString(prefs::kVariationsSeedHash, seed_hash);
232   loaded_seed.Clear();
233   EXPECT_TRUE(variations_service.LoadVariationsSeedFromPref(&loaded_seed));
234   EXPECT_EQ(SerializeSeed(seed), SerializeSeed(loaded_seed));
235 
236   // Check that false is returned and the pref is cleared when hash differs.
237   VariationsSeed different_seed = seed;
238   different_seed.mutable_study(0)->set_name("octopus");
239   std::string different_hash;
240   prefs.SetString(prefs::kVariationsSeed,
241                   SerializeSeedBase64(different_seed, &different_hash));
242   ASSERT_NE(different_hash, prefs.GetString(prefs::kVariationsSeedHash));
243   EXPECT_FALSE(prefs.FindPreference(prefs::kVariationsSeed)->IsDefaultValue());
244   EXPECT_FALSE(variations_service.LoadVariationsSeedFromPref(&loaded_seed));
245   EXPECT_TRUE(prefs.FindPreference(prefs::kVariationsSeed)->IsDefaultValue());
246   EXPECT_TRUE(
247       prefs.FindPreference(prefs::kVariationsSeedDate)->IsDefaultValue());
248   EXPECT_TRUE(
249       prefs.FindPreference(prefs::kVariationsSeedHash)->IsDefaultValue());
250 
251   // Check that loading a bad seed returns false and clears the pref.
252   prefs.ClearPref(prefs::kVariationsSeed);
253   prefs.SetString(prefs::kVariationsSeed, "this should fail");
254   EXPECT_FALSE(prefs.FindPreference(prefs::kVariationsSeed)->IsDefaultValue());
255   EXPECT_FALSE(variations_service.LoadVariationsSeedFromPref(&loaded_seed));
256   EXPECT_TRUE(prefs.FindPreference(prefs::kVariationsSeed)->IsDefaultValue());
257   EXPECT_TRUE(
258       prefs.FindPreference(prefs::kVariationsSeedDate)->IsDefaultValue());
259   EXPECT_TRUE(
260       prefs.FindPreference(prefs::kVariationsSeedHash)->IsDefaultValue());
261 
262   // Check that having no seed in prefs results in a return value of false.
263   prefs.ClearPref(prefs::kVariationsSeed);
264   EXPECT_FALSE(variations_service.LoadVariationsSeedFromPref(&loaded_seed));
265 }
266 
TEST_F(VariationsServiceTest,StoreSeed)267 TEST_F(VariationsServiceTest, StoreSeed) {
268   const base::Time now = base::Time::Now();
269   const VariationsSeed seed = CreateTestSeed();
270   const std::string serialized_seed = SerializeSeed(seed);
271 
272   TestingPrefServiceSimple prefs;
273   VariationsService::RegisterPrefs(prefs.registry());
274 
275   TestVariationsService variations_service(new TestRequestAllowedNotifier,
276                                            &prefs);
277 
278   EXPECT_TRUE(variations_service.StoreSeedData(serialized_seed, now));
279   // Make sure the pref was actually set.
280   EXPECT_FALSE(prefs.FindPreference(prefs::kVariationsSeed)->IsDefaultValue());
281 
282   std::string loaded_serialized_seed = prefs.GetString(prefs::kVariationsSeed);
283   std::string decoded_serialized_seed;
284   ASSERT_TRUE(base::Base64Decode(loaded_serialized_seed,
285                                  &decoded_serialized_seed));
286   // Make sure the stored seed from pref is the same as the seed we created.
287   EXPECT_EQ(serialized_seed, decoded_serialized_seed);
288 
289   // Check if trying to store a bad seed leaves the pref unchanged.
290   prefs.ClearPref(prefs::kVariationsSeed);
291   EXPECT_FALSE(variations_service.StoreSeedData("should fail", now));
292   EXPECT_TRUE(prefs.FindPreference(prefs::kVariationsSeed)->IsDefaultValue());
293 }
294 
TEST_F(VariationsServiceTest,RequestsInitiallyNotAllowed)295 TEST_F(VariationsServiceTest, RequestsInitiallyNotAllowed) {
296   base::MessageLoopForUI message_loop;
297   content::TestBrowserThread ui_thread(content::BrowserThread::UI,
298                                        &message_loop);
299   TestingPrefServiceSimple prefs;
300   VariationsService::RegisterPrefs(prefs.registry());
301 
302   // Pass ownership to TestVariationsService, but keep a weak pointer to
303   // manipulate it for this test.
304   TestRequestAllowedNotifier* test_notifier = new TestRequestAllowedNotifier;
305   TestVariationsService test_service(test_notifier, &prefs);
306 
307   // Force the notifier to initially disallow requests.
308   test_notifier->SetRequestsAllowedOverride(false);
309   test_service.StartRepeatedVariationsSeedFetch();
310   EXPECT_FALSE(test_service.fetch_attempted());
311 
312   test_notifier->NotifyObserver();
313   EXPECT_TRUE(test_service.fetch_attempted());
314 }
315 
TEST_F(VariationsServiceTest,RequestsInitiallyAllowed)316 TEST_F(VariationsServiceTest, RequestsInitiallyAllowed) {
317   base::MessageLoopForUI message_loop;
318   content::TestBrowserThread ui_thread(content::BrowserThread::UI,
319                                        &message_loop);
320   TestingPrefServiceSimple prefs;
321   VariationsService::RegisterPrefs(prefs.registry());
322 
323   // Pass ownership to TestVariationsService, but keep a weak pointer to
324   // manipulate it for this test.
325   TestRequestAllowedNotifier* test_notifier = new TestRequestAllowedNotifier;
326   TestVariationsService test_service(test_notifier, &prefs);
327 
328   test_notifier->SetRequestsAllowedOverride(true);
329   test_service.StartRepeatedVariationsSeedFetch();
330   EXPECT_TRUE(test_service.fetch_attempted());
331 }
332 
TEST_F(VariationsServiceTest,SeedStoredWhenOKStatus)333 TEST_F(VariationsServiceTest, SeedStoredWhenOKStatus) {
334   base::MessageLoop message_loop;
335   content::TestBrowserThread io_thread(content::BrowserThread::IO,
336                                        &message_loop);
337   TestingPrefServiceSimple prefs;
338   VariationsService::RegisterPrefs(prefs.registry());
339 
340   VariationsService variations_service(new TestRequestAllowedNotifier, &prefs);
341 
342   net::TestURLFetcherFactory factory;
343   variations_service.DoActualFetch();
344 
345   net::TestURLFetcher* fetcher = factory.GetFetcherByID(0);
346   SimulateServerResponse(net::HTTP_OK, fetcher);
347   const VariationsSeed seed = CreateTestSeed();
348   fetcher->SetResponseString(SerializeSeed(seed));
349 
350   EXPECT_TRUE(prefs.FindPreference(prefs::kVariationsSeed)->IsDefaultValue());
351   variations_service.OnURLFetchComplete(fetcher);
352   EXPECT_FALSE(prefs.FindPreference(prefs::kVariationsSeed)->IsDefaultValue());
353   const std::string expected_base64 = SerializeSeedBase64(seed, NULL);
354   EXPECT_EQ(expected_base64, prefs.GetString(prefs::kVariationsSeed));
355 }
356 
TEST_F(VariationsServiceTest,SeedNotStoredWhenNonOKStatus)357 TEST_F(VariationsServiceTest, SeedNotStoredWhenNonOKStatus) {
358   const int non_ok_status_codes[] = {
359     net::HTTP_NO_CONTENT,
360     net::HTTP_NOT_MODIFIED,
361     net::HTTP_NOT_FOUND,
362     net::HTTP_INTERNAL_SERVER_ERROR,
363     net::HTTP_SERVICE_UNAVAILABLE,
364   };
365 
366   base::MessageLoop message_loop;
367   content::TestBrowserThread io_thread(content::BrowserThread::IO,
368                                        &message_loop);
369   TestingPrefServiceSimple prefs;
370   VariationsService::RegisterPrefs(prefs.registry());
371 
372   VariationsService variations_service(new TestRequestAllowedNotifier, &prefs);
373   for (size_t i = 0; i < arraysize(non_ok_status_codes); ++i) {
374     net::TestURLFetcherFactory factory;
375     variations_service.DoActualFetch();
376     EXPECT_TRUE(prefs.FindPreference(prefs::kVariationsSeed)->IsDefaultValue());
377 
378     net::TestURLFetcher* fetcher = factory.GetFetcherByID(0);
379     SimulateServerResponse(non_ok_status_codes[i], fetcher);
380     variations_service.OnURLFetchComplete(fetcher);
381 
382     EXPECT_TRUE(prefs.FindPreference(prefs::kVariationsSeed)->IsDefaultValue());
383   }
384 }
385 
TEST_F(VariationsServiceTest,SeedDateUpdatedOn304Status)386 TEST_F(VariationsServiceTest, SeedDateUpdatedOn304Status) {
387   base::MessageLoop message_loop;
388   content::TestBrowserThread io_thread(content::BrowserThread::IO,
389                                        &message_loop);
390   TestingPrefServiceSimple prefs;
391   VariationsService::RegisterPrefs(prefs.registry());
392 
393   VariationsService variations_service(new TestRequestAllowedNotifier, &prefs);
394   net::TestURLFetcherFactory factory;
395   variations_service.DoActualFetch();
396   EXPECT_TRUE(
397       prefs.FindPreference(prefs::kVariationsSeedDate)->IsDefaultValue());
398 
399   net::TestURLFetcher* fetcher = factory.GetFetcherByID(0);
400   SimulateServerResponse(net::HTTP_NOT_MODIFIED, fetcher);
401   variations_service.OnURLFetchComplete(fetcher);
402   EXPECT_FALSE(
403       prefs.FindPreference(prefs::kVariationsSeedDate)->IsDefaultValue());
404 }
405 
406 }  // namespace chrome_variations
407