TYPE3
[iec.git] / src / type3_AndroidCloud / anbox-master / tests / anbox / graphics / buffer_queue_tests.cpp
1 // Copyright (C) 2016 The Android Open Source Project
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 // http://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,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14
15 #include "anbox/graphics/buffer_queue.h"
16 #include "anbox/common/message_channel.h"
17 #include "anbox/logger.h"
18
19 #include <gtest/gtest.h>
20
21 #include <thread>
22
23 namespace anbox {
24 namespace graphics {
25 TEST(BufferQueue, Constructor) {
26     BufferQueue queue(16);
27 }
28
29 TEST(BufferQueue, TryPushLocked) {
30     BufferQueue queue(2);
31
32     EXPECT_EQ(0, queue.try_push_locked(Buffer("Hello")));
33     EXPECT_EQ(0, queue.try_push_locked(Buffer("World")));
34
35     Buffer buff0("You Shall Not Move");
36     EXPECT_EQ(-EAGAIN, queue.try_push_locked(std::move(buff0)));
37     EXPECT_FALSE(buff0.empty()) << "Buffer should not be moved on failure!";
38 }
39
40 TEST(BufferQueue, TryPushLockedOnClosedQueue) {
41     BufferQueue queue(2);
42
43     EXPECT_EQ(0, queue.try_push_locked(Buffer("Hello")));
44
45     // Closing the queue prevents pushing new items to the queue.
46     queue.close_locked();
47
48     EXPECT_EQ(-EIO, queue.try_push_locked(Buffer("World")));
49 }
50
51 TEST(BufferQueue, TryPopLocked) {
52     BufferQueue queue(2);;
53
54     Buffer buffer;
55     EXPECT_EQ(-EAGAIN, queue.try_pop_locked(&buffer));
56
57     EXPECT_EQ(0, queue.try_push_locked(Buffer("Hello")));
58     EXPECT_EQ(0, queue.try_push_locked(Buffer("World")));
59
60     EXPECT_EQ(0, queue.try_pop_locked(&buffer));
61     EXPECT_STREQ("Hello", buffer.data());
62
63     EXPECT_EQ(0, queue.try_pop_locked(&buffer));
64     EXPECT_STREQ("World", buffer.data());
65
66     EXPECT_EQ(-EAGAIN, queue.try_pop_locked(&buffer));
67     EXPECT_STREQ("World", buffer.data());
68 }
69
70 TEST(BufferQueue, TryPopLockedOnClosedQueue) {
71     BufferQueue queue(2);
72
73     Buffer buffer;
74     EXPECT_EQ(-EAGAIN, queue.try_pop_locked(&buffer));
75
76     EXPECT_EQ(0, queue.try_push_locked(Buffer("Hello")));
77     EXPECT_EQ(0, queue.try_push_locked(Buffer("World")));
78
79     EXPECT_EQ(0, queue.try_pop_locked(&buffer));
80     EXPECT_STREQ("Hello", buffer.data());
81
82     // Closing the queue doesn't prevent popping existing items, but
83     // will generate -EIO once it is empty.
84     queue.close_locked();
85
86     EXPECT_EQ(0, queue.try_pop_locked(&buffer));
87     EXPECT_STREQ("World", buffer.data());
88
89     EXPECT_EQ(-EIO, queue.try_pop_locked(&buffer));
90     EXPECT_STREQ("World", buffer.data());
91 }
92
93 namespace {
94 // A TestThread instance that holds a reference to a queue and can either
95 // push or pull to it, on command from another thread. This uses a
96 // MessageChannel to implement the communication channel between the
97 // command thread and this one.
98 class TestThread final {
99  public:
100   TestThread(std::mutex &lock, BufferQueue &queue) :
101     lock_(lock),
102     queue_(queue) {
103   }
104
105   bool start() {
106     thread_ = std::thread(&TestThread::thread_main, this);
107     return true;
108   }
109
110   // Tell the test thread to push |buffer| to the queue.
111   // Call endPush() later to get the command's result.
112   bool start_push(Buffer&& buffer) {
113     input_.send(Request{Cmd::Push, std::move(buffer)});
114     return true;
115   }
116
117   int end_push() {
118     Reply reply = {};
119     output_.receive(&reply);
120     return reply.result;
121   }
122
123   // Tell the test thread to pop a buffer from the queue.
124   // Call end_pop() to get the command's result, as well as the popped
125   // buffer if it is 0.
126   bool start_pop() {
127     input_.send(Request{Cmd::Pop, Buffer{}});
128     return true;
129   }
130
131   // Return the result of a previous start_pop() command. If result is
132   // 0, sets |*buffer| to the result buffer.
133   int end_pop(Buffer* buffer) {
134     Reply reply = {};
135     output_.receive(&reply);
136     if (reply.result == 0)
137         *buffer = std::move(reply.buffer);
138     return reply.result;
139   }
140
141   // Tell the test thread to close the queue from its side.
142   void do_close() {
143     input_.send(Request{Cmd::Close, Buffer{}});
144   }
145
146   // Tell the test thread to stop after completing its current command.
147   void stop() {
148     input_.send(Request{Cmd::Stop, Buffer{}});
149     thread_.join();
150   }
151
152  private:
153   enum class Cmd {
154       Push,
155       Pop,
156       Close,
157       Stop,
158   };
159
160   struct Request {
161       Cmd cmd;
162       Buffer buffer;
163   };
164
165   struct Reply {
166       int result;
167       Buffer buffer;
168   };
169
170   void thread_main() {
171     while (true) {
172       Request r;
173       input_.receive(&r);
174       if (r.cmd == Cmd::Stop)
175           break;
176       std::unique_lock<std::mutex> l(lock_);
177       Reply reply = {};
178       bool sendReply = false;
179       switch (r.cmd) {
180           case Cmd::Push:
181               reply.result = queue_.push_locked(std::move(r.buffer), l);
182               sendReply = true;
183               break;
184
185           case Cmd::Pop:
186               reply.result = queue_.pop_locked(&reply.buffer, l);
187               sendReply = true;
188               break;
189
190           case Cmd::Close:
191               queue_.close_locked();
192               break;
193
194           default:
195               ;
196       }
197       if (sendReply)
198           output_.send(std::move(reply));
199     }
200   }
201
202   std::thread thread_;
203   std::mutex &lock_;
204   BufferQueue &queue_;
205   anbox::common::MessageChannel<Request, 4> input_;
206   anbox::common::MessageChannel<Reply, 4> output_;
207 };
208 } // namespace
209
210 TEST(BufferQueue, PushLocked) {
211     std::mutex lock;
212     BufferQueue queue(2);
213     TestThread thread(lock, queue);
214
215     ASSERT_TRUE(thread.start());
216     ASSERT_TRUE(thread.start_pop());
217
218     std::unique_lock<std::mutex> l(lock);
219     EXPECT_EQ(0, queue.push_locked(Buffer("Hello"), l));
220     EXPECT_EQ(0, queue.push_locked(Buffer("World"), l));
221     EXPECT_EQ(0, queue.push_locked(Buffer("Foo"), l));
222
223     thread.stop();
224 }
225
226 TEST(BufferQueue, PushLockedWithClosedQueue) {
227     std::mutex lock;
228     BufferQueue queue(2);
229     TestThread thread(lock, queue);
230
231     ASSERT_TRUE(thread.start());
232
233     {
234       std::unique_lock<std::mutex> l(lock);
235       EXPECT_EQ(0, queue.push_locked(Buffer("Hello"), l));
236       // Closing the queue prevents pushing new items, but not
237       // pulling from the queue.
238       queue.close_locked();
239       EXPECT_EQ(-EIO, queue.push_locked(Buffer("World"), l));
240     }
241
242     Buffer buffer;
243     ASSERT_TRUE(thread.start_pop());
244     EXPECT_EQ(0, thread.end_pop(&buffer));
245     EXPECT_STREQ("Hello", buffer.data());
246
247     thread.stop();
248 }
249
250 TEST(BufferQueue, PopLocked) {
251     std::mutex lock;
252     BufferQueue queue(2);
253     TestThread thread(lock, queue);
254
255     ASSERT_TRUE(thread.start());
256     ASSERT_TRUE(thread.start_push(Buffer("Hello World")));
257     EXPECT_EQ(0, thread.end_push());
258
259     {
260       std::unique_lock<std::mutex> l(lock);
261       Buffer buffer;
262       EXPECT_EQ(0, queue.pop_locked(&buffer, l));
263       EXPECT_STREQ("Hello World", buffer.data());
264     }
265
266     thread.stop();
267 }
268
269 TEST(BufferQueue, PopLockedWithClosedQueue) {
270     std::mutex lock;
271     BufferQueue queue(2);
272     TestThread thread(lock, queue);
273
274     ASSERT_TRUE(thread.start());
275     ASSERT_TRUE(thread.start_push(Buffer("Hello World")));
276     EXPECT_EQ(0, thread.end_push());
277
278     // Closing the queue shall not prevent pulling items from it.
279     // After that, -EIO shall be returned.
280     thread.do_close();
281
282     ASSERT_TRUE(thread.start_push(Buffer("Foo Bar")));
283     EXPECT_EQ(-EIO, thread.end_push());
284
285     {
286       std::unique_lock<std::mutex> l(lock);
287       Buffer buffer;
288       EXPECT_EQ(0, queue.pop_locked(&buffer, l));
289       EXPECT_STREQ("Hello World", buffer.data());
290
291       EXPECT_EQ(-EIO, queue.pop_locked(&buffer, l));
292       EXPECT_STREQ("Hello World", buffer.data());
293     }
294
295     thread.stop();
296 }
297 } // namespace graphics
298 } // namespace anbox