chromium/chromeos/ash/components/file_manager/speedometer_unittest.cc

// Copyright 2021 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "chromeos/ash/components/file_manager/speedometer.h"

#include <cmath>
#include <limits>

#include "base/test/scoped_mock_clock_override.h"
#include "base/time/time.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"

namespace file_manager {
namespace {

using base::Milliseconds;
using base::Seconds;
using testing::IsNan;

TEST(SpeedometerTest, RemainingTime) {
  base::ScopedMockClockOverride clock;
  Speedometer meter;

  // Testing without setting the total bytes:
  EXPECT_EQ(meter.GetSampleCount(), 0u);
  EXPECT_TRUE(meter.GetRemainingTime().is_max());

  // Sets total number of bytes.
  meter.SetTotalBytes(2000);
  EXPECT_EQ(meter.GetSampleCount(), 0u);
  EXPECT_TRUE(meter.GetRemainingTime().is_max());

  // 1st sample.
  // 1st sample, but not enough to calculate the remaining time.
  clock.Advance(Seconds(11));

  EXPECT_TRUE(meter.Update(100));
  EXPECT_EQ(meter.GetSampleCount(), 1u);
  EXPECT_TRUE(meter.GetRemainingTime().is_max());

  // Sample received less than 3 second after the previous one should be
  // ignored.
  clock.Advance(Milliseconds(2999));
  EXPECT_FALSE(meter.Update(300));
  EXPECT_EQ(meter.GetSampleCount(), 1u);
  EXPECT_TRUE(meter.GetRemainingTime().is_max());

  // 2nd sample, the remaining time can be computed.
  clock.Advance(Milliseconds(1));
  EXPECT_TRUE(meter.Update(300));
  EXPECT_EQ(meter.GetSampleCount(), 2u);
  EXPECT_EQ(meter.GetRemainingTime().InSeconds(), 25);

  // 3rd sample. +3 seconds and still only processed 300 bytes.
  clock.Advance(Seconds(3));
  EXPECT_TRUE(meter.Update(300));
  EXPECT_EQ(meter.GetSampleCount(), 3u);
  EXPECT_EQ(meter.GetRemainingTime().InSeconds(), 50);

  // 4th sample, +5 seconds and still only 300 bytes.
  clock.Advance(Seconds(5));
  EXPECT_TRUE(meter.Update(300));
  EXPECT_EQ(meter.GetSampleCount(), 4u);
  EXPECT_EQ(meter.GetRemainingTime().InSeconds(), 109);

  // 5th sample, +3 seconds and now bumped from 300 to 600 bytes.
  clock.Advance(Seconds(3));
  EXPECT_TRUE(meter.Update(600));
  EXPECT_EQ(meter.GetSampleCount(), 5u);
  EXPECT_EQ(meter.GetRemainingTime().InSeconds(), 55);

  // Elapsed time should impact the remaining time.
  clock.Advance(Seconds(12));
  EXPECT_EQ(meter.GetRemainingTime().InSeconds(), 43);

  // GetRemainingTime() can return negative value.
  clock.Advance(Seconds(60));
  EXPECT_EQ(meter.GetRemainingTime().InSeconds(), -16);
}

TEST(SpeedometerTest, Samples) {
  base::ScopedMockClockOverride clock;
  Speedometer meter;

  constexpr size_t kMaxSamples = 20;
  meter.SetTotalBytes(20000);

  // Slow speed of 100 bytes per second.
  int total_transferred = 0;
  for (size_t i = 0; i < kMaxSamples; i++) {
    EXPECT_EQ(meter.GetSampleCount(), i);
    clock.Advance(Seconds(3));
    total_transferred = i * 100;
    EXPECT_TRUE(meter.Update(total_transferred));
  }

  EXPECT_EQ(meter.GetSampleCount(), kMaxSamples);
  EXPECT_EQ(meter.GetRemainingTime().InSeconds(), 543);

  // +200 to make it compatible with the values in the unittest in the JS
  // version.
  const int initial_transferred_bytes = total_transferred + 200;
  // Faster speed of 300 bytes per second.
  for (size_t i = 0; i < kMaxSamples; i++) {
    // Check buffer not expanded more than the specified length.
    EXPECT_EQ(meter.GetSampleCount(), kMaxSamples);
    clock.Advance(Seconds(3));
    total_transferred = initial_transferred_bytes + (i * 300);
    EXPECT_TRUE(meter.Update(total_transferred));

    // Current speed should be seen as accelerating, thus the remaining time
    // decreasing.
    EXPECT_LT(meter.GetRemainingTime().InSeconds(), 543);
  }

  EXPECT_EQ(meter.GetSampleCount(), kMaxSamples);
  EXPECT_EQ(meter.GetRemainingTime().InSeconds(), 122);

  // Stalling.
  for (size_t i = 0; i < kMaxSamples; i++) {
    // Check buffer not expanded more than the specified length.
    EXPECT_EQ(meter.GetSampleCount(), kMaxSamples);
    clock.Advance(Seconds(3));
    EXPECT_TRUE(meter.Update(total_transferred));
  }

  // When all samples have the same value the remaining time goes to infinity,
  // because the Linear Interpolation expects an inclination/slope, but with all
  // values the same, it becomes a horizontal line, meaning that the bytes will
  // never grow towards the total bytes.
  EXPECT_TRUE(meter.GetRemainingTime().is_max());
}

TEST(SpeedometerTest, ProgressGoingBackwards) {
  base::ScopedMockClockOverride clock;
  Speedometer meter;

  // Sets total number of bytes and a couple of samples.
  meter.SetTotalBytes(2000);
  EXPECT_TRUE(meter.Update(100));
  clock.Advance(Seconds(5));
  EXPECT_TRUE(meter.Update(300));
  EXPECT_EQ(meter.GetSampleCount(), 2u);
  EXPECT_EQ(meter.GetRemainingTime().InSeconds(), 42);

  // Progress going backwards should clear the samples.
  clock.Advance(Seconds(3));
  EXPECT_TRUE(meter.Update(200));
  EXPECT_EQ(meter.GetSampleCount(), 1u);
  EXPECT_TRUE(meter.GetRemainingTime().is_max());

  clock.Advance(Seconds(5));
  EXPECT_TRUE(meter.Update(300));
  EXPECT_EQ(meter.GetSampleCount(), 2u);
  EXPECT_EQ(meter.GetRemainingTime().InSeconds(), 85);
}

TEST(SpeedometerTest, ChangeTotalBytes) {
  base::ScopedMockClockOverride clock;
  Speedometer meter;

  // Sets total number of bytes and a couple of samples.
  meter.SetTotalBytes(2000);
  EXPECT_TRUE(meter.Update(100));
  clock.Advance(Seconds(5));
  EXPECT_TRUE(meter.Update(300));
  EXPECT_EQ(meter.GetSampleCount(), 2u);
  EXPECT_EQ(meter.GetRemainingTime().InSeconds(), 42);

  // Setting the total number of bytes to the existing value shouldn't change
  // anything.
  meter.SetTotalBytes(2000);
  EXPECT_EQ(meter.GetSampleCount(), 2u);
  EXPECT_EQ(meter.GetRemainingTime().InSeconds(), 42);

  // Changing the total number of bytes should clear the samples.
  meter.SetTotalBytes(3000);
  EXPECT_EQ(meter.GetSampleCount(), 0u);
  EXPECT_TRUE(meter.GetRemainingTime().is_max());

  clock.Advance(Seconds(5));
  EXPECT_TRUE(meter.Update(3000));
  EXPECT_EQ(meter.GetSampleCount(), 1u);

  // Go beyond the number of expected bytes.
  clock.Advance(Seconds(5));
  EXPECT_TRUE(meter.Update(4000));
  EXPECT_EQ(meter.GetSampleCount(), 2u);
  EXPECT_EQ(meter.GetRemainingTime().InSeconds(), 0);
}

}  // namespace
}  // namespace file_manager