memgraph/tests/unit/utils_async_timer.cpp
János Benjamin Antal 537855a0b2
Fix usages of constexpr (#367)
* Fix usages of constexpr
2022-03-31 13:52:43 +02:00

150 lines
4.9 KiB
C++

// Copyright 2022 Memgraph Ltd.
//
// Use of this software is governed by the Business Source License
// included in the file licenses/BSL.txt; by using this file, you agree to be bound by the terms of the Business Source
// License, and you may not use this file except in compliance with the Business Source License.
//
// As of the Change Date specified in that file, in accordance with
// the Business Source License, use of this software will be governed
// by the Apache License, Version 2.0, included in the file
// licenses/APL.txt.
#include <chrono>
#include <cmath>
#include <limits>
#include "gtest/gtest.h"
#include "utils/async_timer.hpp"
using AsyncTimer = memgraph::utils::AsyncTimer;
inline constexpr auto kSecondsInMilis = 1000.0;
inline constexpr auto kIntervalInSeconds = 0.3;
inline constexpr auto kIntervalInMilis = kIntervalInSeconds * kSecondsInMilis;
inline constexpr auto kAbsoluteErrorInMilis = 50;
std::chrono::steady_clock::time_point Now() { return std::chrono::steady_clock::now(); }
int ElapsedMilis(const std::chrono::steady_clock::time_point &start, const std::chrono::steady_clock::time_point &end) {
return std::chrono::duration_cast<std::chrono::milliseconds>(end - start).count();
}
void CheckTimeSimple() {
const auto before = Now();
AsyncTimer timer{kIntervalInSeconds};
while (!timer.IsExpired()) {
ASSERT_LT(ElapsedMilis(before, Now()), 2 * kIntervalInMilis);
}
const auto after = Now();
EXPECT_NEAR(ElapsedMilis(before, after), kIntervalInMilis, kAbsoluteErrorInMilis);
}
TEST(AsyncTimer, SimpleWait) { CheckTimeSimple(); }
TEST(AsyncTimer, DoubleWait) {
CheckTimeSimple();
CheckTimeSimple();
}
TEST(AsyncTimer, MoveConstruct) {
const auto before = Now();
AsyncTimer timer_1{kIntervalInSeconds};
AsyncTimer timer_2{std::move(timer_1)};
EXPECT_FALSE(timer_1.IsExpired());
EXPECT_FALSE(timer_2.IsExpired());
const auto first_check_point = Now();
while (!timer_2.IsExpired()) {
ASSERT_LT(ElapsedMilis(before, Now()), 2 * kIntervalInMilis);
}
const auto second_check_point = Now();
EXPECT_FALSE(timer_1.IsExpired());
EXPECT_TRUE(timer_2.IsExpired());
EXPECT_LT(ElapsedMilis(before, first_check_point), kIntervalInMilis / 2);
EXPECT_NEAR(ElapsedMilis(before, second_check_point), kIntervalInMilis, kAbsoluteErrorInMilis);
}
TEST(AsyncTimer, MoveAssign) {
const auto before = Now();
AsyncTimer timer_1{2 * kIntervalInSeconds};
AsyncTimer timer_2{kIntervalInSeconds};
EXPECT_FALSE(timer_1.IsExpired());
EXPECT_FALSE(timer_2.IsExpired());
const auto first_check_point = Now();
timer_2 = std::move(timer_1);
EXPECT_FALSE(timer_1.IsExpired());
EXPECT_FALSE(timer_2.IsExpired());
while (!timer_2.IsExpired()) {
ASSERT_LT(ElapsedMilis(before, Now()), 3 * kIntervalInMilis);
}
const auto second_check_point = Now();
EXPECT_FALSE(timer_1.IsExpired());
EXPECT_TRUE(timer_2.IsExpired());
EXPECT_LT(ElapsedMilis(before, first_check_point), kIntervalInMilis / 2);
EXPECT_NEAR(ElapsedMilis(before, second_check_point), 2 * kIntervalInMilis, kAbsoluteErrorInMilis);
}
TEST(AsyncTimer, AssignToExpiredTimer) {
const auto before = Now();
AsyncTimer timer_1{2 * kIntervalInSeconds};
AsyncTimer timer_2{kIntervalInSeconds};
EXPECT_FALSE(timer_1.IsExpired());
EXPECT_FALSE(timer_2.IsExpired());
const auto first_check_point = Now();
while (!timer_2.IsExpired()) {
ASSERT_LT(ElapsedMilis(before, Now()), 3 * kIntervalInMilis);
}
EXPECT_FALSE(timer_1.IsExpired());
EXPECT_TRUE(timer_2.IsExpired());
const auto second_check_point = Now();
timer_2 = std::move(timer_1);
EXPECT_FALSE(timer_1.IsExpired());
EXPECT_FALSE(timer_2.IsExpired());
const auto third_check_point = Now();
while (!timer_2.IsExpired()) {
ASSERT_LT(ElapsedMilis(before, Now()), 3 * kIntervalInMilis);
}
EXPECT_FALSE(timer_1.IsExpired());
EXPECT_TRUE(timer_2.IsExpired());
const auto fourth_check_point = Now();
EXPECT_LT(ElapsedMilis(before, first_check_point), kIntervalInMilis / 2);
EXPECT_NEAR(ElapsedMilis(before, second_check_point), kIntervalInMilis, kAbsoluteErrorInMilis);
EXPECT_LT(ElapsedMilis(before, third_check_point), 1.5 * kIntervalInMilis);
EXPECT_NEAR(ElapsedMilis(before, fourth_check_point), 2 * kIntervalInMilis, kAbsoluteErrorInMilis);
}
TEST(AsyncTimer, DestroyTimerWhileItIsStillRunning) {
{ AsyncTimer timer_to_destroy{kIntervalInSeconds}; }
const auto before = Now();
AsyncTimer timer_to_wait{1.5 * kIntervalInSeconds};
while (!timer_to_wait.IsExpired()) {
ASSERT_LT(ElapsedMilis(before, Now()), 3 * kIntervalInMilis);
}
// At this point the timer_to_destroy has expired, nothing bad happened. This doesn't mean the timer cancellation
// works properly, it just means that nothing bad happens if a timer get cancelled.
}
TEST(AsyncTimer, TimersWithExtremeValues) {
AsyncTimer timer_with_zero{0};
const double expected_maximum_value = std::nexttoward(std::numeric_limits<time_t>::max(), 0.0);
AsyncTimer timer_with_max_value{expected_maximum_value};
}