1 // Copyright (C) 2016 The Android Open Source Project
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
7 // http://www.apache.org/licenses/LICENSE-2.0
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.
15 #include "anbox/graphics/buffer_queue.h"
16 #include "anbox/common/message_channel.h"
17 #include "anbox/logger.h"
19 #include <gtest/gtest.h>
25 TEST(BufferQueue, Constructor) {
26 BufferQueue queue(16);
29 TEST(BufferQueue, TryPushLocked) {
32 EXPECT_EQ(0, queue.try_push_locked(Buffer("Hello")));
33 EXPECT_EQ(0, queue.try_push_locked(Buffer("World")));
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!";
40 TEST(BufferQueue, TryPushLockedOnClosedQueue) {
43 EXPECT_EQ(0, queue.try_push_locked(Buffer("Hello")));
45 // Closing the queue prevents pushing new items to the queue.
48 EXPECT_EQ(-EIO, queue.try_push_locked(Buffer("World")));
51 TEST(BufferQueue, TryPopLocked) {
52 BufferQueue queue(2);;
55 EXPECT_EQ(-EAGAIN, queue.try_pop_locked(&buffer));
57 EXPECT_EQ(0, queue.try_push_locked(Buffer("Hello")));
58 EXPECT_EQ(0, queue.try_push_locked(Buffer("World")));
60 EXPECT_EQ(0, queue.try_pop_locked(&buffer));
61 EXPECT_STREQ("Hello", buffer.data());
63 EXPECT_EQ(0, queue.try_pop_locked(&buffer));
64 EXPECT_STREQ("World", buffer.data());
66 EXPECT_EQ(-EAGAIN, queue.try_pop_locked(&buffer));
67 EXPECT_STREQ("World", buffer.data());
70 TEST(BufferQueue, TryPopLockedOnClosedQueue) {
74 EXPECT_EQ(-EAGAIN, queue.try_pop_locked(&buffer));
76 EXPECT_EQ(0, queue.try_push_locked(Buffer("Hello")));
77 EXPECT_EQ(0, queue.try_push_locked(Buffer("World")));
79 EXPECT_EQ(0, queue.try_pop_locked(&buffer));
80 EXPECT_STREQ("Hello", buffer.data());
82 // Closing the queue doesn't prevent popping existing items, but
83 // will generate -EIO once it is empty.
86 EXPECT_EQ(0, queue.try_pop_locked(&buffer));
87 EXPECT_STREQ("World", buffer.data());
89 EXPECT_EQ(-EIO, queue.try_pop_locked(&buffer));
90 EXPECT_STREQ("World", buffer.data());
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 {
100 TestThread(std::mutex &lock, BufferQueue &queue) :
106 thread_ = std::thread(&TestThread::thread_main, this);
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)});
119 output_.receive(&reply);
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.
127 input_.send(Request{Cmd::Pop, Buffer{}});
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) {
135 output_.receive(&reply);
136 if (reply.result == 0)
137 *buffer = std::move(reply.buffer);
141 // Tell the test thread to close the queue from its side.
143 input_.send(Request{Cmd::Close, Buffer{}});
146 // Tell the test thread to stop after completing its current command.
148 input_.send(Request{Cmd::Stop, Buffer{}});
174 if (r.cmd == Cmd::Stop)
176 std::unique_lock<std::mutex> l(lock_);
178 bool sendReply = false;
181 reply.result = queue_.push_locked(std::move(r.buffer), l);
186 reply.result = queue_.pop_locked(&reply.buffer, l);
191 queue_.close_locked();
198 output_.send(std::move(reply));
205 anbox::common::MessageChannel<Request, 4> input_;
206 anbox::common::MessageChannel<Reply, 4> output_;
210 TEST(BufferQueue, PushLocked) {
212 BufferQueue queue(2);
213 TestThread thread(lock, queue);
215 ASSERT_TRUE(thread.start());
216 ASSERT_TRUE(thread.start_pop());
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));
226 TEST(BufferQueue, PushLockedWithClosedQueue) {
228 BufferQueue queue(2);
229 TestThread thread(lock, queue);
231 ASSERT_TRUE(thread.start());
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));
243 ASSERT_TRUE(thread.start_pop());
244 EXPECT_EQ(0, thread.end_pop(&buffer));
245 EXPECT_STREQ("Hello", buffer.data());
250 TEST(BufferQueue, PopLocked) {
252 BufferQueue queue(2);
253 TestThread thread(lock, queue);
255 ASSERT_TRUE(thread.start());
256 ASSERT_TRUE(thread.start_push(Buffer("Hello World")));
257 EXPECT_EQ(0, thread.end_push());
260 std::unique_lock<std::mutex> l(lock);
262 EXPECT_EQ(0, queue.pop_locked(&buffer, l));
263 EXPECT_STREQ("Hello World", buffer.data());
269 TEST(BufferQueue, PopLockedWithClosedQueue) {
271 BufferQueue queue(2);
272 TestThread thread(lock, queue);
274 ASSERT_TRUE(thread.start());
275 ASSERT_TRUE(thread.start_push(Buffer("Hello World")));
276 EXPECT_EQ(0, thread.end_push());
278 // Closing the queue shall not prevent pulling items from it.
279 // After that, -EIO shall be returned.
282 ASSERT_TRUE(thread.start_push(Buffer("Foo Bar")));
283 EXPECT_EQ(-EIO, thread.end_push());
286 std::unique_lock<std::mutex> l(lock);
288 EXPECT_EQ(0, queue.pop_locked(&buffer, l));
289 EXPECT_STREQ("Hello World", buffer.data());
291 EXPECT_EQ(-EIO, queue.pop_locked(&buffer, l));
292 EXPECT_STREQ("Hello World", buffer.data());
297 } // namespace graphics