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 time 19 20from acts import asserts 21from acts.test_decorators import test_tracker_info 22from acts.test_utils.net import connectivity_const as cconsts 23from acts.test_utils.wifi.aware import aware_const as aconsts 24from acts.test_utils.wifi.aware import aware_test_utils as autils 25from acts.test_utils.wifi.aware.AwareBaseTest import AwareBaseTest 26 27 28class DataPathStressTest(AwareBaseTest): 29 30 # Number of iterations on create/destroy Attach sessions. 31 ATTACH_ITERATIONS = 2 32 33 # Number of iterations on create/destroy NDP in each discovery session. 34 NDP_ITERATIONS = 50 35 36 # Maximum percentage of NDP setup failures over all iterations 37 MAX_FAILURE_PERCENTAGE = 1 38 39 ################################################################ 40 41 def run_oob_ndp_stress(self, 42 attach_iterations, 43 ndp_iterations, 44 trigger_failure_on_index=None): 45 """Run NDP (NAN data-path) stress test creating and destroying Aware 46 attach sessions, discovery sessions, and NDPs. 47 48 Args: 49 attach_iterations: Number of attach sessions. 50 ndp_iterations: Number of NDP to be attempted per attach session. 51 trigger_failure_on_index: Trigger a failure on this NDP iteration (the 52 mechanism is to request NDP on Initiator 53 before issuing the requeest on the Responder). 54 If None then no artificial failure triggered. 55 """ 56 init_dut = self.android_devices[0] 57 init_dut.pretty_name = 'Initiator' 58 resp_dut = self.android_devices[1] 59 resp_dut.pretty_name = 'Responder' 60 61 ndp_init_setup_success = 0 62 ndp_init_setup_failures = 0 63 ndp_resp_setup_success = 0 64 ndp_resp_setup_failures = 0 65 ndp_full_socket_success = 0 66 67 for attach_iter in range(attach_iterations): 68 init_id = init_dut.droid.wifiAwareAttach(True) 69 autils.wait_for_event(init_dut, aconsts.EVENT_CB_ON_ATTACHED) 70 init_ident_event = autils.wait_for_event( 71 init_dut, aconsts.EVENT_CB_ON_IDENTITY_CHANGED) 72 init_mac = init_ident_event['data']['mac'] 73 time.sleep(self.device_startup_offset) 74 resp_id = resp_dut.droid.wifiAwareAttach(True) 75 autils.wait_for_event(resp_dut, aconsts.EVENT_CB_ON_ATTACHED) 76 resp_ident_event = autils.wait_for_event( 77 resp_dut, aconsts.EVENT_CB_ON_IDENTITY_CHANGED) 78 resp_mac = resp_ident_event['data']['mac'] 79 80 # wait for for devices to synchronize with each other - there are no other 81 # mechanisms to make sure this happens for OOB discovery (except retrying 82 # to execute the data-path request) 83 time.sleep(autils.WAIT_FOR_CLUSTER) 84 85 for ndp_iteration in range(ndp_iterations): 86 if trigger_failure_on_index != ndp_iteration: 87 # Responder: request network 88 resp_req_key = autils.request_network( 89 resp_dut, 90 resp_dut.droid.wifiAwareCreateNetworkSpecifierOob( 91 resp_id, aconsts.DATA_PATH_RESPONDER, init_mac, 92 None)) 93 94 # Wait a minimal amount of time to let the Responder configure itself 95 # and be ready for the request. While calling it first may be 96 # sufficient there are no guarantees that a glitch may slow the 97 # Responder slightly enough to invert the setup order. 98 time.sleep(1) 99 100 # Initiator: request network 101 init_req_key = autils.request_network( 102 init_dut, 103 init_dut.droid.wifiAwareCreateNetworkSpecifierOob( 104 init_id, aconsts.DATA_PATH_INITIATOR, resp_mac, 105 None)) 106 else: 107 # Initiator: request network 108 init_req_key = autils.request_network( 109 init_dut, 110 init_dut.droid.wifiAwareCreateNetworkSpecifierOob( 111 init_id, aconsts.DATA_PATH_INITIATOR, resp_mac, 112 None)) 113 114 # Wait a minimal amount of time to let the Initiator configure itself 115 # to guarantee failure! 116 time.sleep(2) 117 118 # Responder: request network 119 resp_req_key = autils.request_network( 120 resp_dut, 121 resp_dut.droid.wifiAwareCreateNetworkSpecifierOob( 122 resp_id, aconsts.DATA_PATH_RESPONDER, init_mac, 123 None)) 124 125 init_ipv6 = None 126 resp_ipv6 = None 127 128 # Initiator: wait for network formation 129 got_on_available = False 130 got_on_link_props = False 131 got_on_net_cap = False 132 while not got_on_available or not got_on_link_props or not got_on_net_cap: 133 try: 134 nc_event = init_dut.ed.pop_event( 135 cconsts.EVENT_NETWORK_CALLBACK, 136 autils.EVENT_NDP_TIMEOUT) 137 if nc_event['data'][ 138 cconsts. 139 NETWORK_CB_KEY_EVENT] == cconsts.NETWORK_CB_AVAILABLE: 140 got_on_available = True 141 elif (nc_event['data'][cconsts.NETWORK_CB_KEY_EVENT] == 142 cconsts.NETWORK_CB_LINK_PROPERTIES_CHANGED): 143 got_on_link_props = True 144 elif (nc_event['data'][cconsts.NETWORK_CB_KEY_EVENT] == 145 cconsts.NETWORK_CB_CAPABILITIES_CHANGED): 146 got_on_net_cap = True 147 if aconsts.NET_CAP_IPV6 in nc_event["data"]: 148 resp_ipv6 = nc_event["data"][ 149 aconsts.NET_CAP_IPV6] 150 except queue.Empty: 151 ndp_init_setup_failures = ndp_init_setup_failures + 1 152 init_dut.log.info( 153 '[Initiator] Timed out while waiting for ' 154 'EVENT_NETWORK_CALLBACK') 155 break 156 157 if got_on_available and got_on_link_props and got_on_net_cap: 158 ndp_init_setup_success = ndp_init_setup_success + 1 159 160 # Responder: wait for network formation 161 got_on_available = False 162 got_on_link_props = False 163 got_on_net_cap = False 164 while not got_on_available or not got_on_link_props or not got_on_net_cap: 165 try: 166 nc_event = resp_dut.ed.pop_event( 167 cconsts.EVENT_NETWORK_CALLBACK, 168 autils.EVENT_NDP_TIMEOUT) 169 if nc_event['data'][ 170 cconsts. 171 NETWORK_CB_KEY_EVENT] == cconsts.NETWORK_CB_AVAILABLE: 172 got_on_available = True 173 elif (nc_event['data'][cconsts.NETWORK_CB_KEY_EVENT] == 174 cconsts.NETWORK_CB_LINK_PROPERTIES_CHANGED): 175 got_on_link_props = True 176 elif (nc_event['data'][cconsts.NETWORK_CB_KEY_EVENT] == 177 cconsts.NETWORK_CB_CAPABILITIES_CHANGED): 178 got_on_net_cap = True 179 if aconsts.NET_CAP_IPV6 in nc_event["data"]: 180 init_ipv6 = nc_event["data"][ 181 aconsts.NET_CAP_IPV6] 182 except queue.Empty: 183 ndp_resp_setup_failures = ndp_resp_setup_failures + 1 184 init_dut.log.info( 185 '[Responder] Timed out while waiting for ' 186 'EVENT_NETWORK_CALLBACK') 187 break 188 189 if got_on_available and got_on_link_props and got_on_net_cap: 190 ndp_resp_setup_success = ndp_resp_setup_success + 1 191 192 # open sockets to test connection 193 if autils.verify_socket_connect(init_dut, resp_dut, init_ipv6, 194 resp_ipv6, 0): 195 if autils.verify_socket_connect(resp_dut, init_dut, 196 resp_ipv6, init_ipv6, 0): 197 ndp_full_socket_success = ndp_full_socket_success + 1 198 199 # clean-up 200 init_dut.droid.connectivityUnregisterNetworkCallback( 201 init_req_key) 202 resp_dut.droid.connectivityUnregisterNetworkCallback( 203 resp_req_key) 204 205 # clean-up at end of iteration 206 init_dut.droid.wifiAwareDestroy(init_id) 207 resp_dut.droid.wifiAwareDestroy(resp_id) 208 209 results = {} 210 results['ndp_init_setup_success'] = ndp_init_setup_success 211 results['ndp_init_setup_failures'] = ndp_init_setup_failures 212 results['ndp_resp_setup_success'] = ndp_resp_setup_success 213 results['ndp_resp_setup_failures'] = ndp_resp_setup_failures 214 results['ndp_full_socket_success'] = ndp_full_socket_success 215 max_failures = (self.MAX_FAILURE_PERCENTAGE * attach_iterations * 216 ndp_iterations / 100) 217 if max_failures == 0: 218 max_failures = 1 219 if trigger_failure_on_index is not None: 220 max_failures = max_failures + 1 # for the triggered failure 221 asserts.assert_true( 222 (ndp_init_setup_failures + ndp_resp_setup_failures) < 223 (2 * max_failures), 224 'NDP setup failure rate exceeds threshold', 225 extras=results) 226 asserts.explicit_pass("test_oob_ndp_stress* done", extras=results) 227 228 @test_tracker_info(uuid="a20a96ba-e71f-4d31-b850-b88a75381981") 229 def test_oob_ndp_stress(self): 230 """Run NDP (NAN data-path) stress test creating and destroying Aware 231 attach sessions, discovery sessions, and NDPs.""" 232 self.run_oob_ndp_stress(self.ATTACH_ITERATIONS, self.NDP_ITERATIONS) 233 234 @test_tracker_info(uuid="1fb4a383-bf1a-411a-a904-489dd9e29c6a") 235 def test_oob_ndp_stress_failure_case(self): 236 """Run NDP (NAN data-path) stress test creating and destroying Aware 237 attach sessions, discovery sessions, and NDPs. 238 239 Verify recovery from failure by triggering an artifical failure and 240 verifying that all subsequent iterations succeed. 241 """ 242 self.run_oob_ndp_stress( 243 attach_iterations=1, ndp_iterations=10, trigger_failure_on_index=3) 244