1 /*
2 * Copyright 2021 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 "CarTelemetryImpl.h"
18 #include "CarTelemetryInternalImpl.h"
19 #include "FakeLooperWrapper.h"
20 #include "LooperWrapper.h"
21 #include "RingBuffer.h"
22 #include "TelemetryServer.h"
23
24 #include <aidl/android/automotive/telemetry/internal/BnCarDataListener.h>
25 #include <aidl/android/automotive/telemetry/internal/CarDataInternal.h>
26 #include <aidl/android/automotive/telemetry/internal/ICarTelemetryInternal.h>
27 #include <aidl/android/frameworks/automotive/telemetry/CarData.h>
28 #include <aidl/android/frameworks/automotive/telemetry/ICarTelemetry.h>
29 #include <android-base/chrono_utils.h>
30 #include <android-base/logging.h>
31 #include <gmock/gmock.h>
32 #include <gtest/gtest.h>
33 #include <utils/Timers.h> // for ::systemTime()
34
35 #include <unistd.h>
36
37 #include <memory>
38
39 namespace android {
40 namespace automotive {
41 namespace telemetry {
42
43 using ::aidl::android::automotive::telemetry::internal::BnCarDataListener;
44 using ::aidl::android::automotive::telemetry::internal::CarDataInternal;
45 using ::aidl::android::automotive::telemetry::internal::ICarTelemetryInternal;
46 using ::aidl::android::frameworks::automotive::telemetry::CarData;
47 using ::aidl::android::frameworks::automotive::telemetry::ICarTelemetry;
48 using ::ndk::ScopedAStatus;
49 using ::testing::_;
50 using ::testing::ByMove;
51 using ::testing::Return;
52
53 constexpr const std::chrono::nanoseconds kPushCarDataDelayNs = 1000ms;
54 constexpr const std::chrono::nanoseconds kAllowedErrorNs = 100ms;
55 const int kMaxBufferSize = 3;
56
57 // Because `ScopedAStatus` is move-only, `EXPECT_CALL().WillRepeatedly()` will not work.
ReturnOk()58 inline testing::internal::ReturnAction<testing::internal::ByMoveWrapper<ScopedAStatus>> ReturnOk() {
59 return testing::Return(ByMove(ScopedAStatus::ok()));
60 }
61
62 // Builds incoming CarData from writer clients.
buildCarData(int id,const std::vector<uint8_t> & content)63 CarData buildCarData(int id, const std::vector<uint8_t>& content) {
64 CarData msg;
65 msg.id = id;
66 msg.content = content;
67 return msg;
68 }
69
70 // Builds outgoing CarDataInternal to the CarTelemetryService.
buildCarDataInternal(int id,const std::vector<uint8_t> & content)71 CarDataInternal buildCarDataInternal(int id, const std::vector<uint8_t>& content) {
72 CarDataInternal msg;
73 msg.id = id;
74 msg.content = content;
75 return msg;
76 }
77
78 // Mock listener, behaves as CarTelemetryService.
79 class MockCarDataListener : public BnCarDataListener {
80 public:
81 MOCK_METHOD(ScopedAStatus, onCarDataReceived, (const std::vector<CarDataInternal>& dataList),
82 (override));
83 };
84
85 // The main test class. Tests using `ICarTelemetry` and `ICarTelemetryInternal` interfaces.
86 // Pushing data to the listener is done in the looper - always call `mFakeLooper.poll()`.
87 class TelemetryServerTest : public ::testing::Test {
88 protected:
TelemetryServerTest()89 TelemetryServerTest() :
90 mTelemetryServer(&mFakeLooper, kPushCarDataDelayNs, kMaxBufferSize),
91 mMockCarDataListener(ndk::SharedRefBase::make<MockCarDataListener>()),
92 mTelemetry(ndk::SharedRefBase::make<CarTelemetryImpl>(&mTelemetryServer)),
93 mTelemetryInternal(
94 ndk::SharedRefBase::make<CarTelemetryInternalImpl>(&mTelemetryServer)) {}
95
96 // Creates an expectation. This is a nice helper that accepts a std::vector, original
97 // EXPECT_CALL() requires creating std::vector variable.
98 testing::internal::TypedExpectation<ScopedAStatus(const std::vector<CarDataInternal>&)>&
expectMockListenerToReceive(const std::vector<CarDataInternal> & expected)99 expectMockListenerToReceive(const std::vector<CarDataInternal>& expected) {
100 return EXPECT_CALL(*mMockCarDataListener, onCarDataReceived(expected));
101 }
102
103 FakeLooperWrapper mFakeLooper;
104 TelemetryServer mTelemetryServer;
105 std::shared_ptr<MockCarDataListener> mMockCarDataListener;
106 std::shared_ptr<ICarTelemetry> mTelemetry;
107 std::shared_ptr<ICarTelemetryInternal> mTelemetryInternal;
108 };
109
TEST_F(TelemetryServerTest,WriteReturnsOk)110 TEST_F(TelemetryServerTest, WriteReturnsOk) {
111 std::vector<CarData> dataList = {buildCarData(101, {1})};
112
113 auto status = mTelemetry->write(dataList);
114
115 EXPECT_TRUE(status.isOk()) << status.getMessage();
116 }
117
TEST_F(TelemetryServerTest,SetListenerReturnsOk)118 TEST_F(TelemetryServerTest, SetListenerReturnsOk) {
119 auto status = mTelemetryInternal->setListener(mMockCarDataListener);
120
121 EXPECT_TRUE(status.isOk()) << status.getMessage();
122 }
123
TEST_F(TelemetryServerTest,SetListenerFailsWhenAlreadySubscribed)124 TEST_F(TelemetryServerTest, SetListenerFailsWhenAlreadySubscribed) {
125 mTelemetryInternal->setListener(mMockCarDataListener);
126
127 auto status = mTelemetryInternal->setListener(ndk::SharedRefBase::make<MockCarDataListener>());
128
129 EXPECT_EQ(status.getExceptionCode(), ::EX_ILLEGAL_STATE) << status.getMessage();
130 }
131
TEST_F(TelemetryServerTest,ClearListenerWorks)132 TEST_F(TelemetryServerTest, ClearListenerWorks) {
133 mTelemetryInternal->setListener(mMockCarDataListener);
134
135 mTelemetryInternal->clearListener();
136
137 auto status = mTelemetryInternal->setListener(mMockCarDataListener);
138 EXPECT_TRUE(status.isOk()) << status.getMessage();
139 }
140
TEST_F(TelemetryServerTest,ClearListenerRemovesPushMessagesFromLooper)141 TEST_F(TelemetryServerTest, ClearListenerRemovesPushMessagesFromLooper) {
142 std::vector<CarData> dataList = {buildCarData(101, {1})};
143 mTelemetry->write(dataList);
144 mTelemetryInternal->setListener(mMockCarDataListener);
145 EXPECT_NE(mFakeLooper.getNextMessageUptime(), FakeLooperWrapper::kNoScheduledMessage);
146
147 mTelemetryInternal->clearListener();
148
149 EXPECT_EQ(mFakeLooper.getNextMessageUptime(), FakeLooperWrapper::kNoScheduledMessage);
150 }
151
TEST_F(TelemetryServerTest,WriteSchedulesNextMessageAfterRightDelay)152 TEST_F(TelemetryServerTest, WriteSchedulesNextMessageAfterRightDelay) {
153 std::vector<CarData> dataList = {buildCarData(101, {1})};
154 mTelemetryInternal->setListener(mMockCarDataListener);
155
156 mTelemetry->write(dataList);
157
158 EXPECT_NEAR(mFakeLooper.getNextMessageUptime(), ::systemTime() + kPushCarDataDelayNs.count(),
159 kAllowedErrorNs.count());
160 }
161
TEST_F(TelemetryServerTest,SetListenerSchedulesNextMessageAfterRightDelay)162 TEST_F(TelemetryServerTest, SetListenerSchedulesNextMessageAfterRightDelay) {
163 std::vector<CarData> dataList = {buildCarData(101, {1})};
164 mTelemetry->write(dataList);
165
166 mTelemetryInternal->setListener(mMockCarDataListener);
167
168 EXPECT_NEAR(mFakeLooper.getNextMessageUptime(), ::systemTime() + kPushCarDataDelayNs.count(),
169 kAllowedErrorNs.count());
170 }
171
TEST_F(TelemetryServerTest,BuffersOnlyLimitedData)172 TEST_F(TelemetryServerTest, BuffersOnlyLimitedData) {
173 mTelemetryInternal->setListener(mMockCarDataListener);
174 std::vector<CarData> dataList1 = {buildCarData(10, {1, 2}), buildCarData(11, {2, 3})};
175 std::vector<CarData> dataList2 = {buildCarData(101, {1, 2}), buildCarData(102, {2, 3}),
176 buildCarData(103, {3, 4}), buildCarData(104, {4, 5})};
177
178 mTelemetry->write(dataList1);
179 mTelemetry->write(dataList2);
180
181 // Only the last 3 CarData should be received, because kMaxBufferSize = 3.
182 expectMockListenerToReceive({buildCarDataInternal(102, {2, 3})}).WillOnce(ReturnOk());
183 expectMockListenerToReceive({buildCarDataInternal(103, {3, 4})}).WillOnce(ReturnOk());
184 expectMockListenerToReceive({buildCarDataInternal(104, {4, 5})}).WillOnce(ReturnOk());
185
186 mFakeLooper.poll();
187 mFakeLooper.poll();
188 mFakeLooper.poll();
189 mFakeLooper.poll();
190 }
191
192 // First sets the listener, then writes CarData.
TEST_F(TelemetryServerTest,WhenListenerIsAlreadyItPushesData)193 TEST_F(TelemetryServerTest, WhenListenerIsAlreadyItPushesData) {
194 std::vector<CarData> dataList = {buildCarData(101, {1})};
195
196 mTelemetryInternal->setListener(mMockCarDataListener);
197 mTelemetry->write(dataList);
198
199 expectMockListenerToReceive({buildCarDataInternal(101, {1})}).Times(1).WillOnce(ReturnOk());
200
201 mFakeLooper.poll();
202 }
203
204 // First writes CarData, only then sets the listener.
TEST_F(TelemetryServerTest,WhenListenerIsSetLaterItPushesData)205 TEST_F(TelemetryServerTest, WhenListenerIsSetLaterItPushesData) {
206 std::vector<CarData> dataList = {buildCarData(101, {1})};
207
208 mTelemetry->write(dataList);
209 mTelemetryInternal->setListener(mMockCarDataListener);
210
211 expectMockListenerToReceive({buildCarDataInternal(101, {1})}).Times(1).WillOnce(ReturnOk());
212
213 mFakeLooper.poll();
214 }
215
TEST_F(TelemetryServerTest,WriteDuringPushingDataToListener)216 TEST_F(TelemetryServerTest, WriteDuringPushingDataToListener) {
217 std::vector<CarData> dataList = {buildCarData(101, {1}), buildCarData(102, {1})};
218 std::vector<CarData> dataList2 = {buildCarData(103, {1})};
219 mTelemetryInternal->setListener(mMockCarDataListener);
220 mTelemetry->write(dataList);
221
222 expectMockListenerToReceive({buildCarDataInternal(101, {1})}).WillOnce(ReturnOk());
223 expectMockListenerToReceive({buildCarDataInternal(102, {1})}).WillOnce(ReturnOk());
224 expectMockListenerToReceive({buildCarDataInternal(103, {1})}).WillOnce(ReturnOk());
225
226 mFakeLooper.poll(); // sends only 1 CarData (or possibly 2 depenending on impl)
227 mTelemetry->write(dataList2);
228 mFakeLooper.poll(); // all the polls below send the rest of the CarData
229 mFakeLooper.poll();
230 mFakeLooper.poll(); // extra poll to verify there was not excess push calls
231 }
232
TEST_F(TelemetryServerTest,ClearListenerDuringPushingDataToListener)233 TEST_F(TelemetryServerTest, ClearListenerDuringPushingDataToListener) {
234 std::vector<CarData> dataList = {buildCarData(101, {1})};
235 mTelemetryInternal->setListener(mMockCarDataListener);
236 mTelemetry->write(dataList);
237
238 expectMockListenerToReceive({buildCarDataInternal(101, {1})}).Times(1).WillOnce(ReturnOk());
239
240 mFakeLooper.poll();
241 mTelemetry->write(dataList);
242 mTelemetryInternal->clearListener();
243 mFakeLooper.poll();
244 }
245
TEST_F(TelemetryServerTest,RetriesPushAgainIfListenerFails)246 TEST_F(TelemetryServerTest, RetriesPushAgainIfListenerFails) {
247 std::vector<CarData> dataList = {buildCarData(101, {1})};
248 mTelemetryInternal->setListener(mMockCarDataListener);
249 mTelemetry->write(dataList);
250
251 expectMockListenerToReceive({buildCarDataInternal(101, {1})})
252 .WillOnce(Return(ByMove(ScopedAStatus::fromExceptionCode(::EX_TRANSACTION_FAILED))))
253 .WillOnce(ReturnOk());
254
255 mFakeLooper.poll(); // listener returns ::EX_TRANSACTION_FAILED
256 mFakeLooper.poll();
257 }
258
259 // Tests a corner case to make sure `TelemetryServer::mPendingCarDataInternals` variable
260 // is handled properly when transaction fails and clearListener() is called.
TEST_F(TelemetryServerTest,ClearListenerDuringPushingDataAndSetListenerAgain)261 TEST_F(TelemetryServerTest, ClearListenerDuringPushingDataAndSetListenerAgain) {
262 std::vector<CarData> dataList = {buildCarData(101, {1})};
263 mTelemetryInternal->setListener(mMockCarDataListener);
264 mTelemetry->write(dataList);
265
266 expectMockListenerToReceive({buildCarDataInternal(101, {1})})
267 .WillOnce(Return(ByMove(ScopedAStatus::fromExceptionCode(::EX_TRANSACTION_FAILED))))
268 .WillOnce(ReturnOk());
269
270 mFakeLooper.poll(); // listener returns ::EX_TRANSACTION_FAILED
271 mTelemetryInternal->clearListener();
272 mFakeLooper.poll(); // nothing happens
273 mTelemetryInternal->setListener(mMockCarDataListener);
274 mFakeLooper.poll(); // should work
275 }
276
277 // Directly calls pushCarDataToListeners() to make sure it can handle edge-cases.
TEST_F(TelemetryServerTest,NoListenerButMultiplePushes)278 TEST_F(TelemetryServerTest, NoListenerButMultiplePushes) {
279 std::vector<CarData> dataList = {buildCarData(101, {1})};
280 mTelemetry->write(dataList);
281
282 mTelemetryServer.pushCarDataToListeners();
283 mTelemetryServer.pushCarDataToListeners();
284 mTelemetryServer.pushCarDataToListeners();
285
286 EXPECT_CALL(*mMockCarDataListener, onCarDataReceived(_)).Times(0);
287 }
288
289 // Directly calls pushCarDataToListeners() to make sure it can handle edge-cases.
TEST_F(TelemetryServerTest,NoDataButMultiplePushes)290 TEST_F(TelemetryServerTest, NoDataButMultiplePushes) {
291 mTelemetryInternal->setListener(mMockCarDataListener);
292
293 mTelemetryServer.pushCarDataToListeners();
294 mTelemetryServer.pushCarDataToListeners();
295 mTelemetryServer.pushCarDataToListeners();
296
297 EXPECT_CALL(*mMockCarDataListener, onCarDataReceived(_)).Times(0);
298 }
299
300 } // namespace telemetry
301 } // namespace automotive
302 } // namespace android
303