• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2022 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 <cstdint>
18 #include "chre/common.h"
19 #include "chre/core/event_loop_manager.h"
20 #include "chre/core/settings.h"
21 #include "chre/platform/linux/pal_nan.h"
22 #include "chre/platform/log.h"
23 #include "chre/util/system/napp_permissions.h"
24 #include "chre_api/chre/event.h"
25 #include "chre_api/chre/wifi.h"
26 
27 #include "gtest/gtest.h"
28 #include "test_base.h"
29 #include "test_event_queue.h"
30 #include "test_util.h"
31 
32 /**
33  * Simulation to test WiFi NAN functionality in CHRE.
34  *
35  * The test works as follows:
36  * - A test nanoapp starts by requesting NAN subscriptions, with random
37  *   service specific information. It also requests NAN ranging measurements
38  *   if the test desires it. The Linux WiFi PAL has hooks and flags that
39  *   instruct it to cover various test cases (fail subscribe, terminate
40  *   service, etc.), to enable testing of all NAN events that CHRE is
41  *   expected to propagate. These flags should be set before startTestNanoapping
42  * the test nanoapp.
43  *
44  * - The test fails (times out) if any of the events are not sent by CHRE.
45  */
46 
47 namespace chre {
48 namespace {
49 
50 class WifiNanTest : public TestBase {};
51 
52 /**
53  * Common settings for test nanoapps.
54  *
55  * - Grant WiFi permissions,
56  * - Initialize the WiFi state in start.
57  */
58 class NanTestNanoapp : public TestNanoapp {
59  public:
NanTestNanoapp()60   NanTestNanoapp()
61       : TestNanoapp(
62             TestNanoappInfo{.perms = NanoappPermissions::CHRE_PERMS_WIFI}) {}
63 
start()64   bool start() override {
65     EventLoopManagerSingleton::get()->getSettingManager().postSettingChange(
66         Setting::WIFI_AVAILABLE, true /* enabled */);
67     PalNanEngineSingleton::get()->setFlags(PalNanEngine::Flags::NONE);
68     return true;
69   }
70 };
71 
72 /**
73  * Test that an async error is received if NAN operations are attempted when
74  * the WiFi setting is disabled.
75  */
TEST_F(WifiNanTest,WifiNanDisabledViaSettings)76 TEST_F(WifiNanTest, WifiNanDisabledViaSettings) {
77   CREATE_CHRE_TEST_EVENT(NAN_SUBSCRIBE, 0);
78 
79   class App : public NanTestNanoapp {
80    public:
81     void handleEvent(uint32_t, uint16_t eventType,
82                      const void *eventData) override {
83       constexpr uint32_t kSubscribeCookie = 0x10aded;
84 
85       switch (eventType) {
86         case CHRE_EVENT_WIFI_ASYNC_RESULT: {
87           auto *event = static_cast<const chreAsyncResult *>(eventData);
88           if (event->requestType == CHRE_WIFI_REQUEST_TYPE_NAN_SUBSCRIBE) {
89             ASSERT_EQ(event->errorCode, CHRE_ERROR_FUNCTION_DISABLED);
90             TestEventQueueSingleton::get()->pushEvent(
91                 CHRE_EVENT_WIFI_ASYNC_RESULT);
92           }
93           break;
94         }
95 
96         case CHRE_EVENT_TEST_EVENT: {
97           auto event = static_cast<const TestEvent *>(eventData);
98           switch (event->type) {
99             case NAN_SUBSCRIBE: {
100               auto config = (chreWifiNanSubscribeConfig *)(event->data);
101               chreWifiNanSubscribe(config, &kSubscribeCookie);
102               break;
103             }
104           }
105         }
106       }
107     }
108   };
109 
110   uint64_t appId = loadNanoapp(MakeUnique<App>());
111 
112   EventLoopManagerSingleton::get()->getSettingManager().postSettingChange(
113       Setting::WIFI_AVAILABLE, false /* enabled */);
114 
115   chreWifiNanSubscribeConfig config = {
116       .subscribeType = CHRE_WIFI_NAN_SUBSCRIBE_TYPE_PASSIVE,
117       .service = "SomeServiceName",
118   };
119   sendEventToNanoapp(appId, NAN_SUBSCRIBE, config);
120   waitForEvent(CHRE_EVENT_WIFI_ASYNC_RESULT);
121 }
122 
123 /**
124  * Test that a subscription request succeeds, and an identifier event is
125  * received with a matching cookie. Also test that a discovery event is later
126  * received, marking the completion of the subscription process.
127  */
TEST_F(WifiNanTest,WifiNanSuccessfulSubscribe)128 TEST_F(WifiNanTest, WifiNanSuccessfulSubscribe) {
129   CREATE_CHRE_TEST_EVENT(NAN_SUBSCRIBE, 0);
130 
131   class App : public NanTestNanoapp {
132    public:
133     void handleEvent(uint32_t, uint16_t eventType,
134                      const void *eventData) override {
135       const uint32_t kSubscribeCookie = 0x10aded;
136 
137       switch (eventType) {
138         case CHRE_EVENT_WIFI_NAN_IDENTIFIER_RESULT: {
139           auto event =
140               static_cast<const chreWifiNanIdentifierEvent *>(eventData);
141           if (event->result.errorCode == CHRE_ERROR_NONE) {
142             TestEventQueueSingleton::get()->pushEvent(
143                 CHRE_EVENT_WIFI_NAN_IDENTIFIER_RESULT, event->id);
144           }
145           break;
146         }
147 
148         case CHRE_EVENT_WIFI_NAN_DISCOVERY_RESULT: {
149           auto event =
150               static_cast<const chreWifiNanDiscoveryEvent *>(eventData);
151           TestEventQueueSingleton::get()->pushEvent(
152               CHRE_EVENT_WIFI_NAN_DISCOVERY_RESULT, event->subscribeId);
153           break;
154         }
155 
156         case CHRE_EVENT_TEST_EVENT: {
157           auto event = static_cast<const TestEvent *>(eventData);
158           switch (event->type) {
159             case NAN_SUBSCRIBE: {
160               auto config = (chreWifiNanSubscribeConfig *)(event->data);
161               const bool success =
162                   chreWifiNanSubscribe(config, &kSubscribeCookie);
163               TestEventQueueSingleton::get()->pushEvent(NAN_SUBSCRIBE, success);
164               break;
165             }
166           }
167         }
168       }
169     }
170   };
171 
172   uint64_t appId = loadNanoapp(MakeUnique<App>());
173 
174   chreWifiNanSubscribeConfig config = {
175       .subscribeType = CHRE_WIFI_NAN_SUBSCRIBE_TYPE_PASSIVE,
176       .service = "SomeServiceName",
177   };
178   sendEventToNanoapp(appId, NAN_SUBSCRIBE, config);
179   bool success;
180   waitForEvent(NAN_SUBSCRIBE, &success);
181   EXPECT_TRUE(success);
182 
183   uint32_t id;
184   waitForEvent(CHRE_EVENT_WIFI_NAN_IDENTIFIER_RESULT, &id);
185   EXPECT_TRUE(PalNanEngineSingleton::get()->isSubscriptionActive(id));
186 
187   PalNanEngineSingleton::get()->sendDiscoveryEvent(id);
188   uint32_t subscribeId;
189   waitForEvent(CHRE_EVENT_WIFI_NAN_DISCOVERY_RESULT, &subscribeId);
190 
191   EXPECT_EQ(id, subscribeId);
192 }
193 
TEST_F(WifiNanTest,WifiNanUnsSubscribeOnNanoappUnload)194 TEST_F(WifiNanTest, WifiNanUnsSubscribeOnNanoappUnload) {
195   CREATE_CHRE_TEST_EVENT(NAN_SUBSCRIBE, 0);
196 
197   class App : public NanTestNanoapp {
198    public:
199     void handleEvent(uint32_t, uint16_t eventType,
200                      const void *eventData) override {
201       const uint32_t kSubscribeCookie = 0x10aded;
202 
203       switch (eventType) {
204         case CHRE_EVENT_WIFI_NAN_IDENTIFIER_RESULT: {
205           auto event =
206               static_cast<const chreWifiNanIdentifierEvent *>(eventData);
207           if (event->result.errorCode == CHRE_ERROR_NONE) {
208             TestEventQueueSingleton::get()->pushEvent(
209                 CHRE_EVENT_WIFI_NAN_IDENTIFIER_RESULT, event->id);
210           }
211           break;
212         }
213 
214         case CHRE_EVENT_TEST_EVENT: {
215           auto event = static_cast<const TestEvent *>(eventData);
216           switch (event->type) {
217             case NAN_SUBSCRIBE: {
218               auto config = (chreWifiNanSubscribeConfig *)(event->data);
219               const bool success =
220                   chreWifiNanSubscribe(config, &kSubscribeCookie);
221               TestEventQueueSingleton::get()->pushEvent(NAN_SUBSCRIBE, success);
222               break;
223             }
224           }
225         }
226       }
227     }
228   };
229 
230   uint64_t appId = loadNanoapp(MakeUnique<App>());
231 
232   chreWifiNanSubscribeConfig config = {
233       .subscribeType = CHRE_WIFI_NAN_SUBSCRIBE_TYPE_PASSIVE,
234       .service = "SomeServiceName",
235   };
236   sendEventToNanoapp(appId, NAN_SUBSCRIBE, config);
237   bool success;
238   waitForEvent(NAN_SUBSCRIBE, &success);
239   EXPECT_TRUE(success);
240 
241   uint32_t id;
242   waitForEvent(CHRE_EVENT_WIFI_NAN_IDENTIFIER_RESULT, &id);
243   EXPECT_TRUE(PalNanEngineSingleton::get()->isSubscriptionActive(id));
244 
245   unloadNanoapp(appId);
246   EXPECT_FALSE(PalNanEngineSingleton::get()->isSubscriptionActive(id));
247 }
248 
249 /**
250  * Test that a subscription request fails, and an identifier event is received
251  * with a matching cookie, indicating the reason for the error (Note that the
252  * fake PAL engine always returns the generic CHRE_ERROR as the error code,
253  * but this may vary in unsimulated scenarios).
254  */
TEST_F(WifiNanTest,WifiNanUnuccessfulSubscribeTest)255 TEST_F(WifiNanTest, WifiNanUnuccessfulSubscribeTest) {
256   CREATE_CHRE_TEST_EVENT(NAN_SUBSCRIBE, 0);
257 
258   class App : public NanTestNanoapp {
259    public:
260     void handleEvent(uint32_t, uint16_t eventType,
261                      const void *eventData) override {
262       const uint32_t kSubscribeCookie = 0x10aded;
263 
264       switch (eventType) {
265         case CHRE_EVENT_WIFI_NAN_IDENTIFIER_RESULT: {
266           auto event =
267               static_cast<const chreWifiNanIdentifierEvent *>(eventData);
268           if (event->result.errorCode != CHRE_ERROR_NONE) {
269             TestEventQueueSingleton::get()->pushEvent(
270                 CHRE_EVENT_WIFI_NAN_IDENTIFIER_RESULT);
271           }
272           break;
273         }
274 
275         case CHRE_EVENT_TEST_EVENT: {
276           auto event = static_cast<const TestEvent *>(eventData);
277           switch (event->type) {
278             case NAN_SUBSCRIBE: {
279               auto config = (chreWifiNanSubscribeConfig *)(event->data);
280               const bool success =
281                   chreWifiNanSubscribe(config, &kSubscribeCookie);
282               TestEventQueueSingleton::get()->pushEvent(NAN_SUBSCRIBE, success);
283               break;
284             }
285           }
286         }
287       }
288     }
289   };
290 
291   uint64_t appId = loadNanoapp(MakeUnique<App>());
292 
293   PalNanEngineSingleton::get()->setFlags(PalNanEngine::Flags::FAIL_SUBSCRIBE);
294 
295   chreWifiNanSubscribeConfig config = {
296       .subscribeType = CHRE_WIFI_NAN_SUBSCRIBE_TYPE_PASSIVE,
297       .service = "SomeServiceName",
298   };
299   sendEventToNanoapp(appId, NAN_SUBSCRIBE, config);
300   bool success;
301   waitForEvent(NAN_SUBSCRIBE, &success);
302   EXPECT_TRUE(success);
303 
304   waitForEvent(CHRE_EVENT_WIFI_NAN_IDENTIFIER_RESULT);
305 }
306 
307 /**
308  * Test that a terminated event is received upon the Pal NAN engine
309  * terminating a discovered service.
310  */
TEST_F(WifiNanTest,WifiNanServiceTerminatedTest)311 TEST_F(WifiNanTest, WifiNanServiceTerminatedTest) {
312   CREATE_CHRE_TEST_EVENT(NAN_SUBSCRIBE, 0);
313 
314   class App : public NanTestNanoapp {
315    public:
316     void handleEvent(uint32_t, uint16_t eventType,
317                      const void *eventData) override {
318       const uint32_t kSubscribeCookie = 0x10aded;
319 
320       switch (eventType) {
321         case CHRE_EVENT_WIFI_NAN_IDENTIFIER_RESULT: {
322           auto event =
323               static_cast<const chreWifiNanIdentifierEvent *>(eventData);
324           if (event->result.errorCode == CHRE_ERROR_NONE) {
325             TestEventQueueSingleton::get()->pushEvent(
326                 CHRE_EVENT_WIFI_NAN_IDENTIFIER_RESULT, event->id);
327           }
328           break;
329         }
330 
331         case CHRE_EVENT_WIFI_NAN_DISCOVERY_RESULT: {
332           auto event =
333               static_cast<const chreWifiNanDiscoveryEvent *>(eventData);
334           TestEventQueueSingleton::get()->pushEvent(
335               CHRE_EVENT_WIFI_NAN_DISCOVERY_RESULT, event->subscribeId);
336           break;
337         }
338 
339         case CHRE_EVENT_WIFI_NAN_SESSION_TERMINATED: {
340           auto event =
341               static_cast<const chreWifiNanSessionTerminatedEvent *>(eventData);
342           TestEventQueueSingleton::get()->pushEvent(
343               CHRE_EVENT_WIFI_NAN_SESSION_TERMINATED, event->id);
344           break;
345         }
346 
347         case CHRE_EVENT_TEST_EVENT: {
348           auto event = static_cast<const TestEvent *>(eventData);
349           switch (event->type) {
350             case NAN_SUBSCRIBE: {
351               auto config = (chreWifiNanSubscribeConfig *)(event->data);
352               const bool success =
353                   chreWifiNanSubscribe(config, &kSubscribeCookie);
354               TestEventQueueSingleton::get()->pushEvent(NAN_SUBSCRIBE, success);
355               break;
356             }
357           }
358         }
359       }
360     }
361   };
362 
363   uint64_t appId = loadNanoapp(MakeUnique<App>());
364 
365   chreWifiNanSubscribeConfig config = {
366       .subscribeType = CHRE_WIFI_NAN_SUBSCRIBE_TYPE_PASSIVE,
367       .service = "SomeServiceName",
368   };
369   sendEventToNanoapp(appId, NAN_SUBSCRIBE, config);
370   bool success;
371   waitForEvent(NAN_SUBSCRIBE, &success);
372   EXPECT_TRUE(success);
373 
374   uint32_t id;
375   waitForEvent(CHRE_EVENT_WIFI_NAN_IDENTIFIER_RESULT, &id);
376 
377   PalNanEngineSingleton::get()->sendDiscoveryEvent(id);
378   uint32_t subscribeId;
379   waitForEvent(CHRE_EVENT_WIFI_NAN_DISCOVERY_RESULT, &subscribeId);
380   EXPECT_EQ(subscribeId, id);
381 
382   PalNanEngineSingleton::get()->onServiceTerminated(id);
383   uint32_t terminatedId;
384   waitForEvent(CHRE_EVENT_WIFI_NAN_SESSION_TERMINATED, &terminatedId);
385   EXPECT_EQ(terminatedId, id);
386 }
387 
388 /**
389  * Test that a service lost event is received upon the Pal NAN engine 'losing'
390  * a discovered service.
391  */
TEST_F(WifiNanTest,WifiNanServiceLostTest)392 TEST_F(WifiNanTest, WifiNanServiceLostTest) {
393   CREATE_CHRE_TEST_EVENT(NAN_SUBSCRIBE, 0);
394 
395   struct Ids {
396     uint32_t subscribe;
397     uint32_t publish;
398   };
399 
400   class App : public NanTestNanoapp {
401    public:
402     void handleEvent(uint32_t, uint16_t eventType,
403                      const void *eventData) override {
404       const uint32_t kSubscribeCookie = 0x10aded;
405 
406       switch (eventType) {
407         case CHRE_EVENT_WIFI_NAN_IDENTIFIER_RESULT: {
408           auto event =
409               static_cast<const chreWifiNanIdentifierEvent *>(eventData);
410           if (event->result.errorCode == CHRE_ERROR_NONE) {
411             TestEventQueueSingleton::get()->pushEvent(
412                 CHRE_EVENT_WIFI_NAN_IDENTIFIER_RESULT, event->id);
413           }
414           break;
415         }
416 
417         case CHRE_EVENT_WIFI_NAN_DISCOVERY_RESULT: {
418           auto event =
419               static_cast<const chreWifiNanDiscoveryEvent *>(eventData);
420           TestEventQueueSingleton::get()->pushEvent(
421               CHRE_EVENT_WIFI_NAN_DISCOVERY_RESULT, event->subscribeId);
422           break;
423         }
424 
425         case CHRE_EVENT_WIFI_NAN_SESSION_LOST: {
426           auto event =
427               static_cast<const chreWifiNanSessionLostEvent *>(eventData);
428           Ids ids = {.subscribe = event->id, .publish = event->peerId};
429           TestEventQueueSingleton::get()->pushEvent(
430               CHRE_EVENT_WIFI_NAN_SESSION_LOST, ids);
431           break;
432         }
433 
434         case CHRE_EVENT_TEST_EVENT: {
435           auto event = static_cast<const TestEvent *>(eventData);
436           switch (event->type) {
437             case NAN_SUBSCRIBE: {
438               auto config = (chreWifiNanSubscribeConfig *)(event->data);
439               const bool success =
440                   chreWifiNanSubscribe(config, &kSubscribeCookie);
441               TestEventQueueSingleton::get()->pushEvent(NAN_SUBSCRIBE, success);
442               break;
443             }
444           }
445         }
446       }
447     }
448   };
449 
450   uint64_t appId = loadNanoapp(MakeUnique<App>());
451 
452   chreWifiNanSubscribeConfig config = {
453       .subscribeType = CHRE_WIFI_NAN_SUBSCRIBE_TYPE_PASSIVE,
454       .service = "SomeServiceName",
455   };
456   sendEventToNanoapp(appId, NAN_SUBSCRIBE, config);
457   bool success;
458   waitForEvent(NAN_SUBSCRIBE, &success);
459   EXPECT_TRUE(success);
460 
461   uint32_t id;
462   waitForEvent(CHRE_EVENT_WIFI_NAN_IDENTIFIER_RESULT, &id);
463 
464   PalNanEngineSingleton::get()->sendDiscoveryEvent(id);
465   uint32_t subscribeId;
466   waitForEvent(CHRE_EVENT_WIFI_NAN_DISCOVERY_RESULT, &subscribeId);
467   EXPECT_EQ(subscribeId, id);
468 
469   PalNanEngineSingleton::get()->onServiceLost(subscribeId, id);
470   Ids ids;
471   waitForEvent(CHRE_EVENT_WIFI_NAN_SESSION_LOST, &ids);
472   EXPECT_EQ(ids.subscribe, id);
473   EXPECT_EQ(ids.publish, id);
474 }
475 
476 /**
477  * Test that a ranging event is received upon requesting NAN range
478  * measurements.
479  */
TEST_F(WifiNanTest,WifiNanRangingTest)480 TEST_F(WifiNanTest, WifiNanRangingTest) {
481   CREATE_CHRE_TEST_EVENT(NAN_SUBSCRIBE, 0);
482   CREATE_CHRE_TEST_EVENT(REQUEST_RANGING, 1);
483 
484   class App : public NanTestNanoapp {
485    public:
486     void handleEvent(uint32_t, uint16_t eventType,
487                      const void *eventData) override {
488       const uint32_t kRangingCookie = 0xfa11;
489       const uint32_t kSubscribeCookie = 0x10aded;
490 
491       switch (eventType) {
492         case CHRE_EVENT_WIFI_ASYNC_RESULT: {
493           auto *event = static_cast<const chreAsyncResult *>(eventData);
494           if (event->requestType == CHRE_WIFI_REQUEST_TYPE_RANGING) {
495             TestEventQueueSingleton::get()->pushEvent(
496                 CHRE_EVENT_WIFI_ASYNC_RESULT);
497           }
498           break;
499         }
500 
501         case CHRE_EVENT_WIFI_RANGING_RESULT: {
502           TestEventQueueSingleton::get()->pushEvent(
503               CHRE_EVENT_WIFI_RANGING_RESULT);
504           break;
505         }
506 
507         case CHRE_EVENT_TEST_EVENT: {
508           auto event = static_cast<const TestEvent *>(eventData);
509           switch (event->type) {
510             case NAN_SUBSCRIBE: {
511               auto config = (chreWifiNanSubscribeConfig *)(event->data);
512               const bool success =
513                   chreWifiNanSubscribe(config, &kSubscribeCookie);
514               TestEventQueueSingleton::get()->pushEvent(NAN_SUBSCRIBE, success);
515               break;
516             }
517 
518             case REQUEST_RANGING: {
519               uint8_t fakeMacAddress[CHRE_WIFI_BSSID_LEN] = {0x1, 0x2, 0x3,
520                                                              0x4, 0x5, 0x6};
521               struct chreWifiNanRangingParams fakeRangingParams;
522               std::memcpy(fakeRangingParams.macAddress, fakeMacAddress,
523                           CHRE_WIFI_BSSID_LEN);
524               const bool success = chreWifiNanRequestRangingAsync(
525                   &fakeRangingParams, &kRangingCookie);
526               TestEventQueueSingleton::get()->pushEvent(REQUEST_RANGING,
527                                                         success);
528               break;
529             }
530           }
531         }
532       }
533     }
534   };
535 
536   uint64_t appId = loadNanoapp(MakeUnique<App>());
537 
538   bool success;
539 
540   chreWifiNanSubscribeConfig config = {
541       .subscribeType = CHRE_WIFI_NAN_SUBSCRIBE_TYPE_PASSIVE,
542       .service = "SomeServiceName",
543   };
544   sendEventToNanoapp(appId, NAN_SUBSCRIBE, config);
545   waitForEvent(NAN_SUBSCRIBE, &success);
546   EXPECT_TRUE(success);
547 
548   sendEventToNanoapp(appId, REQUEST_RANGING, config);
549   waitForEvent(REQUEST_RANGING, &success);
550   EXPECT_TRUE(success);
551   waitForEvent(CHRE_EVENT_WIFI_ASYNC_RESULT);
552   waitForEvent(CHRE_EVENT_WIFI_RANGING_RESULT);
553 }
554 
TEST_F(WifiNanTest,WifiNanSubscribeCancelTest)555 TEST_F(WifiNanTest, WifiNanSubscribeCancelTest) {
556   CREATE_CHRE_TEST_EVENT(NAN_SUBSCRIBE, 0);
557   CREATE_CHRE_TEST_EVENT(NAN_SUBSCRIBE_DONE, 1);
558   CREATE_CHRE_TEST_EVENT(NAN_UNSUBSCRIBE, 2);
559   CREATE_CHRE_TEST_EVENT(NAN_UNSUBSCRIBE_DONE, 3);
560 
561   class App : public NanTestNanoapp {
562    public:
563     void handleEvent(uint32_t, uint16_t eventType,
564                      const void *eventData) override {
565       const uint32_t kSubscribeCookie = 0x10aded;
566 
567       switch (eventType) {
568         case CHRE_EVENT_WIFI_NAN_IDENTIFIER_RESULT: {
569           auto event =
570               static_cast<const chreWifiNanIdentifierEvent *>(eventData);
571           if (event->result.errorCode == CHRE_ERROR_NONE) {
572             TestEventQueueSingleton::get()->pushEvent(
573                 CHRE_EVENT_WIFI_NAN_IDENTIFIER_RESULT, event->id);
574           }
575           break;
576         }
577 
578         case CHRE_EVENT_TEST_EVENT: {
579           auto event = static_cast<const TestEvent *>(eventData);
580           switch (event->type) {
581             case NAN_SUBSCRIBE: {
582               auto config = (chreWifiNanSubscribeConfig *)(event->data);
583               bool success = chreWifiNanSubscribe(config, &kSubscribeCookie);
584               TestEventQueueSingleton::get()->pushEvent(NAN_SUBSCRIBE_DONE,
585                                                         success);
586               break;
587             }
588             case NAN_UNSUBSCRIBE: {
589               auto *id = static_cast<uint32_t *>(event->data);
590               bool success = chreWifiNanSubscribeCancel(*id);
591               // Note that since we're 'simulating' NAN functionality here,
592               // the async subscribe cancel event will be handled before
593               // the return event below is posted. For a real on-device (or
594               // non-simulated) test, this won't be the case, and care must
595               // be taken to handle the asynchronicity appropriately.
596               TestEventQueueSingleton::get()->pushEvent(NAN_UNSUBSCRIBE_DONE,
597                                                         success);
598               break;
599             }
600           }
601         }
602       }
603     }
604   };
605 
606   uint64_t appId = loadNanoapp(MakeUnique<App>());
607 
608   chreWifiNanSubscribeConfig config = {
609       .subscribeType = CHRE_WIFI_NAN_SUBSCRIBE_TYPE_PASSIVE,
610       .service = "SomeServiceName",
611   };
612 
613   bool success = false;
614   sendEventToNanoapp(appId, NAN_SUBSCRIBE, config);
615   waitForEvent(NAN_SUBSCRIBE_DONE, &success);
616   ASSERT_TRUE(success);
617 
618   uint32_t id;
619   waitForEvent(CHRE_EVENT_WIFI_NAN_IDENTIFIER_RESULT, &id);
620 
621   auto &wifiRequestManager =
622       EventLoopManagerSingleton::get()->getWifiRequestManager();
623   EXPECT_EQ(wifiRequestManager.getNumNanSubscriptions(), 1);
624 
625   success = false;
626   sendEventToNanoapp(appId, NAN_UNSUBSCRIBE, id);
627   waitForEvent(NAN_UNSUBSCRIBE_DONE, &success);
628   ASSERT_TRUE(success);
629   // TODO(b/272351526): consider adding an async result event to catch when the
630   //                     unsubscribe has finished
631   // EXPECT_EQ(wifiRequestManager.getNumNanSubscriptions(), 0);
632 }
633 
634 }  // anonymous namespace
635 }  // namespace chre
636