blob: 3e3f3e42aaeebac20aae4c551cb5cda72fdab36f [file] [log] [blame]
// Copyright 2019 The Fuchsia 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 <algorithm>
#include <storage-metrics/fs-metrics.h>
#include <storage-metrics/storage-metrics.h>
#include <zxtest/zxtest.h>
namespace storage_metrics {
namespace {
using storage_metrics::CallStat;
// Campare CallStat fields with the corresponding fields in fuchsia_storage_metrics_CallStat
// structure
void ExpectCallStatMatchFidlStat(CallStat& cs, fuchsia_storage_metrics_CallStat& cs_fidl) {
EXPECT_EQ(cs.minimum_latency(true), cs_fidl.success.minimum_latency);
EXPECT_EQ(cs.maximum_latency(true), cs_fidl.success.maximum_latency);
EXPECT_EQ(cs.total_time_spent(true), cs_fidl.success.total_time_spent);
EXPECT_EQ(cs.total_calls(true), cs_fidl.success.total_calls);
EXPECT_EQ(cs.bytes_transferred(true), cs_fidl.success.bytes_transferred);
EXPECT_EQ(cs.minimum_latency(false), cs_fidl.failure.minimum_latency);
EXPECT_EQ(cs.maximum_latency(false), cs_fidl.failure.maximum_latency);
EXPECT_EQ(cs.total_time_spent(false), cs_fidl.failure.total_time_spent);
EXPECT_EQ(cs.total_calls(false), cs_fidl.failure.total_calls);
EXPECT_EQ(cs.bytes_transferred(false), cs_fidl.failure.bytes_transferred);
EXPECT_EQ(cs.minimum_latency(),
std::min(cs_fidl.success.minimum_latency, cs_fidl.failure.minimum_latency));
EXPECT_EQ(cs.maximum_latency(),
std::max(cs_fidl.success.maximum_latency, cs_fidl.failure.maximum_latency));
EXPECT_EQ(cs.total_time_spent(),
(cs_fidl.success.total_time_spent + cs_fidl.failure.total_time_spent));
EXPECT_EQ(cs.total_calls(), (cs_fidl.success.total_calls + cs_fidl.failure.total_calls));
EXPECT_EQ(cs.bytes_transferred(),
(cs_fidl.success.bytes_transferred + cs_fidl.failure.bytes_transferred));
fuchsia_storage_metrics_CallStat tmp;
cs.CopyToFidl(&tmp);
}
// Deep campares two fuchsia_storage_metrics_CallStatRaw structures. Can be
void ExpectFidlCallStatRawMatch(const fuchsia_storage_metrics_CallStatRaw& lhs,
const fuchsia_storage_metrics_CallStatRaw& rhs) {
EXPECT_EQ(lhs.total_calls, rhs.total_calls);
EXPECT_EQ(lhs.total_time_spent, rhs.total_time_spent);
EXPECT_EQ(lhs.minimum_latency, rhs.minimum_latency);
EXPECT_EQ(lhs.maximum_latency, rhs.maximum_latency);
EXPECT_EQ(lhs.bytes_transferred, rhs.bytes_transferred);
}
// Compares two fuchsia_storage_metrics_CallStat structures
void ExpectFsMetricsMatchCallStat(const fuchsia_storage_metrics_CallStat& lhs,
const fuchsia_storage_metrics_CallStat& rhs) {
ExpectFidlCallStatRawMatch(lhs.success, rhs.success);
ExpectFidlCallStatRawMatch(lhs.failure, rhs.failure);
}
// Compares all fuchsia_storage_metrics_CallStat fields within |fidl_fs_metrics|,
// with |fidl_call_stat|
void CompareFidlFsStatAll(const fuchsia_storage_metrics_FsMetrics& fidl_fs_metrics,
const fuchsia_storage_metrics_CallStat& fidl_call_stat) {
ExpectFsMetricsMatchCallStat(fidl_fs_metrics.create, fidl_call_stat);
ExpectFsMetricsMatchCallStat(fidl_fs_metrics.read, fidl_call_stat);
ExpectFsMetricsMatchCallStat(fidl_fs_metrics.write, fidl_call_stat);
ExpectFsMetricsMatchCallStat(fidl_fs_metrics.truncate, fidl_call_stat);
ExpectFsMetricsMatchCallStat(fidl_fs_metrics.unlink, fidl_call_stat);
ExpectFsMetricsMatchCallStat(fidl_fs_metrics.rename, fidl_call_stat);
ExpectFsMetricsMatchCallStat(fidl_fs_metrics.lookup, fidl_call_stat);
ExpectFsMetricsMatchCallStat(fidl_fs_metrics.open, fidl_call_stat);
}
// Updates all private CallStat fields of |metrics|
void UpdateAllFsMetricsRaw(storage_metrics::FsMetrics& metrics, bool success, zx_ticks_t delta,
uint64_t bytes_transferred) {
metrics.UpdateCreateStat(success, delta, bytes_transferred);
metrics.UpdateReadStat(success, delta, bytes_transferred);
metrics.UpdateWriteStat(success, delta, bytes_transferred);
metrics.UpdateTruncateStat(success, delta, bytes_transferred);
metrics.UpdateUnlinkStat(success, delta, bytes_transferred);
metrics.UpdateRenameStat(success, delta, bytes_transferred);
metrics.UpdateLookupStat(success, delta, bytes_transferred);
metrics.UpdateOpenStat(success, delta, bytes_transferred);
}
// Updates both success and failure stats with (|minimum_latency|, |bytes_transferred1|)
// (|maximum_latency|, |bytes_transferred2|) respectively.
void FsMetricsUpdate(storage_metrics::FsMetrics& metrics, zx_ticks_t minimum_latency,
zx_ticks_t maximum_latency, uint64_t bytes_transferred1,
uint64_t bytes_transferred2) {
// Update successful minimum and maximum latencies
UpdateAllFsMetricsRaw(metrics, true, minimum_latency, bytes_transferred1);
UpdateAllFsMetricsRaw(metrics, true, maximum_latency, bytes_transferred2);
UpdateAllFsMetricsRaw(metrics, false, minimum_latency, bytes_transferred1);
UpdateAllFsMetricsRaw(metrics, false, maximum_latency, bytes_transferred2);
}
// Expects if |fidl_fs_mterics| is not properly initialized.
void ExpectInitialState(const fuchsia_storage_metrics_FsMetrics& fidl_fs_metrics) {
fuchsia_storage_metrics_CallStat fidl_call_stat = {};
fidl_call_stat.success.minimum_latency = storage_metrics::kUninitializedMinimumLatency;
fidl_call_stat.failure.minimum_latency = storage_metrics::kUninitializedMinimumLatency;
CompareFidlFsStatAll(fidl_fs_metrics, fidl_call_stat);
}
TEST(CallStatTest, UpdateSuccess) {
storage_metrics::CallStat cs = {};
fuchsia_storage_metrics_CallStat fidl_stat;
// Copy initial state
cs.CopyToFidl(&fidl_stat);
cs.UpdateCallStat(true, 10, 100);
fidl_stat.success.total_calls++;
fidl_stat.success.total_time_spent += 10;
fidl_stat.success.minimum_latency = 10;
fidl_stat.success.maximum_latency = 10;
fidl_stat.success.bytes_transferred += 100;
ExpectCallStatMatchFidlStat(cs, fidl_stat);
}
TEST(CallStatTest, UpdateFailure) {
storage_metrics::CallStat cs = {};
fuchsia_storage_metrics_CallStat fidl_stat;
// Copy initial state
cs.CopyToFidl(&fidl_stat);
// No change in success stats but everything else changes
cs.UpdateCallStat(false, 10, 100);
fidl_stat.failure.total_calls++;
fidl_stat.failure.total_time_spent += 10;
fidl_stat.failure.minimum_latency = 10;
fidl_stat.failure.maximum_latency = 10;
fidl_stat.failure.bytes_transferred += 100;
ExpectCallStatMatchFidlStat(cs, fidl_stat);
}
TEST(CallStatTest, UpdateBytesTransferred) {
storage_metrics::CallStat cs = {};
fuchsia_storage_metrics_CallStat fidl_stat;
// Copy initial state
cs.CopyToFidl(&fidl_stat);
// No change in min/max latencies or failure but everything else changes
cs.UpdateCallStat(true, 10, 100);
fidl_stat.success.total_calls++;
fidl_stat.success.total_time_spent += 10;
fidl_stat.success.minimum_latency = 10;
fidl_stat.success.maximum_latency = 10;
fidl_stat.success.bytes_transferred += 100;
ExpectCallStatMatchFidlStat(cs, fidl_stat);
}
TEST(CallStatTest, UpdateMinimumLatency) {
storage_metrics::CallStat cs = {};
fuchsia_storage_metrics_CallStat fidl_stat;
// Copy initial state
cs.CopyToFidl(&fidl_stat);
// Expect min latency to change and bytes transferred unchanged
cs.UpdateCallStat(true, 9, 0);
cs.UpdateCallStat(true, 7, 0);
fidl_stat.success.total_calls += 2;
fidl_stat.success.total_time_spent += (9 + 7);
fidl_stat.success.minimum_latency = 7;
fidl_stat.success.maximum_latency = 9;
fidl_stat.success.bytes_transferred += 0;
ExpectCallStatMatchFidlStat(cs, fidl_stat);
}
TEST(CallStatTest, UpdateFailedMaximumLatency) {
storage_metrics::CallStat cs = {};
fuchsia_storage_metrics_CallStat fidl_stat;
// Copy initial state
cs.CopyToFidl(&fidl_stat);
// Expect max latency and failed count to change
cs.UpdateCallStat(false, 20, 100);
cs.UpdateCallStat(false, 30, 100);
fidl_stat.failure.total_calls += 2;
fidl_stat.failure.total_time_spent += (20 + 30);
fidl_stat.failure.minimum_latency = 20;
fidl_stat.failure.maximum_latency = 30;
fidl_stat.failure.bytes_transferred += (100 + 100);
ExpectCallStatMatchFidlStat(cs, fidl_stat);
}
TEST(CallStatTest, UpdateTimeSpent) {
storage_metrics::CallStat cs = {};
fuchsia_storage_metrics_CallStat fidl_stat;
// Copy initial state
cs.CopyToFidl(&fidl_stat);
// Expect only time spent and total calls to change
cs.UpdateCallStat(true, 20, 0);
cs.UpdateCallStat(true, 20, 0);
fidl_stat.success.total_calls += 2;
fidl_stat.success.minimum_latency = 20;
fidl_stat.success.maximum_latency = 20;
fidl_stat.success.total_time_spent += (20 + 20);
ExpectCallStatMatchFidlStat(cs, fidl_stat);
}
TEST(CallStatTest, Reset) {
storage_metrics::CallStat cs = {};
fuchsia_storage_metrics_CallStat fidl_stat;
cs.UpdateCallStat(true, 20, 100);
cs.UpdateCallStat(false, 20, 100);
// Everything should be cleared
cs.Reset();
fidl_stat = {};
fidl_stat.success.minimum_latency = storage_metrics::kUninitializedMinimumLatency;
fidl_stat.failure.minimum_latency = storage_metrics::kUninitializedMinimumLatency;
ExpectCallStatMatchFidlStat(cs, fidl_stat);
}
TEST(CallStatTest, TestCopyToFidl) {
fuchsia_storage_metrics_CallStat f = {};
storage_metrics::CallStat cs;
// Set max latency
cs.UpdateCallStat(true, 20, 100);
// Set min latency and fail count
cs.UpdateCallStat(true, 10, 20);
cs.CopyToFidl(&f);
ExpectCallStatMatchFidlStat(cs, f);
}
TEST(CallStatTest, TestCopyFromFidl) {
fuchsia_storage_metrics_CallStat f;
storage_metrics::CallStat cs;
f.success.total_calls = 3;
f.success.minimum_latency = 4;
f.success.maximum_latency = 15;
f.success.total_time_spent = 19;
f.success.bytes_transferred = 92;
f.failure.total_calls = 3;
f.failure.minimum_latency = 4;
f.failure.maximum_latency = 15;
f.failure.total_time_spent = 19;
f.failure.bytes_transferred = 92;
cs.CopyFromFidl(&f);
ExpectCallStatMatchFidlStat(cs, f);
}
// Tests enable/disable functionality
TEST(MetricsTest, SetEnable) {
storage_metrics::Metrics metrics;
EXPECT_TRUE(metrics.Enabled());
metrics.SetEnable(false);
EXPECT_FALSE(metrics.Enabled());
metrics.SetEnable(true);
EXPECT_TRUE(metrics.Enabled());
}
// Test initial state of FsMetrics
TEST(FsMetricsTest, DefaultValues) {
storage_metrics::FsMetrics metrics;
fuchsia_storage_metrics_FsMetrics fidl_fs_metrics;
fuchsia_storage_metrics_CallStat fidl_call_stat = {};
fidl_call_stat.success.minimum_latency = storage_metrics::kUninitializedMinimumLatency;
fidl_call_stat.failure.minimum_latency = storage_metrics::kUninitializedMinimumLatency;
EXPECT_TRUE(metrics.Enabled());
metrics.CopyToFidl(&fidl_fs_metrics);
CompareFidlFsStatAll(fidl_fs_metrics, fidl_call_stat);
}
// Tests no-updates are made when metrics is disabled
TEST(FsMetricsTest, DisabledMetricsIgnoreUpdates) {
storage_metrics::FsMetrics metrics;
fuchsia_storage_metrics_FsMetrics fidl_fs_metrics;
EXPECT_TRUE(metrics.Enabled());
metrics.SetEnable(false);
EXPECT_FALSE(metrics.Enabled());
// When not enabled, this should not update anything
FsMetricsUpdate(metrics, 10, 100, 100, 800);
metrics.CopyToFidl(&fidl_fs_metrics);
ExpectInitialState(fidl_fs_metrics);
}
// Tests updates to fs metrics
TEST(FsMetricsTest, EnabledMetricsCollectOnUpdate) {
storage_metrics::FsMetrics metrics;
fuchsia_storage_metrics_FsMetrics fidl_fs_metrics;
fuchsia_storage_metrics_CallStatRaw fidl_call_stat_raw = {};
fuchsia_storage_metrics_CallStat fidl_call_stat;
EXPECT_TRUE(metrics.Enabled());
zx_ticks_t minimum_latency = 10;
zx_ticks_t maximum_latency = 100;
uint64_t bytes_transferred1 = 330;
uint64_t bytes_transferred2 = 440;
FsMetricsUpdate(metrics, minimum_latency, maximum_latency, bytes_transferred1,
bytes_transferred2);
metrics.CopyToFidl(&fidl_fs_metrics);
fidl_call_stat_raw.minimum_latency = minimum_latency;
fidl_call_stat_raw.maximum_latency = maximum_latency;
fidl_call_stat_raw.total_time_spent = minimum_latency + maximum_latency;
fidl_call_stat_raw.total_calls = 2;
fidl_call_stat_raw.bytes_transferred = bytes_transferred1 + bytes_transferred2;
fidl_call_stat.success = fidl_call_stat_raw;
fidl_call_stat.failure = fidl_call_stat_raw;
CompareFidlFsStatAll(fidl_fs_metrics, fidl_call_stat);
// Disable enable should not change the metrics
metrics.SetEnable(false);
metrics.CopyToFidl(&fidl_fs_metrics);
CompareFidlFsStatAll(fidl_fs_metrics, fidl_call_stat);
metrics.SetEnable(true);
metrics.CopyToFidl(&fidl_fs_metrics);
CompareFidlFsStatAll(fidl_fs_metrics, fidl_call_stat);
}
} // namespace
} // namespace storage_metrics