1#!/usr/bin/python3.4
2#
3#   Copyright 2017 - The Android Open Source Project
4#
5#   Licensed under the Apache License, Version 2.0 (the "License");
6#   you may not use this file except in compliance with the License.
7#   You may obtain a copy of the License at
8#
9#       http://www.apache.org/licenses/LICENSE-2.0
10#
11#   Unless required by applicable law or agreed to in writing, software
12#   distributed under the License is distributed on an "AS IS" BASIS,
13#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14#   See the License for the specific language governing permissions and
15#   limitations under the License.
16
17import queue
18import string
19import time
20
21from acts import asserts
22from acts.test_decorators import test_tracker_info
23from acts_contrib.test_utils.wifi.aware import aware_const as aconsts
24from acts_contrib.test_utils.wifi.aware import aware_test_utils as autils
25from acts_contrib.test_utils.wifi.aware.AwareBaseTest import AwareBaseTest
26from acts_contrib.test_utils.wifi.WifiBaseTest import WifiBaseTest
27
28
29class DiscoveryTest(AwareBaseTest):
30    """Set of tests for Wi-Fi Aware discovery."""
31
32    # configuration parameters used by tests
33    PAYLOAD_SIZE_MIN = 0
34    PAYLOAD_SIZE_TYPICAL = 1
35    PAYLOAD_SIZE_MAX = 2
36    EVENT_TIMEOUT = 3
37
38    # message strings
39    query_msg = "How are you doing? 你好嗎?"
40    response_msg = "Doing ok - thanks! 做的不錯 - 謝謝!"
41
42    # message re-transmit counter (increases reliability in open-environment)
43    # Note: reliability of message transmission is tested elsewhere
44    msg_retx_count = 5  # hard-coded max value, internal API
45
46    def create_base_config(self, caps, is_publish, ptype, stype, payload_size,
47                           ttl, term_ind_on, null_match):
48        """Create a base configuration based on input parameters.
49
50    Args:
51      caps: device capability dictionary
52      is_publish: True if a publish config, else False
53      ptype: unsolicited or solicited (used if is_publish is True)
54      stype: passive or active (used if is_publish is False)
55      payload_size: min, typical, max (PAYLOAD_SIZE_xx)
56      ttl: time-to-live configuration (0 - forever)
57      term_ind_on: is termination indication enabled
58      null_match: null-out the middle match filter
59    Returns:
60      publish discovery configuration object.
61    """
62        config = {}
63        if is_publish:
64            config[aconsts.DISCOVERY_KEY_DISCOVERY_TYPE] = ptype
65        else:
66            config[aconsts.DISCOVERY_KEY_DISCOVERY_TYPE] = stype
67        config[aconsts.DISCOVERY_KEY_TTL] = ttl
68        config[aconsts.DISCOVERY_KEY_TERM_CB_ENABLED] = term_ind_on
69        if payload_size == self.PAYLOAD_SIZE_MIN:
70            config[aconsts.DISCOVERY_KEY_SERVICE_NAME] = "a"
71            config[aconsts.DISCOVERY_KEY_SSI] = None
72            config[aconsts.DISCOVERY_KEY_MATCH_FILTER_LIST] = []
73        elif payload_size == self.PAYLOAD_SIZE_TYPICAL:
74            config[aconsts.DISCOVERY_KEY_SERVICE_NAME] = "GoogleTestServiceX"
75            if is_publish:
76                config[aconsts.DISCOVERY_KEY_SSI] = string.ascii_letters
77            else:
78                config[aconsts.
79                       DISCOVERY_KEY_SSI] = string.ascii_letters[::
80                                                                 -1]  # reverse
81            config[
82                aconsts.DISCOVERY_KEY_MATCH_FILTER_LIST] = autils.encode_list(
83                    [(10).to_bytes(1, byteorder="big"), "hello there string"
84                     if not null_match else None,
85                     bytes(range(40))])
86        else:  # PAYLOAD_SIZE_MAX
87            config[aconsts.DISCOVERY_KEY_SERVICE_NAME] = "VeryLong" + "X" * (
88                caps[aconsts.CAP_MAX_SERVICE_NAME_LEN] - 8)
89            config[aconsts.DISCOVERY_KEY_SSI] = (
90                "P" if is_publish else
91                "S") * caps[aconsts.CAP_MAX_SERVICE_SPECIFIC_INFO_LEN]
92            mf = autils.construct_max_match_filter(
93                caps[aconsts.CAP_MAX_MATCH_FILTER_LEN])
94            if null_match:
95                mf[2] = None
96            config[aconsts.
97                   DISCOVERY_KEY_MATCH_FILTER_LIST] = autils.encode_list(mf)
98
99        return config
100
101    def create_publish_config(self, caps, ptype, payload_size, ttl,
102                              term_ind_on, null_match):
103        """Create a publish configuration based on input parameters.
104
105    Args:
106      caps: device capability dictionary
107      ptype: unsolicited or solicited
108      payload_size: min, typical, max (PAYLOAD_SIZE_xx)
109      ttl: time-to-live configuration (0 - forever)
110      term_ind_on: is termination indication enabled
111      null_match: null-out the middle match filter
112    Returns:
113      publish discovery configuration object.
114    """
115        return self.create_base_config(caps, True, ptype, None, payload_size,
116                                       ttl, term_ind_on, null_match)
117
118    def create_subscribe_config(self, caps, stype, payload_size, ttl,
119                                term_ind_on, null_match):
120        """Create a subscribe configuration based on input parameters.
121
122    Args:
123      caps: device capability dictionary
124      stype: passive or active
125      payload_size: min, typical, max (PAYLOAD_SIZE_xx)
126      ttl: time-to-live configuration (0 - forever)
127      term_ind_on: is termination indication enabled
128      null_match: null-out the middle match filter
129    Returns:
130      subscribe discovery configuration object.
131    """
132        return self.create_base_config(caps, False, None, stype, payload_size,
133                                       ttl, term_ind_on, null_match)
134
135    def positive_discovery_test_utility(self, ptype, stype, payload_size):
136        """Utility which runs a positive discovery test:
137    - Discovery (publish/subscribe) with TTL=0 (non-self-terminating)
138    - Exchange messages
139    - Update publish/subscribe
140    - Terminate
141
142    Args:
143      ptype: Publish discovery type
144      stype: Subscribe discovery type
145      payload_size: One of PAYLOAD_SIZE_* constants - MIN, TYPICAL, MAX
146    """
147        p_dut = self.android_devices[0]
148        p_dut.pretty_name = "Publisher"
149        s_dut = self.android_devices[1]
150        s_dut.pretty_name = "Subscriber"
151
152        # Publisher+Subscriber: attach and wait for confirmation
153        p_id = p_dut.droid.wifiAwareAttach(False)
154        autils.wait_for_event(p_dut, aconsts.EVENT_CB_ON_ATTACHED)
155        time.sleep(self.device_startup_offset)
156        s_id = s_dut.droid.wifiAwareAttach(False)
157        autils.wait_for_event(s_dut, aconsts.EVENT_CB_ON_ATTACHED)
158
159        # Publisher: start publish and wait for confirmation
160        p_config = self.create_publish_config(
161            p_dut.aware_capabilities,
162            ptype,
163            payload_size,
164            ttl=0,
165            term_ind_on=False,
166            null_match=False)
167        p_disc_id = p_dut.droid.wifiAwarePublish(p_id, p_config)
168        autils.wait_for_event(p_dut, aconsts.SESSION_CB_ON_PUBLISH_STARTED)
169
170        # Subscriber: start subscribe and wait for confirmation
171        s_config = self.create_subscribe_config(
172            s_dut.aware_capabilities,
173            stype,
174            payload_size,
175            ttl=0,
176            term_ind_on=False,
177            null_match=True)
178        s_disc_id = s_dut.droid.wifiAwareSubscribe(s_id, s_config)
179        autils.wait_for_event(s_dut, aconsts.SESSION_CB_ON_SUBSCRIBE_STARTED)
180
181        # Subscriber: wait for service discovery
182        discovery_event = autils.wait_for_event(
183            s_dut, aconsts.SESSION_CB_ON_SERVICE_DISCOVERED)
184        peer_id_on_sub = discovery_event["data"][
185            aconsts.SESSION_CB_KEY_PEER_ID]
186
187        # Subscriber: validate contents of discovery:
188        # - SSI: publisher's
189        # - Match filter: UNSOLICITED - publisher, SOLICITED - subscriber
190        autils.assert_equal_strings(
191            bytes(discovery_event["data"][
192                aconsts.SESSION_CB_KEY_SERVICE_SPECIFIC_INFO]).decode("utf-8"),
193            p_config[aconsts.DISCOVERY_KEY_SSI],
194            "Discovery mismatch: service specific info (SSI)")
195        asserts.assert_equal(
196            autils.decode_list(discovery_event["data"][
197                aconsts.SESSION_CB_KEY_MATCH_FILTER_LIST]),
198            autils.decode_list(
199                p_config[aconsts.DISCOVERY_KEY_MATCH_FILTER_LIST]
200                if ptype == aconsts.PUBLISH_TYPE_UNSOLICITED else s_config[
201                    aconsts.DISCOVERY_KEY_MATCH_FILTER_LIST]),
202            "Discovery mismatch: match filter")
203
204        # Subscriber: send message to peer (Publisher)
205        s_dut.droid.wifiAwareSendMessage(s_disc_id, peer_id_on_sub,
206                                         self.get_next_msg_id(),
207                                         self.query_msg, self.msg_retx_count)
208        autils.wait_for_event(s_dut, aconsts.SESSION_CB_ON_MESSAGE_SENT)
209
210        # Publisher: wait for received message
211        pub_rx_msg_event = autils.wait_for_event(
212            p_dut, aconsts.SESSION_CB_ON_MESSAGE_RECEIVED)
213        peer_id_on_pub = pub_rx_msg_event["data"][
214            aconsts.SESSION_CB_KEY_PEER_ID]
215
216        # Publisher: validate contents of message
217        asserts.assert_equal(
218            pub_rx_msg_event["data"][aconsts.SESSION_CB_KEY_MESSAGE_AS_STRING],
219            self.query_msg, "Subscriber -> Publisher message corrupted")
220
221        # Publisher: send message to peer (Subscriber)
222        p_dut.droid.wifiAwareSendMessage(p_disc_id, peer_id_on_pub,
223                                         self.get_next_msg_id(),
224                                         self.response_msg,
225                                         self.msg_retx_count)
226        autils.wait_for_event(p_dut, aconsts.SESSION_CB_ON_MESSAGE_SENT)
227
228        # Subscriber: wait for received message
229        sub_rx_msg_event = autils.wait_for_event(
230            s_dut, aconsts.SESSION_CB_ON_MESSAGE_RECEIVED)
231
232        # Subscriber: validate contents of message
233        asserts.assert_equal(
234            sub_rx_msg_event["data"][aconsts.SESSION_CB_KEY_PEER_ID],
235            peer_id_on_sub,
236            "Subscriber received message from different peer ID then discovery!?"
237        )
238        autils.assert_equal_strings(
239            sub_rx_msg_event["data"][aconsts.SESSION_CB_KEY_MESSAGE_AS_STRING],
240            self.response_msg, "Publisher -> Subscriber message corrupted")
241
242        # Subscriber: validate that we're not getting another Service Discovery
243        autils.fail_on_event(s_dut, aconsts.SESSION_CB_ON_SERVICE_DISCOVERED)
244
245        # Publisher: update publish and wait for confirmation
246        p_config[aconsts.DISCOVERY_KEY_SSI] = "something else"
247        p_dut.droid.wifiAwareUpdatePublish(p_disc_id, p_config)
248        autils.wait_for_event(p_dut,
249                              aconsts.SESSION_CB_ON_SESSION_CONFIG_UPDATED)
250
251        # Subscriber: expect a new service discovery
252        discovery_event = autils.wait_for_event(
253            s_dut, aconsts.SESSION_CB_ON_SERVICE_DISCOVERED)
254
255        # Subscriber: validate contents of discovery
256        autils.assert_equal_strings(
257            bytes(discovery_event["data"][
258                aconsts.SESSION_CB_KEY_SERVICE_SPECIFIC_INFO]).decode("utf-8"),
259            p_config[aconsts.DISCOVERY_KEY_SSI],
260            "Discovery mismatch (after pub update): service specific info (SSI)"
261        )
262        asserts.assert_equal(
263            autils.decode_list(discovery_event["data"][
264                aconsts.SESSION_CB_KEY_MATCH_FILTER_LIST]),
265            autils.decode_list(
266                p_config[aconsts.DISCOVERY_KEY_MATCH_FILTER_LIST]
267                if ptype == aconsts.PUBLISH_TYPE_UNSOLICITED else s_config[
268                    aconsts.DISCOVERY_KEY_MATCH_FILTER_LIST]),
269            "Discovery mismatch: match filter")
270        asserts.assert_equal(
271            peer_id_on_sub,
272            discovery_event["data"][aconsts.SESSION_CB_KEY_PEER_ID],
273            "Peer ID changed when publish was updated!?")
274
275        # Subscribe: update subscribe and wait for confirmation
276        s_config = self.create_subscribe_config(
277            s_dut.aware_capabilities,
278            stype,
279            payload_size,
280            ttl=0,
281            term_ind_on=False,
282            null_match=False)
283        s_dut.droid.wifiAwareUpdateSubscribe(s_disc_id, s_config)
284        autils.wait_for_event(s_dut,
285                              aconsts.SESSION_CB_ON_SESSION_CONFIG_UPDATED)
286
287        # Publisher+Subscriber: Terminate sessions
288        p_dut.droid.wifiAwareDestroyDiscoverySession(p_disc_id)
289        s_dut.droid.wifiAwareDestroyDiscoverySession(s_disc_id)
290
291        autils.wait_for_event(p_dut,
292                              aconsts.SESSION_CB_ON_SESSION_TERMINATED)
293        autils.wait_for_event(s_dut,
294                              aconsts.SESSION_CB_ON_SESSION_TERMINATED)
295
296        # verify that forbidden callbacks aren't called
297        autils.validate_forbidden_callbacks(p_dut, {aconsts.CB_EV_MATCH: 0})
298
299    def verify_discovery_session_term(self, dut, disc_id, config, is_publish,
300                                      term_ind_on):
301        """Utility to verify that the specified discovery session has terminated (by
302    waiting for the TTL and then attempting to reconfigure).
303
304    Args:
305      dut: device under test
306      disc_id: discovery id for the existing session
307      config: configuration of the existing session
308      is_publish: True if the configuration was publish, False if subscribe
309      term_ind_on: True if a termination indication is expected, False otherwise
310    """
311        # Wait for session termination
312        if term_ind_on:
313            autils.wait_for_event(
314                dut,
315                autils.decorate_event(aconsts.SESSION_CB_ON_SESSION_TERMINATED,
316                                      disc_id))
317        else:
318            # can't defer wait to end since in any case have to wait for session to
319            # expire
320            autils.fail_on_event(
321                dut,
322                autils.decorate_event(aconsts.SESSION_CB_ON_SESSION_TERMINATED,
323                                      disc_id))
324
325        # Validate that session expired by trying to configure it (expect failure)
326        config[aconsts.DISCOVERY_KEY_SSI] = "something else"
327        if is_publish:
328            dut.droid.wifiAwareUpdatePublish(disc_id, config)
329        else:
330            dut.droid.wifiAwareUpdateSubscribe(disc_id, config)
331
332        # The response to update discovery session is:
333        # term_ind_on=True: session was cleaned-up so won't get an explicit failure, but won't get a
334        #                   success either. Can check for no SESSION_CB_ON_SESSION_CONFIG_UPDATED but
335        #                   will defer to the end of the test (no events on queue).
336        # term_ind_on=False: session was not cleaned-up (yet). So expect
337        #                    SESSION_CB_ON_SESSION_CONFIG_FAILED.
338        if not term_ind_on:
339            autils.wait_for_event(
340                dut,
341                autils.decorate_event(
342                    aconsts.SESSION_CB_ON_SESSION_CONFIG_FAILED, disc_id))
343
344    def positive_ttl_test_utility(self, is_publish, ptype, stype, term_ind_on):
345        """Utility which runs a positive discovery session TTL configuration test
346
347    Iteration 1: Verify session started with TTL
348    Iteration 2: Verify session started without TTL and reconfigured with TTL
349    Iteration 3: Verify session started with (long) TTL and reconfigured with
350                 (short) TTL
351
352    Args:
353      is_publish: True if testing publish, False if testing subscribe
354      ptype: Publish discovery type (used if is_publish is True)
355      stype: Subscribe discovery type (used if is_publish is False)
356      term_ind_on: Configuration of termination indication
357    """
358        SHORT_TTL = 5  # 5 seconds
359        LONG_TTL = 100  # 100 seconds
360        dut = self.android_devices[0]
361
362        # Attach and wait for confirmation
363        id = dut.droid.wifiAwareAttach(False)
364        autils.wait_for_event(dut, aconsts.EVENT_CB_ON_ATTACHED)
365
366        # Iteration 1: Start discovery session with TTL
367        config = self.create_base_config(
368            dut.aware_capabilities, is_publish, ptype, stype,
369            self.PAYLOAD_SIZE_TYPICAL, SHORT_TTL, term_ind_on, False)
370        if is_publish:
371            disc_id = dut.droid.wifiAwarePublish(id, config, True)
372            autils.wait_for_event(
373                dut,
374                autils.decorate_event(aconsts.SESSION_CB_ON_PUBLISH_STARTED,
375                                      disc_id))
376        else:
377            disc_id = dut.droid.wifiAwareSubscribe(id, config, True)
378            autils.wait_for_event(
379                dut,
380                autils.decorate_event(aconsts.SESSION_CB_ON_SUBSCRIBE_STARTED,
381                                      disc_id))
382
383        # Wait for session termination & verify
384        self.verify_discovery_session_term(dut, disc_id, config, is_publish,
385                                           term_ind_on)
386
387        # Iteration 2: Start a discovery session without TTL
388        config = self.create_base_config(
389            dut.aware_capabilities, is_publish, ptype, stype,
390            self.PAYLOAD_SIZE_TYPICAL, 0, term_ind_on, False)
391        if is_publish:
392            disc_id = dut.droid.wifiAwarePublish(id, config, True)
393            autils.wait_for_event(
394                dut,
395                autils.decorate_event(aconsts.SESSION_CB_ON_PUBLISH_STARTED,
396                                      disc_id))
397        else:
398            disc_id = dut.droid.wifiAwareSubscribe(id, config, True)
399            autils.wait_for_event(
400                dut,
401                autils.decorate_event(aconsts.SESSION_CB_ON_SUBSCRIBE_STARTED,
402                                      disc_id))
403
404        # Update with a TTL
405        config = self.create_base_config(
406            dut.aware_capabilities, is_publish, ptype, stype,
407            self.PAYLOAD_SIZE_TYPICAL, SHORT_TTL, term_ind_on, False)
408        if is_publish:
409            dut.droid.wifiAwareUpdatePublish(disc_id, config)
410        else:
411            dut.droid.wifiAwareUpdateSubscribe(disc_id, config)
412        autils.wait_for_event(
413            dut,
414            autils.decorate_event(aconsts.SESSION_CB_ON_SESSION_CONFIG_UPDATED,
415                                  disc_id))
416
417        # Wait for session termination & verify
418        self.verify_discovery_session_term(dut, disc_id, config, is_publish,
419                                           term_ind_on)
420
421        # Iteration 3: Start a discovery session with (long) TTL
422        config = self.create_base_config(
423            dut.aware_capabilities, is_publish, ptype, stype,
424            self.PAYLOAD_SIZE_TYPICAL, LONG_TTL, term_ind_on, False)
425        if is_publish:
426            disc_id = dut.droid.wifiAwarePublish(id, config, True)
427            autils.wait_for_event(
428                dut,
429                autils.decorate_event(aconsts.SESSION_CB_ON_PUBLISH_STARTED,
430                                      disc_id))
431        else:
432            disc_id = dut.droid.wifiAwareSubscribe(id, config, True)
433            autils.wait_for_event(
434                dut,
435                autils.decorate_event(aconsts.SESSION_CB_ON_SUBSCRIBE_STARTED,
436                                      disc_id))
437
438        # Update with a TTL
439        config = self.create_base_config(
440            dut.aware_capabilities, is_publish, ptype, stype,
441            self.PAYLOAD_SIZE_TYPICAL, SHORT_TTL, term_ind_on, False)
442        if is_publish:
443            dut.droid.wifiAwareUpdatePublish(disc_id, config)
444        else:
445            dut.droid.wifiAwareUpdateSubscribe(disc_id, config)
446        autils.wait_for_event(
447            dut,
448            autils.decorate_event(aconsts.SESSION_CB_ON_SESSION_CONFIG_UPDATED,
449                                  disc_id))
450
451        # Wait for session termination & verify
452        self.verify_discovery_session_term(dut, disc_id, config, is_publish,
453                                           term_ind_on)
454
455        # verify that there were no other events
456        autils.verify_no_more_events(dut)
457
458        # verify that forbidden callbacks aren't called
459        if not term_ind_on:
460            autils.validate_forbidden_callbacks(
461                dut, {
462                    aconsts.CB_EV_PUBLISH_TERMINATED: 0,
463                    aconsts.CB_EV_SUBSCRIBE_TERMINATED: 0
464                })
465
466    def discovery_mismatch_test_utility(self,
467                                        is_expected_to_pass,
468                                        p_type,
469                                        s_type,
470                                        p_service_name=None,
471                                        s_service_name=None,
472                                        p_mf_1=None,
473                                        s_mf_1=None):
474        """Utility which runs the negative discovery test for mismatched service
475    configs.
476
477    Args:
478      is_expected_to_pass: True if positive test, False if negative
479      p_type: Publish discovery type
480      s_type: Subscribe discovery type
481      p_service_name: Publish service name (or None to leave unchanged)
482      s_service_name: Subscribe service name (or None to leave unchanged)
483      p_mf_1: Publish match filter element [1] (or None to leave unchanged)
484      s_mf_1: Subscribe match filter element [1] (or None to leave unchanged)
485    """
486        p_dut = self.android_devices[0]
487        p_dut.pretty_name = "Publisher"
488        s_dut = self.android_devices[1]
489        s_dut.pretty_name = "Subscriber"
490
491        # create configurations
492        p_config = self.create_publish_config(
493            p_dut.aware_capabilities,
494            p_type,
495            self.PAYLOAD_SIZE_TYPICAL,
496            ttl=0,
497            term_ind_on=False,
498            null_match=False)
499        if p_service_name is not None:
500            p_config[aconsts.DISCOVERY_KEY_SERVICE_NAME] = p_service_name
501        if p_mf_1 is not None:
502            p_config[
503                aconsts.DISCOVERY_KEY_MATCH_FILTER_LIST] = autils.encode_list(
504                    [(10).to_bytes(1, byteorder="big"), p_mf_1,
505                     bytes(range(40))])
506        s_config = self.create_publish_config(
507            s_dut.aware_capabilities,
508            s_type,
509            self.PAYLOAD_SIZE_TYPICAL,
510            ttl=0,
511            term_ind_on=False,
512            null_match=False)
513        if s_service_name is not None:
514            s_config[aconsts.DISCOVERY_KEY_SERVICE_NAME] = s_service_name
515        if s_mf_1 is not None:
516            s_config[
517                aconsts.DISCOVERY_KEY_MATCH_FILTER_LIST] = autils.encode_list(
518                    [(10).to_bytes(1, byteorder="big"), s_mf_1,
519                     bytes(range(40))])
520
521        p_id = p_dut.droid.wifiAwareAttach(False)
522        autils.wait_for_event(p_dut, aconsts.EVENT_CB_ON_ATTACHED)
523        time.sleep(self.device_startup_offset)
524        s_id = s_dut.droid.wifiAwareAttach(False)
525        autils.wait_for_event(s_dut, aconsts.EVENT_CB_ON_ATTACHED)
526
527        # Publisher: start publish and wait for confirmation
528        p_disc_id = p_dut.droid.wifiAwarePublish(p_id, p_config)
529        autils.wait_for_event(p_dut, aconsts.SESSION_CB_ON_PUBLISH_STARTED)
530
531        # Subscriber: start subscribe and wait for confirmation
532        s_disc_id = s_dut.droid.wifiAwareSubscribe(s_id, s_config)
533        autils.wait_for_event(s_dut, aconsts.SESSION_CB_ON_SUBSCRIBE_STARTED)
534
535        # Subscriber: fail on service discovery
536        if is_expected_to_pass:
537            autils.wait_for_event(s_dut,
538                                  aconsts.SESSION_CB_ON_SERVICE_DISCOVERED)
539        else:
540            autils.fail_on_event(s_dut,
541                                 aconsts.SESSION_CB_ON_SERVICE_DISCOVERED)
542
543        # Publisher+Subscriber: Terminate sessions
544        p_dut.droid.wifiAwareDestroyDiscoverySession(p_disc_id)
545        s_dut.droid.wifiAwareDestroyDiscoverySession(s_disc_id)
546        autils.wait_for_event(p_dut,
547                              aconsts.SESSION_CB_ON_SESSION_TERMINATED)
548        autils.wait_for_event(s_dut,
549                          aconsts.SESSION_CB_ON_SESSION_TERMINATED)
550
551        # verify that there were no other events (including terminations)
552        autils.verify_no_more_events(p_dut, timeout=0)
553        autils.verify_no_more_events(s_dut, timeout=0)
554
555    #######################################
556    # Positive tests key:
557    #
558    # names is: test_<pub_type>_<sub_type>_<size>
559    # where:
560    #
561    # pub_type: Type of publish discovery session: unsolicited or solicited.
562    # sub_type: Type of subscribe discovery session: passive or active.
563    # size: Size of payload fields (service name, service specific info, and match
564    # filter: typical, max, or min.
565    #######################################
566
567    @test_tracker_info(uuid="954ebbde-ed2b-4f04-9e68-88239187d69d")
568    @WifiBaseTest.wifi_test_wrap
569    def test_positive_unsolicited_passive_typical(self):
570        """Functional test case / Discovery test cases / positive test case:
571    - Solicited publish + passive subscribe
572    - Typical payload fields size
573
574    Verifies that discovery and message exchange succeeds.
575    """
576        self.positive_discovery_test_utility(
577            ptype=aconsts.PUBLISH_TYPE_UNSOLICITED,
578            stype=aconsts.SUBSCRIBE_TYPE_PASSIVE,
579            payload_size=self.PAYLOAD_SIZE_TYPICAL)
580
581    @test_tracker_info(uuid="67fb22bb-6985-4345-95a4-90b76681a58b")
582    def test_positive_unsolicited_passive_min(self):
583        """Functional test case / Discovery test cases / positive test case:
584    - Solicited publish + passive subscribe
585    - Minimal payload fields size
586
587    Verifies that discovery and message exchange succeeds.
588    """
589        self.positive_discovery_test_utility(
590            ptype=aconsts.PUBLISH_TYPE_UNSOLICITED,
591            stype=aconsts.SUBSCRIBE_TYPE_PASSIVE,
592            payload_size=self.PAYLOAD_SIZE_MIN)
593
594    @test_tracker_info(uuid="a02a47b9-41bb-47bb-883b-921024a2c30d")
595    def test_positive_unsolicited_passive_max(self):
596        """Functional test case / Discovery test cases / positive test case:
597    - Solicited publish + passive subscribe
598    - Maximal payload fields size
599
600    Verifies that discovery and message exchange succeeds.
601    """
602        self.positive_discovery_test_utility(
603            ptype=aconsts.PUBLISH_TYPE_UNSOLICITED,
604            stype=aconsts.SUBSCRIBE_TYPE_PASSIVE,
605            payload_size=self.PAYLOAD_SIZE_MAX)
606
607    @test_tracker_info(uuid="586c657f-2388-4e7a-baee-9bce2f3d1a16")
608    def test_positive_solicited_active_typical(self):
609        """Functional test case / Discovery test cases / positive test case:
610    - Unsolicited publish + active subscribe
611    - Typical payload fields size
612
613    Verifies that discovery and message exchange succeeds.
614    """
615        self.positive_discovery_test_utility(
616            ptype=aconsts.PUBLISH_TYPE_SOLICITED,
617            stype=aconsts.SUBSCRIBE_TYPE_ACTIVE,
618            payload_size=self.PAYLOAD_SIZE_TYPICAL)
619
620    @test_tracker_info(uuid="5369e4ff-f406-48c5-b41a-df38ec340146")
621    def test_positive_solicited_active_min(self):
622        """Functional test case / Discovery test cases / positive test case:
623    - Unsolicited publish + active subscribe
624    - Minimal payload fields size
625
626    Verifies that discovery and message exchange succeeds.
627    """
628        self.positive_discovery_test_utility(
629            ptype=aconsts.PUBLISH_TYPE_SOLICITED,
630            stype=aconsts.SUBSCRIBE_TYPE_ACTIVE,
631            payload_size=self.PAYLOAD_SIZE_MIN)
632
633    @test_tracker_info(uuid="634c6eb8-2c4f-42bd-9bbb-d874d0ec22f3")
634    def test_positive_solicited_active_max(self):
635        """Functional test case / Discovery test cases / positive test case:
636    - Unsolicited publish + active subscribe
637    - Maximal payload fields size
638
639    Verifies that discovery and message exchange succeeds.
640    """
641        self.positive_discovery_test_utility(
642            ptype=aconsts.PUBLISH_TYPE_SOLICITED,
643            stype=aconsts.SUBSCRIBE_TYPE_ACTIVE,
644            payload_size=self.PAYLOAD_SIZE_MAX)
645
646    #######################################
647    # TTL tests key:
648    #
649    # names is: test_ttl_<pub_type|sub_type>_<term_ind>
650    # where:
651    #
652    # pub_type: Type of publish discovery session: unsolicited or solicited.
653    # sub_type: Type of subscribe discovery session: passive or active.
654    # term_ind: ind_on or ind_off
655    #######################################
656
657    @test_tracker_info(uuid="9d7e758e-e0e2-4550-bcee-bfb6a2bff63e")
658    def test_ttl_unsolicited_ind_on(self):
659        """Functional test case / Discovery test cases / TTL test case:
660    - Unsolicited publish
661    - Termination indication enabled
662    """
663        self.positive_ttl_test_utility(
664            is_publish=True,
665            ptype=aconsts.PUBLISH_TYPE_UNSOLICITED,
666            stype=None,
667            term_ind_on=True)
668
669    @test_tracker_info(uuid="48fd69bc-cc2a-4f65-a0a1-63d7c1720702")
670    def test_ttl_unsolicited_ind_off(self):
671        """Functional test case / Discovery test cases / TTL test case:
672    - Unsolicited publish
673    - Termination indication disabled
674    """
675        self.positive_ttl_test_utility(
676            is_publish=True,
677            ptype=aconsts.PUBLISH_TYPE_UNSOLICITED,
678            stype=None,
679            term_ind_on=False)
680
681    @test_tracker_info(uuid="afb75fc1-9ba7-446a-b5ed-7cd37ab51b1c")
682    def test_ttl_solicited_ind_on(self):
683        """Functional test case / Discovery test cases / TTL test case:
684    - Solicited publish
685    - Termination indication enabled
686    """
687        self.positive_ttl_test_utility(
688            is_publish=True,
689            ptype=aconsts.PUBLISH_TYPE_SOLICITED,
690            stype=None,
691            term_ind_on=True)
692
693    @test_tracker_info(uuid="703311a6-e444-4055-94ee-ea9b9b71799e")
694    def test_ttl_solicited_ind_off(self):
695        """Functional test case / Discovery test cases / TTL test case:
696    - Solicited publish
697    - Termination indication disabled
698    """
699        self.positive_ttl_test_utility(
700            is_publish=True,
701            ptype=aconsts.PUBLISH_TYPE_SOLICITED,
702            stype=None,
703            term_ind_on=False)
704
705    @test_tracker_info(uuid="38a541c4-ff55-4387-87b7-4d940489da9d")
706    def test_ttl_passive_ind_on(self):
707        """Functional test case / Discovery test cases / TTL test case:
708    - Passive subscribe
709    - Termination indication enabled
710    """
711        self.positive_ttl_test_utility(
712            is_publish=False,
713            ptype=None,
714            stype=aconsts.SUBSCRIBE_TYPE_PASSIVE,
715            term_ind_on=True)
716
717    @test_tracker_info(uuid="ba971e12-b0ca-417c-a1b5-9451598de47d")
718    def test_ttl_passive_ind_off(self):
719        """Functional test case / Discovery test cases / TTL test case:
720    - Passive subscribe
721    - Termination indication disabled
722    """
723        self.positive_ttl_test_utility(
724            is_publish=False,
725            ptype=None,
726            stype=aconsts.SUBSCRIBE_TYPE_PASSIVE,
727            term_ind_on=False)
728
729    @test_tracker_info(uuid="7b5d96f2-2415-4b98-9a51-32957f0679a0")
730    def test_ttl_active_ind_on(self):
731        """Functional test case / Discovery test cases / TTL test case:
732    - Active subscribe
733    - Termination indication enabled
734    """
735        self.positive_ttl_test_utility(
736            is_publish=False,
737            ptype=None,
738            stype=aconsts.SUBSCRIBE_TYPE_ACTIVE,
739            term_ind_on=True)
740
741    @test_tracker_info(uuid="c9268eca-0a30-42dd-8e6c-b8b0b84697fb")
742    def test_ttl_active_ind_off(self):
743        """Functional test case / Discovery test cases / TTL test case:
744    - Active subscribe
745    - Termination indication disabled
746    """
747        self.positive_ttl_test_utility(
748            is_publish=False,
749            ptype=None,
750            stype=aconsts.SUBSCRIBE_TYPE_ACTIVE,
751            term_ind_on=False)
752
753    #######################################
754    # Mismatched service name tests key:
755    #
756    # names is: test_mismatch_service_name_<pub_type>_<sub_type>
757    # where:
758    #
759    # pub_type: Type of publish discovery session: unsolicited or solicited.
760    # sub_type: Type of subscribe discovery session: passive or active.
761    #######################################
762
763    @test_tracker_info(uuid="175415e9-7d07-40d0-95f0-3a5f91ea4711")
764    def test_mismatch_service_name_unsolicited_passive(self):
765        """Functional test case / Discovery test cases / Mismatch service name
766    - Unsolicited publish
767    - Passive subscribe
768    """
769        self.discovery_mismatch_test_utility(
770            is_expected_to_pass=False,
771            p_type=aconsts.PUBLISH_TYPE_UNSOLICITED,
772            s_type=aconsts.SUBSCRIBE_TYPE_PASSIVE,
773            p_service_name="GoogleTestServiceXXX",
774            s_service_name="GoogleTestServiceYYY")
775
776    @test_tracker_info(uuid="c22a54ce-9e46-47a5-ac44-831faf93d317")
777    def test_mismatch_service_name_solicited_active(self):
778        """Functional test case / Discovery test cases / Mismatch service name
779    - Solicited publish
780    - Active subscribe
781    """
782        self.discovery_mismatch_test_utility(
783            is_expected_to_pass=False,
784            p_type=aconsts.PUBLISH_TYPE_SOLICITED,
785            s_type=aconsts.SUBSCRIBE_TYPE_ACTIVE,
786            p_service_name="GoogleTestServiceXXX",
787            s_service_name="GoogleTestServiceYYY")
788
789    #######################################
790    # Mismatched discovery session type tests key:
791    #
792    # names is: test_mismatch_service_type_<pub_type>_<sub_type>
793    # where:
794    #
795    # pub_type: Type of publish discovery session: unsolicited or solicited.
796    # sub_type: Type of subscribe discovery session: passive or active.
797    #######################################
798
799    @test_tracker_info(uuid="4806f631-d9eb-45fd-9e75-24674962770f")
800    def test_mismatch_service_type_unsolicited_active(self):
801        """Functional test case / Discovery test cases / Mismatch service name
802    - Unsolicited publish
803    - Active subscribe
804    """
805        self.discovery_mismatch_test_utility(
806            is_expected_to_pass=True,
807            p_type=aconsts.PUBLISH_TYPE_UNSOLICITED,
808            s_type=aconsts.SUBSCRIBE_TYPE_ACTIVE)
809
810    @test_tracker_info(uuid="12d648fd-b8fa-4c0f-9467-95e2366047de")
811    def test_mismatch_service_type_solicited_passive(self):
812        """Functional test case / Discovery test cases / Mismatch service name
813    - Unsolicited publish
814    - Active subscribe
815    """
816        self.discovery_mismatch_test_utility(
817            is_expected_to_pass=False,
818            p_type=aconsts.PUBLISH_TYPE_SOLICITED,
819            s_type=aconsts.SUBSCRIBE_TYPE_PASSIVE)
820
821    #######################################
822    # Mismatched discovery match filter tests key:
823    #
824    # names is: test_mismatch_match_filter_<pub_type>_<sub_type>
825    # where:
826    #
827    # pub_type: Type of publish discovery session: unsolicited or solicited.
828    # sub_type: Type of subscribe discovery session: passive or active.
829    #######################################
830
831    @test_tracker_info(uuid="d98454cb-64af-4266-8fed-f0b545a2d7c4")
832    def test_mismatch_match_filter_unsolicited_passive(self):
833        """Functional test case / Discovery test cases / Mismatch match filter
834    - Unsolicited publish
835    - Passive subscribe
836    """
837        self.discovery_mismatch_test_utility(
838            is_expected_to_pass=False,
839            p_type=aconsts.PUBLISH_TYPE_UNSOLICITED,
840            s_type=aconsts.SUBSCRIBE_TYPE_PASSIVE,
841            p_mf_1="hello there string",
842            s_mf_1="goodbye there string")
843
844    @test_tracker_info(uuid="663c1008-ae11-4e1a-87c7-c311d83f481c")
845    def test_mismatch_match_filter_solicited_active(self):
846        """Functional test case / Discovery test cases / Mismatch match filter
847    - Solicited publish
848    - Active subscribe
849    """
850        self.discovery_mismatch_test_utility(
851            is_expected_to_pass=False,
852            p_type=aconsts.PUBLISH_TYPE_SOLICITED,
853            s_type=aconsts.SUBSCRIBE_TYPE_ACTIVE,
854            p_mf_1="hello there string",
855            s_mf_1="goodbye there string")
856
857    #######################################
858    # Multiple concurrent services
859    #######################################
860
861    def run_multiple_concurrent_services(self, type_x, type_y):
862        """Validate multiple identical discovery services running on both devices:
863    - DUT1 & DUT2 running Publish for X
864    - DUT1 & DUT2 running Publish for Y
865    - DUT1 Subscribes for X
866    - DUT2 Subscribes for Y
867    Message exchanges.
868
869    Note: test requires that devices support 2 publish sessions concurrently.
870    The test will be skipped if the devices are not capable.
871
872    Args:
873      type_x, type_y: A list of [ptype, stype] of the publish and subscribe
874                      types for services X and Y respectively.
875    """
876        dut1 = self.android_devices[0]
877        dut2 = self.android_devices[1]
878
879        X_SERVICE_NAME = "ServiceXXX"
880        Y_SERVICE_NAME = "ServiceYYY"
881
882        asserts.skip_if(
883            dut1.aware_capabilities[aconsts.CAP_MAX_PUBLISHES] < 2
884            or dut2.aware_capabilities[aconsts.CAP_MAX_PUBLISHES] < 2,
885            "Devices do not support 2 publish sessions")
886
887        # attach and wait for confirmation
888        id1 = dut1.droid.wifiAwareAttach(False)
889        autils.wait_for_event(dut1, aconsts.EVENT_CB_ON_ATTACHED)
890        time.sleep(self.device_startup_offset)
891        id2 = dut2.droid.wifiAwareAttach(False)
892        autils.wait_for_event(dut2, aconsts.EVENT_CB_ON_ATTACHED)
893
894        # DUT1 & DUT2: start publishing both X & Y services and wait for
895        # confirmations
896        dut1_x_pid = dut1.droid.wifiAwarePublish(
897            id1, autils.create_discovery_config(X_SERVICE_NAME, type_x[0]))
898        event = autils.wait_for_event(dut1,
899                                      aconsts.SESSION_CB_ON_PUBLISH_STARTED)
900        asserts.assert_equal(event["data"][aconsts.SESSION_CB_KEY_SESSION_ID],
901                             dut1_x_pid,
902                             "Unexpected DUT1 X publish session discovery ID")
903
904        dut1_y_pid = dut1.droid.wifiAwarePublish(
905            id1, autils.create_discovery_config(Y_SERVICE_NAME, type_y[0]))
906        event = autils.wait_for_event(dut1,
907                                      aconsts.SESSION_CB_ON_PUBLISH_STARTED)
908        asserts.assert_equal(event["data"][aconsts.SESSION_CB_KEY_SESSION_ID],
909                             dut1_y_pid,
910                             "Unexpected DUT1 Y publish session discovery ID")
911
912        dut2_x_pid = dut2.droid.wifiAwarePublish(
913            id2, autils.create_discovery_config(X_SERVICE_NAME, type_x[0]))
914        event = autils.wait_for_event(dut2,
915                                      aconsts.SESSION_CB_ON_PUBLISH_STARTED)
916        asserts.assert_equal(event["data"][aconsts.SESSION_CB_KEY_SESSION_ID],
917                             dut2_x_pid,
918                             "Unexpected DUT2 X publish session discovery ID")
919
920        dut2_y_pid = dut2.droid.wifiAwarePublish(
921            id2, autils.create_discovery_config(Y_SERVICE_NAME, type_y[0]))
922        event = autils.wait_for_event(dut2,
923                                      aconsts.SESSION_CB_ON_PUBLISH_STARTED)
924        asserts.assert_equal(event["data"][aconsts.SESSION_CB_KEY_SESSION_ID],
925                             dut2_y_pid,
926                             "Unexpected DUT2 Y publish session discovery ID")
927
928        # DUT1: start subscribing for X
929        dut1_x_sid = dut1.droid.wifiAwareSubscribe(
930            id1, autils.create_discovery_config(X_SERVICE_NAME, type_x[1]))
931        autils.wait_for_event(dut1, aconsts.SESSION_CB_ON_SUBSCRIBE_STARTED)
932
933        # DUT2: start subscribing for Y
934        dut2_y_sid = dut2.droid.wifiAwareSubscribe(
935            id2, autils.create_discovery_config(Y_SERVICE_NAME, type_y[1]))
936        autils.wait_for_event(dut2, aconsts.SESSION_CB_ON_SUBSCRIBE_STARTED)
937
938        # DUT1 & DUT2: wait for service discovery
939        event = autils.wait_for_event(dut1,
940                                      aconsts.SESSION_CB_ON_SERVICE_DISCOVERED)
941        asserts.assert_equal(
942            event["data"][aconsts.SESSION_CB_KEY_SESSION_ID], dut1_x_sid,
943            "Unexpected DUT1 X subscribe session discovery ID")
944        dut1_peer_id_for_dut2_x = event["data"][aconsts.SESSION_CB_KEY_PEER_ID]
945
946        event = autils.wait_for_event(dut2,
947                                      aconsts.SESSION_CB_ON_SERVICE_DISCOVERED)
948        asserts.assert_equal(
949            event["data"][aconsts.SESSION_CB_KEY_SESSION_ID], dut2_y_sid,
950            "Unexpected DUT2 Y subscribe session discovery ID")
951        dut2_peer_id_for_dut1_y = event["data"][aconsts.SESSION_CB_KEY_PEER_ID]
952
953        # DUT1.X send message to DUT2
954        x_msg = "Hello X on DUT2!"
955        dut1.droid.wifiAwareSendMessage(dut1_x_sid, dut1_peer_id_for_dut2_x,
956                                        self.get_next_msg_id(), x_msg,
957                                        self.msg_retx_count)
958        autils.wait_for_event(dut1, aconsts.SESSION_CB_ON_MESSAGE_SENT)
959        event = autils.wait_for_event(dut2,
960                                      aconsts.SESSION_CB_ON_MESSAGE_RECEIVED)
961        asserts.assert_equal(
962            event["data"][aconsts.SESSION_CB_KEY_SESSION_ID], dut2_x_pid,
963            "Unexpected publish session ID on DUT2 for meesage "
964            "received on service X")
965        asserts.assert_equal(
966            event["data"][aconsts.SESSION_CB_KEY_MESSAGE_AS_STRING], x_msg,
967            "Message on service X from DUT1 to DUT2 not received correctly")
968
969        # DUT2.Y send message to DUT1
970        y_msg = "Hello Y on DUT1!"
971        dut2.droid.wifiAwareSendMessage(dut2_y_sid, dut2_peer_id_for_dut1_y,
972                                        self.get_next_msg_id(), y_msg,
973                                        self.msg_retx_count)
974        autils.wait_for_event(dut2, aconsts.SESSION_CB_ON_MESSAGE_SENT)
975        event = autils.wait_for_event(dut1,
976                                      aconsts.SESSION_CB_ON_MESSAGE_RECEIVED)
977        asserts.assert_equal(
978            event["data"][aconsts.SESSION_CB_KEY_SESSION_ID], dut1_y_pid,
979            "Unexpected publish session ID on DUT1 for meesage "
980            "received on service Y")
981        asserts.assert_equal(
982            event["data"][aconsts.SESSION_CB_KEY_MESSAGE_AS_STRING], y_msg,
983            "Message on service Y from DUT2 to DUT1 not received correctly")
984
985    @test_tracker_info(uuid="eef80cf3-1fd2-4526-969b-6af2dce785d7")
986    def test_multiple_concurrent_services_both_unsolicited_passive(self):
987        """Validate multiple concurrent discovery sessions running on both devices.
988    - DUT1 & DUT2 running Publish for X
989    - DUT1 & DUT2 running Publish for Y
990    - DUT1 Subscribes for X
991    - DUT2 Subscribes for Y
992    Message exchanges.
993
994    Both sessions are Unsolicited/Passive.
995
996    Note: test requires that devices support 2 publish sessions concurrently.
997    The test will be skipped if the devices are not capable.
998    """
999        self.run_multiple_concurrent_services(
1000            type_x=[
1001                aconsts.PUBLISH_TYPE_UNSOLICITED,
1002                aconsts.SUBSCRIBE_TYPE_PASSIVE
1003            ],
1004            type_y=[
1005                aconsts.PUBLISH_TYPE_UNSOLICITED,
1006                aconsts.SUBSCRIBE_TYPE_PASSIVE
1007            ])
1008
1009    @test_tracker_info(uuid="46739f04-ab2b-4556-b1a4-9aa2774869b5")
1010    def test_multiple_concurrent_services_both_solicited_active(self):
1011        """Validate multiple concurrent discovery sessions running on both devices.
1012    - DUT1 & DUT2 running Publish for X
1013    - DUT1 & DUT2 running Publish for Y
1014    - DUT1 Subscribes for X
1015    - DUT2 Subscribes for Y
1016    Message exchanges.
1017
1018    Both sessions are Solicited/Active.
1019
1020    Note: test requires that devices support 2 publish sessions concurrently.
1021    The test will be skipped if the devices are not capable.
1022    """
1023        self.run_multiple_concurrent_services(
1024            type_x=[
1025                aconsts.PUBLISH_TYPE_SOLICITED, aconsts.SUBSCRIBE_TYPE_ACTIVE
1026            ],
1027            type_y=[
1028                aconsts.PUBLISH_TYPE_SOLICITED, aconsts.SUBSCRIBE_TYPE_ACTIVE
1029            ])
1030
1031    @test_tracker_info(uuid="5f8f7fd2-4a0e-4cca-8cbb-6d54353f2baa")
1032    def test_multiple_concurrent_services_mix_unsolicited_solicited(self):
1033        """Validate multiple concurrent discovery sessions running on both devices.
1034    - DUT1 & DUT2 running Publish for X
1035    - DUT1 & DUT2 running Publish for Y
1036    - DUT1 Subscribes for X
1037    - DUT2 Subscribes for Y
1038    Message exchanges.
1039
1040    Session A is Unsolicited/Passive.
1041    Session B is Solicited/Active.
1042
1043    Note: test requires that devices support 2 publish sessions concurrently.
1044    The test will be skipped if the devices are not capable.
1045    """
1046        self.run_multiple_concurrent_services(
1047            type_x=[
1048                aconsts.PUBLISH_TYPE_UNSOLICITED,
1049                aconsts.SUBSCRIBE_TYPE_PASSIVE
1050            ],
1051            type_y=[
1052                aconsts.PUBLISH_TYPE_SOLICITED, aconsts.SUBSCRIBE_TYPE_ACTIVE
1053            ])
1054
1055    #########################################################
1056
1057    @test_tracker_info(uuid="908ec896-fc7a-4ee4-b633-a2f042b74448")
1058    def test_upper_lower_service_name_equivalence(self):
1059        """Validate that Service Name is case-insensitive. Publish a service name
1060    with mixed case, subscribe to the same service name with alternative case
1061    and verify that discovery happens."""
1062        p_dut = self.android_devices[0]
1063        s_dut = self.android_devices[1]
1064
1065        pub_service_name = "GoogleAbCdEf"
1066        sub_service_name = "GoogleaBcDeF"
1067
1068        autils.create_discovery_pair(
1069            p_dut,
1070            s_dut,
1071            p_config=autils.create_discovery_config(
1072                pub_service_name, aconsts.PUBLISH_TYPE_UNSOLICITED),
1073            s_config=autils.create_discovery_config(
1074                sub_service_name, aconsts.SUBSCRIBE_TYPE_PASSIVE),
1075            device_startup_offset=self.device_startup_offset)
1076
1077    ##########################################################
1078
1079    def exchange_messages(self, p_dut, p_disc_id, s_dut, s_disc_id, peer_id_on_sub, session_name):
1080        """
1081        Exchange message between Publisher and Subscriber on target discovery session
1082
1083    Args:
1084      p_dut: Publisher device
1085      p_disc_id: Publish discovery session id
1086      s_dut: Subscriber device
1087      s_disc_id: Subscribe discovery session id
1088      peer_id_on_sub: Peer ID of the Publisher as seen on the Subscriber
1089      session_name: dictionary of discovery session name base on role("pub" or "sub")
1090                    {role: {disc_id: name}}
1091    """
1092        msg_template = "Hello {} from {} !"
1093
1094        # Message send from Subscriber to Publisher
1095        s_to_p_msg = msg_template.format(session_name["pub"][p_disc_id],
1096                                         session_name["sub"][s_disc_id])
1097        s_dut.droid.wifiAwareSendMessage(s_disc_id,
1098                                         peer_id_on_sub,
1099                                         self.get_next_msg_id(),
1100                                         s_to_p_msg,
1101                                         self.msg_retx_count)
1102        autils.wait_for_event(s_dut,
1103                              autils.decorate_event(aconsts.SESSION_CB_ON_MESSAGE_SENT, s_disc_id))
1104        event = autils.wait_for_event(p_dut,
1105                                      autils.decorate_event(aconsts.SESSION_CB_ON_MESSAGE_RECEIVED,
1106                                                            p_disc_id))
1107        asserts.assert_equal(
1108            event["data"][aconsts.SESSION_CB_KEY_MESSAGE_AS_STRING], s_to_p_msg,
1109            "Message on service %s from Subscriber to Publisher "
1110            "not received correctly" % session_name["pub"][p_disc_id])
1111        try:
1112            event = p_dut.ed.pop_event(autils.decorate_event(aconsts.SESSION_CB_ON_MESSAGE_RECEIVED,
1113                                             p_disc_id), self.EVENT_TIMEOUT)
1114            p_dut.log.info("re-transmit message received: "
1115                           + event["data"][aconsts.SESSION_CB_KEY_MESSAGE_AS_STRING])
1116            asserts.assert_equal(
1117                event["data"][aconsts.SESSION_CB_KEY_MESSAGE_AS_STRING], s_to_p_msg,
1118                "Message on service %s from Subscriber to Publisher "
1119                "not received correctly" % session_name["pub"][p_disc_id])
1120        except queue.Empty:
1121            p_dut.log.info("no re-transmit message")
1122
1123        peer_id_on_pub = event["data"][aconsts.SESSION_CB_KEY_PEER_ID]
1124
1125        # Message send from Publisher to Subscriber
1126        p_to_s_msg = msg_template.format(session_name["sub"][s_disc_id],
1127                                         session_name["pub"][p_disc_id])
1128        p_dut.droid.wifiAwareSendMessage(p_disc_id,
1129                                         peer_id_on_pub,
1130                                         self.get_next_msg_id(), p_to_s_msg,
1131                                         self.msg_retx_count)
1132        autils.wait_for_event(
1133            p_dut, autils.decorate_event(aconsts.SESSION_CB_ON_MESSAGE_SENT, p_disc_id))
1134        event = autils.wait_for_event(s_dut,
1135                                      autils.decorate_event(aconsts.SESSION_CB_ON_MESSAGE_RECEIVED,
1136                                                            s_disc_id))
1137        asserts.assert_equal(
1138            event["data"][aconsts.SESSION_CB_KEY_MESSAGE_AS_STRING], p_to_s_msg,
1139            "Message on service %s from Publisher to Subscriber"
1140            "not received correctly" % session_name["sub"][s_disc_id])
1141        try:
1142            event = s_dut.ed.pop_event(autils.decorate_event(aconsts.SESSION_CB_ON_MESSAGE_RECEIVED,
1143                                                             s_disc_id), self.EVENT_TIMEOUT)
1144            s_dut.log.info("re-transmit message received: "
1145                           + event["data"][aconsts.SESSION_CB_KEY_MESSAGE_AS_STRING])
1146            asserts.assert_equal(
1147                event["data"][aconsts.SESSION_CB_KEY_MESSAGE_AS_STRING], p_to_s_msg,
1148                "Message on service %s from Publisher to Subscriber"
1149                "not received correctly" % session_name["sub"][s_disc_id])
1150        except queue.Empty:
1151            s_dut.log.info("no re-transmit message")
1152
1153    def run_multiple_concurrent_services_same_name_diff_ssi(self, type_x, type_y):
1154        """Validate same service name with multiple service specific info on publisher
1155        and subscriber can see all service
1156
1157    - p_dut running Publish X and Y
1158    - s_dut running subscribe A and B
1159    - subscribe A find X and Y
1160    - subscribe B find X and Y
1161
1162    Message exchanges:
1163    - A to X and X to A
1164    - B to X and X to B
1165    - A to Y and Y to A
1166    - B to Y and Y to B
1167
1168    Note: test requires that publisher device support 2 publish sessions concurrently,
1169    and subscriber device support 2 subscribe sessions concurrently.
1170    The test will be skipped if the devices are not capable.
1171
1172    Args:
1173      type_x, type_y: A list of [ptype, stype] of the publish and subscribe
1174                      types for services X and Y respectively.
1175    """
1176        p_dut = self.android_devices[0]
1177        s_dut = self.android_devices[1]
1178
1179        asserts.skip_if(
1180            p_dut.aware_capabilities[aconsts.CAP_MAX_PUBLISHES] < 2
1181            or s_dut.aware_capabilities[aconsts.CAP_MAX_SUBSCRIBES] < 2,
1182            "Devices do not support 2 publish sessions or 2 subscribe sessions")
1183
1184        SERVICE_NAME = "ServiceName"
1185        X_SERVICE_SSI = "ServiceSpecificInfoXXX"
1186        Y_SERVICE_SSI = "ServiceSpecificInfoYYY"
1187        use_id = True
1188
1189        # attach and wait for confirmation
1190        p_id = p_dut.droid.wifiAwareAttach(False, None, use_id)
1191        autils.wait_for_event(p_dut, autils.decorate_event(aconsts.EVENT_CB_ON_ATTACHED, p_id))
1192        time.sleep(self.device_startup_offset)
1193        s_id = s_dut.droid.wifiAwareAttach(False, None, use_id)
1194        autils.wait_for_event(s_dut, autils.decorate_event(aconsts.EVENT_CB_ON_ATTACHED, s_id))
1195
1196        # Publisher: start publishing both X & Y services and wait for confirmations
1197        p_disc_id_x = p_dut.droid.wifiAwarePublish(
1198            p_id, autils.create_discovery_config(SERVICE_NAME, type_x[0], X_SERVICE_SSI), use_id)
1199        event = autils.wait_for_event(p_dut,
1200                                      autils.decorate_event(
1201                                          aconsts.SESSION_CB_ON_PUBLISH_STARTED, p_disc_id_x))
1202
1203        p_disc_id_y = p_dut.droid.wifiAwarePublish(
1204            p_id, autils.create_discovery_config(SERVICE_NAME, type_x[0], Y_SERVICE_SSI), use_id)
1205        event = autils.wait_for_event(p_dut,
1206                                      autils.decorate_event(
1207                                          aconsts.SESSION_CB_ON_PUBLISH_STARTED, p_disc_id_y))
1208
1209        # Subscriber: start subscribe session A
1210        s_disc_id_a = s_dut.droid.wifiAwareSubscribe(
1211            s_id, autils.create_discovery_config(SERVICE_NAME, type_x[1]), use_id)
1212        autils.wait_for_event(s_dut, autils.decorate_event(
1213            aconsts.SESSION_CB_ON_SUBSCRIBE_STARTED, s_disc_id_a))
1214
1215        # Subscriber: start subscribe session B
1216        s_disc_id_b = s_dut.droid.wifiAwareSubscribe(
1217            p_id, autils.create_discovery_config(SERVICE_NAME, type_y[1]), use_id)
1218        autils.wait_for_event(s_dut, autils.decorate_event(
1219            aconsts.SESSION_CB_ON_SUBSCRIBE_STARTED, s_disc_id_b))
1220
1221        session_name = {"pub": {p_disc_id_x: "X", p_disc_id_y: "Y"},
1222                        "sub": {s_disc_id_a: "A", s_disc_id_b: "B"}}
1223
1224        # Subscriber: subscribe session A & B wait for service discovery
1225        # Number of results on each session should be exactly 2
1226        results_a = {}
1227        for i in range(2):
1228            event = autils.wait_for_event(s_dut, autils.decorate_event(
1229                aconsts.SESSION_CB_ON_SERVICE_DISCOVERED, s_disc_id_a))
1230            results_a[
1231                bytes(event["data"][
1232                          aconsts.SESSION_CB_KEY_SERVICE_SPECIFIC_INFO]).decode('utf-8')] = event
1233        autils.fail_on_event(s_dut, autils.decorate_event(
1234            aconsts.SESSION_CB_ON_SERVICE_DISCOVERED, s_disc_id_a))
1235
1236        results_b = {}
1237        for i in range(2):
1238            event = autils.wait_for_event(s_dut, autils.decorate_event(
1239                aconsts.SESSION_CB_ON_SERVICE_DISCOVERED, s_disc_id_b))
1240            results_b[
1241                bytes(event["data"][
1242                          aconsts.SESSION_CB_KEY_SERVICE_SPECIFIC_INFO]).decode('utf-8')] = event
1243        autils.fail_on_event(s_dut, autils.decorate_event(
1244            aconsts.SESSION_CB_ON_SERVICE_DISCOVERED, s_disc_id_b))
1245
1246        s_a_peer_id_for_p_x = results_a[X_SERVICE_SSI]["data"][aconsts.SESSION_CB_KEY_PEER_ID]
1247        s_a_peer_id_for_p_y = results_a[Y_SERVICE_SSI]["data"][aconsts.SESSION_CB_KEY_PEER_ID]
1248        s_b_peer_id_for_p_x = results_b[X_SERVICE_SSI]["data"][aconsts.SESSION_CB_KEY_PEER_ID]
1249        s_b_peer_id_for_p_y = results_b[Y_SERVICE_SSI]["data"][aconsts.SESSION_CB_KEY_PEER_ID]
1250
1251        # Message exchange between Publisher and Subscribe
1252        self.exchange_messages(p_dut, p_disc_id_x,
1253                               s_dut, s_disc_id_a, s_a_peer_id_for_p_x, session_name)
1254
1255        self.exchange_messages(p_dut, p_disc_id_x,
1256                               s_dut, s_disc_id_b, s_b_peer_id_for_p_x, session_name)
1257
1258        self.exchange_messages(p_dut, p_disc_id_y,
1259                               s_dut, s_disc_id_a, s_a_peer_id_for_p_y, session_name)
1260
1261        self.exchange_messages(p_dut, p_disc_id_y,
1262                               s_dut, s_disc_id_b, s_b_peer_id_for_p_y, session_name)
1263
1264        # Check no more messages
1265        time.sleep(autils.EVENT_TIMEOUT)
1266        autils.verify_no_more_events(p_dut, timeout=0)
1267        autils.verify_no_more_events(s_dut, timeout=0)
1268
1269        ##########################################################
1270
1271    @test_tracker_info(uuid="78d89d63-1cbc-47f6-a8fc-74057fea655e")
1272    def test_multiple_concurrent_services_diff_ssi_unsolicited_passive(self):
1273        """Multi service test on same service name but different Service Specific Info
1274    - Unsolicited publish
1275    - Passive subscribe
1276    """
1277        self.run_multiple_concurrent_services_same_name_diff_ssi(
1278            type_x=[aconsts.PUBLISH_TYPE_UNSOLICITED, aconsts.SUBSCRIBE_TYPE_PASSIVE],
1279            type_y=[aconsts.PUBLISH_TYPE_UNSOLICITED, aconsts.SUBSCRIBE_TYPE_PASSIVE])
1280
1281    @test_tracker_info(uuid="5d349491-48e4-4ca1-a8af-7afb44e7bcbc")
1282    def test_multiple_concurrent_services_diff_ssi_solicited_active(self):
1283        """Multi service test on same service name but different Service Specific Info
1284    - Solicited publish
1285    - Active subscribe
1286    """
1287        self.run_multiple_concurrent_services_same_name_diff_ssi(
1288            type_x=[aconsts.PUBLISH_TYPE_SOLICITED, aconsts.SUBSCRIBE_TYPE_ACTIVE],
1289            type_y=[aconsts.PUBLISH_TYPE_SOLICITED, aconsts.SUBSCRIBE_TYPE_ACTIVE])
1290
1291    def run_service_discovery_on_service_lost(self, p_type, s_type):
1292        """
1293        Validate service lost callback will be receive on subscriber, when publisher stopped publish
1294    - p_dut running Publish
1295    - s_dut running subscribe
1296    - s_dut discover p_dut
1297    - p_dut stop publish
1298    - s_dut receive service lost callback
1299
1300    Args:
1301      p_type: Publish discovery type
1302      s_type: Subscribe discovery type
1303    """
1304        p_dut = self.android_devices[0]
1305        p_dut.pretty_name = "Publisher"
1306        s_dut = self.android_devices[1]
1307        s_dut.pretty_name = "Subscriber"
1308
1309        asserts.skip_if(not s_dut.droid.isSdkAtLeastS(),
1310                        "R build and below do not have onServiceLost API.")
1311
1312        # Publisher+Subscriber: attach and wait for confirmation
1313        p_id = p_dut.droid.wifiAwareAttach(False)
1314        autils.wait_for_event(p_dut, aconsts.EVENT_CB_ON_ATTACHED)
1315        time.sleep(self.device_startup_offset)
1316        s_id = s_dut.droid.wifiAwareAttach(False)
1317        autils.wait_for_event(s_dut, aconsts.EVENT_CB_ON_ATTACHED)
1318
1319        # Publisher: start publish and wait for confirmation
1320        p_config = self.create_publish_config(
1321            p_dut.aware_capabilities,
1322            p_type,
1323            self.PAYLOAD_SIZE_TYPICAL,
1324            ttl=0,
1325            term_ind_on=False,
1326            null_match=False)
1327        p_disc_id = p_dut.droid.wifiAwarePublish(p_id, p_config)
1328        autils.wait_for_event(p_dut, aconsts.SESSION_CB_ON_PUBLISH_STARTED)
1329
1330        # Subscriber: start subscribe and wait for confirmation
1331        s_config = self.create_subscribe_config(
1332            s_dut.aware_capabilities,
1333            s_type,
1334            self.PAYLOAD_SIZE_TYPICAL,
1335            ttl=0,
1336            term_ind_on=False,
1337            null_match=True)
1338        s_disc_id = s_dut.droid.wifiAwareSubscribe(s_id, s_config)
1339        autils.wait_for_event(s_dut, aconsts.SESSION_CB_ON_SUBSCRIBE_STARTED)
1340
1341        # Subscriber: wait for service discovery
1342        discovery_event = autils.wait_for_event(
1343            s_dut, aconsts.SESSION_CB_ON_SERVICE_DISCOVERED)
1344        peer_id_on_sub = discovery_event["data"][
1345            aconsts.SESSION_CB_KEY_PEER_ID]
1346
1347        # Publisher+Subscriber: Terminate sessions
1348        p_dut.droid.wifiAwareDestroyDiscoverySession(p_disc_id)
1349        time.sleep(10)
1350        service_lost_event = autils.wait_for_event(
1351            s_dut, aconsts.SESSION_CB_ON_SERVICE_LOST)
1352        asserts.assert_equal(peer_id_on_sub,
1353                             service_lost_event["data"][aconsts.SESSION_CB_KEY_PEER_ID])
1354        asserts.assert_equal(aconsts.REASON_PEER_NOT_VISIBLE,
1355                             service_lost_event["data"][aconsts.SESSION_CB_KEY_LOST_REASON])
1356
1357        s_dut.droid.wifiAwareDestroyDiscoverySession(s_disc_id)
1358
1359    @test_tracker_info(uuid="b1894ce3-8692-478b-a96f-db2797e22caa")
1360    def test_service_discovery_on_service_lost_unsolicited_passive(self):
1361        """
1362        Test service discovery lost with unsolicited publish and passive subscribe
1363        """
1364        self.run_service_discovery_on_service_lost(aconsts.PUBLISH_TYPE_UNSOLICITED,
1365                                                   aconsts.SUBSCRIBE_TYPE_PASSIVE)
1366
1367    @test_tracker_info(uuid="4470d897-223a-4f9f-b21f-4061943137dd")
1368    def test_service_discovery_on_service_lost_solicited_active(self):
1369        """
1370        Test service discovery lost with solicited publish and active subscribe
1371        """
1372        self.run_service_discovery_on_service_lost(aconsts.PUBLISH_TYPE_SOLICITED,
1373                                                   aconsts.SUBSCRIBE_TYPE_ACTIVE)
1374