blob: 754a5c451e1962d606bc36832a0e44e644c2f3d3 [file] [log] [blame]
Siarhei Vishniakou473174e2017-12-27 16:44:42 -08001/*
2 * Copyright (C) 2019 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 "../BlockingQueue.h"
18
19
20#include <gtest/gtest.h>
21#include <thread>
22
23namespace android {
24
Prabir Pradhand5678112023-05-18 01:57:10 +000025using std::chrono_literals::operator""ns;
Siarhei Vishniakou473174e2017-12-27 16:44:42 -080026
27// --- BlockingQueueTest ---
28
29/**
Chris Yefa741282020-08-09 10:41:50 -070030 * Validate basic pop and push operation.
Siarhei Vishniakou473174e2017-12-27 16:44:42 -080031 */
32TEST(BlockingQueueTest, Queue_AddAndRemove) {
33 constexpr size_t capacity = 10;
34 BlockingQueue<int> queue(capacity);
35
36 ASSERT_TRUE(queue.push(1));
37 ASSERT_EQ(queue.pop(), 1);
Prabir Pradhand5678112023-05-18 01:57:10 +000038
39 ASSERT_TRUE(queue.emplace(2));
40 ASSERT_EQ(queue.popWithTimeout(0ns), 2);
41
42 ASSERT_TRUE(queue.push(3));
43 ASSERT_EQ(queue.popWithTimeout(100ns), 3);
44
45 ASSERT_EQ(std::nullopt, queue.popWithTimeout(0ns));
Siarhei Vishniakou473174e2017-12-27 16:44:42 -080046}
47
48/**
49 * Make sure the queue has strict capacity limits.
50 */
51TEST(BlockingQueueTest, Queue_ReachesCapacity) {
52 constexpr size_t capacity = 3;
53 BlockingQueue<int> queue(capacity);
54
55 // First 3 elements should be added successfully
56 ASSERT_TRUE(queue.push(1));
57 ASSERT_TRUE(queue.push(2));
58 ASSERT_TRUE(queue.push(3));
59 ASSERT_FALSE(queue.push(4)) << "Queue should reach capacity at size " << capacity;
60}
61
62/**
63 * Make sure the queue maintains FIFO order.
64 * Add elements and remove them, and check the order.
65 */
66TEST(BlockingQueueTest, Queue_isFIFO) {
67 constexpr size_t capacity = 10;
68 BlockingQueue<int> queue(capacity);
69
70 for (size_t i = 0; i < capacity; i++) {
71 ASSERT_TRUE(queue.push(static_cast<int>(i)));
72 }
73 for (size_t i = 0; i < capacity; i++) {
74 ASSERT_EQ(queue.pop(), static_cast<int>(i));
75 }
76}
77
78TEST(BlockingQueueTest, Queue_Clears) {
79 constexpr size_t capacity = 2;
80 BlockingQueue<int> queue(capacity);
81
82 queue.push(1);
83 queue.push(2);
84 queue.clear();
85 queue.push(3);
86 // Should no longer receive elements 1 and 2
87 ASSERT_EQ(3, queue.pop());
88}
89
90TEST(BlockingQueueTest, Queue_Erases) {
91 constexpr size_t capacity = 4;
92 BlockingQueue<int> queue(capacity);
93
94 queue.push(1);
95 queue.push(2);
96 queue.push(3);
97 queue.push(4);
98 // Erase elements 2 and 4
Prabir Pradhand5678112023-05-18 01:57:10 +000099 queue.erase_if([](int element) { return element == 2 || element == 4; });
Siarhei Vishniakou473174e2017-12-27 16:44:42 -0800100 // Should no longer receive elements 2 and 4
101 ASSERT_EQ(1, queue.pop());
102 ASSERT_EQ(3, queue.pop());
103}
104
105// --- BlockingQueueTest - Multiple threads ---
106
107TEST(BlockingQueueTest, Queue_AllowsMultipleThreads) {
108 constexpr size_t capacity = 100; // large capacity to increase likelihood that threads overlap
109 BlockingQueue<int> queue(capacity);
110
111 // Fill queue from a different thread
112 std::thread fillQueue([&queue](){
113 for (size_t i = 0; i < capacity; i++) {
114 ASSERT_TRUE(queue.push(static_cast<int>(i)));
115 }
116 });
117
118 // Make sure all elements are received in correct order
119 for (size_t i = 0; i < capacity; i++) {
120 ASSERT_EQ(queue.pop(), static_cast<int>(i));
121 }
122
123 fillQueue.join();
124}
125
126/**
127 * When the queue has no elements, and pop is called, it should block
128 * the current thread until an element is added to the queue (from another thread).
129 * Here we create a separate thread and call pop on an empty queue. Next,
130 * we check that the thread is blocked.
131 */
132TEST(BlockingQueueTest, Queue_BlocksWhileWaitingForElements) {
133 constexpr size_t capacity = 1;
134 BlockingQueue<int> queue(capacity);
135
136 std::atomic_bool hasReceivedElement = false;
137
138 // fill queue from a different thread
139 std::thread waitUntilHasElements([&queue, &hasReceivedElement](){
140 queue.pop(); // This should block until an element has been added
141 hasReceivedElement = true;
142 });
143
144 ASSERT_FALSE(hasReceivedElement);
145 queue.push(1);
146 waitUntilHasElements.join();
147 ASSERT_TRUE(hasReceivedElement);
148}
149
Prabir Pradhand5678112023-05-18 01:57:10 +0000150TEST(BlockingQueueTest, Queue_TimesOut) {
151 BlockingQueue<int> queue;
152 ASSERT_EQ(std::nullopt, queue.popWithTimeout(1ns));
153}
Siarhei Vishniakou473174e2017-12-27 16:44:42 -0800154
155} // namespace android