| // 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/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 |