about summary refs log tree commit diff
path: root/absl/time/clock_test.cc
diff options
context:
space:
mode:
Diffstat (limited to 'absl/time/clock_test.cc')
-rw-r--r--absl/time/clock_test.cc94
1 files changed, 71 insertions, 23 deletions
diff --git a/absl/time/clock_test.cc b/absl/time/clock_test.cc
index f143c0360b0d..707166d0c289 100644
--- a/absl/time/clock_test.cc
+++ b/absl/time/clock_test.cc
@@ -35,36 +35,84 @@ TEST(Time, Now) {
   EXPECT_GE(after, now);
 }
 
-TEST(SleepForTest, BasicSanity) {
-  absl::Duration sleep_time = absl::Milliseconds(2500);
-  absl::Time start = absl::Now();
-  absl::SleepFor(sleep_time);
-  absl::Time end = absl::Now();
-  EXPECT_LE(sleep_time - absl::Milliseconds(100), end - start);
-  EXPECT_GE(sleep_time + absl::Milliseconds(200), end - start);
-}
+enum class AlarmPolicy { kWithoutAlarm, kWithAlarm };
 
-#ifdef ABSL_HAVE_ALARM
-// Helper for test SleepFor.
+#if defined(ABSL_HAVE_ALARM)
 bool alarm_handler_invoked = false;
+
 void AlarmHandler(int signo) {
   ASSERT_EQ(signo, SIGALRM);
   alarm_handler_invoked = true;
 }
+#endif
+
+// Does SleepFor(d) take between lower_bound and upper_bound at least
+// once between now and (now + timeout)?  If requested (and supported),
+// add an alarm for the middle of the sleep period and expect it to fire.
+bool SleepForBounded(absl::Duration d, absl::Duration lower_bound,
+                     absl::Duration upper_bound, absl::Duration timeout,
+                     AlarmPolicy alarm_policy, int* attempts) {
+  const absl::Time deadline = absl::Now() + timeout;
+  while (absl::Now() < deadline) {
+#if defined(ABSL_HAVE_ALARM)
+    sig_t old_alarm = SIG_DFL;
+    if (alarm_policy == AlarmPolicy::kWithAlarm) {
+      alarm_handler_invoked = false;
+      old_alarm = signal(SIGALRM, AlarmHandler);
+      alarm(absl::ToInt64Seconds(d / 2));
+    }
+#else
+    EXPECT_EQ(alarm_policy, AlarmPolicy::kWithoutAlarm);
+#endif
+    ++*attempts;
+    absl::Time start = absl::Now();
+    absl::SleepFor(d);
+    absl::Duration actual = absl::Now() - start;
+#if defined(ABSL_HAVE_ALARM)
+    if (alarm_policy == AlarmPolicy::kWithAlarm) {
+      signal(SIGALRM, old_alarm);
+      if (!alarm_handler_invoked) continue;
+    }
+#endif
+    if (lower_bound <= actual && actual <= upper_bound) {
+      return true;  // yes, the SleepFor() was correctly bounded
+    }
+  }
+  return false;
+}
 
-TEST(SleepForTest, AlarmSupport) {
-  alarm_handler_invoked = false;
-  sig_t old_alarm = signal(SIGALRM, AlarmHandler);
-  alarm(2);
-  absl::Duration sleep_time = absl::Milliseconds(3500);
-  absl::Time start = absl::Now();
-  absl::SleepFor(sleep_time);
-  absl::Time end = absl::Now();
-  EXPECT_TRUE(alarm_handler_invoked);
-  EXPECT_LE(sleep_time - absl::Milliseconds(100), end - start);
-  EXPECT_GE(sleep_time + absl::Milliseconds(200), end - start);
-  signal(SIGALRM, old_alarm);
+testing::AssertionResult AssertSleepForBounded(absl::Duration d,
+                                               absl::Duration early,
+                                               absl::Duration late,
+                                               absl::Duration timeout,
+                                               AlarmPolicy alarm_policy) {
+  const absl::Duration lower_bound = d - early;
+  const absl::Duration upper_bound = d + late;
+  int attempts = 0;
+  if (SleepForBounded(d, lower_bound, upper_bound, timeout, alarm_policy,
+                      &attempts)) {
+    return testing::AssertionSuccess();
+  }
+  return testing::AssertionFailure()
+         << "SleepFor(" << d << ") did not return within [" << lower_bound
+         << ":" << upper_bound << "] in " << attempts << " attempt"
+         << (attempts == 1 ? "" : "s") << " over " << timeout
+         << (alarm_policy == AlarmPolicy::kWithAlarm ? " with" : " without")
+         << " an alarm";
+}
+
+// Tests that SleepFor() returns neither too early nor too late.
+TEST(SleepFor, Bounded) {
+  const absl::Duration d = absl::Milliseconds(2500);
+  const absl::Duration early = absl::Milliseconds(100);
+  const absl::Duration late = absl::Milliseconds(300);
+  const absl::Duration timeout = 48 * d;
+  EXPECT_TRUE(AssertSleepForBounded(d, early, late, timeout,
+                                    AlarmPolicy::kWithoutAlarm));
+#if defined(ABSL_HAVE_ALARM)
+  EXPECT_TRUE(AssertSleepForBounded(d, early, late, timeout,
+                                    AlarmPolicy::kWithAlarm));
+#endif
 }
-#endif  // ABSL_HAVE_ALARM
 
 }  // namespace