text: // 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 <ddktl/protocol/block.h>
  #include <storage-metrics/block-metrics.h>
  #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
  // ::llcpp::fuchsia::storage::metrics::CallStat structure
  void ExpectCallStatMatchFidlStat(CallStat& cs,
                                   ::llcpp::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));
  
    ::llcpp::fuchsia::storage::metrics::CallStat tmp;
    cs.CopyToFidl(&tmp);
  }
  
  // Deep campares two ::llcpp::fuchsia::storage::metrics::CallStatRaw structures. Can be
  void ExpectFidlCallStatRawMatch(const ::llcpp::fuchsia::storage::metrics::CallStatRaw& lhs,
                                  const ::llcpp::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 ::llcpp::fuchsia::storage::metrics::CallStat structures
  void ExpectMetricsMatchCallStat(const ::llcpp::fuchsia::storage::metrics::CallStat& lhs,
                                  const ::llcpp::fuchsia::storage::metrics::CallStat& rhs) {
    ExpectFidlCallStatRawMatch(lhs.success, rhs.success);
    ExpectFidlCallStatRawMatch(lhs.failure, rhs.failure);
  }
  
  // Compares all ::llcpp::fuchsia::storage::metrics::CallStat fields within |fidl_fs_metrics|,
  // with |fidl_call_stat|
  void CompareFidlFsStatAll(const ::llcpp::fuchsia::storage::metrics::FsMetrics& fidl_fs_metrics,
                            const ::llcpp::fuchsia::storage::metrics::CallStat& fidl_call_stat) {
    ExpectMetricsMatchCallStat(fidl_fs_metrics.create, fidl_call_stat);
    ExpectMetricsMatchCallStat(fidl_fs_metrics.read, fidl_call_stat);
    ExpectMetricsMatchCallStat(fidl_fs_metrics.write, fidl_call_stat);
    ExpectMetricsMatchCallStat(fidl_fs_metrics.truncate, fidl_call_stat);
    ExpectMetricsMatchCallStat(fidl_fs_metrics.unlink, fidl_call_stat);
    ExpectMetricsMatchCallStat(fidl_fs_metrics.rename, fidl_call_stat);
    ExpectMetricsMatchCallStat(fidl_fs_metrics.lookup, fidl_call_stat);
    ExpectMetricsMatchCallStat(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 properly initialized.
  void ExpectFsMetricsInitialState(
      const ::llcpp::fuchsia::storage::metrics::FsMetrics& fidl_fs_metrics) {
    ::llcpp::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);
  }
  
  // Updates all private CallStat fields of |metrics|
  void UpdateAllBlockDeviceMetricsRaw(storage_metrics::BlockDeviceMetrics& metrics, bool success,
                                      zx_ticks_t delta, uint64_t bytes_transferred) {
    metrics.UpdateReadStat(success, delta, bytes_transferred);
    metrics.UpdateWriteStat(success, delta, bytes_transferred);
    metrics.UpdateTrimStat(success, delta, bytes_transferred);
    metrics.UpdateFlushStat(success, delta, bytes_transferred);
    metrics.UpdateBarrierBeforeStat(success, delta, bytes_transferred);
    metrics.UpdateBarrierAfterStat(success, delta, bytes_transferred);
  }
  
  // Updates both success and failure stats with (|minimum_latency|, |bytes_transferred1|)
  // (|maximum_latency|, |bytes_transferred2|) respectively.
  void BlockDeviceMetricsUpdate(storage_metrics::BlockDeviceMetrics& 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
    UpdateAllBlockDeviceMetricsRaw(metrics, true, minimum_latency, bytes_transferred1);
    UpdateAllBlockDeviceMetricsRaw(metrics, true, maximum_latency, bytes_transferred2);
    UpdateAllBlockDeviceMetricsRaw(metrics, false, minimum_latency, bytes_transferred1);
    UpdateAllBlockDeviceMetricsRaw(metrics, false, maximum_latency, bytes_transferred2);
  }
  
  // Compares all ::llcpp::fuchsia::storage::metrics::CallStat fields within
  // |fidl_block_device_metrics|, with |fidl_call_stat|
  void CompareFidlBlockDeviceStatAll(
      const ::llcpp::fuchsia::hardware::block::BlockStats& fidl_block_device_metrics,
      const ::llcpp::fuchsia::storage::metrics::CallStat& fidl_call_stat) {
    ExpectMetricsMatchCallStat(fidl_block_device_metrics.read, fidl_call_stat);
    ExpectMetricsMatchCallStat(fidl_block_device_metrics.write, fidl_call_stat);
    ExpectMetricsMatchCallStat(fidl_block_device_metrics.flush, fidl_call_stat);
    ExpectMetricsMatchCallStat(fidl_block_device_metrics.trim, fidl_call_stat);
    ExpectMetricsMatchCallStat(fidl_block_device_metrics.barrier_before, fidl_call_stat);
    ExpectMetricsMatchCallStat(fidl_block_device_metrics.barrier_after, fidl_call_stat);
  }
  
  // Expects if |fidl_fs_metrics| is properly initialized.
  void ExpectBlockDeviceMetricsInitialState(
      const ::llcpp::fuchsia::hardware::block::BlockStats& fidl_block_device_metrics) {
    ::llcpp::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;
    CompareFidlBlockDeviceStatAll(fidl_block_device_metrics, fidl_call_stat);
  }
  
  TEST(RawCallStatEqual, Same) {
    CallStatRawFidl a = {}, b = {};
    ASSERT_TRUE(RawCallStatEqual(a, b));
  }
  
  TEST(RawCallStatEqual, LargerTotalCalls) {
    CallStatRawFidl a = {}, b = {};
    a.total_calls++;
    ASSERT_FALSE(RawCallStatEqual(a, b));
  }
  
  TEST(RawCallStatEqual, LargerBytesTransferred) {
    CallStatRawFidl a = {}, b = {};
    a.bytes_transferred++;
    ASSERT_FALSE(RawCallStatEqual(a, b));
  }
  
  TEST(CallStatEqual, Same) {
    CallStatFidl a = {}, b = {};
    ASSERT_TRUE(CallStatEqual(a, b));
  }
  
  TEST(CallStatEqual, LargerTotalCalls) {
    CallStatFidl a = {}, b = {};
    a.success.total_calls++;
    ASSERT_FALSE(CallStatEqual(a, b));
  }
  
  TEST(CallStatEqual, LargerBytesTransferred) {
    CallStatFidl a = {}, b = {};
    a.failure.bytes_transferred++;
    ASSERT_FALSE(CallStatEqual(a, b));
  }
  
  TEST(BlockStatEqual, Same) {
    BlockStatFidl a = {}, b = {};
    ASSERT_TRUE(BlockStatEqual(a, b));
  }
  
  TEST(BlockStatEqual, LargerReadTotalCalls) {
    BlockStatFidl a = {}, b = {};
    a.read.success.total_calls++;
    ASSERT_FALSE(BlockStatEqual(a, b));
  }
  
  TEST(BlockStatEqual, LargerWriteBytesTransferred) {
    BlockStatFidl a = {}, b = {};
    a.write.failure.bytes_transferred++;
    ASSERT_FALSE(BlockStatEqual(a, b));
  }
  
  TEST(CallStatTest, UpdateSuccess) {
    storage_metrics::CallStat cs = {};
    ::llcpp::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 = {};
    ::llcpp::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 = {};
    ::llcpp::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 = {};
    ::llcpp::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 = {};
    ::llcpp::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 = {};
    ::llcpp::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 = {};
    ::llcpp::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) {
    ::llcpp::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) {
    ::llcpp::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;
    ::llcpp::fuchsia::storage::metrics::FsMetrics fidl_fs_metrics;
    ::llcpp::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;
    ::llcpp::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);
    ExpectFsMetricsInitialState(fidl_fs_metrics);
  }
  
  // Tests updates to fs metrics
  TEST(FsMetricsTest, EnabledMetricsCollectOnUpdate) {
    storage_metrics::FsMetrics metrics;
    ::llcpp::fuchsia::storage::metrics::FsMetrics fidl_fs_metrics;
    ::llcpp::fuchsia::storage::metrics::CallStatRaw fidl_call_stat_raw = {};
    ::llcpp::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);
  }
  
  // Test initial state of BlockDeviceMetrics
  TEST(BlockDeviceMetricsTest, DefaultValues) {
    storage_metrics::BlockDeviceMetrics metrics;
    ::llcpp::fuchsia::hardware::block::BlockStats fidl_block_metrics;
  
    EXPECT_TRUE(metrics.Enabled());
  
    metrics.CopyToFidl(&fidl_block_metrics);
    ExpectBlockDeviceMetricsInitialState(fidl_block_metrics);
  }
  
  // Tests no-updates are made when metrics is disabled
  TEST(BlockDeviceMetricsTest, DisabledMetricsIgnoreUpdates) {
    storage_metrics::BlockDeviceMetrics metrics;
    ::llcpp::fuchsia::hardware::block::BlockStats fidl_block_metrics;
  
    ASSERT_TRUE(metrics.Enabled());
    metrics.CopyToFidl(&fidl_block_metrics);
    ExpectBlockDeviceMetricsInitialState(fidl_block_metrics);
  
    metrics.SetEnable(false);
    EXPECT_FALSE(metrics.Enabled());
  
    // When not enabled, this should not update anything
    BlockDeviceMetricsUpdate(metrics, 10, 100, 100, 800);
  
    metrics.CopyToFidl(&fidl_block_metrics);
    ExpectBlockDeviceMetricsInitialState(fidl_block_metrics);
  }
  
  // Tests updates to block device metrics
  TEST(BlockDeviceMetricsTest, EnabledMetricsCollectOnUpdate) {
    storage_metrics::BlockDeviceMetrics metrics;
    ::llcpp::fuchsia::hardware::block::BlockStats fidl_block_metrics;
    ::llcpp::fuchsia::storage::metrics::CallStatRaw fidl_call_stat_raw = {};
    ::llcpp::fuchsia::storage::metrics::CallStat fidl_call_stat;
    ASSERT_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;
  
    BlockDeviceMetricsUpdate(metrics, minimum_latency, maximum_latency, bytes_transferred1,
                             bytes_transferred2);
  
    metrics.CopyToFidl(&fidl_block_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;
  
    CompareFidlBlockDeviceStatAll(fidl_block_metrics, fidl_call_stat);
  
    // Disable enable should not change the metrics
    metrics.SetEnable(false);
    metrics.CopyToFidl(&fidl_block_metrics);
    CompareFidlBlockDeviceStatAll(fidl_block_metrics, fidl_call_stat);
    metrics.SetEnable(true);
    metrics.CopyToFidl(&fidl_block_metrics);
    CompareFidlBlockDeviceStatAll(fidl_block_metrics, fidl_call_stat);
  }
  
  TEST(BlockDeviceMetricsTest, UpdateWriteStats) {
    storage_metrics::BlockDeviceMetrics metrics;
    fuchsia_hardware_block_BlockStats fidl_block_metrics;
  
    metrics.UpdateStats(true, zx::ticks(0), BLOCK_OP_WRITE, 100);
    metrics.UpdateStats(false, zx::ticks(0), BLOCK_OP_WRITE, 10);
    metrics.CopyToFidl(&fidl_block_metrics);
  
    ASSERT_EQ(1, fidl_block_metrics.write.success.total_calls);
    ASSERT_EQ(100, fidl_block_metrics.write.success.bytes_transferred);
    ASSERT_LT(0, fidl_block_metrics.write.success.total_time_spent);
    ASSERT_EQ(1, fidl_block_metrics.write.failure.total_calls);
    ASSERT_EQ(10, fidl_block_metrics.write.failure.bytes_transferred);
    ASSERT_LT(0, fidl_block_metrics.write.failure.total_time_spent);
  }
  
  TEST(BlockDeviceMetricsTest, UpdateReadStats) {
    storage_metrics::BlockDeviceMetrics metrics;
    fuchsia_hardware_block_BlockStats fidl_block_metrics;
  
    metrics.UpdateStats(true, zx::ticks(0), BLOCK_OP_READ, 100);
    metrics.UpdateStats(false, zx::ticks(0), BLOCK_OP_READ, 10);
    metrics.CopyToFidl(&fidl_block_metrics);
  
    ASSERT_EQ(1, fidl_block_metrics.read.success.total_calls);
    ASSERT_EQ(100, fidl_block_metrics.read.success.bytes_transferred);
    ASSERT_LT(0, fidl_block_metrics.read.success.total_time_spent);
    ASSERT_EQ(1, fidl_block_metrics.read.failure.total_calls);
    ASSERT_EQ(10, fidl_block_metrics.read.failure.bytes_transferred);
    ASSERT_LT(0, fidl_block_metrics.read.failure.total_time_spent);
  }
  
  TEST(BlockDeviceMetricsTest, UpdateFlushStats) {
    storage_metrics::BlockDeviceMetrics metrics;
    fuchsia_hardware_block_BlockStats fidl_block_metrics;
  
    metrics.UpdateStats(true, zx::ticks(0), BLOCK_OP_FLUSH, 100);
    metrics.UpdateStats(false, zx::ticks(0), BLOCK_OP_FLUSH, 10);
    metrics.CopyToFidl(&fidl_block_metrics);
  
    ASSERT_EQ(1, fidl_block_metrics.flush.success.total_calls);
    ASSERT_EQ(100, fidl_block_metrics.flush.success.bytes_transferred);
    ASSERT_LT(0, fidl_block_metrics.flush.success.total_time_spent);
    ASSERT_EQ(1, fidl_block_metrics.flush.failure.total_calls);
    ASSERT_EQ(10, fidl_block_metrics.flush.failure.bytes_transferred);
    ASSERT_LT(0, fidl_block_metrics.flush.failure.total_time_spent);
  }
  
  TEST(BlockDeviceMetricsTest, UpdateTrimStats) {
    storage_metrics::BlockDeviceMetrics metrics;
    fuchsia_hardware_block_BlockStats fidl_block_metrics;
  
    metrics.UpdateStats(true, zx::ticks(0), BLOCK_OP_TRIM, 100);
    metrics.UpdateStats(false, zx::ticks(0), BLOCK_OP_TRIM, 10);
    metrics.CopyToFidl(&fidl_block_metrics);
  
    ASSERT_EQ(1, fidl_block_metrics.trim.success.total_calls);
    ASSERT_EQ(100, fidl_block_metrics.trim.success.bytes_transferred);
    ASSERT_LT(0, fidl_block_metrics.trim.success.total_time_spent);
    ASSERT_EQ(1, fidl_block_metrics.trim.failure.total_calls);
    ASSERT_EQ(10, fidl_block_metrics.trim.failure.bytes_transferred);
    ASSERT_LT(0, fidl_block_metrics.trim.failure.total_time_spent);
  }
  
  TEST(BlockDeviceMetricsTest, UpdateBarrierStats) {
    storage_metrics::BlockDeviceMetrics metrics;
    fuchsia_hardware_block_BlockStats fidl_block_metrics;
  
    metrics.UpdateStats(true, zx::ticks(0), BLOCK_OP_READ | BLOCK_FL_BARRIER_BEFORE, 100);
    metrics.UpdateStats(false, zx::ticks(0), BLOCK_OP_WRITE | BLOCK_FL_BARRIER_AFTER, 10);
    metrics.UpdateStats(true, zx::ticks(0),
                        BLOCK_OP_TRIM | BLOCK_FL_BARRIER_AFTER | BLOCK_FL_BARRIER_BEFORE, 20);
    metrics.CopyToFidl(&fidl_block_metrics);
  
    ASSERT_EQ(1, fidl_block_metrics.read.success.total_calls);
    ASSERT_EQ(1, fidl_block_metrics.write.failure.total_calls);
    ASSERT_EQ(1, fidl_block_metrics.trim.success.total_calls);
    ASSERT_EQ(2, fidl_block_metrics.barrier_before.success.total_calls);
    ASSERT_EQ(1, fidl_block_metrics.barrier_after.failure.total_calls);
    ASSERT_EQ(1, fidl_block_metrics.barrier_after.success.total_calls);
  
    ASSERT_EQ(100, fidl_block_metrics.read.success.bytes_transferred);
    ASSERT_EQ(10, fidl_block_metrics.write.failure.bytes_transferred);
    ASSERT_EQ(20, fidl_block_metrics.trim.success.bytes_transferred);
    ASSERT_EQ(120, fidl_block_metrics.barrier_before.success.bytes_transferred);
    ASSERT_EQ(10, fidl_block_metrics.barrier_after.failure.bytes_transferred);
    ASSERT_EQ(20, fidl_block_metrics.barrier_after.success.bytes_transferred);
  
    ASSERT_LT(0, fidl_block_metrics.barrier_before.success.total_time_spent);
    ASSERT_EQ(0, fidl_block_metrics.barrier_before.failure.total_time_spent);
    ASSERT_LT(0, fidl_block_metrics.barrier_after.success.total_time_spent);
    ASSERT_LT(0, fidl_block_metrics.barrier_after.failure.total_time_spent);
  }
  
  }  // namespace
  }  // namespace storage_metrics
  