1 /*
2 * Copyright (C) 2023 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 <gmock/gmock.h>
18 #include <gtest/gtest.h>
19
20 #include <chrono>
21
22 #include "stats_buffer_writer_queue_impl.h"
23 #include "stats_event.h"
24 #include "utils.h"
25
26 using testing::_;
27 using testing::AnyNumber;
28 using testing::DoAll;
29 using testing::Return;
30 using testing::StrictMock;
31
32 namespace {
33
34 constexpr static int WAIT_MS = 100;
35
generateTestEvent()36 static AStatsEvent* generateTestEvent() {
37 AStatsEvent* event = AStatsEvent_obtain();
38 AStatsEvent_setAtomId(event, 100);
39 AStatsEvent_writeInt32(event, 5);
40 AStatsEvent_write(event);
41 return event;
42 }
43
44 class BasicBufferWriterQueueMock : public BufferWriterQueue {
45 public:
46 BasicBufferWriterQueueMock() = default;
47 MOCK_METHOD(bool, handleCommand, (const BufferWriterQueue::Cmd& cmd), (const override));
48 };
49
50 typedef StrictMock<BasicBufferWriterQueueMock> BufferWriterQueueMock;
51
52 } // namespace
53
TEST(StatsBufferWriterQueueTest,TestWriteSuccess)54 TEST(StatsBufferWriterQueueTest, TestWriteSuccess) {
55 AStatsEvent* event = generateTestEvent();
56
57 size_t eventBufferSize = 0;
58 const uint8_t* buffer = AStatsEvent_getBuffer(event, &eventBufferSize);
59 EXPECT_GE(eventBufferSize, 0);
60 EXPECT_TRUE(buffer != nullptr);
61
62 const uint32_t atomId = AStatsEvent_getAtomId(event);
63
64 BufferWriterQueueMock queue;
65 EXPECT_CALL(queue, handleCommand(_)).WillOnce(Return(true));
66 // simulate failed write to stats socket
67 const bool addedToQueue = queue.write(buffer, eventBufferSize, atomId);
68 AStatsEvent_release(event);
69 EXPECT_TRUE(addedToQueue);
70 // to yeld to the queue worker thread
71 std::this_thread::sleep_for(std::chrono::milliseconds(WAIT_MS));
72
73 queue.drainQueue();
74 EXPECT_EQ(queue.getQueueSize(), 0);
75 }
76
TEST(StatsBufferWriterQueueTest,TestWriteOverflow)77 TEST(StatsBufferWriterQueueTest, TestWriteOverflow) {
78 AStatsEvent* event = generateTestEvent();
79
80 size_t eventBufferSize = 0;
81 const uint8_t* buffer = AStatsEvent_getBuffer(event, &eventBufferSize);
82 EXPECT_GE(eventBufferSize, 0);
83 EXPECT_TRUE(buffer != nullptr);
84
85 const uint32_t atomId = AStatsEvent_getAtomId(event);
86
87 BufferWriterQueueMock queue;
88 EXPECT_CALL(queue, handleCommand(_)).WillRepeatedly(Return(false));
89 // simulate failed write to stats socket
90 for (int i = 0; i < BufferWriterQueueMock::kQueueMaxSizeLimit; i++) {
91 const bool addedToQueue = queue.write(buffer, eventBufferSize, atomId);
92 EXPECT_TRUE(addedToQueue);
93 }
94
95 const bool addedToQueue = queue.write(buffer, eventBufferSize, atomId);
96 AStatsEvent_release(event);
97 EXPECT_FALSE(addedToQueue);
98
99 EXPECT_EQ(queue.getQueueSize(), BufferWriterQueueMock::kQueueMaxSizeLimit);
100
101 queue.drainQueue();
102 EXPECT_EQ(queue.getQueueSize(), 0);
103 }
104
TEST(StatsBufferWriterQueueTest,TestSleepOnOverflow)105 TEST(StatsBufferWriterQueueTest, TestSleepOnOverflow) {
106 AStatsEvent* event = generateTestEvent();
107
108 size_t eventBufferSize = 0;
109 const uint8_t* buffer = AStatsEvent_getBuffer(event, &eventBufferSize);
110 EXPECT_GE(eventBufferSize, 0);
111 EXPECT_TRUE(buffer != nullptr);
112
113 const uint32_t atomId = AStatsEvent_getAtomId(event);
114
115 std::vector<int64_t> attemptsTs;
116
117 BufferWriterQueueMock queue;
118 ON_CALL(queue, handleCommand(_))
119 .WillByDefault(DoAll(
120 [&attemptsTs](const BufferWriterQueue::Cmd&) {
121 // store timestamp for command handler invocations
122 attemptsTs.push_back(get_elapsed_realtime_ns());
123 return false;
124 },
125 Return(false)));
126
127 EXPECT_CALL(queue, handleCommand(_)).Times(AnyNumber());
128
129 // simulate failed write to stats socket to fill the queue
130 for (int i = 0; i < BufferWriterQueueMock::kQueueMaxSizeLimit; i++) {
131 const bool addedToQueue = queue.write(buffer, eventBufferSize, atomId);
132 EXPECT_TRUE(addedToQueue);
133 }
134 AStatsEvent_release(event);
135 // to yeld to the queue worker thread
136 std::this_thread::sleep_for(std::chrono::milliseconds(WAIT_MS));
137
138 // to eliminate extra commands handling on the worker thread
139 queue.drainQueue();
140 EXPECT_EQ(queue.getQueueSize(), 0);
141
142 EXPECT_GE(attemptsTs.size(), 2);
143 for (int i = 0; i < attemptsTs.size() - 1; i++) {
144 EXPECT_GE(attemptsTs[i + 1] - attemptsTs[i],
145 BufferWriterQueueMock::kDelayOnFailedWriteMs * 1000000);
146 }
147 }
148
TEST(StatsBufferWriterQueueTest,TestTerminateNonEmptyQueue)149 TEST(StatsBufferWriterQueueTest, TestTerminateNonEmptyQueue) {
150 AStatsEvent* event = generateTestEvent();
151
152 size_t eventBufferSize = 0;
153 const uint8_t* buffer = AStatsEvent_getBuffer(event, &eventBufferSize);
154 EXPECT_GE(eventBufferSize, 0);
155 EXPECT_TRUE(buffer != nullptr);
156
157 const uint32_t atomId = AStatsEvent_getAtomId(event);
158
159 BufferWriterQueueMock queue;
160 EXPECT_CALL(queue, handleCommand(_)).WillRepeatedly(Return(false));
161 // simulate failed write to stats socket
162 for (int i = 0; i < BufferWriterQueueMock::kQueueMaxSizeLimit; i++) {
163 const bool addedToQueue = queue.write(buffer, eventBufferSize, atomId);
164 EXPECT_TRUE(addedToQueue);
165 }
166 AStatsEvent_release(event);
167 EXPECT_EQ(queue.getQueueSize(), BufferWriterQueueMock::kQueueMaxSizeLimit);
168 queue.drainQueue();
169 EXPECT_EQ(queue.getQueueSize(), 0);
170 }
171