blob: 8bfb48d6b6a9074949ce159137b0a80038731ded [file] [log] [blame]
# Copyright 2015 The Chromium OS Authors. All rights reserved.
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
import logging
import threading
import time
from autotest_lib.client.common_lib.cros.network import ping_runner
from autotest_lib.client.common_lib.cros.network import xmlrpc_datatypes
from autotest_lib.server.cros.network import netperf_runner
from autotest_lib.server.cros.network import netperf_session
from autotest_lib.server.cros.network import wifi_cell_test_base
from autotest_lib.server.cros.bluetooth.bluetooth_adapter_quick_tests import \
BluetoothAdapterQuickTests
from autotest_lib.server.cros.bluetooth.bluetooth_adapter_audio_tests import (
BluetoothAdapterAudioTests)
from autotest_lib.client.cros.bluetooth.bluetooth_audio_test_data import A2DP
class network_WiFi_BluetoothStreamPerf(wifi_cell_test_base.WiFiCellTestBase,
BluetoothAdapterQuickTests,
BluetoothAdapterAudioTests):
"""Test maximal achievable bandwidth on several channels per band.
Conducts a performance test for a set of specified router configurations
and reports results as keyval pairs.
"""
test_wrapper = BluetoothAdapterQuickTests.quick_test_test_decorator
batch_wrapper = BluetoothAdapterQuickTests.quick_test_batch_decorator
version = 1
NETPERF_CONFIGS = [
netperf_runner.NetperfConfig(
netperf_runner.NetperfConfig.TEST_TYPE_TCP_STREAM),
netperf_runner.NetperfConfig(
netperf_runner.NetperfConfig.TEST_TYPE_TCP_MAERTS),
netperf_runner.NetperfConfig(
netperf_runner.NetperfConfig.TEST_TYPE_UDP_STREAM),
netperf_runner.NetperfConfig(
netperf_runner.NetperfConfig.TEST_TYPE_UDP_MAERTS),
]
def parse_additional_arguments(self, commandline_args, additional_params):
"""Hook into super class to take control files parameters.
@param commandline_args dict of parsed parameters from the autotest.
@param additional_params list of HostapConfig objects.
"""
self._ap_configs = additional_params
def test_one(self, session, config, ap_config_tag, bt_tag):
"""Run one iteration of wifi testing.
@param session NetperfSession session
@param config NetperfConfig config
@param ap_config_tag string for AP configuration
@param bt_tag string for BT operation
"""
get_ping_config = lambda period: ping_runner.PingConfig(
self.context.get_wifi_addr(), interval=1, count=period)
logging.info('testing config %s, ap_config %s, BT:%s',
config.tag, ap_config_tag, bt_tag)
test_str = '_'.join([ap_config_tag, bt_tag])
time.sleep(1)
# Record the signal level.
signal_level = self.context.client.wifi_signal_level
signal_description = '_'.join(['signal', test_str])
self.write_perf_keyval({signal_description: signal_level})
# Run netperf and log the results.
results = session.run(config)
if not results:
logging.error('Failed to take measurement for %s',
config.tag)
return
values = [result.throughput for result in results]
self.output_perf_value(config.tag + '_' + bt_tag, values, units='Mbps',
higher_is_better=True,
graph=ap_config_tag)
result = netperf_runner.NetperfResult.from_samples(results)
self.write_perf_keyval(result.get_keyval(
prefix='_'.join([config.tag, test_str])))
# Log the drop in throughput compared with the 'BT_disconnected'
# baseline. Only positive values are valid. Report the drop as a
# whole integer percentage of (base_through-through)/base_through.
if bt_tag == 'BT_disconnected':
self.base_through = result.throughput
elif self.base_through > 0:
drop = int( (self.base_through - result.throughput) * 100 /
self.base_through)
self.output_perf_value(config.tag + '_' + bt_tag + '_drop',
drop, units='percent_drop',
higher_is_better=False,
graph=ap_config_tag + '_drop')
self.write_perf_keyval({'_'.join([config.tag, test_str, 'drop']):
drop})
logging.info('logging drop value as %d%%', drop)
# Test latency with ping.
result_ping = self.context.client.ping(get_ping_config(3))
self.write_perf_keyval(
{ '_'.join(['ping', test_str]): result_ping.avg_latency })
logging.info('Ping statistics with %s: %r', bt_tag, result_ping)
def pair_audio_device(self, device):
"""Pair an audio device pre-test to simplify later re-connection"""
self.test_device_set_discoverable(device, True)
self.test_discover_device(device.address)
self.test_pairing(device.address, device.pin, trusted=True)
device.SetTrustedByRemoteAddress(self.bluetooth_facade.address)
self.test_disconnection_by_adapter(device.address)
def do_audio_test(self, device):
"""Run the body of the audio test"""
self.test_a2dp_sinewaves(device, A2DP, 60)
@test_wrapper('Coex tests', devices={'BLUETOOTH_AUDIO': 1})
def coex_test(self):
"""Test body."""
start_time = time.time()
device = self.devices['BLUETOOTH_AUDIO'][0]
self.initialize_bluetooth_audio(device, A2DP)
self.pair_audio_device(device)
for ap_config in self._ap_configs:
# Set up the router and associate the client with it.
self.context.configure(ap_config)
assoc_params = xmlrpc_datatypes.AssociationParameters(
ssid=self.context.router.get_ssid(),
security_config=ap_config.security_config)
self.context.assert_connect_wifi(assoc_params)
session = netperf_session.NetperfSession(self.context.client,
self.context.router)
session.MEASUREMENT_MAX_SAMPLES = 6.
# Warmup the wifi path and measure signal.
session.warmup_stations()
ap_config_tag = ap_config.perf_loggable_description
for config in self.NETPERF_CONFIGS:
self.base_through = 0
self.test_one(session, config, ap_config_tag, 'BT_disconnected')
self.test_connection_by_device(device)
self.test_one(session, config, ap_config_tag,
'BT_connected_but_not_streaming')
# Start playing audio in background
audio_thread = threading.Thread(target=self.do_audio_test,
args=(device, ))
audio_thread.start()
self.test_one(session, config, ap_config_tag,
'BT_streaming_audiofile')
# Wait for audio thread to complete
audio_thread.join()
self.test_disconnection_by_adapter(device.address)
self.test_one(session, config, ap_config_tag,
'BT_disconnected_again')
# Clean up router and client state for the next run.
self.context.client.shill.disconnect(self.context.router.get_ssid())
self.context.router.deconfig()
self.cleanup_bluetooth_audio(device, A2DP)
end_time = time.time()
logging.info('Running time %0.1f seconds.', end_time - start_time)
@batch_wrapper('Coex batch')
def coex_health_batch_run(self, num_iterations=1, test_name=None):
"""Run the bluetooth coex health test batch or a specific given test.
@param num_iterations: how many iterations to run
@param test_name: specific test to run otherwise None to run the
whole batch
"""
self.coex_test()
def run_once(self, host, test_name=None):
self.host = host
self.quick_test_init(host, use_btpeer=True)
self.coex_health_batch_run(test_name=test_name)
self.quick_test_cleanup()