xref: /aosp_15_r20/system/chre/chpp/test/app_req_resp_test.cpp (revision 84e339476a462649f82315436d70fd732297a399)
1 /*
2  * Copyright (C) 2023 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 <gtest/gtest.h>
18 
19 #include <stdbool.h>
20 #include <stddef.h>
21 #include <stdint.h>
22 #include <string.h>
23 #include <cstring>
24 #include <thread>
25 
26 #include "chpp/app.h"
27 #include "chpp/clients.h"
28 #include "chpp/clients/discovery.h"
29 #include "chpp/macros.h"
30 #include "chpp/notifier.h"
31 #include "chpp/platform/platform_link.h"
32 #include "chpp/platform/utils.h"
33 #include "chpp/services.h"
34 #include "chpp/transport.h"
35 #include "chre/util/enum.h"
36 #include "chre/util/time.h"
37 
38 namespace chre {
39 namespace {
40 
41 constexpr uint64_t kResetWaitTimeMs = 5000;
42 constexpr uint64_t kDiscoveryWaitTimeMs = 5000;
43 
workThread(void * transportState)44 void *workThread(void *transportState) {
45   ChppTransportState *state = static_cast<ChppTransportState *>(transportState);
46 
47   auto linkContext =
48       static_cast<struct ChppLinuxLinkState *>(state->linkContext);
49 
50   pthread_setname_np(pthread_self(), linkContext->workThreadName);
51 
52   chppWorkThreadStart(state);
53 
54   return nullptr;
55 }
56 
57 #define TEST_UUID                                                           \
58   {                                                                         \
59     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \
60         0x00, 0x00, 0x00, 0x12                                              \
61   }
62 
63 enum class Commands : uint16_t {
64   kOk,
65   kError,
66   kTimeout,
67   // Number of request, must stay last
68   kNumCommands,
69 };
70 
71 constexpr uint16_t kNumCommands = asBaseType(Commands::kNumCommands);
72 
73 // Common code for the client and the service.
74 
75 struct CommonState {
76   bool okResponseStatus;
77   bool errorResponseStatus;
78   bool timeoutResponseStatus;
79   struct ChppNotifier notifier;
80 };
81 
dispatchResponse(struct ChppAppState * appState,struct ChppOutgoingRequestState * outReqStates,struct CommonState * common,struct ChppAppHeader * response,size_t len)82 enum ChppAppErrorCode dispatchResponse(
83     struct ChppAppState *appState,
84     struct ChppOutgoingRequestState *outReqStates, struct CommonState *common,
85     struct ChppAppHeader *response, size_t len) {
86   // The response is composed of the app header only.
87   if (len != sizeof(ChppAppHeader)) {
88     return CHPP_APP_ERROR_NONE;
89   }
90 
91   switch (response->command) {
92     case asBaseType(Commands::kOk):
93       // The response for the kOk command should have a CHPP_APP_ERROR_NONE
94       // error.
95       common->okResponseStatus = chppTimestampIncomingResponse(
96           appState, &outReqStates[asBaseType(Commands::kOk)], response);
97 
98       common->okResponseStatus &= response->error == CHPP_APP_ERROR_NONE;
99       return CHPP_APP_ERROR_NONE;
100 
101     case asBaseType(Commands::kError):
102       // The response for the kError command should have a
103       // CHPP_APP_ERROR_UNSPECIFIED error.
104       common->errorResponseStatus = chppTimestampIncomingResponse(
105           appState, &outReqStates[asBaseType(Commands::kError)], response);
106 
107       common->errorResponseStatus &=
108           response->error == CHPP_APP_ERROR_UNSPECIFIED;
109       return CHPP_APP_ERROR_NONE;
110 
111     case asBaseType(Commands::kTimeout):
112       // The response for the kTimeout command should have a
113       // CHPP_APP_ERROR_TIMEOUT error. That response is generated by the app
114       // layer.
115       common->timeoutResponseStatus = chppTimestampIncomingResponse(
116           appState, &outReqStates[asBaseType(Commands::kTimeout)], response);
117 
118       common->timeoutResponseStatus &=
119           response->error == CHPP_APP_ERROR_TIMEOUT;
120       chppNotifierSignal(&common->notifier, 1 /*signal*/);
121       return CHPP_APP_ERROR_NONE;
122 
123     default:
124       return CHPP_APP_ERROR_NONE;
125   }
126 }
127 
dispatchRequest(struct ChppAppState * appState,struct ChppIncomingRequestState * inReqStates,struct ChppAppHeader * request,size_t len)128 enum ChppAppErrorCode dispatchRequest(
129     struct ChppAppState *appState, struct ChppIncomingRequestState *inReqStates,
130     struct ChppAppHeader *request, size_t len) {
131   // The request is composed of the app header only.
132   if (len != sizeof(ChppAppHeader)) {
133     return CHPP_APP_ERROR_NONE;
134   }
135 
136   switch (request->command) {
137     case asBaseType(Commands::kOk): {
138       // Return a response for the kOk command.
139       chppTimestampIncomingRequest(&inReqStates[asBaseType(Commands::kOk)],
140                                    request);
141 
142       struct ChppAppHeader *response =
143           chppAllocResponse(request, sizeof(ChppAppHeader));
144 
145       chppSendTimestampedResponseOrFail(appState,
146                                         &inReqStates[asBaseType(Commands::kOk)],
147                                         response, sizeof(ChppAppHeader));
148       return CHPP_APP_ERROR_NONE;
149     }
150     case asBaseType(Commands::kError): {
151       // Return a response with a CHPP_APP_ERROR_UNSPECIFIED error on kError
152       // command.
153       return CHPP_APP_ERROR_UNSPECIFIED;
154     }
155 
156     case asBaseType(Commands::kTimeout): {
157       // Do not send a response on kTimeout for the remote endpoint to timeout.
158       chppTimestampIncomingRequest(&inReqStates[asBaseType(Commands::kError)],
159                                    request);
160 
161       return CHPP_APP_ERROR_NONE;
162     }
163 
164     default:
165       return CHPP_APP_ERROR_NONE;
166   }
167 }
168 
169 // Client specific code.
170 struct ClientState {
171   struct ChppEndpointState chppClientState;
172   struct ChppOutgoingRequestState outReqStates[kNumCommands];
173   struct ChppIncomingRequestState inReqStates[kNumCommands];
174   struct CommonState common;
175 };
176 
177 bool clientInit(void *clientState, uint8_t handle,
178                 struct ChppVersion serviceVersion);
179 void clientDeinit(void *clientState);
180 enum ChppAppErrorCode clientDispatchResponse(void *clientState, uint8_t *buf,
181                                              size_t len);
182 enum ChppAppErrorCode clientDispatchRequest(void *clientState, uint8_t *buf,
183                                             size_t len);
184 
185 constexpr struct ChppClient kClient = {
186     .descriptor.uuid = TEST_UUID,
187     .descriptor.version.major = 1,
188     .descriptor.version.minor = 0,
189     .descriptor.version.patch = 0,
190     .resetNotifierFunctionPtr = nullptr,
191     .matchNotifierFunctionPtr = nullptr,
192     .responseDispatchFunctionPtr = &clientDispatchResponse,
193     .notificationDispatchFunctionPtr = nullptr,
194     .requestDispatchFunctionPtr = &clientDispatchRequest,
195     .initFunctionPtr = &clientInit,
196     .deinitFunctionPtr = &clientDeinit,
197     .outReqCount = kNumCommands,
198     .minLength = sizeof(struct ChppAppHeader),
199 };
200 
201 // Called when a response is received from the service.
clientDispatchResponse(void * clientState,uint8_t * buf,size_t len)202 enum ChppAppErrorCode clientDispatchResponse(void *clientState, uint8_t *buf,
203                                              size_t len) {
204   CHPP_NOT_NULL(clientState);
205 
206   auto state = static_cast<struct ClientState *>(clientState);
207 
208   return dispatchResponse(state->chppClientState.appContext,
209                           state->outReqStates, &state->common,
210                           reinterpret_cast<struct ChppAppHeader *>(buf), len);
211 }
212 
213 // Called when a request is received from the service.
clientDispatchRequest(void * clientState,uint8_t * buf,size_t len)214 enum ChppAppErrorCode clientDispatchRequest(void *clientState, uint8_t *buf,
215                                             size_t len) {
216   auto request = reinterpret_cast<struct ChppAppHeader *>(buf);
217   auto state = static_cast<struct ClientState *>(clientState);
218 
219   return dispatchRequest(state->chppClientState.appContext, state->inReqStates,
220                          request, len);
221 }
222 
clientInit(void * clientState,uint8_t handle,struct ChppVersion serviceVersion)223 bool clientInit(void *clientState, uint8_t handle,
224                 struct ChppVersion serviceVersion) {
225   UNUSED_VAR(serviceVersion);
226   auto state = static_cast<struct ClientState *>(clientState);
227   state->chppClientState.openState = CHPP_OPEN_STATE_OPENED;
228   chppClientInit(&state->chppClientState, handle);
229   return true;
230 }
231 
clientDeinit(void * clientState)232 void clientDeinit(void *clientState) {
233   auto state = static_cast<struct ClientState *>(clientState);
234   chppClientDeinit(&state->chppClientState);
235   state->chppClientState.openState = CHPP_OPEN_STATE_CLOSED;
236 }
237 
238 // Service specific code.
239 
240 struct ServiceState {
241   struct ChppEndpointState chppServiceState;
242   struct ChppOutgoingRequestState outReqStates[kNumCommands];
243   struct ChppIncomingRequestState inReqStates[kNumCommands];
244   struct CommonState common;
245 };
246 
247 // Called when a request is received from the client.
serviceDispatchRequest(void * serviceState,uint8_t * buf,size_t len)248 enum ChppAppErrorCode serviceDispatchRequest(void *serviceState, uint8_t *buf,
249                                              size_t len) {
250   auto request = reinterpret_cast<struct ChppAppHeader *>(buf);
251   auto state = static_cast<struct ServiceState *>(serviceState);
252 
253   return dispatchRequest(state->chppServiceState.appContext, state->inReqStates,
254                          request, len);
255 }
256 
257 // Called when a response is received from the client.
serviceDispatchResponse(void * serviceState,uint8_t * buf,size_t len)258 enum ChppAppErrorCode serviceDispatchResponse(void *serviceState, uint8_t *buf,
259                                               size_t len) {
260   CHPP_NOT_NULL(serviceState);
261 
262   auto state = static_cast<struct ServiceState *>(serviceState);
263 
264   return dispatchResponse(state->chppServiceState.appContext,
265                           state->outReqStates, &state->common,
266                           reinterpret_cast<struct ChppAppHeader *>(buf), len);
267 }
268 
269 const struct ChppService kService = {
270     .descriptor.uuid = TEST_UUID,
271     .descriptor.name = "Test",
272     .descriptor.version.major = 1,
273     .descriptor.version.minor = 0,
274     .descriptor.version.patch = 0,
275     .resetNotifierFunctionPtr = nullptr,
276     .requestDispatchFunctionPtr = &serviceDispatchRequest,
277     .notificationDispatchFunctionPtr = nullptr,
278     .responseDispatchFunctionPtr = &serviceDispatchResponse,
279     .outReqCount = kNumCommands,
280     .minLength = sizeof(struct ChppAppHeader),
281 };
282 
283 /**
284  * Test requests and responses.
285  *
286  * The test parameter is:
287  * - CHPP_MESSAGE_TYPE_CLIENT_REQUEST for client side requests
288  * - CHPP_MESSAGE_TYPE_SERVICE_REQUEST for service side requests
289  */
290 class AppReqRespParamTest : public testing::TestWithParam<ChppMessageType> {
291  protected:
SetUp()292   void SetUp() {
293     chppClearTotalAllocBytes();
294     chppNotifierInit(&mClientState.common.notifier);
295     chppNotifierInit(&mServiceState.common.notifier);
296     memset(&mClientLinkState, 0, sizeof(mClientLinkState));
297     memset(&mServiceLinkState, 0, sizeof(mServiceLinkState));
298 
299     mServiceLinkState.linkThreadName = "Service Link";
300     mServiceLinkState.workThreadName = "Service worker";
301     mServiceLinkState.isLinkActive = true;
302     mServiceLinkState.remoteLinkState = &mClientLinkState;
303     mServiceLinkState.rxInRemoteEndpointWorker = false;
304 
305     mClientLinkState.linkThreadName = "Client Link";
306     mClientLinkState.workThreadName = "Client worker";
307     mClientLinkState.isLinkActive = true;
308     mClientLinkState.remoteLinkState = &mServiceLinkState;
309     mClientLinkState.rxInRemoteEndpointWorker = false;
310 
311     // No default clients/services.
312     struct ChppClientServiceSet set;
313     memset(&set, 0, sizeof(set));
314 
315     const struct ChppLinkApi *linkApi = getLinuxLinkApi();
316 
317     // Init client side.
318     chppTransportInit(&mClientTransportState, &mClientAppState,
319                       &mClientLinkState, linkApi);
320     chppAppInitWithClientServiceSet(&mClientAppState, &mClientTransportState,
321                                     set);
322 
323     // Init service side.
324     chppTransportInit(&mServiceTransportState, &mServiceAppState,
325                       &mServiceLinkState, linkApi);
326     chppAppInitWithClientServiceSet(&mServiceAppState, &mServiceTransportState,
327                                     set);
328 
329     BringUpClient();
330     std::this_thread::sleep_for(std::chrono::milliseconds(450));
331     BringUpService();
332     mClientLinkState.linkEstablished = true;
333     mServiceLinkState.linkEstablished = true;
334 
335     EXPECT_TRUE(chppTransportWaitForResetComplete(&mClientTransportState,
336                                                   kResetWaitTimeMs));
337     EXPECT_TRUE(chppTransportWaitForResetComplete(&mServiceTransportState,
338                                                   kResetWaitTimeMs));
339 
340     EXPECT_TRUE(
341         chppWaitForDiscoveryComplete(&mClientAppState, kDiscoveryWaitTimeMs));
342     EXPECT_TRUE(
343         chppWaitForDiscoveryComplete(&mServiceAppState, kDiscoveryWaitTimeMs));
344   }
345 
BringUpClient()346   void BringUpClient() {
347     memset(&mClientState, 0, sizeof(mClientState));
348     chppRegisterClient(&mClientAppState, &mClientState,
349                        &mClientState.chppClientState,
350                        &mClientState.outReqStates[0], &kClient);
351 
352     pthread_create(&mClientWorkThread, NULL, workThread,
353                    &mClientTransportState);
354   }
355 
BringUpService()356   void BringUpService() {
357     memset(&mServiceState, 0, sizeof(mServiceState));
358     chppRegisterService(&mServiceAppState, &mServiceState,
359                         &mServiceState.chppServiceState,
360                         &mServiceState.outReqStates[0], &kService);
361 
362     pthread_create(&mServiceWorkThread, NULL, workThread,
363                    &mServiceTransportState);
364   }
365 
TearDown()366   void TearDown() {
367     chppNotifierDeinit(&mClientState.common.notifier);
368     chppNotifierDeinit(&mServiceState.common.notifier);
369     chppWorkThreadStop(&mClientTransportState);
370     chppWorkThreadStop(&mServiceTransportState);
371     pthread_join(mClientWorkThread, NULL);
372     pthread_join(mServiceWorkThread, NULL);
373 
374     // Deinit client side.
375     chppAppDeinit(&mClientAppState);
376     chppTransportDeinit(&mClientTransportState);
377 
378     // Deinit service side.
379     chppAppDeinit(&mServiceAppState);
380     chppTransportDeinit(&mServiceTransportState);
381 
382     EXPECT_EQ(chppGetTotalAllocBytes(), 0);
383   }
384 
AllocRequestCommand(Commands command)385   struct ChppAppHeader *AllocRequestCommand(Commands command) {
386     return GetParam() == CHPP_MESSAGE_TYPE_CLIENT_REQUEST
387                ? chppAllocClientRequestCommand(&mClientState.chppClientState,
388                                                asBaseType(command))
389                : chppAllocServiceRequestCommand(&mServiceState.chppServiceState,
390                                                 asBaseType(command));
391   }
392 
GetCommonState()393   struct CommonState *GetCommonState() {
394     return GetParam() == CHPP_MESSAGE_TYPE_CLIENT_REQUEST
395                ? &mClientState.common
396                : &mServiceState.common;
397   }
398 
SendTimestampedRequestAndWait(struct ChppAppHeader * request)399   bool SendTimestampedRequestAndWait(struct ChppAppHeader *request) {
400     constexpr size_t len = sizeof(struct ChppAppHeader);
401     if (request->type == CHPP_MESSAGE_TYPE_CLIENT_REQUEST) {
402       return chppClientSendTimestampedRequestAndWait(
403           &mClientState.chppClientState,
404           &mClientState.outReqStates[request->command], request, len);
405     }
406 
407     return chppServiceSendTimestampedRequestAndWait(
408         &mServiceState.chppServiceState,
409         &mServiceState.outReqStates[request->command], request, len);
410   }
411 
SendTimestampedRequestOrFail(struct ChppAppHeader * request,uint64_t timeoutNs)412   bool SendTimestampedRequestOrFail(struct ChppAppHeader *request,
413                                     uint64_t timeoutNs) {
414     constexpr size_t len = sizeof(struct ChppAppHeader);
415     if (request->type == CHPP_MESSAGE_TYPE_CLIENT_REQUEST) {
416       return chppClientSendTimestampedRequestOrFail(
417           &mClientState.chppClientState,
418           &mClientState.outReqStates[request->command], request, len,
419           timeoutNs);
420     }
421 
422     return chppServiceSendTimestampedRequestOrFail(
423         &mServiceState.chppServiceState,
424         &mServiceState.outReqStates[request->command], request, len, timeoutNs);
425   }
426 
427   // Client side.
428   ChppLinuxLinkState mClientLinkState = {};
429   ChppTransportState mClientTransportState = {};
430   ChppAppState mClientAppState = {};
431   ClientState mClientState;
432   pthread_t mClientWorkThread;
433 
434   // Service side
435   ChppLinuxLinkState mServiceLinkState = {};
436   ChppTransportState mServiceTransportState = {};
437   ChppAppState mServiceAppState = {};
438   ServiceState mServiceState = {};
439   pthread_t mServiceWorkThread;
440 };
441 
TEST_P(AppReqRespParamTest,sendsRequestAndReceiveResponse)442 TEST_P(AppReqRespParamTest, sendsRequestAndReceiveResponse) {
443   struct ChppAppHeader *request = AllocRequestCommand(Commands::kOk);
444   ASSERT_NE(request, nullptr);
445 
446   GetCommonState()->okResponseStatus = false;
447 
448   EXPECT_TRUE(SendTimestampedRequestAndWait(request));
449 
450   EXPECT_TRUE(GetCommonState()->okResponseStatus);
451 }
452 
TEST_P(AppReqRespParamTest,sendsRequestAndReceiveErrorResponse)453 TEST_P(AppReqRespParamTest, sendsRequestAndReceiveErrorResponse) {
454   struct ChppAppHeader *request = AllocRequestCommand(Commands::kError);
455   ASSERT_NE(request, nullptr);
456 
457   GetCommonState()->errorResponseStatus = false;
458 
459   EXPECT_TRUE(SendTimestampedRequestAndWait(request));
460 
461   EXPECT_TRUE(GetCommonState()->errorResponseStatus);
462 }
463 
TEST_P(AppReqRespParamTest,sendsRequestAndReceiveTimeoutResponse)464 TEST_P(AppReqRespParamTest, sendsRequestAndReceiveTimeoutResponse) {
465   struct ChppAppHeader *request = AllocRequestCommand(Commands::kTimeout);
466   ASSERT_NE(request, nullptr);
467 
468   GetCommonState()->timeoutResponseStatus = false;
469 
470   EXPECT_TRUE(
471       SendTimestampedRequestOrFail(request, 10 * kOneMicrosecondInNanoseconds));
472 
473   chppNotifierWait(&GetCommonState()->notifier);
474 
475   EXPECT_TRUE(GetCommonState()->timeoutResponseStatus);
476 }
477 
478 INSTANTIATE_TEST_SUITE_P(
479     AppReqRespTest, AppReqRespParamTest,
480     testing::Values(CHPP_MESSAGE_TYPE_CLIENT_REQUEST,
481                     CHPP_MESSAGE_TYPE_SERVICE_REQUEST),
__anonbd6951b40202(const testing::TestParamInfo<AppReqRespParamTest::ParamType> &info) 482     [](const testing::TestParamInfo<AppReqRespParamTest::ParamType> &info) {
483       return info.param == CHPP_MESSAGE_TYPE_CLIENT_REQUEST ? "ClientRequests"
484                                                             : "ServiceRequests";
485     });
486 
487 }  // namespace
488 }  // namespace chre