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