blob: e488d6ccbf1a25ae27c7db8a8d6d82ff11c02841 [file] [log] [blame]
// Copyright 2022 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 "src/local_aggregation_1_1/civil_time_manager.h"
#include <gmock/gmock.h>
#include <gtest/gtest.h>
#include "src/lib/util/clock.h"
#include "src/lib/util/datetime_util.h"
#include "src/public/lib/clock_interfaces.h"
#include "src/public/lib/statusor/status_macros.h"
#include "src/public/lib/statusor/statusor.h"
namespace cobalt::local_aggregation {
namespace {
using lib::statusor::StatusOr;
using ::testing::DefaultValue;
using util::TimeInfo;
constexpr std::chrono::system_clock::time_point kInitialTime(std::chrono::hours(10000));
class MockCivilTimeConverter : public util::CivilTimeConverterInterface {
public:
MOCK_METHOD(lib::statusor::StatusOr<std::tm>, civil_time,
(std::chrono::system_clock::time_point time, const std::string& time_zone),
(const, override));
};
TEST(CivilTimeManager, GetInitialUtc) {
MockCivilTimeConverter converter;
CivilTimeManager manager(kInitialTime, converter);
TimeInfo initial_info = manager.GetInitialUtc();
TimeInfo expected_info = TimeInfo::FromTimePointUtc(kInitialTime);
EXPECT_EQ(initial_info.day_index, expected_info.day_index);
EXPECT_EQ(initial_info.hour_id, expected_info.hour_id);
EXPECT_CALL(converter, civil_time).Times(0);
}
TEST(CivilTimeManager, GetTimeInfoUtc) {
MockCivilTimeConverter converter;
CivilTimeManager manager(kInitialTime, converter);
MetricDefinition metric;
metric.set_time_zone_policy(MetricDefinition::UTC);
// Get some UTC TimeInfos. This should not invoke the civil time converter.
EXPECT_CALL(converter, civil_time).Times(0);
CB_ASSERT_OK_AND_ASSIGN(TimeInfo info_0, manager.GetTimeInfo(0, metric));
CB_ASSERT_OK_AND_ASSIGN(TimeInfo info_1, manager.GetTimeInfo(1, metric));
CB_ASSERT_OK_AND_ASSIGN(TimeInfo info_3, manager.GetTimeInfo(3, metric));
// Get the same UTC TimeInfos again, this time from the cache.
CB_ASSERT_OK_AND_ASSIGN(TimeInfo cached_0, manager.GetTimeInfo(0, metric));
CB_ASSERT_OK_AND_ASSIGN(TimeInfo cached_1, manager.GetTimeInfo(1, metric));
CB_ASSERT_OK_AND_ASSIGN(TimeInfo cached_3, manager.GetTimeInfo(3, metric));
// Check that the TimeInfos are correct.
TimeInfo expected_0 = TimeInfo::FromTimePointUtc(kInitialTime);
TimeInfo expected_1 = TimeInfo::FromTimePointUtc(kInitialTime - util::kOneHour);
TimeInfo expected_3 = TimeInfo::FromTimePointUtc(kInitialTime - 3 * util::kOneHour);
EXPECT_EQ(info_0.day_index, expected_0.day_index);
EXPECT_EQ(info_0.hour_id, expected_0.hour_id);
EXPECT_EQ(info_1.day_index, expected_1.day_index);
EXPECT_EQ(info_1.hour_id, expected_1.hour_id);
EXPECT_EQ(info_3.day_index, expected_3.day_index);
EXPECT_EQ(info_3.hour_id, expected_3.hour_id);
EXPECT_EQ(cached_0.day_index, expected_0.day_index);
EXPECT_EQ(cached_0.hour_id, expected_0.hour_id);
EXPECT_EQ(cached_1.day_index, expected_1.day_index);
EXPECT_EQ(cached_1.hour_id, expected_1.hour_id);
EXPECT_EQ(cached_3.day_index, expected_3.day_index);
EXPECT_EQ(cached_3.hour_id, expected_3.hour_id);
}
TEST(CivilTimeManager, GetTimeInfoLocal) {
MockCivilTimeConverter converter;
CivilTimeManager manager(kInitialTime, converter);
MetricDefinition metric;
metric.set_time_zone_policy(MetricDefinition::LOCAL);
// Get some TimeInfos in local time. This should not invoke the civil time converter.
EXPECT_CALL(converter, civil_time).Times(0);
CB_ASSERT_OK_AND_ASSIGN(TimeInfo info_0, manager.GetTimeInfo(0, metric));
CB_ASSERT_OK_AND_ASSIGN(TimeInfo info_1, manager.GetTimeInfo(1, metric));
CB_ASSERT_OK_AND_ASSIGN(TimeInfo info_3, manager.GetTimeInfo(3, metric));
// Get the same TimeInfos again, this time from the cache.
CB_ASSERT_OK_AND_ASSIGN(TimeInfo cached_0, manager.GetTimeInfo(0, metric));
CB_ASSERT_OK_AND_ASSIGN(TimeInfo cached_1, manager.GetTimeInfo(1, metric));
CB_ASSERT_OK_AND_ASSIGN(TimeInfo cached_3, manager.GetTimeInfo(3, metric));
// Check that the TimeInfos are correct.
CB_ASSERT_OK_AND_ASSIGN(TimeInfo expected_0,
TimeInfo::FromTimePoint(kInitialTime, converter, metric));
CB_ASSERT_OK_AND_ASSIGN(
TimeInfo expected_1,
TimeInfo::FromTimePoint(kInitialTime - util::kOneHour, converter, metric));
CB_ASSERT_OK_AND_ASSIGN(
TimeInfo expected_3,
TimeInfo::FromTimePoint(kInitialTime - 3 * util::kOneHour, converter, metric));
EXPECT_EQ(info_0.day_index, expected_0.day_index);
EXPECT_EQ(info_0.hour_id, expected_0.hour_id);
EXPECT_EQ(info_1.day_index, expected_1.day_index);
EXPECT_EQ(info_1.hour_id, expected_1.hour_id);
EXPECT_EQ(info_3.day_index, expected_3.day_index);
EXPECT_EQ(info_3.hour_id, expected_3.hour_id);
EXPECT_EQ(cached_0.day_index, expected_0.day_index);
EXPECT_EQ(cached_0.hour_id, expected_0.hour_id);
EXPECT_EQ(cached_1.day_index, expected_1.day_index);
EXPECT_EQ(cached_1.hour_id, expected_1.hour_id);
EXPECT_EQ(cached_3.day_index, expected_3.day_index);
EXPECT_EQ(cached_3.hour_id, expected_3.hour_id);
}
TEST(CivilTimeManager, GetTimeInfoOtherTimeZone) {
const uint32_t kDayIndex = 100;
std::tm time_struct;
std::time_t time_t = std::chrono::system_clock::to_time_t(
std::chrono::system_clock::time_point(util::kOneDay * kDayIndex));
gmtime_r(&time_t, &time_struct);
DefaultValue<lib::statusor::StatusOr<std::tm>>::Set(time_struct);
TimeInfo expected = TimeInfo::FromDayIndex(kDayIndex);
MockCivilTimeConverter converter;
CivilTimeManager manager(kInitialTime, converter);
MetricDefinition metric;
metric.set_time_zone_policy(MetricDefinition::OTHER_TIME_ZONE);
metric.set_other_time_zone("other");
// Get some TimeInfos in the "other" time zone, then get the TimeInfos again. This should invoke
// the civil time converter just once for each time offset.
EXPECT_CALL(converter, civil_time(kInitialTime, "other")).Times(1);
EXPECT_CALL(converter, civil_time(kInitialTime - util::kOneHour, "other")).Times(1);
EXPECT_CALL(converter, civil_time(kInitialTime - 3 * util::kOneHour, "other")).Times(1);
CB_ASSERT_OK_AND_ASSIGN(TimeInfo info_0, manager.GetTimeInfo(0, metric));
CB_ASSERT_OK_AND_ASSIGN(TimeInfo info_1, manager.GetTimeInfo(1, metric));
CB_ASSERT_OK_AND_ASSIGN(TimeInfo info_3, manager.GetTimeInfo(3, metric));
CB_ASSERT_OK_AND_ASSIGN(TimeInfo cached_0, manager.GetTimeInfo(0, metric));
CB_ASSERT_OK_AND_ASSIGN(TimeInfo cached_1, manager.GetTimeInfo(1, metric));
CB_ASSERT_OK_AND_ASSIGN(TimeInfo cached_3, manager.GetTimeInfo(3, metric));
// The TimeInfos should all be equal to `expected`, since the mock converter always returns the
// same civil time for an OTHER_TIME_ZONE metric.
EXPECT_EQ(info_0.day_index, expected.day_index);
EXPECT_EQ(info_0.hour_id, expected.hour_id);
EXPECT_EQ(info_1.day_index, expected.day_index);
EXPECT_EQ(info_1.hour_id, expected.hour_id);
EXPECT_EQ(info_3.day_index, expected.day_index);
EXPECT_EQ(info_3.hour_id, expected.hour_id);
EXPECT_EQ(cached_0.day_index, expected.day_index);
EXPECT_EQ(cached_0.hour_id, expected.hour_id);
EXPECT_EQ(cached_1.day_index, expected.day_index);
EXPECT_EQ(cached_1.hour_id, expected.hour_id);
EXPECT_EQ(cached_3.day_index, expected.day_index);
EXPECT_EQ(cached_3.hour_id, expected.hour_id);
}
} // namespace
} // namespace cobalt::local_aggregation