1#!/usr/bin/python3.4
2#
3#   Copyright 2017 - The Android Open Source Project
4#
5#   Licensed under the Apache License, Version 2.0 (the "License");
6#   you may not use this file except in compliance with the License.
7#   You may obtain a copy of the License at
8#
9#       http://www.apache.org/licenses/LICENSE-2.0
10#
11#   Unless required by applicable law or agreed to in writing, software
12#   distributed under the License is distributed on an "AS IS" BASIS,
13#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14#   See the License for the specific language governing permissions and
15#   limitations under the License.
16
17import queue
18import threading
19
20from acts import asserts
21from acts.test_utils.wifi import wifi_constants as wconsts
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 InfraAssociationStressTest(AwareBaseTest):
28
29  def __init__(self, controllers):
30    AwareBaseTest.__init__(self, controllers)
31
32  # Length of test in seconds
33  TEST_DURATION_SECONDS = 300
34
35  # Service name
36  SERVICE_NAME = "GoogleTestServiceXYXYXY"
37
38  def is_associated(self, dut):
39    """Checks whether the device is associated (to any AP).
40
41    Args:
42      dut: Device under test.
43
44    Returns: True if associated (to any AP), False otherwise.
45    """
46    info = dut.droid.wifiGetConnectionInfo()
47    return info is not None and info["supplicant_state"] != "disconnected"
48
49  def wait_for_disassociation(self, q, dut):
50    """Waits for a disassociation event on the specified DUT for the given
51    timeout. Place a result into the queue (False) only if disassociation
52    observed.
53
54    Args:
55      q: The synchronization queue into which to place the results.
56      dut: The device to track.
57    """
58    try:
59      dut.ed.pop_event(wconsts.WIFI_DISCONNECTED, self.TEST_DURATION_SECONDS)
60      q.put(True)
61    except queue.Empty:
62      pass
63
64  def run_infra_assoc_oob_ndp_stress(self, with_ndp_traffic):
65    """Validates that Wi-Fi Aware NDP does not interfere with infrastructure
66    (AP) association.
67
68    Test assumes (and verifies) that device is already associated to an AP.
69
70    Args:
71      with_ndp_traffic: True to run traffic over the NDP.
72    """
73    init_dut = self.android_devices[0]
74    resp_dut = self.android_devices[1]
75
76    # check that associated and start tracking
77    init_dut.droid.wifiStartTrackingStateChange()
78    resp_dut.droid.wifiStartTrackingStateChange()
79    asserts.assert_true(
80        self.is_associated(init_dut), "DUT is not associated to an AP!")
81    asserts.assert_true(
82        self.is_associated(resp_dut), "DUT is not associated to an AP!")
83
84    # set up NDP
85    (init_req_key, resp_req_key, init_aware_if, resp_aware_if, init_ipv6,
86     resp_ipv6) = autils.create_oob_ndp(init_dut, resp_dut)
87    self.log.info("Interface names: I=%s, R=%s", init_aware_if, resp_aware_if)
88    self.log.info("Interface addresses (IPv6): I=%s, R=%s", init_ipv6,
89                  resp_ipv6)
90
91    # wait for any disassociation change events
92    q = queue.Queue()
93    init_thread = threading.Thread(
94        target=self.wait_for_disassociation, args=(q, init_dut))
95    resp_thread = threading.Thread(
96        target=self.wait_for_disassociation, args=(q, resp_dut))
97
98    init_thread.start()
99    resp_thread.start()
100
101    any_disassociations = False
102    try:
103      q.get(True, self.TEST_DURATION_SECONDS)
104      any_disassociations = True  # only happens on any disassociation
105    except queue.Empty:
106      pass
107    finally:
108      # TODO: no way to terminate thread (so even if we fast fail we still have
109      # to wait for the full timeout.
110      init_dut.droid.wifiStopTrackingStateChange()
111      resp_dut.droid.wifiStopTrackingStateChange()
112
113    asserts.assert_false(any_disassociations,
114                         "Wi-Fi disassociated during test run")
115
116  ################################################################
117
118  def test_infra_assoc_discovery_stress(self):
119    """Validates that Wi-Fi Aware discovery does not interfere with
120    infrastructure (AP) association.
121
122    Test assumes (and verifies) that device is already associated to an AP.
123    """
124    dut = self.android_devices[0]
125
126    # check that associated and start tracking
127    dut.droid.wifiStartTrackingStateChange()
128    asserts.assert_true(
129        self.is_associated(dut), "DUT is not associated to an AP!")
130
131    # attach
132    session_id = dut.droid.wifiAwareAttach(True)
133    autils.wait_for_event(dut, aconsts.EVENT_CB_ON_ATTACHED)
134
135    # publish
136    p_disc_id = dut.droid.wifiAwarePublish(
137        session_id,
138        autils.create_discovery_config(self.SERVICE_NAME,
139                                       aconsts.PUBLISH_TYPE_UNSOLICITED))
140    autils.wait_for_event(dut, aconsts.SESSION_CB_ON_PUBLISH_STARTED)
141
142    # wait for any disassociation change events
143    any_disassociations = False
144    try:
145      dut.ed.pop_event(wconsts.WIFI_DISCONNECTED, self.TEST_DURATION_SECONDS)
146      any_disassociations = True
147    except queue.Empty:
148      pass
149    finally:
150      dut.droid.wifiStopTrackingStateChange()
151
152    asserts.assert_false(any_disassociations,
153                         "Wi-Fi disassociated during test run")
154
155  def test_infra_assoc_ndp_no_traffic_stress(self):
156    """Validates that Wi-Fi Aware NDP (with no traffic) does not interfere with
157    infrastructure (AP) association.
158
159    Test assumes (and verifies) that devices are already associated to an AP.
160    """
161    self.run_infra_assoc_oob_ndp_stress(with_ndp_traffic=False)
162