• Home
Name Date Size #Lines LOC

..--

inc/03-May-2024-543215

README.mdD03-May-20247.5 KiB261208

audio_test.ccD03-May-20245.1 KiB169131

ble_test.ccD03-May-202418.7 KiB579457

gnss_test.ccD03-May-202417.5 KiB520430

host_endpoint_notification_test.ccD03-May-20244.5 KiB13692

memory_test.ccD03-May-20248.5 KiB264210

sensor_test.ccD03-May-20245.4 KiB163127

settings_test.ccD03-May-20246.8 KiB203146

test_base.ccD03-May-20244 KiB12271

test_util.ccD03-May-20244.6 KiB13999

timer_test.ccD03-May-20245.4 KiB182134

wifi_nan_test.ccD03-May-202421.8 KiB627477

wifi_test.ccD03-May-20247.7 KiB231183

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  struct App : public TestNanoapp {
35    void (*handleEvent)(uint32_t, uint16_t,
36                        const void *) = [](uint32_t, uint16_t eventType,
37                                           const void *eventData) {
38      switch (eventType) {
39        // 3. Handle system events.
40        case CHRE_EVENT_WIFI_ASYNC_RESULT: {
41          // ...
42          // 4. Send event back to the test.
43          TestEventQueueSingleton::get()->pushEvent(
44            CHRE_EVENT_WIFI_ASYNC_RESULT)
45          break;
46        }
47
48        case CHRE_EVENT_TEST_EVENT: {
49          auto event = static_cast<const TestEvent *>(eventData);
50          switch (event->type) {
51            // 5. Handle test events to execute code in the context the Nanoapp.
52            case MY_TEST_EVENT:
53              // ...
54              break;
55          }
56        }
57      }
58    };
59  };
60
61  // 6. Load the app and add initial expectations.
62  auto app = loadNanoapp<App>();
63  EXPECT_TRUE(...);
64
65  // 7. Send test events to the Nanoapp to execute some actions and add
66  //    expectations about the result.
67  sendEventToNanoapp(app, MY_TEST_EVENT);
68  waitForEvent(CHRE_EVENT_WIFI_ASYNC_RESULT);
69  EXPECT_TRUE(...);
70
71  // 8. Optionally unload the Nanoapp
72  unloadNanoapp(app);
73}
74```
75
76##### Test app (#2, #6, #8)
77
78Inherit from `TestNanoapp` to create a test nanoapp. The following
79properties oif a nanoapp can be overridden `name`, `id`, `version`, `perms`,
80`start`, `handleEvent`, and `end`.
81
82Typical tests only override of few of the above properties:
83
84* `perms` to set the permissions required for the test,
85* `start` to put the system in a known state before each test,
86* `handleEvent` is probably the most important function where system and test
87   events are handled. See the sections below for more details.
88
89##### Test events (#1)
90
91The test events are local to a single test and created using the
92`CREATE_CHRE_TEST_EVENT(name, id)` macro. The id must be unique in a single
93test and in the range [0, 0xfff].
94
95##### System event (#3)
96
97Add code to `handleEvent` to handle the system events you are interested in for
98the test:
99
100```cpp
101void (*handleEvent)(uint32_t, uint16_t,
102                    const void *) = [](uint32_t, uint16_t eventType,
103                                        const void *eventData) {
104  switch (eventType) {
105    case CHRE_EVENT_WIFI_ASYNC_RESULT: {
106      // ...
107      break;
108    }
109  }
110};
111```
112
113The handler would typically send an event back to the nanoapp, see the next
114section for more details.
115
116##### Send event from the nanoapp (#4)
117
118You can send an event from the nanoapp (typically inside `handleEvent`):
119
120```cpp
121// Sending a system event.
122TestEventQueueSingleton::get()->pushEvent(CHRE_EVENT_WIFI_ASYNC_RESULT);
123
124// Sending a test event.
125TestEventQueueSingleton::get()->pushEvent(MY_TEST_EVENT);
126```
127
128Use `waitForEvent` to wait for an event in your test code:
129
130```cpp
131// Wait for a system event.
132waitForEvent(CHRE_EVENT_WIFI_ASYNC_RESULT);
133
134// Wait for a test event.
135waitForEvent(MY_TEST_EVENT);
136```
137
138Waiting for an event as described above is sufficient to express a boolean
139expectation. For example the status of an event:
140
141```cpp
142  void (*handleEvent)(uint32_t, uint16_t,
143                      const void *) = [](uint32_t, uint16_t eventType,
144                                          const void *eventData) {
145    switch (eventType) {
146      case CHRE_EVENT_WIFI_ASYNC_RESULT: {
147        auto *event = static_cast<const chreAsyncResult *>(eventData);
148        if (event->success) {
149          TestEventQueueSingleton::get()->pushEvent(
150              CHRE_EVENT_WIFI_ASYNC_RESULT);
151        }
152        break;
153      }
154    }
155  };
156};
157```
158
159With the above snippet `waitForEvent(CHRE_EVENT_WIFI_ASYNC_RESULT)` will timeout
160if the nanoapp did not receive a successful status.
161
162Sometimes you want to attach additional data alongside the event. Simply pass
163the data as the second argument to pushEvent:
164
165```cpp
166    void (*handleEvent)(uint32_t, uint16_t,
167                        const void *) = [](uint32_t, uint16_t eventType,
168                                           const void *eventData) {
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(app, 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,
212                    const void *) = [](uint32_t, uint16_t eventType,
213                                        const void *eventData) {
214  switch (eventType) {
215    // Test event are received with a CHRE_EVENT_TEST_EVENT type.
216    case CHRE_EVENT_TEST_EVENT: {
217      auto event = static_cast<const TestEvent *>(eventData);
218      switch (event->type) {
219        // Create a case for each of the test events.
220        case MY_TEST_EVENT:
221          // Code running in the context of the nanoapp.
222          break;
223      }
224    }
225  }
226};
227```
228
229It is possible to send data alongside a test event:
230
231```cpp
232bool enable = true;
233sendEventToNanoapp(app, MY_TEST_EVENT, &enable);
234```
235
236The data should be a scalar type or a struct of scalars. Be careful not to send
237a pointer to a memory block that might be released before the data is consumed
238in `handleEvent`. This would result in a use after free error and flaky tests.
239
240The `handleEvent` function receives a copy of the data in the `data` field of
241the `TestEvent`:
242
243```cpp
244void (*handleEvent)(uint32_t, uint16_t,
245                    const void *) = [](uint32_t, uint16_t eventType,
246                                        const void *eventData) {
247  switch (eventType) {
248    // Test event are received with a CHRE_EVENT_TEST_EVENT type.
249    case CHRE_EVENT_TEST_EVENT: {
250      auto event = static_cast<const TestEvent *>(eventData);
251      switch (event->type) {
252        // Create a case for each of the test events.
253        case MY_TEST_EVENT:
254          chreFunctionTakingABool(*(bool*(event->data)));
255          break;
256      }
257    }
258  }
259};
260```
261