xref: /aosp_15_r20/external/pigweed/pw_rpc/fuzz/alarm_timer_test.cc (revision 61c4878ac05f98d0ceed94b57d316916de578985)
1 // Copyright 2023 The Pigweed Authors
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License"); you may not
4 // use this file except in compliance with the License. You may obtain a copy of
5 // 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, WITHOUT
11 // WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
12 // License for the specific language governing permissions and limitations under
13 // the License.
14 
15 #include "pw_rpc/fuzz/alarm_timer.h"
16 
17 #include <chrono>
18 
19 #include "pw_chrono/system_clock.h"
20 #include "pw_sync/binary_semaphore.h"
21 #include "pw_unit_test/framework.h"
22 
23 namespace pw::rpc::fuzz {
24 namespace {
25 
26 using namespace std::chrono_literals;
27 
TEST(AlarmTimerTest,Start)28 TEST(AlarmTimerTest, Start) {
29   sync::BinarySemaphore sem;
30   AlarmTimer timer([&sem](chrono::SystemClock::time_point) { sem.release(); });
31   timer.Start(chrono::SystemClock::for_at_least(10ms));
32   sem.acquire();
33 }
34 
TEST(AlarmTimerTest,Restart)35 TEST(AlarmTimerTest, Restart) {
36   sync::BinarySemaphore final_sem;
37   sync::BinarySemaphore kick_sem;
38   constexpr auto kTimerDuration = 200ms;
39   constexpr auto kTimerKickDuration = 10ms;
40   constexpr size_t kNumRestarts = 10;
41   static_assert(kTimerKickDuration < kTimerDuration);
42 
43   AlarmTimer timer(
44       [&final_sem](chrono::SystemClock::time_point) { final_sem.release(); });
45   AlarmTimer timer_kicker(
46       [&kick_sem](chrono::SystemClock::time_point) { kick_sem.release(); });
47 
48   timer.Start(chrono::SystemClock::for_at_least(kTimerDuration));
49 
50   bool acquired = false;
51   const auto start = chrono::SystemClock::now();
52   for (size_t i = 0; i < kNumRestarts; ++i) {
53     // Be overly aggressive with restarting the timer, the point is to ensure
54     // that it doesn't time out when restareted. Since this tests timings, it
55     // inherrently is very prone to flake in some environments (e.g. heavy load
56     // on a Windows machine).
57     timer.Restart();
58     timer_kicker.Start(chrono::SystemClock::for_at_least(kTimerKickDuration));
59     timer.Restart();
60     kick_sem.acquire();
61     timer.Restart();
62 
63     acquired = final_sem.try_acquire();
64     EXPECT_FALSE(acquired);
65     if (acquired) {
66       break;
67     }
68   }
69 
70   if (!acquired) {
71     final_sem.acquire();
72   }
73   auto end = chrono::SystemClock::now();
74   EXPECT_GT(end - start, kTimerKickDuration * kNumRestarts + kTimerDuration);
75 }
76 
TEST(AlarmTimerTest,Cancel)77 TEST(AlarmTimerTest, Cancel) {
78   sync::BinarySemaphore sem;
79   AlarmTimer timer([&sem](chrono::SystemClock::time_point) { sem.release(); });
80   timer.Start(chrono::SystemClock::for_at_least(50ms));
81   timer.Cancel();
82   EXPECT_FALSE(sem.try_acquire_for(chrono::SystemClock::for_at_least(100us)));
83 }
84 
TEST(AlarmTimerTest,Destroy)85 TEST(AlarmTimerTest, Destroy) {
86   sync::BinarySemaphore sem;
87   {
88     AlarmTimer timer(
89         [&sem](chrono::SystemClock::time_point) { sem.release(); });
90     timer.Start(chrono::SystemClock::for_at_least(50ms));
91   }
92   EXPECT_FALSE(sem.try_acquire_for(chrono::SystemClock::for_at_least(100us)));
93 }
94 
95 }  // namespace
96 }  // namespace pw::rpc::fuzz
97