1*84e33947SAndroid Build Coastguard Worker### CHRE Simulation Test Framework 2*84e33947SAndroid Build Coastguard Worker 3*84e33947SAndroid Build Coastguard Worker#### Background 4*84e33947SAndroid Build Coastguard Worker 5*84e33947SAndroid Build Coastguard WorkerSimulation tests are written for the CHRE linux (i.e. simulation) platform, and 6*84e33947SAndroid Build Coastguard Workercan be useful in validating higher level CHRE behavior. By "higher level", we 7*84e33947SAndroid Build Coastguard Workermean: 8*84e33947SAndroid Build Coastguard Worker 9*84e33947SAndroid Build Coastguard Worker* More coverage than a module-level unit test. 10*84e33947SAndroid Build Coastguard Worker* But smaller in scope compared to a full end-to-end integration test. 11*84e33947SAndroid Build Coastguard Worker 12*84e33947SAndroid Build Coastguard WorkerYou can think of a simulation test as treating the core CHRE framework as a 13*84e33947SAndroid Build Coastguard Workerblack box, and is able to validate its output. 14*84e33947SAndroid Build Coastguard Worker 15*84e33947SAndroid Build Coastguard Worker#### Running the tests 16*84e33947SAndroid Build Coastguard Worker 17*84e33947SAndroid Build Coastguard WorkerYou can run simulation tests through `atest`: 18*84e33947SAndroid Build Coastguard Worker 19*84e33947SAndroid Build Coastguard Worker``` 20*84e33947SAndroid Build Coastguard Workeratest --host chre_simulation_tests 21*84e33947SAndroid Build Coastguard Worker``` 22*84e33947SAndroid Build Coastguard Worker 23*84e33947SAndroid Build Coastguard Worker#### How to write a test 24*84e33947SAndroid Build Coastguard Worker 25*84e33947SAndroid Build Coastguard WorkerThe simulation test framework encourages writing self contained tests as follow: 26*84e33947SAndroid Build Coastguard Worker 27*84e33947SAndroid Build Coastguard Worker```cpp 28*84e33947SAndroid Build Coastguard Worker// Use the same unique prefix for all the tests in a single file 29*84e33947SAndroid Build Coastguard WorkerTEST_F(TestBase, <PrefixedTestName>) { 30*84e33947SAndroid Build Coastguard Worker // 1. Create tests event to trigger code in the Nanoapp context. 31*84e33947SAndroid Build Coastguard Worker CREATE_CHRE_TEST_EVENT(MY_TEST_EVENT, 0); 32*84e33947SAndroid Build Coastguard Worker 33*84e33947SAndroid Build Coastguard Worker // 2. Create a test Nanpoapp by inheriting TestNanoapp. 34*84e33947SAndroid Build Coastguard Worker class App : public TestNanoapp { 35*84e33947SAndroid Build Coastguard Worker void handleEvent(uint32_t, uint16_t eventType, const void *eventData) override { 36*84e33947SAndroid Build Coastguard Worker switch (eventType) { 37*84e33947SAndroid Build Coastguard Worker // 3. Handle system events. 38*84e33947SAndroid Build Coastguard Worker case CHRE_EVENT_WIFI_ASYNC_RESULT: { 39*84e33947SAndroid Build Coastguard Worker // ... 40*84e33947SAndroid Build Coastguard Worker // 4. Send event back to the test. 41*84e33947SAndroid Build Coastguard Worker TestEventQueueSingleton::get()->pushEvent( 42*84e33947SAndroid Build Coastguard Worker CHRE_EVENT_WIFI_ASYNC_RESULT) 43*84e33947SAndroid Build Coastguard Worker break; 44*84e33947SAndroid Build Coastguard Worker } 45*84e33947SAndroid Build Coastguard Worker 46*84e33947SAndroid Build Coastguard Worker case CHRE_EVENT_TEST_EVENT: { 47*84e33947SAndroid Build Coastguard Worker auto event = static_cast<const TestEvent *>(eventData); 48*84e33947SAndroid Build Coastguard Worker switch (event->type) { 49*84e33947SAndroid Build Coastguard Worker // 5. Handle test events to execute code in the context the Nanoapp. 50*84e33947SAndroid Build Coastguard Worker case MY_TEST_EVENT: 51*84e33947SAndroid Build Coastguard Worker // ... 52*84e33947SAndroid Build Coastguard Worker break; 53*84e33947SAndroid Build Coastguard Worker } 54*84e33947SAndroid Build Coastguard Worker } 55*84e33947SAndroid Build Coastguard Worker } 56*84e33947SAndroid Build Coastguard Worker } 57*84e33947SAndroid Build Coastguard Worker }; 58*84e33947SAndroid Build Coastguard Worker 59*84e33947SAndroid Build Coastguard Worker // 6. Load the app and add initial expectations. 60*84e33947SAndroid Build Coastguard Worker uint64_t appId = loadNanoapp(MakeUnique<App>());; 61*84e33947SAndroid Build Coastguard Worker EXPECT_TRUE(...); 62*84e33947SAndroid Build Coastguard Worker 63*84e33947SAndroid Build Coastguard Worker // 7. Send test events to the Nanoapp to execute some actions and add 64*84e33947SAndroid Build Coastguard Worker // expectations about the result. 65*84e33947SAndroid Build Coastguard Worker sendEventToNanoapp(appId, MY_TEST_EVENT); 66*84e33947SAndroid Build Coastguard Worker waitForEvent(CHRE_EVENT_WIFI_ASYNC_RESULT); 67*84e33947SAndroid Build Coastguard Worker EXPECT_TRUE(...); 68*84e33947SAndroid Build Coastguard Worker 69*84e33947SAndroid Build Coastguard Worker // 8. Optionally unload the Nanoapp 70*84e33947SAndroid Build Coastguard Worker unloadNanoapp(appId); 71*84e33947SAndroid Build Coastguard Worker} 72*84e33947SAndroid Build Coastguard Worker``` 73*84e33947SAndroid Build Coastguard Worker 74*84e33947SAndroid Build Coastguard Worker##### Test app (#2, #6, #8) 75*84e33947SAndroid Build Coastguard Worker 76*84e33947SAndroid Build Coastguard WorkerInherit from `TestNanoapp` to create a test nanoapp. 77*84e33947SAndroid Build Coastguard Worker 78*84e33947SAndroid Build Coastguard WorkerIf you need to customize any of the nanoapp `name`, `id`, `version`, or `perms`, 79*84e33947SAndroid Build Coastguard Workeryou will need to add a constructor calling the `TestNanoapp` constructor with that info, i.e.: 80*84e33947SAndroid Build Coastguard Worker 81*84e33947SAndroid Build Coastguard Worker``` 82*84e33947SAndroid Build Coastguard Workerclass App: public TestNanoapp { 83*84e33947SAndroid Build Coastguard Worker public: 84*84e33947SAndroid Build Coastguard Worker explicit App(TestNanoappInfo info): TestNanoapp(info) {} 85*84e33947SAndroid Build Coastguard Worker 86*84e33947SAndroid Build Coastguard Worker // ... 87*84e33947SAndroid Build Coastguard Worker}; 88*84e33947SAndroid Build Coastguard Worker``` 89*84e33947SAndroid Build Coastguard Worker 90*84e33947SAndroid Build Coastguard WorkerThe nanoapp entry points are implemented as methods of the class: 91*84e33947SAndroid Build Coastguard Worker 92*84e33947SAndroid Build Coastguard Worker- `start`, 93*84e33947SAndroid Build Coastguard Worker- `handleEvent`, 94*84e33947SAndroid Build Coastguard Worker- `end`. 95*84e33947SAndroid Build Coastguard Worker 96*84e33947SAndroid Build Coastguard Worker##### Test events (#1) 97*84e33947SAndroid Build Coastguard Worker 98*84e33947SAndroid Build Coastguard WorkerThe test events are local to a single test and created using the 99*84e33947SAndroid Build Coastguard Worker`CREATE_CHRE_TEST_EVENT(name, id)` macro. The id must be unique in a single 100*84e33947SAndroid Build Coastguard Workertest and in the range [0, 0xfff]. 101*84e33947SAndroid Build Coastguard Worker 102*84e33947SAndroid Build Coastguard Worker##### System event (#3) 103*84e33947SAndroid Build Coastguard Worker 104*84e33947SAndroid Build Coastguard WorkerAdd code to `handleEvent` to handle the system events you are interested in for 105*84e33947SAndroid Build Coastguard Workerthe test: 106*84e33947SAndroid Build Coastguard Worker 107*84e33947SAndroid Build Coastguard Worker```cpp 108*84e33947SAndroid Build Coastguard Workervoid handleEvent(uint32_t, uint16_t eventType, const void *eventData) override { 109*84e33947SAndroid Build Coastguard Worker switch (eventType) { 110*84e33947SAndroid Build Coastguard Worker case CHRE_EVENT_WIFI_ASYNC_RESULT: { 111*84e33947SAndroid Build Coastguard Worker // ... 112*84e33947SAndroid Build Coastguard Worker break; 113*84e33947SAndroid Build Coastguard Worker } 114*84e33947SAndroid Build Coastguard Worker } 115*84e33947SAndroid Build Coastguard Worker} 116*84e33947SAndroid Build Coastguard Worker``` 117*84e33947SAndroid Build Coastguard Worker 118*84e33947SAndroid Build Coastguard WorkerThe handler would typically send an event back to the nanoapp, see the next 119*84e33947SAndroid Build Coastguard Workersection for more details. 120*84e33947SAndroid Build Coastguard Worker 121*84e33947SAndroid Build Coastguard Worker##### Send event from the nanoapp (#4) 122*84e33947SAndroid Build Coastguard Worker 123*84e33947SAndroid Build Coastguard WorkerYou can send an event from the nanoapp (typically inside `handleEvent`): 124*84e33947SAndroid Build Coastguard Worker 125*84e33947SAndroid Build Coastguard Worker```cpp 126*84e33947SAndroid Build Coastguard Worker// Sending a system event. 127*84e33947SAndroid Build Coastguard WorkerTestEventQueueSingleton::get()->pushEvent(CHRE_EVENT_WIFI_ASYNC_RESULT); 128*84e33947SAndroid Build Coastguard Worker 129*84e33947SAndroid Build Coastguard Worker// Sending a test event. 130*84e33947SAndroid Build Coastguard WorkerTestEventQueueSingleton::get()->pushEvent(MY_TEST_EVENT); 131*84e33947SAndroid Build Coastguard Worker``` 132*84e33947SAndroid Build Coastguard Worker 133*84e33947SAndroid Build Coastguard WorkerUse `waitForEvent` to wait for an event in your test code: 134*84e33947SAndroid Build Coastguard Worker 135*84e33947SAndroid Build Coastguard Worker```cpp 136*84e33947SAndroid Build Coastguard Worker// Wait for a system event. 137*84e33947SAndroid Build Coastguard WorkerwaitForEvent(CHRE_EVENT_WIFI_ASYNC_RESULT); 138*84e33947SAndroid Build Coastguard Worker 139*84e33947SAndroid Build Coastguard Worker// Wait for a test event. 140*84e33947SAndroid Build Coastguard WorkerwaitForEvent(MY_TEST_EVENT); 141*84e33947SAndroid Build Coastguard Worker``` 142*84e33947SAndroid Build Coastguard Worker 143*84e33947SAndroid Build Coastguard WorkerWaiting for an event as described above is sufficient to express a boolean 144*84e33947SAndroid Build Coastguard Workerexpectation. For example the status of an event: 145*84e33947SAndroid Build Coastguard Worker 146*84e33947SAndroid Build Coastguard Worker```cpp 147*84e33947SAndroid Build Coastguard Workervoid handleEvent(uint32_t, uint16_t eventType, const void *eventData) override { 148*84e33947SAndroid Build Coastguard Worker switch (eventType) { 149*84e33947SAndroid Build Coastguard Worker case CHRE_EVENT_WIFI_ASYNC_RESULT: { 150*84e33947SAndroid Build Coastguard Worker auto *event = static_cast<const chreAsyncResult *>(eventData); 151*84e33947SAndroid Build Coastguard Worker if (event->success) { 152*84e33947SAndroid Build Coastguard Worker TestEventQueueSingleton::get()->pushEvent( 153*84e33947SAndroid Build Coastguard Worker CHRE_EVENT_WIFI_ASYNC_RESULT); 154*84e33947SAndroid Build Coastguard Worker } 155*84e33947SAndroid Build Coastguard Worker break; 156*84e33947SAndroid Build Coastguard Worker } 157*84e33947SAndroid Build Coastguard Worker } 158*84e33947SAndroid Build Coastguard Worker} 159*84e33947SAndroid Build Coastguard Worker``` 160*84e33947SAndroid Build Coastguard Worker 161*84e33947SAndroid Build Coastguard WorkerWith the above snippet `waitForEvent(CHRE_EVENT_WIFI_ASYNC_RESULT)` will timeout 162*84e33947SAndroid Build Coastguard Workerif the nanoapp did not receive a successful status. 163*84e33947SAndroid Build Coastguard Worker 164*84e33947SAndroid Build Coastguard WorkerSometimes you want to attach additional data alongside the event. Simply pass 165*84e33947SAndroid Build Coastguard Workerthe data as the second argument to pushEvent: 166*84e33947SAndroid Build Coastguard Worker 167*84e33947SAndroid Build Coastguard Worker```cpp 168*84e33947SAndroid Build Coastguard Worker void handleEvent(uint32_t, uint16_t eventType, const void *eventData) override { 169*84e33947SAndroid Build Coastguard Worker switch (eventType) { 170*84e33947SAndroid Build Coastguard Worker case CHRE_EVENT_WIFI_ASYNC_RESULT: { 171*84e33947SAndroid Build Coastguard Worker auto *event = static_cast<const chreAsyncResult *>(eventData); 172*84e33947SAndroid Build Coastguard Worker if (event->success) { 173*84e33947SAndroid Build Coastguard Worker TestEventQueueSingleton::get()->pushEvent( 174*84e33947SAndroid Build Coastguard Worker CHRE_EVENT_WIFI_ASYNC_RESULT, 175*84e33947SAndroid Build Coastguard Worker *(static_cast<const uint32_t *>(event->cookie))); 176*84e33947SAndroid Build Coastguard Worker } 177*84e33947SAndroid Build Coastguard Worker break; 178*84e33947SAndroid Build Coastguard Worker } 179*84e33947SAndroid Build Coastguard Worker } 180*84e33947SAndroid Build Coastguard Worker } 181*84e33947SAndroid Build Coastguard Worker``` 182*84e33947SAndroid Build Coastguard Worker 183*84e33947SAndroid Build Coastguard WorkerThe data must be trivially copyable (a scalar or a struct of scalar are safe). 184*84e33947SAndroid Build Coastguard Worker 185*84e33947SAndroid Build Coastguard WorkerUse the second argument of `waitForEvent` to retrieve the data in your test 186*84e33947SAndroid Build Coastguard Workercode: 187*84e33947SAndroid Build Coastguard Worker 188*84e33947SAndroid Build Coastguard Worker```cpp 189*84e33947SAndroid Build Coastguard Workeruint32_t cookie; 190*84e33947SAndroid Build Coastguard WorkerwaitForEvent(CHRE_EVENT_WIFI_ASYNC_RESULT, &cookie); 191*84e33947SAndroid Build Coastguard WorkerEXPECT_EQ(cookie, ...); 192*84e33947SAndroid Build Coastguard Worker``` 193*84e33947SAndroid Build Coastguard Worker 194*84e33947SAndroid Build Coastguard Worker##### Send event to the nanoapp (#5) 195*84e33947SAndroid Build Coastguard Worker 196*84e33947SAndroid Build Coastguard WorkerTo execute the code in the nanoapp context, you will need to create a test 197*84e33947SAndroid Build Coastguard Workerevent and send it to the nanoapp as follow: 198*84e33947SAndroid Build Coastguard Worker 199*84e33947SAndroid Build Coastguard Worker```cpp 200*84e33947SAndroid Build Coastguard WorkerCREATE_CHRE_TEST_EVENT(MY_TEST_EVENT, 0); 201*84e33947SAndroid Build Coastguard Worker 202*84e33947SAndroid Build Coastguard Worker// ... 203*84e33947SAndroid Build Coastguard Worker 204*84e33947SAndroid Build Coastguard WorkersendEventToNanoapp(appId, MY_TEST_EVENT); 205*84e33947SAndroid Build Coastguard Worker``` 206*84e33947SAndroid Build Coastguard Worker 207*84e33947SAndroid Build Coastguard WorkerThe code to be executed in the context of the nanoapp should be added to its 208*84e33947SAndroid Build Coastguard Worker`handleEvent` function: 209*84e33947SAndroid Build Coastguard Worker 210*84e33947SAndroid Build Coastguard Worker```cpp 211*84e33947SAndroid Build Coastguard Workervoid handleEvent(uint32_t, uint16_t eventType, const void *eventData) override { 212*84e33947SAndroid Build Coastguard Worker switch (eventType) { 213*84e33947SAndroid Build Coastguard Worker // Test event are received with a CHRE_EVENT_TEST_EVENT type. 214*84e33947SAndroid Build Coastguard Worker case CHRE_EVENT_TEST_EVENT: { 215*84e33947SAndroid Build Coastguard Worker auto event = static_cast<const TestEvent *>(eventData); 216*84e33947SAndroid Build Coastguard Worker switch (event->type) { 217*84e33947SAndroid Build Coastguard Worker // Create a case for each of the test events. 218*84e33947SAndroid Build Coastguard Worker case MY_TEST_EVENT: 219*84e33947SAndroid Build Coastguard Worker // Code running in the context of the nanoapp. 220*84e33947SAndroid Build Coastguard Worker break; 221*84e33947SAndroid Build Coastguard Worker } 222*84e33947SAndroid Build Coastguard Worker } 223*84e33947SAndroid Build Coastguard Worker } 224*84e33947SAndroid Build Coastguard Worker} 225*84e33947SAndroid Build Coastguard Worker``` 226*84e33947SAndroid Build Coastguard Worker 227*84e33947SAndroid Build Coastguard WorkerIt is possible to send data alongside a test event: 228*84e33947SAndroid Build Coastguard Worker 229*84e33947SAndroid Build Coastguard Worker```cpp 230*84e33947SAndroid Build Coastguard Workerbool enable = true; 231*84e33947SAndroid Build Coastguard WorkersendEventToNanoapp(appId, MY_TEST_EVENT, &enable); 232*84e33947SAndroid Build Coastguard Worker``` 233*84e33947SAndroid Build Coastguard Worker 234*84e33947SAndroid Build Coastguard WorkerThe data should be a scalar type or a struct of scalars. Be careful not to send 235*84e33947SAndroid Build Coastguard Workera pointer to a memory block that might be released before the data is consumed 236*84e33947SAndroid Build Coastguard Workerin `handleEvent`. This would result in a use after free error and flaky tests. 237*84e33947SAndroid Build Coastguard Worker 238*84e33947SAndroid Build Coastguard WorkerThe `handleEvent` function receives a copy of the data in the `data` field of 239*84e33947SAndroid Build Coastguard Workerthe `TestEvent`: 240*84e33947SAndroid Build Coastguard Worker 241*84e33947SAndroid Build Coastguard Worker```cpp 242*84e33947SAndroid Build Coastguard Workervoid handleEvent(uint32_t, uint16_t eventType, const void *eventData) override { 243*84e33947SAndroid Build Coastguard Worker switch (eventType) { 244*84e33947SAndroid Build Coastguard Worker // Test event are received with a CHRE_EVENT_TEST_EVENT type. 245*84e33947SAndroid Build Coastguard Worker case CHRE_EVENT_TEST_EVENT: { 246*84e33947SAndroid Build Coastguard Worker auto event = static_cast<const TestEvent *>(eventData); 247*84e33947SAndroid Build Coastguard Worker switch (event->type) { 248*84e33947SAndroid Build Coastguard Worker // Create a case for each of the test events. 249*84e33947SAndroid Build Coastguard Worker case MY_TEST_EVENT: 250*84e33947SAndroid Build Coastguard Worker chreFunctionTakingABool(*(bool*(event->data))); 251*84e33947SAndroid Build Coastguard Worker break; 252*84e33947SAndroid Build Coastguard Worker } 253*84e33947SAndroid Build Coastguard Worker } 254*84e33947SAndroid Build Coastguard Worker } 255*84e33947SAndroid Build Coastguard Worker} 256*84e33947SAndroid Build Coastguard Worker``` 257