diff options
author | veranika <veranika@chromium.org> | 2015-10-19 09:37:56 -0700 |
---|---|---|
committer | Commit bot <commit-bot@chromium.org> | 2015-10-19 16:38:43 +0000 |
commit | f6acefe76a605a6fc17714306919c56ab3b2e2af (patch) | |
tree | 07cbf238cf8e98a2822b955282b9c7d13e4ae956 | |
parent | 91f64126aba750764c13d2278eda7147c5b98368 (diff) | |
download | chromium_src-f6acefe76a605a6fc17714306919c56ab3b2e2af.zip chromium_src-f6acefe76a605a6fc17714306919c56ab3b2e2af.tar.gz chromium_src-f6acefe76a605a6fc17714306919c56ab3b2e2af.tar.bz2 |
Support gzip-compressed seed data from the variations server.
Firstly, the client asks for gzip-compressed data by adding "gzip" to
A-IM HTTP request header. Secondly, if "gzip" is present in IM HTTP
response header, the client uncompresses data. Gzip compression could be
used in combination with delta compression.
A-IM and IM headers are defined in RFC 3229:
http://tools.ietf.org/html/rfc3229#page-32
This CL re-adds components/variations/service tests to components_unittests.
BUG=543271
Review URL: https://codereview.chromium.org/1404583004
Cr-Commit-Position: refs/heads/master@{#354788}
-rw-r--r-- | components/BUILD.gn | 1 | ||||
-rw-r--r-- | components/variations/service/variations_service.cc | 76 | ||||
-rw-r--r-- | components/variations/service/variations_service.h | 10 | ||||
-rw-r--r-- | components/variations/service/variations_service_unittest.cc | 112 | ||||
-rw-r--r-- | components/variations/variations_seed_store.cc | 47 | ||||
-rw-r--r-- | components/variations/variations_seed_store.h | 8 | ||||
-rw-r--r-- | components/variations/variations_seed_store_unittest.cc | 44 | ||||
-rw-r--r-- | tools/metrics/histograms/histograms.xml | 20 |
8 files changed, 280 insertions, 38 deletions
diff --git a/components/BUILD.gn b/components/BUILD.gn index 03c729c..c3ac7cd 100644 --- a/components/BUILD.gn +++ b/components/BUILD.gn @@ -397,6 +397,7 @@ test("components_unittests") { "//components/upload_list:unit_tests", "//components/user_prefs/tracked:unit_tests", "//components/variations:unit_tests", + "//components/variations/service:unit_tests", "//components/wallpaper:unit_tests", "//components/web_resource:unit_tests", "//components/webcrypto:unit_tests", diff --git a/components/variations/service/variations_service.cc b/components/variations/service/variations_service.cc index 2607ead..8d3ced5 100644 --- a/components/variations/service/variations_service.cc +++ b/components/variations/service/variations_service.cc @@ -10,6 +10,7 @@ #include "base/metrics/sparse_histogram.h" #include "base/prefs/pref_registry_simple.h" #include "base/prefs/pref_service.h" +#include "base/strings/string_util.h" #include "base/sys_info.h" #include "base/task_runner_util.h" #include "base/timer/elapsed_timer.h" @@ -214,6 +215,55 @@ std::string GetHeaderValue(const net::HttpResponseHeaders* headers, return value; } +// Returns the list of values for |name| from |headers|. If the header in not +// set, return an empty list. +std::vector<std::string> GetHeaderValuesList( + const net::HttpResponseHeaders* headers, + const base::StringPiece& name) { + std::vector<std::string> values; + void* iter = NULL; + std::string value; + while (headers->EnumerateHeader(&iter, name, &value)) { + values.push_back(value); + } + return values; +} + +// Looks for delta and gzip compression instance manipulation flags set by the +// server in |headers|. Checks the order of flags and presence of unknown +// instance manipulations. If successful, |is_delta_compressed| and +// |is_gzip_compressed| contain compression flags and true is returned. +bool GetInstanceManipulations(const net::HttpResponseHeaders* headers, + bool* is_delta_compressed, + bool* is_gzip_compressed) { + std::vector<std::string> ims = GetHeaderValuesList(headers, "IM"); + const auto delta_im = std::find(ims.begin(), ims.end(), "x-bm"); + const auto gzip_im = std::find(ims.begin(), ims.end(), "gzip"); + *is_delta_compressed = delta_im != ims.end(); + *is_gzip_compressed = gzip_im != ims.end(); + + // The IM field should not have anything but x-bm and gzip. + size_t im_count = (*is_delta_compressed ? 1 : 0) + + (*is_gzip_compressed ? 1 : 0); + if (im_count != ims.size()) { + DVLOG(1) << "Unrecognized instance manipulations in " + << base::JoinString(ims, ",") + << "; only x-bm and gzip are supported"; + return false; + } + + // The IM field defines order in which instance manipulations were applied. + // The client requests and supports gzip-compressed delta-compressed seeds, + // but not vice versa. + if (*is_delta_compressed && *is_gzip_compressed && delta_im > gzip_im) { + DVLOG(1) << "Unsupported instance manipulations order: " + << "requested x-bm,gzip but received gzip,x-bm"; + return false; + } + + return true; +} + } // namespace VariationsService::VariationsService( @@ -474,6 +524,7 @@ void VariationsService::DoActualFetch() { net::LOAD_DO_NOT_SAVE_COOKIES); pending_seed_request_->SetRequestContext(client_->GetURLRequestContext()); pending_seed_request_->SetMaxRetriesOn5xx(kMaxRetrySeedFetch); + bool enable_deltas = false; if (!seed_store_.variations_serial_number().empty() && !disable_deltas_for_next_request_) { // If the current seed includes a country code, deltas are not supported (as @@ -484,12 +535,16 @@ void VariationsService::DoActualFetch() { // that have an old seed with a country code becomes miniscule. if (!seed_store_.seed_has_country_code()) { // Tell the server that delta-compressed seeds are supported. - pending_seed_request_->AddExtraRequestHeader("A-IM:x-bm"); + enable_deltas = true; } // Get the seed only if its serial number doesn't match what we have. pending_seed_request_->AddExtraRequestHeader( "If-None-Match:" + seed_store_.variations_serial_number()); } + // Tell the server that delta-compressed and gzipped seeds are supported. + const char* supported_im = enable_deltas ? "A-IM:x-bm,gzip" : "A-IM:gzip"; + pending_seed_request_->AddExtraRequestHeader(supported_im); + pending_seed_request_->Start(); const base::TimeTicks now = base::TimeTicks::Now(); @@ -510,13 +565,14 @@ bool VariationsService::StoreSeed(const std::string& seed_data, const std::string& seed_signature, const std::string& country_code, const base::Time& date_fetched, - bool is_delta_compressed) { + bool is_delta_compressed, + bool is_gzip_compressed) { DCHECK(thread_checker_.CalledOnValidThread()); scoped_ptr<variations::VariationsSeed> seed(new variations::VariationsSeed); if (!seed_store_.StoreSeedData(seed_data, seed_signature, country_code, date_fetched, is_delta_compressed, - seed.get())) { + is_gzip_compressed, seed.get())) { return false; } RecordLastFetchTime(); @@ -628,11 +684,21 @@ void VariationsService::OnURLFetchComplete(const net::URLFetcher* source) { DCHECK(success); net::HttpResponseHeaders* headers = request->GetResponseHeaders(); + bool is_delta_compressed; + bool is_gzip_compressed; + if (!GetInstanceManipulations(headers, &is_delta_compressed, + &is_gzip_compressed)) { + // The header does not specify supported instance manipulations, unable to + // process data. Details of errors were logged by GetInstanceManipulations. + seed_store_.ReportUnsupportedSeedFormatError(); + return; + } + const std::string signature = GetHeaderValue(headers, "X-Seed-Signature"); const std::string country_code = GetHeaderValue(headers, "X-Country"); - const bool is_delta_compressed = (GetHeaderValue(headers, "IM") == "x-bm"); const bool store_success = StoreSeed(seed_data, signature, country_code, - response_date, is_delta_compressed); + response_date, is_delta_compressed, + is_gzip_compressed); if (!store_success && is_delta_compressed) { disable_deltas_for_next_request_ = true; request_scheduler_->ScheduleFetchShortly(); diff --git a/components/variations/service/variations_service.h b/components/variations/service/variations_service.h index e9b786f..0f65da0 100644 --- a/components/variations/service/variations_service.h +++ b/components/variations/service/variations_service.h @@ -167,7 +167,8 @@ class VariationsService const std::string& seed_signature, const std::string& country_code, const base::Time& date_fetched, - bool is_delta_compressed); + bool is_delta_compressed, + bool is_gzip_compressed); // Creates the VariationsService with the given |local_state| prefs service // and |state_manager|. Does not take ownership of |state_manager|. Caller @@ -180,11 +181,16 @@ class VariationsService metrics::MetricsStateManager* state_manager, const UIStringOverrider& ui_string_overrider); + // Sets the URL for querying the variations server. Used for testing. + void set_variations_server_url(const GURL& url) { + variations_server_url_ = url; + } + private: FRIEND_TEST_ALL_PREFIXES(VariationsServiceTest, Observer); FRIEND_TEST_ALL_PREFIXES(VariationsServiceTest, SeedStoredWhenOKStatus); FRIEND_TEST_ALL_PREFIXES(VariationsServiceTest, SeedNotStoredWhenNonOKStatus); - FRIEND_TEST_ALL_PREFIXES(VariationsServiceTest, SeedDateUpdatedOn304Status); + FRIEND_TEST_ALL_PREFIXES(VariationsServiceTest, InstanceManipulations); FRIEND_TEST_ALL_PREFIXES(VariationsServiceTest, LoadPermanentConsistencyCountry); FRIEND_TEST_ALL_PREFIXES(VariationsServiceTest, CountryHeader); diff --git a/components/variations/service/variations_service_unittest.cc b/components/variations/service/variations_service_unittest.cc index 1b85ce7..fcc0ff5 100644 --- a/components/variations/service/variations_service_unittest.cc +++ b/components/variations/service/variations_service_unittest.cc @@ -83,9 +83,13 @@ class TestVariationsService : public VariationsService { UIStringOverrider()), intercepts_fetch_(true), fetch_attempted_(false), - seed_stored_(false) { + seed_stored_(false), + delta_compressed_seed_(false), + gzip_compressed_seed_(false) { // Set this so StartRepeatedVariationsSeedFetch can be called in tests. SetCreateTrialsFromSeedCalledForTesting(true); + set_variations_server_url( + GetVariationsServerURL(local_state, std::string())); } ~TestVariationsService() override {} @@ -97,6 +101,8 @@ class TestVariationsService : public VariationsService { bool fetch_attempted() const { return fetch_attempted_; } bool seed_stored() const { return seed_stored_; } const std::string& stored_country() const { return stored_country_; } + bool delta_compressed_seed() const { return delta_compressed_seed_; } + bool gzip_compressed_seed() const { return gzip_compressed_seed_; } void DoActualFetch() override { if (intercepts_fetch_) { @@ -111,10 +117,13 @@ class TestVariationsService : public VariationsService { const std::string& seed_signature, const std::string& country_code, const base::Time& date_fetched, - bool is_delta_compressed) override { + bool is_delta_compressed, + bool is_gzip_compressed) override { seed_stored_ = true; stored_seed_data_ = seed_data; stored_country_ = country_code; + delta_compressed_seed_ = is_delta_compressed; + gzip_compressed_seed_ = is_gzip_compressed; return true; } @@ -130,6 +139,8 @@ class TestVariationsService : public VariationsService { bool seed_stored_; std::string stored_seed_data_; std::string stored_country_; + bool delta_compressed_seed_; + bool gzip_compressed_seed_; DISALLOW_COPY_AND_ASSIGN(TestVariationsService); }; @@ -201,18 +212,30 @@ std::string SerializeSeed(const variations::VariationsSeed& seed) { } // Simulates a variations service response by setting a date header and the -// specified HTTP |response_code| on |fetcher|. -scoped_refptr<net::HttpResponseHeaders> SimulateServerResponse( +// specified HTTP |response_code| on |fetcher|. Sets additional header |header| +// if it is not null. +scoped_refptr<net::HttpResponseHeaders> SimulateServerResponseWithHeader( int response_code, - net::TestURLFetcher* fetcher) { + net::TestURLFetcher* fetcher, + const std::string* header) { EXPECT_TRUE(fetcher); scoped_refptr<net::HttpResponseHeaders> headers( new net::HttpResponseHeaders("date:Wed, 13 Feb 2013 00:25:24 GMT\0\0")); + if (header) + headers->AddHeader(*header); fetcher->set_response_headers(headers); fetcher->set_response_code(response_code); return headers; } +// Simulates a variations service response by setting a date header and the +// specified HTTP |response_code| on |fetcher|. +scoped_refptr<net::HttpResponseHeaders> SimulateServerResponse( + int response_code, + net::TestURLFetcher* fetcher) { + return SimulateServerResponseWithHeader(response_code, fetcher, nullptr); +} + // Converts |list_value| to a string, to make it easier for debugging. std::string ListValueToString(const base::ListValue& list_value) { std::string json; @@ -253,7 +276,7 @@ TEST_F(VariationsServiceTest, CreateTrialsFromSeed) { // Store a seed. service.StoreSeed(SerializeSeed(CreateTestSeed()), std::string(), - std::string(), base::Time::Now(), false); + std::string(), base::Time::Now(), false, false); prefs.SetInt64(prefs::kVariationsLastFetchTime, base::Time::Now().ToInternalValue()); @@ -284,7 +307,7 @@ TEST_F(VariationsServiceTest, CreateTrialsFromSeedNoLastFetchTime) { // Store a seed. To simulate a first run, |prefs::kVariationsLastFetchTime| // is left empty. service.StoreSeed(SerializeSeed(CreateTestSeed()), std::string(), - std::string(), base::Time::Now(), false); + std::string(), base::Time::Now(), false, false); EXPECT_EQ(0, prefs.GetInt64(prefs::kVariationsLastFetchTime)); // Check that field trials are created from the seed. Since the test study has @@ -315,7 +338,7 @@ TEST_F(VariationsServiceTest, CreateTrialsFromOutdatedSeed) { const base::Time seed_date = base::Time::Now() - base::TimeDelta::FromDays(31); service.StoreSeed(SerializeSeed(CreateTestSeed()), std::string(), - std::string(), seed_date, false); + std::string(), seed_date, false, false); prefs.SetInt64(prefs::kVariationsLastFetchTime, seed_date.ToInternalValue()); // Check that field trials are not created from the seed. @@ -422,8 +445,6 @@ TEST_F(VariationsServiceTest, SeedStoredWhenOKStatus) { TestVariationsService service( make_scoped_ptr(new web_resource::TestRequestAllowedNotifier(&prefs)), &prefs); - service.variations_server_url_ = - service.GetVariationsServerURL(&prefs, std::string()); service.set_intercepts_fetch(false); net::TestURLFetcherFactory factory; @@ -450,12 +471,10 @@ TEST_F(VariationsServiceTest, SeedNotStoredWhenNonOKStatus) { TestingPrefServiceSimple prefs; VariationsService::RegisterPrefs(prefs.registry()); - VariationsService service( - make_scoped_ptr(new TestVariationsServiceClient()), + TestVariationsService service( make_scoped_ptr(new web_resource::TestRequestAllowedNotifier(&prefs)), - &prefs, NULL, UIStringOverrider()); - service.variations_server_url_ = - service.GetVariationsServerURL(&prefs, std::string()); + &prefs); + service.set_intercepts_fetch(false); for (size_t i = 0; i < arraysize(non_ok_status_codes); ++i) { net::TestURLFetcherFactory factory; service.DoActualFetch(); @@ -469,6 +488,67 @@ TEST_F(VariationsServiceTest, SeedNotStoredWhenNonOKStatus) { } } +TEST_F(VariationsServiceTest, RequestGzipCompressedSeed) { + TestingPrefServiceSimple prefs; + VariationsService::RegisterPrefs(prefs.registry()); + net::TestURLFetcherFactory factory; + + TestVariationsService service( + make_scoped_ptr(new web_resource::TestRequestAllowedNotifier(&prefs)), + &prefs); + service.set_intercepts_fetch(false); + service.DoActualFetch(); + + net::TestURLFetcher* fetcher = factory.GetFetcherByID(0); + net::HttpRequestHeaders headers; + fetcher->GetExtraRequestHeaders(&headers); + std::string field; + ASSERT_TRUE(headers.GetHeader("A-IM", &field)); + EXPECT_EQ("gzip", field); +} + +TEST_F(VariationsServiceTest, InstanceManipulations) { + struct { + std::string im; + bool delta_compressed; + bool gzip_compressed; + bool seed_stored; + } cases[] = { + {"", false, false, true}, + {"IM:gzip", false, true, true}, + {"IM:x-bm", true, false, true}, + {"IM:x-bm,gzip", true, true, true}, + {"IM: x-bm, gzip", true, true, true}, + {"IM:gzip,x-bm", false, false, false}, + {"IM:deflate,x-bm,gzip", false, false, false}, + }; + + TestingPrefServiceSimple prefs; + VariationsService::RegisterPrefs(prefs.registry()); + std::string serialized_seed = SerializeSeed(CreateTestSeed()); + net::TestURLFetcherFactory factory; + + for (size_t i = 0; i < arraysize(cases); ++i) { + TestVariationsService service( + make_scoped_ptr(new web_resource::TestRequestAllowedNotifier(&prefs)), + &prefs); + service.set_intercepts_fetch(false); + service.DoActualFetch(); + net::TestURLFetcher* fetcher = factory.GetFetcherByID(0); + + if (cases[i].im.empty()) + SimulateServerResponse(net::HTTP_OK, fetcher); + else + SimulateServerResponseWithHeader(net::HTTP_OK, fetcher, &cases[i].im); + fetcher->SetResponseString(serialized_seed); + service.OnURLFetchComplete(fetcher); + + EXPECT_EQ(cases[i].seed_stored, service.seed_stored()); + EXPECT_EQ(cases[i].delta_compressed, service.delta_compressed_seed()); + EXPECT_EQ(cases[i].gzip_compressed, service.gzip_compressed_seed()); + } +} + TEST_F(VariationsServiceTest, CountryHeader) { TestingPrefServiceSimple prefs; VariationsService::RegisterPrefs(prefs.registry()); @@ -476,8 +556,6 @@ TEST_F(VariationsServiceTest, CountryHeader) { TestVariationsService service( make_scoped_ptr(new web_resource::TestRequestAllowedNotifier(&prefs)), &prefs); - service.variations_server_url_ = - service.GetVariationsServerURL(&prefs, std::string()); service.set_intercepts_fetch(false); net::TestURLFetcherFactory factory; diff --git a/components/variations/variations_seed_store.cc b/components/variations/variations_seed_store.cc index e20b056..89e1af2 100644 --- a/components/variations/variations_seed_store.cc +++ b/components/variations/variations_seed_store.cc @@ -91,6 +91,9 @@ enum VariationsSeedStoreResult { VARIATIONS_SEED_STORE_FAILED_DELTA_READ_SEED, VARIATIONS_SEED_STORE_FAILED_DELTA_APPLY, VARIATIONS_SEED_STORE_FAILED_DELTA_STORE, + VARIATIONS_SEED_STORE_FAILED_UNGZIP, + VARIATIONS_SEED_STORE_FAILED_EMPTY_GZIP_CONTENTS, + VARIATIONS_SEED_STORE_FAILED_UNSUPPORTED_SEED_FORMAT, VARIATIONS_SEED_STORE_RESULT_ENUM_SIZE, }; @@ -194,14 +197,38 @@ bool VariationsSeedStore::StoreSeedData( const std::string& country_code, const base::Time& date_fetched, bool is_delta_compressed, + bool is_gzip_compressed, variations::VariationsSeed* parsed_seed) { + // If the data is gzip compressed, first uncompress it. + std::string ungzipped_data; + if (is_gzip_compressed) { + if (compression::GzipUncompress(data, &ungzipped_data)) { + if (ungzipped_data.empty()) { + RecordSeedStoreHistogram( + VARIATIONS_SEED_STORE_FAILED_EMPTY_GZIP_CONTENTS); + return false; + } + + int size_reduction = ungzipped_data.length() - data.length(); + UMA_HISTOGRAM_PERCENTAGE("Variations.StoreSeed.GzipSize.ReductionPercent", + 100 * size_reduction / ungzipped_data.length()); + UMA_HISTOGRAM_COUNTS_1000("Variations.StoreSeed.GzipSize", + data.length() / 1024); + } else { + RecordSeedStoreHistogram(VARIATIONS_SEED_STORE_FAILED_UNGZIP); + return false; + } + } else { + ungzipped_data = data; + } + if (!is_delta_compressed) { const bool result = - StoreSeedDataNoDelta(data, base64_seed_signature, country_code, - date_fetched, parsed_seed); + StoreSeedDataNoDelta(ungzipped_data, base64_seed_signature, + country_code, date_fetched, parsed_seed); if (result) { UMA_HISTOGRAM_COUNTS_1000("Variations.StoreSeed.Size", - data.length() / 1024); + ungzipped_data.length() / 1024); } return result; } @@ -216,7 +243,8 @@ bool VariationsSeedStore::StoreSeedData( RecordSeedStoreHistogram(VARIATIONS_SEED_STORE_FAILED_DELTA_READ_SEED); return false; } - if (!ApplyDeltaPatch(existing_seed_data, data, &updated_seed_data)) { + if (!ApplyDeltaPatch(existing_seed_data, ungzipped_data, + &updated_seed_data)) { RecordSeedStoreHistogram(VARIATIONS_SEED_STORE_FAILED_DELTA_APPLY); return false; } @@ -227,11 +255,11 @@ bool VariationsSeedStore::StoreSeedData( if (result) { // Note: |updated_seed_data.length()| is guaranteed to be non-zero, else // result would be false. - int size_reduction = updated_seed_data.length() - data.length(); + int size_reduction = updated_seed_data.length() - ungzipped_data.length(); UMA_HISTOGRAM_PERCENTAGE("Variations.StoreSeed.DeltaSize.ReductionPercent", 100 * size_reduction / updated_seed_data.length()); UMA_HISTOGRAM_COUNTS_1000("Variations.StoreSeed.DeltaSize", - data.length() / 1024); + ungzipped_data.length() / 1024); } else { RecordSeedStoreHistogram(VARIATIONS_SEED_STORE_FAILED_DELTA_STORE); } @@ -347,7 +375,7 @@ bool VariationsSeedStore::StoreSeedDataNoDelta( const base::Time& date_fetched, variations::VariationsSeed* parsed_seed) { if (seed_data.empty()) { - RecordSeedStoreHistogram(VARIATIONS_SEED_STORE_FAILED_EMPTY); + RecordSeedStoreHistogram(VARIATIONS_SEED_STORE_FAILED_EMPTY_GZIP_CONTENTS); return false; } @@ -450,4 +478,9 @@ bool VariationsSeedStore::ApplyDeltaPatch(const std::string& existing_data, return true; } +void VariationsSeedStore::ReportUnsupportedSeedFormatError() { + RecordSeedStoreHistogram( + VARIATIONS_SEED_STORE_FAILED_UNSUPPORTED_SEED_FORMAT); +} + } // namespace variations diff --git a/components/variations/variations_seed_store.h b/components/variations/variations_seed_store.h index e705a29..cc743d88 100644 --- a/components/variations/variations_seed_store.h +++ b/components/variations/variations_seed_store.h @@ -34,7 +34,9 @@ class VariationsSeedStore { // Stores the given seed |data| (serialized protobuf) to local state, along // with a base64-encoded digital signature for seed and the date when it was - // fetched. If |is_delta_compressed| is true, treats |data| as being delta + // fetched. If |is_gzip_compressed| is true, treats |data| as being gzip + // compressed and decompresses it before any other processing. + // If |is_delta_compressed| is true, treats |data| as being delta // compressed and attempts to decode it first using the store's seed data. // The actual seed data will be base64 encoded for storage. If the string // is invalid, the existing prefs are untouched and false is returned. @@ -46,12 +48,16 @@ class VariationsSeedStore { const std::string& country_code, const base::Time& date_fetched, bool is_delta_compressed, + bool is_gzip_compressed, variations::VariationsSeed* parsed_seed); // Updates |kVariationsSeedDate| and logs when previous date was from a // different day. void UpdateSeedDateAndLogDayChange(const base::Time& server_date_fetched); + // Reports to UMA that the seed format specified by the server is unsupported. + void ReportUnsupportedSeedFormatError(); + // Returns the serial number of the last loaded or stored seed. const std::string& variations_serial_number() const { return variations_serial_number_; diff --git a/components/variations/variations_seed_store_unittest.cc b/components/variations/variations_seed_store_unittest.cc index 5821475..ab7f506 100644 --- a/components/variations/variations_seed_store_unittest.cc +++ b/components/variations/variations_seed_store_unittest.cc @@ -24,7 +24,7 @@ class TestVariationsSeedStore : public VariationsSeedStore { bool StoreSeedForTesting(const std::string& seed_data) { return StoreSeedData(seed_data, std::string(), std::string(), - base::Time::Now(), false, nullptr); + base::Time::Now(), false, false, nullptr); } VariationsSeedStore::VerifySignatureResult VerifySeedSignature( @@ -211,7 +211,7 @@ TEST(VariationsSeedStoreTest, StoreSeedData_ParsedSeed) { variations::VariationsSeed parsed_seed; EXPECT_TRUE(seed_store.StoreSeedData(serialized_seed, std::string(), std::string(), base::Time::Now(), false, - &parsed_seed)); + false, &parsed_seed)); EXPECT_EQ(serialized_seed, SerializeSeed(parsed_seed)); } @@ -225,7 +225,7 @@ TEST(VariationsSeedStoreTest, StoreSeedData_CountryCode) { seed.set_country_code("test_country"); EXPECT_TRUE(seed_store.StoreSeedData(SerializeSeed(seed), std::string(), std::string(), base::Time::Now(), false, - nullptr)); + false, nullptr)); EXPECT_EQ("test_country", prefs.GetString(prefs::kVariationsCountry)); // Test with a header value and no seed country. @@ -233,7 +233,7 @@ TEST(VariationsSeedStoreTest, StoreSeedData_CountryCode) { seed.clear_country_code(); EXPECT_TRUE(seed_store.StoreSeedData(SerializeSeed(seed), std::string(), "test_country2", base::Time::Now(), - false, nullptr)); + false, false, nullptr)); EXPECT_EQ("test_country2", prefs.GetString(prefs::kVariationsCountry)); // Test with a seed country code and header value. @@ -241,17 +241,49 @@ TEST(VariationsSeedStoreTest, StoreSeedData_CountryCode) { seed.set_country_code("test_country3"); EXPECT_TRUE(seed_store.StoreSeedData(SerializeSeed(seed), std::string(), "test_country4", base::Time::Now(), - false, nullptr)); + false, false, nullptr)); EXPECT_EQ("test_country4", prefs.GetString(prefs::kVariationsCountry)); // Test with no country code specified - which should preserve the old value. seed.clear_country_code(); EXPECT_TRUE(seed_store.StoreSeedData(SerializeSeed(seed), std::string(), std::string(), base::Time::Now(), false, - nullptr)); + false, nullptr)); EXPECT_EQ("test_country4", prefs.GetString(prefs::kVariationsCountry)); } +TEST(VariationsSeedStoreTest, StoreSeedData_GzippedSeed) { + const variations::VariationsSeed seed = CreateTestSeed(); + const std::string serialized_seed = SerializeSeed(seed); + std::string compressed_seed; + ASSERT_TRUE(compression::GzipCompress(serialized_seed, &compressed_seed)); + + TestingPrefServiceSimple prefs; + VariationsSeedStore::RegisterPrefs(prefs.registry()); + TestVariationsSeedStore seed_store(&prefs); + + variations::VariationsSeed parsed_seed; + EXPECT_TRUE(seed_store.StoreSeedData(compressed_seed, std::string(), + std::string(), base::Time::Now(), false, + true, &parsed_seed)); + EXPECT_EQ(serialized_seed, SerializeSeed(parsed_seed)); +} + +TEST(VariationsSeedStoreTest, StoreSeedData_GzippedEmptySeed) { + std::string empty_seed; + std::string compressed_seed; + ASSERT_TRUE(compression::GzipCompress(empty_seed, &compressed_seed)); + + TestingPrefServiceSimple prefs; + VariationsSeedStore::RegisterPrefs(prefs.registry()); + TestVariationsSeedStore seed_store(&prefs); + + variations::VariationsSeed parsed_seed; + EXPECT_FALSE(seed_store.StoreSeedData(compressed_seed, std::string(), + std::string(), base::Time::Now(), false, + true, &parsed_seed)); +} + TEST(VariationsSeedStoreTest, VerifySeedSignature) { // The below seed and signature pair were generated using the server's // private key. diff --git a/tools/metrics/histograms/histograms.xml b/tools/metrics/histograms/histograms.xml index 67ad828..9aab46f 100644 --- a/tools/metrics/histograms/histograms.xml +++ b/tools/metrics/histograms/histograms.xml @@ -49610,6 +49610,23 @@ http://cs/file:chrome/histograms.xml - but prefer this file for new entries. </summary> </histogram> +<histogram name="Variations.StoreSeed.GzipSize" units="KiB"> + <owner>asvitkine@chromium.org</owner> + <summary> + Records the size of the gzip-compressed variations seed in KiB. + </summary> +</histogram> + +<histogram name="Variations.StoreSeed.GzipSize.ReductionPercent" units="%"> + <owner>asvitkine@chromium.org</owner> + <summary> + Records the size of the gzip-compressed variations seed as a percentage of + the decoded seed size. Note that variations seed could be first + delta-compressed and then gzip-compressed. In this case we record + gzip-compressed seed size as a percentage of the delta-compressed seed size. + </summary> +</histogram> + <histogram name="Variations.StoreSeed.Size" units="KiB"> <owner>asvitkine@chromium.org</owner> <summary> @@ -74342,6 +74359,9 @@ To add a new entry, add it with any value and run test to compute valid value. <int value="6" label="Failed - Delta: Read Seed"/> <int value="7" label="Failed - Delta: Apply"/> <int value="8" label="Failed - Delta: Store Seed"/> + <int value="9" label="Failed - Gzip Uncompress Error"/> + <int value="10" label="Failed - Empty Gzip Contents"/> + <int value="11" label="Failed - Unsupported Seed Format"/> </enum> <enum name="VaryType" type="int"> |