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