Update V8 to version 4.6.22.
[chromium-blink-merge.git] / chrome / browser / metrics / variations / variations_service_unittest.cc
blobff08fedefc8b9a0d4d0d0a1a9c2cc9d0d8f28d65
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/prefs/testing_pref_service.h"
11 #include "base/sha1.h"
12 #include "base/strings/string_number_conversions.h"
13 #include "base/strings/string_split.h"
14 #include "base/strings/string_util.h"
15 #include "base/test/histogram_tester.h"
16 #include "base/version.h"
17 #include "chrome/common/pref_names.h"
18 #include "chrome/test/base/testing_browser_process.h"
19 #include "chrome/test/base/testing_pref_service_syncable.h"
20 #include "components/variations/proto/study.pb.h"
21 #include "components/variations/proto/variations_seed.pb.h"
22 #include "components/web_resource/resource_request_allowed_notifier_test_util.h"
23 #include "content/public/test/test_browser_thread.h"
24 #include "content/public/test/test_browser_thread_bundle.h"
25 #include "net/base/url_util.h"
26 #include "net/http/http_response_headers.h"
27 #include "net/http/http_status_code.h"
28 #include "net/url_request/test_url_fetcher_factory.h"
29 #include "testing/gtest/include/gtest/gtest.h"
31 #if defined(OS_CHROMEOS)
32 #include "chrome/browser/chromeos/settings/cros_settings.h"
33 #include "chrome/browser/chromeos/settings/device_settings_service.h"
34 #include "chrome/browser/chromeos/settings/stub_cros_settings_provider.h"
35 #endif
37 namespace chrome_variations {
39 namespace {
41 // A test class used to validate expected functionality in VariationsService.
42 class TestVariationsService : public VariationsService {
43 public:
44 TestVariationsService(web_resource::TestRequestAllowedNotifier* test_notifier,
45 PrefService* local_state)
46 : VariationsService(test_notifier, local_state, NULL),
47 intercepts_fetch_(true),
48 fetch_attempted_(false),
49 seed_stored_(false) {
50 // Set this so StartRepeatedVariationsSeedFetch can be called in tests.
51 SetCreateTrialsFromSeedCalledForTesting(true);
54 ~TestVariationsService() override {}
56 void set_intercepts_fetch(bool value) {
57 intercepts_fetch_ = value;
60 bool fetch_attempted() const { return fetch_attempted_; }
62 bool seed_stored() const { return seed_stored_; }
64 void DoActualFetch() override {
65 if (intercepts_fetch_) {
66 fetch_attempted_ = true;
67 return;
70 VariationsService::DoActualFetch();
73 protected:
74 void StoreSeed(const std::string& seed_data,
75 const std::string& seed_signature,
76 const base::Time& date_fetched) override {
77 seed_stored_ = true;
80 private:
81 bool intercepts_fetch_;
82 bool fetch_attempted_;
83 bool seed_stored_;
85 DISALLOW_COPY_AND_ASSIGN(TestVariationsService);
88 class TestVariationsServiceObserver : public VariationsService::Observer {
89 public:
90 TestVariationsServiceObserver()
91 : best_effort_changes_notified_(0),
92 crticial_changes_notified_(0) {
94 ~TestVariationsServiceObserver() override {}
96 void OnExperimentChangesDetected(Severity severity) override {
97 switch (severity) {
98 case BEST_EFFORT:
99 ++best_effort_changes_notified_;
100 break;
101 case CRITICAL:
102 ++crticial_changes_notified_;
103 break;
107 int best_effort_changes_notified() const {
108 return best_effort_changes_notified_;
111 int crticial_changes_notified() const {
112 return crticial_changes_notified_;
115 private:
116 // Number of notification received with BEST_EFFORT severity.
117 int best_effort_changes_notified_;
119 // Number of notification received with CRITICAL severity.
120 int crticial_changes_notified_;
122 DISALLOW_COPY_AND_ASSIGN(TestVariationsServiceObserver);
125 // Populates |seed| with simple test data. The resulting seed will contain one
126 // study called "test", which contains one experiment called "abc" with
127 // probability weight 100. |seed|'s study field will be cleared before adding
128 // the new study.
129 variations::VariationsSeed CreateTestSeed() {
130 variations::VariationsSeed seed;
131 variations::Study* study = seed.add_study();
132 study->set_name("test");
133 study->set_default_experiment_name("abc");
134 variations::Study_Experiment* experiment = study->add_experiment();
135 experiment->set_name("abc");
136 experiment->set_probability_weight(100);
137 seed.set_serial_number("123");
138 return seed;
141 // Serializes |seed| to protobuf binary format.
142 std::string SerializeSeed(const variations::VariationsSeed& seed) {
143 std::string serialized_seed;
144 seed.SerializeToString(&serialized_seed);
145 return serialized_seed;
148 // Simulates a variations service response by setting a date header and the
149 // specified HTTP |response_code| on |fetcher|.
150 void SimulateServerResponse(int response_code, net::TestURLFetcher* fetcher) {
151 ASSERT_TRUE(fetcher);
152 scoped_refptr<net::HttpResponseHeaders> headers(
153 new net::HttpResponseHeaders("date:Wed, 13 Feb 2013 00:25:24 GMT\0\0"));
154 fetcher->set_response_headers(headers);
155 fetcher->set_response_code(response_code);
158 // Helper class that abstracts away platform-specific details relating to the
159 // pref store used for the "restrict" param policy.
160 class TestVariationsPrefsStore {
161 public:
162 TestVariationsPrefsStore() {
163 #if defined(OS_ANDROID)
164 // Android uses profile prefs as the PrefService to generate the URL.
165 VariationsService::RegisterProfilePrefs(prefs_.registry());
166 #else
167 VariationsService::RegisterPrefs(prefs_.registry());
168 #endif
170 #if defined(OS_CHROMEOS)
171 cros_settings_ = chromeos::CrosSettings::Get();
172 DCHECK(cros_settings_ != NULL);
173 // Remove the real DeviceSettingsProvider and replace it with a stub that
174 // allows modifications in a test.
175 // TODO(asvitkine): Make a scoped helper class for this operation.
176 device_settings_provider_ = cros_settings_->GetProvider(
177 chromeos::kReportDeviceVersionInfo);
178 EXPECT_TRUE(device_settings_provider_ != NULL);
179 EXPECT_TRUE(cros_settings_->RemoveSettingsProvider(
180 device_settings_provider_));
181 cros_settings_->AddSettingsProvider(&stub_settings_provider_);
182 #endif
185 ~TestVariationsPrefsStore() {
186 #if defined(OS_CHROMEOS)
187 // Restore the real DeviceSettingsProvider.
188 EXPECT_TRUE(
189 cros_settings_->RemoveSettingsProvider(&stub_settings_provider_));
190 cros_settings_->AddSettingsProvider(device_settings_provider_);
191 #endif
194 void SetVariationsRestrictParameterPolicyValue(const std::string& value) {
195 #if defined(OS_CHROMEOS)
196 cros_settings_->SetString(chromeos::kVariationsRestrictParameter, value);
197 #else
198 prefs_.SetString(prefs::kVariationsRestrictParameter, value);
199 #endif
202 PrefService* prefs() { return &prefs_; }
204 private:
205 #if defined(OS_ANDROID)
206 // Android uses profile prefs as the PrefService to generate the URL.
207 TestingPrefServiceSyncable prefs_;
208 #else
209 TestingPrefServiceSimple prefs_;
210 #endif
212 #if defined(OS_CHROMEOS)
213 chromeos::CrosSettings* cros_settings_;
214 chromeos::StubCrosSettingsProvider stub_settings_provider_;
215 chromeos::CrosSettingsProvider* device_settings_provider_;
216 #endif
218 DISALLOW_COPY_AND_ASSIGN(TestVariationsPrefsStore);
221 } // namespace
223 class VariationsServiceTest : public ::testing::Test {
224 protected:
225 VariationsServiceTest() {}
227 private:
228 content::TestBrowserThreadBundle thread_bundle_;
229 #if defined(OS_CHROMEOS)
230 // Not used directly. Initializes CrosSettings for testing.
231 chromeos::ScopedTestDeviceSettingsService test_device_settings_service_;
232 chromeos::ScopedTestCrosSettings test_cros_settings_;
233 #endif
235 DISALLOW_COPY_AND_ASSIGN(VariationsServiceTest);
238 TEST_F(VariationsServiceTest, GetVariationsServerURL) {
239 TestVariationsPrefsStore prefs_store;
240 PrefService* prefs = prefs_store.prefs();
241 const std::string default_variations_url =
242 VariationsService::GetDefaultVariationsServerURLForTesting();
244 std::string value;
245 GURL url = VariationsService::GetVariationsServerURL(prefs, std::string());
246 EXPECT_TRUE(base::StartsWith(url.spec(), default_variations_url,
247 base::CompareCase::SENSITIVE));
248 EXPECT_FALSE(net::GetValueForKeyInQuery(url, "restrict", &value));
250 prefs_store.SetVariationsRestrictParameterPolicyValue("restricted");
251 url = VariationsService::GetVariationsServerURL(prefs, std::string());
252 EXPECT_TRUE(base::StartsWith(url.spec(), default_variations_url,
253 base::CompareCase::SENSITIVE));
254 EXPECT_TRUE(net::GetValueForKeyInQuery(url, "restrict", &value));
255 EXPECT_EQ("restricted", value);
257 // The override value should take precedence over what's in prefs.
258 url = VariationsService::GetVariationsServerURL(prefs, "override");
259 EXPECT_TRUE(base::StartsWith(url.spec(), default_variations_url,
260 base::CompareCase::SENSITIVE));
261 EXPECT_TRUE(net::GetValueForKeyInQuery(url, "restrict", &value));
262 EXPECT_EQ("override", value);
265 TEST_F(VariationsServiceTest, VariationsURLHasOSNameParam) {
266 TestingPrefServiceSimple prefs;
267 VariationsService::RegisterPrefs(prefs.registry());
268 const GURL url =
269 VariationsService::GetVariationsServerURL(&prefs, std::string());
271 std::string value;
272 EXPECT_TRUE(net::GetValueForKeyInQuery(url, "osname", &value));
273 EXPECT_FALSE(value.empty());
276 TEST_F(VariationsServiceTest, RequestsInitiallyNotAllowed) {
277 TestingPrefServiceSimple prefs;
278 VariationsService::RegisterPrefs(prefs.registry());
280 // Pass ownership to TestVariationsService, but keep a weak pointer to
281 // manipulate it for this test.
282 web_resource::TestRequestAllowedNotifier* test_notifier =
283 new web_resource::TestRequestAllowedNotifier(&prefs);
284 TestVariationsService test_service(test_notifier, &prefs);
286 // Force the notifier to initially disallow requests.
287 test_notifier->SetRequestsAllowedOverride(false);
288 test_service.StartRepeatedVariationsSeedFetch();
289 EXPECT_FALSE(test_service.fetch_attempted());
291 test_notifier->NotifyObserver();
292 EXPECT_TRUE(test_service.fetch_attempted());
295 TEST_F(VariationsServiceTest, RequestsInitiallyAllowed) {
296 TestingPrefServiceSimple prefs;
297 VariationsService::RegisterPrefs(prefs.registry());
299 // Pass ownership to TestVariationsService, but keep a weak pointer to
300 // manipulate it for this test.
301 web_resource::TestRequestAllowedNotifier* test_notifier =
302 new web_resource::TestRequestAllowedNotifier(&prefs);
303 TestVariationsService test_service(test_notifier, &prefs);
305 test_notifier->SetRequestsAllowedOverride(true);
306 test_service.StartRepeatedVariationsSeedFetch();
307 EXPECT_TRUE(test_service.fetch_attempted());
310 TEST_F(VariationsServiceTest, SeedStoredWhenOKStatus) {
311 TestingPrefServiceSimple prefs;
312 VariationsService::RegisterPrefs(prefs.registry());
314 TestVariationsService service(
315 new web_resource::TestRequestAllowedNotifier(&prefs), &prefs);
316 service.variations_server_url_ =
317 VariationsService::GetVariationsServerURL(&prefs, std::string());
318 service.set_intercepts_fetch(false);
320 net::TestURLFetcherFactory factory;
321 service.DoActualFetch();
323 net::TestURLFetcher* fetcher = factory.GetFetcherByID(0);
324 SimulateServerResponse(net::HTTP_OK, fetcher);
325 fetcher->SetResponseString(SerializeSeed(CreateTestSeed()));
327 EXPECT_FALSE(service.seed_stored());
328 service.OnURLFetchComplete(fetcher);
329 EXPECT_TRUE(service.seed_stored());
332 TEST_F(VariationsServiceTest, SeedNotStoredWhenNonOKStatus) {
333 const int non_ok_status_codes[] = {
334 net::HTTP_NO_CONTENT,
335 net::HTTP_NOT_MODIFIED,
336 net::HTTP_NOT_FOUND,
337 net::HTTP_INTERNAL_SERVER_ERROR,
338 net::HTTP_SERVICE_UNAVAILABLE,
341 TestingPrefServiceSimple prefs;
342 VariationsService::RegisterPrefs(prefs.registry());
344 VariationsService service(
345 new web_resource::TestRequestAllowedNotifier(&prefs), &prefs, NULL);
346 service.variations_server_url_ =
347 VariationsService::GetVariationsServerURL(&prefs, std::string());
348 for (size_t i = 0; i < arraysize(non_ok_status_codes); ++i) {
349 net::TestURLFetcherFactory factory;
350 service.DoActualFetch();
351 EXPECT_TRUE(prefs.FindPreference(prefs::kVariationsSeed)->IsDefaultValue());
353 net::TestURLFetcher* fetcher = factory.GetFetcherByID(0);
354 SimulateServerResponse(non_ok_status_codes[i], fetcher);
355 service.OnURLFetchComplete(fetcher);
357 EXPECT_TRUE(prefs.FindPreference(prefs::kVariationsSeed)->IsDefaultValue());
361 TEST_F(VariationsServiceTest, SeedDateUpdatedOn304Status) {
362 TestingPrefServiceSimple prefs;
363 VariationsService::RegisterPrefs(prefs.registry());
365 net::TestURLFetcherFactory factory;
366 VariationsService service(
367 new web_resource::TestRequestAllowedNotifier(&prefs), &prefs, NULL);
368 service.variations_server_url_ =
369 VariationsService::GetVariationsServerURL(&prefs, std::string());
370 service.DoActualFetch();
371 EXPECT_TRUE(
372 prefs.FindPreference(prefs::kVariationsSeedDate)->IsDefaultValue());
374 net::TestURLFetcher* fetcher = factory.GetFetcherByID(0);
375 SimulateServerResponse(net::HTTP_NOT_MODIFIED, fetcher);
376 service.OnURLFetchComplete(fetcher);
377 EXPECT_FALSE(
378 prefs.FindPreference(prefs::kVariationsSeedDate)->IsDefaultValue());
381 TEST_F(VariationsServiceTest, Observer) {
382 TestingPrefServiceSimple prefs;
383 VariationsService::RegisterPrefs(prefs.registry());
384 VariationsService service(
385 new web_resource::TestRequestAllowedNotifier(&prefs), &prefs, NULL);
387 struct {
388 int normal_count;
389 int best_effort_count;
390 int critical_count;
391 int expected_best_effort_notifications;
392 int expected_crtical_notifications;
393 } cases[] = {
394 {0, 0, 0, 0, 0},
395 {1, 0, 0, 0, 0},
396 {10, 0, 0, 0, 0},
397 {0, 1, 0, 1, 0},
398 {0, 10, 0, 1, 0},
399 {0, 0, 1, 0, 1},
400 {0, 0, 10, 0, 1},
401 {0, 1, 1, 0, 1},
402 {1, 1, 1, 0, 1},
403 {1, 1, 0, 1, 0},
404 {1, 0, 1, 0, 1},
407 for (size_t i = 0; i < arraysize(cases); ++i) {
408 TestVariationsServiceObserver observer;
409 service.AddObserver(&observer);
411 variations::VariationsSeedSimulator::Result result;
412 result.normal_group_change_count = cases[i].normal_count;
413 result.kill_best_effort_group_change_count = cases[i].best_effort_count;
414 result.kill_critical_group_change_count = cases[i].critical_count;
415 service.NotifyObservers(result);
417 EXPECT_EQ(cases[i].expected_best_effort_notifications,
418 observer.best_effort_changes_notified()) << i;
419 EXPECT_EQ(cases[i].expected_crtical_notifications,
420 observer.crticial_changes_notified()) << i;
422 service.RemoveObserver(&observer);
426 TEST_F(VariationsServiceTest, LoadPermanentConsistencyCountry) {
427 struct {
428 // Comma separated list, NULL if the pref isn't set initially.
429 const char* pref_value_before;
430 const char* version;
431 // NULL indicates that no country code is present in the seed.
432 const char* seed_country_code;
433 // Comma separated list.
434 const char* expected_pref_value_after;
435 std::string expected_country;
436 VariationsService::LoadPermanentConsistencyCountryResult expected_result;
437 } test_cases[] = {
438 // Existing pref value present for this version.
439 {"20.0.0.0,us", "20.0.0.0", "ca", "20.0.0.0,us", "us",
440 VariationsService::LOAD_COUNTRY_HAS_BOTH_VERSION_EQ_COUNTRY_NEQ},
441 {"20.0.0.0,us", "20.0.0.0", "us", "20.0.0.0,us", "us",
442 VariationsService::LOAD_COUNTRY_HAS_BOTH_VERSION_EQ_COUNTRY_EQ},
443 {"20.0.0.0,us", "20.0.0.0", nullptr, "20.0.0.0,us", "us",
444 VariationsService::LOAD_COUNTRY_HAS_PREF_NO_SEED_VERSION_EQ},
446 // Existing pref value present for a different version.
447 {"19.0.0.0,ca", "20.0.0.0", "us", "20.0.0.0,us", "us",
448 VariationsService::LOAD_COUNTRY_HAS_BOTH_VERSION_NEQ_COUNTRY_NEQ},
449 {"19.0.0.0,us", "20.0.0.0", "us", "20.0.0.0,us", "us",
450 VariationsService::LOAD_COUNTRY_HAS_BOTH_VERSION_NEQ_COUNTRY_EQ},
451 {"19.0.0.0,ca", "20.0.0.0", nullptr, "", "",
452 VariationsService::LOAD_COUNTRY_HAS_PREF_NO_SEED_VERSION_NEQ},
454 // No existing pref value present.
455 {nullptr, "20.0.0.0", "us", "20.0.0.0,us", "us",
456 VariationsService::LOAD_COUNTRY_NO_PREF_HAS_SEED},
457 {nullptr, "20.0.0.0", nullptr, "", "",
458 VariationsService::LOAD_COUNTRY_NO_PREF_NO_SEED},
459 {"", "20.0.0.0", "us", "20.0.0.0,us", "us",
460 VariationsService::LOAD_COUNTRY_NO_PREF_HAS_SEED},
461 {"", "20.0.0.0", nullptr, "", "",
462 VariationsService::LOAD_COUNTRY_NO_PREF_NO_SEED},
464 // Invalid existing pref value.
465 {"20.0.0.0", "20.0.0.0", "us", "20.0.0.0,us", "us",
466 VariationsService::LOAD_COUNTRY_INVALID_PREF_HAS_SEED},
467 {"20.0.0.0", "20.0.0.0", nullptr, "", "",
468 VariationsService::LOAD_COUNTRY_INVALID_PREF_NO_SEED},
469 {"20.0.0.0,us,element3", "20.0.0.0", "us", "20.0.0.0,us", "us",
470 VariationsService::LOAD_COUNTRY_INVALID_PREF_HAS_SEED},
471 {"20.0.0.0,us,element3", "20.0.0.0", nullptr, "", "",
472 VariationsService::LOAD_COUNTRY_INVALID_PREF_NO_SEED},
473 {"badversion,ca", "20.0.0.0", "us", "20.0.0.0,us", "us",
474 VariationsService::LOAD_COUNTRY_INVALID_PREF_HAS_SEED},
475 {"badversion,ca", "20.0.0.0", nullptr, "", "",
476 VariationsService::LOAD_COUNTRY_INVALID_PREF_NO_SEED},
479 for (const auto& test : test_cases) {
480 TestingPrefServiceSimple prefs;
481 VariationsService::RegisterPrefs(prefs.registry());
482 VariationsService service(
483 new web_resource::TestRequestAllowedNotifier(&prefs), &prefs, NULL);
485 if (test.pref_value_before) {
486 base::ListValue list_value;
487 for (const std::string& component : base::SplitString(
488 test.pref_value_before, ",",
489 base::TRIM_WHITESPACE, base::SPLIT_WANT_ALL))
490 list_value.AppendString(component);
491 prefs.Set(prefs::kVariationsPermanentConsistencyCountry, list_value);
494 variations::VariationsSeed seed(CreateTestSeed());
495 if (test.seed_country_code)
496 seed.set_country_code(test.seed_country_code);
498 base::HistogramTester histogram_tester;
499 EXPECT_EQ(test.expected_country, service.LoadPermanentConsistencyCountry(
500 base::Version(test.version), seed));
502 base::ListValue expected_list_value;
503 for (const std::string& component : base::SplitString(
504 test.expected_pref_value_after, ",",
505 base::TRIM_WHITESPACE, base::SPLIT_WANT_ALL))
506 expected_list_value.AppendString(component);
507 EXPECT_TRUE(expected_list_value.Equals(
508 prefs.GetList(prefs::kVariationsPermanentConsistencyCountry)));
510 histogram_tester.ExpectUniqueSample(
511 "Variations.LoadPermanentConsistencyCountryResult",
512 test.expected_result, 1);
516 } // namespace chrome_variations