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