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 "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"
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"
33 namespace chrome_variations
{
37 // A test class used to validate expected functionality in VariationsService.
38 class TestVariationsService
: public VariationsService
{
40 TestVariationsService(TestRequestAllowedNotifier
* test_notifier
,
41 PrefService
* local_state
)
42 : VariationsService(test_notifier
, local_state
, NULL
),
43 intercepts_fetch_(true),
44 fetch_attempted_(false),
46 // Set this so StartRepeatedVariationsSeedFetch can be called in tests.
47 SetCreateTrialsFromSeedCalledForTesting(true);
50 virtual ~TestVariationsService() {
53 void set_intercepts_fetch(bool value
) {
54 intercepts_fetch_
= value
;
57 bool fetch_attempted() const { return fetch_attempted_
; }
59 bool seed_stored() const { return seed_stored_
; }
61 virtual void DoActualFetch() OVERRIDE
{
62 if (intercepts_fetch_
) {
63 fetch_attempted_
= true;
67 VariationsService::DoActualFetch();
71 virtual void StoreSeed(const std::string
& seed_data
,
72 const std::string
& seed_signature
,
73 const base::Time
& date_fetched
) OVERRIDE
{
78 bool intercepts_fetch_
;
79 bool fetch_attempted_
;
82 DISALLOW_COPY_AND_ASSIGN(TestVariationsService
);
85 class TestVariationsServiceObserver
: public VariationsService::Observer
{
87 TestVariationsServiceObserver()
88 : best_effort_changes_notified_(0),
89 crticial_changes_notified_(0) {
91 virtual ~TestVariationsServiceObserver() {
94 virtual void OnExperimentChangesDetected(Severity severity
) OVERRIDE
{
97 ++best_effort_changes_notified_
;
100 ++crticial_changes_notified_
;
105 int best_effort_changes_notified() const {
106 return best_effort_changes_notified_
;
109 int crticial_changes_notified() const {
110 return crticial_changes_notified_
;
114 // Number of notification received with BEST_EFFORT severity.
115 int best_effort_changes_notified_
;
117 // Number of notification received with CRITICAL severity.
118 int crticial_changes_notified_
;
120 DISALLOW_COPY_AND_ASSIGN(TestVariationsServiceObserver
);
123 // Populates |seed| with simple test data. The resulting seed will contain one
124 // study called "test", which contains one experiment called "abc" with
125 // probability weight 100. |seed|'s study field will be cleared before adding
127 variations::VariationsSeed
CreateTestSeed() {
128 variations::VariationsSeed seed
;
129 variations::Study
* study
= seed
.add_study();
130 study
->set_name("test");
131 study
->set_default_experiment_name("abc");
132 variations::Study_Experiment
* experiment
= study
->add_experiment();
133 experiment
->set_name("abc");
134 experiment
->set_probability_weight(100);
135 seed
.set_serial_number("123");
139 // Serializes |seed| to protobuf binary format.
140 std::string
SerializeSeed(const variations::VariationsSeed
& seed
) {
141 std::string serialized_seed
;
142 seed
.SerializeToString(&serialized_seed
);
143 return serialized_seed
;
146 // Simulates a variations service response by setting a date header and the
147 // specified HTTP |response_code| on |fetcher|.
148 void SimulateServerResponse(int response_code
, net::TestURLFetcher
* fetcher
) {
149 ASSERT_TRUE(fetcher
);
150 scoped_refptr
<net::HttpResponseHeaders
> headers(
151 new net::HttpResponseHeaders("date:Wed, 13 Feb 2013 00:25:24 GMT\0\0"));
152 fetcher
->set_response_headers(headers
);
153 fetcher
->set_response_code(response_code
);
158 class VariationsServiceTest
: public ::testing::Test
{
160 VariationsServiceTest() {}
163 #if defined(OS_CHROMEOS)
164 // Not used directly. Initializes CrosSettings for testing.
165 chromeos::ScopedTestDeviceSettingsService test_device_settings_service_
;
166 chromeos::ScopedTestCrosSettings test_cros_settings_
;
169 DISALLOW_COPY_AND_ASSIGN(VariationsServiceTest
);
172 #if !defined(OS_CHROMEOS)
173 TEST_F(VariationsServiceTest
, VariationsURLIsValid
) {
174 #if defined(OS_ANDROID)
175 // Android uses profile prefs as the PrefService to generate the URL.
176 TestingPrefServiceSyncable prefs
;
177 VariationsService::RegisterProfilePrefs(prefs
.registry());
179 TestingPrefServiceSimple prefs
;
180 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 prefs
.SetString(prefs::kVariationsRestrictParameter
, "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
);
197 class VariationsServiceTestChromeOS
: public VariationsServiceTest
{
199 VariationsServiceTestChromeOS() {}
201 virtual void SetUp() OVERRIDE
{
202 cros_settings_
= chromeos::CrosSettings::Get();
203 DCHECK(cros_settings_
!= NULL
);
204 // Remove the real DeviceSettingsProvider and replace it with a stub that
205 // allows modifications in a test.
206 device_settings_provider_
= cros_settings_
->GetProvider(
207 chromeos::kReportDeviceVersionInfo
);
208 EXPECT_TRUE(device_settings_provider_
!= NULL
);
209 EXPECT_TRUE(cros_settings_
->RemoveSettingsProvider(
210 device_settings_provider_
));
211 cros_settings_
->AddSettingsProvider(&stub_settings_provider_
);
214 virtual void TearDown() OVERRIDE
{
215 // Restore the real DeviceSettingsProvider.
217 cros_settings_
->RemoveSettingsProvider(&stub_settings_provider_
));
218 cros_settings_
->AddSettingsProvider(device_settings_provider_
);
221 void SetVariationsRestrictParameterPolicyValue(std::string value
) {
222 cros_settings_
->SetString(chromeos::kVariationsRestrictParameter
, value
);
226 chromeos::CrosSettings
* cros_settings_
;
227 chromeos::StubCrosSettingsProvider stub_settings_provider_
;
228 chromeos::CrosSettingsProvider
* device_settings_provider_
;
230 DISALLOW_COPY_AND_ASSIGN(VariationsServiceTestChromeOS
);
233 TEST_F(VariationsServiceTestChromeOS
, VariationsURLIsValid
) {
234 TestingPrefServiceSimple prefs
;
235 VariationsService::RegisterPrefs(prefs
.registry());
236 const std::string default_variations_url
=
237 VariationsService::GetDefaultVariationsServerURLForTesting();
240 GURL url
= VariationsService::GetVariationsServerURL(&prefs
);
241 EXPECT_TRUE(StartsWithASCII(url
.spec(), default_variations_url
, true));
242 EXPECT_FALSE(net::GetValueForKeyInQuery(url
, "restrict", &value
));
244 SetVariationsRestrictParameterPolicyValue("restricted");
245 url
= VariationsService::GetVariationsServerURL(&prefs
);
246 EXPECT_TRUE(StartsWithASCII(url
.spec(), default_variations_url
, true));
247 EXPECT_TRUE(net::GetValueForKeyInQuery(url
, "restrict", &value
));
248 EXPECT_EQ("restricted", value
);
252 TEST_F(VariationsServiceTest
, VariationsURLHasOSNameParam
) {
253 TestingPrefServiceSimple prefs
;
254 VariationsService::RegisterPrefs(prefs
.registry());
255 const GURL url
= VariationsService::GetVariationsServerURL(&prefs
);
258 EXPECT_TRUE(net::GetValueForKeyInQuery(url
, "osname", &value
));
259 EXPECT_FALSE(value
.empty());
262 TEST_F(VariationsServiceTest
, RequestsInitiallyNotAllowed
) {
263 base::MessageLoopForUI message_loop
;
264 content::TestBrowserThread
ui_thread(content::BrowserThread::UI
,
266 TestingPrefServiceSimple prefs
;
267 VariationsService::RegisterPrefs(prefs
.registry());
269 // Pass ownership to TestVariationsService, but keep a weak pointer to
270 // manipulate it for this test.
271 TestRequestAllowedNotifier
* test_notifier
= new TestRequestAllowedNotifier
;
272 TestVariationsService
test_service(test_notifier
, &prefs
);
274 // Force the notifier to initially disallow requests.
275 test_notifier
->SetRequestsAllowedOverride(false);
276 test_service
.StartRepeatedVariationsSeedFetch();
277 EXPECT_FALSE(test_service
.fetch_attempted());
279 test_notifier
->NotifyObserver();
280 EXPECT_TRUE(test_service
.fetch_attempted());
283 TEST_F(VariationsServiceTest
, RequestsInitiallyAllowed
) {
284 base::MessageLoopForUI message_loop
;
285 content::TestBrowserThread
ui_thread(content::BrowserThread::UI
,
287 TestingPrefServiceSimple prefs
;
288 VariationsService::RegisterPrefs(prefs
.registry());
290 // Pass ownership to TestVariationsService, but keep a weak pointer to
291 // manipulate it for this test.
292 TestRequestAllowedNotifier
* test_notifier
= new TestRequestAllowedNotifier
;
293 TestVariationsService
test_service(test_notifier
, &prefs
);
295 test_notifier
->SetRequestsAllowedOverride(true);
296 test_service
.StartRepeatedVariationsSeedFetch();
297 EXPECT_TRUE(test_service
.fetch_attempted());
300 TEST_F(VariationsServiceTest
, SeedStoredWhenOKStatus
) {
301 base::MessageLoop message_loop
;
302 content::TestBrowserThread
io_thread(content::BrowserThread::IO
,
304 TestingPrefServiceSimple prefs
;
305 VariationsService::RegisterPrefs(prefs
.registry());
307 TestVariationsService
service(new TestRequestAllowedNotifier
, &prefs
);
308 service
.set_intercepts_fetch(false);
310 net::TestURLFetcherFactory factory
;
311 service
.DoActualFetch();
313 net::TestURLFetcher
* fetcher
= factory
.GetFetcherByID(0);
314 SimulateServerResponse(net::HTTP_OK
, fetcher
);
315 fetcher
->SetResponseString(SerializeSeed(CreateTestSeed()));
317 EXPECT_FALSE(service
.seed_stored());
318 service
.OnURLFetchComplete(fetcher
);
319 EXPECT_TRUE(service
.seed_stored());
322 TEST_F(VariationsServiceTest
, SeedNotStoredWhenNonOKStatus
) {
323 const int non_ok_status_codes
[] = {
324 net::HTTP_NO_CONTENT
,
325 net::HTTP_NOT_MODIFIED
,
327 net::HTTP_INTERNAL_SERVER_ERROR
,
328 net::HTTP_SERVICE_UNAVAILABLE
,
331 base::MessageLoop message_loop
;
332 content::TestBrowserThread
io_thread(content::BrowserThread::IO
,
334 TestingPrefServiceSimple prefs
;
335 VariationsService::RegisterPrefs(prefs
.registry());
337 VariationsService
service(new TestRequestAllowedNotifier
, &prefs
, NULL
);
338 for (size_t i
= 0; i
< arraysize(non_ok_status_codes
); ++i
) {
339 net::TestURLFetcherFactory factory
;
340 service
.DoActualFetch();
341 EXPECT_TRUE(prefs
.FindPreference(prefs::kVariationsSeed
)->IsDefaultValue());
343 net::TestURLFetcher
* fetcher
= factory
.GetFetcherByID(0);
344 SimulateServerResponse(non_ok_status_codes
[i
], fetcher
);
345 service
.OnURLFetchComplete(fetcher
);
347 EXPECT_TRUE(prefs
.FindPreference(prefs::kVariationsSeed
)->IsDefaultValue());
351 TEST_F(VariationsServiceTest
, SeedDateUpdatedOn304Status
) {
352 base::MessageLoop message_loop
;
353 content::TestBrowserThread
io_thread(content::BrowserThread::IO
,
355 TestingPrefServiceSimple prefs
;
356 VariationsService::RegisterPrefs(prefs
.registry());
358 VariationsService
service(new TestRequestAllowedNotifier
, &prefs
, NULL
);
359 net::TestURLFetcherFactory factory
;
360 service
.DoActualFetch();
362 prefs
.FindPreference(prefs::kVariationsSeedDate
)->IsDefaultValue());
364 net::TestURLFetcher
* fetcher
= factory
.GetFetcherByID(0);
365 SimulateServerResponse(net::HTTP_NOT_MODIFIED
, fetcher
);
366 service
.OnURLFetchComplete(fetcher
);
368 prefs
.FindPreference(prefs::kVariationsSeedDate
)->IsDefaultValue());
371 TEST_F(VariationsServiceTest
, Observer
) {
372 TestingPrefServiceSimple prefs
;
373 VariationsService::RegisterPrefs(prefs
.registry());
374 VariationsService
service(new TestRequestAllowedNotifier
, &prefs
, NULL
);
378 int best_effort_count
;
380 int expected_best_effort_notifications
;
381 int expected_crtical_notifications
;
396 for (size_t i
= 0; i
< ARRAYSIZE_UNSAFE(cases
); ++i
) {
397 TestVariationsServiceObserver observer
;
398 service
.AddObserver(&observer
);
400 variations::VariationsSeedSimulator::Result result
;
401 result
.normal_group_change_count
= cases
[i
].normal_count
;
402 result
.kill_best_effort_group_change_count
= cases
[i
].best_effort_count
;
403 result
.kill_critical_group_change_count
= cases
[i
].critical_count
;
404 service
.NotifyObservers(result
);
406 EXPECT_EQ(cases
[i
].expected_best_effort_notifications
,
407 observer
.best_effort_changes_notified()) << i
;
408 EXPECT_EQ(cases
[i
].expected_crtical_notifications
,
409 observer
.crticial_changes_notified()) << i
;
411 service
.RemoveObserver(&observer
);
415 } // namespace chrome_variations