1 # Copyright 2015 The Chromium OS Authors. All rights reserved. 2 # Use of this source code is governed by a BSD-style license that can be 3 # found in the LICENSE file. 4 import logging 5 import time 6 7 8 from autotest_lib.client.common_lib import error 9 from autotest_lib.client.common_lib.cros.network import ping_runner 10 from autotest_lib.client.common_lib.cros.network import xmlrpc_datatypes 11 from autotest_lib.client.cros.chameleon import chameleon_audio_helper 12 from autotest_lib.client.cros.chameleon import chameleon_audio_ids 13 from autotest_lib.server.cros.audio import audio_test 14 from autotest_lib.server.cros.multimedia import remote_facade_factory 15 from autotest_lib.server.cros.network import netperf_runner 16 from autotest_lib.server.cros.network import netperf_session 17 from autotest_lib.server.cros.network import wifi_cell_test_base 18 19 20 class network_WiFi_BluetoothStreamPerf(wifi_cell_test_base.WiFiCellTestBase): 21 """Test maximal achievable bandwidth on several channels per band. 22 23 Conducts a performance test for a set of specified router configurations 24 and reports results as keyval pairs. 25 26 """ 27 28 version = 1 29 30 NETPERF_CONFIGS = [ 31 netperf_runner.NetperfConfig( 32 netperf_runner.NetperfConfig.TEST_TYPE_TCP_STREAM), 33 netperf_runner.NetperfConfig( 34 netperf_runner.NetperfConfig.TEST_TYPE_TCP_MAERTS), 35 netperf_runner.NetperfConfig( 36 netperf_runner.NetperfConfig.TEST_TYPE_UDP_STREAM), 37 netperf_runner.NetperfConfig( 38 netperf_runner.NetperfConfig.TEST_TYPE_UDP_MAERTS), 39 ] 40 41 42 def parse_additional_arguments(self, commandline_args, additional_params): 43 """Hook into super class to take control files parameters. 44 45 @param commandline_args dict of parsed parameters from the autotest. 46 @param additional_params list of HostapConfig objects. 47 48 """ 49 self._ap_configs = additional_params 50 51 52 def test_one(self, session, config, ap_config_tag, bt_tag): 53 """Run one iteration of wifi testing. 54 55 @param session NetperfSession session 56 @param config NetperfConfig config 57 @param ap_config_tag string for AP configuration 58 @param bt_tag string for BT operation 59 60 """ 61 get_ping_config = lambda period: ping_runner.PingConfig( 62 self.context.get_wifi_addr(), interval=1, count=period) 63 64 logging.info('testing config %s, ap_config %s, BT:%s', 65 config.tag, ap_config_tag, bt_tag) 66 test_str = '_'.join([ap_config_tag, bt_tag]) 67 time.sleep(1) 68 69 # Record the signal level. 70 signal_level = self.context.client.wifi_signal_level 71 signal_description = '_'.join(['signal', test_str]) 72 self.write_perf_keyval({signal_description: signal_level}) 73 74 # Run netperf and log the results. 75 results = session.run(config) 76 if not results: 77 logging.error('Failed to take measurement for %s', 78 config.tag) 79 return 80 values = [result.throughput for result in results] 81 self.output_perf_value(config.tag + '_' + bt_tag, values, units='Mbps', 82 higher_is_better=True, 83 graph=ap_config_tag) 84 result = netperf_runner.NetperfResult.from_samples(results) 85 self.write_perf_keyval(result.get_keyval( 86 prefix='_'.join([config.tag, test_str]))) 87 88 # Log the drop in throughput compared with the 'BT_disconnected' 89 # baseline. Only positive values are valid. Report the drop as a 90 # whole integer percentage of (base_through-through)/base_through. 91 if bt_tag == 'BT_disconnected': 92 self.base_through = result.throughput 93 elif self.base_through > 0: 94 drop = int( (self.base_through - result.throughput) * 100 / 95 self.base_through) 96 self.output_perf_value(config.tag + '_' + bt_tag + '_drop', 97 drop, units='percent_drop', 98 higher_is_better=False, 99 graph=ap_config_tag + '_drop') 100 self.write_perf_keyval({'_'.join([config.tag, test_str, 'drop']): 101 drop}) 102 logging.info('logging drop value as %d%%', drop) 103 104 # Test latency with ping. 105 result_ping = self.context.client.ping(get_ping_config(3)) 106 self.write_perf_keyval( 107 { '_'.join(['ping', test_str]): result_ping.avg_latency }) 108 logging.info('Ping statistics with %s: %r', bt_tag, result_ping) 109 110 111 112 def run_once(self, host): 113 """Test body.""" 114 start_time = time.time() 115 116 # Setup Bluetooth widgets and their binder, but do not yet connect. 117 audio_test.audio_test_requirement() 118 factory = remote_facade_factory.RemoteFacadeFactory( 119 host, results_dir=self.resultsdir) 120 chameleon_board = host.chameleon 121 if chameleon_board is None: 122 raise error.TestNAError("No chameleon device is present") 123 124 chameleon_board.setup_and_reset(self.outputdir) 125 widget_factory = chameleon_audio_helper.AudioWidgetFactory( 126 factory, host) 127 source = widget_factory.create_widget( 128 chameleon_audio_ids.CrosIds.BLUETOOTH_HEADPHONE) 129 bluetooth_widget = widget_factory.create_widget( 130 chameleon_audio_ids.PeripheralIds.BLUETOOTH_DATA_RX) 131 binder = widget_factory.create_binder( 132 source, bluetooth_widget) 133 audio_test_file = 'http://commondatastorage.googleapis.com/' \ 134 'chromiumos-test-assets-public/audio_test/' \ 135 'chameleon/Headphone/test_256_16.mp3' 136 137 138 for ap_config in self._ap_configs: 139 # Set up the router and associate the client with it. 140 self.context.configure(ap_config) 141 assoc_params = xmlrpc_datatypes.AssociationParameters( 142 ssid=self.context.router.get_ssid(), 143 security_config=ap_config.security_config) 144 self.context.assert_connect_wifi(assoc_params) 145 session = netperf_session.NetperfSession(self.context.client, 146 self.context.router) 147 session.MEASUREMENT_MAX_SAMPLES = 6. 148 149 150 # Warmup the wifi path and measure signal. 151 session.warmup_stations() 152 ap_config_tag = ap_config.perf_loggable_description 153 154 for config in self.NETPERF_CONFIGS: 155 self.base_through = 0 156 self.test_one(session, config, ap_config_tag, 'BT_disconnected') 157 with chameleon_audio_helper.bind_widgets(binder): 158 self.test_one(session, config, ap_config_tag, 159 'BT_connected_but_not_streaming') 160 logging.info('Playing an audio test file') 161 browser_facade = factory.create_browser_facade() 162 browser_facade.new_tab(audio_test_file) 163 self.test_one(session, config, ap_config_tag, 164 'BT_streaming_audiofile') 165 self.test_one(session, config, ap_config_tag, 166 'BT_disconnected_again') 167 168 # Clean up router and client state for the next run. 169 self.context.client.shill.disconnect(self.context.router.get_ssid()) 170 self.context.router.deconfig() 171 172 end_time = time.time() 173 logging.info('Running time %0.1f seconds.', end_time - start_time) 174 175