blob: 6293ce1f511ebd9c435f059b89fe9f758d30f3ad [file] [log] [blame]
// Copyright 2022 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/reporting/health/health_module_files.h"
#include <string>
#include "base/files/scoped_temp_dir.h"
#include "base/strings/strcat.h"
#include "base/strings/string_number_conversions.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
using ::testing::IsEmpty;
using ::testing::StrEq;
namespace reporting {
namespace {
constexpr char kBaseFileOne[] = "base_file_name";
constexpr char kUnmatchedBaseFile[] = "no_files_match_this";
constexpr int kInitialFiles = 3;
constexpr int kIntialRecordsPerFile = 5;
constexpr uint32_t kSimpleEnqueueRecordCallLineSize = 21u;
constexpr uint32_t kSmallMaxStorageSize = 70u;
constexpr uint32_t kLargeMaxStorageSize = 1000u;
constexpr uint32_t kFullMaxStorageSize = 20000u;
constexpr char kHexCharLookup[0x10] = {
'0', '1', '2', '3', '4', '5', '6', '7',
'8', '9', 'A', 'B', 'C', 'D', 'E', 'F',
};
std::string BytesToHexString(base::StringPiece bytes) {
std::string result;
for (char byte : bytes) {
result.push_back(kHexCharLookup[(byte >> 4) & 0xf]);
result.push_back(kHexCharLookup[byte & 0xf]);
}
return result;
}
class HealthModuleFilesTest : public ::testing::Test {
protected:
void SetUp() override {
ASSERT_TRUE(directory_.CreateUniqueTempDir());
for (int i = 0; i < kInitialFiles; i++) {
const std::string file_name =
base::StrCat({kBaseFileOne, base::NumberToString(i)});
for (int k = 0; k < kIntialRecordsPerFile; k++) {
auto call = AddEnqueueRecordCall();
*initial_health_data_.add_history() = call;
ASSERT_TRUE(AppendLine(directory_.GetPath().AppendASCII(file_name),
BytesToHexString(call.SerializeAsString()))
.ok());
}
}
}
HealthDataHistory AddEnqueueRecordCall() {
HealthDataHistory history;
EnqueueRecordCall call;
call.set_priority(
static_cast<Priority>(priority_counter_++ % Priority_MAX + 1));
*history.mutable_enqueue_record_call() = call;
history.set_timestamp_seconds(base::Time::Now().ToTimeT());
return history;
}
base::ScopedTempDir directory_;
ERPHealthData initial_health_data_;
private:
int priority_counter_ = Priority_MIN;
};
TEST_F(HealthModuleFilesTest, TestCreation) {
ERPHealthData history;
std::unique_ptr<HealthModuleFiles> files = HealthModuleFiles::Create(
directory_.GetPath(), kBaseFileOne, kLargeMaxStorageSize);
ASSERT_TRUE(files != nullptr);
files->PopulateHistory(&history);
EXPECT_THAT(history.SerializeAsString(),
StrEq(initial_health_data_.SerializeAsString()));
ERPHealthData empty_history;
std::unique_ptr<HealthModuleFiles> no_files = HealthModuleFiles::Create(
directory_.GetPath(), kUnmatchedBaseFile, kLargeMaxStorageSize);
ASSERT_TRUE(no_files != nullptr);
no_files->PopulateHistory(&empty_history);
EXPECT_THAT(empty_history.history(), IsEmpty());
ERPHealthData small_history;
const uint32_t total_records_stored =
kSmallMaxStorageSize / kSimpleEnqueueRecordCallLineSize;
std::unique_ptr<HealthModuleFiles> small_files = HealthModuleFiles::Create(
directory_.GetPath(), kBaseFileOne, kSmallMaxStorageSize);
ASSERT_TRUE(small_files != nullptr);
small_files->PopulateHistory(&small_history);
int initial_size = initial_health_data_.history_size();
initial_health_data_.mutable_history()->DeleteSubrange(
0, initial_size - total_records_stored);
EXPECT_THAT(small_history.SerializeAsString(),
StrEq(initial_health_data_.SerializeAsString()));
std::unique_ptr<HealthModuleFiles> null_files = HealthModuleFiles::Create(
directory_.GetPath(), kBaseFileOne, /*max_storage_space=*/0);
ASSERT_TRUE(null_files == nullptr);
}
TEST_F(HealthModuleFilesTest, TestFullStorage) {
ERPHealthData history;
std::unique_ptr<HealthModuleFiles> files = HealthModuleFiles::Create(
directory_.GetPath(), kBaseFileOne, kFullMaxStorageSize);
static constexpr uint32_t total_records_stored =
kFullMaxStorageSize / kSimpleEnqueueRecordCallLineSize;
ASSERT_TRUE(files != nullptr);
for (int i = 0; i < 1000; i++) {
auto call = AddEnqueueRecordCall();
ASSERT_OK(files->Write(BytesToHexString(call.SerializeAsString())));
if (i + total_records_stored >= 1000) {
*history.add_history() = call;
}
}
ERPHealthData got;
files->PopulateHistory(&got);
EXPECT_THAT(history.SerializeAsString(), StrEq(got.SerializeAsString()));
}
TEST_F(HealthModuleFilesTest, NotEnoughStorage) {
ERPHealthData history;
std::unique_ptr<HealthModuleFiles> files = HealthModuleFiles::Create(
directory_.GetPath(), kBaseFileOne, /*max_storage_space=*/1);
ASSERT_TRUE(files != nullptr);
files->PopulateHistory(&history);
ASSERT_THAT(history.history(), IsEmpty());
ASSERT_FALSE(
files->Write(BytesToHexString(AddEnqueueRecordCall().SerializeAsString()))
.ok());
files->PopulateHistory(&history);
ASSERT_THAT(history.history(), IsEmpty());
}
TEST_F(HealthModuleFilesTest, JustEnoughStorage) {
ERPHealthData history;
std::unique_ptr<HealthModuleFiles> files = HealthModuleFiles::Create(
directory_.GetPath(), kBaseFileOne, kSimpleEnqueueRecordCallLineSize);
ASSERT_TRUE(files != nullptr);
files->PopulateHistory(&history);
int initial_size = initial_health_data_.history_size();
initial_health_data_.mutable_history()->DeleteSubrange(0, initial_size - 1);
ASSERT_THAT(history.SerializeAsString(),
StrEq(initial_health_data_.SerializeAsString()));
history.mutable_history()->Clear();
auto call = AddEnqueueRecordCall();
*initial_health_data_.mutable_history(0) = call;
ASSERT_TRUE(files->Write(BytesToHexString(call.SerializeAsString())).ok());
files->PopulateHistory(&history);
EXPECT_THAT(history.SerializeAsString(),
StrEq(initial_health_data_.SerializeAsString()));
}
} // namespace
} // namespace reporting