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 create_base_config(self, caps, is_publish, ptype, stype, payload_size,
44                           ttl, term_ind_on, null_match):
45        """Create a base configuration based on input parameters.
46
47    Args:
48      caps: device capability dictionary
49      is_publish: True if a publish config, else False
50      ptype: unsolicited or solicited (used if is_publish is True)
51      stype: passive or active (used if is_publish is False)
52      payload_size: min, typical, max (PAYLOAD_SIZE_xx)
53      ttl: time-to-live configuration (0 - forever)
54      term_ind_on: is termination indication enabled
55      null_match: null-out the middle match filter
56    Returns:
57      publish discovery configuration object.
58    """
59        config = {}
60        if is_publish:
61            config[aconsts.DISCOVERY_KEY_DISCOVERY_TYPE] = ptype
62        else:
63            config[aconsts.DISCOVERY_KEY_DISCOVERY_TYPE] = stype
64        config[aconsts.DISCOVERY_KEY_TTL] = ttl
65        config[aconsts.DISCOVERY_KEY_TERM_CB_ENABLED] = term_ind_on
66        if payload_size == self.PAYLOAD_SIZE_MIN:
67            config[aconsts.DISCOVERY_KEY_SERVICE_NAME] = "a"
68            config[aconsts.DISCOVERY_KEY_SSI] = None
69            config[aconsts.DISCOVERY_KEY_MATCH_FILTER_LIST] = []
70        elif payload_size == self.PAYLOAD_SIZE_TYPICAL:
71            config[aconsts.DISCOVERY_KEY_SERVICE_NAME] = "GoogleTestServiceX"
72            if is_publish:
73                config[aconsts.DISCOVERY_KEY_SSI] = string.ascii_letters
74            else:
75                config[aconsts.
76                       DISCOVERY_KEY_SSI] = string.ascii_letters[::
77                                                                 -1]  # reverse
78            config[
79                aconsts.DISCOVERY_KEY_MATCH_FILTER_LIST] = autils.encode_list(
80                    [(10).to_bytes(1, byteorder="big"), "hello there string"
81                     if not null_match else None,
82                     bytes(range(40))])
83        else:  # PAYLOAD_SIZE_MAX
84            config[aconsts.DISCOVERY_KEY_SERVICE_NAME] = "VeryLong" + "X" * (
85                caps[aconsts.CAP_MAX_SERVICE_NAME_LEN] - 8)
86            config[aconsts.DISCOVERY_KEY_SSI] = (
87                "P" if is_publish else
88                "S") * caps[aconsts.CAP_MAX_SERVICE_SPECIFIC_INFO_LEN]
89            mf = autils.construct_max_match_filter(
90                caps[aconsts.CAP_MAX_MATCH_FILTER_LEN])
91            if null_match:
92                mf[2] = None
93            config[aconsts.
94                   DISCOVERY_KEY_MATCH_FILTER_LIST] = autils.encode_list(mf)
95
96        return config
97
98    def create_publish_config(self, caps, ptype, payload_size, ttl,
99                              term_ind_on, null_match):
100        """Create a publish configuration based on input parameters.
101
102    Args:
103      caps: device capability dictionary
104      ptype: unsolicited or solicited
105      payload_size: min, typical, max (PAYLOAD_SIZE_xx)
106      ttl: time-to-live configuration (0 - forever)
107      term_ind_on: is termination indication enabled
108      null_match: null-out the middle match filter
109    Returns:
110      publish discovery configuration object.
111    """
112        return self.create_base_config(caps, True, ptype, None, payload_size,
113                                       ttl, term_ind_on, null_match)
114
115    def create_subscribe_config(self, caps, stype, payload_size, ttl,
116                                term_ind_on, null_match):
117        """Create a subscribe configuration based on input parameters.
118
119    Args:
120      caps: device capability dictionary
121      stype: passive or active
122      payload_size: min, typical, max (PAYLOAD_SIZE_xx)
123      ttl: time-to-live configuration (0 - forever)
124      term_ind_on: is termination indication enabled
125      null_match: null-out the middle match filter
126    Returns:
127      subscribe discovery configuration object.
128    """
129        return self.create_base_config(caps, False, None, stype, payload_size,
130                                       ttl, term_ind_on, null_match)
131
132    def positive_discovery_test_utility(self, ptype, stype, payload_size):
133        """Utility which runs a positive discovery test:
134    - Discovery (publish/subscribe) with TTL=0 (non-self-terminating)
135    - Exchange messages
136    - Update publish/subscribe
137    - Terminate
138
139    Args:
140      ptype: Publish discovery type
141      stype: Subscribe discovery type
142      payload_size: One of PAYLOAD_SIZE_* constants - MIN, TYPICAL, MAX
143    """
144        p_dut = self.android_devices[0]
145        p_dut.pretty_name = "Publisher"
146        s_dut = self.android_devices[1]
147        s_dut.pretty_name = "Subscriber"
148
149        # Publisher+Subscriber: attach and wait for confirmation
150        p_id = p_dut.droid.wifiAwareAttach(False)
151        autils.wait_for_event(p_dut, aconsts.EVENT_CB_ON_ATTACHED)
152        time.sleep(self.device_startup_offset)
153        s_id = s_dut.droid.wifiAwareAttach(False)
154        autils.wait_for_event(s_dut, aconsts.EVENT_CB_ON_ATTACHED)
155
156        # Publisher: start publish and wait for confirmation
157        p_config = self.create_publish_config(
158            p_dut.aware_capabilities,
159            ptype,
160            payload_size,
161            ttl=0,
162            term_ind_on=False,
163            null_match=False)
164        p_disc_id = p_dut.droid.wifiAwarePublish(p_id, p_config)
165        autils.wait_for_event(p_dut, aconsts.SESSION_CB_ON_PUBLISH_STARTED)
166
167        # Subscriber: start subscribe and wait for confirmation
168        s_config = self.create_subscribe_config(
169            s_dut.aware_capabilities,
170            stype,
171            payload_size,
172            ttl=0,
173            term_ind_on=False,
174            null_match=True)
175        s_disc_id = s_dut.droid.wifiAwareSubscribe(s_id, s_config)
176        autils.wait_for_event(s_dut, aconsts.SESSION_CB_ON_SUBSCRIBE_STARTED)
177
178        # Subscriber: wait for service discovery
179        discovery_event = autils.wait_for_event(
180            s_dut, aconsts.SESSION_CB_ON_SERVICE_DISCOVERED)
181        peer_id_on_sub = discovery_event["data"][
182            aconsts.SESSION_CB_KEY_PEER_ID]
183
184        # Subscriber: validate contents of discovery:
185        # - SSI: publisher's
186        # - Match filter: UNSOLICITED - publisher, SOLICITED - subscriber
187        autils.assert_equal_strings(
188            bytes(discovery_event["data"][
189                aconsts.SESSION_CB_KEY_SERVICE_SPECIFIC_INFO]).decode("utf-8"),
190            p_config[aconsts.DISCOVERY_KEY_SSI],
191            "Discovery mismatch: service specific info (SSI)")
192        asserts.assert_equal(
193            autils.decode_list(discovery_event["data"][
194                aconsts.SESSION_CB_KEY_MATCH_FILTER_LIST]),
195            autils.decode_list(
196                p_config[aconsts.DISCOVERY_KEY_MATCH_FILTER_LIST]
197                if ptype == aconsts.PUBLISH_TYPE_UNSOLICITED else s_config[
198                    aconsts.DISCOVERY_KEY_MATCH_FILTER_LIST]),
199            "Discovery mismatch: match filter")
200
201        # Subscriber: send message to peer (Publisher)
202        s_dut.droid.wifiAwareSendMessage(s_disc_id, peer_id_on_sub,
203                                         self.get_next_msg_id(),
204                                         self.query_msg, self.msg_retx_count)
205        autils.wait_for_event(s_dut, aconsts.SESSION_CB_ON_MESSAGE_SENT)
206
207        # Publisher: wait for received message
208        pub_rx_msg_event = autils.wait_for_event(
209            p_dut, aconsts.SESSION_CB_ON_MESSAGE_RECEIVED)
210        peer_id_on_pub = pub_rx_msg_event["data"][
211            aconsts.SESSION_CB_KEY_PEER_ID]
212
213        # Publisher: validate contents of message
214        asserts.assert_equal(
215            pub_rx_msg_event["data"][aconsts.SESSION_CB_KEY_MESSAGE_AS_STRING],
216            self.query_msg, "Subscriber -> Publisher message corrupted")
217
218        # Publisher: send message to peer (Subscriber)
219        p_dut.droid.wifiAwareSendMessage(p_disc_id, peer_id_on_pub,
220                                         self.get_next_msg_id(),
221                                         self.response_msg,
222                                         self.msg_retx_count)
223        autils.wait_for_event(p_dut, aconsts.SESSION_CB_ON_MESSAGE_SENT)
224
225        # Subscriber: wait for received message
226        sub_rx_msg_event = autils.wait_for_event(
227            s_dut, aconsts.SESSION_CB_ON_MESSAGE_RECEIVED)
228
229        # Subscriber: validate contents of message
230        asserts.assert_equal(
231            sub_rx_msg_event["data"][aconsts.SESSION_CB_KEY_PEER_ID],
232            peer_id_on_sub,
233            "Subscriber received message from different peer ID then discovery!?"
234        )
235        autils.assert_equal_strings(
236            sub_rx_msg_event["data"][aconsts.SESSION_CB_KEY_MESSAGE_AS_STRING],
237            self.response_msg, "Publisher -> Subscriber message corrupted")
238
239        # Subscriber: validate that we're not getting another Service Discovery
240        autils.fail_on_event(s_dut, aconsts.SESSION_CB_ON_SERVICE_DISCOVERED)
241
242        # Publisher: update publish and wait for confirmation
243        p_config[aconsts.DISCOVERY_KEY_SSI] = "something else"
244        p_dut.droid.wifiAwareUpdatePublish(p_disc_id, p_config)
245        autils.wait_for_event(p_dut,
246                              aconsts.SESSION_CB_ON_SESSION_CONFIG_UPDATED)
247
248        # Subscriber: expect a new service discovery
249        discovery_event = autils.wait_for_event(
250            s_dut, aconsts.SESSION_CB_ON_SERVICE_DISCOVERED)
251
252        # Subscriber: validate contents of discovery
253        autils.assert_equal_strings(
254            bytes(discovery_event["data"][
255                aconsts.SESSION_CB_KEY_SERVICE_SPECIFIC_INFO]).decode("utf-8"),
256            p_config[aconsts.DISCOVERY_KEY_SSI],
257            "Discovery mismatch (after pub update): service specific info (SSI)"
258        )
259        asserts.assert_equal(
260            autils.decode_list(discovery_event["data"][
261                aconsts.SESSION_CB_KEY_MATCH_FILTER_LIST]),
262            autils.decode_list(
263                p_config[aconsts.DISCOVERY_KEY_MATCH_FILTER_LIST]
264                if ptype == aconsts.PUBLISH_TYPE_UNSOLICITED else s_config[
265                    aconsts.DISCOVERY_KEY_MATCH_FILTER_LIST]),
266            "Discovery mismatch: match filter")
267        asserts.assert_equal(
268            peer_id_on_sub,
269            discovery_event["data"][aconsts.SESSION_CB_KEY_PEER_ID],
270            "Peer ID changed when publish was updated!?")
271
272        # Subscribe: update subscribe and wait for confirmation
273        s_config = self.create_subscribe_config(
274            s_dut.aware_capabilities,
275            stype,
276            payload_size,
277            ttl=0,
278            term_ind_on=False,
279            null_match=False)
280        s_dut.droid.wifiAwareUpdateSubscribe(s_disc_id, s_config)
281        autils.wait_for_event(s_dut,
282                              aconsts.SESSION_CB_ON_SESSION_CONFIG_UPDATED)
283
284        # Publisher+Subscriber: Terminate sessions
285        p_dut.droid.wifiAwareDestroyDiscoverySession(p_disc_id)
286        s_dut.droid.wifiAwareDestroyDiscoverySession(s_disc_id)
287
288        # sleep for timeout period and then verify all 'fail_on_event' together
289        time.sleep(autils.EVENT_TIMEOUT)
290
291        # verify that there were no other events
292        autils.verify_no_more_events(p_dut, timeout=0)
293        autils.verify_no_more_events(s_dut, timeout=0)
294
295        # verify that forbidden callbacks aren't called
296        autils.validate_forbidden_callbacks(p_dut, {aconsts.CB_EV_MATCH: 0})
297
298    def verify_discovery_session_term(self, dut, disc_id, config, is_publish,
299                                      term_ind_on):
300        """Utility to verify that the specified discovery session has terminated (by
301    waiting for the TTL and then attempting to reconfigure).
302
303    Args:
304      dut: device under test
305      disc_id: discovery id for the existing session
306      config: configuration of the existing session
307      is_publish: True if the configuration was publish, False if subscribe
308      term_ind_on: True if a termination indication is expected, False otherwise
309    """
310        # Wait for session termination
311        if term_ind_on:
312            autils.wait_for_event(
313                dut,
314                autils.decorate_event(aconsts.SESSION_CB_ON_SESSION_TERMINATED,
315                                      disc_id))
316        else:
317            # can't defer wait to end since in any case have to wait for session to
318            # expire
319            autils.fail_on_event(
320                dut,
321                autils.decorate_event(aconsts.SESSION_CB_ON_SESSION_TERMINATED,
322                                      disc_id))
323
324        # Validate that session expired by trying to configure it (expect failure)
325        config[aconsts.DISCOVERY_KEY_SSI] = "something else"
326        if is_publish:
327            dut.droid.wifiAwareUpdatePublish(disc_id, config)
328        else:
329            dut.droid.wifiAwareUpdateSubscribe(disc_id, config)
330
331        # The response to update discovery session is:
332        # term_ind_on=True: session was cleaned-up so won't get an explicit failure, but won't get a
333        #                   success either. Can check for no SESSION_CB_ON_SESSION_CONFIG_UPDATED but
334        #                   will defer to the end of the test (no events on queue).
335        # term_ind_on=False: session was not cleaned-up (yet). So expect
336        #                    SESSION_CB_ON_SESSION_CONFIG_FAILED.
337        if not term_ind_on:
338            autils.wait_for_event(
339                dut,
340                autils.decorate_event(
341                    aconsts.SESSION_CB_ON_SESSION_CONFIG_FAILED, disc_id))
342
343    def positive_ttl_test_utility(self, is_publish, ptype, stype, term_ind_on):
344        """Utility which runs a positive discovery session TTL configuration test
345
346    Iteration 1: Verify session started with TTL
347    Iteration 2: Verify session started without TTL and reconfigured with TTL
348    Iteration 3: Verify session started with (long) TTL and reconfigured with
349                 (short) TTL
350
351    Args:
352      is_publish: True if testing publish, False if testing subscribe
353      ptype: Publish discovery type (used if is_publish is True)
354      stype: Subscribe discovery type (used if is_publish is False)
355      term_ind_on: Configuration of termination indication
356    """
357        SHORT_TTL = 5  # 5 seconds
358        LONG_TTL = 100  # 100 seconds
359        dut = self.android_devices[0]
360
361        # Attach and wait for confirmation
362        id = dut.droid.wifiAwareAttach(False)
363        autils.wait_for_event(dut, aconsts.EVENT_CB_ON_ATTACHED)
364
365        # Iteration 1: Start discovery session with TTL
366        config = self.create_base_config(
367            dut.aware_capabilities, is_publish, ptype, stype,
368            self.PAYLOAD_SIZE_TYPICAL, SHORT_TTL, term_ind_on, False)
369        if is_publish:
370            disc_id = dut.droid.wifiAwarePublish(id, config, True)
371            autils.wait_for_event(
372                dut,
373                autils.decorate_event(aconsts.SESSION_CB_ON_PUBLISH_STARTED,
374                                      disc_id))
375        else:
376            disc_id = dut.droid.wifiAwareSubscribe(id, config, True)
377            autils.wait_for_event(
378                dut,
379                autils.decorate_event(aconsts.SESSION_CB_ON_SUBSCRIBE_STARTED,
380                                      disc_id))
381
382        # Wait for session termination & verify
383        self.verify_discovery_session_term(dut, disc_id, config, is_publish,
384                                           term_ind_on)
385
386        # Iteration 2: Start a discovery session without TTL
387        config = self.create_base_config(
388            dut.aware_capabilities, is_publish, ptype, stype,
389            self.PAYLOAD_SIZE_TYPICAL, 0, term_ind_on, False)
390        if is_publish:
391            disc_id = dut.droid.wifiAwarePublish(id, config, True)
392            autils.wait_for_event(
393                dut,
394                autils.decorate_event(aconsts.SESSION_CB_ON_PUBLISH_STARTED,
395                                      disc_id))
396        else:
397            disc_id = dut.droid.wifiAwareSubscribe(id, config, True)
398            autils.wait_for_event(
399                dut,
400                autils.decorate_event(aconsts.SESSION_CB_ON_SUBSCRIBE_STARTED,
401                                      disc_id))
402
403        # Update with a TTL
404        config = self.create_base_config(
405            dut.aware_capabilities, is_publish, ptype, stype,
406            self.PAYLOAD_SIZE_TYPICAL, SHORT_TTL, term_ind_on, False)
407        if is_publish:
408            dut.droid.wifiAwareUpdatePublish(disc_id, config)
409        else:
410            dut.droid.wifiAwareUpdateSubscribe(disc_id, config)
411        autils.wait_for_event(
412            dut,
413            autils.decorate_event(aconsts.SESSION_CB_ON_SESSION_CONFIG_UPDATED,
414                                  disc_id))
415
416        # Wait for session termination & verify
417        self.verify_discovery_session_term(dut, disc_id, config, is_publish,
418                                           term_ind_on)
419
420        # Iteration 3: Start a discovery session with (long) TTL
421        config = self.create_base_config(
422            dut.aware_capabilities, is_publish, ptype, stype,
423            self.PAYLOAD_SIZE_TYPICAL, LONG_TTL, term_ind_on, False)
424        if is_publish:
425            disc_id = dut.droid.wifiAwarePublish(id, config, True)
426            autils.wait_for_event(
427                dut,
428                autils.decorate_event(aconsts.SESSION_CB_ON_PUBLISH_STARTED,
429                                      disc_id))
430        else:
431            disc_id = dut.droid.wifiAwareSubscribe(id, config, True)
432            autils.wait_for_event(
433                dut,
434                autils.decorate_event(aconsts.SESSION_CB_ON_SUBSCRIBE_STARTED,
435                                      disc_id))
436
437        # Update with a TTL
438        config = self.create_base_config(
439            dut.aware_capabilities, is_publish, ptype, stype,
440            self.PAYLOAD_SIZE_TYPICAL, SHORT_TTL, term_ind_on, False)
441        if is_publish:
442            dut.droid.wifiAwareUpdatePublish(disc_id, config)
443        else:
444            dut.droid.wifiAwareUpdateSubscribe(disc_id, config)
445        autils.wait_for_event(
446            dut,
447            autils.decorate_event(aconsts.SESSION_CB_ON_SESSION_CONFIG_UPDATED,
448                                  disc_id))
449
450        # Wait for session termination & verify
451        self.verify_discovery_session_term(dut, disc_id, config, is_publish,
452                                           term_ind_on)
453
454        # verify that there were no other events
455        autils.verify_no_more_events(dut)
456
457        # verify that forbidden callbacks aren't called
458        if not term_ind_on:
459            autils.validate_forbidden_callbacks(
460                dut, {
461                    aconsts.CB_EV_PUBLISH_TERMINATED: 0,
462                    aconsts.CB_EV_SUBSCRIBE_TERMINATED: 0
463                })
464
465    def discovery_mismatch_test_utility(self,
466                                        is_expected_to_pass,
467                                        p_type,
468                                        s_type,
469                                        p_service_name=None,
470                                        s_service_name=None,
471                                        p_mf_1=None,
472                                        s_mf_1=None):
473        """Utility which runs the negative discovery test for mismatched service
474    configs.
475
476    Args:
477      is_expected_to_pass: True if positive test, False if negative
478      p_type: Publish discovery type
479      s_type: Subscribe discovery type
480      p_service_name: Publish service name (or None to leave unchanged)
481      s_service_name: Subscribe service name (or None to leave unchanged)
482      p_mf_1: Publish match filter element [1] (or None to leave unchanged)
483      s_mf_1: Subscribe match filter element [1] (or None to leave unchanged)
484    """
485        p_dut = self.android_devices[0]
486        p_dut.pretty_name = "Publisher"
487        s_dut = self.android_devices[1]
488        s_dut.pretty_name = "Subscriber"
489
490        # create configurations
491        p_config = self.create_publish_config(
492            p_dut.aware_capabilities,
493            p_type,
494            self.PAYLOAD_SIZE_TYPICAL,
495            ttl=0,
496            term_ind_on=False,
497            null_match=False)
498        if p_service_name is not None:
499            p_config[aconsts.DISCOVERY_KEY_SERVICE_NAME] = p_service_name
500        if p_mf_1 is not None:
501            p_config[
502                aconsts.DISCOVERY_KEY_MATCH_FILTER_LIST] = autils.encode_list(
503                    [(10).to_bytes(1, byteorder="big"), p_mf_1,
504                     bytes(range(40))])
505        s_config = self.create_publish_config(
506            s_dut.aware_capabilities,
507            s_type,
508            self.PAYLOAD_SIZE_TYPICAL,
509            ttl=0,
510            term_ind_on=False,
511            null_match=False)
512        if s_service_name is not None:
513            s_config[aconsts.DISCOVERY_KEY_SERVICE_NAME] = s_service_name
514        if s_mf_1 is not None:
515            s_config[
516                aconsts.DISCOVERY_KEY_MATCH_FILTER_LIST] = autils.encode_list(
517                    [(10).to_bytes(1, byteorder="big"), s_mf_1,
518                     bytes(range(40))])
519
520        p_id = p_dut.droid.wifiAwareAttach(False)
521        autils.wait_for_event(p_dut, aconsts.EVENT_CB_ON_ATTACHED)
522        time.sleep(self.device_startup_offset)
523        s_id = s_dut.droid.wifiAwareAttach(False)
524        autils.wait_for_event(s_dut, aconsts.EVENT_CB_ON_ATTACHED)
525
526        # Publisher: start publish and wait for confirmation
527        p_disc_id = p_dut.droid.wifiAwarePublish(p_id, p_config)
528        autils.wait_for_event(p_dut, aconsts.SESSION_CB_ON_PUBLISH_STARTED)
529
530        # Subscriber: start subscribe and wait for confirmation
531        s_disc_id = s_dut.droid.wifiAwareSubscribe(s_id, s_config)
532        autils.wait_for_event(s_dut, aconsts.SESSION_CB_ON_SUBSCRIBE_STARTED)
533
534        # Subscriber: fail on service discovery
535        if is_expected_to_pass:
536            autils.wait_for_event(s_dut,
537                                  aconsts.SESSION_CB_ON_SERVICE_DISCOVERED)
538        else:
539            autils.fail_on_event(s_dut,
540                                 aconsts.SESSION_CB_ON_SERVICE_DISCOVERED)
541
542        # Publisher+Subscriber: Terminate sessions
543        p_dut.droid.wifiAwareDestroyDiscoverySession(p_disc_id)
544        s_dut.droid.wifiAwareDestroyDiscoverySession(s_disc_id)
545
546        # verify that there were no other events (including terminations)
547        time.sleep(autils.EVENT_TIMEOUT)
548        autils.verify_no_more_events(p_dut, timeout=0)
549        autils.verify_no_more_events(s_dut, timeout=0)
550
551    #######################################
552    # Positive tests key:
553    #
554    # names is: test_<pub_type>_<sub_type>_<size>
555    # where:
556    #
557    # pub_type: Type of publish discovery session: unsolicited or solicited.
558    # sub_type: Type of subscribe discovery session: passive or active.
559    # size: Size of payload fields (service name, service specific info, and match
560    # filter: typical, max, or min.
561    #######################################
562
563    @test_tracker_info(uuid="954ebbde-ed2b-4f04-9e68-88239187d69d")
564    def test_positive_unsolicited_passive_typical(self):
565        """Functional test case / Discovery test cases / positive test case:
566    - Solicited publish + passive subscribe
567    - Typical payload fields size
568
569    Verifies that discovery and message exchange succeeds.
570    """
571        self.positive_discovery_test_utility(
572            ptype=aconsts.PUBLISH_TYPE_UNSOLICITED,
573            stype=aconsts.SUBSCRIBE_TYPE_PASSIVE,
574            payload_size=self.PAYLOAD_SIZE_TYPICAL)
575
576    @test_tracker_info(uuid="67fb22bb-6985-4345-95a4-90b76681a58b")
577    def test_positive_unsolicited_passive_min(self):
578        """Functional test case / Discovery test cases / positive test case:
579    - Solicited publish + passive subscribe
580    - Minimal payload fields size
581
582    Verifies that discovery and message exchange succeeds.
583    """
584        self.positive_discovery_test_utility(
585            ptype=aconsts.PUBLISH_TYPE_UNSOLICITED,
586            stype=aconsts.SUBSCRIBE_TYPE_PASSIVE,
587            payload_size=self.PAYLOAD_SIZE_MIN)
588
589    @test_tracker_info(uuid="a02a47b9-41bb-47bb-883b-921024a2c30d")
590    def test_positive_unsolicited_passive_max(self):
591        """Functional test case / Discovery test cases / positive test case:
592    - Solicited publish + passive subscribe
593    - Maximal payload fields size
594
595    Verifies that discovery and message exchange succeeds.
596    """
597        self.positive_discovery_test_utility(
598            ptype=aconsts.PUBLISH_TYPE_UNSOLICITED,
599            stype=aconsts.SUBSCRIBE_TYPE_PASSIVE,
600            payload_size=self.PAYLOAD_SIZE_MAX)
601
602    @test_tracker_info(uuid="586c657f-2388-4e7a-baee-9bce2f3d1a16")
603    def test_positive_solicited_active_typical(self):
604        """Functional test case / Discovery test cases / positive test case:
605    - Unsolicited publish + active subscribe
606    - Typical payload fields size
607
608    Verifies that discovery and message exchange succeeds.
609    """
610        self.positive_discovery_test_utility(
611            ptype=aconsts.PUBLISH_TYPE_SOLICITED,
612            stype=aconsts.SUBSCRIBE_TYPE_ACTIVE,
613            payload_size=self.PAYLOAD_SIZE_TYPICAL)
614
615    @test_tracker_info(uuid="5369e4ff-f406-48c5-b41a-df38ec340146")
616    def test_positive_solicited_active_min(self):
617        """Functional test case / Discovery test cases / positive test case:
618    - Unsolicited publish + active subscribe
619    - Minimal payload fields size
620
621    Verifies that discovery and message exchange succeeds.
622    """
623        self.positive_discovery_test_utility(
624            ptype=aconsts.PUBLISH_TYPE_SOLICITED,
625            stype=aconsts.SUBSCRIBE_TYPE_ACTIVE,
626            payload_size=self.PAYLOAD_SIZE_MIN)
627
628    @test_tracker_info(uuid="634c6eb8-2c4f-42bd-9bbb-d874d0ec22f3")
629    def test_positive_solicited_active_max(self):
630        """Functional test case / Discovery test cases / positive test case:
631    - Unsolicited publish + active subscribe
632    - Maximal payload fields size
633
634    Verifies that discovery and message exchange succeeds.
635    """
636        self.positive_discovery_test_utility(
637            ptype=aconsts.PUBLISH_TYPE_SOLICITED,
638            stype=aconsts.SUBSCRIBE_TYPE_ACTIVE,
639            payload_size=self.PAYLOAD_SIZE_MAX)
640
641    #######################################
642    # TTL tests key:
643    #
644    # names is: test_ttl_<pub_type|sub_type>_<term_ind>
645    # where:
646    #
647    # pub_type: Type of publish discovery session: unsolicited or solicited.
648    # sub_type: Type of subscribe discovery session: passive or active.
649    # term_ind: ind_on or ind_off
650    #######################################
651
652    @test_tracker_info(uuid="9d7e758e-e0e2-4550-bcee-bfb6a2bff63e")
653    def test_ttl_unsolicited_ind_on(self):
654        """Functional test case / Discovery test cases / TTL test case:
655    - Unsolicited publish
656    - Termination indication enabled
657    """
658        self.positive_ttl_test_utility(
659            is_publish=True,
660            ptype=aconsts.PUBLISH_TYPE_UNSOLICITED,
661            stype=None,
662            term_ind_on=True)
663
664    @test_tracker_info(uuid="48fd69bc-cc2a-4f65-a0a1-63d7c1720702")
665    def test_ttl_unsolicited_ind_off(self):
666        """Functional test case / Discovery test cases / TTL test case:
667    - Unsolicited publish
668    - Termination indication disabled
669    """
670        self.positive_ttl_test_utility(
671            is_publish=True,
672            ptype=aconsts.PUBLISH_TYPE_UNSOLICITED,
673            stype=None,
674            term_ind_on=False)
675
676    @test_tracker_info(uuid="afb75fc1-9ba7-446a-b5ed-7cd37ab51b1c")
677    def test_ttl_solicited_ind_on(self):
678        """Functional test case / Discovery test cases / TTL test case:
679    - Solicited publish
680    - Termination indication enabled
681    """
682        self.positive_ttl_test_utility(
683            is_publish=True,
684            ptype=aconsts.PUBLISH_TYPE_SOLICITED,
685            stype=None,
686            term_ind_on=True)
687
688    @test_tracker_info(uuid="703311a6-e444-4055-94ee-ea9b9b71799e")
689    def test_ttl_solicited_ind_off(self):
690        """Functional test case / Discovery test cases / TTL test case:
691    - Solicited publish
692    - Termination indication disabled
693    """
694        self.positive_ttl_test_utility(
695            is_publish=True,
696            ptype=aconsts.PUBLISH_TYPE_SOLICITED,
697            stype=None,
698            term_ind_on=False)
699
700    @test_tracker_info(uuid="38a541c4-ff55-4387-87b7-4d940489da9d")
701    def test_ttl_passive_ind_on(self):
702        """Functional test case / Discovery test cases / TTL test case:
703    - Passive subscribe
704    - Termination indication enabled
705    """
706        self.positive_ttl_test_utility(
707            is_publish=False,
708            ptype=None,
709            stype=aconsts.SUBSCRIBE_TYPE_PASSIVE,
710            term_ind_on=True)
711
712    @test_tracker_info(uuid="ba971e12-b0ca-417c-a1b5-9451598de47d")
713    def test_ttl_passive_ind_off(self):
714        """Functional test case / Discovery test cases / TTL test case:
715    - Passive subscribe
716    - Termination indication disabled
717    """
718        self.positive_ttl_test_utility(
719            is_publish=False,
720            ptype=None,
721            stype=aconsts.SUBSCRIBE_TYPE_PASSIVE,
722            term_ind_on=False)
723
724    @test_tracker_info(uuid="7b5d96f2-2415-4b98-9a51-32957f0679a0")
725    def test_ttl_active_ind_on(self):
726        """Functional test case / Discovery test cases / TTL test case:
727    - Active subscribe
728    - Termination indication enabled
729    """
730        self.positive_ttl_test_utility(
731            is_publish=False,
732            ptype=None,
733            stype=aconsts.SUBSCRIBE_TYPE_ACTIVE,
734            term_ind_on=True)
735
736    @test_tracker_info(uuid="c9268eca-0a30-42dd-8e6c-b8b0b84697fb")
737    def test_ttl_active_ind_off(self):
738        """Functional test case / Discovery test cases / TTL test case:
739    - Active subscribe
740    - Termination indication disabled
741    """
742        self.positive_ttl_test_utility(
743            is_publish=False,
744            ptype=None,
745            stype=aconsts.SUBSCRIBE_TYPE_ACTIVE,
746            term_ind_on=False)
747
748    #######################################
749    # Mismatched service name tests key:
750    #
751    # names is: test_mismatch_service_name_<pub_type>_<sub_type>
752    # where:
753    #
754    # pub_type: Type of publish discovery session: unsolicited or solicited.
755    # sub_type: Type of subscribe discovery session: passive or active.
756    #######################################
757
758    @test_tracker_info(uuid="175415e9-7d07-40d0-95f0-3a5f91ea4711")
759    def test_mismatch_service_name_unsolicited_passive(self):
760        """Functional test case / Discovery test cases / Mismatch service name
761    - Unsolicited publish
762    - Passive subscribe
763    """
764        self.discovery_mismatch_test_utility(
765            is_expected_to_pass=False,
766            p_type=aconsts.PUBLISH_TYPE_UNSOLICITED,
767            s_type=aconsts.SUBSCRIBE_TYPE_PASSIVE,
768            p_service_name="GoogleTestServiceXXX",
769            s_service_name="GoogleTestServiceYYY")
770
771    @test_tracker_info(uuid="c22a54ce-9e46-47a5-ac44-831faf93d317")
772    def test_mismatch_service_name_solicited_active(self):
773        """Functional test case / Discovery test cases / Mismatch service name
774    - Solicited publish
775    - Active subscribe
776    """
777        self.discovery_mismatch_test_utility(
778            is_expected_to_pass=False,
779            p_type=aconsts.PUBLISH_TYPE_SOLICITED,
780            s_type=aconsts.SUBSCRIBE_TYPE_ACTIVE,
781            p_service_name="GoogleTestServiceXXX",
782            s_service_name="GoogleTestServiceYYY")
783
784    #######################################
785    # Mismatched discovery session type tests key:
786    #
787    # names is: test_mismatch_service_type_<pub_type>_<sub_type>
788    # where:
789    #
790    # pub_type: Type of publish discovery session: unsolicited or solicited.
791    # sub_type: Type of subscribe discovery session: passive or active.
792    #######################################
793
794    @test_tracker_info(uuid="4806f631-d9eb-45fd-9e75-24674962770f")
795    def test_mismatch_service_type_unsolicited_active(self):
796        """Functional test case / Discovery test cases / Mismatch service name
797    - Unsolicited publish
798    - Active subscribe
799    """
800        self.discovery_mismatch_test_utility(
801            is_expected_to_pass=True,
802            p_type=aconsts.PUBLISH_TYPE_UNSOLICITED,
803            s_type=aconsts.SUBSCRIBE_TYPE_ACTIVE)
804
805    @test_tracker_info(uuid="12d648fd-b8fa-4c0f-9467-95e2366047de")
806    def test_mismatch_service_type_solicited_passive(self):
807        """Functional test case / Discovery test cases / Mismatch service name
808    - Unsolicited publish
809    - Active subscribe
810    """
811        self.discovery_mismatch_test_utility(
812            is_expected_to_pass=False,
813            p_type=aconsts.PUBLISH_TYPE_SOLICITED,
814            s_type=aconsts.SUBSCRIBE_TYPE_PASSIVE)
815
816    #######################################
817    # Mismatched discovery match filter tests key:
818    #
819    # names is: test_mismatch_match_filter_<pub_type>_<sub_type>
820    # where:
821    #
822    # pub_type: Type of publish discovery session: unsolicited or solicited.
823    # sub_type: Type of subscribe discovery session: passive or active.
824    #######################################
825
826    @test_tracker_info(uuid="d98454cb-64af-4266-8fed-f0b545a2d7c4")
827    def test_mismatch_match_filter_unsolicited_passive(self):
828        """Functional test case / Discovery test cases / Mismatch match filter
829    - Unsolicited publish
830    - Passive subscribe
831    """
832        self.discovery_mismatch_test_utility(
833            is_expected_to_pass=False,
834            p_type=aconsts.PUBLISH_TYPE_UNSOLICITED,
835            s_type=aconsts.SUBSCRIBE_TYPE_PASSIVE,
836            p_mf_1="hello there string",
837            s_mf_1="goodbye there string")
838
839    @test_tracker_info(uuid="663c1008-ae11-4e1a-87c7-c311d83f481c")
840    def test_mismatch_match_filter_solicited_active(self):
841        """Functional test case / Discovery test cases / Mismatch match filter
842    - Solicited publish
843    - Active subscribe
844    """
845        self.discovery_mismatch_test_utility(
846            is_expected_to_pass=False,
847            p_type=aconsts.PUBLISH_TYPE_SOLICITED,
848            s_type=aconsts.SUBSCRIBE_TYPE_ACTIVE,
849            p_mf_1="hello there string",
850            s_mf_1="goodbye there string")
851
852    #######################################
853    # Multiple concurrent services
854    #######################################
855
856    def run_multiple_concurrent_services(self, type_x, type_y):
857        """Validate multiple identical discovery services running on both devices:
858    - DUT1 & DUT2 running Publish for X
859    - DUT1 & DUT2 running Publish for Y
860    - DUT1 Subscribes for X
861    - DUT2 Subscribes for Y
862    Message exchanges.
863
864    Note: test requires that devices support 2 publish sessions concurrently.
865    The test will be skipped if the devices are not capable.
866
867    Args:
868      type_x, type_y: A list of [ptype, stype] of the publish and subscribe
869                      types for services X and Y respectively.
870    """
871        dut1 = self.android_devices[0]
872        dut2 = self.android_devices[1]
873
874        X_SERVICE_NAME = "ServiceXXX"
875        Y_SERVICE_NAME = "ServiceYYY"
876
877        asserts.skip_if(
878            dut1.aware_capabilities[aconsts.CAP_MAX_PUBLISHES] < 2
879            or dut2.aware_capabilities[aconsts.CAP_MAX_PUBLISHES] < 2,
880            "Devices do not support 2 publish sessions")
881
882        # attach and wait for confirmation
883        id1 = dut1.droid.wifiAwareAttach(False)
884        autils.wait_for_event(dut1, aconsts.EVENT_CB_ON_ATTACHED)
885        time.sleep(self.device_startup_offset)
886        id2 = dut2.droid.wifiAwareAttach(False)
887        autils.wait_for_event(dut2, aconsts.EVENT_CB_ON_ATTACHED)
888
889        # DUT1 & DUT2: start publishing both X & Y services and wait for
890        # confirmations
891        dut1_x_pid = dut1.droid.wifiAwarePublish(
892            id1, autils.create_discovery_config(X_SERVICE_NAME, type_x[0]))
893        event = autils.wait_for_event(dut1,
894                                      aconsts.SESSION_CB_ON_PUBLISH_STARTED)
895        asserts.assert_equal(event["data"][aconsts.SESSION_CB_KEY_SESSION_ID],
896                             dut1_x_pid,
897                             "Unexpected DUT1 X publish session discovery ID")
898
899        dut1_y_pid = dut1.droid.wifiAwarePublish(
900            id1, autils.create_discovery_config(Y_SERVICE_NAME, type_y[0]))
901        event = autils.wait_for_event(dut1,
902                                      aconsts.SESSION_CB_ON_PUBLISH_STARTED)
903        asserts.assert_equal(event["data"][aconsts.SESSION_CB_KEY_SESSION_ID],
904                             dut1_y_pid,
905                             "Unexpected DUT1 Y publish session discovery ID")
906
907        dut2_x_pid = dut2.droid.wifiAwarePublish(
908            id2, autils.create_discovery_config(X_SERVICE_NAME, type_x[0]))
909        event = autils.wait_for_event(dut2,
910                                      aconsts.SESSION_CB_ON_PUBLISH_STARTED)
911        asserts.assert_equal(event["data"][aconsts.SESSION_CB_KEY_SESSION_ID],
912                             dut2_x_pid,
913                             "Unexpected DUT2 X publish session discovery ID")
914
915        dut2_y_pid = dut2.droid.wifiAwarePublish(
916            id2, autils.create_discovery_config(Y_SERVICE_NAME, type_y[0]))
917        event = autils.wait_for_event(dut2,
918                                      aconsts.SESSION_CB_ON_PUBLISH_STARTED)
919        asserts.assert_equal(event["data"][aconsts.SESSION_CB_KEY_SESSION_ID],
920                             dut2_y_pid,
921                             "Unexpected DUT2 Y publish session discovery ID")
922
923        # DUT1: start subscribing for X
924        dut1_x_sid = dut1.droid.wifiAwareSubscribe(
925            id1, autils.create_discovery_config(X_SERVICE_NAME, type_x[1]))
926        autils.wait_for_event(dut1, aconsts.SESSION_CB_ON_SUBSCRIBE_STARTED)
927
928        # DUT2: start subscribing for Y
929        dut2_y_sid = dut2.droid.wifiAwareSubscribe(
930            id2, autils.create_discovery_config(Y_SERVICE_NAME, type_y[1]))
931        autils.wait_for_event(dut2, aconsts.SESSION_CB_ON_SUBSCRIBE_STARTED)
932
933        # DUT1 & DUT2: wait for service discovery
934        event = autils.wait_for_event(dut1,
935                                      aconsts.SESSION_CB_ON_SERVICE_DISCOVERED)
936        asserts.assert_equal(
937            event["data"][aconsts.SESSION_CB_KEY_SESSION_ID], dut1_x_sid,
938            "Unexpected DUT1 X subscribe session discovery ID")
939        dut1_peer_id_for_dut2_x = event["data"][aconsts.SESSION_CB_KEY_PEER_ID]
940
941        event = autils.wait_for_event(dut2,
942                                      aconsts.SESSION_CB_ON_SERVICE_DISCOVERED)
943        asserts.assert_equal(
944            event["data"][aconsts.SESSION_CB_KEY_SESSION_ID], dut2_y_sid,
945            "Unexpected DUT2 Y subscribe session discovery ID")
946        dut2_peer_id_for_dut1_y = event["data"][aconsts.SESSION_CB_KEY_PEER_ID]
947
948        # DUT1.X send message to DUT2
949        x_msg = "Hello X on DUT2!"
950        dut1.droid.wifiAwareSendMessage(dut1_x_sid, dut1_peer_id_for_dut2_x,
951                                        self.get_next_msg_id(), x_msg,
952                                        self.msg_retx_count)
953        autils.wait_for_event(dut1, aconsts.SESSION_CB_ON_MESSAGE_SENT)
954        event = autils.wait_for_event(dut2,
955                                      aconsts.SESSION_CB_ON_MESSAGE_RECEIVED)
956        asserts.assert_equal(
957            event["data"][aconsts.SESSION_CB_KEY_SESSION_ID], dut2_x_pid,
958            "Unexpected publish session ID on DUT2 for meesage "
959            "received on service X")
960        asserts.assert_equal(
961            event["data"][aconsts.SESSION_CB_KEY_MESSAGE_AS_STRING], x_msg,
962            "Message on service X from DUT1 to DUT2 not received correctly")
963
964        # DUT2.Y send message to DUT1
965        y_msg = "Hello Y on DUT1!"
966        dut2.droid.wifiAwareSendMessage(dut2_y_sid, dut2_peer_id_for_dut1_y,
967                                        self.get_next_msg_id(), y_msg,
968                                        self.msg_retx_count)
969        autils.wait_for_event(dut2, aconsts.SESSION_CB_ON_MESSAGE_SENT)
970        event = autils.wait_for_event(dut1,
971                                      aconsts.SESSION_CB_ON_MESSAGE_RECEIVED)
972        asserts.assert_equal(
973            event["data"][aconsts.SESSION_CB_KEY_SESSION_ID], dut1_y_pid,
974            "Unexpected publish session ID on DUT1 for meesage "
975            "received on service Y")
976        asserts.assert_equal(
977            event["data"][aconsts.SESSION_CB_KEY_MESSAGE_AS_STRING], y_msg,
978            "Message on service Y from DUT2 to DUT1 not received correctly")
979
980    @test_tracker_info(uuid="eef80cf3-1fd2-4526-969b-6af2dce785d7")
981    def test_multiple_concurrent_services_both_unsolicited_passive(self):
982        """Validate multiple concurrent discovery sessions running on both devices.
983    - DUT1 & DUT2 running Publish for X
984    - DUT1 & DUT2 running Publish for Y
985    - DUT1 Subscribes for X
986    - DUT2 Subscribes for Y
987    Message exchanges.
988
989    Both sessions are Unsolicited/Passive.
990
991    Note: test requires that devices support 2 publish sessions concurrently.
992    The test will be skipped if the devices are not capable.
993    """
994        self.run_multiple_concurrent_services(
995            type_x=[
996                aconsts.PUBLISH_TYPE_UNSOLICITED,
997                aconsts.SUBSCRIBE_TYPE_PASSIVE
998            ],
999            type_y=[
1000                aconsts.PUBLISH_TYPE_UNSOLICITED,
1001                aconsts.SUBSCRIBE_TYPE_PASSIVE
1002            ])
1003
1004    @test_tracker_info(uuid="46739f04-ab2b-4556-b1a4-9aa2774869b5")
1005    def test_multiple_concurrent_services_both_solicited_active(self):
1006        """Validate multiple concurrent discovery sessions running on both devices.
1007    - DUT1 & DUT2 running Publish for X
1008    - DUT1 & DUT2 running Publish for Y
1009    - DUT1 Subscribes for X
1010    - DUT2 Subscribes for Y
1011    Message exchanges.
1012
1013    Both sessions are Solicited/Active.
1014
1015    Note: test requires that devices support 2 publish sessions concurrently.
1016    The test will be skipped if the devices are not capable.
1017    """
1018        self.run_multiple_concurrent_services(
1019            type_x=[
1020                aconsts.PUBLISH_TYPE_SOLICITED, aconsts.SUBSCRIBE_TYPE_ACTIVE
1021            ],
1022            type_y=[
1023                aconsts.PUBLISH_TYPE_SOLICITED, aconsts.SUBSCRIBE_TYPE_ACTIVE
1024            ])
1025
1026    @test_tracker_info(uuid="5f8f7fd2-4a0e-4cca-8cbb-6d54353f2baa")
1027    def test_multiple_concurrent_services_mix_unsolicited_solicited(self):
1028        """Validate multiple concurrent discovery sessions running on both devices.
1029    - DUT1 & DUT2 running Publish for X
1030    - DUT1 & DUT2 running Publish for Y
1031    - DUT1 Subscribes for X
1032    - DUT2 Subscribes for Y
1033    Message exchanges.
1034
1035    Session A is Unsolicited/Passive.
1036    Session B is Solicited/Active.
1037
1038    Note: test requires that devices support 2 publish sessions concurrently.
1039    The test will be skipped if the devices are not capable.
1040    """
1041        self.run_multiple_concurrent_services(
1042            type_x=[
1043                aconsts.PUBLISH_TYPE_UNSOLICITED,
1044                aconsts.SUBSCRIBE_TYPE_PASSIVE
1045            ],
1046            type_y=[
1047                aconsts.PUBLISH_TYPE_SOLICITED, aconsts.SUBSCRIBE_TYPE_ACTIVE
1048            ])
1049
1050    #########################################################
1051
1052    @test_tracker_info(uuid="908ec896-fc7a-4ee4-b633-a2f042b74448")
1053    def test_upper_lower_service_name_equivalence(self):
1054        """Validate that Service Name is case-insensitive. Publish a service name
1055    with mixed case, subscribe to the same service name with alternative case
1056    and verify that discovery happens."""
1057        p_dut = self.android_devices[0]
1058        s_dut = self.android_devices[1]
1059
1060        pub_service_name = "GoogleAbCdEf"
1061        sub_service_name = "GoogleaBcDeF"
1062
1063        autils.create_discovery_pair(
1064            p_dut,
1065            s_dut,
1066            p_config=autils.create_discovery_config(
1067                pub_service_name, aconsts.PUBLISH_TYPE_UNSOLICITED),
1068            s_config=autils.create_discovery_config(
1069                sub_service_name, aconsts.SUBSCRIBE_TYPE_PASSIVE),
1070            device_startup_offset=self.device_startup_offset)
1071