/* * Copyright (C) 2022 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include "RemoteAccessService.h" #include #include #include #include #include #include #include #include #include #include #include #include namespace android { namespace hardware { namespace automotive { namespace remoteaccess { namespace { using ::android::base::ScopedLockAssertion; using ::android::frameworks::automotive::vhal::AidlHalPropValue; using ::android::frameworks::automotive::vhal::IHalPropConfig; using ::android::frameworks::automotive::vhal::IHalPropValue; using ::android::frameworks::automotive::vhal::ISubscriptionCallback; using ::android::frameworks::automotive::vhal::ISubscriptionClient; using ::android::frameworks::automotive::vhal::IVhalClient; using ::android::frameworks::automotive::vhal::VhalClientResult; using ::aidl::android::hardware::automotive::remoteaccess::ApState; using ::aidl::android::hardware::automotive::remoteaccess::BnRemoteTaskCallback; using ::aidl::android::hardware::automotive::remoteaccess::ScheduleInfo; using ::aidl::android::hardware::automotive::remoteaccess::TaskType; using ::aidl::android::hardware::automotive::vehicle::VehiclePropValue; using ::grpc::ClientAsyncReaderInterface; using ::grpc::ClientAsyncResponseReaderInterface; using ::grpc::ClientContext; using ::grpc::ClientReader; using ::grpc::ClientReaderInterface; using ::grpc::CompletionQueue; using ::grpc::Status; using ::grpc::testing::MockClientReader; using ::ndk::ScopedAStatus; using ::testing::_; using ::testing::DoAll; using ::testing::ElementsAre; using ::testing::Return; using ::testing::SetArgPointee; constexpr char kTestVin[] = "test_VIN"; const std::string kTestClientId = "test client id"; const std::string kTestScheduleId = "test schedule id"; const std::vector kTestData = {0xde, 0xad, 0xbe, 0xef}; constexpr int32_t kTestCount = 1234; constexpr int64_t kTestStartTimeInEpochSeconds = 2345; constexpr int64_t kTestPeriodicInSeconds = 123; } // namespace class MockGrpcClientStub : public WakeupClient::StubInterface { public: MOCK_METHOD(ClientReaderInterface*, GetRemoteTasksRaw, (ClientContext * context, const GetRemoteTasksRequest& request)); MOCK_METHOD(Status, NotifyWakeupRequired, (ClientContext * context, const NotifyWakeupRequiredRequest& request, NotifyWakeupRequiredResponse* response)); MOCK_METHOD(Status, ScheduleTask, (ClientContext * context, const ScheduleTaskRequest& request, ScheduleTaskResponse* response)); MOCK_METHOD(Status, UnscheduleTask, (ClientContext * context, const UnscheduleTaskRequest& request, UnscheduleTaskResponse* response)); MOCK_METHOD(Status, UnscheduleAllTasks, (ClientContext * context, const UnscheduleAllTasksRequest& request, UnscheduleAllTasksResponse* response)); MOCK_METHOD(Status, IsTaskScheduled, (ClientContext * context, const IsTaskScheduledRequest& request, IsTaskScheduledResponse* response)); MOCK_METHOD(Status, GetAllPendingScheduledTasks, (ClientContext * context, const GetAllPendingScheduledTasksRequest& request, GetAllPendingScheduledTasksResponse* response)); // Async methods which we do not care. MOCK_METHOD(ClientAsyncReaderInterface*, AsyncGetRemoteTasksRaw, (ClientContext * context, const GetRemoteTasksRequest& request, CompletionQueue* cq, void* tag)); MOCK_METHOD(ClientAsyncReaderInterface*, PrepareAsyncGetRemoteTasksRaw, (ClientContext * context, const GetRemoteTasksRequest& request, CompletionQueue* cq)); MOCK_METHOD(ClientAsyncResponseReaderInterface*, AsyncNotifyWakeupRequiredRaw, (ClientContext * context, const NotifyWakeupRequiredRequest& request, CompletionQueue* cq)); MOCK_METHOD(ClientAsyncResponseReaderInterface*, PrepareAsyncNotifyWakeupRequiredRaw, (ClientContext * context, const NotifyWakeupRequiredRequest& request, CompletionQueue* cq)); MOCK_METHOD(ClientAsyncResponseReaderInterface*, AsyncScheduleTaskRaw, (ClientContext * context, const ScheduleTaskRequest& request, CompletionQueue* cq)); MOCK_METHOD(ClientAsyncResponseReaderInterface*, PrepareAsyncScheduleTaskRaw, (ClientContext * context, const ScheduleTaskRequest& request, CompletionQueue* cq)); MOCK_METHOD(ClientAsyncResponseReaderInterface*, AsyncUnscheduleTaskRaw, (ClientContext * context, const UnscheduleTaskRequest& request, CompletionQueue* cq)); MOCK_METHOD(ClientAsyncResponseReaderInterface*, PrepareAsyncUnscheduleTaskRaw, (ClientContext * context, const UnscheduleTaskRequest& request, CompletionQueue* cq)); MOCK_METHOD(ClientAsyncResponseReaderInterface*, AsyncUnscheduleAllTasksRaw, (ClientContext * context, const UnscheduleAllTasksRequest& request, CompletionQueue* cq)); MOCK_METHOD(ClientAsyncResponseReaderInterface*, PrepareAsyncUnscheduleAllTasksRaw, (ClientContext * context, const UnscheduleAllTasksRequest& request, CompletionQueue* cq)); MOCK_METHOD(ClientAsyncResponseReaderInterface*, AsyncIsTaskScheduledRaw, (ClientContext * context, const IsTaskScheduledRequest& request, CompletionQueue* cq)); MOCK_METHOD(ClientAsyncResponseReaderInterface*, PrepareAsyncIsTaskScheduledRaw, (ClientContext * context, const IsTaskScheduledRequest& request, CompletionQueue* cq)); MOCK_METHOD(ClientAsyncResponseReaderInterface*, AsyncGetAllPendingScheduledTasksRaw, (ClientContext * context, const GetAllPendingScheduledTasksRequest& request, CompletionQueue* cq)); MOCK_METHOD(ClientAsyncResponseReaderInterface*, PrepareAsyncGetAllPendingScheduledTasksRaw, (ClientContext * context, const GetAllPendingScheduledTasksRequest& request, CompletionQueue* cq)); }; class FakeVhalClient final : public android::frameworks::automotive::vhal::IVhalClient { public: inline bool isAidlVhal() { return true; } VhalClientResult> getValueSync( const IHalPropValue& requestValue) override { auto propValue = std::make_unique(requestValue.getPropId()); propValue->setStringValue(kTestVin); return propValue; } std::unique_ptr createHalPropValue(int32_t propId) override { return std::make_unique(propId); } // Functions we do not care. std::unique_ptr createHalPropValue([[maybe_unused]] int32_t propId, [[maybe_unused]] int32_t areaId) override { return nullptr; } void getValue([[maybe_unused]] const IHalPropValue& requestValue, [[maybe_unused]] std::shared_ptr callback) override {} void setValue([[maybe_unused]] const IHalPropValue& requestValue, [[maybe_unused]] std::shared_ptr callback) override {} VhalClientResult setValueSync([[maybe_unused]] const IHalPropValue& requestValue) { return {}; } VhalClientResult addOnBinderDiedCallback( [[maybe_unused]] std::shared_ptr callback) override { return {}; } VhalClientResult removeOnBinderDiedCallback( [[maybe_unused]] std::shared_ptr callback) override { return {}; } VhalClientResult>> getAllPropConfigs() override { return std::vector>(); } VhalClientResult>> getPropConfigs( [[maybe_unused]] std::vector propIds) override { return std::vector>(); } std::unique_ptr getSubscriptionClient( [[maybe_unused]] std::shared_ptr callback) override { return nullptr; } }; class FakeRemoteTaskCallback : public BnRemoteTaskCallback { public: ScopedAStatus onRemoteTaskRequested(const std::string& clientId, const std::vector& data) override { std::lock_guard lockGuard(mLock); mDataByClientId[clientId] = data; mTaskCount++; mCv.notify_all(); return ScopedAStatus::ok(); } std::vector getData(const std::string& clientId) { return mDataByClientId[clientId]; } bool wait(size_t taskCount, size_t timeoutInSec) { std::unique_lock lock(mLock); return mCv.wait_for(lock, std::chrono::seconds(timeoutInSec), [taskCount, this] { ScopedLockAssertion lockAssertion(mLock); return mTaskCount >= taskCount; }); } private: std::mutex mLock; std::unordered_map> mDataByClientId GUARDED_BY(mLock); size_t mTaskCount GUARDED_BY(mLock) = 0; std::condition_variable mCv; }; class RemoteAccessServiceUnitTest : public ::testing::Test { public: virtual void SetUp() override { mGrpcWakeupClientStub = std::make_unique(); mService = ndk::SharedRefBase::make(mGrpcWakeupClientStub.get()); } MockGrpcClientStub* getGrpcWakeupClientStub() { return mGrpcWakeupClientStub.get(); } RemoteAccessService* getService() { return mService.get(); } void setRetryWaitInMs(size_t retryWaitInMs) { mService->setRetryWaitInMs(retryWaitInMs); } ScopedAStatus getVehicleIdWithClient(IVhalClient& vhalClient, std::string* vehicleId) { return mService->getVehicleIdWithClient(vhalClient, vehicleId); } private: std::unique_ptr mGrpcWakeupClientStub; std::shared_ptr mService; }; TEST_F(RemoteAccessServiceUnitTest, TestGetWakeupServiceName) { std::string serviceName; ScopedAStatus status = getService()->getWakeupServiceName(&serviceName); EXPECT_TRUE(status.isOk()); EXPECT_EQ(serviceName, "com.google.vehicle.wakeup"); } TEST_F(RemoteAccessServiceUnitTest, TestNotifyApStateChangeWakeupRequired) { bool isWakeupRequired = false; EXPECT_CALL(*getGrpcWakeupClientStub(), NotifyWakeupRequired) .WillOnce([&isWakeupRequired]([[maybe_unused]] ClientContext* context, const NotifyWakeupRequiredRequest& request, [[maybe_unused]] NotifyWakeupRequiredResponse* response) { isWakeupRequired = request.iswakeuprequired(); return Status(); }); ApState newState = { .isWakeupRequired = true, }; ScopedAStatus status = getService()->notifyApStateChange(newState); EXPECT_TRUE(status.isOk()); EXPECT_TRUE(isWakeupRequired); } TEST_F(RemoteAccessServiceUnitTest, TestGetRemoteTasks) { GetRemoteTasksResponse response1; std::vector testData = {0xde, 0xad, 0xbe, 0xef}; response1.set_clientid("1"); response1.set_data(testData.data(), testData.size()); GetRemoteTasksResponse response2; response2.set_clientid("2"); std::shared_ptr callback = ndk::SharedRefBase::make(); ON_CALL(*getGrpcWakeupClientStub(), GetRemoteTasksRaw) .WillByDefault( [response1, response2]([[maybe_unused]] ClientContext* context, [[maybe_unused]] const GetRemoteTasksRequest& request) { // mockReader ownership will be transferred to the client so we don't own it // here. MockClientReader* mockClientReader = new MockClientReader(); EXPECT_CALL(*mockClientReader, Finish()).WillOnce(Return(Status::OK)); EXPECT_CALL(*mockClientReader, Read(_)) .WillOnce(DoAll(SetArgPointee<0>(response1), Return(true))) .WillOnce(DoAll(SetArgPointee<0>(response2), Return(true))) .WillRepeatedly(Return(false)); return mockClientReader; }); getService()->setRemoteTaskCallback(callback); // Start the long live connection to receive tasks. ApState newState = { .isReadyForRemoteTask = true, }; ASSERT_TRUE(getService()->notifyApStateChange(newState).isOk()); ASSERT_TRUE(callback->wait(/*taskCount=*/2, /*timeoutInSec=*/10)) << "Did not receive enough tasks"; EXPECT_EQ(callback->getData("1"), testData); EXPECT_EQ(callback->getData("2"), std::vector()); } TEST_F(RemoteAccessServiceUnitTest, TestGetRemoteTasksRetryConnection) { GetRemoteTasksResponse response; std::shared_ptr callback = ndk::SharedRefBase::make(); ON_CALL(*getGrpcWakeupClientStub(), GetRemoteTasksRaw) .WillByDefault([response]([[maybe_unused]] ClientContext* context, [[maybe_unused]] const GetRemoteTasksRequest& request) { // mockReader ownership will be transferred to the client so we don't own it here. MockClientReader* mockClientReader = new MockClientReader(); EXPECT_CALL(*mockClientReader, Finish()).WillOnce(Return(Status::OK)); // Connection fails after receiving one task. Should retry after some time. EXPECT_CALL(*mockClientReader, Read(_)) .WillOnce(DoAll(SetArgPointee<0>(response), Return(true))) .WillRepeatedly(Return(false)); return mockClientReader; }); getService()->setRemoteTaskCallback(callback); setRetryWaitInMs(100); // Start the long live connection to receive tasks. ApState newState = { .isReadyForRemoteTask = true, }; ASSERT_TRUE(getService()->notifyApStateChange(newState).isOk()); ASSERT_TRUE(callback->wait(/*taskCount=*/2, /*timeoutInSec=*/10)) << "Did not receive enough tasks"; } TEST_F(RemoteAccessServiceUnitTest, TestGetRemoteTasksDefaultNotReady) { GetRemoteTasksResponse response1; std::vector testData = {0xde, 0xad, 0xbe, 0xef}; response1.set_clientid("1"); response1.set_data(testData.data(), testData.size()); GetRemoteTasksResponse response2; response2.set_clientid("2"); std::shared_ptr callback = ndk::SharedRefBase::make(); EXPECT_CALL(*getGrpcWakeupClientStub(), GetRemoteTasksRaw).Times(0); // Default state is not ready for remote tasks, so no callback will be called. getService()->setRemoteTaskCallback(callback); std::this_thread::sleep_for(std::chrono::milliseconds(100)); } TEST_F(RemoteAccessServiceUnitTest, TestGetRemoteTasksNotReadyAfterReady) { GetRemoteTasksResponse response1; std::vector testData = {0xde, 0xad, 0xbe, 0xef}; response1.set_clientid("1"); response1.set_data(testData.data(), testData.size()); GetRemoteTasksResponse response2; response2.set_clientid("2"); std::shared_ptr callback = ndk::SharedRefBase::make(); ON_CALL(*getGrpcWakeupClientStub(), GetRemoteTasksRaw) .WillByDefault( [response1, response2]([[maybe_unused]] ClientContext* context, [[maybe_unused]] const GetRemoteTasksRequest& request) { // mockReader ownership will be transferred to the client so we don't own it // here. MockClientReader* mockClientReader = new MockClientReader(); EXPECT_CALL(*mockClientReader, Finish()).WillOnce(Return(Status::OK)); EXPECT_CALL(*mockClientReader, Read(_)) .WillOnce(DoAll(SetArgPointee<0>(response1), Return(true))) .WillOnce(DoAll(SetArgPointee<0>(response2), Return(true))) .WillRepeatedly(Return(false)); return mockClientReader; }); // Should only be called once when is is ready for remote task. EXPECT_CALL(*getGrpcWakeupClientStub(), GetRemoteTasksRaw).Times(1); getService()->setRemoteTaskCallback(callback); setRetryWaitInMs(100); // Start the long live connection to receive tasks. ApState newState = { .isReadyForRemoteTask = true, }; ASSERT_TRUE(getService()->notifyApStateChange(newState).isOk()); ASSERT_TRUE(callback->wait(/*taskCount=*/2, /*timeoutInSec=*/10)) << "Did not receive enough tasks"; // Stop the long live connection. newState.isReadyForRemoteTask = false; ASSERT_TRUE(getService()->notifyApStateChange(newState).isOk()); // Wait for the retry delay, but the loop should already exit. std::this_thread::sleep_for(std::chrono::milliseconds(150)); } TEST_F(RemoteAccessServiceUnitTest, testGetVehicleId) { std::string vehicleId; FakeVhalClient vhalClient; ASSERT_TRUE(getVehicleIdWithClient(vhalClient, &vehicleId).isOk()); ASSERT_EQ(vehicleId, kTestVin); } TEST_F(RemoteAccessServiceUnitTest, TestIsTaskScheduleSupported) { bool out = false; ScopedAStatus status = getService()->isTaskScheduleSupported(&out); EXPECT_TRUE(status.isOk()); EXPECT_TRUE(out); } TEST_F(RemoteAccessServiceUnitTest, TestGetSupportedTaskTypesForScheduling) { std::vector out; ScopedAStatus status = getService()->getSupportedTaskTypesForScheduling(&out); EXPECT_TRUE(status.isOk()); EXPECT_THAT(out, ElementsAre(TaskType::CUSTOM)); } TEST_F(RemoteAccessServiceUnitTest, TestScheduleTask) { ScheduleTaskRequest grpcRequest = {}; EXPECT_CALL(*getGrpcWakeupClientStub(), ScheduleTask) .WillOnce([&grpcRequest]([[maybe_unused]] ClientContext* context, const ScheduleTaskRequest& request, [[maybe_unused]] ScheduleTaskResponse* response) { grpcRequest = request; return Status(); }); ScheduleInfo scheduleInfo = { .clientId = kTestClientId, .scheduleId = kTestScheduleId, .taskData = kTestData, .count = kTestCount, .startTimeInEpochSeconds = kTestStartTimeInEpochSeconds, .periodicInSeconds = kTestPeriodicInSeconds, }; ScopedAStatus status = getService()->scheduleTask(scheduleInfo); ASSERT_TRUE(status.isOk()); EXPECT_EQ(grpcRequest.scheduleinfo().clientid(), kTestClientId); EXPECT_EQ(grpcRequest.scheduleinfo().scheduleid(), kTestScheduleId); EXPECT_EQ(grpcRequest.scheduleinfo().data(), std::string(kTestData.begin(), kTestData.end())); EXPECT_EQ(grpcRequest.scheduleinfo().count(), kTestCount); EXPECT_EQ(grpcRequest.scheduleinfo().starttimeinepochseconds(), kTestStartTimeInEpochSeconds); EXPECT_EQ(grpcRequest.scheduleinfo().periodicinseconds(), kTestPeriodicInSeconds); } TEST_F(RemoteAccessServiceUnitTest, TestScheduleTask_InvalidCount) { ScheduleInfo scheduleInfo = { .clientId = kTestClientId, .scheduleId = kTestScheduleId, .taskData = kTestData, .count = -1, .startTimeInEpochSeconds = kTestStartTimeInEpochSeconds, .periodicInSeconds = kTestPeriodicInSeconds, }; ScopedAStatus status = getService()->scheduleTask(scheduleInfo); ASSERT_FALSE(status.isOk()); ASSERT_EQ(status.getExceptionCode(), EX_ILLEGAL_ARGUMENT); } TEST_F(RemoteAccessServiceUnitTest, TestScheduleTask_InvalidStartTimeInEpochSeconds) { ScheduleInfo scheduleInfo = { .clientId = kTestClientId, .scheduleId = kTestScheduleId, .taskData = kTestData, .count = kTestCount, .startTimeInEpochSeconds = -1, .periodicInSeconds = kTestPeriodicInSeconds, }; ScopedAStatus status = getService()->scheduleTask(scheduleInfo); ASSERT_FALSE(status.isOk()); ASSERT_EQ(status.getExceptionCode(), EX_ILLEGAL_ARGUMENT); } TEST_F(RemoteAccessServiceUnitTest, TestScheduleTask_InvalidPeriodicInSeconds) { ScheduleInfo scheduleInfo = { .clientId = kTestClientId, .scheduleId = kTestScheduleId, .taskData = kTestData, .count = kTestCount, .startTimeInEpochSeconds = kTestStartTimeInEpochSeconds, .periodicInSeconds = -1, }; ScopedAStatus status = getService()->scheduleTask(scheduleInfo); ASSERT_FALSE(status.isOk()); ASSERT_EQ(status.getExceptionCode(), EX_ILLEGAL_ARGUMENT); } TEST_F(RemoteAccessServiceUnitTest, TestScheduleTask_TaskDataTooLarge) { ScheduleInfo scheduleInfo = { .clientId = kTestClientId, .scheduleId = kTestScheduleId, .taskData = std::vector(ScheduleInfo::MAX_TASK_DATA_SIZE_IN_BYTES + 1), .count = kTestCount, .startTimeInEpochSeconds = kTestStartTimeInEpochSeconds, .periodicInSeconds = kTestPeriodicInSeconds, }; ScopedAStatus status = getService()->scheduleTask(scheduleInfo); ASSERT_FALSE(status.isOk()); ASSERT_EQ(status.getExceptionCode(), EX_ILLEGAL_ARGUMENT); } TEST_F(RemoteAccessServiceUnitTest, TestScheduleTask_InvalidArgFromGrpcServer) { EXPECT_CALL(*getGrpcWakeupClientStub(), ScheduleTask) .WillOnce([]([[maybe_unused]] ClientContext* context, [[maybe_unused]] const ScheduleTaskRequest& request, ScheduleTaskResponse* response) { response->set_errorcode(ErrorCode::INVALID_ARG); return Status(); }); ScheduleInfo scheduleInfo = { .clientId = kTestClientId, .scheduleId = kTestScheduleId, .taskData = kTestData, .count = kTestCount, .startTimeInEpochSeconds = kTestStartTimeInEpochSeconds, .periodicInSeconds = kTestPeriodicInSeconds, }; ScopedAStatus status = getService()->scheduleTask(scheduleInfo); ASSERT_FALSE(status.isOk()); ASSERT_EQ(status.getExceptionCode(), EX_ILLEGAL_ARGUMENT); } TEST_F(RemoteAccessServiceUnitTest, TestScheduleTask_UnspecifiedError) { EXPECT_CALL(*getGrpcWakeupClientStub(), ScheduleTask) .WillOnce([]([[maybe_unused]] ClientContext* context, [[maybe_unused]] const ScheduleTaskRequest& request, ScheduleTaskResponse* response) { response->set_errorcode(ErrorCode::UNSPECIFIED); return Status(); }); ScheduleInfo scheduleInfo = { .clientId = kTestClientId, .scheduleId = kTestScheduleId, .taskData = kTestData, .count = kTestCount, .startTimeInEpochSeconds = kTestStartTimeInEpochSeconds, .periodicInSeconds = kTestPeriodicInSeconds, }; ScopedAStatus status = getService()->scheduleTask(scheduleInfo); ASSERT_FALSE(status.isOk()); ASSERT_EQ(status.getExceptionCode(), EX_SERVICE_SPECIFIC); } TEST_F(RemoteAccessServiceUnitTest, TestUnscheduleTask) { UnscheduleTaskRequest grpcRequest = {}; EXPECT_CALL(*getGrpcWakeupClientStub(), UnscheduleTask) .WillOnce([&grpcRequest]([[maybe_unused]] ClientContext* context, const UnscheduleTaskRequest& request, [[maybe_unused]] UnscheduleTaskResponse* response) { grpcRequest = request; return Status(); }); ScopedAStatus status = getService()->unscheduleTask(kTestClientId, kTestScheduleId); ASSERT_TRUE(status.isOk()); EXPECT_EQ(grpcRequest.clientid(), kTestClientId); EXPECT_EQ(grpcRequest.scheduleid(), kTestScheduleId); } TEST_F(RemoteAccessServiceUnitTest, TestUnscheduleAllTasks) { UnscheduleAllTasksRequest grpcRequest = {}; EXPECT_CALL(*getGrpcWakeupClientStub(), UnscheduleAllTasks) .WillOnce([&grpcRequest]([[maybe_unused]] ClientContext* context, const UnscheduleAllTasksRequest& request, [[maybe_unused]] UnscheduleAllTasksResponse* response) { grpcRequest = request; return Status(); }); ScopedAStatus status = getService()->unscheduleAllTasks(kTestClientId); ASSERT_TRUE(status.isOk()); EXPECT_EQ(grpcRequest.clientid(), kTestClientId); } TEST_F(RemoteAccessServiceUnitTest, TestIsTaskScheduled) { bool isTaskScheduled = false; IsTaskScheduledRequest grpcRequest = {}; EXPECT_CALL(*getGrpcWakeupClientStub(), IsTaskScheduled) .WillOnce([&grpcRequest]([[maybe_unused]] ClientContext* context, const IsTaskScheduledRequest& request, IsTaskScheduledResponse* response) { grpcRequest = request; response->set_istaskscheduled(true); return Status(); }); ScopedAStatus status = getService()->isTaskScheduled(kTestClientId, kTestScheduleId, &isTaskScheduled); ASSERT_TRUE(status.isOk()); EXPECT_TRUE(isTaskScheduled); EXPECT_EQ(grpcRequest.clientid(), kTestClientId); EXPECT_EQ(grpcRequest.scheduleid(), kTestScheduleId); } TEST_F(RemoteAccessServiceUnitTest, testGetAllPendingScheduledTasks) { std::vector result; GetAllPendingScheduledTasksRequest grpcRequest = {}; EXPECT_CALL(*getGrpcWakeupClientStub(), GetAllPendingScheduledTasks) .WillOnce([&grpcRequest]([[maybe_unused]] ClientContext* context, const GetAllPendingScheduledTasksRequest& request, GetAllPendingScheduledTasksResponse* response) { grpcRequest = request; GrpcScheduleInfo* newInfo = response->add_allscheduledtasks(); newInfo->set_clientid(kTestClientId); newInfo->set_scheduleid(kTestScheduleId); newInfo->set_data(kTestData.data(), kTestData.size()); newInfo->set_count(kTestCount); newInfo->set_starttimeinepochseconds(kTestStartTimeInEpochSeconds); newInfo->set_periodicinseconds(kTestPeriodicInSeconds); return Status(); }); ScopedAStatus status = getService()->getAllPendingScheduledTasks(kTestClientId, &result); ASSERT_TRUE(status.isOk()); EXPECT_EQ(grpcRequest.clientid(), kTestClientId); ASSERT_EQ(result.size(), 1u); ASSERT_EQ(result[0].clientId, kTestClientId); ASSERT_EQ(result[0].scheduleId, kTestScheduleId); ASSERT_EQ(result[0].taskData, kTestData); ASSERT_EQ(result[0].count, kTestCount); ASSERT_EQ(result[0].startTimeInEpochSeconds, kTestStartTimeInEpochSeconds); ASSERT_EQ(result[0].periodicInSeconds, kTestPeriodicInSeconds); } } // namespace remoteaccess } // namespace automotive } // namespace hardware } // namespace android