Name Date Size #Lines LOC

..--

inc/H25-Apr-2025-679291

rpc/H25-Apr-2025-1410

README.mdH A D25-Apr-20256.9 KiB257201

audio_test.ccH A D25-Apr-20255.1 KiB172134

ble_test.ccH A D25-Apr-202527.6 KiB867677

chre_message_hub_test.ccH A D25-Apr-202512.8 KiB360279

delay_event_test.ccH A D25-Apr-20252.6 KiB9564

gnss_test.ccH A D25-Apr-202517.3 KiB554452

host_endpoint_notification_test.ccH A D25-Apr-20255 KiB14599

info_struct_version_test.ccH A D25-Apr-20252.4 KiB7441

memory_test.ccH A D25-Apr-20258.1 KiB257204

rpc_test.ccH A D25-Apr-202512.5 KiB413326

sensor_test.ccH A D25-Apr-20255.3 KiB169130

settings_test.ccH A D25-Apr-20256.9 KiB206148

test_base.ccH A D25-Apr-20255.4 KiB173111

test_util.ccH A D25-Apr-20257.8 KiB263175

timer_test.ccH A D25-Apr-20255.3 KiB183135

wifi_nan_test.ccH A D25-Apr-202520.8 KiB634480

wifi_scan_test.ccH A D25-Apr-202515.6 KiB433342

wifi_test.ccH A D25-Apr-20257.7 KiB246195

wifi_timeout_test.ccH A D25-Apr-202515.6 KiB471374

README.md

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