Revert "Reland c91b178b07b0d - Delete dead signin code (SigninGlobalError)"
[chromium-blink-merge.git] / chrome / browser / metrics / variations / variations_service_unittest.cc
blobdee8dfa45d87c21d84c55fcc8449f62012fe7556
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"
7 #include <vector>
9 #include "base/base64.h"
10 #include "base/json/json_string_value_serializer.h"
11 #include "base/prefs/testing_pref_service.h"
12 #include "base/sha1.h"
13 #include "base/strings/string_number_conversions.h"
14 #include "base/strings/string_split.h"
15 #include "base/strings/string_util.h"
16 #include "base/test/histogram_tester.h"
17 #include "base/version.h"
18 #include "chrome/browser/metrics/variations/chrome_variations_service_client.h"
19 #include "chrome/test/base/testing_browser_process.h"
20 #include "chrome/test/base/testing_pref_service_syncable.h"
21 #include "components/variations/pref_names.h"
22 #include "components/variations/proto/study.pb.h"
23 #include "components/variations/proto/variations_seed.pb.h"
24 #include "components/web_resource/resource_request_allowed_notifier_test_util.h"
25 #include "content/public/test/test_browser_thread.h"
26 #include "content/public/test/test_browser_thread_bundle.h"
27 #include "net/base/url_util.h"
28 #include "net/http/http_response_headers.h"
29 #include "net/http/http_status_code.h"
30 #include "net/url_request/test_url_fetcher_factory.h"
31 #include "testing/gtest/include/gtest/gtest.h"
33 #if defined(OS_CHROMEOS)
34 #include "chrome/browser/chromeos/settings/cros_settings.h"
35 #include "chrome/browser/chromeos/settings/device_settings_service.h"
36 #include "chrome/browser/chromeos/settings/stub_cros_settings_provider.h"
37 #endif
39 namespace chrome_variations {
41 namespace {
43 // A test class used to validate expected functionality in VariationsService.
44 class TestVariationsService : public VariationsService {
45 public:
46 TestVariationsService(web_resource::TestRequestAllowedNotifier* test_notifier,
47 PrefService* local_state)
48 : VariationsService(make_scoped_ptr(new ChromeVariationsServiceClient()),
49 test_notifier,
50 local_state,
51 NULL),
52 intercepts_fetch_(true),
53 fetch_attempted_(false),
54 seed_stored_(false) {
55 // Set this so StartRepeatedVariationsSeedFetch can be called in tests.
56 SetCreateTrialsFromSeedCalledForTesting(true);
59 ~TestVariationsService() override {}
61 void set_intercepts_fetch(bool value) {
62 intercepts_fetch_ = value;
65 bool fetch_attempted() const { return fetch_attempted_; }
66 bool seed_stored() const { return seed_stored_; }
67 const std::string& stored_country() const { return stored_country_; }
69 void DoActualFetch() override {
70 if (intercepts_fetch_) {
71 fetch_attempted_ = true;
72 return;
75 VariationsService::DoActualFetch();
78 protected:
79 bool StoreSeed(const std::string& seed_data,
80 const std::string& seed_signature,
81 const std::string& country_code,
82 const base::Time& date_fetched,
83 bool is_delta_compressed) override {
84 seed_stored_ = true;
85 stored_country_ = country_code;
86 return true;
89 private:
90 bool intercepts_fetch_;
91 bool fetch_attempted_;
92 bool seed_stored_;
93 std::string stored_country_;
95 DISALLOW_COPY_AND_ASSIGN(TestVariationsService);
98 class TestVariationsServiceObserver : public VariationsService::Observer {
99 public:
100 TestVariationsServiceObserver()
101 : best_effort_changes_notified_(0),
102 crticial_changes_notified_(0) {
104 ~TestVariationsServiceObserver() override {}
106 void OnExperimentChangesDetected(Severity severity) override {
107 switch (severity) {
108 case BEST_EFFORT:
109 ++best_effort_changes_notified_;
110 break;
111 case CRITICAL:
112 ++crticial_changes_notified_;
113 break;
117 int best_effort_changes_notified() const {
118 return best_effort_changes_notified_;
121 int crticial_changes_notified() const {
122 return crticial_changes_notified_;
125 private:
126 // Number of notification received with BEST_EFFORT severity.
127 int best_effort_changes_notified_;
129 // Number of notification received with CRITICAL severity.
130 int crticial_changes_notified_;
132 DISALLOW_COPY_AND_ASSIGN(TestVariationsServiceObserver);
135 // Populates |seed| with simple test data. The resulting seed will contain one
136 // study called "test", which contains one experiment called "abc" with
137 // probability weight 100. |seed|'s study field will be cleared before adding
138 // the new study.
139 variations::VariationsSeed CreateTestSeed() {
140 variations::VariationsSeed seed;
141 variations::Study* study = seed.add_study();
142 study->set_name("test");
143 study->set_default_experiment_name("abc");
144 variations::Study_Experiment* experiment = study->add_experiment();
145 experiment->set_name("abc");
146 experiment->set_probability_weight(100);
147 seed.set_serial_number("123");
148 return seed;
151 // Serializes |seed| to protobuf binary format.
152 std::string SerializeSeed(const variations::VariationsSeed& seed) {
153 std::string serialized_seed;
154 seed.SerializeToString(&serialized_seed);
155 return serialized_seed;
158 // Simulates a variations service response by setting a date header and the
159 // specified HTTP |response_code| on |fetcher|.
160 scoped_refptr<net::HttpResponseHeaders> SimulateServerResponse(
161 int response_code,
162 net::TestURLFetcher* fetcher) {
163 EXPECT_TRUE(fetcher);
164 scoped_refptr<net::HttpResponseHeaders> headers(
165 new net::HttpResponseHeaders("date:Wed, 13 Feb 2013 00:25:24 GMT\0\0"));
166 fetcher->set_response_headers(headers);
167 fetcher->set_response_code(response_code);
168 return headers;
171 // Helper class that abstracts away platform-specific details relating to the
172 // pref store used for the "restrict" param policy.
173 class TestVariationsPrefsStore {
174 public:
175 TestVariationsPrefsStore() {
176 #if defined(OS_ANDROID)
177 // Android uses profile prefs as the PrefService to generate the URL.
178 VariationsService::RegisterProfilePrefs(prefs_.registry());
179 #else
180 VariationsService::RegisterPrefs(prefs_.registry());
181 #endif
183 #if defined(OS_CHROMEOS)
184 cros_settings_ = chromeos::CrosSettings::Get();
185 DCHECK(cros_settings_ != NULL);
186 // Remove the real DeviceSettingsProvider and replace it with a stub that
187 // allows modifications in a test.
188 // TODO(asvitkine): Make a scoped helper class for this operation.
189 device_settings_provider_ = cros_settings_->GetProvider(
190 chromeos::kReportDeviceVersionInfo);
191 EXPECT_TRUE(device_settings_provider_ != NULL);
192 EXPECT_TRUE(cros_settings_->RemoveSettingsProvider(
193 device_settings_provider_));
194 cros_settings_->AddSettingsProvider(&stub_settings_provider_);
195 #endif
198 ~TestVariationsPrefsStore() {
199 #if defined(OS_CHROMEOS)
200 // Restore the real DeviceSettingsProvider.
201 EXPECT_TRUE(
202 cros_settings_->RemoveSettingsProvider(&stub_settings_provider_));
203 cros_settings_->AddSettingsProvider(device_settings_provider_);
204 #endif
207 void SetVariationsRestrictParameterPolicyValue(const std::string& value) {
208 #if defined(OS_CHROMEOS)
209 cros_settings_->SetString(chromeos::kVariationsRestrictParameter, value);
210 #else
211 prefs_.SetString(prefs::kVariationsRestrictParameter, value);
212 #endif
215 PrefService* prefs() { return &prefs_; }
217 private:
218 #if defined(OS_ANDROID)
219 // Android uses profile prefs as the PrefService to generate the URL.
220 TestingPrefServiceSyncable prefs_;
221 #else
222 TestingPrefServiceSimple prefs_;
223 #endif
225 #if defined(OS_CHROMEOS)
226 chromeos::CrosSettings* cros_settings_;
227 chromeos::StubCrosSettingsProvider stub_settings_provider_;
228 chromeos::CrosSettingsProvider* device_settings_provider_;
229 #endif
231 DISALLOW_COPY_AND_ASSIGN(TestVariationsPrefsStore);
234 // Converts |list_value| to a string, to make it easier for debugging.
235 std::string ListValueToString(const base::ListValue& list_value) {
236 std::string json;
237 JSONStringValueSerializer serializer(&json);
238 serializer.set_pretty_print(true);
239 serializer.Serialize(list_value);
240 return json;
243 } // namespace
245 class VariationsServiceTest : public ::testing::Test {
246 protected:
247 VariationsServiceTest() {}
249 private:
250 content::TestBrowserThreadBundle thread_bundle_;
251 #if defined(OS_CHROMEOS)
252 // Not used directly. Initializes CrosSettings for testing.
253 chromeos::ScopedTestDeviceSettingsService test_device_settings_service_;
254 chromeos::ScopedTestCrosSettings test_cros_settings_;
255 #endif
257 DISALLOW_COPY_AND_ASSIGN(VariationsServiceTest);
260 TEST_F(VariationsServiceTest, GetVariationsServerURL) {
261 TestVariationsPrefsStore prefs_store;
262 PrefService* prefs = prefs_store.prefs();
263 const std::string default_variations_url =
264 VariationsService::GetDefaultVariationsServerURLForTesting();
266 std::string value;
267 GURL url = VariationsService::GetVariationsServerURL(prefs, std::string());
268 EXPECT_TRUE(base::StartsWith(url.spec(), default_variations_url,
269 base::CompareCase::SENSITIVE));
270 EXPECT_FALSE(net::GetValueForKeyInQuery(url, "restrict", &value));
272 prefs_store.SetVariationsRestrictParameterPolicyValue("restricted");
273 url = VariationsService::GetVariationsServerURL(prefs, std::string());
274 EXPECT_TRUE(base::StartsWith(url.spec(), default_variations_url,
275 base::CompareCase::SENSITIVE));
276 EXPECT_TRUE(net::GetValueForKeyInQuery(url, "restrict", &value));
277 EXPECT_EQ("restricted", value);
279 // The override value should take precedence over what's in prefs.
280 url = VariationsService::GetVariationsServerURL(prefs, "override");
281 EXPECT_TRUE(base::StartsWith(url.spec(), default_variations_url,
282 base::CompareCase::SENSITIVE));
283 EXPECT_TRUE(net::GetValueForKeyInQuery(url, "restrict", &value));
284 EXPECT_EQ("override", value);
287 TEST_F(VariationsServiceTest, VariationsURLHasOSNameParam) {
288 TestingPrefServiceSimple prefs;
289 VariationsService::RegisterPrefs(prefs.registry());
290 const GURL url =
291 VariationsService::GetVariationsServerURL(&prefs, std::string());
293 std::string value;
294 EXPECT_TRUE(net::GetValueForKeyInQuery(url, "osname", &value));
295 EXPECT_FALSE(value.empty());
298 TEST_F(VariationsServiceTest, RequestsInitiallyNotAllowed) {
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 web_resource::TestRequestAllowedNotifier* test_notifier =
305 new web_resource::TestRequestAllowedNotifier(&prefs);
306 TestVariationsService test_service(test_notifier, &prefs);
308 // Force the notifier to initially disallow requests.
309 test_notifier->SetRequestsAllowedOverride(false);
310 test_service.StartRepeatedVariationsSeedFetch();
311 EXPECT_FALSE(test_service.fetch_attempted());
313 test_notifier->NotifyObserver();
314 EXPECT_TRUE(test_service.fetch_attempted());
317 TEST_F(VariationsServiceTest, RequestsInitiallyAllowed) {
318 TestingPrefServiceSimple prefs;
319 VariationsService::RegisterPrefs(prefs.registry());
321 // Pass ownership to TestVariationsService, but keep a weak pointer to
322 // manipulate it for this test.
323 web_resource::TestRequestAllowedNotifier* test_notifier =
324 new web_resource::TestRequestAllowedNotifier(&prefs);
325 TestVariationsService test_service(test_notifier, &prefs);
327 test_notifier->SetRequestsAllowedOverride(true);
328 test_service.StartRepeatedVariationsSeedFetch();
329 EXPECT_TRUE(test_service.fetch_attempted());
332 TEST_F(VariationsServiceTest, SeedStoredWhenOKStatus) {
333 TestingPrefServiceSimple prefs;
334 VariationsService::RegisterPrefs(prefs.registry());
336 TestVariationsService service(
337 new web_resource::TestRequestAllowedNotifier(&prefs), &prefs);
338 service.variations_server_url_ =
339 VariationsService::GetVariationsServerURL(&prefs, std::string());
340 service.set_intercepts_fetch(false);
342 net::TestURLFetcherFactory factory;
343 service.DoActualFetch();
345 net::TestURLFetcher* fetcher = factory.GetFetcherByID(0);
346 SimulateServerResponse(net::HTTP_OK, fetcher);
347 fetcher->SetResponseString(SerializeSeed(CreateTestSeed()));
349 EXPECT_FALSE(service.seed_stored());
350 service.OnURLFetchComplete(fetcher);
351 EXPECT_TRUE(service.seed_stored());
354 TEST_F(VariationsServiceTest, SeedNotStoredWhenNonOKStatus) {
355 const int non_ok_status_codes[] = {
356 net::HTTP_NO_CONTENT,
357 net::HTTP_NOT_MODIFIED,
358 net::HTTP_NOT_FOUND,
359 net::HTTP_INTERNAL_SERVER_ERROR,
360 net::HTTP_SERVICE_UNAVAILABLE,
363 TestingPrefServiceSimple prefs;
364 VariationsService::RegisterPrefs(prefs.registry());
366 VariationsService service(
367 make_scoped_ptr(new ChromeVariationsServiceClient()),
368 new web_resource::TestRequestAllowedNotifier(&prefs), &prefs, NULL);
369 service.variations_server_url_ =
370 VariationsService::GetVariationsServerURL(&prefs, std::string());
371 for (size_t i = 0; i < arraysize(non_ok_status_codes); ++i) {
372 net::TestURLFetcherFactory factory;
373 service.DoActualFetch();
374 EXPECT_TRUE(prefs.FindPreference(prefs::kVariationsSeed)->IsDefaultValue());
376 net::TestURLFetcher* fetcher = factory.GetFetcherByID(0);
377 SimulateServerResponse(non_ok_status_codes[i], fetcher);
378 service.OnURLFetchComplete(fetcher);
380 EXPECT_TRUE(prefs.FindPreference(prefs::kVariationsSeed)->IsDefaultValue());
384 TEST_F(VariationsServiceTest, CountryHeader) {
385 TestingPrefServiceSimple prefs;
386 VariationsService::RegisterPrefs(prefs.registry());
388 TestVariationsService service(
389 new web_resource::TestRequestAllowedNotifier(&prefs), &prefs);
390 service.variations_server_url_ =
391 VariationsService::GetVariationsServerURL(&prefs, std::string());
392 service.set_intercepts_fetch(false);
394 net::TestURLFetcherFactory factory;
395 service.DoActualFetch();
397 net::TestURLFetcher* fetcher = factory.GetFetcherByID(0);
398 scoped_refptr<net::HttpResponseHeaders> headers =
399 SimulateServerResponse(net::HTTP_OK, fetcher);
400 headers->AddHeader("X-Country: test");
401 fetcher->SetResponseString(SerializeSeed(CreateTestSeed()));
403 EXPECT_FALSE(service.seed_stored());
404 service.OnURLFetchComplete(fetcher);
405 EXPECT_TRUE(service.seed_stored());
406 EXPECT_EQ("test", service.stored_country());
409 TEST_F(VariationsServiceTest, Observer) {
410 TestingPrefServiceSimple prefs;
411 VariationsService::RegisterPrefs(prefs.registry());
412 VariationsService service(
413 make_scoped_ptr(new ChromeVariationsServiceClient()),
414 new web_resource::TestRequestAllowedNotifier(&prefs), &prefs, NULL);
416 struct {
417 int normal_count;
418 int best_effort_count;
419 int critical_count;
420 int expected_best_effort_notifications;
421 int expected_crtical_notifications;
422 } cases[] = {
423 {0, 0, 0, 0, 0},
424 {1, 0, 0, 0, 0},
425 {10, 0, 0, 0, 0},
426 {0, 1, 0, 1, 0},
427 {0, 10, 0, 1, 0},
428 {0, 0, 1, 0, 1},
429 {0, 0, 10, 0, 1},
430 {0, 1, 1, 0, 1},
431 {1, 1, 1, 0, 1},
432 {1, 1, 0, 1, 0},
433 {1, 0, 1, 0, 1},
436 for (size_t i = 0; i < arraysize(cases); ++i) {
437 TestVariationsServiceObserver observer;
438 service.AddObserver(&observer);
440 variations::VariationsSeedSimulator::Result result;
441 result.normal_group_change_count = cases[i].normal_count;
442 result.kill_best_effort_group_change_count = cases[i].best_effort_count;
443 result.kill_critical_group_change_count = cases[i].critical_count;
444 service.NotifyObservers(result);
446 EXPECT_EQ(cases[i].expected_best_effort_notifications,
447 observer.best_effort_changes_notified()) << i;
448 EXPECT_EQ(cases[i].expected_crtical_notifications,
449 observer.crticial_changes_notified()) << i;
451 service.RemoveObserver(&observer);
455 TEST_F(VariationsServiceTest, LoadPermanentConsistencyCountry) {
456 struct {
457 // Comma separated list, NULL if the pref isn't set initially.
458 const char* pref_value_before;
459 const char* version;
460 // NULL indicates that no latest country code is present.
461 const char* latest_country_code;
462 // Comma separated list.
463 const char* expected_pref_value_after;
464 std::string expected_country;
465 VariationsService::LoadPermanentConsistencyCountryResult expected_result;
466 } test_cases[] = {
467 // Existing pref value present for this version.
468 {"20.0.0.0,us", "20.0.0.0", "ca", "20.0.0.0,us", "us",
469 VariationsService::LOAD_COUNTRY_HAS_BOTH_VERSION_EQ_COUNTRY_NEQ},
470 {"20.0.0.0,us", "20.0.0.0", "us", "20.0.0.0,us", "us",
471 VariationsService::LOAD_COUNTRY_HAS_BOTH_VERSION_EQ_COUNTRY_EQ},
472 {"20.0.0.0,us", "20.0.0.0", nullptr, "20.0.0.0,us", "us",
473 VariationsService::LOAD_COUNTRY_HAS_PREF_NO_SEED_VERSION_EQ},
475 // Existing pref value present for a different version.
476 {"19.0.0.0,ca", "20.0.0.0", "us", "20.0.0.0,us", "us",
477 VariationsService::LOAD_COUNTRY_HAS_BOTH_VERSION_NEQ_COUNTRY_NEQ},
478 {"19.0.0.0,us", "20.0.0.0", "us", "20.0.0.0,us", "us",
479 VariationsService::LOAD_COUNTRY_HAS_BOTH_VERSION_NEQ_COUNTRY_EQ},
480 {"19.0.0.0,ca", "20.0.0.0", nullptr, "19.0.0.0,ca", "",
481 VariationsService::LOAD_COUNTRY_HAS_PREF_NO_SEED_VERSION_NEQ},
483 // No existing pref value present.
484 {nullptr, "20.0.0.0", "us", "20.0.0.0,us", "us",
485 VariationsService::LOAD_COUNTRY_NO_PREF_HAS_SEED},
486 {nullptr, "20.0.0.0", nullptr, "", "",
487 VariationsService::LOAD_COUNTRY_NO_PREF_NO_SEED},
488 {"", "20.0.0.0", "us", "20.0.0.0,us", "us",
489 VariationsService::LOAD_COUNTRY_NO_PREF_HAS_SEED},
490 {"", "20.0.0.0", nullptr, "", "",
491 VariationsService::LOAD_COUNTRY_NO_PREF_NO_SEED},
493 // Invalid existing pref value.
494 {"20.0.0.0", "20.0.0.0", "us", "20.0.0.0,us", "us",
495 VariationsService::LOAD_COUNTRY_INVALID_PREF_HAS_SEED},
496 {"20.0.0.0", "20.0.0.0", nullptr, "", "",
497 VariationsService::LOAD_COUNTRY_INVALID_PREF_NO_SEED},
498 {"20.0.0.0,us,element3", "20.0.0.0", "us", "20.0.0.0,us", "us",
499 VariationsService::LOAD_COUNTRY_INVALID_PREF_HAS_SEED},
500 {"20.0.0.0,us,element3", "20.0.0.0", nullptr, "", "",
501 VariationsService::LOAD_COUNTRY_INVALID_PREF_NO_SEED},
502 {"badversion,ca", "20.0.0.0", "us", "20.0.0.0,us", "us",
503 VariationsService::LOAD_COUNTRY_INVALID_PREF_HAS_SEED},
504 {"badversion,ca", "20.0.0.0", nullptr, "", "",
505 VariationsService::LOAD_COUNTRY_INVALID_PREF_NO_SEED},
508 for (const auto& test : test_cases) {
509 TestingPrefServiceSimple prefs;
510 VariationsService::RegisterPrefs(prefs.registry());
511 VariationsService service(
512 make_scoped_ptr(new ChromeVariationsServiceClient()),
513 new web_resource::TestRequestAllowedNotifier(&prefs), &prefs, NULL);
515 if (test.pref_value_before) {
516 base::ListValue list_value;
517 for (const std::string& component :
518 base::SplitString(test.pref_value_before, ",", base::TRIM_WHITESPACE,
519 base::SPLIT_WANT_ALL)) {
520 list_value.AppendString(component);
522 prefs.Set(prefs::kVariationsPermanentConsistencyCountry, list_value);
525 variations::VariationsSeed seed(CreateTestSeed());
526 std::string latest_country;
527 if (test.latest_country_code)
528 latest_country = test.latest_country_code;
530 base::HistogramTester histogram_tester;
531 EXPECT_EQ(test.expected_country,
532 service.LoadPermanentConsistencyCountry(
533 base::Version(test.version), latest_country))
534 << test.pref_value_before << ", " << test.version << ", "
535 << test.latest_country_code;
537 base::ListValue expected_list_value;
538 for (const std::string& component :
539 base::SplitString(test.expected_pref_value_after, ",",
540 base::TRIM_WHITESPACE, base::SPLIT_WANT_ALL)) {
541 expected_list_value.AppendString(component);
543 const base::ListValue* pref_value =
544 prefs.GetList(prefs::kVariationsPermanentConsistencyCountry);
545 EXPECT_EQ(ListValueToString(expected_list_value),
546 ListValueToString(*pref_value))
547 << test.pref_value_before << ", " << test.version << ", "
548 << test.latest_country_code;
550 histogram_tester.ExpectUniqueSample(
551 "Variations.LoadPermanentConsistencyCountryResult",
552 test.expected_result, 1);
556 } // namespace chrome_variations