• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2018 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 <vector>
18 
19 #include <gmock/gmock.h>
20 
21 #include <application.h>
22 #include <nos/transport.h>
23 
24 #include "crc16.h"
25 
26 using ::testing::_;
27 using ::testing::Args;
28 using ::testing::DoAll;
29 using ::testing::Eq;
30 using ::testing::ElementsAreArray;
31 using ::testing::InSequence;
32 using ::testing::IsNull;
33 using ::testing::Return;
34 using ::testing::SetArrayArgument;
35 using ::testing::StrictMock;
36 
37 namespace {
38 
39 struct Device {
40   virtual int Read(uint32_t command, uint8_t* buf, uint32_t len) = 0;
41   virtual int Write(uint32_t command, const uint8_t* buf, uint32_t len) = 0;
42   virtual int WaitForInterrupt(int msecs) = 0;
43   virtual int Reset() = 0;
44 };
45 
46 struct MockDevice : public Device {
47   MOCK_METHOD3(Read, int(uint32_t command, uint8_t* buf, uint32_t len));
48   MOCK_METHOD3(Write, int(uint32_t command, const uint8_t* buf, uint32_t len));
49   MOCK_METHOD1(WaitForInterrupt, int(int msecs));
50   MOCK_METHOD0(Reset, int());
51 };
52 
53 // We want to closely examine the interactions with the device to make it a
54 // strict mock
55 using CtxType = StrictMock<MockDevice>;
56 
57 // Forward calls onto the mock
read_datagram(void * ctx,uint32_t command,uint8_t * buf,uint32_t len)58 int read_datagram(void* ctx, uint32_t command, uint8_t* buf, uint32_t len) {
59   return reinterpret_cast<CtxType*>(ctx)->Read(command, buf, len);
60 }
write_datagram(void * ctx,uint32_t command,const uint8_t * buf,uint32_t len)61 int write_datagram(void* ctx, uint32_t command, const uint8_t* buf, uint32_t len) {
62   return reinterpret_cast<CtxType*>(ctx)->Write(command, buf, len);
63 }
wait_for_interrupt(void * ctx,int msecs)64 int wait_for_interrupt(void* ctx, int msecs) {
65   return reinterpret_cast<CtxType*>(ctx)->WaitForInterrupt(msecs);
66 }
reset(void * ctx)67 int reset(void* ctx) {
68   return reinterpret_cast<CtxType*>(ctx)->Reset();
69 }
close_device(void * ctx)70 void close_device(void* ctx) {
71   delete reinterpret_cast<CtxType*>(ctx);
72 }
73 
74 // Implement the datagram API that calls a mock.
75 extern "C" {
nos_device_open(const char * device_name,struct nos_device * dev)76 int nos_device_open(const char* device_name, struct nos_device* dev) {
77   EXPECT_THAT(device_name, IsNull());
78   dev->ctx = new CtxType;
79   dev->ops.read = read_datagram;
80   dev->ops.write = write_datagram;
81   dev->ops.wait_for_interrupt = wait_for_interrupt;
82   dev->ops.reset = reset;
83   dev->ops.close = close_device;
84   return 0;
85 }
86 }
87 
88 // Test fixture that sets up the mocked device.
89 struct TransportTest : public ::testing::Test {
SetUp__anonb1b6e5140111::TransportTest90   virtual void SetUp() override {
91     nos_device_open(nullptr, &dev_);
92     mock_dev_ = reinterpret_cast<CtxType*>(dev_.ctx);
93   }
TearDown__anonb1b6e5140111::TransportTest94   virtual void TearDown() override {
95     dev_.ops.close(dev_.ctx);
96   }
97 
dev__anonb1b6e5140111::TransportTest98   nos_device* dev() { return &dev_; }
mock_dev__anonb1b6e5140111::TransportTest99   CtxType& mock_dev() { return *mock_dev_; }
100 
101 private:
102   nos_device dev_;
103   CtxType* mock_dev_;
104 };
105 
command_crc(uint32_t command,const uint8_t * args,uint16_t args_len,const transport_command_info * command_info)106 uint16_t command_crc(uint32_t command, const uint8_t* args, uint16_t args_len,
107                      const transport_command_info* command_info) {
108   uint16_t crc = crc16(&args_len, sizeof(args_len));
109   crc = crc16_update(args, args_len, crc);
110   crc = crc16_update(&command, sizeof(command), crc);
111   crc = crc16_update(command_info, sizeof(*command_info), crc);
112   return htole16(crc);
113 }
114 
115 } // namespace
116 
117 /* Actions to return mock data */
118 
119 #define READ_UNSET 0xdf
120 
ACTION(ReadStatusV0_Idle)121 ACTION(ReadStatusV0_Idle) {
122   transport_status* status = (transport_status*)arg1;
123   memset(status, READ_UNSET, sizeof(*status));
124   status->status = APP_STATUS_IDLE;
125   status->reply_len = 0;
126 }
127 
ACTION(ReadStatusV1_Idle)128 ACTION(ReadStatusV1_Idle) {
129   transport_status* status = (transport_status*)arg1;
130   memset(status, READ_UNSET, sizeof(*status));
131   status->status = APP_STATUS_IDLE;
132   status->reply_len = 0;
133   status->length = sizeof(transport_status);
134   status->version = TRANSPORT_V1;
135   status->flags = 0;
136   status->crc = STATUS_CRC_FOR_IDLE;
137   status->reply_crc = 0;
138 }
139 
ACTION(ReadStatusV1_IdleWithBadCrc)140 ACTION(ReadStatusV1_IdleWithBadCrc) {
141   transport_status* status = (transport_status*)arg1;
142   memset(status, READ_UNSET, sizeof(*status));
143   status->status = APP_STATUS_IDLE;
144   status->reply_len = 0;
145   status->length = sizeof(transport_status);
146   status->version = TRANSPORT_V1;
147   status->flags = 0;
148   status->crc = STATUS_CRC_FOR_IDLE + 1; // <- wrong!
149   status->reply_crc = 0;
150 }
151 
ACTION(ReadStatusV1_Working)152 ACTION(ReadStatusV1_Working) {
153   transport_status* status = (transport_status*)arg1;
154   memset(status, READ_UNSET, sizeof(*status));
155   status->status = APP_STATUS_IDLE;
156   status->reply_len = 0;
157   status->length = sizeof(transport_status);
158   status->version = TRANSPORT_V1;
159   status->flags = STATUS_FLAG_WORKING;
160   status->crc = STATUS_CRC_FOR_WORKING;
161   status->reply_crc = 0;
162 }
163 
ACTION_P(ReadStatusV0_DoneWithData,reply_len)164 ACTION_P(ReadStatusV0_DoneWithData, reply_len) {
165   transport_status* status = (transport_status*)arg1;
166   memset(status, READ_UNSET, sizeof(*status));
167   status->status = APP_STATUS_DONE | APP_SUCCESS;
168   status->reply_len = reply_len;
169 }
170 
ACTION_P2(ReadStatusV1_DoneWithData,reply,reply_len)171 ACTION_P2(ReadStatusV1_DoneWithData, reply, reply_len) {
172   transport_status* status = (transport_status*)arg1;
173   memset(status, READ_UNSET, sizeof(*status));
174   status->status = APP_STATUS_DONE | APP_SUCCESS;
175   status->reply_len = reply_len;
176   status->length = sizeof(transport_status);
177   status->version = TRANSPORT_V1;
178   status->flags = 0;
179   status->reply_crc = crc16(reply, reply_len);
180   status->crc = 0;
181   status->crc = crc16(status, status->length);
182 }
183 
ACTION(ReadStatusV1_BadCrc)184 ACTION(ReadStatusV1_BadCrc) {
185   transport_status* status = (transport_status*)arg1;
186   memset(status, READ_UNSET, sizeof(*status));
187   status->status = APP_STATUS_DONE | APP_ERROR_CHECKSUM;
188   status->reply_len = 0;
189   status->length = sizeof(transport_status);
190   status->version = TRANSPORT_V1;
191   status->flags = 0;
192   status->crc = 0x92c0;
193   status->reply_crc = 0;
194 }
195 
ACTION(ReadStatusV42_Working)196 ACTION(ReadStatusV42_Working) {
197   memset(arg1, 0xb3, STATUS_MAX_LENGTH);
198   transport_status* status = (transport_status*)arg1;
199   status->status = APP_STATUS_IDLE;
200   status->reply_len = 0;
201   status->length = STATUS_MAX_LENGTH;
202   status->version = 42;
203   status->flags = STATUS_FLAG_WORKING;
204   status->crc = 0xaec0;
205   status->reply_crc = 0;
206 }
207 
ACTION_P3(ReadData,len,data,size)208 ACTION_P3(ReadData, len, data, size) {
209   memset(arg1, READ_UNSET, len);
210   memcpy(arg1, data, size);
211 }
212 
213 /* Helper macros to expect datagram calls */
214 
215 #define EXPECT_GET_STATUS_V0_IDLE(app_id) do { \
216   const uint32_t command = CMD_ID((app_id)) | CMD_IS_READ | CMD_TRANSPORT; \
217   EXPECT_CALL(mock_dev(), Read(command, _, STATUS_MAX_LENGTH)) \
218       .WillOnce(DoAll(ReadStatusV0_Idle(), Return(0))); \
219 } while (0)
220 
221 #define EXPECT_GET_STATUS_IDLE(app_id) do { \
222   const uint32_t command = CMD_ID((app_id)) | CMD_IS_READ | CMD_TRANSPORT; \
223   EXPECT_CALL(mock_dev(), Read(command, _, STATUS_MAX_LENGTH)) \
224       .WillOnce(DoAll(ReadStatusV1_Idle(), Return(0))); \
225 } while (0)
226 
227 #define EXPECT_GET_STATUS_IDLE_WITH_BAD_CRC(app_id) do { \
228   const uint32_t command = CMD_ID((app_id)) | CMD_IS_READ | CMD_TRANSPORT; \
229   EXPECT_CALL(mock_dev(), Read(command, _, STATUS_MAX_LENGTH)) \
230       .WillOnce(DoAll(ReadStatusV1_IdleWithBadCrc(), Return(0))); \
231 } while (0)
232 
233 #define EXPECT_GET_STATUS_BAD_CRC(app_id) do { \
234   const uint32_t command = CMD_ID((app_id)) | CMD_IS_READ | CMD_TRANSPORT; \
235   EXPECT_CALL(mock_dev(), Read(command, _, STATUS_MAX_LENGTH)) \
236       .WillOnce(DoAll(ReadStatusV1_BadCrc(), Return(0))); \
237 } while (0)
238 
239 #define EXPECT_GET_STATUS_WORKING(app_id) do { \
240   const uint32_t command = CMD_ID((app_id)) | CMD_IS_READ | CMD_TRANSPORT; \
241   EXPECT_CALL(mock_dev(), Read(command, _, STATUS_MAX_LENGTH)) \
242       .WillOnce(DoAll(ReadStatusV1_Working(), Return(0))); \
243 } while (0)
244 
245 #define EXPECT_GET_STATUS_V0_DONE(app_id) do { \
246   const uint32_t command = CMD_ID((app_id)) | CMD_IS_READ | CMD_TRANSPORT; \
247   EXPECT_CALL(mock_dev(), Read(command, _, STATUS_MAX_LENGTH)) \
248       .WillOnce(DoAll(ReadStatusV0_DoneWithData(0), Return(0))); \
249 } while (0)
250 
251 #define EXPECT_GET_STATUS_V0_DONE_WITH_DATA(app_id, reply_len) do { \
252   const uint32_t command = CMD_ID((app_id)) | CMD_IS_READ | CMD_TRANSPORT; \
253   EXPECT_CALL(mock_dev(), Read(command, _, STATUS_MAX_LENGTH)) \
254       .WillOnce(DoAll(ReadStatusV0_DoneWithData((reply_len)), Return(0))); \
255 } while (0)
256 
257 #define EXPECT_GET_STATUS_DONE(app_id) do { \
258   const uint32_t command = CMD_ID((app_id)) | CMD_IS_READ | CMD_TRANSPORT; \
259   EXPECT_CALL(mock_dev(), Read(command, _, STATUS_MAX_LENGTH)) \
260       .WillOnce(DoAll(ReadStatusV1_DoneWithData(nullptr, 0), Return(0))); \
261 } while (0)
262 
263 #define EXPECT_GET_STATUS_DONE_WITH_DATA(app_id, reply, reply_len) do { \
264   const uint32_t command = CMD_ID((app_id)) | CMD_IS_READ | CMD_TRANSPORT; \
265   EXPECT_CALL(mock_dev(), Read(command, _, STATUS_MAX_LENGTH)) \
266       .WillOnce(DoAll(ReadStatusV1_DoneWithData((reply), (reply_len)), Return(0))); \
267 } while (0)
268 
269 #define EXPECT_GET_STATUS_DONE_BAD_CRC(app_id, reply, reply_len) do { \
270   const uint32_t command = CMD_ID((app_id)) | CMD_IS_READ | CMD_TRANSPORT; \
271   EXPECT_CALL(mock_dev(), Read(command, _, STATUS_MAX_LENGTH)) \
272       .WillOnce(DoAll(ReadStatusV1_DoneBadCrc((reply), (reply_len)), Return(0))); \
273 } while (0)
274 
275 #define EXPECT_SEND_DATA(app_id, args, args_len) do { \
276   const uint32_t command = CMD_ID((app_id)) | CMD_IS_DATA | CMD_TRANSPORT | CMD_PARAM((args_len)); \
277   EXPECT_CALL(mock_dev(), Write(command, _, (args_len))) \
278       .With(Args<1,2>(ElementsAreArray((uint8_t*)(args), (args_len)))) \
279       .WillOnce(Return(0)); \
280 } while (0)
281 
282 #define EXPECT_GO_COMMAND(app_id, param, args, args_len, reply_len) do { \
283   const uint32_t command = CMD_ID((app_id)) | CMD_PARAM((param)); \
284   transport_command_info command_info = {}; \
285   command_info.length = sizeof(command_info); \
286   command_info.version = htole16(TRANSPORT_V1); \
287   command_info.reply_len_hint = htole16((reply_len)); \
288   command_info.crc = command_crc(command, (args), (args_len), &command_info); \
289   EXPECT_CALL(mock_dev(), Write(command, _, command_info.length)) \
290       .With(Args<1,2>(ElementsAreArray((uint8_t*)&command_info, command_info.length))) \
291       .WillOnce(Return(0)); \
292 } while (0)
293 
294 #define EXPECT_RECV_DATA(app_id, len, reply, reply_len) do { \
295   const uint32_t command = CMD_ID((app_id)) | CMD_IS_READ | CMD_IS_DATA | CMD_TRANSPORT; \
296   EXPECT_CALL(mock_dev(), Read(command, _, (reply_len))) \
297       .WillOnce(DoAll(ReadData((len), (reply), (reply_len)), Return(0))); \
298 } while (0)
299 
300 #define EXPECT_RECV_MORE_DATA(app_id, len, reply, reply_len) do { \
301   const uint32_t command = \
302       CMD_ID((app_id)) | CMD_IS_READ | CMD_IS_DATA | CMD_MORE_TO_COME | CMD_TRANSPORT; \
303   EXPECT_CALL(mock_dev(), Read(command, _, (reply_len))) \
304       .WillOnce(DoAll(ReadData((len), (reply), (reply_len)), Return(0))); \
305 } while (0)
306 
307 #define EXPECT_CLEAR_STATUS(app_id) do { \
308   const uint32_t command = CMD_ID((app_id)) | CMD_TRANSPORT; \
309   EXPECT_CALL(mock_dev(), Write(command, _, 0)) \
310       .WillOnce(Return(0)); \
311 } while (0)
312 
313 /* Protocol tests */
314 
TEST_F(TransportTest,WorkingAppIsBusy)315 TEST_F(TransportTest, WorkingAppIsBusy) {
316   const uint8_t app_id = 213;
317   EXPECT_GET_STATUS_WORKING(app_id);
318 
319   const uint16_t param = 2;
320   uint32_t reply_len = 0;
321   uint32_t res = nos_call_application(dev(), app_id, param, nullptr, 0, nullptr, &reply_len);
322   EXPECT_THAT(res, Eq(APP_ERROR_BUSY));
323 }
324 
TEST_F(TransportTest,WorkingIsForwardCompatible)325 TEST_F(TransportTest, WorkingIsForwardCompatible) {
326   const uint8_t app_id = 25;
327   const uint32_t command = CMD_ID(app_id) | CMD_IS_READ | CMD_TRANSPORT;
328   EXPECT_CALL(mock_dev(), Read(command, _, STATUS_MAX_LENGTH))
329       .WillOnce(DoAll(ReadStatusV42_Working(), Return(0)));
330 
331   const uint16_t param = 2;
332   uint32_t reply_len = 0;
333   uint32_t res = nos_call_application(dev(), app_id, param, nullptr, 0, nullptr, &reply_len);
334   EXPECT_THAT(res, Eq(APP_ERROR_BUSY));
335 }
336 
TEST_F(TransportTest,SuccessIfStatusNotClear)337 TEST_F(TransportTest, SuccessIfStatusNotClear) {
338   const uint8_t app_id = 12;
339   const uint16_t param = 2;
340   const uint8_t args[] = {1, 2, 3};
341   const uint16_t args_len = 3;
342 
343   InSequence please;
344   EXPECT_GET_STATUS_BAD_CRC(app_id);
345   // Try and reset
346   EXPECT_CLEAR_STATUS(app_id);
347   // Try again
348   EXPECT_GET_STATUS_IDLE(app_id);
349   EXPECT_SEND_DATA(app_id, args, args_len);
350   EXPECT_GO_COMMAND(app_id, param, args, args_len, 0);
351   EXPECT_GET_STATUS_WORKING(app_id);
352   EXPECT_GET_STATUS_DONE(app_id);
353   EXPECT_CLEAR_STATUS(app_id);
354 
355   uint32_t res = nos_call_application(dev(), app_id, param, args, args_len, nullptr, nullptr);
356   EXPECT_THAT(res, Eq(APP_SUCCESS));
357 }
358 
TEST_F(TransportTest,StatusCrcError)359 TEST_F(TransportTest, StatusCrcError) {
360   const uint8_t app_id = 53;
361   const uint16_t param = 192;
362 
363   InSequence please;
364   // Try 3 times
365   EXPECT_GET_STATUS_IDLE_WITH_BAD_CRC(app_id);
366   EXPECT_GET_STATUS_IDLE_WITH_BAD_CRC(app_id);
367   EXPECT_GET_STATUS_IDLE_WITH_BAD_CRC(app_id);
368 
369   uint32_t res = nos_call_application(dev(), app_id, param, nullptr, 0, nullptr, nullptr);
370   EXPECT_THAT(res, Eq(APP_ERROR_IO));
371 }
372 
TEST_F(TransportTest,FailToClearStatus)373 TEST_F(TransportTest, FailToClearStatus) {
374   const uint8_t app_id = 12;
375   const uint16_t param = 2;
376   const uint8_t args[] = {1, 2, 3};
377   const uint16_t args_len = 3;
378 
379   InSequence please;
380   EXPECT_GET_STATUS_BAD_CRC(app_id);
381   // Try and reset
382   EXPECT_CLEAR_STATUS(app_id);
383   // No luck
384   EXPECT_GET_STATUS_BAD_CRC(app_id);
385 
386   uint32_t res = nos_call_application(dev(), app_id, param, args, args_len, nullptr, nullptr);
387   EXPECT_THAT(res, Eq(APP_ERROR_IO));
388 }
389 
TEST_F(TransportTest,FailToClearStatusAfterStatusCrcError)390 TEST_F(TransportTest, FailToClearStatusAfterStatusCrcError) {
391   const uint8_t app_id = 53;
392   const uint16_t param = 192;
393 
394   InSequence please;
395   // Try 3 times
396   EXPECT_GET_STATUS_IDLE_WITH_BAD_CRC(app_id);
397   EXPECT_GET_STATUS_IDLE_WITH_BAD_CRC(app_id);
398   EXPECT_GET_STATUS_BAD_CRC(app_id);
399   // Try and reset
400   EXPECT_CLEAR_STATUS(app_id);
401   // No luck
402   EXPECT_GET_STATUS_BAD_CRC(app_id);
403 
404   uint32_t res = nos_call_application(dev(), app_id, param, nullptr, 0, nullptr, nullptr);
405   EXPECT_THAT(res, Eq(APP_ERROR_IO));
406 }
407 
TEST_F(TransportTest,RequestCrcError)408 TEST_F(TransportTest, RequestCrcError) {
409   const uint8_t app_id = 58;
410   const uint16_t param = 93;
411   const uint8_t args[] = {4, 24, 183, 255, 219};
412   const uint16_t args_len = 5;
413 
414   InSequence please;
415   // Should try 3 times
416   EXPECT_GET_STATUS_IDLE(app_id);
417   EXPECT_SEND_DATA(app_id, args, args_len);
418   EXPECT_GO_COMMAND(app_id, param, args, args_len, 0);
419   EXPECT_GET_STATUS_BAD_CRC(app_id);
420   // 2 more
421   EXPECT_GET_STATUS_IDLE(app_id);
422   EXPECT_SEND_DATA(app_id, args, args_len);
423   EXPECT_GO_COMMAND(app_id, param, args, args_len, 0);
424   EXPECT_GET_STATUS_BAD_CRC(app_id);
425   // last one
426   EXPECT_GET_STATUS_IDLE(app_id);
427   EXPECT_SEND_DATA(app_id, args, args_len);
428   EXPECT_GO_COMMAND(app_id, param, args, args_len, 0);
429   EXPECT_GET_STATUS_BAD_CRC(app_id);
430   // Clean up
431   EXPECT_CLEAR_STATUS(app_id);
432 
433   uint32_t res = nos_call_application(dev(), app_id, param, args, args_len, nullptr, nullptr);
434   EXPECT_THAT(res, Eq(APP_ERROR_IO));
435 }
436 
TEST_F(TransportTest,SuccessAfterRequestCrcError)437 TEST_F(TransportTest, SuccessAfterRequestCrcError) {
438   const uint8_t app_id = 255;
439   const uint16_t param = 163;
440   const uint8_t args[] = {42, 89, 125, 0, 83, 92, 80};
441   const uint16_t args_len = 7;
442 
443   InSequence please;
444   // First request is CRC error
445   EXPECT_GET_STATUS_IDLE(app_id);
446   EXPECT_SEND_DATA(app_id, args, args_len);
447   EXPECT_GO_COMMAND(app_id, param, args, args_len, 0);
448   EXPECT_GET_STATUS_BAD_CRC(app_id);
449   // The retry succeeds
450   EXPECT_GET_STATUS_IDLE(app_id);
451   EXPECT_SEND_DATA(app_id, args, args_len);
452   EXPECT_GO_COMMAND(app_id, param, args, args_len, 0);
453   EXPECT_GET_STATUS_WORKING(app_id);
454   EXPECT_GET_STATUS_DONE(app_id);
455   EXPECT_CLEAR_STATUS(app_id);
456 
457   uint32_t res = nos_call_application(dev(), app_id, param, args, args_len, nullptr, nullptr);
458   EXPECT_THAT(res, Eq(APP_SUCCESS));
459 }
460 
TEST_F(TransportTest,SuccessWithoutReply)461 TEST_F(TransportTest, SuccessWithoutReply) {
462   const uint8_t app_id = 12;
463   const uint16_t param = 2;
464   const uint8_t args[] = {1, 2, 3};
465   const uint16_t args_len = 3;
466 
467   InSequence please;
468   EXPECT_GET_STATUS_IDLE(app_id);
469   EXPECT_SEND_DATA(app_id, args, args_len);
470   EXPECT_GO_COMMAND(app_id, param, args, args_len, 0);
471   EXPECT_GET_STATUS_WORKING(app_id);
472   EXPECT_GET_STATUS_DONE(app_id);
473   EXPECT_CLEAR_STATUS(app_id);
474 
475   uint32_t res = nos_call_application(dev(), app_id, param, args, args_len, nullptr, nullptr);
476   EXPECT_THAT(res, Eq(APP_SUCCESS));
477 }
478 
TEST_F(TransportTest,DetectAppAbort)479 TEST_F(TransportTest, DetectAppAbort) {
480   const uint8_t app_id = 25;
481   const uint16_t param = 252;
482   const uint8_t args[] = {17, 27, 43, 193};
483   const uint16_t args_len = 4;
484 
485   InSequence please;
486   EXPECT_GET_STATUS_IDLE(app_id);
487   EXPECT_SEND_DATA(app_id, args, args_len);
488   EXPECT_GO_COMMAND(app_id, param, args, args_len, 0);
489   EXPECT_GET_STATUS_WORKING(app_id);
490   EXPECT_GET_STATUS_WORKING(app_id);
491   EXPECT_GET_STATUS_WORKING(app_id);
492   // It just stopped working
493   EXPECT_GET_STATUS_IDLE(app_id);
494   // It's probably already clear but just making sure
495   EXPECT_CLEAR_STATUS(app_id);
496 
497   uint32_t res = nos_call_application(dev(), app_id, param, args, args_len, nullptr, nullptr);
498   EXPECT_THAT(res, Eq(APP_ERROR_INTERNAL));
499 }
500 
TEST_F(TransportTest,SuccessWithReply)501 TEST_F(TransportTest, SuccessWithReply) {
502   const uint8_t app_id = 165;
503   const uint16_t param = 16;
504   const uint8_t data[] = {5, 6, 7, 8};
505   uint8_t reply[4];
506   uint32_t reply_len = 4;
507 
508   InSequence please;
509   EXPECT_GET_STATUS_IDLE(app_id);
510   EXPECT_SEND_DATA(app_id, nullptr, 0);
511   EXPECT_GO_COMMAND(app_id, param, nullptr, 0, reply_len);
512   EXPECT_GET_STATUS_DONE_WITH_DATA(app_id, data, sizeof(data));
513   EXPECT_RECV_DATA(app_id, reply_len, data, sizeof(data));
514   EXPECT_CLEAR_STATUS(app_id);
515 
516   uint32_t res = nos_call_application(dev(), app_id, param, nullptr, 0, reply, &reply_len);
517   EXPECT_THAT(res, Eq(APP_SUCCESS));
518   EXPECT_THAT(reply_len, Eq(4));
519   EXPECT_THAT(reply, ElementsAreArray(data, sizeof(data)));
520 }
521 
TEST_F(TransportTest,SuccessWithReplyInMultipleDatagrams)522 TEST_F(TransportTest, SuccessWithReplyInMultipleDatagrams) {
523   const uint8_t app_id = 165;
524   const uint16_t param = 16;
525   std::vector<uint8_t> data(MAX_DEVICE_TRANSFER + 24, 0xea);
526   std::vector<uint8_t> reply(data.size());
527   uint32_t reply_len = reply.size();
528 
529   InSequence please;
530   EXPECT_GET_STATUS_IDLE(app_id);
531   EXPECT_SEND_DATA(app_id, nullptr, 0);
532   EXPECT_GO_COMMAND(app_id, param, nullptr, 0, reply_len);
533   EXPECT_GET_STATUS_DONE_WITH_DATA(app_id, data.data(), data.size());
534   EXPECT_RECV_DATA(app_id, reply_len, data.data(), MAX_DEVICE_TRANSFER);
535   EXPECT_RECV_MORE_DATA(app_id, 24, data.data() + MAX_DEVICE_TRANSFER, 24);
536   EXPECT_CLEAR_STATUS(app_id);
537 
538   uint32_t res = nos_call_application(dev(), app_id, param, nullptr, 0, reply.data(), &reply_len);
539   EXPECT_THAT(res, Eq(APP_SUCCESS));
540   EXPECT_THAT(reply_len, Eq(MAX_DEVICE_TRANSFER + 24));
541   EXPECT_THAT(reply, ElementsAreArray(data));
542 }
543 
TEST_F(TransportTest,ReplyCrcError)544 TEST_F(TransportTest, ReplyCrcError) {
545   const uint8_t app_id = 5;
546   const uint16_t param = 0;
547   const uint8_t data[] = {1, 1, 2, 3, 5, 7};
548   const uint8_t wrong_data[] = {3, 1, 2, 3, 5, 7};
549   uint8_t reply[6];
550   uint32_t reply_len = 6;
551 
552   InSequence please;
553   EXPECT_GET_STATUS_IDLE(app_id);
554   EXPECT_SEND_DATA(app_id, nullptr, 0);
555   EXPECT_GO_COMMAND(app_id, param, nullptr, 0, reply_len);
556   EXPECT_GET_STATUS_DONE_WITH_DATA(app_id, data, sizeof(data));
557   // Try 3 times to read data
558   EXPECT_RECV_DATA(app_id, reply_len, wrong_data, sizeof(wrong_data));
559   EXPECT_RECV_DATA(app_id, reply_len, wrong_data, sizeof(wrong_data));
560   EXPECT_RECV_DATA(app_id, reply_len, wrong_data, sizeof(wrong_data));
561 
562   uint32_t res = nos_call_application(dev(), app_id, param, nullptr, 0, reply, &reply_len);
563   EXPECT_THAT(res, Eq(APP_ERROR_IO));
564 }
565 
TEST_F(TransportTest,SuccessAfterReplyCrcError)566 TEST_F(TransportTest, SuccessAfterReplyCrcError) {
567   const uint8_t app_id = 5;
568   const uint16_t param = 0;
569   const uint8_t data[] = {2, 4, 9, 16};
570   const uint8_t wrong_data[] = {2, 4, 9, 48};
571   uint8_t reply[4];
572   uint32_t reply_len = 4;
573 
574   InSequence please;
575   EXPECT_GET_STATUS_IDLE(app_id);
576   EXPECT_SEND_DATA(app_id, nullptr, 0);
577   EXPECT_GO_COMMAND(app_id, param, nullptr, 0, reply_len);
578   EXPECT_GET_STATUS_DONE_WITH_DATA(app_id, data, sizeof(data));
579   // Retry due to crc error
580   EXPECT_RECV_DATA(app_id, reply_len, wrong_data, sizeof(wrong_data));
581   EXPECT_RECV_DATA(app_id, reply_len, wrong_data, sizeof(wrong_data));
582   EXPECT_RECV_DATA(app_id, reply_len, data, sizeof(data));
583   EXPECT_CLEAR_STATUS(app_id);
584 
585   uint32_t res = nos_call_application(dev(), app_id, param, nullptr, 0, reply, &reply_len);
586   EXPECT_THAT(res, Eq(APP_SUCCESS));
587   EXPECT_THAT(reply_len, Eq(4));
588   EXPECT_THAT(reply, ElementsAreArray(data, sizeof(data)));
589 }
590 
TEST_F(TransportTest,V0SuccessWithoutReply)591 TEST_F(TransportTest, V0SuccessWithoutReply) {
592   const uint8_t app_id = 6;
593   const uint16_t param = 92;
594 
595   InSequence please;
596   EXPECT_GET_STATUS_V0_IDLE(app_id);
597   EXPECT_SEND_DATA(app_id, nullptr, 0);
598   EXPECT_GO_COMMAND(app_id, param, nullptr, 0, 0);
599   EXPECT_GET_STATUS_V0_DONE(app_id);
600   EXPECT_CLEAR_STATUS(app_id);
601 
602   uint32_t res = nos_call_application(dev(), app_id, param, nullptr, 0, nullptr, nullptr);
603   EXPECT_THAT(res, Eq(APP_SUCCESS));
604 }
605 
TEST_F(TransportTest,V0SuccessWithReply)606 TEST_F(TransportTest, V0SuccessWithReply) {
607   const uint8_t app_id = 0;
608   const uint16_t param = 18;
609   const uint8_t data[] = {15, 20, 25, 30, 35, 40};
610   uint8_t reply[6];
611   uint32_t reply_len = 6;
612 
613   InSequence please;
614   EXPECT_GET_STATUS_V0_IDLE(app_id);
615   EXPECT_SEND_DATA(app_id, nullptr, 0);
616   EXPECT_GO_COMMAND(app_id, param, nullptr, 0, reply_len);
617   EXPECT_GET_STATUS_V0_DONE_WITH_DATA(app_id, sizeof(data));
618   EXPECT_RECV_DATA(app_id, reply_len, data, sizeof(data));
619   EXPECT_CLEAR_STATUS(app_id);
620 
621   uint32_t res = nos_call_application(dev(), app_id, param, nullptr, 0, reply, &reply_len);
622   EXPECT_THAT(res, Eq(APP_SUCCESS));
623   EXPECT_THAT(reply_len, Eq(6));
624   EXPECT_THAT(reply, ElementsAreArray(data, sizeof(data)));
625 }
626 
TEST_F(TransportTest,ErrorIfArgsLenButNotArgs)627 TEST_F(TransportTest, ErrorIfArgsLenButNotArgs) {
628   uint8_t reply[] = {1, 2, 3};
629   uint32_t reply_len = 0;
630   uint32_t status = nos_call_application(dev(), 1, 2, nullptr, 5, reply, &reply_len);
631   EXPECT_THAT(status, Eq(APP_ERROR_IO));
632 }
633 
main(int argc,char ** argv)634 int main(int argc, char** argv) {
635   ::testing::InitGoogleTest(&argc, argv);
636   return RUN_ALL_TESTS();
637 }
638 
639 #ifdef TEST_TIMEOUT
TEST_F(TransportTest,Timeout)640 TEST_F(TransportTest, Timeout) {
641   const uint8_t app_id = 49;
642   const uint16_t param = 64;
643 
644   InSequence please;
645   EXPECT_GET_STATUS_IDLE(app_id);
646   EXPECT_SEND_DATA(app_id, nullptr, 0);
647   EXPECT_GO_COMMAND(app_id, param, nullptr, 0, 0);
648 
649   // Keep saying we're working on it
650   const uint32_t command = CMD_ID((app_id)) | CMD_IS_READ | CMD_TRANSPORT;
651   EXPECT_CALL(mock_dev(), Read(command, _, STATUS_MAX_LENGTH))
652       .WillRepeatedly(DoAll(ReadStatusV1_Working(), Return(0)));
653 
654   // We'll still try and clean up
655   EXPECT_CLEAR_STATUS(app_id);
656 
657   uint32_t res = nos_call_application(dev(), app_id, param, nullptr, 0, nullptr, nullptr);
658   EXPECT_THAT(res, Eq(APP_ERROR_TIMEOUT));
659 }
660 #endif
661