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/BnCarTelemetryCallback.h>
28 #include <aidl/android/frameworks/automotive/telemetry/CallbackConfig.h>
29 #include <aidl/android/frameworks/automotive/telemetry/CarData.h>
30 #include <aidl/android/frameworks/automotive/telemetry/ICarTelemetry.h>
31 #include <android-base/chrono_utils.h>
32 #include <android-base/logging.h>
33 #include <gmock/gmock.h>
34 #include <gtest/gtest.h>
35 #include <utils/Timers.h> // for ::systemTime()
36
37 #include <unistd.h>
38
39 #include <cstdint>
40 #include <memory>
41 #include <unordered_set>
42
43 namespace android {
44 namespace automotive {
45 namespace telemetry {
46
47 using ::aidl::android::automotive::telemetry::internal::BnCarDataListener;
48 using ::aidl::android::automotive::telemetry::internal::CarDataInternal;
49 using ::aidl::android::automotive::telemetry::internal::ICarTelemetryInternal;
50 using ::aidl::android::frameworks::automotive::telemetry::BnCarTelemetryCallback;
51 using ::aidl::android::frameworks::automotive::telemetry::CallbackConfig;
52 using ::aidl::android::frameworks::automotive::telemetry::CarData;
53 using ::aidl::android::frameworks::automotive::telemetry::ICarTelemetry;
54 using ::ndk::ScopedAStatus;
55 using ::testing::_;
56 using ::testing::ByMove;
57 using ::testing::Return;
58 using ::testing::UnorderedElementsAre;
59
60 constexpr const std::chrono::nanoseconds kPushCarDataDelayNs = 1000ms;
61 constexpr const std::chrono::nanoseconds kAllowedErrorNs = 100ms;
62 const int kMaxBufferSize = 3;
63
64 // Because `ScopedAStatus` is move-only, `EXPECT_CALL().WillRepeatedly()` will not work.
ReturnOk()65 inline testing::internal::ReturnAction<testing::internal::ByMoveWrapper<ScopedAStatus>> ReturnOk() {
66 return testing::Return(ByMove(ScopedAStatus::ok()));
67 }
68
69 // Builds CallbackConfig from clients.
buildConfig(const std::vector<int32_t> & ids)70 CallbackConfig buildConfig(const std::vector<int32_t>& ids) {
71 CallbackConfig config;
72 config.carDataIds = ids;
73 return config;
74 }
75
76 // Builds incoming CarData from writer clients.
buildCarData(int id,const std::vector<uint8_t> & content)77 CarData buildCarData(int id, const std::vector<uint8_t>& content) {
78 CarData msg;
79 msg.id = id;
80 msg.content = content;
81 return msg;
82 }
83
84 // Builds outgoing CarDataInternal to the CarTelemetryService.
buildCarDataInternal(int id,const std::vector<uint8_t> & content)85 CarDataInternal buildCarDataInternal(int id, const std::vector<uint8_t>& content) {
86 CarDataInternal msg;
87 msg.id = id;
88 msg.content = content;
89 return msg;
90 }
91
92 // Mock ICarDataListener, behaves as CarTelemetryService.
93 class MockCarDataListener : public BnCarDataListener {
94 public:
95 MOCK_METHOD(ScopedAStatus, onCarDataReceived, (const std::vector<CarDataInternal>& dataList),
96 (override));
97 };
98
99 // Mock ICarTelemetryCallback, behaves as client application.
100 class MockCarTelemetryCallback : public BnCarTelemetryCallback {
101 public:
102 MOCK_METHOD(ScopedAStatus, onChange, (const std::vector<int32_t>& ids), (override));
103 };
104
105 // The main test class. Tests using `ICarTelemetry` and `ICarTelemetryInternal` interfaces.
106 // Pushing data to the listener is done in the looper - always call `mFakeLooper.poll()`.
107 class TelemetryServerTest : public ::testing::Test {
108 protected:
TelemetryServerTest()109 TelemetryServerTest() :
110 mTelemetryServer(&mFakeLooper, kPushCarDataDelayNs, kMaxBufferSize),
111 mDefaultConfig(buildConfig({101})),
112 mMockCarDataListener(ndk::SharedRefBase::make<MockCarDataListener>()),
113 mMockCarTelemetryCallback(ndk::SharedRefBase::make<MockCarTelemetryCallback>()),
114 mTelemetry(ndk::SharedRefBase::make<CarTelemetryImpl>(&mTelemetryServer)),
115 mTelemetryInternal(
116 ndk::SharedRefBase::make<CarTelemetryInternalImpl>(&mTelemetryServer)) {}
117
118 // Creates an expectation. This is a nice helper that accepts a std::vector, original
119 // EXPECT_CALL() requires creating std::vector variable.
120 testing::internal::TypedExpectation<ScopedAStatus(const std::vector<CarDataInternal>&)>&
expectMockListenerToReceive(const std::vector<CarDataInternal> & expected)121 expectMockListenerToReceive(const std::vector<CarDataInternal>& expected) {
122 return EXPECT_CALL(*mMockCarDataListener, onCarDataReceived(expected));
123 }
124
TearDown()125 void TearDown() override {
126 mTelemetryServer.mCarDataIds.clear();
127 mTelemetryServer.mCallbacks.clear();
128 mTelemetryServer.mIdToCallbacksMap.clear();
129 }
130
131 FakeLooperWrapper mFakeLooper;
132 TelemetryServer mTelemetryServer;
133 CallbackConfig mDefaultConfig;
134 std::shared_ptr<MockCarDataListener> mMockCarDataListener;
135 std::shared_ptr<MockCarTelemetryCallback> mMockCarTelemetryCallback;
136 std::shared_ptr<ICarTelemetry> mTelemetry;
137 std::shared_ptr<ICarTelemetryInternal> mTelemetryInternal;
138 };
139
TEST_F(TelemetryServerTest,WriteReturnsOk)140 TEST_F(TelemetryServerTest, WriteReturnsOk) {
141 std::vector<CarData> dataList = {buildCarData(101, {1})};
142
143 auto status = mTelemetry->write(dataList);
144
145 EXPECT_TRUE(status.isOk()) << status.getMessage();
146 }
147
TEST_F(TelemetryServerTest,AddCarDataIdsReturnsOk)148 TEST_F(TelemetryServerTest, AddCarDataIdsReturnsOk) {
149 auto status = mTelemetryInternal->addCarDataIds({101});
150
151 EXPECT_TRUE(status.isOk()) << status.getMessage();
152 }
153
TEST_F(TelemetryServerTest,AddCarDataIdsNotifiesInterestedCallbacks)154 TEST_F(TelemetryServerTest, AddCarDataIdsNotifiesInterestedCallbacks) {
155 CallbackConfig config = buildConfig({101, 102});
156 std::shared_ptr<MockCarTelemetryCallback> mockCallback =
157 ndk::SharedRefBase::make<MockCarTelemetryCallback>();
158 mTelemetry->addCallback(config, mockCallback);
159 // mDefaultConfig only contains ID 101
160 mTelemetry->addCallback(mDefaultConfig, mMockCarTelemetryCallback);
161
162 EXPECT_CALL(*mMockCarTelemetryCallback, onChange(UnorderedElementsAre(101)))
163 .Times(1)
164 .WillOnce(ReturnOk());
165 EXPECT_CALL(*mockCallback, onChange(UnorderedElementsAre(101, 102)))
166 .Times(1)
167 .WillOnce(ReturnOk());
168
169 mTelemetryInternal->addCarDataIds({101, 102, 103, 104});
170 }
171
TEST_F(TelemetryServerTest,RemoveCarDataIdsReturnsOk)172 TEST_F(TelemetryServerTest, RemoveCarDataIdsReturnsOk) {
173 mTelemetryInternal->addCarDataIds({101, 102, 103});
174 EXPECT_EQ(3, mTelemetryServer.mCarDataIds.size());
175
176 auto status = mTelemetryInternal->removeCarDataIds({101, 103});
177
178 EXPECT_TRUE(status.isOk()) << status.getMessage();
179 EXPECT_EQ(1, mTelemetryServer.mCarDataIds.size());
180 EXPECT_NE(mTelemetryServer.mCarDataIds.end(), mTelemetryServer.mCarDataIds.find(102));
181 }
182
TEST_F(TelemetryServerTest,RemoveCarDataIdsNotifiesInterestedCallbacks)183 TEST_F(TelemetryServerTest, RemoveCarDataIdsNotifiesInterestedCallbacks) {
184 // should only receive updates on IDs 101, 102, 103
185 CallbackConfig config = buildConfig({101, 102, 103});
186 mTelemetry->addCallback(config, mMockCarTelemetryCallback);
187
188 EXPECT_CALL(*mMockCarTelemetryCallback, onChange(UnorderedElementsAre(101, 102, 103)))
189 .Times(1)
190 .WillOnce(ReturnOk());
191 EXPECT_CALL(*mMockCarTelemetryCallback, onChange(UnorderedElementsAre(101, 102)))
192 .Times(1)
193 .WillOnce(ReturnOk());
194
195 mTelemetryInternal->addCarDataIds({101, 102, 103, 104});
196 mTelemetryInternal->removeCarDataIds({103, 104});
197 }
198
TEST_F(TelemetryServerTest,SetListenerReturnsOk)199 TEST_F(TelemetryServerTest, SetListenerReturnsOk) {
200 auto status = mTelemetryInternal->setListener(mMockCarDataListener);
201
202 EXPECT_TRUE(status.isOk()) << status.getMessage();
203 }
204
TEST_F(TelemetryServerTest,SetListenerAllowedWhenAlreadySubscribed)205 TEST_F(TelemetryServerTest, SetListenerAllowedWhenAlreadySubscribed) {
206 mTelemetryInternal->setListener(mMockCarDataListener);
207
208 auto status = mTelemetryInternal->setListener(ndk::SharedRefBase::make<MockCarDataListener>());
209
210 EXPECT_TRUE(status.isOk()) << status.getMessage();
211 }
212
TEST_F(TelemetryServerTest,ClearListenerWorks)213 TEST_F(TelemetryServerTest, ClearListenerWorks) {
214 mTelemetryInternal->setListener(mMockCarDataListener);
215
216 mTelemetryInternal->clearListener();
217
218 auto status = mTelemetryInternal->setListener(mMockCarDataListener);
219 EXPECT_TRUE(status.isOk()) << status.getMessage();
220 }
221
TEST_F(TelemetryServerTest,ClearListenerRemovesPushMessagesFromLooper)222 TEST_F(TelemetryServerTest, ClearListenerRemovesPushMessagesFromLooper) {
223 std::vector<CarData> dataList = {buildCarData(101, {1})};
224 mTelemetry->write(dataList);
225 mTelemetryInternal->setListener(mMockCarDataListener);
226 EXPECT_NE(mFakeLooper.getNextMessageUptime(), FakeLooperWrapper::kNoScheduledMessage);
227
228 mTelemetryInternal->clearListener();
229
230 EXPECT_EQ(mFakeLooper.getNextMessageUptime(), FakeLooperWrapper::kNoScheduledMessage);
231 }
232
TEST_F(TelemetryServerTest,AddCallbackReturnsOk)233 TEST_F(TelemetryServerTest, AddCallbackReturnsOk) {
234 auto status = mTelemetry->addCallback(mDefaultConfig, mMockCarTelemetryCallback);
235
236 EXPECT_TRUE(status.isOk()) << status.getMessage();
237 }
238
TEST_F(TelemetryServerTest,AddCallbackReturnsErrorForExistingCallback)239 TEST_F(TelemetryServerTest, AddCallbackReturnsErrorForExistingCallback) {
240 mTelemetry->addCallback(mDefaultConfig, mMockCarTelemetryCallback);
241
242 auto status = mTelemetry->addCallback(mDefaultConfig, mMockCarTelemetryCallback);
243
244 EXPECT_FALSE(status.isOk()) << status.getMessage();
245 }
246
TEST_F(TelemetryServerTest,AddCallbackReceivesCarDataIds)247 TEST_F(TelemetryServerTest, AddCallbackReceivesCarDataIds) {
248 CallbackConfig config = buildConfig({101, 102, 103});
249 mTelemetryInternal->addCarDataIds({101, 102, 103, 104});
250
251 EXPECT_CALL(*mMockCarTelemetryCallback, onChange(UnorderedElementsAre(101, 102, 103)))
252 .Times(1)
253 .WillOnce(ReturnOk());
254
255 auto status = mTelemetry->addCallback(config, mMockCarTelemetryCallback);
256 }
257
TEST_F(TelemetryServerTest,RemoveCallbackReturnsOk)258 TEST_F(TelemetryServerTest, RemoveCallbackReturnsOk) {
259 mTelemetry->addCallback(mDefaultConfig, mMockCarTelemetryCallback);
260
261 auto status = mTelemetry->removeCallback(mMockCarTelemetryCallback);
262
263 EXPECT_TRUE(status.isOk()) << status.getMessage();
264 EXPECT_EQ(0, mTelemetryServer.mCallbacks.size());
265 EXPECT_EQ(0, mTelemetryServer.mIdToCallbacksMap.size());
266 }
267
TEST_F(TelemetryServerTest,RemoveCallbackReturnsErrorForNonexistentCallback)268 TEST_F(TelemetryServerTest, RemoveCallbackReturnsErrorForNonexistentCallback) {
269 auto status = mTelemetry->removeCallback(mMockCarTelemetryCallback);
270
271 EXPECT_FALSE(status.isOk()) << status.getMessage();
272 }
273
TEST_F(TelemetryServerTest,WriteSchedulesNextMessageAfterRightDelay)274 TEST_F(TelemetryServerTest, WriteSchedulesNextMessageAfterRightDelay) {
275 std::vector<CarData> dataList = {buildCarData(101, {1})};
276 mTelemetryInternal->setListener(mMockCarDataListener);
277
278 mTelemetry->write(dataList);
279
280 EXPECT_NEAR(mFakeLooper.getNextMessageUptime(), ::systemTime() + kPushCarDataDelayNs.count(),
281 kAllowedErrorNs.count());
282 }
283
TEST_F(TelemetryServerTest,SetListenerSchedulesNextMessageAfterRightDelay)284 TEST_F(TelemetryServerTest, SetListenerSchedulesNextMessageAfterRightDelay) {
285 std::vector<CarData> dataList = {buildCarData(101, {1})};
286 mTelemetry->write(dataList);
287
288 mTelemetryInternal->setListener(mMockCarDataListener);
289
290 EXPECT_NEAR(mFakeLooper.getNextMessageUptime(), ::systemTime() + kPushCarDataDelayNs.count(),
291 kAllowedErrorNs.count());
292 }
293
TEST_F(TelemetryServerTest,BuffersOnlyLimitedData)294 TEST_F(TelemetryServerTest, BuffersOnlyLimitedData) {
295 mTelemetryInternal->setListener(mMockCarDataListener);
296 std::vector<CarData> dataList1 = {buildCarData(10, {1, 2}), buildCarData(11, {2, 3})};
297 std::vector<CarData> dataList2 = {buildCarData(101, {1, 2}), buildCarData(102, {2, 3}),
298 buildCarData(103, {3, 4}), buildCarData(104, {4, 5})};
299 mTelemetryInternal->addCarDataIds({10, 11, 101, 102, 103, 104});
300
301 mTelemetry->write(dataList1);
302 mTelemetry->write(dataList2);
303
304 // Only the last 3 CarData should be received, because kMaxBufferSize = 3.
305 expectMockListenerToReceive({buildCarDataInternal(102, {2, 3})}).WillOnce(ReturnOk());
306 expectMockListenerToReceive({buildCarDataInternal(103, {3, 4})}).WillOnce(ReturnOk());
307 expectMockListenerToReceive({buildCarDataInternal(104, {4, 5})}).WillOnce(ReturnOk());
308
309 mFakeLooper.poll();
310 mFakeLooper.poll();
311 mFakeLooper.poll();
312 mFakeLooper.poll();
313 }
314
315 // Data is filtered out when mTelemetryInternal->addCarDataIds() is not called
TEST_F(TelemetryServerTest,WriteFiltersDataBasedOnId)316 TEST_F(TelemetryServerTest, WriteFiltersDataBasedOnId) {
317 std::vector<CarData> dataList = {buildCarData(101, {1})};
318 mTelemetryInternal->setListener(mMockCarDataListener);
319
320 mTelemetry->write(dataList);
321
322 expectMockListenerToReceive({buildCarDataInternal(101, {1})}).Times(0);
323
324 mFakeLooper.poll();
325 }
326
327 // First sets the listener, then writes CarData.
TEST_F(TelemetryServerTest,WhenListenerIsAlreadySetItPushesData)328 TEST_F(TelemetryServerTest, WhenListenerIsAlreadySetItPushesData) {
329 std::vector<CarData> dataList = {buildCarData(101, {1})};
330 mTelemetryInternal->addCarDataIds({101});
331
332 mTelemetryInternal->setListener(mMockCarDataListener);
333 mTelemetry->write(dataList);
334
335 expectMockListenerToReceive({buildCarDataInternal(101, {1})}).Times(1).WillOnce(ReturnOk());
336
337 mFakeLooper.poll();
338 }
339
340 // First writes CarData, only then sets the listener.
TEST_F(TelemetryServerTest,WhenListenerIsSetLaterItPushesData)341 TEST_F(TelemetryServerTest, WhenListenerIsSetLaterItPushesData) {
342 std::vector<CarData> dataList = {buildCarData(101, {1})};
343 mTelemetryInternal->addCarDataIds({101});
344
345 mTelemetry->write(dataList);
346 mTelemetryInternal->setListener(mMockCarDataListener);
347
348 expectMockListenerToReceive({buildCarDataInternal(101, {1})}).Times(1).WillOnce(ReturnOk());
349
350 mFakeLooper.poll();
351 }
352
TEST_F(TelemetryServerTest,WriteDuringPushingDataToListener)353 TEST_F(TelemetryServerTest, WriteDuringPushingDataToListener) {
354 mTelemetryInternal->addCarDataIds({101, 102, 103});
355 std::vector<CarData> dataList = {buildCarData(101, {1}), buildCarData(102, {1})};
356 std::vector<CarData> dataList2 = {buildCarData(103, {1})};
357 mTelemetryInternal->setListener(mMockCarDataListener);
358 mTelemetry->write(dataList);
359
360 expectMockListenerToReceive({buildCarDataInternal(101, {1})}).WillOnce(ReturnOk());
361 expectMockListenerToReceive({buildCarDataInternal(102, {1})}).WillOnce(ReturnOk());
362 expectMockListenerToReceive({buildCarDataInternal(103, {1})}).WillOnce(ReturnOk());
363
364 mFakeLooper.poll(); // sends only 1 CarData (or possibly 2 depenending on impl)
365 mTelemetry->write(dataList2);
366 mFakeLooper.poll(); // all the polls below send the rest of the CarData
367 mFakeLooper.poll();
368 mFakeLooper.poll(); // extra poll to verify there was not excess push calls
369 }
370
TEST_F(TelemetryServerTest,ClearListenerDuringPushingDataToListener)371 TEST_F(TelemetryServerTest, ClearListenerDuringPushingDataToListener) {
372 std::vector<CarData> dataList = {buildCarData(101, {1})};
373 mTelemetryInternal->addCarDataIds({101});
374 mTelemetryInternal->setListener(mMockCarDataListener);
375 mTelemetry->write(dataList);
376
377 expectMockListenerToReceive({buildCarDataInternal(101, {1})}).Times(1).WillOnce(ReturnOk());
378
379 mFakeLooper.poll();
380 mTelemetry->write(dataList);
381 mTelemetryInternal->clearListener();
382 mFakeLooper.poll();
383 }
384
TEST_F(TelemetryServerTest,RetriesPushAgainIfListenerFails)385 TEST_F(TelemetryServerTest, RetriesPushAgainIfListenerFails) {
386 std::vector<CarData> dataList = {buildCarData(101, {1})};
387 mTelemetryInternal->addCarDataIds({101});
388 mTelemetryInternal->setListener(mMockCarDataListener);
389 mTelemetry->write(dataList);
390
391 expectMockListenerToReceive({buildCarDataInternal(101, {1})})
392 .WillOnce(Return(ByMove(ScopedAStatus::fromExceptionCode(::EX_TRANSACTION_FAILED))))
393 .WillOnce(ReturnOk());
394
395 mFakeLooper.poll(); // listener returns ::EX_TRANSACTION_FAILED
396 mFakeLooper.poll();
397 }
398
399 // Tests a corner case to make sure `TelemetryServer::mPendingCarDataInternals` variable
400 // is handled properly when transaction fails and clearListener() is called.
TEST_F(TelemetryServerTest,ClearListenerDuringPushingDataAndSetListenerAgain)401 TEST_F(TelemetryServerTest, ClearListenerDuringPushingDataAndSetListenerAgain) {
402 std::vector<CarData> dataList = {buildCarData(101, {1})};
403 mTelemetryInternal->addCarDataIds({101});
404 mTelemetryInternal->setListener(mMockCarDataListener);
405 mTelemetry->write(dataList);
406
407 expectMockListenerToReceive({buildCarDataInternal(101, {1})})
408 .WillOnce(Return(ByMove(ScopedAStatus::fromExceptionCode(::EX_TRANSACTION_FAILED))))
409 .WillOnce(ReturnOk());
410
411 mFakeLooper.poll(); // listener returns ::EX_TRANSACTION_FAILED
412 mTelemetryInternal->clearListener();
413 mFakeLooper.poll(); // nothing happens
414 mTelemetryInternal->setListener(mMockCarDataListener);
415 mFakeLooper.poll(); // should work
416 }
417
418 // Directly calls pushCarDataToListeners() to make sure it can handle edge-cases.
TEST_F(TelemetryServerTest,NoListenerButMultiplePushes)419 TEST_F(TelemetryServerTest, NoListenerButMultiplePushes) {
420 std::vector<CarData> dataList = {buildCarData(101, {1})};
421 mTelemetryInternal->addCarDataIds({101});
422 mTelemetry->write(dataList);
423
424 mTelemetryServer.pushCarDataToListeners();
425 mTelemetryServer.pushCarDataToListeners();
426 mTelemetryServer.pushCarDataToListeners();
427
428 EXPECT_CALL(*mMockCarDataListener, onCarDataReceived(_)).Times(0);
429 }
430
431 // Directly calls pushCarDataToListeners() to make sure it can handle edge-cases.
TEST_F(TelemetryServerTest,NoDataButMultiplePushes)432 TEST_F(TelemetryServerTest, NoDataButMultiplePushes) {
433 mTelemetryInternal->setListener(mMockCarDataListener);
434
435 mTelemetryServer.pushCarDataToListeners();
436 mTelemetryServer.pushCarDataToListeners();
437 mTelemetryServer.pushCarDataToListeners();
438
439 EXPECT_CALL(*mMockCarDataListener, onCarDataReceived(_)).Times(0);
440 }
441
442 } // namespace telemetry
443 } // namespace automotive
444 } // namespace android
445