1*05767d91SRobert Wu /*
2*05767d91SRobert Wu * Copyright 2018 The Android Open Source Project
3*05767d91SRobert Wu *
4*05767d91SRobert Wu * Licensed under the Apache License, Version 2.0 (the "License");
5*05767d91SRobert Wu * you may not use this file except in compliance with the License.
6*05767d91SRobert Wu * You may obtain a copy of the License at
7*05767d91SRobert Wu *
8*05767d91SRobert Wu * http://www.apache.org/licenses/LICENSE-2.0
9*05767d91SRobert Wu *
10*05767d91SRobert Wu * Unless required by applicable law or agreed to in writing, software
11*05767d91SRobert Wu * distributed under the License is distributed on an "AS IS" BASIS,
12*05767d91SRobert Wu * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13*05767d91SRobert Wu * See the License for the specific language governing permissions and
14*05767d91SRobert Wu * limitations under the License.
15*05767d91SRobert Wu */
16*05767d91SRobert Wu
17*05767d91SRobert Wu #include <thread>
18*05767d91SRobert Wu #include <iostream>
19*05767d91SRobert Wu
20*05767d91SRobert Wu #include <gtest/gtest.h>
21*05767d91SRobert Wu #include "utils/LockFreeQueue.h"
22*05767d91SRobert Wu
23*05767d91SRobert Wu /**
24*05767d91SRobert Wu * Tests
25*05767d91SRobert Wu * =====
26*05767d91SRobert Wu *
27*05767d91SRobert Wu * READ/POP:
28*05767d91SRobert Wu * - if queue is empty return false
29*05767d91SRobert Wu * - if queue has elements return true
30*05767d91SRobert Wu * - returns correct value once
31*05767d91SRobert Wu * - returns correct value more than once
32*05767d91SRobert Wu *
33*05767d91SRobert Wu * WRITE/PUSH:
34*05767d91SRobert Wu * - if queue is full return false
35*05767d91SRobert Wu * - if queue has space return true
36*05767d91SRobert Wu *
37*05767d91SRobert Wu * WRAP:
38*05767d91SRobert Wu * - read from full queue, then write one more element, then correct read
39*05767d91SRobert Wu *
40*05767d91SRobert Wu * PEEK:
41*05767d91SRobert Wu * - peek once
42*05767d91SRobert Wu * - peek twice
43*05767d91SRobert Wu *
44*05767d91SRobert Wu * SIZE:
45*05767d91SRobert Wu * - correct zero
46*05767d91SRobert Wu * - correct once
47*05767d91SRobert Wu * - correct many
48*05767d91SRobert Wu *
49*05767d91SRobert Wu * MULTI-THREADED:
50*05767d91SRobert Wu * - write and read concurrently, queue is empty at end and item order is maintained
51*05767d91SRobert Wu *
52*05767d91SRobert Wu * CANNOT TEST:
53*05767d91SRobert Wu * - read/writes correct after wraparound (takes too long to run)
54*05767d91SRobert Wu * - Constructing queue with non power of 2 capacity results in assert failure (needs death test)
55*05767d91SRobert Wu * - Constructing queue with signed type results in assert failure (needs death test)
56*05767d91SRobert Wu *
57*05767d91SRobert Wu */
58*05767d91SRobert Wu
59*05767d91SRobert Wu constexpr int kQueueCapacity = 2;
60*05767d91SRobert Wu
61*05767d91SRobert Wu class TestLockFreeQueue : public ::testing::Test {
62*05767d91SRobert Wu
63*05767d91SRobert Wu public:
64*05767d91SRobert Wu
65*05767d91SRobert Wu int result1;
66*05767d91SRobert Wu int result2;
67*05767d91SRobert Wu int result3;
68*05767d91SRobert Wu LockFreeQueue<int, kQueueCapacity> q;
69*05767d91SRobert Wu };
70*05767d91SRobert Wu
TEST_F(TestLockFreeQueue,PopReturnsFalseWhenEmpty)71*05767d91SRobert Wu TEST_F(TestLockFreeQueue, PopReturnsFalseWhenEmpty){
72*05767d91SRobert Wu bool result = q.pop(result1);
73*05767d91SRobert Wu ASSERT_EQ(result, false);
74*05767d91SRobert Wu }
75*05767d91SRobert Wu
TEST_F(TestLockFreeQueue,PopReturnsTrueWhenNotEmpty)76*05767d91SRobert Wu TEST_F(TestLockFreeQueue, PopReturnsTrueWhenNotEmpty){
77*05767d91SRobert Wu q.push(123);
78*05767d91SRobert Wu bool result = q.pop(result1);
79*05767d91SRobert Wu ASSERT_EQ(result, true);
80*05767d91SRobert Wu }
81*05767d91SRobert Wu
TEST_F(TestLockFreeQueue,PopReturnsOneCorrectValue)82*05767d91SRobert Wu TEST_F(TestLockFreeQueue, PopReturnsOneCorrectValue){
83*05767d91SRobert Wu q.push(123);
84*05767d91SRobert Wu q.pop(result1);
85*05767d91SRobert Wu ASSERT_EQ(result1, 123);
86*05767d91SRobert Wu }
87*05767d91SRobert Wu
TEST_F(TestLockFreeQueue,PopReturnsManyCorrectValues)88*05767d91SRobert Wu TEST_F(TestLockFreeQueue, PopReturnsManyCorrectValues){
89*05767d91SRobert Wu q.push(123);
90*05767d91SRobert Wu q.push(456);
91*05767d91SRobert Wu q.pop(result1);
92*05767d91SRobert Wu q.pop(result2);
93*05767d91SRobert Wu ASSERT_EQ(result1, 123);
94*05767d91SRobert Wu ASSERT_EQ(result2, 456);
95*05767d91SRobert Wu }
96*05767d91SRobert Wu
TEST_F(TestLockFreeQueue,PushWhenFullReturnsFalse)97*05767d91SRobert Wu TEST_F(TestLockFreeQueue, PushWhenFullReturnsFalse){
98*05767d91SRobert Wu q.push(123);
99*05767d91SRobert Wu q.push(123);
100*05767d91SRobert Wu ASSERT_EQ(q.push(123), false);
101*05767d91SRobert Wu }
102*05767d91SRobert Wu
TEST_F(TestLockFreeQueue,PushWhenSpaceAvailableReturnsTrue)103*05767d91SRobert Wu TEST_F(TestLockFreeQueue, PushWhenSpaceAvailableReturnsTrue){
104*05767d91SRobert Wu ASSERT_EQ(q.push(123), true);
105*05767d91SRobert Wu }
106*05767d91SRobert Wu
TEST_F(TestLockFreeQueue,PushHandlesWrapCorrectly)107*05767d91SRobert Wu TEST_F(TestLockFreeQueue, PushHandlesWrapCorrectly){
108*05767d91SRobert Wu q.push(123);
109*05767d91SRobert Wu q.push(234);
110*05767d91SRobert Wu q.pop(result1);
111*05767d91SRobert Wu q.push(999);
112*05767d91SRobert Wu q.pop(result2);
113*05767d91SRobert Wu ASSERT_EQ(result2, 234);
114*05767d91SRobert Wu q.pop(result3);
115*05767d91SRobert Wu ASSERT_EQ(result3, 999);
116*05767d91SRobert Wu }
117*05767d91SRobert Wu
TEST_F(TestLockFreeQueue,PeekWhenEmptyReturnsFalse)118*05767d91SRobert Wu TEST_F(TestLockFreeQueue, PeekWhenEmptyReturnsFalse){
119*05767d91SRobert Wu ASSERT_EQ(q.peek(result1), false);
120*05767d91SRobert Wu }
121*05767d91SRobert Wu
TEST_F(TestLockFreeQueue,PeekWhenNotEmptyReturnsTrue)122*05767d91SRobert Wu TEST_F(TestLockFreeQueue, PeekWhenNotEmptyReturnsTrue){
123*05767d91SRobert Wu q.push(123);
124*05767d91SRobert Wu ASSERT_EQ(q.peek(result1), true);
125*05767d91SRobert Wu }
126*05767d91SRobert Wu
TEST_F(TestLockFreeQueue,PeekReturnsCorrectValueOnce)127*05767d91SRobert Wu TEST_F(TestLockFreeQueue, PeekReturnsCorrectValueOnce){
128*05767d91SRobert Wu q.push(456);
129*05767d91SRobert Wu q.peek(result1);
130*05767d91SRobert Wu ASSERT_EQ(result1, 456);
131*05767d91SRobert Wu }
132*05767d91SRobert Wu
TEST_F(TestLockFreeQueue,PeekReturnsCorrectValueTwice)133*05767d91SRobert Wu TEST_F(TestLockFreeQueue, PeekReturnsCorrectValueTwice){
134*05767d91SRobert Wu q.push(456);
135*05767d91SRobert Wu q.peek(result1);
136*05767d91SRobert Wu q.peek(result2);
137*05767d91SRobert Wu ASSERT_EQ(result2, 456);
138*05767d91SRobert Wu }
139*05767d91SRobert Wu
TEST_F(TestLockFreeQueue,SizeReturnsZeroAfterInit)140*05767d91SRobert Wu TEST_F(TestLockFreeQueue, SizeReturnsZeroAfterInit){
141*05767d91SRobert Wu ASSERT_EQ(q.size(), 0);
142*05767d91SRobert Wu }
143*05767d91SRobert Wu
TEST_F(TestLockFreeQueue,SizeIsOneAfterPushOnce)144*05767d91SRobert Wu TEST_F(TestLockFreeQueue, SizeIsOneAfterPushOnce){
145*05767d91SRobert Wu q.push(321);
146*05767d91SRobert Wu ASSERT_EQ(q.size(), 1);
147*05767d91SRobert Wu }
148*05767d91SRobert Wu
TEST_F(TestLockFreeQueue,SizeIsCorrectAfterPushingMaxItems)149*05767d91SRobert Wu TEST_F(TestLockFreeQueue, SizeIsCorrectAfterPushingMaxItems){
150*05767d91SRobert Wu for (int i = 0; i < kQueueCapacity; ++i) { q.push(i); }
151*05767d91SRobert Wu ASSERT_EQ(q.size(), kQueueCapacity);
152*05767d91SRobert Wu }
153*05767d91SRobert Wu
TEST_F(TestLockFreeQueue,SizeCorrectAfterWriteCounterWraps)154*05767d91SRobert Wu TEST_F(TestLockFreeQueue, SizeCorrectAfterWriteCounterWraps){
155*05767d91SRobert Wu
156*05767d91SRobert Wu const uint32_t kCapacity = (uint32_t) 1 << 7;
157*05767d91SRobert Wu LockFreeQueue<int, kCapacity, uint8_t> myQ;
158*05767d91SRobert Wu
159*05767d91SRobert Wu for (int i = 0; i < UINT8_MAX; ++i) {
160*05767d91SRobert Wu myQ.push(i);
161*05767d91SRobert Wu myQ.pop(result1);
162*05767d91SRobert Wu }
163*05767d91SRobert Wu
164*05767d91SRobert Wu myQ.push(1);
165*05767d91SRobert Wu ASSERT_EQ(myQ.size(), 1);
166*05767d91SRobert Wu }
167*05767d91SRobert Wu
TEST_F(TestLockFreeQueue,MultiThreadedTest)168*05767d91SRobert Wu TEST_F(TestLockFreeQueue, MultiThreadedTest){
169*05767d91SRobert Wu
170*05767d91SRobert Wu // Push and pop from the queue concurrently
171*05767d91SRobert Wu // Check that the queue is empty
172*05767d91SRobert Wu // Check that the order of the read values matches the order of the written values
173*05767d91SRobert Wu
174*05767d91SRobert Wu constexpr int kQueueCapacity = 2048;
175*05767d91SRobert Wu LockFreeQueue<int, kQueueCapacity> myQ;
176*05767d91SRobert Wu std::array<int, kQueueCapacity> sourceData;
177*05767d91SRobert Wu std::array<int, kQueueCapacity> targetData { 0 };
178*05767d91SRobert Wu
179*05767d91SRobert Wu // Populate the source data
180*05767d91SRobert Wu for (int i = 0; i < kQueueCapacity; i++){
181*05767d91SRobert Wu sourceData[i] = i;
182*05767d91SRobert Wu }
183*05767d91SRobert Wu
184*05767d91SRobert Wu std::thread writer([&myQ, &sourceData](){
185*05767d91SRobert Wu for (int i = 0; i < kQueueCapacity; i++){
186*05767d91SRobert Wu myQ.push(sourceData[i]);
187*05767d91SRobert Wu }
188*05767d91SRobert Wu });
189*05767d91SRobert Wu
190*05767d91SRobert Wu std::thread reader([&myQ, &targetData](){
191*05767d91SRobert Wu for (int i = 0; i < kQueueCapacity; i++){
192*05767d91SRobert Wu // pop the latest element, or wait for it to become available
193*05767d91SRobert Wu while (!myQ.pop(targetData[i])){
194*05767d91SRobert Wu std::cout << "Waiting for element at index " << i << " to be written" << std::endl;
195*05767d91SRobert Wu usleep(500);
196*05767d91SRobert Wu }
197*05767d91SRobert Wu }
198*05767d91SRobert Wu });
199*05767d91SRobert Wu
200*05767d91SRobert Wu writer.join();
201*05767d91SRobert Wu reader.join();
202*05767d91SRobert Wu
203*05767d91SRobert Wu int v;
204*05767d91SRobert Wu ASSERT_FALSE(myQ.pop(v));
205*05767d91SRobert Wu
206*05767d91SRobert Wu // Check that the target matches the source
207*05767d91SRobert Wu for (int i = 0; i < kQueueCapacity; i++){
208*05767d91SRobert Wu ASSERT_EQ(sourceData[i], targetData[i]) << "Elements at index " << i << " did not match";
209*05767d91SRobert Wu }
210*05767d91SRobert Wu }
211