537855a0b2
* Fix usages of constexpr
150 lines
4.9 KiB
C++
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};
|
|
}
|