xref: /aosp_15_r20/system/chre/test/simulation/README.md (revision 84e339476a462649f82315436d70fd732297a399)
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