Pin Chrome's shortcut to the Win10 Start menu on install and OS upgrade.
[chromium-blink-merge.git] / chrome / browser / metrics / variations / variations_seed_store_unittest.cc
blob3bd30351bc998b5cc0c811eb996eed8252d4e889
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 "chrome/browser/metrics/variations/variations_seed_store.h"
7 #include "base/base64.h"
8 #include "base/prefs/testing_pref_service.h"
9 #include "chrome/common/pref_names.h"
10 #include "components/metrics/compression_utils.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 chrome_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(), base::Time::Now(), NULL);
29 VariationsSeedStore::VerifySignatureResult VerifySeedSignature(
30 const std::string& seed_bytes,
31 const std::string& base64_seed_signature) override {
32 return VariationsSeedStore::VARIATIONS_SEED_SIGNATURE_ENUM_SIZE;
35 private:
36 DISALLOW_COPY_AND_ASSIGN(TestVariationsSeedStore);
40 // Populates |seed| with simple test data. The resulting seed will contain one
41 // study called "test", which contains one experiment called "abc" with
42 // probability weight 100. |seed|'s study field will be cleared before adding
43 // the new study.
44 variations::VariationsSeed CreateTestSeed() {
45 variations::VariationsSeed seed;
46 variations::Study* study = seed.add_study();
47 study->set_name("test");
48 study->set_default_experiment_name("abc");
49 variations::Study_Experiment* experiment = study->add_experiment();
50 experiment->set_name("abc");
51 experiment->set_probability_weight(100);
52 seed.set_serial_number("123");
53 return seed;
56 // Serializes |seed| to protobuf binary format.
57 std::string SerializeSeed(const variations::VariationsSeed& seed) {
58 std::string serialized_seed;
59 seed.SerializeToString(&serialized_seed);
60 return serialized_seed;
63 // Compresses |data| using Gzip compression and returns the result.
64 std::string Compress(const std::string& data) {
65 std::string compressed;
66 const bool result = metrics::GzipCompress(data, &compressed);
67 EXPECT_TRUE(result);
68 return compressed;
71 // Serializes |seed| to compressed base64-encoded protobuf binary format.
72 std::string SerializeSeedBase64(const variations::VariationsSeed& seed) {
73 std::string serialized_seed = SerializeSeed(seed);
74 std::string base64_serialized_seed;
75 base::Base64Encode(Compress(serialized_seed), &base64_serialized_seed);
76 return base64_serialized_seed;
79 // Checks whether the pref with name |pref_name| is at its default value in
80 // |prefs|.
81 bool PrefHasDefaultValue(const TestingPrefServiceSimple& prefs,
82 const char* pref_name) {
83 return prefs.FindPreference(pref_name)->IsDefaultValue();
86 } // namespace
88 TEST(VariationsSeedStoreTest, LoadSeed) {
89 // Store good seed data to test if loading from prefs works.
90 const variations::VariationsSeed seed = CreateTestSeed();
91 const std::string base64_seed = SerializeSeedBase64(seed);
93 TestingPrefServiceSimple prefs;
94 VariationsSeedStore::RegisterPrefs(prefs.registry());
95 prefs.SetString(prefs::kVariationsCompressedSeed, base64_seed);
97 TestVariationsSeedStore seed_store(&prefs);
99 variations::VariationsSeed loaded_seed;
100 // Check that loading a seed works correctly.
101 EXPECT_TRUE(seed_store.LoadSeed(&loaded_seed));
103 // Check that the loaded data is the same as the original.
104 EXPECT_EQ(SerializeSeed(seed), SerializeSeed(loaded_seed));
105 // Make sure the pref hasn't been changed.
106 EXPECT_FALSE(PrefHasDefaultValue(prefs, prefs::kVariationsCompressedSeed));
107 EXPECT_EQ(base64_seed, prefs.GetString(prefs::kVariationsCompressedSeed));
109 // Check that loading a bad seed returns false and clears the pref.
110 prefs.SetString(prefs::kVariationsCompressedSeed, "this should fail");
111 EXPECT_FALSE(PrefHasDefaultValue(prefs, prefs::kVariationsCompressedSeed));
112 EXPECT_FALSE(seed_store.LoadSeed(&loaded_seed));
113 EXPECT_TRUE(PrefHasDefaultValue(prefs, prefs::kVariationsCompressedSeed));
114 EXPECT_TRUE(PrefHasDefaultValue(prefs, prefs::kVariationsSeedDate));
115 EXPECT_TRUE(PrefHasDefaultValue(prefs, prefs::kVariationsSeedSignature));
117 // Check that having no seed in prefs results in a return value of false.
118 prefs.ClearPref(prefs::kVariationsCompressedSeed);
119 EXPECT_FALSE(seed_store.LoadSeed(&loaded_seed));
122 TEST(VariationsSeedStoreTest, GetInvalidSignature) {
123 const variations::VariationsSeed seed = CreateTestSeed();
124 const std::string base64_seed = SerializeSeedBase64(seed);
126 TestingPrefServiceSimple prefs;
127 VariationsSeedStore::RegisterPrefs(prefs.registry());
128 prefs.SetString(prefs::kVariationsSeed, base64_seed);
130 // The below seed and signature pair were generated using the server's
131 // private key.
132 const std::string base64_seed_data =
133 "CigxZDI5NDY0ZmIzZDc4ZmYxNTU2ZTViNTUxYzY0NDdjYmM3NGU1ZmQwEr0BCh9VTUEtVW5p"
134 "Zm9ybWl0eS1UcmlhbC0xMC1QZXJjZW50GICckqUFOAFCB2RlZmF1bHRKCwoHZGVmYXVsdBAB"
135 "SgwKCGdyb3VwXzAxEAFKDAoIZ3JvdXBfMDIQAUoMCghncm91cF8wMxABSgwKCGdyb3VwXzA0"
136 "EAFKDAoIZ3JvdXBfMDUQAUoMCghncm91cF8wNhABSgwKCGdyb3VwXzA3EAFKDAoIZ3JvdXBf"
137 "MDgQAUoMCghncm91cF8wORAB";
138 const std::string base64_seed_signature =
139 "MEQCIDD1IVxjzWYncun+9IGzqYjZvqxxujQEayJULTlbTGA/AiAr0oVmEgVUQZBYq5VLOSvy"
140 "96JkMYgzTkHPwbv7K/CmgA==";
141 const std::string base64_seed_signature_invalid =
142 "AEQCIDD1IVxjzWYncun+9IGzqYjZvqxxujQEayJULTlbTGA/AiAr0oVmEgVUQZBYq5VLOSvy"
143 "96JkMYgzTkHPwbv7K/CmgA==";
145 // Set seed and valid signature in prefs.
146 prefs.SetString(prefs::kVariationsSeed, base64_seed_data);
147 prefs.SetString(prefs::kVariationsSeedSignature, base64_seed_signature);
149 VariationsSeedStore seed_store(&prefs);
150 variations::VariationsSeed loaded_seed;
151 seed_store.LoadSeed(&loaded_seed);
152 std::string invalid_signature = seed_store.GetInvalidSignature();
153 // Valid signature so we get an empty string.
154 EXPECT_EQ(std::string(), invalid_signature);
156 prefs.SetString(prefs::kVariationsSeedSignature,
157 base64_seed_signature_invalid);
158 seed_store.LoadSeed(&loaded_seed);
159 // Invalid signature, so we should get the signature itself, except on mobile
160 // where we should get an empty string because verification is not enabled.
161 invalid_signature = seed_store.GetInvalidSignature();
162 #if defined(OS_IOS) || defined(OS_ANDROID)
163 EXPECT_EQ(std::string(), invalid_signature);
164 #else
165 EXPECT_EQ(base64_seed_signature_invalid, invalid_signature);
166 #endif
168 prefs.SetString(prefs::kVariationsSeedSignature, std::string());
169 seed_store.LoadSeed(&loaded_seed);
170 invalid_signature = seed_store.GetInvalidSignature();
171 // Empty signature, not considered invalid.
172 EXPECT_EQ(std::string(), invalid_signature);
175 TEST(VariationsSeedStoreTest, StoreSeedData) {
176 const variations::VariationsSeed seed = CreateTestSeed();
177 const std::string serialized_seed = SerializeSeed(seed);
179 TestingPrefServiceSimple prefs;
180 VariationsSeedStore::RegisterPrefs(prefs.registry());
182 TestVariationsSeedStore seed_store(&prefs);
184 EXPECT_TRUE(seed_store.StoreSeedForTesting(serialized_seed));
185 // Make sure the pref was actually set.
186 EXPECT_FALSE(PrefHasDefaultValue(prefs, prefs::kVariationsCompressedSeed));
188 std::string loaded_compressed_seed =
189 prefs.GetString(prefs::kVariationsCompressedSeed);
190 std::string decoded_compressed_seed;
191 ASSERT_TRUE(base::Base64Decode(loaded_compressed_seed,
192 &decoded_compressed_seed));
193 // Make sure the stored seed from pref is the same as the seed we created.
194 EXPECT_EQ(Compress(serialized_seed), decoded_compressed_seed);
196 // Check if trying to store a bad seed leaves the pref unchanged.
197 prefs.ClearPref(prefs::kVariationsCompressedSeed);
198 EXPECT_FALSE(seed_store.StoreSeedForTesting("should fail"));
199 EXPECT_TRUE(PrefHasDefaultValue(prefs, prefs::kVariationsCompressedSeed));
202 TEST(VariationsSeedStoreTest, StoreSeedData_ParsedSeed) {
203 const variations::VariationsSeed seed = CreateTestSeed();
204 const std::string serialized_seed = SerializeSeed(seed);
206 TestingPrefServiceSimple prefs;
207 VariationsSeedStore::RegisterPrefs(prefs.registry());
208 TestVariationsSeedStore seed_store(&prefs);
210 variations::VariationsSeed parsed_seed;
211 EXPECT_TRUE(seed_store.StoreSeedData(serialized_seed, std::string(),
212 base::Time::Now(), &parsed_seed));
213 EXPECT_EQ(serialized_seed, SerializeSeed(parsed_seed));
216 TEST(VariationsSeedStoreTest, VerifySeedSignature) {
217 // The below seed and signature pair were generated using the server's
218 // private key.
219 const std::string base64_seed_data =
220 "CigxZDI5NDY0ZmIzZDc4ZmYxNTU2ZTViNTUxYzY0NDdjYmM3NGU1ZmQwEr0BCh9VTUEtVW5p"
221 "Zm9ybWl0eS1UcmlhbC0xMC1QZXJjZW50GICckqUFOAFCB2RlZmF1bHRKCwoHZGVmYXVsdBAB"
222 "SgwKCGdyb3VwXzAxEAFKDAoIZ3JvdXBfMDIQAUoMCghncm91cF8wMxABSgwKCGdyb3VwXzA0"
223 "EAFKDAoIZ3JvdXBfMDUQAUoMCghncm91cF8wNhABSgwKCGdyb3VwXzA3EAFKDAoIZ3JvdXBf"
224 "MDgQAUoMCghncm91cF8wORAB";
225 const std::string base64_seed_signature =
226 "MEQCIDD1IVxjzWYncun+9IGzqYjZvqxxujQEayJULTlbTGA/AiAr0oVmEgVUQZBYq5VLOSvy"
227 "96JkMYgzTkHPwbv7K/CmgA==";
229 std::string seed_data;
230 EXPECT_TRUE(base::Base64Decode(base64_seed_data, &seed_data));
232 VariationsSeedStore seed_store(NULL);
234 #if defined(OS_IOS) || defined(OS_ANDROID)
235 // Signature verification is not enabled on mobile.
236 if (seed_store.VerifySeedSignature(seed_data, base64_seed_signature) ==
237 VariationsSeedStore::VARIATIONS_SEED_SIGNATURE_ENUM_SIZE) {
238 return;
240 #endif
242 // The above inputs should be valid.
243 EXPECT_EQ(VariationsSeedStore::VARIATIONS_SEED_SIGNATURE_VALID,
244 seed_store.VerifySeedSignature(seed_data, base64_seed_signature));
246 // If there's no signature, the corresponding result should be returned.
247 EXPECT_EQ(VariationsSeedStore::VARIATIONS_SEED_SIGNATURE_MISSING,
248 seed_store.VerifySeedSignature(seed_data, std::string()));
250 // Using non-base64 encoded value as signature (e.g. seed data) should fail.
251 EXPECT_EQ(VariationsSeedStore::VARIATIONS_SEED_SIGNATURE_DECODE_FAILED,
252 seed_store.VerifySeedSignature(seed_data, seed_data));
254 // Using a different signature (e.g. the base64 seed data) should fail.
255 #if defined(USE_OPENSSL)
256 // OpenSSL doesn't distinguish signature decode failure from the
257 // signature not matching.
258 EXPECT_EQ(VariationsSeedStore::VARIATIONS_SEED_SIGNATURE_INVALID_SEED,
259 seed_store.VerifySeedSignature(seed_data, base64_seed_data));
260 #else
261 EXPECT_EQ(VariationsSeedStore::VARIATIONS_SEED_SIGNATURE_INVALID_SIGNATURE,
262 seed_store.VerifySeedSignature(seed_data, base64_seed_data));
263 #endif
265 // Using a different seed should not match the signature.
266 seed_data[0] = 'x';
267 EXPECT_EQ(VariationsSeedStore::VARIATIONS_SEED_SIGNATURE_INVALID_SEED,
268 seed_store.VerifySeedSignature(seed_data, base64_seed_signature));
271 } // namespace chrome_variations