blob: 11523f69db36c4eb6c7af4102ce35ac21b3e4785 [file] [log] [blame]
Yu Shane2974562022-08-10 18:37:03 -07001/*
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
Yu Shanb138c422022-09-06 19:11:23 -070019#include <aidl/android/hardware/automotive/remoteaccess/ApState.h>
20#include <aidl/android/hardware/automotive/remoteaccess/BnRemoteTaskCallback.h>
Yu Shane2974562022-08-10 18:37:03 -070021#include <gmock/gmock.h>
Yu Shanb138c422022-09-06 19:11:23 -070022#include <grpcpp/test/mock_stream.h>
Yu Shane2974562022-08-10 18:37:03 -070023#include <gtest/gtest.h>
24#include <wakeup_client.grpc.pb.h>
Yu Shanb138c422022-09-06 19:11:23 -070025#include <chrono>
26#include <thread>
Yu Shane2974562022-08-10 18:37:03 -070027
28namespace android {
29namespace hardware {
30namespace automotive {
31namespace remoteaccess {
32
Yu Shanb138c422022-09-06 19:11:23 -070033using ::android::base::ScopedLockAssertion;
34
35using ::aidl::android::hardware::automotive::remoteaccess::ApState;
36using ::aidl::android::hardware::automotive::remoteaccess::BnRemoteTaskCallback;
37
Yu Shane2974562022-08-10 18:37:03 -070038using ::grpc::ClientAsyncReaderInterface;
39using ::grpc::ClientAsyncResponseReaderInterface;
40using ::grpc::ClientContext;
41using ::grpc::ClientReader;
42using ::grpc::ClientReaderInterface;
43using ::grpc::CompletionQueue;
44using ::grpc::Status;
Yu Shanb138c422022-09-06 19:11:23 -070045using ::grpc::testing::MockClientReader;
Yu Shane2974562022-08-10 18:37:03 -070046using ::ndk::ScopedAStatus;
Yu Shanb138c422022-09-06 19:11:23 -070047using ::testing::_;
48using ::testing::DoAll;
49using ::testing::Return;
50using ::testing::SetArgPointee;
Yu Shane2974562022-08-10 18:37:03 -070051
52class MockGrpcClientStub : public WakeupClient::StubInterface {
53 public:
54 MOCK_METHOD(ClientReaderInterface<GetRemoteTasksResponse>*, GetRemoteTasksRaw,
55 (ClientContext * context, const GetRemoteTasksRequest& request));
56 MOCK_METHOD(Status, NotifyWakeupRequired,
57 (ClientContext * context, const NotifyWakeupRequiredRequest& request,
58 NotifyWakeupRequiredResponse* response));
59 // Async methods which we do not care.
60 MOCK_METHOD(ClientAsyncReaderInterface<GetRemoteTasksResponse>*, AsyncGetRemoteTasksRaw,
61 (ClientContext * context, const GetRemoteTasksRequest& request, CompletionQueue* cq,
62 void* tag));
63 MOCK_METHOD(ClientAsyncReaderInterface<GetRemoteTasksResponse>*, PrepareAsyncGetRemoteTasksRaw,
64 (ClientContext * context, const GetRemoteTasksRequest& request,
65 CompletionQueue* cq));
66 MOCK_METHOD(ClientAsyncResponseReaderInterface<NotifyWakeupRequiredResponse>*,
67 AsyncNotifyWakeupRequiredRaw,
68 (ClientContext * context, const NotifyWakeupRequiredRequest& request,
69 CompletionQueue* cq));
70 MOCK_METHOD(ClientAsyncResponseReaderInterface<NotifyWakeupRequiredResponse>*,
71 PrepareAsyncNotifyWakeupRequiredRaw,
72 (ClientContext * context, const NotifyWakeupRequiredRequest& request,
73 CompletionQueue* cq));
74};
75
Yu Shanb138c422022-09-06 19:11:23 -070076class FakeRemoteTaskCallback : public BnRemoteTaskCallback {
77 public:
78 ScopedAStatus onRemoteTaskRequested(const std::string& clientId,
79 const std::vector<uint8_t>& data) override {
80 std::lock_guard<std::mutex> lockGuard(mLock);
81 mDataByClientId[clientId] = data;
82 mTaskCount++;
83 mCv.notify_all();
84 return ScopedAStatus::ok();
85 }
86
87 std::vector<uint8_t> getData(const std::string& clientId) { return mDataByClientId[clientId]; }
88
89 bool wait(size_t taskCount, size_t timeoutInSec) {
90 std::unique_lock<std::mutex> lock(mLock);
91 return mCv.wait_for(lock, std::chrono::seconds(timeoutInSec), [taskCount, this] {
92 ScopedLockAssertion lockAssertion(mLock);
93 return mTaskCount >= taskCount;
94 });
95 }
96
97 private:
98 std::mutex mLock;
99 std::unordered_map<std::string, std::vector<uint8_t>> mDataByClientId GUARDED_BY(mLock);
100 size_t mTaskCount GUARDED_BY(mLock) = 0;
101 std::condition_variable mCv;
102};
103
Yu Shane2974562022-08-10 18:37:03 -0700104class RemoteAccessServiceUnitTest : public ::testing::Test {
105 public:
Yu Shanb138c422022-09-06 19:11:23 -0700106 virtual void SetUp() override {
Yu Shane2974562022-08-10 18:37:03 -0700107 mGrpcWakeupClientStub = std::make_unique<MockGrpcClientStub>();
108 mService = ndk::SharedRefBase::make<RemoteAccessService>(mGrpcWakeupClientStub.get());
109 }
110
111 MockGrpcClientStub* getGrpcWakeupClientStub() { return mGrpcWakeupClientStub.get(); }
112
113 RemoteAccessService* getService() { return mService.get(); }
114
Yu Shanb138c422022-09-06 19:11:23 -0700115 void setRetryWaitInMs(size_t retryWaitInMs) { mService->setRetryWaitInMs(retryWaitInMs); }
116
Yu Shane2974562022-08-10 18:37:03 -0700117 private:
118 std::unique_ptr<MockGrpcClientStub> mGrpcWakeupClientStub;
119 std::shared_ptr<RemoteAccessService> mService;
Yu Shanb138c422022-09-06 19:11:23 -0700120 MockClientReader<GetRemoteTasksResponse>* mMockTaskReader;
Yu Shane2974562022-08-10 18:37:03 -0700121};
122
123TEST_F(RemoteAccessServiceUnitTest, TestGetWakeupServiceName) {
124 std::string serviceName;
125
126 ScopedAStatus status = getService()->getWakeupServiceName(&serviceName);
127
128 EXPECT_TRUE(status.isOk());
129 EXPECT_EQ(serviceName, "com.google.vehicle.wakeup");
130}
131
Yu Shanb138c422022-09-06 19:11:23 -0700132TEST_F(RemoteAccessServiceUnitTest, TestNotifyApStateChangeWakeupRequired) {
133 bool isWakeupRequired = false;
134 EXPECT_CALL(*getGrpcWakeupClientStub(), NotifyWakeupRequired)
135 .WillOnce([&isWakeupRequired]([[maybe_unused]] ClientContext* context,
136 const NotifyWakeupRequiredRequest& request,
137 [[maybe_unused]] NotifyWakeupRequiredResponse* response) {
138 isWakeupRequired = request.iswakeuprequired();
139 return Status();
140 });
141
142 ApState newState = {
143 .isWakeupRequired = true,
144 };
145 ScopedAStatus status = getService()->notifyApStateChange(newState);
146
147 EXPECT_TRUE(status.isOk());
148 EXPECT_TRUE(isWakeupRequired);
149}
150
151TEST_F(RemoteAccessServiceUnitTest, TestGetRemoteTasks) {
152 GetRemoteTasksResponse response1;
153 std::vector<uint8_t> testData = {0xde, 0xad, 0xbe, 0xef};
154 response1.set_clientid("1");
155 response1.set_data(testData.data(), testData.size());
156 GetRemoteTasksResponse response2;
157 response2.set_clientid("2");
158 std::shared_ptr<FakeRemoteTaskCallback> callback =
159 ndk::SharedRefBase::make<FakeRemoteTaskCallback>();
160
161 ON_CALL(*getGrpcWakeupClientStub(), GetRemoteTasksRaw)
162 .WillByDefault(
163 [response1, response2]([[maybe_unused]] ClientContext* context,
164 [[maybe_unused]] const GetRemoteTasksRequest& request) {
165 // mockReader ownership will be transferred to the client so we don't own it
166 // here.
167 MockClientReader<GetRemoteTasksResponse>* mockClientReader =
168 new MockClientReader<GetRemoteTasksResponse>();
169 EXPECT_CALL(*mockClientReader, Finish()).WillOnce(Return(Status::OK));
170 EXPECT_CALL(*mockClientReader, Read(_))
171 .WillOnce(DoAll(SetArgPointee<0>(response1), Return(true)))
172 .WillOnce(DoAll(SetArgPointee<0>(response2), Return(true)))
173 .WillRepeatedly(Return(false));
174 return mockClientReader;
175 });
176
177 getService()->setRemoteTaskCallback(callback);
178 // Start the long live connection to receive tasks.
179 ApState newState = {
180 .isReadyForRemoteTask = true,
181 };
182 ASSERT_TRUE(getService()->notifyApStateChange(newState).isOk());
183
184 ASSERT_TRUE(callback->wait(/*taskCount=*/2, /*timeoutInSec=*/10))
185 << "Did not receive enough tasks";
186 EXPECT_EQ(callback->getData("1"), testData);
187 EXPECT_EQ(callback->getData("2"), std::vector<uint8_t>());
188}
189
190TEST_F(RemoteAccessServiceUnitTest, TestGetRemoteTasksRetryConnection) {
191 GetRemoteTasksResponse response;
192 std::shared_ptr<FakeRemoteTaskCallback> callback =
193 ndk::SharedRefBase::make<FakeRemoteTaskCallback>();
194
195 ON_CALL(*getGrpcWakeupClientStub(), GetRemoteTasksRaw)
196 .WillByDefault([response]([[maybe_unused]] ClientContext* context,
197 [[maybe_unused]] const GetRemoteTasksRequest& request) {
198 // mockReader ownership will be transferred to the client so we don't own it here.
199 MockClientReader<GetRemoteTasksResponse>* mockClientReader =
200 new MockClientReader<GetRemoteTasksResponse>();
201 EXPECT_CALL(*mockClientReader, Finish()).WillOnce(Return(Status::OK));
202 // Connection fails after receiving one task. Should retry after some time.
203 EXPECT_CALL(*mockClientReader, Read(_))
204 .WillOnce(DoAll(SetArgPointee<0>(response), Return(true)))
205 .WillRepeatedly(Return(false));
206 return mockClientReader;
207 });
208
209 getService()->setRemoteTaskCallback(callback);
210 setRetryWaitInMs(100);
211 // Start the long live connection to receive tasks.
212 ApState newState = {
213 .isReadyForRemoteTask = true,
214 };
215 ASSERT_TRUE(getService()->notifyApStateChange(newState).isOk());
216
217 ASSERT_TRUE(callback->wait(/*taskCount=*/2, /*timeoutInSec=*/10))
218 << "Did not receive enough tasks";
219}
220
221TEST_F(RemoteAccessServiceUnitTest, TestGetRemoteTasksDefaultNotReady) {
222 GetRemoteTasksResponse response1;
223 std::vector<uint8_t> testData = {0xde, 0xad, 0xbe, 0xef};
224 response1.set_clientid("1");
225 response1.set_data(testData.data(), testData.size());
226 GetRemoteTasksResponse response2;
227 response2.set_clientid("2");
228 std::shared_ptr<FakeRemoteTaskCallback> callback =
229 ndk::SharedRefBase::make<FakeRemoteTaskCallback>();
230
231 EXPECT_CALL(*getGrpcWakeupClientStub(), GetRemoteTasksRaw).Times(0);
232
233 // Default state is not ready for remote tasks, so no callback will be called.
234 getService()->setRemoteTaskCallback(callback);
235
236 std::this_thread::sleep_for(std::chrono::milliseconds(100));
237}
238
239TEST_F(RemoteAccessServiceUnitTest, TestGetRemoteTasksNotReadyAfterReady) {
240 GetRemoteTasksResponse response1;
241 std::vector<uint8_t> testData = {0xde, 0xad, 0xbe, 0xef};
242 response1.set_clientid("1");
243 response1.set_data(testData.data(), testData.size());
244 GetRemoteTasksResponse response2;
245 response2.set_clientid("2");
246 std::shared_ptr<FakeRemoteTaskCallback> callback =
247 ndk::SharedRefBase::make<FakeRemoteTaskCallback>();
248
249 ON_CALL(*getGrpcWakeupClientStub(), GetRemoteTasksRaw)
250 .WillByDefault(
251 [response1, response2]([[maybe_unused]] ClientContext* context,
252 [[maybe_unused]] const GetRemoteTasksRequest& request) {
253 // mockReader ownership will be transferred to the client so we don't own it
254 // here.
255 MockClientReader<GetRemoteTasksResponse>* mockClientReader =
256 new MockClientReader<GetRemoteTasksResponse>();
257 EXPECT_CALL(*mockClientReader, Finish()).WillOnce(Return(Status::OK));
258 EXPECT_CALL(*mockClientReader, Read(_))
259 .WillOnce(DoAll(SetArgPointee<0>(response1), Return(true)))
260 .WillOnce(DoAll(SetArgPointee<0>(response2), Return(true)))
261 .WillRepeatedly(Return(false));
262 return mockClientReader;
263 });
264 // Should only be called once when is is ready for remote task.
265 EXPECT_CALL(*getGrpcWakeupClientStub(), GetRemoteTasksRaw).Times(1);
266
267 getService()->setRemoteTaskCallback(callback);
268 setRetryWaitInMs(100);
269 // Start the long live connection to receive tasks.
270 ApState newState = {
271 .isReadyForRemoteTask = true,
272 };
273 ASSERT_TRUE(getService()->notifyApStateChange(newState).isOk());
274 ASSERT_TRUE(callback->wait(/*taskCount=*/2, /*timeoutInSec=*/10))
275 << "Did not receive enough tasks";
276
277 // Stop the long live connection.
278 newState.isReadyForRemoteTask = false;
279 ASSERT_TRUE(getService()->notifyApStateChange(newState).isOk());
280
281 // Wait for the retry delay, but the loop should already exit.
282 std::this_thread::sleep_for(std::chrono::milliseconds(150));
283}
284
Yu Shane2974562022-08-10 18:37:03 -0700285} // namespace remoteaccess
286} // namespace automotive
287} // namespace hardware
288} // namespace android