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