blob: 28f28d605d8c0100120a2798f8a30150ea2dc3a6 [file] [log] [blame]
// Copyright 2018 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "components/variations/service/safe_seed_manager.h"
#include <memory>
#include <string>
#include "base/base_switches.h"
#include "base/command_line.h"
#include "base/macros.h"
#include "base/test/metrics/histogram_tester.h"
#include "base/time/time.h"
#include "components/prefs/testing_pref_service.h"
#include "components/variations/client_filterable_state.h"
#include "components/variations/pref_names.h"
#include "components/variations/variations_seed_store.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace variations {
namespace {
const char kTestSeed[] = "compressed, base-64 encoded serialized seed data";
const char kTestSignature[] = "a completely unforged signature, I promise!";
const char kTestLocale[] = "en-US";
const char kTestPermanentConsistencyCountry[] = "US";
const char kTestSessionConsistencyCountry[] = "CA";
base::Time GetTestFetchTime() {
return base::Time::FromDeltaSinceWindowsEpoch(base::TimeDelta::FromDays(123));
}
// A simple fake data store.
class FakeSeedStore : public VariationsSeedStore {
public:
explicit FakeSeedStore(PrefService* local_state)
: VariationsSeedStore(local_state) {}
~FakeSeedStore() override = default;
bool StoreSafeSeed(const std::string& seed_data,
const std::string& base64_seed_signature,
const ClientFilterableState& client_state,
base::Time seed_fetch_time) override {
seed_data_ = seed_data;
signature_ = base64_seed_signature;
date_ = client_state.reference_date;
locale_ = client_state.locale;
permanent_consistency_country_ = client_state.permanent_consistency_country;
session_consistency_country_ = client_state.session_consistency_country;
fetch_time_ = seed_fetch_time;
return true;
}
const std::string& seed_data() const { return seed_data_; }
const std::string& signature() const { return signature_; }
const base::Time& date() const { return date_; }
const std::string& locale() const { return locale_; }
const std::string& permanent_consistency_country() const {
return permanent_consistency_country_;
}
const std::string& session_consistency_country() const {
return session_consistency_country_;
}
const base::Time& fetch_time() const { return fetch_time_; }
private:
// The stored data.
std::string seed_data_;
std::string signature_;
base::Time date_;
std::string locale_;
std::string permanent_consistency_country_;
std::string session_consistency_country_;
base::Time fetch_time_;
DISALLOW_COPY_AND_ASSIGN(FakeSeedStore);
};
// Passes the default test values as the active state into the
// |safe_seed_manager|.
void SetDefaultActiveState(SafeSeedManager* safe_seed_manager) {
std::unique_ptr<ClientFilterableState> client_state =
std::make_unique<ClientFilterableState>();
client_state->locale = kTestLocale;
client_state->permanent_consistency_country =
kTestPermanentConsistencyCountry;
client_state->session_consistency_country = kTestSessionConsistencyCountry;
client_state->reference_date = base::Time::UnixEpoch();
safe_seed_manager->SetActiveSeedState(
kTestSeed, kTestSignature, std::move(client_state), GetTestFetchTime());
}
// Verifies that the default test values were written to the seed store.
void ExpectDefaultActiveState(const FakeSeedStore& seed_store) {
EXPECT_EQ(kTestSeed, seed_store.seed_data());
EXPECT_EQ(kTestSignature, seed_store.signature());
EXPECT_EQ(kTestLocale, seed_store.locale());
EXPECT_EQ(kTestPermanentConsistencyCountry,
seed_store.permanent_consistency_country());
EXPECT_EQ(kTestSessionConsistencyCountry,
seed_store.session_consistency_country());
EXPECT_EQ(base::Time::UnixEpoch(), seed_store.date());
EXPECT_EQ(GetTestFetchTime(), seed_store.fetch_time());
}
} // namespace
class SafeSeedManagerTest : public testing::Test {
public:
SafeSeedManagerTest() { SafeSeedManager::RegisterPrefs(prefs_.registry()); }
~SafeSeedManagerTest() override = default;
protected:
TestingPrefServiceSimple prefs_;
};
TEST_F(SafeSeedManagerTest, RecordSuccessfulFetch_FirstCallSavesSafeSeed) {
SafeSeedManager safe_seed_manager(true, &prefs_);
SetDefaultActiveState(&safe_seed_manager);
FakeSeedStore seed_store(&prefs_);
safe_seed_manager.RecordSuccessfulFetch(&seed_store);
ExpectDefaultActiveState(seed_store);
}
TEST_F(SafeSeedManagerTest, RecordSuccessfulFetch_RepeatedCallsRetainSafeSeed) {
SafeSeedManager safe_seed_manager(true, &prefs_);
SetDefaultActiveState(&safe_seed_manager);
FakeSeedStore seed_store(&prefs_);
safe_seed_manager.RecordSuccessfulFetch(&seed_store);
safe_seed_manager.RecordSuccessfulFetch(&seed_store);
safe_seed_manager.RecordSuccessfulFetch(&seed_store);
ExpectDefaultActiveState(seed_store);
}
TEST_F(SafeSeedManagerTest,
RecordSuccessfulFetch_NoActiveState_DoesntSaveSafeSeed) {
SafeSeedManager safe_seed_manager(true, &prefs_);
// Omit setting any active state.
FakeSeedStore seed_store(&prefs_);
safe_seed_manager.RecordSuccessfulFetch(&seed_store);
EXPECT_EQ(std::string(), seed_store.seed_data());
EXPECT_EQ(std::string(), seed_store.signature());
EXPECT_EQ(std::string(), seed_store.locale());
EXPECT_EQ(std::string(), seed_store.permanent_consistency_country());
EXPECT_EQ(std::string(), seed_store.session_consistency_country());
EXPECT_EQ(base::Time(), seed_store.date());
EXPECT_EQ(base::Time(), seed_store.fetch_time());
}
TEST_F(SafeSeedManagerTest, StreakMetrics_NoPrefs) {
base::HistogramTester histogram_tester;
SafeSeedManager safe_seed_manager(true, &prefs_);
histogram_tester.ExpectUniqueSample("Variations.SafeMode.Streak.Crashes", 0,
1);
histogram_tester.ExpectUniqueSample(
"Variations.SafeMode.Streak.FetchFailures", 0, 1);
}
TEST_F(SafeSeedManagerTest, StreakMetrics_NoCrashes_NoFetchFailures) {
prefs_.SetInteger(prefs::kVariationsCrashStreak, 0);
prefs_.SetInteger(prefs::kVariationsFailedToFetchSeedStreak, 0);
base::HistogramTester histogram_tester;
SafeSeedManager safe_seed_manager(true, &prefs_);
histogram_tester.ExpectUniqueSample("Variations.SafeMode.Streak.Crashes", 0,
1);
histogram_tester.ExpectUniqueSample(
"Variations.SafeMode.Streak.FetchFailures", 0, 1);
}
TEST_F(SafeSeedManagerTest, StreakMetrics_SomeCrashes_SomeFetchFailures) {
prefs_.SetInteger(prefs::kVariationsCrashStreak, 1);
prefs_.SetInteger(prefs::kVariationsFailedToFetchSeedStreak, 2);
base::HistogramTester histogram_tester;
SafeSeedManager safe_seed_manager(true, &prefs_);
histogram_tester.ExpectUniqueSample("Variations.SafeMode.Streak.Crashes", 1,
1);
histogram_tester.ExpectUniqueSample(
"Variations.SafeMode.Streak.FetchFailures", 2, 1);
}
TEST_F(SafeSeedManagerTest, StreakMetrics_CrashIncrementsCrashStreak) {
prefs_.SetInteger(prefs::kVariationsCrashStreak, 1);
base::HistogramTester histogram_tester;
SafeSeedManager safe_seed_manager(false, &prefs_);
EXPECT_EQ(2, prefs_.GetInteger(prefs::kVariationsCrashStreak));
histogram_tester.ExpectUniqueSample("Variations.SafeMode.Streak.Crashes", 2,
1);
}
TEST_F(SafeSeedManagerTest, StreakMetrics_CrashIncrementsCrashStreak_NoPrefs) {
base::HistogramTester histogram_tester;
SafeSeedManager safe_seed_manager(false, &prefs_);
EXPECT_EQ(1, prefs_.GetInteger(prefs::kVariationsCrashStreak));
histogram_tester.ExpectUniqueSample("Variations.SafeMode.Streak.Crashes", 1,
1);
}
TEST_F(SafeSeedManagerTest, ShouldRunInSafeMode_OverriddenByCommandlineFlag) {
// So many failures.
prefs_.SetInteger(prefs::kVariationsCrashStreak, 100);
prefs_.SetInteger(prefs::kVariationsFailedToFetchSeedStreak, 100);
base::CommandLine::ForCurrentProcess()->AppendSwitchASCII(
::switches::kForceFieldTrials, "SomeFieldTrial");
SafeSeedManager safe_seed_manager(true, &prefs_);
EXPECT_FALSE(safe_seed_manager.ShouldRunInSafeMode());
}
TEST_F(SafeSeedManagerTest, ShouldRunInSafeMode_NoCrashes_NoFetchFailures) {
prefs_.SetInteger(prefs::kVariationsCrashStreak, 0);
prefs_.SetInteger(prefs::kVariationsFailedToFetchSeedStreak, 0);
SafeSeedManager safe_seed_manager(true, &prefs_);
EXPECT_FALSE(safe_seed_manager.ShouldRunInSafeMode());
}
TEST_F(SafeSeedManagerTest, ShouldRunInSafeMode_NoPrefs) {
// Don't explicitly set either of the prefs. The implicit/default values
// should be zero.
SafeSeedManager safe_seed_manager(true, &prefs_);
EXPECT_FALSE(safe_seed_manager.ShouldRunInSafeMode());
}
TEST_F(SafeSeedManagerTest, ShouldRunInSafeMode_FewCrashes_FewFetchFailures) {
prefs_.SetInteger(prefs::kVariationsCrashStreak, 2);
prefs_.SetInteger(prefs::kVariationsFailedToFetchSeedStreak, 2);
SafeSeedManager safe_seed_manager(true, &prefs_);
EXPECT_FALSE(safe_seed_manager.ShouldRunInSafeMode());
}
TEST_F(SafeSeedManagerTest, ShouldRunInSafeMode_ManyCrashes_NoFetchFailures) {
prefs_.SetInteger(prefs::kVariationsCrashStreak, 3);
prefs_.SetInteger(prefs::kVariationsFailedToFetchSeedStreak, 0);
SafeSeedManager safe_seed_manager(true, &prefs_);
EXPECT_TRUE(safe_seed_manager.ShouldRunInSafeMode());
}
TEST_F(SafeSeedManagerTest, ShouldRunInSafeMode_NoCrashes_ManyFetchFailures) {
prefs_.SetInteger(prefs::kVariationsCrashStreak, 0);
prefs_.SetInteger(prefs::kVariationsFailedToFetchSeedStreak, 50);
SafeSeedManager safe_seed_manager(true, &prefs_);
EXPECT_TRUE(safe_seed_manager.ShouldRunInSafeMode());
}
TEST_F(SafeSeedManagerTest, ShouldRunInSafeMode_ManyCrashes_ManyFetchFailures) {
prefs_.SetInteger(prefs::kVariationsCrashStreak, 3);
prefs_.SetInteger(prefs::kVariationsFailedToFetchSeedStreak, 50);
SafeSeedManager safe_seed_manager(true, &prefs_);
EXPECT_TRUE(safe_seed_manager.ShouldRunInSafeMode());
}
} // namespace variations