423 lines
18 KiB
C++
423 lines
18 KiB
C++
// 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,
|
|
/*min_log_count=*/3,
|
|
/*min_log_bytes=*/1,
|
|
/*max_log_size=*/0,
|
|
/*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(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
|