1 // Copyright 2017 The Abseil Authors.
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 // https://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14
15 #include "absl/time/clock.h"
16
17 #include "absl/base/config.h"
18 #if defined(ABSL_HAVE_ALARM)
19 #include <signal.h>
20 #include <unistd.h>
21 #ifdef _AIX
22 // sig_t is not defined in AIX.
23 typedef void (*sig_t)(int);
24 #endif
25 #elif defined(__linux__) || defined(__APPLE__)
26 #error all known Linux and Apple targets have alarm
27 #endif
28
29 #include "gtest/gtest.h"
30 #include "absl/time/time.h"
31
32 namespace {
33
TEST(Time,Now)34 TEST(Time, Now) {
35 const absl::Time before = absl::FromUnixNanos(absl::GetCurrentTimeNanos());
36 const absl::Time now = absl::Now();
37 const absl::Time after = absl::FromUnixNanos(absl::GetCurrentTimeNanos());
38 EXPECT_GE(now, before);
39 EXPECT_GE(after, now);
40 }
41
42 enum class AlarmPolicy { kWithoutAlarm, kWithAlarm };
43
44 #if defined(ABSL_HAVE_ALARM)
45 bool alarm_handler_invoked = false;
46
AlarmHandler(int signo)47 void AlarmHandler(int signo) {
48 ASSERT_EQ(signo, SIGALRM);
49 alarm_handler_invoked = true;
50 }
51 #endif
52
53 // Does SleepFor(d) take between lower_bound and upper_bound at least
54 // once between now and (now + timeout)? If requested (and supported),
55 // add an alarm for the middle of the sleep period and expect it to fire.
SleepForBounded(absl::Duration d,absl::Duration lower_bound,absl::Duration upper_bound,absl::Duration timeout,AlarmPolicy alarm_policy,int * attempts)56 bool SleepForBounded(absl::Duration d, absl::Duration lower_bound,
57 absl::Duration upper_bound, absl::Duration timeout,
58 AlarmPolicy alarm_policy, int* attempts) {
59 const absl::Time deadline = absl::Now() + timeout;
60 while (absl::Now() < deadline) {
61 #if defined(ABSL_HAVE_ALARM)
62 sig_t old_alarm = SIG_DFL;
63 if (alarm_policy == AlarmPolicy::kWithAlarm) {
64 alarm_handler_invoked = false;
65 old_alarm = signal(SIGALRM, AlarmHandler);
66 alarm(absl::ToInt64Seconds(d / 2));
67 }
68 #else
69 EXPECT_EQ(alarm_policy, AlarmPolicy::kWithoutAlarm);
70 #endif
71 ++*attempts;
72 absl::Time start = absl::Now();
73 absl::SleepFor(d);
74 absl::Duration actual = absl::Now() - start;
75 #if defined(ABSL_HAVE_ALARM)
76 if (alarm_policy == AlarmPolicy::kWithAlarm) {
77 signal(SIGALRM, old_alarm);
78 if (!alarm_handler_invoked) continue;
79 }
80 #endif
81 if (lower_bound <= actual && actual <= upper_bound) {
82 return true; // yes, the SleepFor() was correctly bounded
83 }
84 }
85 return false;
86 }
87
AssertSleepForBounded(absl::Duration d,absl::Duration early,absl::Duration late,absl::Duration timeout,AlarmPolicy alarm_policy)88 testing::AssertionResult AssertSleepForBounded(absl::Duration d,
89 absl::Duration early,
90 absl::Duration late,
91 absl::Duration timeout,
92 AlarmPolicy alarm_policy) {
93 const absl::Duration lower_bound = d - early;
94 const absl::Duration upper_bound = d + late;
95 int attempts = 0;
96 if (SleepForBounded(d, lower_bound, upper_bound, timeout, alarm_policy,
97 &attempts)) {
98 return testing::AssertionSuccess();
99 }
100 return testing::AssertionFailure()
101 << "SleepFor(" << d << ") did not return within [" << lower_bound
102 << ":" << upper_bound << "] in " << attempts << " attempt"
103 << (attempts == 1 ? "" : "s") << " over " << timeout
104 << (alarm_policy == AlarmPolicy::kWithAlarm ? " with" : " without")
105 << " an alarm";
106 }
107
108 // Tests that SleepFor() returns neither too early nor too late.
TEST(SleepFor,Bounded)109 TEST(SleepFor, Bounded) {
110 const absl::Duration d = absl::Milliseconds(2500);
111 const absl::Duration early = absl::Milliseconds(100);
112 const absl::Duration late = absl::Milliseconds(300);
113 const absl::Duration timeout = 48 * d;
114 EXPECT_TRUE(AssertSleepForBounded(d, early, late, timeout,
115 AlarmPolicy::kWithoutAlarm));
116 #if defined(ABSL_HAVE_ALARM)
117 EXPECT_TRUE(AssertSleepForBounded(d, early, late, timeout,
118 AlarmPolicy::kWithAlarm));
119 #endif
120 }
121
122 } // namespace
123