• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 #include <gtest/gtest.h>
2 #include <hardware/hardware.h>
3 
4 #include <chrono>
5 #include <mutex>
6 
7 #include "queue_worker.h"
8 
9 using android::QueueWorker;
10 
11 #define UNUSED_ARG(x) (void)(x)
12 
13 struct TestData {
TestDataTestData14   TestData(int val) : value(val) {
15   }
~TestDataTestData16   virtual ~TestData() {
17   }
18 
CheckValueTestData19   virtual void CheckValue(int prev_value) {
20     ASSERT_EQ(prev_value + 1, value);
21   }
22 
23   int value;
24 };
25 
26 struct TestQueueWorker : public QueueWorker<TestData> {
TestQueueWorkerTestQueueWorker27   TestQueueWorker()
28       : QueueWorker("test-queueworker", HAL_PRIORITY_URGENT_DISPLAY), value(0) {
29   }
30 
InitTestQueueWorker31   int Init() {
32     return InitWorker();
33   }
34 
ProcessWorkTestQueueWorker35   void ProcessWork(std::unique_ptr<TestData> data) {
36     std::lock_guard<std::mutex> blk(block);
37     data->CheckValue(value);
38     {
39       std::lock_guard<std::mutex> lk(lock);
40       value = data->value;
41     }
42     cond.notify_one();
43   }
44 
ProcessIdleTestQueueWorker45   void ProcessIdle() {
46     ASSERT_FALSE(idle());
47   }
48 
49   std::mutex lock;
50   std::mutex block;
51   std::condition_variable cond;
52   int value;
53 };
54 
55 struct QueueWorkerTest : public testing::Test {
56   static const int kTimeoutMs = 1000;
57   TestQueueWorker qw;
58 
SetUpQueueWorkerTest59   virtual void SetUp() {
60     qw.Init();
61   }
QueueValueQueueWorkerTest62   bool QueueValue(int val) {
63     std::unique_ptr<TestData> data(new TestData(val));
64     return !qw.QueueWork(std::move(data));
65   }
66 
WaitForQueueWorkerTest67   bool WaitFor(int val, int timeout_ms = kTimeoutMs) {
68     std::unique_lock<std::mutex> lk(qw.lock);
69 
70     auto timeout = std::chrono::milliseconds(timeout_ms);
71     return qw.cond.wait_for(lk, timeout, [&] { return qw.value == val; });
72   }
73 };
74 
75 struct IdleQueueWorkerTest : public QueueWorkerTest {
76   const int64_t kIdleTimeoutMs = 100;
77 
SetUpIdleQueueWorkerTest78   virtual void SetUp() {
79     qw.set_idle_timeout(kIdleTimeoutMs);
80     qw.Init();
81   }
82 };
83 
TEST_F(QueueWorkerTest,single_queue)84 TEST_F(QueueWorkerTest, single_queue) {
85   // already isInitialized so should fail
86   ASSERT_NE(qw.Init(), 0);
87 
88   ASSERT_EQ(qw.value, 0);
89   ASSERT_TRUE(QueueValue(1));
90   ASSERT_TRUE(WaitFor(1));
91   ASSERT_EQ(qw.value, 1);
92   ASSERT_FALSE(qw.IsWorkPending());
93 }
94 
TEST_F(QueueWorkerTest,multiple_waits)95 TEST_F(QueueWorkerTest, multiple_waits) {
96   for (int i = 1; i <= 100; i++) {
97     ASSERT_TRUE(QueueValue(i));
98     ASSERT_TRUE(WaitFor(i));
99     ASSERT_EQ(qw.value, i);
100     ASSERT_FALSE(qw.IsWorkPending());
101   }
102 }
103 
TEST_F(QueueWorkerTest,multiple_queue)104 TEST_F(QueueWorkerTest, multiple_queue) {
105   for (int i = 1; i <= 100; i++) {
106     ASSERT_TRUE(QueueValue(i));
107   }
108   ASSERT_TRUE(WaitFor(100));
109   ASSERT_EQ(qw.value, 100);
110   ASSERT_FALSE(qw.IsWorkPending());
111 }
112 
TEST_F(QueueWorkerTest,blocking)113 TEST_F(QueueWorkerTest, blocking) {
114   // First wait for inital value to be setup
115   ASSERT_TRUE(QueueValue(1));
116   ASSERT_TRUE(WaitFor(1));
117 
118   // Block processing and fill up the queue
119   std::unique_lock<std::mutex> lk(qw.block);
120   size_t expected_value = qw.max_queue_size() + 2;
121   for (size_t i = 2; i <= expected_value; i++) {
122     ASSERT_TRUE(QueueValue(i));
123   }
124 
125   qw.set_queue_timeout(100);
126   // any additional queueing should fail
127   ASSERT_FALSE(QueueValue(expected_value + 1));
128 
129   // make sure value is not changed while blocked
130   {
131     std::unique_lock<std::mutex> lock(qw.lock);
132     auto timeout = std::chrono::milliseconds(100);
133     ASSERT_FALSE(
134         qw.cond.wait_for(lock, timeout, [&] { return qw.value != 1; }));
135   }
136   ASSERT_EQ(qw.value, 1);
137   ASSERT_TRUE(qw.IsWorkPending());
138 
139   // unblock and wait for value to be reached
140   lk.unlock();
141   ASSERT_TRUE(WaitFor(expected_value));
142   ASSERT_FALSE(qw.IsWorkPending());
143 }
144 
TEST_F(QueueWorkerTest,exit_slow)145 TEST_F(QueueWorkerTest, exit_slow) {
146   struct SlowData : public TestData {
147     SlowData(int val) : TestData(val) {
148     }
149     void CheckValue(int prev_value) {
150       UNUSED_ARG(prev_value);
151 
152       std::this_thread::sleep_for(std::chrono::milliseconds(100));
153     }
154   };
155   std::unique_ptr<SlowData> data(new SlowData(1));
156   ASSERT_EQ(qw.QueueWork(std::move(data)), 0);
157   data = std::unique_ptr<SlowData>(new SlowData(2));
158   ASSERT_EQ(qw.QueueWork(std::move(data)), 0);
159   qw.Exit();
160   ASSERT_FALSE(qw.initialized());
161 }
162 
TEST_F(QueueWorkerTest,exit_empty)163 TEST_F(QueueWorkerTest, exit_empty) {
164   qw.Exit();
165   ASSERT_FALSE(qw.initialized());
166 }
167 
TEST_F(QueueWorkerTest,queue_worker_noidling)168 TEST_F(QueueWorkerTest, queue_worker_noidling) {
169   ASSERT_TRUE(QueueValue(1));
170   ASSERT_TRUE(WaitFor(1));
171 
172   ASSERT_FALSE(qw.idle());
173   auto timeout = std::chrono::milliseconds(200);
174   std::this_thread::sleep_for(timeout);
175   ASSERT_FALSE(qw.idle());
176 }
177 
TEST_F(IdleQueueWorkerTest,queue_worker_idling)178 TEST_F(IdleQueueWorkerTest, queue_worker_idling) {
179   ASSERT_TRUE(QueueValue(1));
180   ASSERT_TRUE(WaitFor(1));
181   ASSERT_FALSE(qw.idle());
182 
183   auto timeout = std::chrono::milliseconds(kIdleTimeoutMs + 10);
184   std::this_thread::sleep_for(timeout);
185   ASSERT_TRUE(qw.idle());
186   ASSERT_TRUE(QueueValue(2));
187   ASSERT_TRUE(WaitFor(2));
188   ASSERT_FALSE(qw.idle());
189 
190   std::this_thread::sleep_for(3 * timeout);
191   ASSERT_TRUE(qw.idle());
192 
193   ASSERT_TRUE(QueueValue(3));
194   ASSERT_TRUE(WaitFor(3));
195   for (int i = 4; i <= 100; i++) {
196     QueueValue(i);
197   }
198   ASSERT_FALSE(qw.idle());
199   qw.Exit();
200   ASSERT_FALSE(qw.initialized());
201 }