1 /*
2 * Copyright (C) 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 "clients_test.h"
18
19 #include <gtest/gtest.h>
20
21 #include <string.h>
22 #include <thread>
23
24 #include "chpp/app.h"
25 #include "chpp/clients.h"
26 #include "chpp/macros.h"
27 #include "chpp/memory.h"
28 #include "chpp/platform/utils.h"
29 #include "chpp/services.h"
30 #include "chpp/time.h"
31 #include "chpp/transport.h"
32 #include "chre/pal/wwan.h"
33
34 class ClientsTest : public testing::Test {
35 protected:
SetUp()36 void SetUp() override {
37 chppClearTotalAllocBytes();
38 memset(&mTransportContext.linkParams, 0,
39 sizeof(mTransportContext.linkParams));
40 mTransportContext.linkParams.linkEstablished = true;
41 chppTransportInit(&mTransportContext, &mAppContext);
42 chppAppInit(&mAppContext, &mTransportContext);
43 mClientState =
44 (struct ChppClientState *)mAppContext.registeredClientContexts[0];
45 chppClientInit(mClientState, CHPP_HANDLE_NEGOTIATED_RANGE_START);
46
47 mTransportContext.resetState = CHPP_RESET_STATE_NONE;
48 }
49
TearDown()50 void TearDown() override {
51 chppAppDeinit(&mAppContext);
52 chppTransportDeinit(&mTransportContext);
53
54 EXPECT_EQ(chppGetTotalAllocBytes(), 0);
55 }
56
57 struct ChppTransportState mTransportContext;
58 struct ChppAppState mAppContext;
59 struct ChppClient mClient;
60 struct ChppClientState *mClientState;
61 struct ChppRequestResponseState mRRState;
62 };
63
getClientRRStateInputCheck(struct ChppClientState * clientState,struct ChppAppHeader * header)64 void getClientRRStateInputCheck(struct ChppClientState *clientState,
65 struct ChppAppHeader *header) {
66 ASSERT_TRUE(clientState != NULL);
67 uint8_t clientIdx = clientState->index;
68
69 ASSERT_TRUE(clientState->appContext != NULL);
70 ASSERT_TRUE(clientState->appContext->registeredClients != NULL);
71 ASSERT_TRUE(clientState->appContext->registeredClients[clientIdx] != NULL);
72 ASSERT_TRUE(
73 clientState->appContext->registeredClientStates[clientIdx]->rRStates !=
74 NULL);
75 ASSERT_LT(
76 header->command,
77 clientState->appContext->registeredClients[clientIdx]->rRStateCount);
78 }
79
getClientRRState(struct ChppClientState * clientState,struct ChppAppHeader * header)80 struct ChppRequestResponseState *getClientRRState(
81 struct ChppClientState *clientState, struct ChppAppHeader *header) {
82 getClientRRStateInputCheck(clientState, header);
83
84 uint8_t clientIdx = clientState->index;
85 return &(clientState->appContext->registeredClientStates[clientIdx]
86 ->rRStates[header->command]);
87 }
88
isTimeoutAsExpected(uint64_t timeoutTimeNs,uint64_t expectedTimeNs)89 void isTimeoutAsExpected(uint64_t timeoutTimeNs, uint64_t expectedTimeNs) {
90 uint64_t kJitterNs = 10 * CHPP_NSEC_PER_MSEC;
91
92 if (expectedTimeNs == CHPP_TIME_MAX) {
93 EXPECT_EQ(timeoutTimeNs, expectedTimeNs);
94 } else {
95 EXPECT_GE(timeoutTimeNs, expectedTimeNs);
96 EXPECT_LE(timeoutTimeNs, expectedTimeNs + kJitterNs);
97 }
98 }
99
registerAndValidateRequestForTimeout(struct ChppClientState * clientState,struct ChppAppHeader * header,uint64_t timeoutNs,uint64_t expectedTimeNs)100 void registerAndValidateRequestForTimeout(struct ChppClientState *clientState,
101 struct ChppAppHeader *header,
102 uint64_t timeoutNs,
103 uint64_t expectedTimeNs) {
104 struct ChppRequestResponseState *rRState =
105 getClientRRState(clientState, header);
106 chppClientTimestampRequest(clientState, rRState, header, timeoutNs);
107
108 isTimeoutAsExpected(clientState->appContext->nextRequestTimeoutNs,
109 expectedTimeNs);
110 }
111
registerAndValidateResponseForTimeout(struct ChppClientState * clientState,const struct ChppAppHeader * header,uint64_t expectedTimeNs)112 void registerAndValidateResponseForTimeout(struct ChppClientState *clientState,
113 const struct ChppAppHeader *header,
114 uint64_t expectedTimeNs) {
115 ASSERT_FALSE(clientState == NULL);
116 uint8_t clientIdx = clientState->index;
117
118 ASSERT_FALSE(clientState->appContext == NULL);
119 ASSERT_FALSE(clientState->appContext->registeredClients == NULL);
120 ASSERT_FALSE(clientState->appContext->registeredClients[clientIdx] == NULL);
121 ASSERT_FALSE(
122 clientState->appContext->registeredClientStates[clientIdx]->rRStates ==
123 NULL);
124 ASSERT_LT(
125 header->command,
126 clientState->appContext->registeredClients[clientIdx]->rRStateCount);
127
128 struct ChppRequestResponseState *rRState =
129 &(clientState->appContext->registeredClientStates[clientIdx]
130 ->rRStates[header->command]);
131 chppClientTimestampResponse(clientState, rRState, header);
132
133 isTimeoutAsExpected(clientState->appContext->nextRequestTimeoutNs,
134 expectedTimeNs);
135 }
136
validateTimeoutResponse(const struct ChppAppHeader * request,const struct ChppAppHeader * response)137 void validateTimeoutResponse(const struct ChppAppHeader *request,
138 const struct ChppAppHeader *response) {
139 ASSERT_TRUE(request != NULL);
140 ASSERT_TRUE(response != NULL);
141
142 EXPECT_EQ(response->handle, request->handle);
143 EXPECT_EQ(response->type, CHPP_MESSAGE_TYPE_SERVICE_RESPONSE);
144 EXPECT_EQ(response->transaction, request->transaction);
145 EXPECT_EQ(response->error, CHPP_APP_ERROR_TIMEOUT);
146 EXPECT_EQ(response->command, request->command);
147 }
148
TEST_F(ClientsTest,RequestResponseTimestampValid)149 TEST_F(ClientsTest, RequestResponseTimestampValid) {
150 struct ChppAppHeader *reqHeader =
151 chppAllocClientRequestCommand(mClientState, 0 /* command */);
152 chppClientTimestampRequest(mClientState, &mRRState, reqHeader,
153 CHPP_CLIENT_REQUEST_TIMEOUT_INFINITE);
154
155 struct ChppAppHeader *respHeader =
156 chppAllocServiceResponse(reqHeader, sizeof(*reqHeader));
157 ASSERT_TRUE(chppClientTimestampResponse(mClientState, &mRRState, respHeader));
158
159 chppFree(reqHeader);
160 chppFree(respHeader);
161 }
162
TEST_F(ClientsTest,RequestResponseTimestampDuplicate)163 TEST_F(ClientsTest, RequestResponseTimestampDuplicate) {
164 struct ChppAppHeader *reqHeader =
165 chppAllocClientRequestCommand(mClientState, 0 /* command */);
166 chppClientTimestampRequest(mClientState, &mRRState, reqHeader,
167 CHPP_CLIENT_REQUEST_TIMEOUT_INFINITE);
168
169 struct ChppAppHeader *respHeader =
170 chppAllocServiceResponse(reqHeader, sizeof(*reqHeader));
171 ASSERT_TRUE(chppClientTimestampResponse(mClientState, &mRRState, respHeader));
172 ASSERT_FALSE(
173 chppClientTimestampResponse(mClientState, &mRRState, respHeader));
174
175 chppFree(reqHeader);
176 chppFree(respHeader);
177 }
178
TEST_F(ClientsTest,RequestResponseTimestampInvalidId)179 TEST_F(ClientsTest, RequestResponseTimestampInvalidId) {
180 struct ChppAppHeader *reqHeader =
181 chppAllocClientRequestCommand(mClientState, 0 /* command */);
182 chppClientTimestampRequest(mClientState, &mRRState, reqHeader,
183 CHPP_CLIENT_REQUEST_TIMEOUT_INFINITE);
184
185 struct ChppAppHeader *newReqHeader =
186 chppAllocClientRequestCommand(mClientState, 0 /* command */);
187 struct ChppAppHeader *respHeader =
188 chppAllocServiceResponse(newReqHeader, sizeof(*reqHeader));
189 ASSERT_FALSE(
190 chppClientTimestampResponse(mClientState, &mRRState, respHeader));
191
192 chppFree(reqHeader);
193 chppFree(newReqHeader);
194 chppFree(respHeader);
195 }
196
TEST_F(ClientsTest,RequestTimeoutAddRemoveSingle)197 TEST_F(ClientsTest, RequestTimeoutAddRemoveSingle) {
198 EXPECT_EQ(mAppContext.nextRequestTimeoutNs, CHPP_TIME_MAX);
199
200 struct ChppAppHeader *reqHeader =
201 chppAllocClientRequestCommand(mClientState, 1 /* command */);
202
203 uint64_t time = chppGetCurrentTimeNs();
204 uint64_t timeout = 1000 * CHPP_NSEC_PER_MSEC;
205 registerAndValidateRequestForTimeout(mClientState, reqHeader, timeout,
206 time + timeout);
207
208 EXPECT_TRUE(
209 chppTransportGetClientRequestTimeoutResponse(&mTransportContext) == NULL);
210
211 registerAndValidateResponseForTimeout(mClientState, reqHeader, CHPP_TIME_MAX);
212
213 chppFree(reqHeader);
214 }
215
TEST_F(ClientsTest,RequestTimeoutAddRemoveMultiple)216 TEST_F(ClientsTest, RequestTimeoutAddRemoveMultiple) {
217 struct ChppAppHeader *reqHeader1 =
218 chppAllocClientRequestCommand(mClientState, 0 /* command */);
219 struct ChppAppHeader *reqHeader2 =
220 chppAllocClientRequestCommand(mClientState, 1 /* command */);
221 struct ChppAppHeader *reqHeader3 =
222 chppAllocClientRequestCommand(mClientState, 2 /* command */);
223
224 EXPECT_EQ(mAppContext.nextRequestTimeoutNs, CHPP_TIME_MAX);
225
226 uint64_t time1 = chppGetCurrentTimeNs();
227 uint64_t timeout1 = 2000 * CHPP_NSEC_PER_MSEC;
228 registerAndValidateRequestForTimeout(mClientState, reqHeader1, timeout1,
229 time1 + timeout1);
230
231 uint64_t time2 = chppGetCurrentTimeNs();
232 uint64_t timeout2 = 4000 * CHPP_NSEC_PER_MSEC;
233 registerAndValidateRequestForTimeout(mClientState, reqHeader2, timeout2,
234 time1 + timeout1);
235
236 uint64_t time3 = chppGetCurrentTimeNs();
237 uint64_t timeout3 = 3000 * CHPP_NSEC_PER_MSEC;
238 registerAndValidateRequestForTimeout(mClientState, reqHeader3, timeout3,
239 time1 + timeout1);
240
241 registerAndValidateResponseForTimeout(mClientState, reqHeader1,
242 time3 + timeout3);
243
244 EXPECT_TRUE(
245 chppTransportGetClientRequestTimeoutResponse(&mTransportContext) == NULL);
246
247 uint64_t time4 = chppGetCurrentTimeNs();
248 uint64_t timeout4 = 1000 * CHPP_NSEC_PER_MSEC;
249 registerAndValidateRequestForTimeout(mClientState, reqHeader1, timeout4,
250 time4 + timeout4);
251
252 registerAndValidateResponseForTimeout(mClientState, reqHeader1,
253 time3 + timeout3);
254
255 registerAndValidateResponseForTimeout(mClientState, reqHeader3,
256 time2 + timeout2);
257
258 registerAndValidateResponseForTimeout(mClientState, reqHeader2,
259 CHPP_TIME_MAX);
260
261 EXPECT_TRUE(
262 chppTransportGetClientRequestTimeoutResponse(&mTransportContext) == NULL);
263
264 chppFree(reqHeader1);
265 chppFree(reqHeader2);
266 chppFree(reqHeader3);
267 }
268
TEST_F(ClientsTest,DuplicateRequestTimeoutResponse)269 TEST_F(ClientsTest, DuplicateRequestTimeoutResponse) {
270 EXPECT_EQ(mAppContext.nextRequestTimeoutNs, CHPP_TIME_MAX);
271
272 struct ChppAppHeader *reqHeader =
273 chppAllocClientRequestCommand(mClientState, 1 /* command */);
274
275 uint64_t time1 = chppGetCurrentTimeNs();
276 uint64_t timeout1 = 200 * CHPP_NSEC_PER_MSEC;
277 registerAndValidateRequestForTimeout(mClientState, reqHeader, timeout1,
278 time1 + timeout1);
279
280 std::this_thread::sleep_for(std::chrono::nanoseconds(timeout1 / 2));
281
282 uint64_t time2 = chppGetCurrentTimeNs();
283 uint64_t timeout2 = 200 * CHPP_NSEC_PER_MSEC;
284 registerAndValidateRequestForTimeout(mClientState, reqHeader, timeout2,
285 time2 + timeout2);
286
287 std::this_thread::sleep_for(
288 std::chrono::nanoseconds(timeout1 + time1 - chppGetCurrentTimeNs()));
289 // First request would have timed out but superseded by second request
290 ASSERT_GT(mAppContext.nextRequestTimeoutNs, chppGetCurrentTimeNs());
291
292 std::this_thread::sleep_for(
293 std::chrono::nanoseconds(timeout2 + time2 - chppGetCurrentTimeNs()));
294 // Second request should have timed out
295 ASSERT_LT(mAppContext.nextRequestTimeoutNs, chppGetCurrentTimeNs());
296
297 struct ChppAppHeader *response =
298 chppTransportGetClientRequestTimeoutResponse(&mTransportContext);
299 validateTimeoutResponse(reqHeader, response);
300 if (response != NULL) {
301 chppFree(response);
302 }
303
304 registerAndValidateResponseForTimeout(mClientState, reqHeader, CHPP_TIME_MAX);
305 EXPECT_TRUE(
306 chppTransportGetClientRequestTimeoutResponse(&mTransportContext) == NULL);
307
308 chppFree(reqHeader);
309 }
310
TEST_F(ClientsTest,RequestTimeoutResponse)311 TEST_F(ClientsTest, RequestTimeoutResponse) {
312 EXPECT_EQ(mAppContext.nextRequestTimeoutNs, CHPP_TIME_MAX);
313
314 struct ChppAppHeader *reqHeader1 =
315 chppAllocClientRequestCommand(mClientState, 1 /* command */);
316 struct ChppAppHeader *reqHeader2 =
317 chppAllocClientRequestCommand(mClientState, 2 /* command */);
318
319 uint64_t time1 = chppGetCurrentTimeNs();
320 uint64_t timeout1 = 200 * CHPP_NSEC_PER_MSEC;
321 registerAndValidateRequestForTimeout(mClientState, reqHeader1, timeout1,
322 time1 + timeout1);
323
324 std::this_thread::sleep_for(std::chrono::nanoseconds(timeout1));
325 ASSERT_LT(mAppContext.nextRequestTimeoutNs, chppGetCurrentTimeNs());
326
327 struct ChppAppHeader *response =
328 chppTransportGetClientRequestTimeoutResponse(&mTransportContext);
329 validateTimeoutResponse(reqHeader1, response);
330 if (response != NULL) {
331 chppFree(response);
332 }
333
334 registerAndValidateResponseForTimeout(mClientState, reqHeader1,
335 CHPP_TIME_MAX);
336 EXPECT_TRUE(
337 chppTransportGetClientRequestTimeoutResponse(&mTransportContext) == NULL);
338
339 uint64_t time2 = chppGetCurrentTimeNs();
340 uint64_t timeout2 = 200 * CHPP_NSEC_PER_MSEC;
341 registerAndValidateRequestForTimeout(mClientState, reqHeader2, timeout2,
342 time2 + timeout2);
343
344 std::this_thread::sleep_for(std::chrono::nanoseconds(timeout2));
345 ASSERT_LT(mAppContext.nextRequestTimeoutNs, chppGetCurrentTimeNs());
346
347 response = chppTransportGetClientRequestTimeoutResponse(&mTransportContext);
348 validateTimeoutResponse(reqHeader2, response);
349 if (response != NULL) {
350 chppFree(response);
351 }
352
353 chppFree(reqHeader1);
354 chppFree(reqHeader2);
355 }
356