• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1#!/usr/bin/python3.4
2#
3#   Copyright 2017 - The Android Open Source Project
4#
5#   Licensed under the Apache License, Version 2.0 (the "License");
6#   you may not use this file except in compliance with the License.
7#   You may obtain a copy of the License at
8#
9#       http://www.apache.org/licenses/LICENSE-2.0
10#
11#   Unless required by applicable law or agreed to in writing, software
12#   distributed under the License is distributed on an "AS IS" BASIS,
13#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14#   See the License for the specific language governing permissions and
15#   limitations under the License.
16
17import string
18import time
19
20from acts import asserts
21from acts.test_decorators import test_tracker_info
22from acts.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
25
26
27class DiscoveryTest(AwareBaseTest):
28    """Set of tests for Wi-Fi Aware discovery."""
29
30    # configuration parameters used by tests
31    PAYLOAD_SIZE_MIN = 0
32    PAYLOAD_SIZE_TYPICAL = 1
33    PAYLOAD_SIZE_MAX = 2
34
35    # message strings
36    query_msg = "How are you doing? 你好嗎?"
37    response_msg = "Doing ok - thanks! 做的不錯 - 謝謝!"
38
39    # message re-transmit counter (increases reliability in open-environment)
40    # Note: reliability of message transmission is tested elsewhere
41    msg_retx_count = 5  # hard-coded max value, internal API
42
43    def __init__(self, controllers):
44        AwareBaseTest.__init__(self, controllers)
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        # sleep for timeout period and then verify all 'fail_on_event' together
292        time.sleep(autils.EVENT_TIMEOUT)
293
294        # verify that there were no other events
295        autils.verify_no_more_events(p_dut, timeout=0)
296        autils.verify_no_more_events(s_dut, timeout=0)
297
298        # verify that forbidden callbacks aren't called
299        autils.validate_forbidden_callbacks(p_dut, {aconsts.CB_EV_MATCH: 0})
300
301    def verify_discovery_session_term(self, dut, disc_id, config, is_publish,
302                                      term_ind_on):
303        """Utility to verify that the specified discovery session has terminated (by
304    waiting for the TTL and then attempting to reconfigure).
305
306    Args:
307      dut: device under test
308      disc_id: discovery id for the existing session
309      config: configuration of the existing session
310      is_publish: True if the configuration was publish, False if subscribe
311      term_ind_on: True if a termination indication is expected, False otherwise
312    """
313        # Wait for session termination
314        if term_ind_on:
315            autils.wait_for_event(
316                dut,
317                autils.decorate_event(aconsts.SESSION_CB_ON_SESSION_TERMINATED,
318                                      disc_id))
319        else:
320            # can't defer wait to end since in any case have to wait for session to
321            # expire
322            autils.fail_on_event(
323                dut,
324                autils.decorate_event(aconsts.SESSION_CB_ON_SESSION_TERMINATED,
325                                      disc_id))
326
327        # Validate that session expired by trying to configure it (expect failure)
328        config[aconsts.DISCOVERY_KEY_SSI] = "something else"
329        if is_publish:
330            dut.droid.wifiAwareUpdatePublish(disc_id, config)
331        else:
332            dut.droid.wifiAwareUpdateSubscribe(disc_id, config)
333
334        # The response to update discovery session is:
335        # term_ind_on=True: session was cleaned-up so won't get an explicit failure, but won't get a
336        #                   success either. Can check for no SESSION_CB_ON_SESSION_CONFIG_UPDATED but
337        #                   will defer to the end of the test (no events on queue).
338        # term_ind_on=False: session was not cleaned-up (yet). So expect
339        #                    SESSION_CB_ON_SESSION_CONFIG_FAILED.
340        if not term_ind_on:
341            autils.wait_for_event(
342                dut,
343                autils.decorate_event(
344                    aconsts.SESSION_CB_ON_SESSION_CONFIG_FAILED, disc_id))
345
346    def positive_ttl_test_utility(self, is_publish, ptype, stype, term_ind_on):
347        """Utility which runs a positive discovery session TTL configuration test
348
349    Iteration 1: Verify session started with TTL
350    Iteration 2: Verify session started without TTL and reconfigured with TTL
351    Iteration 3: Verify session started with (long) TTL and reconfigured with
352                 (short) TTL
353
354    Args:
355      is_publish: True if testing publish, False if testing subscribe
356      ptype: Publish discovery type (used if is_publish is True)
357      stype: Subscribe discovery type (used if is_publish is False)
358      term_ind_on: Configuration of termination indication
359    """
360        SHORT_TTL = 5  # 5 seconds
361        LONG_TTL = 100  # 100 seconds
362        dut = self.android_devices[0]
363
364        # Attach and wait for confirmation
365        id = dut.droid.wifiAwareAttach(False)
366        autils.wait_for_event(dut, aconsts.EVENT_CB_ON_ATTACHED)
367
368        # Iteration 1: Start discovery session with TTL
369        config = self.create_base_config(
370            dut.aware_capabilities, is_publish, ptype, stype,
371            self.PAYLOAD_SIZE_TYPICAL, SHORT_TTL, term_ind_on, False)
372        if is_publish:
373            disc_id = dut.droid.wifiAwarePublish(id, config, True)
374            autils.wait_for_event(
375                dut,
376                autils.decorate_event(aconsts.SESSION_CB_ON_PUBLISH_STARTED,
377                                      disc_id))
378        else:
379            disc_id = dut.droid.wifiAwareSubscribe(id, config, True)
380            autils.wait_for_event(
381                dut,
382                autils.decorate_event(aconsts.SESSION_CB_ON_SUBSCRIBE_STARTED,
383                                      disc_id))
384
385        # Wait for session termination & verify
386        self.verify_discovery_session_term(dut, disc_id, config, is_publish,
387                                           term_ind_on)
388
389        # Iteration 2: Start a discovery session without TTL
390        config = self.create_base_config(
391            dut.aware_capabilities, is_publish, ptype, stype,
392            self.PAYLOAD_SIZE_TYPICAL, 0, term_ind_on, False)
393        if is_publish:
394            disc_id = dut.droid.wifiAwarePublish(id, config, True)
395            autils.wait_for_event(
396                dut,
397                autils.decorate_event(aconsts.SESSION_CB_ON_PUBLISH_STARTED,
398                                      disc_id))
399        else:
400            disc_id = dut.droid.wifiAwareSubscribe(id, config, True)
401            autils.wait_for_event(
402                dut,
403                autils.decorate_event(aconsts.SESSION_CB_ON_SUBSCRIBE_STARTED,
404                                      disc_id))
405
406        # Update with a TTL
407        config = self.create_base_config(
408            dut.aware_capabilities, is_publish, ptype, stype,
409            self.PAYLOAD_SIZE_TYPICAL, SHORT_TTL, term_ind_on, False)
410        if is_publish:
411            dut.droid.wifiAwareUpdatePublish(disc_id, config)
412        else:
413            dut.droid.wifiAwareUpdateSubscribe(disc_id, config)
414        autils.wait_for_event(
415            dut,
416            autils.decorate_event(aconsts.SESSION_CB_ON_SESSION_CONFIG_UPDATED,
417                                  disc_id))
418
419        # Wait for session termination & verify
420        self.verify_discovery_session_term(dut, disc_id, config, is_publish,
421                                           term_ind_on)
422
423        # Iteration 3: Start a discovery session with (long) TTL
424        config = self.create_base_config(
425            dut.aware_capabilities, is_publish, ptype, stype,
426            self.PAYLOAD_SIZE_TYPICAL, LONG_TTL, term_ind_on, False)
427        if is_publish:
428            disc_id = dut.droid.wifiAwarePublish(id, config, True)
429            autils.wait_for_event(
430                dut,
431                autils.decorate_event(aconsts.SESSION_CB_ON_PUBLISH_STARTED,
432                                      disc_id))
433        else:
434            disc_id = dut.droid.wifiAwareSubscribe(id, config, True)
435            autils.wait_for_event(
436                dut,
437                autils.decorate_event(aconsts.SESSION_CB_ON_SUBSCRIBE_STARTED,
438                                      disc_id))
439
440        # Update with a TTL
441        config = self.create_base_config(
442            dut.aware_capabilities, is_publish, ptype, stype,
443            self.PAYLOAD_SIZE_TYPICAL, SHORT_TTL, term_ind_on, False)
444        if is_publish:
445            dut.droid.wifiAwareUpdatePublish(disc_id, config)
446        else:
447            dut.droid.wifiAwareUpdateSubscribe(disc_id, config)
448        autils.wait_for_event(
449            dut,
450            autils.decorate_event(aconsts.SESSION_CB_ON_SESSION_CONFIG_UPDATED,
451                                  disc_id))
452
453        # Wait for session termination & verify
454        self.verify_discovery_session_term(dut, disc_id, config, is_publish,
455                                           term_ind_on)
456
457        # verify that there were no other events
458        autils.verify_no_more_events(dut)
459
460        # verify that forbidden callbacks aren't called
461        if not term_ind_on:
462            autils.validate_forbidden_callbacks(
463                dut, {
464                    aconsts.CB_EV_PUBLISH_TERMINATED: 0,
465                    aconsts.CB_EV_SUBSCRIBE_TERMINATED: 0
466                })
467
468    def discovery_mismatch_test_utility(self,
469                                        is_expected_to_pass,
470                                        p_type,
471                                        s_type,
472                                        p_service_name=None,
473                                        s_service_name=None,
474                                        p_mf_1=None,
475                                        s_mf_1=None):
476        """Utility which runs the negative discovery test for mismatched service
477    configs.
478
479    Args:
480      is_expected_to_pass: True if positive test, False if negative
481      p_type: Publish discovery type
482      s_type: Subscribe discovery type
483      p_service_name: Publish service name (or None to leave unchanged)
484      s_service_name: Subscribe service name (or None to leave unchanged)
485      p_mf_1: Publish match filter element [1] (or None to leave unchanged)
486      s_mf_1: Subscribe match filter element [1] (or None to leave unchanged)
487    """
488        p_dut = self.android_devices[0]
489        p_dut.pretty_name = "Publisher"
490        s_dut = self.android_devices[1]
491        s_dut.pretty_name = "Subscriber"
492
493        # create configurations
494        p_config = self.create_publish_config(
495            p_dut.aware_capabilities,
496            p_type,
497            self.PAYLOAD_SIZE_TYPICAL,
498            ttl=0,
499            term_ind_on=False,
500            null_match=False)
501        if p_service_name is not None:
502            p_config[aconsts.DISCOVERY_KEY_SERVICE_NAME] = p_service_name
503        if p_mf_1 is not None:
504            p_config[
505                aconsts.DISCOVERY_KEY_MATCH_FILTER_LIST] = autils.encode_list(
506                    [(10).to_bytes(1, byteorder="big"), p_mf_1,
507                     bytes(range(40))])
508        s_config = self.create_publish_config(
509            s_dut.aware_capabilities,
510            s_type,
511            self.PAYLOAD_SIZE_TYPICAL,
512            ttl=0,
513            term_ind_on=False,
514            null_match=False)
515        if s_service_name is not None:
516            s_config[aconsts.DISCOVERY_KEY_SERVICE_NAME] = s_service_name
517        if s_mf_1 is not None:
518            s_config[
519                aconsts.DISCOVERY_KEY_MATCH_FILTER_LIST] = autils.encode_list(
520                    [(10).to_bytes(1, byteorder="big"), s_mf_1,
521                     bytes(range(40))])
522
523        p_id = p_dut.droid.wifiAwareAttach(False)
524        autils.wait_for_event(p_dut, aconsts.EVENT_CB_ON_ATTACHED)
525        time.sleep(self.device_startup_offset)
526        s_id = s_dut.droid.wifiAwareAttach(False)
527        autils.wait_for_event(s_dut, aconsts.EVENT_CB_ON_ATTACHED)
528
529        # Publisher: start publish and wait for confirmation
530        p_disc_id = p_dut.droid.wifiAwarePublish(p_id, p_config)
531        autils.wait_for_event(p_dut, aconsts.SESSION_CB_ON_PUBLISH_STARTED)
532
533        # Subscriber: start subscribe and wait for confirmation
534        s_disc_id = s_dut.droid.wifiAwareSubscribe(s_id, s_config)
535        autils.wait_for_event(s_dut, aconsts.SESSION_CB_ON_SUBSCRIBE_STARTED)
536
537        # Subscriber: fail on service discovery
538        if is_expected_to_pass:
539            autils.wait_for_event(s_dut,
540                                  aconsts.SESSION_CB_ON_SERVICE_DISCOVERED)
541        else:
542            autils.fail_on_event(s_dut,
543                                 aconsts.SESSION_CB_ON_SERVICE_DISCOVERED)
544
545        # Publisher+Subscriber: Terminate sessions
546        p_dut.droid.wifiAwareDestroyDiscoverySession(p_disc_id)
547        s_dut.droid.wifiAwareDestroyDiscoverySession(s_disc_id)
548
549        # verify that there were no other events (including terminations)
550        time.sleep(autils.EVENT_TIMEOUT)
551        autils.verify_no_more_events(p_dut, timeout=0)
552        autils.verify_no_more_events(s_dut, timeout=0)
553
554    #######################################
555    # Positive tests key:
556    #
557    # names is: test_<pub_type>_<sub_type>_<size>
558    # where:
559    #
560    # pub_type: Type of publish discovery session: unsolicited or solicited.
561    # sub_type: Type of subscribe discovery session: passive or active.
562    # size: Size of payload fields (service name, service specific info, and match
563    # filter: typical, max, or min.
564    #######################################
565
566    @test_tracker_info(uuid="954ebbde-ed2b-4f04-9e68-88239187d69d")
567    def test_positive_unsolicited_passive_typical(self):
568        """Functional test case / Discovery test cases / positive test case:
569    - Solicited publish + passive subscribe
570    - Typical payload fields size
571
572    Verifies that discovery and message exchange succeeds.
573    """
574        self.positive_discovery_test_utility(
575            ptype=aconsts.PUBLISH_TYPE_UNSOLICITED,
576            stype=aconsts.SUBSCRIBE_TYPE_PASSIVE,
577            payload_size=self.PAYLOAD_SIZE_TYPICAL)
578
579    @test_tracker_info(uuid="67fb22bb-6985-4345-95a4-90b76681a58b")
580    def test_positive_unsolicited_passive_min(self):
581        """Functional test case / Discovery test cases / positive test case:
582    - Solicited publish + passive subscribe
583    - Minimal payload fields size
584
585    Verifies that discovery and message exchange succeeds.
586    """
587        self.positive_discovery_test_utility(
588            ptype=aconsts.PUBLISH_TYPE_UNSOLICITED,
589            stype=aconsts.SUBSCRIBE_TYPE_PASSIVE,
590            payload_size=self.PAYLOAD_SIZE_MIN)
591
592    @test_tracker_info(uuid="a02a47b9-41bb-47bb-883b-921024a2c30d")
593    def test_positive_unsolicited_passive_max(self):
594        """Functional test case / Discovery test cases / positive test case:
595    - Solicited publish + passive subscribe
596    - Maximal payload fields size
597
598    Verifies that discovery and message exchange succeeds.
599    """
600        self.positive_discovery_test_utility(
601            ptype=aconsts.PUBLISH_TYPE_UNSOLICITED,
602            stype=aconsts.SUBSCRIBE_TYPE_PASSIVE,
603            payload_size=self.PAYLOAD_SIZE_MAX)
604
605    @test_tracker_info(uuid="586c657f-2388-4e7a-baee-9bce2f3d1a16")
606    def test_positive_solicited_active_typical(self):
607        """Functional test case / Discovery test cases / positive test case:
608    - Unsolicited publish + active subscribe
609    - Typical payload fields size
610
611    Verifies that discovery and message exchange succeeds.
612    """
613        self.positive_discovery_test_utility(
614            ptype=aconsts.PUBLISH_TYPE_SOLICITED,
615            stype=aconsts.SUBSCRIBE_TYPE_ACTIVE,
616            payload_size=self.PAYLOAD_SIZE_TYPICAL)
617
618    @test_tracker_info(uuid="5369e4ff-f406-48c5-b41a-df38ec340146")
619    def test_positive_solicited_active_min(self):
620        """Functional test case / Discovery test cases / positive test case:
621    - Unsolicited publish + active subscribe
622    - Minimal payload fields size
623
624    Verifies that discovery and message exchange succeeds.
625    """
626        self.positive_discovery_test_utility(
627            ptype=aconsts.PUBLISH_TYPE_SOLICITED,
628            stype=aconsts.SUBSCRIBE_TYPE_ACTIVE,
629            payload_size=self.PAYLOAD_SIZE_MIN)
630
631    @test_tracker_info(uuid="634c6eb8-2c4f-42bd-9bbb-d874d0ec22f3")
632    def test_positive_solicited_active_max(self):
633        """Functional test case / Discovery test cases / positive test case:
634    - Unsolicited publish + active subscribe
635    - Maximal payload fields size
636
637    Verifies that discovery and message exchange succeeds.
638    """
639        self.positive_discovery_test_utility(
640            ptype=aconsts.PUBLISH_TYPE_SOLICITED,
641            stype=aconsts.SUBSCRIBE_TYPE_ACTIVE,
642            payload_size=self.PAYLOAD_SIZE_MAX)
643
644    #######################################
645    # TTL tests key:
646    #
647    # names is: test_ttl_<pub_type|sub_type>_<term_ind>
648    # where:
649    #
650    # pub_type: Type of publish discovery session: unsolicited or solicited.
651    # sub_type: Type of subscribe discovery session: passive or active.
652    # term_ind: ind_on or ind_off
653    #######################################
654
655    @test_tracker_info(uuid="9d7e758e-e0e2-4550-bcee-bfb6a2bff63e")
656    def test_ttl_unsolicited_ind_on(self):
657        """Functional test case / Discovery test cases / TTL test case:
658    - Unsolicited publish
659    - Termination indication enabled
660    """
661        self.positive_ttl_test_utility(
662            is_publish=True,
663            ptype=aconsts.PUBLISH_TYPE_UNSOLICITED,
664            stype=None,
665            term_ind_on=True)
666
667    @test_tracker_info(uuid="48fd69bc-cc2a-4f65-a0a1-63d7c1720702")
668    def test_ttl_unsolicited_ind_off(self):
669        """Functional test case / Discovery test cases / TTL test case:
670    - Unsolicited publish
671    - Termination indication disabled
672    """
673        self.positive_ttl_test_utility(
674            is_publish=True,
675            ptype=aconsts.PUBLISH_TYPE_UNSOLICITED,
676            stype=None,
677            term_ind_on=False)
678
679    @test_tracker_info(uuid="afb75fc1-9ba7-446a-b5ed-7cd37ab51b1c")
680    def test_ttl_solicited_ind_on(self):
681        """Functional test case / Discovery test cases / TTL test case:
682    - Solicited publish
683    - Termination indication enabled
684    """
685        self.positive_ttl_test_utility(
686            is_publish=True,
687            ptype=aconsts.PUBLISH_TYPE_SOLICITED,
688            stype=None,
689            term_ind_on=True)
690
691    @test_tracker_info(uuid="703311a6-e444-4055-94ee-ea9b9b71799e")
692    def test_ttl_solicited_ind_off(self):
693        """Functional test case / Discovery test cases / TTL test case:
694    - Solicited publish
695    - Termination indication disabled
696    """
697        self.positive_ttl_test_utility(
698            is_publish=True,
699            ptype=aconsts.PUBLISH_TYPE_SOLICITED,
700            stype=None,
701            term_ind_on=False)
702
703    @test_tracker_info(uuid="38a541c4-ff55-4387-87b7-4d940489da9d")
704    def test_ttl_passive_ind_on(self):
705        """Functional test case / Discovery test cases / TTL test case:
706    - Passive subscribe
707    - Termination indication enabled
708    """
709        self.positive_ttl_test_utility(
710            is_publish=False,
711            ptype=None,
712            stype=aconsts.SUBSCRIBE_TYPE_PASSIVE,
713            term_ind_on=True)
714
715    @test_tracker_info(uuid="ba971e12-b0ca-417c-a1b5-9451598de47d")
716    def test_ttl_passive_ind_off(self):
717        """Functional test case / Discovery test cases / TTL test case:
718    - Passive subscribe
719    - Termination indication disabled
720    """
721        self.positive_ttl_test_utility(
722            is_publish=False,
723            ptype=None,
724            stype=aconsts.SUBSCRIBE_TYPE_PASSIVE,
725            term_ind_on=False)
726
727    @test_tracker_info(uuid="7b5d96f2-2415-4b98-9a51-32957f0679a0")
728    def test_ttl_active_ind_on(self):
729        """Functional test case / Discovery test cases / TTL test case:
730    - Active subscribe
731    - Termination indication enabled
732    """
733        self.positive_ttl_test_utility(
734            is_publish=False,
735            ptype=None,
736            stype=aconsts.SUBSCRIBE_TYPE_ACTIVE,
737            term_ind_on=True)
738
739    @test_tracker_info(uuid="c9268eca-0a30-42dd-8e6c-b8b0b84697fb")
740    def test_ttl_active_ind_off(self):
741        """Functional test case / Discovery test cases / TTL test case:
742    - Active subscribe
743    - Termination indication disabled
744    """
745        self.positive_ttl_test_utility(
746            is_publish=False,
747            ptype=None,
748            stype=aconsts.SUBSCRIBE_TYPE_ACTIVE,
749            term_ind_on=False)
750
751    #######################################
752    # Mismatched service name tests key:
753    #
754    # names is: test_mismatch_service_name_<pub_type>_<sub_type>
755    # where:
756    #
757    # pub_type: Type of publish discovery session: unsolicited or solicited.
758    # sub_type: Type of subscribe discovery session: passive or active.
759    #######################################
760
761    @test_tracker_info(uuid="175415e9-7d07-40d0-95f0-3a5f91ea4711")
762    def test_mismatch_service_name_unsolicited_passive(self):
763        """Functional test case / Discovery test cases / Mismatch service name
764    - Unsolicited publish
765    - Passive subscribe
766    """
767        self.discovery_mismatch_test_utility(
768            is_expected_to_pass=False,
769            p_type=aconsts.PUBLISH_TYPE_UNSOLICITED,
770            s_type=aconsts.SUBSCRIBE_TYPE_PASSIVE,
771            p_service_name="GoogleTestServiceXXX",
772            s_service_name="GoogleTestServiceYYY")
773
774    @test_tracker_info(uuid="c22a54ce-9e46-47a5-ac44-831faf93d317")
775    def test_mismatch_service_name_solicited_active(self):
776        """Functional test case / Discovery test cases / Mismatch service name
777    - Solicited publish
778    - Active subscribe
779    """
780        self.discovery_mismatch_test_utility(
781            is_expected_to_pass=False,
782            p_type=aconsts.PUBLISH_TYPE_SOLICITED,
783            s_type=aconsts.SUBSCRIBE_TYPE_ACTIVE,
784            p_service_name="GoogleTestServiceXXX",
785            s_service_name="GoogleTestServiceYYY")
786
787    #######################################
788    # Mismatched discovery session type tests key:
789    #
790    # names is: test_mismatch_service_type_<pub_type>_<sub_type>
791    # where:
792    #
793    # pub_type: Type of publish discovery session: unsolicited or solicited.
794    # sub_type: Type of subscribe discovery session: passive or active.
795    #######################################
796
797    @test_tracker_info(uuid="4806f631-d9eb-45fd-9e75-24674962770f")
798    def test_mismatch_service_type_unsolicited_active(self):
799        """Functional test case / Discovery test cases / Mismatch service name
800    - Unsolicited publish
801    - Active subscribe
802    """
803        self.discovery_mismatch_test_utility(
804            is_expected_to_pass=True,
805            p_type=aconsts.PUBLISH_TYPE_UNSOLICITED,
806            s_type=aconsts.SUBSCRIBE_TYPE_ACTIVE)
807
808    @test_tracker_info(uuid="12d648fd-b8fa-4c0f-9467-95e2366047de")
809    def test_mismatch_service_type_solicited_passive(self):
810        """Functional test case / Discovery test cases / Mismatch service name
811    - Unsolicited publish
812    - Active subscribe
813    """
814        self.discovery_mismatch_test_utility(
815            is_expected_to_pass=False,
816            p_type=aconsts.PUBLISH_TYPE_SOLICITED,
817            s_type=aconsts.SUBSCRIBE_TYPE_PASSIVE)
818
819    #######################################
820    # Mismatched discovery match filter tests key:
821    #
822    # names is: test_mismatch_match_filter_<pub_type>_<sub_type>
823    # where:
824    #
825    # pub_type: Type of publish discovery session: unsolicited or solicited.
826    # sub_type: Type of subscribe discovery session: passive or active.
827    #######################################
828
829    @test_tracker_info(uuid="d98454cb-64af-4266-8fed-f0b545a2d7c4")
830    def test_mismatch_match_filter_unsolicited_passive(self):
831        """Functional test case / Discovery test cases / Mismatch match filter
832    - Unsolicited publish
833    - Passive subscribe
834    """
835        self.discovery_mismatch_test_utility(
836            is_expected_to_pass=False,
837            p_type=aconsts.PUBLISH_TYPE_UNSOLICITED,
838            s_type=aconsts.SUBSCRIBE_TYPE_PASSIVE,
839            p_mf_1="hello there string",
840            s_mf_1="goodbye there string")
841
842    @test_tracker_info(uuid="663c1008-ae11-4e1a-87c7-c311d83f481c")
843    def test_mismatch_match_filter_solicited_active(self):
844        """Functional test case / Discovery test cases / Mismatch match filter
845    - Solicited publish
846    - Active subscribe
847    """
848        self.discovery_mismatch_test_utility(
849            is_expected_to_pass=False,
850            p_type=aconsts.PUBLISH_TYPE_SOLICITED,
851            s_type=aconsts.SUBSCRIBE_TYPE_ACTIVE,
852            p_mf_1="hello there string",
853            s_mf_1="goodbye there string")
854
855    #######################################
856    # Multiple concurrent services
857    #######################################
858
859    def run_multiple_concurrent_services(self, type_x, type_y):
860        """Validate multiple identical discovery services running on both devices:
861    - DUT1 & DUT2 running Publish for X
862    - DUT1 & DUT2 running Publish for Y
863    - DUT1 Subscribes for X
864    - DUT2 Subscribes for Y
865    Message exchanges.
866
867    Note: test requires that devices support 2 publish sessions concurrently.
868    The test will be skipped if the devices are not capable.
869
870    Args:
871      type_x, type_y: A list of [ptype, stype] of the publish and subscribe
872                      types for services X and Y respectively.
873    """
874        dut1 = self.android_devices[0]
875        dut2 = self.android_devices[1]
876
877        X_SERVICE_NAME = "ServiceXXX"
878        Y_SERVICE_NAME = "ServiceYYY"
879
880        asserts.skip_if(
881            dut1.aware_capabilities[aconsts.CAP_MAX_PUBLISHES] < 2
882            or dut2.aware_capabilities[aconsts.CAP_MAX_PUBLISHES] < 2,
883            "Devices do not support 2 publish sessions")
884
885        # attach and wait for confirmation
886        id1 = dut1.droid.wifiAwareAttach(False)
887        autils.wait_for_event(dut1, aconsts.EVENT_CB_ON_ATTACHED)
888        time.sleep(self.device_startup_offset)
889        id2 = dut2.droid.wifiAwareAttach(False)
890        autils.wait_for_event(dut2, aconsts.EVENT_CB_ON_ATTACHED)
891
892        # DUT1 & DUT2: start publishing both X & Y services and wait for
893        # confirmations
894        dut1_x_pid = dut1.droid.wifiAwarePublish(
895            id1, autils.create_discovery_config(X_SERVICE_NAME, type_x[0]))
896        event = autils.wait_for_event(dut1,
897                                      aconsts.SESSION_CB_ON_PUBLISH_STARTED)
898        asserts.assert_equal(event["data"][aconsts.SESSION_CB_KEY_SESSION_ID],
899                             dut1_x_pid,
900                             "Unexpected DUT1 X publish session discovery ID")
901
902        dut1_y_pid = dut1.droid.wifiAwarePublish(
903            id1, autils.create_discovery_config(Y_SERVICE_NAME, type_y[0]))
904        event = autils.wait_for_event(dut1,
905                                      aconsts.SESSION_CB_ON_PUBLISH_STARTED)
906        asserts.assert_equal(event["data"][aconsts.SESSION_CB_KEY_SESSION_ID],
907                             dut1_y_pid,
908                             "Unexpected DUT1 Y publish session discovery ID")
909
910        dut2_x_pid = dut2.droid.wifiAwarePublish(
911            id2, autils.create_discovery_config(X_SERVICE_NAME, type_x[0]))
912        event = autils.wait_for_event(dut2,
913                                      aconsts.SESSION_CB_ON_PUBLISH_STARTED)
914        asserts.assert_equal(event["data"][aconsts.SESSION_CB_KEY_SESSION_ID],
915                             dut2_x_pid,
916                             "Unexpected DUT2 X publish session discovery ID")
917
918        dut2_y_pid = dut2.droid.wifiAwarePublish(
919            id2, autils.create_discovery_config(Y_SERVICE_NAME, type_y[0]))
920        event = autils.wait_for_event(dut2,
921                                      aconsts.SESSION_CB_ON_PUBLISH_STARTED)
922        asserts.assert_equal(event["data"][aconsts.SESSION_CB_KEY_SESSION_ID],
923                             dut2_y_pid,
924                             "Unexpected DUT2 Y publish session discovery ID")
925
926        # DUT1: start subscribing for X
927        dut1_x_sid = dut1.droid.wifiAwareSubscribe(
928            id1, autils.create_discovery_config(X_SERVICE_NAME, type_x[1]))
929        autils.wait_for_event(dut1, aconsts.SESSION_CB_ON_SUBSCRIBE_STARTED)
930
931        # DUT2: start subscribing for Y
932        dut2_y_sid = dut2.droid.wifiAwareSubscribe(
933            id2, autils.create_discovery_config(Y_SERVICE_NAME, type_y[1]))
934        autils.wait_for_event(dut2, aconsts.SESSION_CB_ON_SUBSCRIBE_STARTED)
935
936        # DUT1 & DUT2: wait for service discovery
937        event = autils.wait_for_event(dut1,
938                                      aconsts.SESSION_CB_ON_SERVICE_DISCOVERED)
939        asserts.assert_equal(
940            event["data"][aconsts.SESSION_CB_KEY_SESSION_ID], dut1_x_sid,
941            "Unexpected DUT1 X subscribe session discovery ID")
942        dut1_peer_id_for_dut2_x = event["data"][aconsts.SESSION_CB_KEY_PEER_ID]
943
944        event = autils.wait_for_event(dut2,
945                                      aconsts.SESSION_CB_ON_SERVICE_DISCOVERED)
946        asserts.assert_equal(
947            event["data"][aconsts.SESSION_CB_KEY_SESSION_ID], dut2_y_sid,
948            "Unexpected DUT2 Y subscribe session discovery ID")
949        dut2_peer_id_for_dut1_y = event["data"][aconsts.SESSION_CB_KEY_PEER_ID]
950
951        # DUT1.X send message to DUT2
952        x_msg = "Hello X on DUT2!"
953        dut1.droid.wifiAwareSendMessage(dut1_x_sid, dut1_peer_id_for_dut2_x,
954                                        self.get_next_msg_id(), x_msg,
955                                        self.msg_retx_count)
956        autils.wait_for_event(dut1, aconsts.SESSION_CB_ON_MESSAGE_SENT)
957        event = autils.wait_for_event(dut2,
958                                      aconsts.SESSION_CB_ON_MESSAGE_RECEIVED)
959        asserts.assert_equal(
960            event["data"][aconsts.SESSION_CB_KEY_SESSION_ID], dut2_x_pid,
961            "Unexpected publish session ID on DUT2 for meesage "
962            "received on service X")
963        asserts.assert_equal(
964            event["data"][aconsts.SESSION_CB_KEY_MESSAGE_AS_STRING], x_msg,
965            "Message on service X from DUT1 to DUT2 not received correctly")
966
967        # DUT2.Y send message to DUT1
968        y_msg = "Hello Y on DUT1!"
969        dut2.droid.wifiAwareSendMessage(dut2_y_sid, dut2_peer_id_for_dut1_y,
970                                        self.get_next_msg_id(), y_msg,
971                                        self.msg_retx_count)
972        autils.wait_for_event(dut2, aconsts.SESSION_CB_ON_MESSAGE_SENT)
973        event = autils.wait_for_event(dut1,
974                                      aconsts.SESSION_CB_ON_MESSAGE_RECEIVED)
975        asserts.assert_equal(
976            event["data"][aconsts.SESSION_CB_KEY_SESSION_ID], dut1_y_pid,
977            "Unexpected publish session ID on DUT1 for meesage "
978            "received on service Y")
979        asserts.assert_equal(
980            event["data"][aconsts.SESSION_CB_KEY_MESSAGE_AS_STRING], y_msg,
981            "Message on service Y from DUT2 to DUT1 not received correctly")
982
983    @test_tracker_info(uuid="eef80cf3-1fd2-4526-969b-6af2dce785d7")
984    def test_multiple_concurrent_services_both_unsolicited_passive(self):
985        """Validate multiple concurrent discovery sessions running on both devices.
986    - DUT1 & DUT2 running Publish for X
987    - DUT1 & DUT2 running Publish for Y
988    - DUT1 Subscribes for X
989    - DUT2 Subscribes for Y
990    Message exchanges.
991
992    Both sessions are Unsolicited/Passive.
993
994    Note: test requires that devices support 2 publish sessions concurrently.
995    The test will be skipped if the devices are not capable.
996    """
997        self.run_multiple_concurrent_services(
998            type_x=[
999                aconsts.PUBLISH_TYPE_UNSOLICITED,
1000                aconsts.SUBSCRIBE_TYPE_PASSIVE
1001            ],
1002            type_y=[
1003                aconsts.PUBLISH_TYPE_UNSOLICITED,
1004                aconsts.SUBSCRIBE_TYPE_PASSIVE
1005            ])
1006
1007    @test_tracker_info(uuid="46739f04-ab2b-4556-b1a4-9aa2774869b5")
1008    def test_multiple_concurrent_services_both_solicited_active(self):
1009        """Validate multiple concurrent discovery sessions running on both devices.
1010    - DUT1 & DUT2 running Publish for X
1011    - DUT1 & DUT2 running Publish for Y
1012    - DUT1 Subscribes for X
1013    - DUT2 Subscribes for Y
1014    Message exchanges.
1015
1016    Both sessions are Solicited/Active.
1017
1018    Note: test requires that devices support 2 publish sessions concurrently.
1019    The test will be skipped if the devices are not capable.
1020    """
1021        self.run_multiple_concurrent_services(
1022            type_x=[
1023                aconsts.PUBLISH_TYPE_SOLICITED, aconsts.SUBSCRIBE_TYPE_ACTIVE
1024            ],
1025            type_y=[
1026                aconsts.PUBLISH_TYPE_SOLICITED, aconsts.SUBSCRIBE_TYPE_ACTIVE
1027            ])
1028
1029    @test_tracker_info(uuid="5f8f7fd2-4a0e-4cca-8cbb-6d54353f2baa")
1030    def test_multiple_concurrent_services_mix_unsolicited_solicited(self):
1031        """Validate multiple concurrent discovery sessions running on both devices.
1032    - DUT1 & DUT2 running Publish for X
1033    - DUT1 & DUT2 running Publish for Y
1034    - DUT1 Subscribes for X
1035    - DUT2 Subscribes for Y
1036    Message exchanges.
1037
1038    Session A is Unsolicited/Passive.
1039    Session B is Solicited/Active.
1040
1041    Note: test requires that devices support 2 publish sessions concurrently.
1042    The test will be skipped if the devices are not capable.
1043    """
1044        self.run_multiple_concurrent_services(
1045            type_x=[
1046                aconsts.PUBLISH_TYPE_UNSOLICITED,
1047                aconsts.SUBSCRIBE_TYPE_PASSIVE
1048            ],
1049            type_y=[
1050                aconsts.PUBLISH_TYPE_SOLICITED, aconsts.SUBSCRIBE_TYPE_ACTIVE
1051            ])
1052
1053    #########################################################
1054
1055    @test_tracker_info(uuid="908ec896-fc7a-4ee4-b633-a2f042b74448")
1056    def test_upper_lower_service_name_equivalence(self):
1057        """Validate that Service Name is case-insensitive. Publish a service name
1058    with mixed case, subscribe to the same service name with alternative case
1059    and verify that discovery happens."""
1060        p_dut = self.android_devices[0]
1061        s_dut = self.android_devices[1]
1062
1063        pub_service_name = "GoogleAbCdEf"
1064        sub_service_name = "GoogleaBcDeF"
1065
1066        autils.create_discovery_pair(
1067            p_dut,
1068            s_dut,
1069            p_config=autils.create_discovery_config(
1070                pub_service_name, aconsts.PUBLISH_TYPE_UNSOLICITED),
1071            s_config=autils.create_discovery_config(
1072                sub_service_name, aconsts.SUBSCRIBE_TYPE_PASSIVE),
1073            device_startup_offset=self.device_startup_offset)
1074