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.
5 #include "chrome/browser/metrics/variations/variations_service.h"
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"
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"
32 namespace chrome_variations
{
36 // A test class used to validate expected functionality in VariationsService.
37 class TestVariationsService
: public VariationsService
{
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);
47 virtual ~TestVariationsService() {
50 bool fetch_attempted() const { return fetch_attempted_
; }
53 virtual void DoActualFetch() OVERRIDE
{
54 fetch_attempted_
= true;
58 bool fetch_attempted_
;
60 DISALLOW_COPY_AND_ASSIGN(TestVariationsService
);
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
67 VariationsSeed
CreateTestSeed() {
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");
79 // Serializes |seed| to protobuf binary format.
80 std::string
SerializeSeed(const VariationsSeed
& seed
) {
81 std::string serialized_seed
;
82 seed
.SerializeToString(&serialized_seed
);
83 return serialized_seed
;
86 // Serializes |seed| to base64-encoded protobuf binary format.
87 std::string
SerializeSeedBase64(const VariationsSeed
& seed
, std::string
* hash
) {
88 std::string serialized_seed
= SerializeSeed(seed
);
90 std::string sha1
= base::SHA1HashString(serialized_seed
);
91 *hash
= base::HexEncode(sha1
.data(), sha1
.size());
93 std::string base64_serialized_seed
;
94 base::Base64Encode(serialized_seed
, &base64_serialized_seed
);
95 return base64_serialized_seed
;
98 // Simulates a variations service response by setting a date header and the
99 // specified HTTP |response_code| on |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
);
110 class VariationsServiceTest
: public ::testing::Test
{
112 VariationsServiceTest() {}
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_
;
121 DISALLOW_COPY_AND_ASSIGN(VariationsServiceTest
);
124 #if !defined(OS_CHROMEOS)
125 TEST_F(VariationsServiceTest
, VariationsURLIsValid
) {
126 TestingPrefServiceSimple prefs
;
127 VariationsService::RegisterPrefs(prefs
.registry());
128 const std::string default_variations_url
=
129 VariationsService::GetDefaultVariationsServerURLForTesting();
132 GURL url
= VariationsService::GetVariationsServerURL(&prefs
);
133 EXPECT_TRUE(StartsWithASCII(url
.spec(), default_variations_url
, true));
134 EXPECT_FALSE(net::GetValueForKeyInQuery(url
, "restrict", &value
));
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
);
143 class VariationsServiceTestChromeOS
: public VariationsServiceTest
{
145 VariationsServiceTestChromeOS() {}
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_
);
160 virtual void TearDown() OVERRIDE
{
161 // Restore the real DeviceSettingsProvider.
163 cros_settings_
->RemoveSettingsProvider(&stub_settings_provider_
));
164 cros_settings_
->AddSettingsProvider(device_settings_provider_
);
167 void SetVariationsRestrictParameterPolicyValue(std::string value
) {
168 cros_settings_
->SetString(chromeos::kVariationsRestrictParameter
, value
);
172 chromeos::CrosSettings
* cros_settings_
;
173 chromeos::StubCrosSettingsProvider stub_settings_provider_
;
174 chromeos::CrosSettingsProvider
* device_settings_provider_
;
176 DISALLOW_COPY_AND_ASSIGN(VariationsServiceTestChromeOS
);
179 TEST_F(VariationsServiceTestChromeOS
, VariationsURLIsValid
) {
180 TestingPrefServiceSimple prefs
;
181 VariationsService::RegisterPrefs(prefs
.registry());
182 const std::string default_variations_url
=
183 VariationsService::GetDefaultVariationsServerURLForTesting();
186 GURL url
= VariationsService::GetVariationsServerURL(&prefs
);
187 EXPECT_TRUE(StartsWithASCII(url
.spec(), default_variations_url
, true));
188 EXPECT_FALSE(net::GetValueForKeyInQuery(url
, "restrict", &value
));
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
);
198 TEST_F(VariationsServiceTest
, VariationsURLHasOSNameParam
) {
199 TestingPrefServiceSimple prefs
;
200 VariationsService::RegisterPrefs(prefs
.registry());
201 const GURL url
= VariationsService::GetVariationsServerURL(&prefs
);
204 EXPECT_TRUE(net::GetValueForKeyInQuery(url
, "osname", &value
));
205 EXPECT_FALSE(value
.empty());
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
);
214 TestingPrefServiceSimple prefs
;
215 VariationsService::RegisterPrefs(prefs
.registry());
216 prefs
.SetString(prefs::kVariationsSeed
, base64_seed
);
218 TestVariationsService
variations_service(new TestRequestAllowedNotifier
,
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
));
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
));
230 // Check that loading a seed with the correct hash works.
231 prefs
.SetString(prefs::kVariationsSeedHash
, seed_hash
);
233 EXPECT_TRUE(variations_service
.LoadVariationsSeedFromPref(&loaded_seed
));
234 EXPECT_EQ(SerializeSeed(seed
), SerializeSeed(loaded_seed
));
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());
247 prefs
.FindPreference(prefs::kVariationsSeedDate
)->IsDefaultValue());
249 prefs
.FindPreference(prefs::kVariationsSeedHash
)->IsDefaultValue());
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());
258 prefs
.FindPreference(prefs::kVariationsSeedDate
)->IsDefaultValue());
260 prefs
.FindPreference(prefs::kVariationsSeedHash
)->IsDefaultValue());
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
));
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
);
272 TestingPrefServiceSimple prefs
;
273 VariationsService::RegisterPrefs(prefs
.registry());
275 TestVariationsService
variations_service(new TestRequestAllowedNotifier
,
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());
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
);
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());
295 TEST_F(VariationsServiceTest
, RequestsInitiallyNotAllowed
) {
296 base::MessageLoopForUI message_loop
;
297 content::TestBrowserThread
ui_thread(content::BrowserThread::UI
,
299 TestingPrefServiceSimple prefs
;
300 VariationsService::RegisterPrefs(prefs
.registry());
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
);
307 // Force the notifier to initially disallow requests.
308 test_notifier
->SetRequestsAllowedOverride(false);
309 test_service
.StartRepeatedVariationsSeedFetch();
310 EXPECT_FALSE(test_service
.fetch_attempted());
312 test_notifier
->NotifyObserver();
313 EXPECT_TRUE(test_service
.fetch_attempted());
316 TEST_F(VariationsServiceTest
, RequestsInitiallyAllowed
) {
317 base::MessageLoopForUI message_loop
;
318 content::TestBrowserThread
ui_thread(content::BrowserThread::UI
,
320 TestingPrefServiceSimple prefs
;
321 VariationsService::RegisterPrefs(prefs
.registry());
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
);
328 test_notifier
->SetRequestsAllowedOverride(true);
329 test_service
.StartRepeatedVariationsSeedFetch();
330 EXPECT_TRUE(test_service
.fetch_attempted());
333 TEST_F(VariationsServiceTest
, SeedStoredWhenOKStatus
) {
334 base::MessageLoop message_loop
;
335 content::TestBrowserThread
io_thread(content::BrowserThread::IO
,
337 TestingPrefServiceSimple prefs
;
338 VariationsService::RegisterPrefs(prefs
.registry());
340 VariationsService
variations_service(new TestRequestAllowedNotifier
, &prefs
);
342 net::TestURLFetcherFactory factory
;
343 variations_service
.DoActualFetch();
345 net::TestURLFetcher
* fetcher
= factory
.GetFetcherByID(0);
346 SimulateServerResponse(net::HTTP_OK
, fetcher
);
347 const VariationsSeed seed
= CreateTestSeed();
348 fetcher
->SetResponseString(SerializeSeed(seed
));
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
));
357 TEST_F(VariationsServiceTest
, SeedNotStoredWhenNonOKStatus
) {
358 const int non_ok_status_codes
[] = {
359 net::HTTP_NO_CONTENT
,
360 net::HTTP_NOT_MODIFIED
,
362 net::HTTP_INTERNAL_SERVER_ERROR
,
363 net::HTTP_SERVICE_UNAVAILABLE
,
366 base::MessageLoop message_loop
;
367 content::TestBrowserThread
io_thread(content::BrowserThread::IO
,
369 TestingPrefServiceSimple prefs
;
370 VariationsService::RegisterPrefs(prefs
.registry());
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());
378 net::TestURLFetcher
* fetcher
= factory
.GetFetcherByID(0);
379 SimulateServerResponse(non_ok_status_codes
[i
], fetcher
);
380 variations_service
.OnURLFetchComplete(fetcher
);
382 EXPECT_TRUE(prefs
.FindPreference(prefs::kVariationsSeed
)->IsDefaultValue());
386 TEST_F(VariationsServiceTest
, SeedDateUpdatedOn304Status
) {
387 base::MessageLoop message_loop
;
388 content::TestBrowserThread
io_thread(content::BrowserThread::IO
,
390 TestingPrefServiceSimple prefs
;
391 VariationsService::RegisterPrefs(prefs
.registry());
393 VariationsService
variations_service(new TestRequestAllowedNotifier
, &prefs
);
394 net::TestURLFetcherFactory factory
;
395 variations_service
.DoActualFetch();
397 prefs
.FindPreference(prefs::kVariationsSeedDate
)->IsDefaultValue());
399 net::TestURLFetcher
* fetcher
= factory
.GetFetcherByID(0);
400 SimulateServerResponse(net::HTTP_NOT_MODIFIED
, fetcher
);
401 variations_service
.OnURLFetchComplete(fetcher
);
403 prefs
.FindPreference(prefs::kVariationsSeedDate
)->IsDefaultValue());
406 } // namespace chrome_variations