blob: 50b78c7cd88e9163913749d7ea36411c6b3d5b93 [file] [log] [blame]
// Copyright 2017 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/metrics/metrics_log_store.h"
#include "components/metrics/metrics_pref_names.h"
#include "components/metrics/test_metrics_service_client.h"
#include "components/prefs/testing_pref_service.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace metrics {
namespace {
class MetricsLogStoreTest : public testing::Test {
public:
MetricsLogStoreTest() {
MetricsLogStore::RegisterPrefs(pref_service_.registry());
}
~MetricsLogStoreTest() override {}
MetricsLog* CreateLog(MetricsLog::LogType log_type) {
return new MetricsLog("id", 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)->GetSize();
}
TestMetricsServiceClient client_;
TestingPrefServiceSimple pref_service_;
private:
DISALLOW_COPY_AND_ASSIGN(MetricsLogStoreTest);
};
} // namespace
TEST_F(MetricsLogStoreTest, StandardFlow) {
MetricsLogStore log_store(&pref_service_, 0);
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);
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_, 0);
log_store.LoadPersistedUnsentLogs();
EXPECT_FALSE(log_store.has_unsent_logs());
log_store.StoreLog("a", MetricsLog::ONGOING_LOG);
log_store.PersistUnsentLogs();
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_, 0);
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);
log_store.StageNextLog();
log_store.StoreLog("b", MetricsLog::ONGOING_LOG);
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.PersistUnsentLogs();
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_, 0);
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.PersistUnsentLogs();
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 PersistUnsentLogs hasn't been
// called again.
EXPECT_EQ(2U, TypeCount(MetricsLog::ONGOING_LOG));
// Persist, and make sure nothing is left.
log_store.PersistUnsentLogs();
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_, 0);
log_store.LoadPersistedUnsentLogs();
log_store.StoreLog("a", MetricsLog::ONGOING_LOG);
log_store.StageNextLog();
log_store.PersistUnsentLogs();
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_, 0);
log_store.LoadPersistedUnsentLogs();
log_store.StoreLog("b", MetricsLog::INITIAL_STABILITY_LOG);
log_store.StageNextLog();
log_store.PersistUnsentLogs();
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.
MetricsLogStore log_store(&pref_service_, 1);
log_store.LoadPersistedUnsentLogs();
log_store.StoreLog("persisted", MetricsLog::INITIAL_STABILITY_LOG);
log_store.StoreLog("not_persisted", MetricsLog::ONGOING_LOG);
// Only the stability log should be written out, due to the threshold.
log_store.PersistUnsentLogs();
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_, 0);
log_store.LoadPersistedUnsentLogs();
log_store.StoreLog("a", MetricsLog::ONGOING_LOG);
log_store.StoreLog("b", MetricsLog::ONGOING_LOG);
log_store.StageNextLog();
log_store.StoreLog("c", MetricsLog::INITIAL_STABILITY_LOG);
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());
}
} // namespace metrics