1 /*
2 * Copyright (C) 2022 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 "RemoteAccessService.h"
18
19 #include <AidlHalPropValue.h>
20 #include <IVhalClient.h>
21 #include <aidl/android/hardware/automotive/remoteaccess/ApState.h>
22 #include <aidl/android/hardware/automotive/remoteaccess/BnRemoteTaskCallback.h>
23 #include <aidl/android/hardware/automotive/vehicle/VehiclePropValue.h>
24 #include <android/binder_status.h>
25 #include <gmock/gmock.h>
26 #include <grpcpp/test/mock_stream.h>
27 #include <gtest/gtest.h>
28 #include <wakeup_client.grpc.pb.h>
29 #include <chrono>
30 #include <thread>
31
32 namespace android {
33 namespace hardware {
34 namespace automotive {
35 namespace remoteaccess {
36
37 namespace {
38
39 using ::android::base::ScopedLockAssertion;
40 using ::android::frameworks::automotive::vhal::AidlHalPropValue;
41 using ::android::frameworks::automotive::vhal::IHalPropConfig;
42 using ::android::frameworks::automotive::vhal::IHalPropValue;
43 using ::android::frameworks::automotive::vhal::ISubscriptionCallback;
44 using ::android::frameworks::automotive::vhal::ISubscriptionClient;
45 using ::android::frameworks::automotive::vhal::IVhalClient;
46 using ::android::frameworks::automotive::vhal::VhalClientResult;
47
48 using ::aidl::android::hardware::automotive::remoteaccess::ApState;
49 using ::aidl::android::hardware::automotive::remoteaccess::BnRemoteTaskCallback;
50 using ::aidl::android::hardware::automotive::remoteaccess::ScheduleInfo;
51 using ::aidl::android::hardware::automotive::remoteaccess::TaskType;
52 using ::aidl::android::hardware::automotive::vehicle::VehiclePropValue;
53
54 using ::grpc::ClientAsyncReaderInterface;
55 using ::grpc::ClientAsyncResponseReaderInterface;
56 using ::grpc::ClientContext;
57 using ::grpc::ClientReader;
58 using ::grpc::ClientReaderInterface;
59 using ::grpc::CompletionQueue;
60 using ::grpc::Status;
61 using ::grpc::testing::MockClientReader;
62 using ::ndk::ScopedAStatus;
63 using ::testing::_;
64 using ::testing::DoAll;
65 using ::testing::ElementsAre;
66 using ::testing::Return;
67 using ::testing::SetArgPointee;
68
69 constexpr char kTestVin[] = "test_VIN";
70 const std::string kTestClientId = "test client id";
71 const std::string kTestScheduleId = "test schedule id";
72 const std::vector<uint8_t> kTestData = {0xde, 0xad, 0xbe, 0xef};
73 constexpr int32_t kTestCount = 1234;
74 constexpr int64_t kTestStartTimeInEpochSeconds = 2345;
75 constexpr int64_t kTestPeriodicInSeconds = 123;
76
77 } // namespace
78
79 class MockGrpcClientStub : public WakeupClient::StubInterface {
80 public:
81 MOCK_METHOD(ClientReaderInterface<GetRemoteTasksResponse>*, GetRemoteTasksRaw,
82 (ClientContext * context, const GetRemoteTasksRequest& request));
83 MOCK_METHOD(Status, NotifyWakeupRequired,
84 (ClientContext * context, const NotifyWakeupRequiredRequest& request,
85 NotifyWakeupRequiredResponse* response));
86 MOCK_METHOD(Status, ScheduleTask,
87 (ClientContext * context, const ScheduleTaskRequest& request,
88 ScheduleTaskResponse* response));
89 MOCK_METHOD(Status, UnscheduleTask,
90 (ClientContext * context, const UnscheduleTaskRequest& request,
91 UnscheduleTaskResponse* response));
92 MOCK_METHOD(Status, UnscheduleAllTasks,
93 (ClientContext * context, const UnscheduleAllTasksRequest& request,
94 UnscheduleAllTasksResponse* response));
95 MOCK_METHOD(Status, IsTaskScheduled,
96 (ClientContext * context, const IsTaskScheduledRequest& request,
97 IsTaskScheduledResponse* response));
98 MOCK_METHOD(Status, GetAllPendingScheduledTasks,
99 (ClientContext * context, const GetAllPendingScheduledTasksRequest& request,
100 GetAllPendingScheduledTasksResponse* response));
101 // Async methods which we do not care.
102 MOCK_METHOD(ClientAsyncReaderInterface<GetRemoteTasksResponse>*, AsyncGetRemoteTasksRaw,
103 (ClientContext * context, const GetRemoteTasksRequest& request, CompletionQueue* cq,
104 void* tag));
105 MOCK_METHOD(ClientAsyncReaderInterface<GetRemoteTasksResponse>*, PrepareAsyncGetRemoteTasksRaw,
106 (ClientContext * context, const GetRemoteTasksRequest& request,
107 CompletionQueue* cq));
108 MOCK_METHOD(ClientAsyncResponseReaderInterface<NotifyWakeupRequiredResponse>*,
109 AsyncNotifyWakeupRequiredRaw,
110 (ClientContext * context, const NotifyWakeupRequiredRequest& request,
111 CompletionQueue* cq));
112 MOCK_METHOD(ClientAsyncResponseReaderInterface<NotifyWakeupRequiredResponse>*,
113 PrepareAsyncNotifyWakeupRequiredRaw,
114 (ClientContext * context, const NotifyWakeupRequiredRequest& request,
115 CompletionQueue* cq));
116 MOCK_METHOD(ClientAsyncResponseReaderInterface<ScheduleTaskResponse>*, AsyncScheduleTaskRaw,
117 (ClientContext * context, const ScheduleTaskRequest& request, CompletionQueue* cq));
118 MOCK_METHOD(ClientAsyncResponseReaderInterface<ScheduleTaskResponse>*,
119 PrepareAsyncScheduleTaskRaw,
120 (ClientContext * context, const ScheduleTaskRequest& request, CompletionQueue* cq));
121 MOCK_METHOD(ClientAsyncResponseReaderInterface<UnscheduleTaskResponse>*, AsyncUnscheduleTaskRaw,
122 (ClientContext * context, const UnscheduleTaskRequest& request,
123 CompletionQueue* cq));
124 MOCK_METHOD(ClientAsyncResponseReaderInterface<UnscheduleTaskResponse>*,
125 PrepareAsyncUnscheduleTaskRaw,
126 (ClientContext * context, const UnscheduleTaskRequest& request,
127 CompletionQueue* cq));
128 MOCK_METHOD(ClientAsyncResponseReaderInterface<UnscheduleAllTasksResponse>*,
129 AsyncUnscheduleAllTasksRaw,
130 (ClientContext * context, const UnscheduleAllTasksRequest& request,
131 CompletionQueue* cq));
132 MOCK_METHOD(ClientAsyncResponseReaderInterface<UnscheduleAllTasksResponse>*,
133 PrepareAsyncUnscheduleAllTasksRaw,
134 (ClientContext * context, const UnscheduleAllTasksRequest& request,
135 CompletionQueue* cq));
136 MOCK_METHOD(ClientAsyncResponseReaderInterface<IsTaskScheduledResponse>*,
137 AsyncIsTaskScheduledRaw,
138 (ClientContext * context, const IsTaskScheduledRequest& request,
139 CompletionQueue* cq));
140 MOCK_METHOD(ClientAsyncResponseReaderInterface<IsTaskScheduledResponse>*,
141 PrepareAsyncIsTaskScheduledRaw,
142 (ClientContext * context, const IsTaskScheduledRequest& request,
143 CompletionQueue* cq));
144 MOCK_METHOD(ClientAsyncResponseReaderInterface<GetAllPendingScheduledTasksResponse>*,
145 AsyncGetAllPendingScheduledTasksRaw,
146 (ClientContext * context, const GetAllPendingScheduledTasksRequest& request,
147 CompletionQueue* cq));
148 MOCK_METHOD(ClientAsyncResponseReaderInterface<GetAllPendingScheduledTasksResponse>*,
149 PrepareAsyncGetAllPendingScheduledTasksRaw,
150 (ClientContext * context, const GetAllPendingScheduledTasksRequest& request,
151 CompletionQueue* cq));
152 };
153
154 class FakeVhalClient final : public android::frameworks::automotive::vhal::IVhalClient {
155 public:
isAidlVhal()156 inline bool isAidlVhal() { return true; }
157
getValueSync(const IHalPropValue & requestValue)158 VhalClientResult<std::unique_ptr<IHalPropValue>> getValueSync(
159 const IHalPropValue& requestValue) override {
160 auto propValue = std::make_unique<AidlHalPropValue>(requestValue.getPropId());
161 propValue->setStringValue(kTestVin);
162 return propValue;
163 }
164
createHalPropValue(int32_t propId)165 std::unique_ptr<IHalPropValue> createHalPropValue(int32_t propId) override {
166 return std::make_unique<AidlHalPropValue>(propId);
167 }
168
169 // Functions we do not care.
createHalPropValue(int32_t propId,int32_t areaId)170 std::unique_ptr<IHalPropValue> createHalPropValue([[maybe_unused]] int32_t propId,
171 [[maybe_unused]] int32_t areaId) override {
172 return nullptr;
173 }
174
getValue(const IHalPropValue & requestValue,std::shared_ptr<GetValueCallbackFunc> callback)175 void getValue([[maybe_unused]] const IHalPropValue& requestValue,
176 [[maybe_unused]] std::shared_ptr<GetValueCallbackFunc> callback) override {}
177
setValue(const IHalPropValue & requestValue,std::shared_ptr<SetValueCallbackFunc> callback)178 void setValue([[maybe_unused]] const IHalPropValue& requestValue,
179 [[maybe_unused]] std::shared_ptr<SetValueCallbackFunc> callback) override {}
180
setValueSync(const IHalPropValue & requestValue)181 VhalClientResult<void> setValueSync([[maybe_unused]] const IHalPropValue& requestValue) {
182 return {};
183 }
184
addOnBinderDiedCallback(std::shared_ptr<OnBinderDiedCallbackFunc> callback)185 VhalClientResult<void> addOnBinderDiedCallback(
186 [[maybe_unused]] std::shared_ptr<OnBinderDiedCallbackFunc> callback) override {
187 return {};
188 }
189
removeOnBinderDiedCallback(std::shared_ptr<OnBinderDiedCallbackFunc> callback)190 VhalClientResult<void> removeOnBinderDiedCallback(
191 [[maybe_unused]] std::shared_ptr<OnBinderDiedCallbackFunc> callback) override {
192 return {};
193 }
194
getAllPropConfigs()195 VhalClientResult<std::vector<std::unique_ptr<IHalPropConfig>>> getAllPropConfigs() override {
196 return std::vector<std::unique_ptr<IHalPropConfig>>();
197 }
198
getPropConfigs(std::vector<int32_t> propIds)199 VhalClientResult<std::vector<std::unique_ptr<IHalPropConfig>>> getPropConfigs(
200 [[maybe_unused]] std::vector<int32_t> propIds) override {
201 return std::vector<std::unique_ptr<IHalPropConfig>>();
202 }
203
getSubscriptionClient(std::shared_ptr<ISubscriptionCallback> callback)204 std::unique_ptr<ISubscriptionClient> getSubscriptionClient(
205 [[maybe_unused]] std::shared_ptr<ISubscriptionCallback> callback) override {
206 return nullptr;
207 }
208 };
209
210 class FakeRemoteTaskCallback : public BnRemoteTaskCallback {
211 public:
onRemoteTaskRequested(const std::string & clientId,const std::vector<uint8_t> & data)212 ScopedAStatus onRemoteTaskRequested(const std::string& clientId,
213 const std::vector<uint8_t>& data) override {
214 std::lock_guard<std::mutex> lockGuard(mLock);
215 mDataByClientId[clientId] = data;
216 mTaskCount++;
217 mCv.notify_all();
218 return ScopedAStatus::ok();
219 }
220
getData(const std::string & clientId)221 std::vector<uint8_t> getData(const std::string& clientId) { return mDataByClientId[clientId]; }
222
wait(size_t taskCount,size_t timeoutInSec)223 bool wait(size_t taskCount, size_t timeoutInSec) {
224 std::unique_lock<std::mutex> lock(mLock);
225 return mCv.wait_for(lock, std::chrono::seconds(timeoutInSec), [taskCount, this] {
226 ScopedLockAssertion lockAssertion(mLock);
227 return mTaskCount >= taskCount;
228 });
229 }
230
231 private:
232 std::mutex mLock;
233 std::unordered_map<std::string, std::vector<uint8_t>> mDataByClientId GUARDED_BY(mLock);
234 size_t mTaskCount GUARDED_BY(mLock) = 0;
235 std::condition_variable mCv;
236 };
237
238 class RemoteAccessServiceUnitTest : public ::testing::Test {
239 public:
SetUp()240 virtual void SetUp() override {
241 mGrpcWakeupClientStub = std::make_unique<MockGrpcClientStub>();
242 mService = ndk::SharedRefBase::make<RemoteAccessService>(mGrpcWakeupClientStub.get());
243 }
244
getGrpcWakeupClientStub()245 MockGrpcClientStub* getGrpcWakeupClientStub() { return mGrpcWakeupClientStub.get(); }
246
getService()247 RemoteAccessService* getService() { return mService.get(); }
248
setRetryWaitInMs(size_t retryWaitInMs)249 void setRetryWaitInMs(size_t retryWaitInMs) { mService->setRetryWaitInMs(retryWaitInMs); }
250
getVehicleIdWithClient(IVhalClient & vhalClient,std::string * vehicleId)251 ScopedAStatus getVehicleIdWithClient(IVhalClient& vhalClient, std::string* vehicleId) {
252 return mService->getVehicleIdWithClient(vhalClient, vehicleId);
253 }
254
255 private:
256 std::unique_ptr<MockGrpcClientStub> mGrpcWakeupClientStub;
257 std::shared_ptr<RemoteAccessService> mService;
258 };
259
TEST_F(RemoteAccessServiceUnitTest,TestGetWakeupServiceName)260 TEST_F(RemoteAccessServiceUnitTest, TestGetWakeupServiceName) {
261 std::string serviceName;
262
263 ScopedAStatus status = getService()->getWakeupServiceName(&serviceName);
264
265 EXPECT_TRUE(status.isOk());
266 EXPECT_EQ(serviceName, "com.google.vehicle.wakeup");
267 }
268
TEST_F(RemoteAccessServiceUnitTest,TestNotifyApStateChangeWakeupRequired)269 TEST_F(RemoteAccessServiceUnitTest, TestNotifyApStateChangeWakeupRequired) {
270 bool isWakeupRequired = false;
271 EXPECT_CALL(*getGrpcWakeupClientStub(), NotifyWakeupRequired)
272 .WillOnce([&isWakeupRequired]([[maybe_unused]] ClientContext* context,
273 const NotifyWakeupRequiredRequest& request,
274 [[maybe_unused]] NotifyWakeupRequiredResponse* response) {
275 isWakeupRequired = request.iswakeuprequired();
276 return Status();
277 });
278
279 ApState newState = {
280 .isWakeupRequired = true,
281 };
282 ScopedAStatus status = getService()->notifyApStateChange(newState);
283
284 EXPECT_TRUE(status.isOk());
285 EXPECT_TRUE(isWakeupRequired);
286 }
287
TEST_F(RemoteAccessServiceUnitTest,TestGetRemoteTasks)288 TEST_F(RemoteAccessServiceUnitTest, TestGetRemoteTasks) {
289 GetRemoteTasksResponse response1;
290 std::vector<uint8_t> testData = {0xde, 0xad, 0xbe, 0xef};
291 response1.set_clientid("1");
292 response1.set_data(testData.data(), testData.size());
293 GetRemoteTasksResponse response2;
294 response2.set_clientid("2");
295 std::shared_ptr<FakeRemoteTaskCallback> callback =
296 ndk::SharedRefBase::make<FakeRemoteTaskCallback>();
297
298 ON_CALL(*getGrpcWakeupClientStub(), GetRemoteTasksRaw)
299 .WillByDefault(
300 [response1, response2]([[maybe_unused]] ClientContext* context,
301 [[maybe_unused]] const GetRemoteTasksRequest& request) {
302 // mockReader ownership will be transferred to the client so we don't own it
303 // here.
304 MockClientReader<GetRemoteTasksResponse>* mockClientReader =
305 new MockClientReader<GetRemoteTasksResponse>();
306 EXPECT_CALL(*mockClientReader, Finish()).WillOnce(Return(Status::OK));
307 EXPECT_CALL(*mockClientReader, Read(_))
308 .WillOnce(DoAll(SetArgPointee<0>(response1), Return(true)))
309 .WillOnce(DoAll(SetArgPointee<0>(response2), Return(true)))
310 .WillRepeatedly(Return(false));
311 return mockClientReader;
312 });
313
314 getService()->setRemoteTaskCallback(callback);
315 // Start the long live connection to receive tasks.
316 ApState newState = {
317 .isReadyForRemoteTask = true,
318 };
319 ASSERT_TRUE(getService()->notifyApStateChange(newState).isOk());
320
321 ASSERT_TRUE(callback->wait(/*taskCount=*/2, /*timeoutInSec=*/10))
322 << "Did not receive enough tasks";
323 EXPECT_EQ(callback->getData("1"), testData);
324 EXPECT_EQ(callback->getData("2"), std::vector<uint8_t>());
325 }
326
TEST_F(RemoteAccessServiceUnitTest,TestGetRemoteTasksRetryConnection)327 TEST_F(RemoteAccessServiceUnitTest, TestGetRemoteTasksRetryConnection) {
328 GetRemoteTasksResponse response;
329 std::shared_ptr<FakeRemoteTaskCallback> callback =
330 ndk::SharedRefBase::make<FakeRemoteTaskCallback>();
331
332 ON_CALL(*getGrpcWakeupClientStub(), GetRemoteTasksRaw)
333 .WillByDefault([response]([[maybe_unused]] ClientContext* context,
334 [[maybe_unused]] const GetRemoteTasksRequest& request) {
335 // mockReader ownership will be transferred to the client so we don't own it here.
336 MockClientReader<GetRemoteTasksResponse>* mockClientReader =
337 new MockClientReader<GetRemoteTasksResponse>();
338 EXPECT_CALL(*mockClientReader, Finish()).WillOnce(Return(Status::OK));
339 // Connection fails after receiving one task. Should retry after some time.
340 EXPECT_CALL(*mockClientReader, Read(_))
341 .WillOnce(DoAll(SetArgPointee<0>(response), Return(true)))
342 .WillRepeatedly(Return(false));
343 return mockClientReader;
344 });
345
346 getService()->setRemoteTaskCallback(callback);
347 setRetryWaitInMs(100);
348 // Start the long live connection to receive tasks.
349 ApState newState = {
350 .isReadyForRemoteTask = true,
351 };
352 ASSERT_TRUE(getService()->notifyApStateChange(newState).isOk());
353
354 ASSERT_TRUE(callback->wait(/*taskCount=*/2, /*timeoutInSec=*/10))
355 << "Did not receive enough tasks";
356 }
357
TEST_F(RemoteAccessServiceUnitTest,TestGetRemoteTasksDefaultNotReady)358 TEST_F(RemoteAccessServiceUnitTest, TestGetRemoteTasksDefaultNotReady) {
359 GetRemoteTasksResponse response1;
360 std::vector<uint8_t> testData = {0xde, 0xad, 0xbe, 0xef};
361 response1.set_clientid("1");
362 response1.set_data(testData.data(), testData.size());
363 GetRemoteTasksResponse response2;
364 response2.set_clientid("2");
365 std::shared_ptr<FakeRemoteTaskCallback> callback =
366 ndk::SharedRefBase::make<FakeRemoteTaskCallback>();
367
368 EXPECT_CALL(*getGrpcWakeupClientStub(), GetRemoteTasksRaw).Times(0);
369
370 // Default state is not ready for remote tasks, so no callback will be called.
371 getService()->setRemoteTaskCallback(callback);
372
373 std::this_thread::sleep_for(std::chrono::milliseconds(100));
374 }
375
TEST_F(RemoteAccessServiceUnitTest,TestGetRemoteTasksNotReadyAfterReady)376 TEST_F(RemoteAccessServiceUnitTest, TestGetRemoteTasksNotReadyAfterReady) {
377 GetRemoteTasksResponse response1;
378 std::vector<uint8_t> testData = {0xde, 0xad, 0xbe, 0xef};
379 response1.set_clientid("1");
380 response1.set_data(testData.data(), testData.size());
381 GetRemoteTasksResponse response2;
382 response2.set_clientid("2");
383 std::shared_ptr<FakeRemoteTaskCallback> callback =
384 ndk::SharedRefBase::make<FakeRemoteTaskCallback>();
385
386 ON_CALL(*getGrpcWakeupClientStub(), GetRemoteTasksRaw)
387 .WillByDefault(
388 [response1, response2]([[maybe_unused]] ClientContext* context,
389 [[maybe_unused]] const GetRemoteTasksRequest& request) {
390 // mockReader ownership will be transferred to the client so we don't own it
391 // here.
392 MockClientReader<GetRemoteTasksResponse>* mockClientReader =
393 new MockClientReader<GetRemoteTasksResponse>();
394 EXPECT_CALL(*mockClientReader, Finish()).WillOnce(Return(Status::OK));
395 EXPECT_CALL(*mockClientReader, Read(_))
396 .WillOnce(DoAll(SetArgPointee<0>(response1), Return(true)))
397 .WillOnce(DoAll(SetArgPointee<0>(response2), Return(true)))
398 .WillRepeatedly(Return(false));
399 return mockClientReader;
400 });
401 // Should only be called once when is is ready for remote task.
402 EXPECT_CALL(*getGrpcWakeupClientStub(), GetRemoteTasksRaw).Times(1);
403
404 getService()->setRemoteTaskCallback(callback);
405 setRetryWaitInMs(100);
406 // Start the long live connection to receive tasks.
407 ApState newState = {
408 .isReadyForRemoteTask = true,
409 };
410 ASSERT_TRUE(getService()->notifyApStateChange(newState).isOk());
411 ASSERT_TRUE(callback->wait(/*taskCount=*/2, /*timeoutInSec=*/10))
412 << "Did not receive enough tasks";
413
414 // Stop the long live connection.
415 newState.isReadyForRemoteTask = false;
416 ASSERT_TRUE(getService()->notifyApStateChange(newState).isOk());
417
418 // Wait for the retry delay, but the loop should already exit.
419 std::this_thread::sleep_for(std::chrono::milliseconds(150));
420 }
421
TEST_F(RemoteAccessServiceUnitTest,testGetVehicleId)422 TEST_F(RemoteAccessServiceUnitTest, testGetVehicleId) {
423 std::string vehicleId;
424
425 FakeVhalClient vhalClient;
426
427 ASSERT_TRUE(getVehicleIdWithClient(vhalClient, &vehicleId).isOk());
428 ASSERT_EQ(vehicleId, kTestVin);
429 }
430
TEST_F(RemoteAccessServiceUnitTest,TestIsTaskScheduleSupported)431 TEST_F(RemoteAccessServiceUnitTest, TestIsTaskScheduleSupported) {
432 bool out = false;
433 ScopedAStatus status = getService()->isTaskScheduleSupported(&out);
434
435 EXPECT_TRUE(status.isOk());
436 EXPECT_TRUE(out);
437 }
438
TEST_F(RemoteAccessServiceUnitTest,TestGetSupportedTaskTypesForScheduling)439 TEST_F(RemoteAccessServiceUnitTest, TestGetSupportedTaskTypesForScheduling) {
440 std::vector<TaskType> out;
441 ScopedAStatus status = getService()->getSupportedTaskTypesForScheduling(&out);
442
443 EXPECT_TRUE(status.isOk());
444 EXPECT_THAT(out, ElementsAre(TaskType::CUSTOM));
445 }
446
TEST_F(RemoteAccessServiceUnitTest,TestScheduleTask)447 TEST_F(RemoteAccessServiceUnitTest, TestScheduleTask) {
448 ScheduleTaskRequest grpcRequest = {};
449 EXPECT_CALL(*getGrpcWakeupClientStub(), ScheduleTask)
450 .WillOnce([&grpcRequest]([[maybe_unused]] ClientContext* context,
451 const ScheduleTaskRequest& request,
452 [[maybe_unused]] ScheduleTaskResponse* response) {
453 grpcRequest = request;
454 return Status();
455 });
456 ScheduleInfo scheduleInfo = {
457 .clientId = kTestClientId,
458 .scheduleId = kTestScheduleId,
459 .taskData = kTestData,
460 .count = kTestCount,
461 .startTimeInEpochSeconds = kTestStartTimeInEpochSeconds,
462 .periodicInSeconds = kTestPeriodicInSeconds,
463 };
464
465 ScopedAStatus status = getService()->scheduleTask(scheduleInfo);
466
467 ASSERT_TRUE(status.isOk());
468 EXPECT_EQ(grpcRequest.scheduleinfo().clientid(), kTestClientId);
469 EXPECT_EQ(grpcRequest.scheduleinfo().scheduleid(), kTestScheduleId);
470 EXPECT_EQ(grpcRequest.scheduleinfo().data(), std::string(kTestData.begin(), kTestData.end()));
471 EXPECT_EQ(grpcRequest.scheduleinfo().count(), kTestCount);
472 EXPECT_EQ(grpcRequest.scheduleinfo().starttimeinepochseconds(), kTestStartTimeInEpochSeconds);
473 EXPECT_EQ(grpcRequest.scheduleinfo().periodicinseconds(), kTestPeriodicInSeconds);
474 }
475
TEST_F(RemoteAccessServiceUnitTest,TestScheduleTask_InvalidCount)476 TEST_F(RemoteAccessServiceUnitTest, TestScheduleTask_InvalidCount) {
477 ScheduleInfo scheduleInfo = {
478 .clientId = kTestClientId,
479 .scheduleId = kTestScheduleId,
480 .taskData = kTestData,
481 .count = -1,
482 .startTimeInEpochSeconds = kTestStartTimeInEpochSeconds,
483 .periodicInSeconds = kTestPeriodicInSeconds,
484 };
485
486 ScopedAStatus status = getService()->scheduleTask(scheduleInfo);
487
488 ASSERT_FALSE(status.isOk());
489 ASSERT_EQ(status.getExceptionCode(), EX_ILLEGAL_ARGUMENT);
490 }
491
TEST_F(RemoteAccessServiceUnitTest,TestScheduleTask_InvalidStartTimeInEpochSeconds)492 TEST_F(RemoteAccessServiceUnitTest, TestScheduleTask_InvalidStartTimeInEpochSeconds) {
493 ScheduleInfo scheduleInfo = {
494 .clientId = kTestClientId,
495 .scheduleId = kTestScheduleId,
496 .taskData = kTestData,
497 .count = kTestCount,
498 .startTimeInEpochSeconds = -1,
499 .periodicInSeconds = kTestPeriodicInSeconds,
500 };
501
502 ScopedAStatus status = getService()->scheduleTask(scheduleInfo);
503
504 ASSERT_FALSE(status.isOk());
505 ASSERT_EQ(status.getExceptionCode(), EX_ILLEGAL_ARGUMENT);
506 }
507
TEST_F(RemoteAccessServiceUnitTest,TestScheduleTask_InvalidPeriodicInSeconds)508 TEST_F(RemoteAccessServiceUnitTest, TestScheduleTask_InvalidPeriodicInSeconds) {
509 ScheduleInfo scheduleInfo = {
510 .clientId = kTestClientId,
511 .scheduleId = kTestScheduleId,
512 .taskData = kTestData,
513 .count = kTestCount,
514 .startTimeInEpochSeconds = kTestStartTimeInEpochSeconds,
515 .periodicInSeconds = -1,
516 };
517
518 ScopedAStatus status = getService()->scheduleTask(scheduleInfo);
519
520 ASSERT_FALSE(status.isOk());
521 ASSERT_EQ(status.getExceptionCode(), EX_ILLEGAL_ARGUMENT);
522 }
523
TEST_F(RemoteAccessServiceUnitTest,TestScheduleTask_TaskDataTooLarge)524 TEST_F(RemoteAccessServiceUnitTest, TestScheduleTask_TaskDataTooLarge) {
525 ScheduleInfo scheduleInfo = {
526 .clientId = kTestClientId,
527 .scheduleId = kTestScheduleId,
528 .taskData = std::vector<uint8_t>(ScheduleInfo::MAX_TASK_DATA_SIZE_IN_BYTES + 1),
529 .count = kTestCount,
530 .startTimeInEpochSeconds = kTestStartTimeInEpochSeconds,
531 .periodicInSeconds = kTestPeriodicInSeconds,
532 };
533
534 ScopedAStatus status = getService()->scheduleTask(scheduleInfo);
535
536 ASSERT_FALSE(status.isOk());
537 ASSERT_EQ(status.getExceptionCode(), EX_ILLEGAL_ARGUMENT);
538 }
539
TEST_F(RemoteAccessServiceUnitTest,TestScheduleTask_InvalidArgFromGrpcServer)540 TEST_F(RemoteAccessServiceUnitTest, TestScheduleTask_InvalidArgFromGrpcServer) {
541 EXPECT_CALL(*getGrpcWakeupClientStub(), ScheduleTask)
542 .WillOnce([]([[maybe_unused]] ClientContext* context,
543 [[maybe_unused]] const ScheduleTaskRequest& request,
544 ScheduleTaskResponse* response) {
545 response->set_errorcode(ErrorCode::INVALID_ARG);
546 return Status();
547 });
548 ScheduleInfo scheduleInfo = {
549 .clientId = kTestClientId,
550 .scheduleId = kTestScheduleId,
551 .taskData = kTestData,
552 .count = kTestCount,
553 .startTimeInEpochSeconds = kTestStartTimeInEpochSeconds,
554 .periodicInSeconds = kTestPeriodicInSeconds,
555 };
556
557 ScopedAStatus status = getService()->scheduleTask(scheduleInfo);
558
559 ASSERT_FALSE(status.isOk());
560 ASSERT_EQ(status.getExceptionCode(), EX_ILLEGAL_ARGUMENT);
561 }
562
TEST_F(RemoteAccessServiceUnitTest,TestScheduleTask_UnspecifiedError)563 TEST_F(RemoteAccessServiceUnitTest, TestScheduleTask_UnspecifiedError) {
564 EXPECT_CALL(*getGrpcWakeupClientStub(), ScheduleTask)
565 .WillOnce([]([[maybe_unused]] ClientContext* context,
566 [[maybe_unused]] const ScheduleTaskRequest& request,
567 ScheduleTaskResponse* response) {
568 response->set_errorcode(ErrorCode::UNSPECIFIED);
569 return Status();
570 });
571 ScheduleInfo scheduleInfo = {
572 .clientId = kTestClientId,
573 .scheduleId = kTestScheduleId,
574 .taskData = kTestData,
575 .count = kTestCount,
576 .startTimeInEpochSeconds = kTestStartTimeInEpochSeconds,
577 .periodicInSeconds = kTestPeriodicInSeconds,
578 };
579
580 ScopedAStatus status = getService()->scheduleTask(scheduleInfo);
581
582 ASSERT_FALSE(status.isOk());
583 ASSERT_EQ(status.getExceptionCode(), EX_SERVICE_SPECIFIC);
584 }
585
TEST_F(RemoteAccessServiceUnitTest,TestUnscheduleTask)586 TEST_F(RemoteAccessServiceUnitTest, TestUnscheduleTask) {
587 UnscheduleTaskRequest grpcRequest = {};
588 EXPECT_CALL(*getGrpcWakeupClientStub(), UnscheduleTask)
589 .WillOnce([&grpcRequest]([[maybe_unused]] ClientContext* context,
590 const UnscheduleTaskRequest& request,
591 [[maybe_unused]] UnscheduleTaskResponse* response) {
592 grpcRequest = request;
593 return Status();
594 });
595
596 ScopedAStatus status = getService()->unscheduleTask(kTestClientId, kTestScheduleId);
597
598 ASSERT_TRUE(status.isOk());
599 EXPECT_EQ(grpcRequest.clientid(), kTestClientId);
600 EXPECT_EQ(grpcRequest.scheduleid(), kTestScheduleId);
601 }
602
TEST_F(RemoteAccessServiceUnitTest,TestUnscheduleAllTasks)603 TEST_F(RemoteAccessServiceUnitTest, TestUnscheduleAllTasks) {
604 UnscheduleAllTasksRequest grpcRequest = {};
605 EXPECT_CALL(*getGrpcWakeupClientStub(), UnscheduleAllTasks)
606 .WillOnce([&grpcRequest]([[maybe_unused]] ClientContext* context,
607 const UnscheduleAllTasksRequest& request,
608 [[maybe_unused]] UnscheduleAllTasksResponse* response) {
609 grpcRequest = request;
610 return Status();
611 });
612
613 ScopedAStatus status = getService()->unscheduleAllTasks(kTestClientId);
614
615 ASSERT_TRUE(status.isOk());
616 EXPECT_EQ(grpcRequest.clientid(), kTestClientId);
617 }
618
TEST_F(RemoteAccessServiceUnitTest,TestIsTaskScheduled)619 TEST_F(RemoteAccessServiceUnitTest, TestIsTaskScheduled) {
620 bool isTaskScheduled = false;
621 IsTaskScheduledRequest grpcRequest = {};
622 EXPECT_CALL(*getGrpcWakeupClientStub(), IsTaskScheduled)
623 .WillOnce([&grpcRequest]([[maybe_unused]] ClientContext* context,
624 const IsTaskScheduledRequest& request,
625 IsTaskScheduledResponse* response) {
626 grpcRequest = request;
627 response->set_istaskscheduled(true);
628 return Status();
629 });
630
631 ScopedAStatus status =
632 getService()->isTaskScheduled(kTestClientId, kTestScheduleId, &isTaskScheduled);
633
634 ASSERT_TRUE(status.isOk());
635 EXPECT_TRUE(isTaskScheduled);
636 EXPECT_EQ(grpcRequest.clientid(), kTestClientId);
637 EXPECT_EQ(grpcRequest.scheduleid(), kTestScheduleId);
638 }
639
TEST_F(RemoteAccessServiceUnitTest,testGetAllPendingScheduledTasks)640 TEST_F(RemoteAccessServiceUnitTest, testGetAllPendingScheduledTasks) {
641 std::vector<ScheduleInfo> result;
642 GetAllPendingScheduledTasksRequest grpcRequest = {};
643 EXPECT_CALL(*getGrpcWakeupClientStub(), GetAllPendingScheduledTasks)
644 .WillOnce([&grpcRequest]([[maybe_unused]] ClientContext* context,
645 const GetAllPendingScheduledTasksRequest& request,
646 GetAllPendingScheduledTasksResponse* response) {
647 grpcRequest = request;
648 GrpcScheduleInfo* newInfo = response->add_allscheduledtasks();
649 newInfo->set_clientid(kTestClientId);
650 newInfo->set_scheduleid(kTestScheduleId);
651 newInfo->set_data(kTestData.data(), kTestData.size());
652 newInfo->set_count(kTestCount);
653 newInfo->set_starttimeinepochseconds(kTestStartTimeInEpochSeconds);
654 newInfo->set_periodicinseconds(kTestPeriodicInSeconds);
655 return Status();
656 });
657
658 ScopedAStatus status = getService()->getAllPendingScheduledTasks(kTestClientId, &result);
659
660 ASSERT_TRUE(status.isOk());
661 EXPECT_EQ(grpcRequest.clientid(), kTestClientId);
662 ASSERT_EQ(result.size(), 1u);
663 ASSERT_EQ(result[0].clientId, kTestClientId);
664 ASSERT_EQ(result[0].scheduleId, kTestScheduleId);
665 ASSERT_EQ(result[0].taskData, kTestData);
666 ASSERT_EQ(result[0].count, kTestCount);
667 ASSERT_EQ(result[0].startTimeInEpochSeconds, kTestStartTimeInEpochSeconds);
668 ASSERT_EQ(result[0].periodicInSeconds, kTestPeriodicInSeconds);
669 }
670
671 } // namespace remoteaccess
672 } // namespace automotive
673 } // namespace hardware
674 } // namespace android
675