xref: /aosp_15_r20/external/pigweed/pw_work_queue/work_queue_test.cc (revision 61c4878ac05f98d0ceed94b57d316916de578985)
1 // Copyright 2021 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_work_queue/work_queue.h"
16 
17 #include "pw_function/function.h"
18 #include "pw_log/log.h"
19 #include "pw_sync/thread_notification.h"
20 #include "pw_thread/thread.h"
21 #include "pw_unit_test/framework.h"
22 #include "pw_work_queue/test_thread.h"
23 
24 namespace pw::work_queue {
25 namespace {
26 
TEST(WorkQueue,PingPongOneRequestType)27 TEST(WorkQueue, PingPongOneRequestType) {
28   struct {
29     int counter = 0;
30     sync::ThreadNotification worker_ping;
31   } context;
32 
33   WorkQueueWithBuffer<10> work_queue;
34 
35   // Start the worker thread.
36   Thread work_thread(test::WorkQueueThreadOptions(), work_queue);
37 
38   // Pick a number bigger than the circular buffer to ensure we loop around.
39   const int kPingPongs = 300;
40 
41   for (int i = 0; i < kPingPongs; ++i) {
42     // Ping: throw work at the queue that will increment our counter.
43     EXPECT_EQ(OkStatus(), work_queue.PushWork([&context] {
44       context.counter++;
45       PW_LOG_INFO("Send pong...");
46       context.worker_ping.release();
47     }));
48 
49     // Throw a distraction in the queue.
50     EXPECT_EQ(OkStatus(), work_queue.PushWork([] {
51       PW_LOG_INFO("I'm a random task in the work queue; nothing to see here!");
52     }));
53 
54     // Pong: wait for the callback to notify us from the worker thread.
55     context.worker_ping.acquire();
56   }
57 
58   // Wait for the worker thread to terminate.
59   work_queue.RequestStop();
60   work_thread.join();
61 
62   EXPECT_EQ(context.counter, kPingPongs);
63 }
64 
TEST(WorkQueue,PingPongTwoRequestTypesWithExtraRequests)65 TEST(WorkQueue, PingPongTwoRequestTypesWithExtraRequests) {
66   struct {
67     int counter = 0;
68     sync::ThreadNotification worker_ping;
69   } context_a, context_b;
70 
71   WorkQueueWithBuffer<10> work_queue;
72 
73   // Start the worker thread.
74   Thread work_thread(test::WorkQueueThreadOptions(), work_queue);
75 
76   // Pick a number bigger than the circular buffer to ensure we loop around.
77   const int kPingPongs = 300;
78 
79   // Run a bunch of work items in the queue.
80   for (int i = 0; i < kPingPongs; ++i) {
81     // Other requests...
82     EXPECT_EQ(OkStatus(),
83               work_queue.PushWork([] { PW_LOG_INFO("Chopping onions"); }));
84 
85     // Ping A: throw work at the queue that will increment our counter.
86     EXPECT_EQ(OkStatus(), work_queue.PushWork([&context_a] {
87       context_a.counter++;
88       context_a.worker_ping.release();
89     }));
90 
91     // Other requests...
92     EXPECT_EQ(OkStatus(),
93               work_queue.PushWork([] { PW_LOG_INFO("Dicing carrots"); }));
94     EXPECT_EQ(OkStatus(),
95               work_queue.PushWork([] { PW_LOG_INFO("Blanching spinach"); }));
96 
97     // Ping B: throw work at the queue that will increment our counter.
98     EXPECT_EQ(OkStatus(), work_queue.PushWork([&context_b] {
99       context_b.counter++;
100       context_b.worker_ping.release();
101     }));
102 
103     // Other requests...
104     EXPECT_EQ(OkStatus(),
105               work_queue.PushWork([] { PW_LOG_INFO("Peeling potatoes"); }));
106 
107     // Pong A & B: wait for the callbacks to notify us from the worker thread.
108     context_a.worker_ping.acquire();
109     context_b.worker_ping.acquire();
110   }
111 
112   // Wait for the worker thread to terminate.
113   work_queue.RequestStop();
114   work_thread.join();
115 
116   EXPECT_EQ(context_a.counter, kPingPongs);
117   EXPECT_EQ(context_b.counter, kPingPongs);
118 }
119 
120 // TODO(ewout): Add unit tests for the metrics once they have been restructured.
121 
122 }  // namespace
123 }  // namespace pw::work_queue
124