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