blob: d1c04708d20845757e92a682fc2c6acce927e3c8 [file] [log] [blame]
Adrian Salido0e892682017-03-01 14:57:39 -08001#include <gtest/gtest.h>
2#include <hardware/hardware.h>
3
4#include <chrono>
5#include <mutex>
6
7#include "queue_worker.h"
8
9using android::QueueWorker;
10
11#define UNUSED_ARG(x) (void)(x)
12
13struct TestData {
14 TestData(int val) : value(val) {
15 }
16 virtual ~TestData() {
17 }
18
19 virtual void CheckValue(int prev_value) {
20 ASSERT_EQ(prev_value + 1, value);
21 }
22
23 int value;
24};
25
26struct TestQueueWorker : public QueueWorker<TestData> {
27 TestQueueWorker()
28 : QueueWorker("test-queueworker", HAL_PRIORITY_URGENT_DISPLAY), value(0) {
29 }
30
31 int Init() {
32 return InitWorker();
33 }
34
35 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
45 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
55struct QueueWorkerTest : public testing::Test {
56 static const int kTimeoutMs = 1000;
57 TestQueueWorker qw;
58
59 virtual void SetUp() {
60 qw.Init();
61 }
62 bool QueueValue(int val) {
63 std::unique_ptr<TestData> data(new TestData(val));
64 return !qw.QueueWork(std::move(data));
65 }
66
67 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
75struct IdleQueueWorkerTest : public QueueWorkerTest {
76 const int64_t kIdleTimeoutMs = 100;
77
78 virtual void SetUp() {
79 qw.set_idle_timeout(kIdleTimeoutMs);
80 qw.Init();
81 }
82};
83
84TEST_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
95TEST_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
104TEST_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
113TEST_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
145TEST_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
163TEST_F(QueueWorkerTest, exit_empty) {
164 qw.Exit();
165 ASSERT_FALSE(qw.initialized());
166}
167
168TEST_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
178TEST_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}