blob: aeb51a905780bd06e0b0a3e8ca9ba5112b19f78d [file] [log] [blame]
// Copyright 2017 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "components/metrics/metrics_log_store.h"
#include "components/metrics/metrics_logs_event_manager.h"
#include "components/metrics/metrics_pref_names.h"
#include "components/metrics/test/test_metrics_service_client.h"
#include "components/metrics/unsent_log_store_metrics_impl.h"
#include "components/prefs/pref_registry_simple.h"
#include "components/prefs/testing_pref_service.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace metrics {
namespace {
const char kTestPrefName[] = "TestPref";
class TestUnsentLogStore : public UnsentLogStore {
public:
explicit TestUnsentLogStore(PrefService* service)
: UnsentLogStore(std::make_unique<UnsentLogStoreMetricsImpl>(),
service,
kTestPrefName,
nullptr,
// Set to 3 so logs are not dropped in the test.
UnsentLogStore::UnsentLogStoreLimits{
.min_log_count = 3,
},
/*signing_key=*/std::string(),
/*logs_event_manager=*/nullptr) {}
~TestUnsentLogStore() override = default;
TestUnsentLogStore(const TestUnsentLogStore&) = delete;
TestUnsentLogStore& operator=(const TestUnsentLogStore&) = delete;
static void RegisterPrefs(PrefRegistrySimple* registry) {
registry->RegisterListPref(kTestPrefName);
}
};
class MetricsLogStoreTest : public testing::Test {
public:
MetricsLogStoreTest() {
MetricsLogStore::RegisterPrefs(pref_service_.registry());
TestUnsentLogStore::RegisterPrefs(pref_service_.registry());
}
MetricsLogStoreTest(const MetricsLogStoreTest&) = delete;
MetricsLogStoreTest& operator=(const MetricsLogStoreTest&) = delete;
~MetricsLogStoreTest() override {}
MetricsLog* CreateLog(MetricsLog::LogType log_type) {
return new MetricsLog("0a94430b-18e5-43c8-a657-580f7e855ce1", 0, log_type,
&client_);
}
// Returns the stored number of logs of the given type.
size_t TypeCount(MetricsLog::LogType log_type) {
const char* pref = log_type == MetricsLog::INITIAL_STABILITY_LOG
? prefs::kMetricsInitialLogs
: prefs::kMetricsOngoingLogs;
return pref_service_.GetList(pref).size();
}
TestMetricsServiceClient client_;
TestingPrefServiceSimple pref_service_;
};
} // namespace
TEST_F(MetricsLogStoreTest, StandardFlow) {
MetricsLogStore log_store(&pref_service_, client_.GetStorageLimits(),
/*signing_key=*/std::string(),
/*logs_event_manager=*/nullptr);
log_store.LoadPersistedUnsentLogs();
// Make sure a new manager has a clean slate.
EXPECT_FALSE(log_store.has_staged_log());
EXPECT_FALSE(log_store.has_unsent_logs());
log_store.StoreLog("a", MetricsLog::ONGOING_LOG, LogMetadata(),
MetricsLogsEventManager::CreateReason::kUnknown);
EXPECT_TRUE(log_store.has_unsent_logs());
EXPECT_FALSE(log_store.has_staged_log());
log_store.StageNextLog();
EXPECT_TRUE(log_store.has_staged_log());
EXPECT_FALSE(log_store.staged_log().empty());
log_store.DiscardStagedLog();
EXPECT_FALSE(log_store.has_staged_log());
EXPECT_FALSE(log_store.has_unsent_logs());
}
TEST_F(MetricsLogStoreTest, StoreAndLoad) {
// Set up some in-progress logging in a scoped log manager simulating the
// leadup to quitting, then persist as would be done on quit.
{
MetricsLogStore log_store(&pref_service_, client_.GetStorageLimits(),
/*signing_key=*/std::string(),
/*logs_event_manager=*/nullptr);
log_store.LoadPersistedUnsentLogs();
EXPECT_FALSE(log_store.has_unsent_logs());
log_store.StoreLog("a", MetricsLog::ONGOING_LOG, LogMetadata(),
MetricsLogsEventManager::CreateReason::kUnknown);
log_store.TrimAndPersistUnsentLogs(/*overwrite_in_memory_store=*/true);
EXPECT_EQ(0U, TypeCount(MetricsLog::INITIAL_STABILITY_LOG));
EXPECT_EQ(1U, TypeCount(MetricsLog::ONGOING_LOG));
}
// Relaunch load and store more logs.
{
MetricsLogStore log_store(&pref_service_, client_.GetStorageLimits(),
/*signing_key=*/std::string(),
/*logs_event_manager=*/nullptr);
log_store.LoadPersistedUnsentLogs();
EXPECT_TRUE(log_store.has_unsent_logs());
EXPECT_EQ(0U, TypeCount(MetricsLog::INITIAL_STABILITY_LOG));
EXPECT_EQ(1U, TypeCount(MetricsLog::ONGOING_LOG));
log_store.StoreLog("x", MetricsLog::INITIAL_STABILITY_LOG, LogMetadata(),
MetricsLogsEventManager::CreateReason::kUnknown);
log_store.StageNextLog();
log_store.StoreLog("b", MetricsLog::ONGOING_LOG, LogMetadata(),
MetricsLogsEventManager::CreateReason::kUnknown);
EXPECT_TRUE(log_store.has_unsent_logs());
EXPECT_TRUE(log_store.has_staged_log());
EXPECT_EQ(0U, TypeCount(MetricsLog::INITIAL_STABILITY_LOG));
EXPECT_EQ(1U, TypeCount(MetricsLog::ONGOING_LOG));
log_store.TrimAndPersistUnsentLogs(/*overwrite_in_memory_store=*/true);
EXPECT_EQ(1U, TypeCount(MetricsLog::INITIAL_STABILITY_LOG));
EXPECT_EQ(2U, TypeCount(MetricsLog::ONGOING_LOG));
}
// Relaunch and verify that once logs are handled they are not re-persisted.
{
MetricsLogStore log_store(&pref_service_, client_.GetStorageLimits(),
/*signing_key=*/std::string(),
/*logs_event_manager=*/nullptr);
log_store.LoadPersistedUnsentLogs();
EXPECT_TRUE(log_store.has_unsent_logs());
log_store.StageNextLog();
log_store.DiscardStagedLog();
// The initial log should be sent first; update the persisted storage to
// verify.
log_store.TrimAndPersistUnsentLogs(/*overwrite_in_memory_store=*/true);
EXPECT_EQ(0U, TypeCount(MetricsLog::INITIAL_STABILITY_LOG));
EXPECT_EQ(2U, TypeCount(MetricsLog::ONGOING_LOG));
// Handle the first ongoing log.
log_store.StageNextLog();
log_store.DiscardStagedLog();
EXPECT_TRUE(log_store.has_unsent_logs());
// Handle the last log.
log_store.StageNextLog();
log_store.DiscardStagedLog();
EXPECT_FALSE(log_store.has_unsent_logs());
// Nothing should have changed "on disk" since TrimAndPersistUnsentLogs
// hasn't been called again.
EXPECT_EQ(2U, TypeCount(MetricsLog::ONGOING_LOG));
// Persist, and make sure nothing is left.
log_store.TrimAndPersistUnsentLogs(/*overwrite_in_memory_store=*/true);
EXPECT_EQ(0U, TypeCount(MetricsLog::INITIAL_STABILITY_LOG));
EXPECT_EQ(0U, TypeCount(MetricsLog::ONGOING_LOG));
}
}
TEST_F(MetricsLogStoreTest, StoreStagedOngoingLog) {
// Ensure that types are preserved when storing staged logs.
MetricsLogStore log_store(&pref_service_, client_.GetStorageLimits(),
/*signing_key=*/std::string(),
/*logs_event_manager=*/nullptr);
log_store.LoadPersistedUnsentLogs();
log_store.StoreLog("a", MetricsLog::ONGOING_LOG, LogMetadata(),
MetricsLogsEventManager::CreateReason::kUnknown);
log_store.StageNextLog();
log_store.TrimAndPersistUnsentLogs(/*overwrite_in_memory_store=*/true);
EXPECT_EQ(0U, TypeCount(MetricsLog::INITIAL_STABILITY_LOG));
EXPECT_EQ(1U, TypeCount(MetricsLog::ONGOING_LOG));
}
TEST_F(MetricsLogStoreTest, StoreStagedInitialLog) {
// Ensure that types are preserved when storing staged logs.
MetricsLogStore log_store(&pref_service_, client_.GetStorageLimits(),
/*signing_key=*/std::string(),
/*logs_event_manager=*/nullptr);
log_store.LoadPersistedUnsentLogs();
log_store.StoreLog("b", MetricsLog::INITIAL_STABILITY_LOG, LogMetadata(),
MetricsLogsEventManager::CreateReason::kUnknown);
log_store.StageNextLog();
log_store.TrimAndPersistUnsentLogs(/*overwrite_in_memory_store=*/true);
EXPECT_EQ(1U, TypeCount(MetricsLog::INITIAL_STABILITY_LOG));
EXPECT_EQ(0U, TypeCount(MetricsLog::ONGOING_LOG));
}
TEST_F(MetricsLogStoreTest, LargeLogDiscarding) {
// Set the size threshold very low, to verify that it's honored.
client_.set_max_ongoing_log_size_bytes(1);
MetricsLogStore log_store(&pref_service_, client_.GetStorageLimits(),
/*signing_key=*/std::string(),
/*logs_event_manager=*/nullptr);
log_store.LoadPersistedUnsentLogs();
log_store.StoreLog("persisted", MetricsLog::INITIAL_STABILITY_LOG,
LogMetadata(),
MetricsLogsEventManager::CreateReason::kUnknown);
log_store.StoreLog("not_persisted", MetricsLog::ONGOING_LOG, LogMetadata(),
MetricsLogsEventManager::CreateReason::kUnknown);
// Only the stability log should be written out, due to the threshold.
log_store.TrimAndPersistUnsentLogs(/*overwrite_in_memory_store=*/true);
EXPECT_EQ(1U, TypeCount(MetricsLog::INITIAL_STABILITY_LOG));
EXPECT_EQ(0U, TypeCount(MetricsLog::ONGOING_LOG));
}
TEST_F(MetricsLogStoreTest, DiscardOrder) {
// Ensure that the correct log is discarded if new logs are pushed while
// a log is staged.
MetricsLogStore log_store(&pref_service_, client_.GetStorageLimits(),
/*signing_key=*/std::string(),
/*logs_event_manager=*/nullptr);
log_store.LoadPersistedUnsentLogs();
log_store.StoreLog("a", MetricsLog::ONGOING_LOG, LogMetadata(),
MetricsLogsEventManager::CreateReason::kUnknown);
log_store.StoreLog("b", MetricsLog::ONGOING_LOG, LogMetadata(),
MetricsLogsEventManager::CreateReason::kUnknown);
log_store.StageNextLog();
log_store.StoreLog("c", MetricsLog::INITIAL_STABILITY_LOG, LogMetadata(),
MetricsLogsEventManager::CreateReason::kUnknown);
EXPECT_EQ(2U, log_store.ongoing_log_count());
EXPECT_EQ(1U, log_store.initial_log_count());
// Should discard the ongoing log staged earlier.
log_store.DiscardStagedLog();
EXPECT_EQ(1U, log_store.ongoing_log_count());
EXPECT_EQ(1U, log_store.initial_log_count());
// Initial log should be staged next.
log_store.StageNextLog();
log_store.DiscardStagedLog();
EXPECT_EQ(1U, log_store.ongoing_log_count());
EXPECT_EQ(0U, log_store.initial_log_count());
}
TEST_F(MetricsLogStoreTest, WritesToAlternateOngoingLogStore) {
MetricsLogStore log_store(&pref_service_, client_.GetStorageLimits(),
/*signing_key=*/std::string(),
/*logs_event_manager=*/nullptr);
std::unique_ptr<TestUnsentLogStore> alternate_ongoing_log_store =
std::make_unique<TestUnsentLogStore>(&pref_service_);
TestUnsentLogStore* alternate_ongoing_log_store_ptr =
alternate_ongoing_log_store.get();
// Needs to be called before writing logs to alternate ongoing store since
// SetAlternateOngoingLogStore loads persisted unsent logs and assumes that
// the native initial and ongoing unsent logs have already been loaded.
log_store.LoadPersistedUnsentLogs();
log_store.StoreLog("a", MetricsLog::ONGOING_LOG, LogMetadata(),
MetricsLogsEventManager::CreateReason::kUnknown);
log_store.SetAlternateOngoingLogStore(std::move(alternate_ongoing_log_store));
log_store.StoreLog("b", MetricsLog::ONGOING_LOG, LogMetadata(),
MetricsLogsEventManager::CreateReason::kUnknown);
log_store.StoreLog("c", MetricsLog::ONGOING_LOG, LogMetadata(),
MetricsLogsEventManager::CreateReason::kUnknown);
EXPECT_EQ(1U, log_store.ongoing_log_count());
EXPECT_EQ(2U, alternate_ongoing_log_store_ptr->size());
}
TEST_F(MetricsLogStoreTest, AlternateOngoingLogStoreGetsEventsLogsManager) {
// Create a MetricsLogStore with a MetricsLogsEventManager.
MetricsLogsEventManager logs_event_manager;
MetricsLogStore log_store(&pref_service_, client_.GetStorageLimits(),
/*signing_key=*/std::string(), &logs_event_manager);
// Create an UnsentLogStore that will be used as an alternate ongoing log
// store.
std::unique_ptr<TestUnsentLogStore> alternate_ongoing_log_store =
std::make_unique<TestUnsentLogStore>(&pref_service_);
TestUnsentLogStore* alternate_ongoing_log_store_ptr =
alternate_ongoing_log_store.get();
// Verify that |alternate_ongoing_log_store| has no logs event manager.
EXPECT_FALSE(
alternate_ongoing_log_store_ptr->GetLogsEventManagerForTesting());
// Needs to be called before we can set |log_store|'s alternate ongoing log
// store.
log_store.LoadPersistedUnsentLogs();
// Verify that after setting |log_store|'s alternate ongoing log store to
// |alternate_ongoing_log_store|, the latter should have the former's logs
// event manager.
log_store.SetAlternateOngoingLogStore(std::move(alternate_ongoing_log_store));
EXPECT_EQ(alternate_ongoing_log_store_ptr->GetLogsEventManagerForTesting(),
&logs_event_manager);
}
TEST_F(MetricsLogStoreTest, StagesInitialOverBothOngoing) {
MetricsLogStore log_store(&pref_service_, client_.GetStorageLimits(),
/*signing_key=*/std::string(),
/*logs_event_manager=*/nullptr);
std::unique_ptr<TestUnsentLogStore> alternate_ongoing_log_store =
std::make_unique<TestUnsentLogStore>(&pref_service_);
TestUnsentLogStore* alternate_ongoing_log_store_ptr =
alternate_ongoing_log_store.get();
// Needs to be called before writing logs to alternate ongoing store since
// SetAlternateOngoingLogStore loads persisted unsent logs and assumes that
// the native initial and ongoing unsent logs have already been loaded.
log_store.LoadPersistedUnsentLogs();
log_store.StoreLog("a", MetricsLog::INITIAL_STABILITY_LOG, LogMetadata(),
MetricsLogsEventManager::CreateReason::kUnknown);
log_store.StoreLog("b", MetricsLog::ONGOING_LOG, LogMetadata(),
MetricsLogsEventManager::CreateReason::kUnknown);
log_store.SetAlternateOngoingLogStore(std::move(alternate_ongoing_log_store));
log_store.StoreLog("c", MetricsLog::ONGOING_LOG, LogMetadata(),
MetricsLogsEventManager::CreateReason::kUnknown);
log_store.StageNextLog();
log_store.DiscardStagedLog();
// Discarded log should be from initial_log_store.
EXPECT_EQ(0U, log_store.initial_log_count());
EXPECT_EQ(1U, log_store.ongoing_log_count());
EXPECT_EQ(1U, alternate_ongoing_log_store_ptr->size());
}
TEST_F(MetricsLogStoreTest, StagesAlternateOverOngoing) {
MetricsLogStore log_store(&pref_service_, client_.GetStorageLimits(),
/*signing_key=*/std::string(),
/*logs_event_manager=*/nullptr);
std::unique_ptr<TestUnsentLogStore> alternate_ongoing_log_store =
std::make_unique<TestUnsentLogStore>(&pref_service_);
TestUnsentLogStore* alternate_ongoing_log_store_ptr =
alternate_ongoing_log_store.get();
// Needs to be called before writing logs to alternate ongoing store since
// SetAlternateOngoingLogStore loads persisted unsent logs and assumes that
// the native initial and ongoing unsent logs have already been loaded.
log_store.LoadPersistedUnsentLogs();
log_store.StoreLog("a", MetricsLog::ONGOING_LOG, LogMetadata(),
MetricsLogsEventManager::CreateReason::kUnknown);
log_store.SetAlternateOngoingLogStore(std::move(alternate_ongoing_log_store));
log_store.StoreLog("b", MetricsLog::ONGOING_LOG, LogMetadata(),
MetricsLogsEventManager::CreateReason::kUnknown);
log_store.StageNextLog();
log_store.DiscardStagedLog();
// Discarded log should be from alternate_ongoing_log_store.
EXPECT_EQ(1U, log_store.ongoing_log_count());
EXPECT_EQ(0U, alternate_ongoing_log_store_ptr->size());
}
TEST_F(MetricsLogStoreTest,
UnboundAlternateOngoingLogStoreWritesToNativeOngoing) {
MetricsLogStore log_store(&pref_service_, client_.GetStorageLimits(),
/*signing_key=*/std::string(),
/*logs_event_manager=*/nullptr);
std::unique_ptr<TestUnsentLogStore> alternate_ongoing_log_store =
std::make_unique<TestUnsentLogStore>(&pref_service_);
// Needs to be called before writing logs to alternate ongoing store since
// SetAlternateOngoingLogStore loads persisted unsent logs and assumes that
// the native initial and ongoing unsent logs have already been loaded.
log_store.LoadPersistedUnsentLogs();
log_store.SetAlternateOngoingLogStore(std::move(alternate_ongoing_log_store));
// Should be written to alternate ongoing log store.
log_store.StoreLog("a", MetricsLog::ONGOING_LOG, LogMetadata(),
MetricsLogsEventManager::CreateReason::kUnknown);
log_store.UnsetAlternateOngoingLogStore();
// Should be in native ongoing log store.
log_store.StoreLog("b", MetricsLog::ONGOING_LOG, LogMetadata(),
MetricsLogsEventManager::CreateReason::kUnknown);
log_store.StoreLog("c", MetricsLog::ONGOING_LOG, LogMetadata(),
MetricsLogsEventManager::CreateReason::kUnknown);
EXPECT_EQ(2U, log_store.ongoing_log_count());
}
TEST_F(MetricsLogStoreTest,
StageOngoingLogWhenAlternateOngoingLogStoreIsEmpty) {
MetricsLogStore log_store(&pref_service_, client_.GetStorageLimits(),
/*signing_key=*/std::string(),
/*logs_event_manager=*/nullptr);
std::unique_ptr<TestUnsentLogStore> alternate_ongoing_log_store =
std::make_unique<TestUnsentLogStore>(&pref_service_);
// Needs to be called before writing logs to alternate ongoing store since
// SetAlternateOngoingLogStore loads persisted unsent logs and assumes that
// the native initial and ongoing unsent logs have already been loaded.
log_store.LoadPersistedUnsentLogs();
// Should be written to ongoing log store.
log_store.StoreLog("a", MetricsLog::ONGOING_LOG, LogMetadata(),
MetricsLogsEventManager::CreateReason::kUnknown);
// Ensure that the log was stored in ongoing log.
EXPECT_EQ(1U, log_store.ongoing_log_count());
log_store.SetAlternateOngoingLogStore(std::move(alternate_ongoing_log_store));
log_store.StageNextLog();
log_store.DiscardStagedLog();
// Discarded log should be from ongoing.
EXPECT_EQ(0U, log_store.ongoing_log_count());
}
} // namespace metrics