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 ~TestVariationsService() override {}
52 void set_intercepts_fetch(bool value) {
53 intercepts_fetch_ = value;
56 bool fetch_attempted() const { return fetch_attempted_; }
58 bool seed_stored() const { return seed_stored_; }
60 void DoActualFetch() override {
61 if (intercepts_fetch_) {
62 fetch_attempted_ = true;
66 VariationsService::DoActualFetch();
70 void StoreSeed(const std::string& seed_data,
71 const std::string& seed_signature,
72 const base::Time& date_fetched) override {
77 bool intercepts_fetch_;
78 bool fetch_attempted_;
81 DISALLOW_COPY_AND_ASSIGN(TestVariationsService);
84 class TestVariationsServiceObserver : public VariationsService::Observer {
86 TestVariationsServiceObserver()
87 : best_effort_changes_notified_(0),
88 crticial_changes_notified_(0) {
90 ~TestVariationsServiceObserver() override {}
92 void OnExperimentChangesDetected(Severity severity) override {
95 ++best_effort_changes_notified_;
98 ++crticial_changes_notified_;
103 int best_effort_changes_notified() const {
104 return best_effort_changes_notified_;
107 int crticial_changes_notified() const {
108 return crticial_changes_notified_;
112 // Number of notification received with BEST_EFFORT severity.
113 int best_effort_changes_notified_;
115 // Number of notification received with CRITICAL severity.
116 int crticial_changes_notified_;
118 DISALLOW_COPY_AND_ASSIGN(TestVariationsServiceObserver);
121 // Populates |seed| with simple test data. The resulting seed will contain one
122 // study called "test", which contains one experiment called "abc" with
123 // probability weight 100. |seed|'s study field will be cleared before adding
125 variations::VariationsSeed CreateTestSeed() {
126 variations::VariationsSeed seed;
127 variations::Study* study = seed.add_study();
128 study->set_name("test");
129 study->set_default_experiment_name("abc");
130 variations::Study_Experiment* experiment = study->add_experiment();
131 experiment->set_name("abc");
132 experiment->set_probability_weight(100);
133 seed.set_serial_number("123");
137 // Serializes |seed| to protobuf binary format.
138 std::string SerializeSeed(const variations::VariationsSeed& seed) {
139 std::string serialized_seed;
140 seed.SerializeToString(&serialized_seed);
141 return serialized_seed;
144 // Simulates a variations service response by setting a date header and the
145 // specified HTTP |response_code| on |fetcher|.
146 void SimulateServerResponse(int response_code, net::TestURLFetcher* fetcher) {
147 ASSERT_TRUE(fetcher);
148 scoped_refptr<net::HttpResponseHeaders> headers(
149 new net::HttpResponseHeaders("date:Wed, 13 Feb 2013 00:25:24 GMT\0\0"));
150 fetcher->set_response_headers(headers);
151 fetcher->set_response_code(response_code);
156 class VariationsServiceTest : public ::testing::Test {
158 VariationsServiceTest() {}
161 #if defined(OS_CHROMEOS)
162 // Not used directly. Initializes CrosSettings for testing.
163 chromeos::ScopedTestDeviceSettingsService test_device_settings_service_;
164 chromeos::ScopedTestCrosSettings test_cros_settings_;
167 DISALLOW_COPY_AND_ASSIGN(VariationsServiceTest);
170 #if !defined(OS_CHROMEOS)
171 TEST_F(VariationsServiceTest, VariationsURLIsValid) {
172 #if defined(OS_ANDROID)
173 // Android uses profile prefs as the PrefService to generate the URL.
174 TestingPrefServiceSyncable prefs;
175 VariationsService::RegisterProfilePrefs(prefs.registry());
177 TestingPrefServiceSimple prefs;
178 VariationsService::RegisterPrefs(prefs.registry());
180 const std::string default_variations_url =
181 VariationsService::GetDefaultVariationsServerURLForTesting();
184 GURL url = VariationsService::GetVariationsServerURL(&prefs);
185 EXPECT_TRUE(StartsWithASCII(url.spec(), default_variations_url, true));
186 EXPECT_FALSE(net::GetValueForKeyInQuery(url, "restrict", &value));
188 prefs.SetString(prefs::kVariationsRestrictParameter, "restricted");
189 url = VariationsService::GetVariationsServerURL(&prefs);
190 EXPECT_TRUE(StartsWithASCII(url.spec(), default_variations_url, true));
191 EXPECT_TRUE(net::GetValueForKeyInQuery(url, "restrict", &value));
192 EXPECT_EQ("restricted", value);
195 class VariationsServiceTestChromeOS : public VariationsServiceTest {
197 VariationsServiceTestChromeOS() {}
199 virtual void SetUp() override {
200 cros_settings_ = chromeos::CrosSettings::Get();
201 DCHECK(cros_settings_ != NULL);
202 // Remove the real DeviceSettingsProvider and replace it with a stub that
203 // allows modifications in a test.
204 device_settings_provider_ = cros_settings_->GetProvider(
205 chromeos::kReportDeviceVersionInfo);
206 EXPECT_TRUE(device_settings_provider_ != NULL);
207 EXPECT_TRUE(cros_settings_->RemoveSettingsProvider(
208 device_settings_provider_));
209 cros_settings_->AddSettingsProvider(&stub_settings_provider_);
212 virtual void TearDown() override {
213 // Restore the real DeviceSettingsProvider.
215 cros_settings_->RemoveSettingsProvider(&stub_settings_provider_));
216 cros_settings_->AddSettingsProvider(device_settings_provider_);
219 void SetVariationsRestrictParameterPolicyValue(std::string value) {
220 cros_settings_->SetString(chromeos::kVariationsRestrictParameter, value);
224 chromeos::CrosSettings* cros_settings_;
225 chromeos::StubCrosSettingsProvider stub_settings_provider_;
226 chromeos::CrosSettingsProvider* device_settings_provider_;
228 DISALLOW_COPY_AND_ASSIGN(VariationsServiceTestChromeOS);
231 TEST_F(VariationsServiceTestChromeOS, VariationsURLIsValid) {
232 TestingPrefServiceSimple prefs;
233 VariationsService::RegisterPrefs(prefs.registry());
234 const std::string default_variations_url =
235 VariationsService::GetDefaultVariationsServerURLForTesting();
238 GURL url = VariationsService::GetVariationsServerURL(&prefs);
239 EXPECT_TRUE(StartsWithASCII(url.spec(), default_variations_url, true));
240 EXPECT_FALSE(net::GetValueForKeyInQuery(url, "restrict", &value));
242 SetVariationsRestrictParameterPolicyValue("restricted");
243 url = VariationsService::GetVariationsServerURL(&prefs);
244 EXPECT_TRUE(StartsWithASCII(url.spec(), default_variations_url, true));
245 EXPECT_TRUE(net::GetValueForKeyInQuery(url, "restrict", &value));
246 EXPECT_EQ("restricted", value);
250 TEST_F(VariationsServiceTest, VariationsURLHasOSNameParam) {
251 TestingPrefServiceSimple prefs;
252 VariationsService::RegisterPrefs(prefs.registry());
253 const GURL url = VariationsService::GetVariationsServerURL(&prefs);
256 EXPECT_TRUE(net::GetValueForKeyInQuery(url, "osname", &value));
257 EXPECT_FALSE(value.empty());
260 TEST_F(VariationsServiceTest, RequestsInitiallyNotAllowed) {
261 base::MessageLoopForUI message_loop;
262 content::TestBrowserThread ui_thread(content::BrowserThread::UI,
264 TestingPrefServiceSimple prefs;
265 VariationsService::RegisterPrefs(prefs.registry());
267 // Pass ownership to TestVariationsService, but keep a weak pointer to
268 // manipulate it for this test.
269 TestRequestAllowedNotifier* test_notifier = new TestRequestAllowedNotifier;
270 TestVariationsService test_service(test_notifier, &prefs);
272 // Force the notifier to initially disallow requests.
273 test_notifier->SetRequestsAllowedOverride(false);
274 test_service.StartRepeatedVariationsSeedFetch();
275 EXPECT_FALSE(test_service.fetch_attempted());
277 test_notifier->NotifyObserver();
278 EXPECT_TRUE(test_service.fetch_attempted());
281 TEST_F(VariationsServiceTest, RequestsInitiallyAllowed) {
282 base::MessageLoopForUI message_loop;
283 content::TestBrowserThread ui_thread(content::BrowserThread::UI,
285 TestingPrefServiceSimple prefs;
286 VariationsService::RegisterPrefs(prefs.registry());
288 // Pass ownership to TestVariationsService, but keep a weak pointer to
289 // manipulate it for this test.
290 TestRequestAllowedNotifier* test_notifier = new TestRequestAllowedNotifier;
291 TestVariationsService test_service(test_notifier, &prefs);
293 test_notifier->SetRequestsAllowedOverride(true);
294 test_service.StartRepeatedVariationsSeedFetch();
295 EXPECT_TRUE(test_service.fetch_attempted());
298 TEST_F(VariationsServiceTest, SeedStoredWhenOKStatus) {
299 base::MessageLoop message_loop;
300 content::TestBrowserThread io_thread(content::BrowserThread::IO,
302 TestingPrefServiceSimple prefs;
303 VariationsService::RegisterPrefs(prefs.registry());
305 TestVariationsService service(new TestRequestAllowedNotifier, &prefs);
306 service.set_intercepts_fetch(false);
308 net::TestURLFetcherFactory factory;
309 service.DoActualFetch();
311 net::TestURLFetcher* fetcher = factory.GetFetcherByID(0);
312 SimulateServerResponse(net::HTTP_OK, fetcher);
313 fetcher->SetResponseString(SerializeSeed(CreateTestSeed()));
315 EXPECT_FALSE(service.seed_stored());
316 service.OnURLFetchComplete(fetcher);
317 EXPECT_TRUE(service.seed_stored());
320 TEST_F(VariationsServiceTest, SeedNotStoredWhenNonOKStatus) {
321 const int non_ok_status_codes[] = {
322 net::HTTP_NO_CONTENT,
323 net::HTTP_NOT_MODIFIED,
325 net::HTTP_INTERNAL_SERVER_ERROR,
326 net::HTTP_SERVICE_UNAVAILABLE,
329 base::MessageLoop message_loop;
330 content::TestBrowserThread io_thread(content::BrowserThread::IO,
332 TestingPrefServiceSimple prefs;
333 VariationsService::RegisterPrefs(prefs.registry());
335 VariationsService service(new TestRequestAllowedNotifier, &prefs, NULL);
336 for (size_t i = 0; i < arraysize(non_ok_status_codes); ++i) {
337 net::TestURLFetcherFactory factory;
338 service.DoActualFetch();
339 EXPECT_TRUE(prefs.FindPreference(prefs::kVariationsSeed)->IsDefaultValue());
341 net::TestURLFetcher* fetcher = factory.GetFetcherByID(0);
342 SimulateServerResponse(non_ok_status_codes[i], fetcher);
343 service.OnURLFetchComplete(fetcher);
345 EXPECT_TRUE(prefs.FindPreference(prefs::kVariationsSeed)->IsDefaultValue());
349 TEST_F(VariationsServiceTest, SeedDateUpdatedOn304Status) {
350 base::MessageLoop message_loop;
351 content::TestBrowserThread io_thread(content::BrowserThread::IO,
353 TestingPrefServiceSimple prefs;
354 VariationsService::RegisterPrefs(prefs.registry());
356 VariationsService service(new TestRequestAllowedNotifier, &prefs, NULL);
357 net::TestURLFetcherFactory factory;
358 service.DoActualFetch();
360 prefs.FindPreference(prefs::kVariationsSeedDate)->IsDefaultValue());
362 net::TestURLFetcher* fetcher = factory.GetFetcherByID(0);
363 SimulateServerResponse(net::HTTP_NOT_MODIFIED, fetcher);
364 service.OnURLFetchComplete(fetcher);
366 prefs.FindPreference(prefs::kVariationsSeedDate)->IsDefaultValue());
369 TEST_F(VariationsServiceTest, Observer) {
370 TestingPrefServiceSimple prefs;
371 VariationsService::RegisterPrefs(prefs.registry());
372 VariationsService service(new TestRequestAllowedNotifier, &prefs, NULL);
376 int best_effort_count;
378 int expected_best_effort_notifications;
379 int expected_crtical_notifications;
394 for (size_t i = 0; i < arraysize(cases); ++i) {
395 TestVariationsServiceObserver observer;
396 service.AddObserver(&observer);
398 variations::VariationsSeedSimulator::Result result;
399 result.normal_group_change_count = cases[i].normal_count;
400 result.kill_best_effort_group_change_count = cases[i].best_effort_count;
401 result.kill_critical_group_change_count = cases[i].critical_count;
402 service.NotifyObservers(result);
404 EXPECT_EQ(cases[i].expected_best_effort_notifications,
405 observer.best_effort_changes_notified()) << i;
406 EXPECT_EQ(cases[i].expected_crtical_notifications,
407 observer.crticial_changes_notified()) << i;
409 service.RemoveObserver(&observer);
413 } // namespace chrome_variations