1 //
2 // Copyright 2018 The Android Open Source Project
3 //
4 // Licensed under the Apache License, Version 2.0 (the "License");
5 // you may not use this file except in compliance with the License.
6 // You may obtain a copy of the License at
7 //
8 // http://www.apache.org/licenses/LICENSE-2.0
9 //
10 // Unless required by applicable law or agreed to in writing, software
11 // distributed under the License is distributed on an "AS IS" BASIS,
12 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 // See the License for the specific language governing permissions and
14 // limitations under the License.
15 //
16
17 #include "fmq_driver/VtsFmqDriver.h"
18
19 #include <errno.h>
20 #include <limits.h>
21 #include <math.h>
22 #include <stdio.h>
23 #include <stdlib.h>
24 #include <string.h>
25 #include <sys/wait.h>
26 #include <time.h>
27 #include <unistd.h>
28
29 #include <fmq/MessageQueue.h>
30 #include <gtest/gtest.h>
31
32 using android::hardware::kSynchronizedReadWrite;
33 using android::hardware::kUnsynchronizedWrite;
34 using namespace std;
35
36 namespace android {
37 namespace vts {
38
39 // A test that initializes a single writer and a single reader.
40 class SyncReadWrites : public ::testing::Test {
41 protected:
SetUp()42 virtual void SetUp() {
43 static constexpr size_t NUM_ELEMS = 2048;
44
45 // initialize a writer
46 writer_id_ = manager_.CreateFmq<uint16_t, kSynchronizedReadWrite>(
47 "uint16_t", NUM_ELEMS, false);
48 ASSERT_NE(writer_id_, -1);
49
50 // initialize a reader
51 reader_id_ = manager_.CreateFmq<uint16_t, kSynchronizedReadWrite>(
52 "uint16_t", writer_id_);
53 ASSERT_NE(reader_id_, -1);
54 }
55
TearDown()56 virtual void TearDown() {}
57
58 VtsFmqDriver manager_;
59 QueueId writer_id_;
60 QueueId reader_id_;
61 };
62
63 // A test that initializes a single writer and a single reader.
64 // TODO: add tests for blocking between multiple queues later when there is more
65 // use case.
66 class BlockingReadWrites : public ::testing::Test {
67 protected:
SetUp()68 virtual void SetUp() {
69 static constexpr size_t NUM_ELEMS = 2048;
70
71 // initialize a writer
72 writer_id_ = manager_.CreateFmq<uint16_t, kSynchronizedReadWrite>(
73 "uint16_t", NUM_ELEMS, true);
74 ASSERT_NE(writer_id_, -1);
75
76 // initialize a reader
77 reader_id_ = manager_.CreateFmq<uint16_t, kSynchronizedReadWrite>(
78 "uint16_t", writer_id_);
79 ASSERT_NE(reader_id_, -1);
80 }
81
TearDown()82 virtual void TearDown() {}
83
84 VtsFmqDriver manager_;
85 QueueId writer_id_;
86 QueueId reader_id_;
87 };
88
89 // A test that initializes a single writer and two readers.
90 class UnsynchronizedWrites : public ::testing::Test {
91 protected:
SetUp()92 virtual void SetUp() {
93 static constexpr size_t NUM_ELEMS = 2048;
94
95 // initialize a writer
96 writer_id_ = manager_.CreateFmq<uint16_t, kUnsynchronizedWrite>(
97 "uint16_t", NUM_ELEMS, false);
98 ASSERT_NE(writer_id_, -1);
99
100 // initialize two readers
101 reader_id1_ = manager_.CreateFmq<uint16_t, kUnsynchronizedWrite>(
102 "uint16_t", writer_id_);
103 reader_id2_ = manager_.CreateFmq<uint16_t, kUnsynchronizedWrite>(
104 "uint16_t", writer_id_);
105 ASSERT_NE(reader_id1_, -1);
106 ASSERT_NE(reader_id2_, -1);
107 }
108
TearDown()109 virtual void TearDown() {}
110
111 VtsFmqDriver manager_;
112 QueueId writer_id_;
113 QueueId reader_id1_;
114 QueueId reader_id2_;
115 };
116
117 // Tests the reader and writer are set up correctly.
TEST_F(SyncReadWrites,SetupBasicTest)118 TEST_F(SyncReadWrites, SetupBasicTest) {
119 static constexpr size_t NUM_ELEMS = 2048;
120
121 // check if the writer has a valid queue
122 ASSERT_TRUE((manager_.IsValid<uint16_t, kSynchronizedReadWrite>("uint16_t",
123 writer_id_)));
124
125 // check queue size on writer side
126 size_t writer_queue_size;
127 ASSERT_TRUE((manager_.GetQuantumCount<uint16_t, kSynchronizedReadWrite>(
128 "uint16_t", writer_id_, &writer_queue_size)));
129 ASSERT_EQ(NUM_ELEMS, writer_queue_size);
130
131 // check queue element size on writer side
132 size_t writer_elem_size;
133 ASSERT_TRUE((manager_.GetQuantumSize<uint16_t, kSynchronizedReadWrite>(
134 "uint16_t", writer_id_, &writer_elem_size)));
135 ASSERT_EQ(sizeof(uint16_t), writer_elem_size);
136
137 // check space available for writer
138 size_t writer_available_writes;
139 ASSERT_TRUE((manager_.AvailableToWrite<uint16_t, kSynchronizedReadWrite>(
140 "uint16_t", writer_id_, &writer_available_writes)));
141 ASSERT_EQ(NUM_ELEMS, writer_available_writes);
142
143 // check if the reader has a valid queue
144 ASSERT_TRUE((manager_.IsValid<uint16_t, kSynchronizedReadWrite>("uint16_t",
145 reader_id_)));
146
147 // check queue size on reader side
148 size_t reader_queue_size;
149 ASSERT_TRUE((manager_.GetQuantumCount<uint16_t, kSynchronizedReadWrite>(
150 "uint16_t", reader_id_, &reader_queue_size)));
151 ASSERT_EQ(NUM_ELEMS, reader_queue_size);
152
153 // check queue element size on reader side
154 size_t reader_elem_size;
155 ASSERT_TRUE((manager_.GetQuantumSize<uint16_t, kSynchronizedReadWrite>(
156 "uint16_t", reader_id_, &reader_elem_size)));
157 ASSERT_EQ(sizeof(uint16_t), reader_elem_size);
158
159 // check items available for reader
160 size_t reader_available_reads;
161 ASSERT_TRUE((manager_.AvailableToRead<uint16_t, kSynchronizedReadWrite>(
162 "uint16_t", reader_id_, &reader_available_reads)));
163 ASSERT_EQ(0, reader_available_reads);
164 }
165
166 // util method to initialize data
InitData(uint16_t * data,size_t len)167 void InitData(uint16_t* data, size_t len) {
168 for (size_t i = 0; i < len; i++) {
169 data[i] = rand() % 100 + 1; // a random value between 1 and 100
170 }
171 }
172
173 // Tests a basic writer and reader interaction.
174 // Reader reads back data written by the writer correctly.
TEST_F(SyncReadWrites,ReadWriteSuccessTest)175 TEST_F(SyncReadWrites, ReadWriteSuccessTest) {
176 static constexpr size_t DATA_SIZE = 64;
177 uint16_t write_data[DATA_SIZE];
178 uint16_t read_data[DATA_SIZE];
179
180 // initialize the data to transfer
181 InitData(write_data, DATA_SIZE);
182
183 // writer should succeed
184 ASSERT_TRUE((manager_.WriteFmq<uint16_t, kSynchronizedReadWrite>(
185 "uint16_t", writer_id_, write_data, DATA_SIZE)));
186
187 // reader should succeed
188 ASSERT_TRUE((manager_.ReadFmq<uint16_t, kSynchronizedReadWrite>(
189 "uint16_t", reader_id_, read_data, DATA_SIZE)));
190
191 // check if the data is read back correctly
192 ASSERT_EQ(0, memcmp(write_data, read_data, DATA_SIZE * sizeof(uint16_t)));
193 }
194
195 // Tests reading from an empty queue.
TEST_F(SyncReadWrites,ReadEmpty)196 TEST_F(SyncReadWrites, ReadEmpty) {
197 static constexpr size_t DATA_SIZE = 64;
198 uint16_t read_data[DATA_SIZE];
199
200 // attempt to read from an empty queue
201 ASSERT_FALSE((manager_.ReadFmq<uint16_t, kSynchronizedReadWrite>(
202 "uint16_t", reader_id_, read_data, DATA_SIZE)));
203 }
204
205 // Tests writing to a full queue.
TEST_F(SyncReadWrites,WriteFull)206 TEST_F(SyncReadWrites, WriteFull) {
207 static constexpr size_t DATA_SIZE = 2048;
208 uint16_t write_data[DATA_SIZE];
209 uint16_t read_data[DATA_SIZE];
210
211 // initialize the data to transfer
212 InitData(write_data, DATA_SIZE);
213
214 // This write succeeds, filling up the queue
215 ASSERT_TRUE((manager_.WriteFmq<uint16_t, kSynchronizedReadWrite>(
216 "uint16_t", writer_id_, write_data, DATA_SIZE)));
217
218 // This write fails, queue is full
219 ASSERT_FALSE((manager_.WriteFmq<uint16_t, kSynchronizedReadWrite>(
220 "uint16_t", writer_id_, write_data, DATA_SIZE)));
221
222 // checks space available is 0
223 size_t writer_available_writes;
224 ASSERT_TRUE((manager_.AvailableToWrite<uint16_t, kSynchronizedReadWrite>(
225 "uint16_t", writer_id_, &writer_available_writes)));
226 ASSERT_EQ(0, writer_available_writes);
227
228 // reader succeeds, reads the entire queue back correctly
229 ASSERT_TRUE((manager_.ReadFmq<uint16_t, kSynchronizedReadWrite>(
230 "uint16_t", reader_id_, read_data, DATA_SIZE)));
231
232 ASSERT_EQ(0, memcmp(write_data, read_data, DATA_SIZE * sizeof(uint16_t)));
233 }
234
235 // Attempt to write more than the size of the queue.
TEST_F(SyncReadWrites,WriteTooLarge)236 TEST_F(SyncReadWrites, WriteTooLarge) {
237 static constexpr size_t LARGE_DATA_SIZE = 2049;
238 uint16_t write_data[LARGE_DATA_SIZE];
239
240 // initialize data to transfer
241 InitData(write_data, LARGE_DATA_SIZE);
242
243 // write more than the queue size
244 ASSERT_FALSE((manager_.WriteFmq<uint16_t, kSynchronizedReadWrite>(
245 "uint16_t", writer_id_, write_data, LARGE_DATA_SIZE)));
246 }
247
248 // Pass the wrong type.
TEST_F(SyncReadWrites,WrongType)249 TEST_F(SyncReadWrites, WrongType) {
250 static constexpr size_t DATA_SIZE = 2;
251 uint16_t write_data[DATA_SIZE];
252
253 // initialize data to transfer
254 InitData(write_data, DATA_SIZE);
255
256 // attempt to write uint32_t type
257 ASSERT_FALSE((manager_.WriteFmq<uint16_t, kSynchronizedReadWrite>(
258 "uint32_t", writer_id_, write_data, DATA_SIZE)));
259 }
260
261 // Tests consecutive interaction between writer and reader.
262 // Reader immediately reads back what writer writes.
TEST_F(SyncReadWrites,ConsecutiveReadWrite)263 TEST_F(SyncReadWrites, ConsecutiveReadWrite) {
264 static constexpr size_t DATA_SIZE = 64;
265 static constexpr size_t BATCH_SIZE = 10;
266 uint16_t read_data[DATA_SIZE];
267 uint16_t write_data[DATA_SIZE];
268
269 // 10 consecutive writes and reads
270 for (size_t i = 0; i < BATCH_SIZE; i++) {
271 InitData(write_data, DATA_SIZE);
272 ASSERT_TRUE((manager_.WriteFmq<uint16_t, kSynchronizedReadWrite>(
273 "uint16_t", writer_id_, write_data, DATA_SIZE)));
274
275 ASSERT_TRUE((manager_.ReadFmq<uint16_t, kSynchronizedReadWrite>(
276 "uint16_t", reader_id_, read_data, DATA_SIZE)));
277 ASSERT_EQ(0, memcmp(write_data, read_data, DATA_SIZE * sizeof(uint16_t)));
278 }
279
280 // no more available to read
281 size_t reader_available_reads;
282 ASSERT_TRUE((manager_.AvailableToRead<uint16_t, kSynchronizedReadWrite>(
283 "uint16_t", reader_id_, &reader_available_reads)));
284 ASSERT_EQ(0, reader_available_reads);
285 }
286
287 // Tests reader waiting for data to be available.
288 // Writer waits for 0.05s and writes the data.
289 // Reader blocks for at most 0.1s and reads the data if it is available.
TEST_F(BlockingReadWrites,ReadWriteSuccess)290 TEST_F(BlockingReadWrites, ReadWriteSuccess) {
291 static constexpr size_t DATA_SIZE = 64;
292
293 uint16_t read_data[DATA_SIZE];
294 uint16_t write_data[DATA_SIZE];
295
296 // initialize data to transfer
297 InitData(write_data, DATA_SIZE);
298
299 pid_t pid = fork();
300 if (pid == 0) { // child process is a reader, blocking for at most 0.1s.
301 ASSERT_TRUE((manager_.ReadFmqBlocking<uint16_t, kSynchronizedReadWrite>(
302 "uint16_t", reader_id_, read_data, DATA_SIZE, 100 * 1000000)));
303 ASSERT_EQ(0, memcmp(write_data, read_data, DATA_SIZE * sizeof(uint16_t)));
304 exit(0);
305 } else if (pid > 0) {
306 // parent process is a writer, waits for 0.05s and writes.
307 struct timespec writer_wait_time = {0, 50 * 1000000};
308 nanosleep(&writer_wait_time, NULL);
309 ASSERT_TRUE((manager_.WriteFmqBlocking<uint16_t, kSynchronizedReadWrite>(
310 "uint16_t", writer_id_, write_data, DATA_SIZE, 1000000)));
311 }
312 }
313
314 // Tests reader blocking times out.
TEST_F(BlockingReadWrites,BlockingTimeOut)315 TEST_F(BlockingReadWrites, BlockingTimeOut) {
316 static constexpr size_t DATA_SIZE = 64;
317 uint16_t read_data[DATA_SIZE];
318
319 // block for 0.05s, timeout
320 ASSERT_FALSE((manager_.ReadFmqBlocking<uint16_t, kSynchronizedReadWrite>(
321 "uint16_t", reader_id_, read_data, DATA_SIZE, 50 * 1000000)));
322 }
323
324 // Tests two readers can both read back what writer writes correctly.
TEST_F(UnsynchronizedWrites,ReadWriteSuccess)325 TEST_F(UnsynchronizedWrites, ReadWriteSuccess) {
326 static constexpr size_t DATA_SIZE = 64;
327 uint16_t write_data[DATA_SIZE];
328 uint16_t read_data1[DATA_SIZE];
329 uint16_t read_data2[DATA_SIZE];
330
331 // initialize data to transfer
332 InitData(write_data, DATA_SIZE);
333
334 // writer writes 64 items
335 ASSERT_TRUE((manager_.WriteFmq<uint16_t, kUnsynchronizedWrite>(
336 "uint16_t", writer_id_, write_data, DATA_SIZE)));
337
338 // reader 1 reads back data correctly
339 ASSERT_TRUE((manager_.ReadFmq<uint16_t, kUnsynchronizedWrite>(
340 "uint16_t", reader_id1_, read_data1, DATA_SIZE)));
341 ASSERT_EQ(0, memcmp(write_data, read_data1, DATA_SIZE * sizeof(uint16_t)));
342
343 // reader 2 reads back data correctly
344 ASSERT_TRUE((manager_.ReadFmq<uint16_t, kUnsynchronizedWrite>(
345 "uint16_t", reader_id2_, read_data2, DATA_SIZE)));
346 ASSERT_EQ(0, memcmp(write_data, read_data2, DATA_SIZE * sizeof(uint16_t)));
347 }
348
349 // Tests that blocking is not allowed on unsynchronized queue.
TEST_F(UnsynchronizedWrites,IllegalBlocking)350 TEST_F(UnsynchronizedWrites, IllegalBlocking) {
351 static constexpr size_t DATA_SIZE = 64;
352 uint16_t write_data[DATA_SIZE];
353
354 // initialize data to transfer
355 InitData(write_data, DATA_SIZE);
356
357 // should fail immediately, instead of blocking
358 ASSERT_FALSE((manager_.WriteFmqBlocking<uint16_t, kUnsynchronizedWrite>(
359 "uint16_t", writer_id_, write_data, DATA_SIZE, 1000000)));
360 }
361
362 } // namespace vts
363 } // namespace android
364