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),
43 fetch_attempted_(false) {
44 // Set this so StartRepeatedVariationsSeedFetch can be called in tests.
45 SetCreateTrialsFromSeedCalledForTesting(true);
48 virtual ~TestVariationsService() {
51 bool fetch_attempted() const { return fetch_attempted_; }
54 virtual void DoActualFetch() OVERRIDE {
55 fetch_attempted_ = true;
59 bool fetch_attempted_;
61 DISALLOW_COPY_AND_ASSIGN(TestVariationsService);
64 // Populates |seed| with simple test data. The resulting seed will contain one
65 // study called "test", which contains one experiment called "abc" with
66 // probability weight 100. |seed|'s study field will be cleared before adding
68 VariationsSeed CreateTestSeed() {
70 Study* study = seed.add_study();
71 study->set_name("test");
72 study->set_default_experiment_name("abc");
73 Study_Experiment* experiment = study->add_experiment();
74 experiment->set_name("abc");
75 experiment->set_probability_weight(100);
76 seed.set_serial_number("123");
80 // Serializes |seed| to protobuf binary format.
81 std::string SerializeSeed(const VariationsSeed& seed) {
82 std::string serialized_seed;
83 seed.SerializeToString(&serialized_seed);
84 return serialized_seed;
87 // Serializes |seed| to base64-encoded protobuf binary format.
88 std::string SerializeSeedBase64(const VariationsSeed& seed, std::string* hash) {
89 std::string serialized_seed = SerializeSeed(seed);
91 std::string sha1 = base::SHA1HashString(serialized_seed);
92 *hash = base::HexEncode(sha1.data(), sha1.size());
94 std::string base64_serialized_seed;
95 base::Base64Encode(serialized_seed, &base64_serialized_seed);
96 return base64_serialized_seed;
99 // Simulates a variations service response by setting a date header and the
100 // specified HTTP |response_code| on |fetcher|.
101 void SimulateServerResponse(int response_code, net::TestURLFetcher* fetcher) {
102 ASSERT_TRUE(fetcher);
103 scoped_refptr<net::HttpResponseHeaders> headers(
104 new net::HttpResponseHeaders("date:Wed, 13 Feb 2013 00:25:24 GMT\0\0"));
105 fetcher->set_response_headers(headers);
106 fetcher->set_response_code(response_code);
111 class VariationsServiceTest : public ::testing::Test {
113 VariationsServiceTest() {}
116 #if defined(OS_CHROMEOS)
117 // Not used directly. Initializes CrosSettings for testing.
118 chromeos::ScopedTestDeviceSettingsService test_device_settings_service_;
119 chromeos::ScopedTestCrosSettings test_cros_settings_;
122 DISALLOW_COPY_AND_ASSIGN(VariationsServiceTest);
125 #if !defined(OS_CHROMEOS)
126 TEST_F(VariationsServiceTest, VariationsURLIsValid) {
127 #if defined(OS_ANDROID)
128 // Android uses profile prefs as the PrefService to generate the URL.
129 TestingPrefServiceSyncable prefs;
130 VariationsService::RegisterProfilePrefs(prefs.registry());
132 TestingPrefServiceSimple prefs;
133 VariationsService::RegisterPrefs(prefs.registry());
135 const std::string default_variations_url =
136 VariationsService::GetDefaultVariationsServerURLForTesting();
139 GURL url = VariationsService::GetVariationsServerURL(&prefs);
140 EXPECT_TRUE(StartsWithASCII(url.spec(), default_variations_url, true));
141 EXPECT_FALSE(net::GetValueForKeyInQuery(url, "restrict", &value));
143 prefs.SetString(prefs::kVariationsRestrictParameter, "restricted");
144 url = VariationsService::GetVariationsServerURL(&prefs);
145 EXPECT_TRUE(StartsWithASCII(url.spec(), default_variations_url, true));
146 EXPECT_TRUE(net::GetValueForKeyInQuery(url, "restrict", &value));
147 EXPECT_EQ("restricted", value);
150 class VariationsServiceTestChromeOS : public VariationsServiceTest {
152 VariationsServiceTestChromeOS() {}
154 virtual void SetUp() OVERRIDE {
155 cros_settings_ = chromeos::CrosSettings::Get();
156 DCHECK(cros_settings_ != NULL);
157 // Remove the real DeviceSettingsProvider and replace it with a stub that
158 // allows modifications in a test.
159 device_settings_provider_ = cros_settings_->GetProvider(
160 chromeos::kReportDeviceVersionInfo);
161 EXPECT_TRUE(device_settings_provider_ != NULL);
162 EXPECT_TRUE(cros_settings_->RemoveSettingsProvider(
163 device_settings_provider_));
164 cros_settings_->AddSettingsProvider(&stub_settings_provider_);
167 virtual void TearDown() OVERRIDE {
168 // Restore the real DeviceSettingsProvider.
170 cros_settings_->RemoveSettingsProvider(&stub_settings_provider_));
171 cros_settings_->AddSettingsProvider(device_settings_provider_);
174 void SetVariationsRestrictParameterPolicyValue(std::string value) {
175 cros_settings_->SetString(chromeos::kVariationsRestrictParameter, value);
179 chromeos::CrosSettings* cros_settings_;
180 chromeos::StubCrosSettingsProvider stub_settings_provider_;
181 chromeos::CrosSettingsProvider* device_settings_provider_;
183 DISALLOW_COPY_AND_ASSIGN(VariationsServiceTestChromeOS);
186 TEST_F(VariationsServiceTestChromeOS, VariationsURLIsValid) {
187 TestingPrefServiceSimple prefs;
188 VariationsService::RegisterPrefs(prefs.registry());
189 const std::string default_variations_url =
190 VariationsService::GetDefaultVariationsServerURLForTesting();
193 GURL url = VariationsService::GetVariationsServerURL(&prefs);
194 EXPECT_TRUE(StartsWithASCII(url.spec(), default_variations_url, true));
195 EXPECT_FALSE(net::GetValueForKeyInQuery(url, "restrict", &value));
197 SetVariationsRestrictParameterPolicyValue("restricted");
198 url = VariationsService::GetVariationsServerURL(&prefs);
199 EXPECT_TRUE(StartsWithASCII(url.spec(), default_variations_url, true));
200 EXPECT_TRUE(net::GetValueForKeyInQuery(url, "restrict", &value));
201 EXPECT_EQ("restricted", value);
205 TEST_F(VariationsServiceTest, VariationsURLHasOSNameParam) {
206 TestingPrefServiceSimple prefs;
207 VariationsService::RegisterPrefs(prefs.registry());
208 const GURL url = VariationsService::GetVariationsServerURL(&prefs);
211 EXPECT_TRUE(net::GetValueForKeyInQuery(url, "osname", &value));
212 EXPECT_FALSE(value.empty());
215 TEST_F(VariationsServiceTest, RequestsInitiallyNotAllowed) {
216 base::MessageLoopForUI message_loop;
217 content::TestBrowserThread ui_thread(content::BrowserThread::UI,
219 TestingPrefServiceSimple prefs;
220 VariationsService::RegisterPrefs(prefs.registry());
222 // Pass ownership to TestVariationsService, but keep a weak pointer to
223 // manipulate it for this test.
224 TestRequestAllowedNotifier* test_notifier = new TestRequestAllowedNotifier;
225 TestVariationsService test_service(test_notifier, &prefs);
227 // Force the notifier to initially disallow requests.
228 test_notifier->SetRequestsAllowedOverride(false);
229 test_service.StartRepeatedVariationsSeedFetch();
230 EXPECT_FALSE(test_service.fetch_attempted());
232 test_notifier->NotifyObserver();
233 EXPECT_TRUE(test_service.fetch_attempted());
236 TEST_F(VariationsServiceTest, RequestsInitiallyAllowed) {
237 base::MessageLoopForUI message_loop;
238 content::TestBrowserThread ui_thread(content::BrowserThread::UI,
240 TestingPrefServiceSimple prefs;
241 VariationsService::RegisterPrefs(prefs.registry());
243 // Pass ownership to TestVariationsService, but keep a weak pointer to
244 // manipulate it for this test.
245 TestRequestAllowedNotifier* test_notifier = new TestRequestAllowedNotifier;
246 TestVariationsService test_service(test_notifier, &prefs);
248 test_notifier->SetRequestsAllowedOverride(true);
249 test_service.StartRepeatedVariationsSeedFetch();
250 EXPECT_TRUE(test_service.fetch_attempted());
253 TEST_F(VariationsServiceTest, SeedStoredWhenOKStatus) {
254 base::MessageLoop message_loop;
255 content::TestBrowserThread io_thread(content::BrowserThread::IO,
257 TestingPrefServiceSimple prefs;
258 VariationsService::RegisterPrefs(prefs.registry());
260 VariationsService variations_service(new TestRequestAllowedNotifier, &prefs);
262 net::TestURLFetcherFactory factory;
263 variations_service.DoActualFetch();
265 net::TestURLFetcher* fetcher = factory.GetFetcherByID(0);
266 SimulateServerResponse(net::HTTP_OK, fetcher);
267 const VariationsSeed seed = CreateTestSeed();
268 fetcher->SetResponseString(SerializeSeed(seed));
270 EXPECT_TRUE(prefs.FindPreference(prefs::kVariationsSeed)->IsDefaultValue());
271 variations_service.OnURLFetchComplete(fetcher);
272 EXPECT_FALSE(prefs.FindPreference(prefs::kVariationsSeed)->IsDefaultValue());
273 const std::string expected_base64 = SerializeSeedBase64(seed, NULL);
274 EXPECT_EQ(expected_base64, prefs.GetString(prefs::kVariationsSeed));
277 TEST_F(VariationsServiceTest, SeedNotStoredWhenNonOKStatus) {
278 const int non_ok_status_codes[] = {
279 net::HTTP_NO_CONTENT,
280 net::HTTP_NOT_MODIFIED,
282 net::HTTP_INTERNAL_SERVER_ERROR,
283 net::HTTP_SERVICE_UNAVAILABLE,
286 base::MessageLoop message_loop;
287 content::TestBrowserThread io_thread(content::BrowserThread::IO,
289 TestingPrefServiceSimple prefs;
290 VariationsService::RegisterPrefs(prefs.registry());
292 VariationsService variations_service(new TestRequestAllowedNotifier, &prefs);
293 for (size_t i = 0; i < arraysize(non_ok_status_codes); ++i) {
294 net::TestURLFetcherFactory factory;
295 variations_service.DoActualFetch();
296 EXPECT_TRUE(prefs.FindPreference(prefs::kVariationsSeed)->IsDefaultValue());
298 net::TestURLFetcher* fetcher = factory.GetFetcherByID(0);
299 SimulateServerResponse(non_ok_status_codes[i], fetcher);
300 variations_service.OnURLFetchComplete(fetcher);
302 EXPECT_TRUE(prefs.FindPreference(prefs::kVariationsSeed)->IsDefaultValue());
306 TEST_F(VariationsServiceTest, SeedDateUpdatedOn304Status) {
307 base::MessageLoop message_loop;
308 content::TestBrowserThread io_thread(content::BrowserThread::IO,
310 TestingPrefServiceSimple prefs;
311 VariationsService::RegisterPrefs(prefs.registry());
313 VariationsService variations_service(new TestRequestAllowedNotifier, &prefs);
314 net::TestURLFetcherFactory factory;
315 variations_service.DoActualFetch();
317 prefs.FindPreference(prefs::kVariationsSeedDate)->IsDefaultValue());
319 net::TestURLFetcher* fetcher = factory.GetFetcherByID(0);
320 SimulateServerResponse(net::HTTP_NOT_MODIFIED, fetcher);
321 variations_service.OnURLFetchComplete(fetcher);
323 prefs.FindPreference(prefs::kVariationsSeedDate)->IsDefaultValue());
326 } // namespace chrome_variations