Roll src/third_party/WebKit 605a979:06cb9e9 (svn 202556:202558)
[chromium-blink-merge.git] / components / variations / variations_seed_store_unittest.cc
blob5821475bc0ba9ca752eb1a9d0968da5175793cf6
1 // Copyright 2014 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 "components/variations/variations_seed_store.h"
7 #include "base/base64.h"
8 #include "base/prefs/testing_pref_service.h"
9 #include "components/compression/compression_utils.h"
10 #include "components/variations/pref_names.h"
11 #include "components/variations/proto/study.pb.h"
12 #include "components/variations/proto/variations_seed.pb.h"
13 #include "testing/gtest/include/gtest/gtest.h"
15 namespace variations {
17 namespace {
19 class TestVariationsSeedStore : public VariationsSeedStore {
20 public:
21 explicit TestVariationsSeedStore(PrefService* local_state)
22 : VariationsSeedStore(local_state) {}
23 ~TestVariationsSeedStore() override {}
25 bool StoreSeedForTesting(const std::string& seed_data) {
26 return StoreSeedData(seed_data, std::string(), std::string(),
27 base::Time::Now(), false, nullptr);
30 VariationsSeedStore::VerifySignatureResult VerifySeedSignature(
31 const std::string& seed_bytes,
32 const std::string& base64_seed_signature) override {
33 return VariationsSeedStore::VARIATIONS_SEED_SIGNATURE_ENUM_SIZE;
36 private:
37 DISALLOW_COPY_AND_ASSIGN(TestVariationsSeedStore);
41 // Populates |seed| with simple test data. The resulting seed will contain one
42 // study called "test", which contains one experiment called "abc" with
43 // probability weight 100. |seed|'s study field will be cleared before adding
44 // the new study.
45 variations::VariationsSeed CreateTestSeed() {
46 variations::VariationsSeed seed;
47 variations::Study* study = seed.add_study();
48 study->set_name("test");
49 study->set_default_experiment_name("abc");
50 variations::Study_Experiment* experiment = study->add_experiment();
51 experiment->set_name("abc");
52 experiment->set_probability_weight(100);
53 seed.set_serial_number("123");
54 return seed;
57 // Serializes |seed| to protobuf binary format.
58 std::string SerializeSeed(const variations::VariationsSeed& seed) {
59 std::string serialized_seed;
60 seed.SerializeToString(&serialized_seed);
61 return serialized_seed;
64 // Compresses |data| using Gzip compression and returns the result.
65 std::string Compress(const std::string& data) {
66 std::string compressed;
67 const bool result = compression::GzipCompress(data, &compressed);
68 EXPECT_TRUE(result);
69 return compressed;
72 // Serializes |seed| to compressed base64-encoded protobuf binary format.
73 std::string SerializeSeedBase64(const variations::VariationsSeed& seed) {
74 std::string serialized_seed = SerializeSeed(seed);
75 std::string base64_serialized_seed;
76 base::Base64Encode(Compress(serialized_seed), &base64_serialized_seed);
77 return base64_serialized_seed;
80 // Checks whether the pref with name |pref_name| is at its default value in
81 // |prefs|.
82 bool PrefHasDefaultValue(const TestingPrefServiceSimple& prefs,
83 const char* pref_name) {
84 return prefs.FindPreference(pref_name)->IsDefaultValue();
87 } // namespace
89 TEST(VariationsSeedStoreTest, LoadSeed) {
90 // Store good seed data to test if loading from prefs works.
91 const variations::VariationsSeed seed = CreateTestSeed();
92 const std::string base64_seed = SerializeSeedBase64(seed);
94 TestingPrefServiceSimple prefs;
95 VariationsSeedStore::RegisterPrefs(prefs.registry());
96 prefs.SetString(prefs::kVariationsCompressedSeed, base64_seed);
98 TestVariationsSeedStore seed_store(&prefs);
100 variations::VariationsSeed loaded_seed;
101 // Check that loading a seed works correctly.
102 EXPECT_TRUE(seed_store.LoadSeed(&loaded_seed));
104 // Check that the loaded data is the same as the original.
105 EXPECT_EQ(SerializeSeed(seed), SerializeSeed(loaded_seed));
106 // Make sure the pref hasn't been changed.
107 EXPECT_FALSE(PrefHasDefaultValue(prefs, prefs::kVariationsCompressedSeed));
108 EXPECT_EQ(base64_seed, prefs.GetString(prefs::kVariationsCompressedSeed));
110 // Check that loading a bad seed returns false and clears the pref.
111 prefs.SetString(prefs::kVariationsCompressedSeed, "this should fail");
112 EXPECT_FALSE(PrefHasDefaultValue(prefs, prefs::kVariationsCompressedSeed));
113 EXPECT_FALSE(seed_store.LoadSeed(&loaded_seed));
114 EXPECT_TRUE(PrefHasDefaultValue(prefs, prefs::kVariationsCompressedSeed));
115 EXPECT_TRUE(PrefHasDefaultValue(prefs, prefs::kVariationsSeedDate));
116 EXPECT_TRUE(PrefHasDefaultValue(prefs, prefs::kVariationsSeedSignature));
118 // Check that having no seed in prefs results in a return value of false.
119 prefs.ClearPref(prefs::kVariationsCompressedSeed);
120 EXPECT_FALSE(seed_store.LoadSeed(&loaded_seed));
123 TEST(VariationsSeedStoreTest, GetInvalidSignature) {
124 const variations::VariationsSeed seed = CreateTestSeed();
125 const std::string base64_seed = SerializeSeedBase64(seed);
127 TestingPrefServiceSimple prefs;
128 VariationsSeedStore::RegisterPrefs(prefs.registry());
129 prefs.SetString(prefs::kVariationsSeed, base64_seed);
131 // The below seed and signature pair were generated using the server's
132 // private key.
133 const std::string base64_seed_data =
134 "CigxZDI5NDY0ZmIzZDc4ZmYxNTU2ZTViNTUxYzY0NDdjYmM3NGU1ZmQwEr0BCh9VTUEtVW5p"
135 "Zm9ybWl0eS1UcmlhbC0xMC1QZXJjZW50GICckqUFOAFCB2RlZmF1bHRKCwoHZGVmYXVsdBAB"
136 "SgwKCGdyb3VwXzAxEAFKDAoIZ3JvdXBfMDIQAUoMCghncm91cF8wMxABSgwKCGdyb3VwXzA0"
137 "EAFKDAoIZ3JvdXBfMDUQAUoMCghncm91cF8wNhABSgwKCGdyb3VwXzA3EAFKDAoIZ3JvdXBf"
138 "MDgQAUoMCghncm91cF8wORAB";
139 const std::string base64_seed_signature =
140 "MEQCIDD1IVxjzWYncun+9IGzqYjZvqxxujQEayJULTlbTGA/AiAr0oVmEgVUQZBYq5VLOSvy"
141 "96JkMYgzTkHPwbv7K/CmgA==";
142 const std::string base64_seed_signature_invalid =
143 "AEQCIDD1IVxjzWYncun+9IGzqYjZvqxxujQEayJULTlbTGA/AiAr0oVmEgVUQZBYq5VLOSvy"
144 "96JkMYgzTkHPwbv7K/CmgA==";
146 // Set seed and valid signature in prefs.
147 prefs.SetString(prefs::kVariationsSeed, base64_seed_data);
148 prefs.SetString(prefs::kVariationsSeedSignature, base64_seed_signature);
150 VariationsSeedStore seed_store(&prefs);
151 variations::VariationsSeed loaded_seed;
152 seed_store.LoadSeed(&loaded_seed);
153 std::string invalid_signature = seed_store.GetInvalidSignature();
154 // Valid signature so we get an empty string.
155 EXPECT_EQ(std::string(), invalid_signature);
157 prefs.SetString(prefs::kVariationsSeedSignature,
158 base64_seed_signature_invalid);
159 seed_store.LoadSeed(&loaded_seed);
160 // Invalid signature, so we should get the signature itself, except on mobile
161 // where we should get an empty string because verification is not enabled.
162 invalid_signature = seed_store.GetInvalidSignature();
163 #if defined(OS_IOS) || defined(OS_ANDROID)
164 EXPECT_EQ(std::string(), invalid_signature);
165 #else
166 EXPECT_EQ(base64_seed_signature_invalid, invalid_signature);
167 #endif
169 prefs.SetString(prefs::kVariationsSeedSignature, std::string());
170 seed_store.LoadSeed(&loaded_seed);
171 invalid_signature = seed_store.GetInvalidSignature();
172 // Empty signature, not considered invalid.
173 EXPECT_EQ(std::string(), invalid_signature);
176 TEST(VariationsSeedStoreTest, StoreSeedData) {
177 const variations::VariationsSeed seed = CreateTestSeed();
178 const std::string serialized_seed = SerializeSeed(seed);
180 TestingPrefServiceSimple prefs;
181 VariationsSeedStore::RegisterPrefs(prefs.registry());
183 TestVariationsSeedStore seed_store(&prefs);
185 EXPECT_TRUE(seed_store.StoreSeedForTesting(serialized_seed));
186 // Make sure the pref was actually set.
187 EXPECT_FALSE(PrefHasDefaultValue(prefs, prefs::kVariationsCompressedSeed));
189 std::string loaded_compressed_seed =
190 prefs.GetString(prefs::kVariationsCompressedSeed);
191 std::string decoded_compressed_seed;
192 ASSERT_TRUE(base::Base64Decode(loaded_compressed_seed,
193 &decoded_compressed_seed));
194 // Make sure the stored seed from pref is the same as the seed we created.
195 EXPECT_EQ(Compress(serialized_seed), decoded_compressed_seed);
197 // Check if trying to store a bad seed leaves the pref unchanged.
198 prefs.ClearPref(prefs::kVariationsCompressedSeed);
199 EXPECT_FALSE(seed_store.StoreSeedForTesting("should fail"));
200 EXPECT_TRUE(PrefHasDefaultValue(prefs, prefs::kVariationsCompressedSeed));
203 TEST(VariationsSeedStoreTest, StoreSeedData_ParsedSeed) {
204 const variations::VariationsSeed seed = CreateTestSeed();
205 const std::string serialized_seed = SerializeSeed(seed);
207 TestingPrefServiceSimple prefs;
208 VariationsSeedStore::RegisterPrefs(prefs.registry());
209 TestVariationsSeedStore seed_store(&prefs);
211 variations::VariationsSeed parsed_seed;
212 EXPECT_TRUE(seed_store.StoreSeedData(serialized_seed, std::string(),
213 std::string(), base::Time::Now(), false,
214 &parsed_seed));
215 EXPECT_EQ(serialized_seed, SerializeSeed(parsed_seed));
218 TEST(VariationsSeedStoreTest, StoreSeedData_CountryCode) {
219 TestingPrefServiceSimple prefs;
220 VariationsSeedStore::RegisterPrefs(prefs.registry());
221 TestVariationsSeedStore seed_store(&prefs);
223 // Test with a seed country code and no header value.
224 variations::VariationsSeed seed = CreateTestSeed();
225 seed.set_country_code("test_country");
226 EXPECT_TRUE(seed_store.StoreSeedData(SerializeSeed(seed), std::string(),
227 std::string(), base::Time::Now(), false,
228 nullptr));
229 EXPECT_EQ("test_country", prefs.GetString(prefs::kVariationsCountry));
231 // Test with a header value and no seed country.
232 prefs.ClearPref(prefs::kVariationsCountry);
233 seed.clear_country_code();
234 EXPECT_TRUE(seed_store.StoreSeedData(SerializeSeed(seed), std::string(),
235 "test_country2", base::Time::Now(),
236 false, nullptr));
237 EXPECT_EQ("test_country2", prefs.GetString(prefs::kVariationsCountry));
239 // Test with a seed country code and header value.
240 prefs.ClearPref(prefs::kVariationsCountry);
241 seed.set_country_code("test_country3");
242 EXPECT_TRUE(seed_store.StoreSeedData(SerializeSeed(seed), std::string(),
243 "test_country4", base::Time::Now(),
244 false, nullptr));
245 EXPECT_EQ("test_country4", prefs.GetString(prefs::kVariationsCountry));
247 // Test with no country code specified - which should preserve the old value.
248 seed.clear_country_code();
249 EXPECT_TRUE(seed_store.StoreSeedData(SerializeSeed(seed), std::string(),
250 std::string(), base::Time::Now(), false,
251 nullptr));
252 EXPECT_EQ("test_country4", prefs.GetString(prefs::kVariationsCountry));
255 TEST(VariationsSeedStoreTest, VerifySeedSignature) {
256 // The below seed and signature pair were generated using the server's
257 // private key.
258 const std::string base64_seed_data =
259 "CigxZDI5NDY0ZmIzZDc4ZmYxNTU2ZTViNTUxYzY0NDdjYmM3NGU1ZmQwEr0BCh9VTUEtVW5p"
260 "Zm9ybWl0eS1UcmlhbC0xMC1QZXJjZW50GICckqUFOAFCB2RlZmF1bHRKCwoHZGVmYXVsdBAB"
261 "SgwKCGdyb3VwXzAxEAFKDAoIZ3JvdXBfMDIQAUoMCghncm91cF8wMxABSgwKCGdyb3VwXzA0"
262 "EAFKDAoIZ3JvdXBfMDUQAUoMCghncm91cF8wNhABSgwKCGdyb3VwXzA3EAFKDAoIZ3JvdXBf"
263 "MDgQAUoMCghncm91cF8wORAB";
264 const std::string base64_seed_signature =
265 "MEQCIDD1IVxjzWYncun+9IGzqYjZvqxxujQEayJULTlbTGA/AiAr0oVmEgVUQZBYq5VLOSvy"
266 "96JkMYgzTkHPwbv7K/CmgA==";
268 std::string seed_data;
269 EXPECT_TRUE(base::Base64Decode(base64_seed_data, &seed_data));
271 VariationsSeedStore seed_store(NULL);
273 #if defined(OS_IOS) || defined(OS_ANDROID)
274 // Signature verification is not enabled on mobile.
275 if (seed_store.VerifySeedSignature(seed_data, base64_seed_signature) ==
276 VariationsSeedStore::VARIATIONS_SEED_SIGNATURE_ENUM_SIZE) {
277 return;
279 #endif
281 // The above inputs should be valid.
282 EXPECT_EQ(VariationsSeedStore::VARIATIONS_SEED_SIGNATURE_VALID,
283 seed_store.VerifySeedSignature(seed_data, base64_seed_signature));
285 // If there's no signature, the corresponding result should be returned.
286 EXPECT_EQ(VariationsSeedStore::VARIATIONS_SEED_SIGNATURE_MISSING,
287 seed_store.VerifySeedSignature(seed_data, std::string()));
289 // Using non-base64 encoded value as signature (e.g. seed data) should fail.
290 EXPECT_EQ(VariationsSeedStore::VARIATIONS_SEED_SIGNATURE_DECODE_FAILED,
291 seed_store.VerifySeedSignature(seed_data, seed_data));
293 // Using a different signature (e.g. the base64 seed data) should fail.
294 #if defined(USE_OPENSSL)
295 // OpenSSL doesn't distinguish signature decode failure from the
296 // signature not matching.
297 EXPECT_EQ(VariationsSeedStore::VARIATIONS_SEED_SIGNATURE_INVALID_SEED,
298 seed_store.VerifySeedSignature(seed_data, base64_seed_data));
299 #else
300 EXPECT_EQ(VariationsSeedStore::VARIATIONS_SEED_SIGNATURE_INVALID_SIGNATURE,
301 seed_store.VerifySeedSignature(seed_data, base64_seed_data));
302 #endif
304 // Using a different seed should not match the signature.
305 seed_data[0] = 'x';
306 EXPECT_EQ(VariationsSeedStore::VARIATIONS_SEED_SIGNATURE_INVALID_SEED,
307 seed_store.VerifySeedSignature(seed_data, base64_seed_signature));
310 TEST(VariationsSeedStoreTest, ApplyDeltaPatch) {
311 // Sample seeds and the server produced delta between them to verify that the
312 // client code is able to decode the deltas produced by the server.
313 const std::string base64_before_seed_data =
314 "CigxN2E4ZGJiOTI4ODI0ZGU3ZDU2MGUyODRlODY1ZDllYzg2NzU1MTE0ElgKDFVNQVN0YWJp"
315 "bGl0eRjEyomgBTgBQgtTZXBhcmF0ZUxvZ0oLCgdEZWZhdWx0EABKDwoLU2VwYXJhdGVMb2cQ"
316 "ZFIVEgszNC4wLjE4MDEuMCAAIAEgAiADEkQKIFVNQS1Vbmlmb3JtaXR5LVRyaWFsLTEwMC1Q"
317 "ZXJjZW50GIDjhcAFOAFCCGdyb3VwXzAxSgwKCGdyb3VwXzAxEAFgARJPCh9VTUEtVW5pZm9y"
318 "bWl0eS1UcmlhbC01MC1QZXJjZW50GIDjhcAFOAFCB2RlZmF1bHRKDAoIZ3JvdXBfMDEQAUoL"
319 "CgdkZWZhdWx0EAFgAQ==";
320 const std::string base64_after_seed_data =
321 "CigyNGQzYTM3ZTAxYmViOWYwNWYzMjM4YjUzNWY3MDg1ZmZlZWI4NzQwElgKDFVNQVN0YWJp"
322 "bGl0eRjEyomgBTgBQgtTZXBhcmF0ZUxvZ0oLCgdEZWZhdWx0EABKDwoLU2VwYXJhdGVMb2cQ"
323 "ZFIVEgszNC4wLjE4MDEuMCAAIAEgAiADEpIBCh9VTUEtVW5pZm9ybWl0eS1UcmlhbC0yMC1Q"
324 "ZXJjZW50GIDjhcAFOAFCB2RlZmF1bHRKEQoIZ3JvdXBfMDEQARijtskBShEKCGdyb3VwXzAy"
325 "EAEYpLbJAUoRCghncm91cF8wMxABGKW2yQFKEQoIZ3JvdXBfMDQQARimtskBShAKB2RlZmF1"
326 "bHQQARiitskBYAESWAofVU1BLVVuaWZvcm1pdHktVHJpYWwtNTAtUGVyY2VudBiA44XABTgB"
327 "QgdkZWZhdWx0Sg8KC25vbl9kZWZhdWx0EAFKCwoHZGVmYXVsdBABUgQoACgBYAE=";
328 const std::string base64_delta_data =
329 "KgooMjRkM2EzN2UwMWJlYjlmMDVmMzIzOGI1MzVmNzA4NWZmZWViODc0MAAqW+4BkgEKH1VN"
330 "QS1Vbmlmb3JtaXR5LVRyaWFsLTIwLVBlcmNlbnQYgOOFwAU4AUIHZGVmYXVsdEoRCghncm91"
331 "cF8wMRABGKO2yQFKEQoIZ3JvdXBfMDIQARiktskBShEKCGdyb3VwXzAzEAEYpbbJAUoRCghn"
332 "cm91cF8wNBABGKa2yQFKEAoHZGVmYXVsdBABGKK2yQFgARJYCh9VTUEtVW5pZm9ybWl0eS1U"
333 "cmlhbC01MC1QZXJjZW50GIDjhcAFOAFCB2RlZmF1bHRKDwoLbm9uX2RlZmF1bHQQAUoLCgdk"
334 "ZWZhdWx0EAFSBCgAKAFgAQ==";
336 std::string before_seed_data;
337 std::string after_seed_data;
338 std::string delta_data;
339 EXPECT_TRUE(base::Base64Decode(base64_before_seed_data, &before_seed_data));
340 EXPECT_TRUE(base::Base64Decode(base64_after_seed_data, &after_seed_data));
341 EXPECT_TRUE(base::Base64Decode(base64_delta_data, &delta_data));
343 std::string output;
344 EXPECT_TRUE(VariationsSeedStore::ApplyDeltaPatch(before_seed_data, delta_data,
345 &output));
346 EXPECT_EQ(after_seed_data, output);
349 } // namespace variations