blob: 6e446178c66bc15ba7b735512a1abac7271898ac [file] [log] [blame]
#!/usr/bin/env python3
# Copyright 2024 The ChromiumOS Authors
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
# pylint: disable=protected-access
import glob
import os
import shutil
import time
from typing import Dict, Optional, Tuple, Union
import unittest
from unittest import mock
from cros.factory.device import device_utils
from cros.factory.test import event_log
from cros.factory.test.pytests import bluetooth
from cros.factory.test import session
from cros.factory.test import state
from cros.factory.test import test_case
from cros.factory.test import test_ui
from cros.factory.test.utils import bluetooth_utils
from cros.factory.testlog import testlog
from cros.factory.utils import file_utils
from cros.factory.utils import type_utils
class FakeArgs:
def __init__(self, **kwargs):
self.expected_adapter_count: int = 0
self.manufacturer_id: Optional[int] = None
self.detect_adapters_retry_times: int = 10
self.detect_adapters_interval_secs: int = 2
self.read_bluetooth_uuid_timeout_secs: int = 0
self.scan_devices: bool = False
self.prompt_scan_message: bool = True
self.keyword: Optional[str] = None
self.average_rssi_threshold: float = -70.0
self.scan_counts: int = 3
self.scan_timeout_secs: int = 10
self.input_device_mac: Optional[str] = None
self.input_device_mac_key: Optional[str] = None
self.input_device_rssi_key: Optional[str] = None
self.firmware_revision_string_key: Optional[str] = None
self.firmware_revision_string: Optional[str] = None
self.average_rssi_lower_threshold: Optional[Tuple[float, dict]] = None
self.average_rssi_upper_threshold: Optional[Tuple[float, dict]] = None
self.pair_with_match: bool = False
self.finish_after_pair: bool = False
self.unpair: bool = False
self.check_shift_pair_keys: bool = False
self.check_battery_charging: bool = False
self.read_battery_level: Optional[int] = None
self.check_battery_level: bool = False
self.prompt_into_fixture: bool = False
self.use_charge_fixture: bool = False
self.reset_fixture: bool = False
self.start_charging: bool = False
self.enable_magnet: bool = False
self.reset_magnet: bool = False
self.stop_charging: bool = False
self.base_enclosure_serial_number: Optional[str] = None
self.battery_log: Optional[str] = None
self.expected_battery_level: int = 100
self.log_path: Optional[str] = None
self.keep_raw_logs: bool = True
self.test_host_id_file: Optional[str] = None
for k, v in kwargs.items():
setattr(self, k, v)
def i18n(text):
return {
'en-US': text
}
class BluetoothUnitTest(unittest.TestCase):
def setUp(self):
self.test = bluetooth.BluetoothTest()
self.ui = mock.create_autospec(test_ui.StandardUI)
type_utils.LazyProperty.Override(self.test, 'ui', self.ui)
self.fake_data_shelf: Dict[str, Union[str, int]] = {}
def set_helper(key, val):
self.fake_data_shelf[key] = val
patcher = mock.patch.object(device_utils, 'CreateDUTInterface',
autospec=True)
self.mock_dut = patcher.start().return_value
patcher = mock.patch.object(test_ui, 'EventLoop', autospec=True)
self.test.event_loop = patcher.start().return_value
patcher = mock.patch.object(bluetooth_utils, 'VerifyAltSetting',
autospec=True)
self.mock_verify_setting = patcher.start()
patcher = mock.patch.object(bluetooth_utils, 'BtMgmt', autospec=True)
self.btmgmt = patcher.start()
self.mock_btmgmt = self.btmgmt.return_value
self.mock_hci_device = self.mock_btmgmt.GetHciDevice.return_value
self.mock_host_mac = self.mock_btmgmt.GetMac.return_value
patcher = mock.patch.object(testlog, 'GroupParam', autospec=True)
self.group_param = patcher.start()
self.mock_group_checker = self.group_param.return_value
patcher = mock.patch.object(file_utils, 'CreateTemporaryFile',
autospec=True)
self.mock_create_tmp_file = patcher.start()
self.mock_log_tmp_file = self.mock_create_tmp_file.return_value
patcher = mock.patch.object(file_utils, 'ReadFile', autospec=True)
self.mock_read_file = patcher.start()
patcher = mock.patch.object(os.path, 'isfile', autospec=True)
self.mock_is_file = patcher.start()
patcher = mock.patch.object(os.path, 'join', autospec=True)
self.mock_join = patcher.start()
self.mock_log_file = self.mock_join.return_value
patcher = mock.patch.object(state, 'DataShelfGetValue', autospec=True)
self.mock_datashelf_get = patcher.start()
self.mock_datashelf_get.side_effect = (
lambda x: self.fake_data_shelf.get(x, None))
patcher = mock.patch.object(state, 'DataShelfSetValue', autospec=True)
self.mock_datshelf_set = patcher.start()
self.mock_datshelf_set.side_effect = set_helper
patcher = mock.patch.object(test_case.TestCase, 'AddTask', autospec=True)
self.mock_add_task = patcher.start()
patcher = mock.patch.object(test_case.TestCase, 'FailTask', autospec=True)
self.mock_fail_task = patcher.start()
patcher = mock.patch.object(test_case.TestCase, 'assertEqual',
autospec=True)
self.mock_assert_equal = patcher.start()
patcher = mock.patch.object(time, 'strftime', autospec=True)
self.mock_strftime = patcher.start()
self.addCleanup(mock.patch.stopall)
self.test.args = FakeArgs() # type: ignore #TODO(b/338318729) Fixit! # pylint: disable=line-too-long
self.mock_bt_manager = self.mock_dut.bluetooth
@mock.patch.object(glob, 'glob', autospec=True)
def test_GetInputCount(self, mock_glob):
mock_glob.return_value = ['/dev/input/event1', '/dev/input/event2']
cnt = bluetooth.GetInputCount()
self.assertEqual(cnt, 2)
@mock.patch.object(os.path, 'dirname', autospec=True)
@mock.patch.object(file_utils, 'TryMakeDirs', autospec=True)
def test_AppendLog(self, mock_try_make_dir, mock_dirname):
self.mock_strftime.return_value = '2024-01-01 01:02:03'
mock_dirname.return_value = 'fake_log_dir'
with mock.patch("builtins.open", mock.mock_open()) as mock_file:
bluetooth._AppendLog('fake_log_file', 'data1\ndata2\ndata3')
mock_log = mock_file.return_value
mock_dirname.assert_called_once_with('fake_log_file')
mock_try_make_dir.assert_called_once_with('fake_log_dir')
mock_file.assert_called_once_with('fake_log_file', 'a', encoding='utf8')
mock_log.write.assert_called_once_with('2024-01-01 01:02:03 data1\n'
'2024-01-01 01:02:03 data2\n'
'2024-01-01 01:02:03 data3\n')
def test_setUp_Init(self):
self.test.args = FakeArgs(manufacturer_id=123) # type: ignore #TODO(b/338318729) Fixit! # pylint: disable=line-too-long
self.test.setUp()
self.mock_verify_setting.assert_called_once()
self.ui.ToggleTemplateClass.assert_called_once_with('font-large', True)
self.btmgmt.assert_called_once_with(123)
self.mock_btmgmt.PowerOn.assert_called_once()
self.group_param.assert_called_once_with('avg_rssi',
['mac', 'average_rssi'])
def test_setUp_GetMacByKey(self):
self.test.args = FakeArgs(input_device_mac_key='fake_key') # type: ignore #TODO(b/338318729) Fixit! # pylint: disable=line-too-long
self.fake_data_shelf['fake_key'] = 'ABCDEF012345'
self.test.setUp()
self.assertEqual(self.test._input_device_mac, 'AB:CD:EF:01:23:45')
del self.fake_data_shelf['fake_key']
def test_setUp_SetLogFile(self):
self.test.args = FakeArgs( # type: ignore #TODO(b/338318729) Fixit! # pylint: disable=line-too-long
base_enclosure_serial_number='fake_serial_num',
test_host_id_file='fake_id_file', log_path='fake_log_path')
self.mock_is_file.return_value = True
self.mock_read_file.return_value = 'fake_test_host_id'
self.test.setUp()
self.mock_create_tmp_file.assert_called_once()
self.mock_is_file.assert_called_once_with('fake_id_file')
self.mock_read_file.assert_has_calls([
mock.call(bluetooth.CURRENT_BT_DAEMON_FILE),
mock.call('fake_id_file')
])
self.mock_join.assert_called_once_with('fake_log_path',
'fake_serial_num.fake_test_host_id')
def test_setUp_DetectAdapter(self):
self.test.args = FakeArgs(expected_adapter_count=3) # type: ignore #TODO(b/338318729) Fixit! # pylint: disable=line-too-long
self.test.setUp()
self.mock_add_task.assert_called_once_with(self.test,
self.test.DetectAdapter, 3)
def test_setUp_ScanDevices(self):
self.test.args = FakeArgs(scan_devices=True, prompt_scan_message=True) # type: ignore #TODO(b/338318729) Fixit! # pylint: disable=line-too-long
self.test.setUp()
self.mock_add_task.assert_has_calls([
mock.call(
self.test, self.test.WaitKeyPressed,
i18n('Enable the connection ability of bluetooth device '
'and press Enter')),
mock.call(self.test, self.test.ScanDevices)
])
def test_setUp_DetectRSSIofTargetMAC(self):
self.test.args = FakeArgs(input_device_rssi_key='fake_rssi_key') # type: ignore #TODO(b/338318729) Fixit! # pylint: disable=line-too-long
self.test.setUp()
self.mock_add_task.assert_called_once_with(self.test,
self.test.DetectRSSIofTargetMAC)
def test_setUp_PromptIntoFixture(self):
self.test.args = FakeArgs(prompt_into_fixture=True) # type: ignore #TODO(b/338318729) Fixit! # pylint: disable=line-too-long
self.test.setUp()
self.mock_add_task.assert_called_once_with(
self.test, self.test.WaitKeyPressed,
i18n('Place the base into the fixture, '
'and press the space key on the test host.'), test_ui.SPACE_KEY)
def test_setUp_ReadBatteryLevel_1(self):
self.test.args = FakeArgs( # type: ignore #TODO(b/338318729) Fixit! # pylint: disable=line-too-long
read_battery_level=1, input_device_mac='AB:CD:EF:01:23:45')
self.test.setUp()
self.mock_add_task.assert_called_once_with(
self.test, self.test.ReadBatteryLevel, 'AB:CD:EF:01:23:45',
'read_battery_1')
def test_setUp_EnableMagnet(self):
self.test.args = FakeArgs(enable_magnet=True, use_charge_fixture=True) # type: ignore #TODO(b/338318729) Fixit! # pylint: disable=line-too-long
self.test.setUp()
self.mock_add_task.assert_called_once_with(
self.test, self.test.FixtureControl, 'ENABLE_MAGNET')
def test_setUp_ResetMagnet_UseFixture(self):
self.test.args = FakeArgs(reset_magnet=True, use_charge_fixture=True) # type: ignore #TODO(b/338318729) Fixit! # pylint: disable=line-too-long
self.test.setUp()
self.mock_add_task.assert_has_calls([
mock.call(self.test, self.test.FixtureControl, 'DISABLE_MAGNET',
post_sleep=1),
mock.call(self.test, self.test.FixtureControl, 'ENABLE_MAGNET')
])
def test_setUp_ResetMagnet_DoNotUseFixture(self):
self.test.args = FakeArgs(reset_magnet=True, use_charge_fixture=False) # type: ignore #TODO(b/338318729) Fixit! # pylint: disable=line-too-long
self.test.setUp()
self.mock_add_task.assert_called_once_with(
self.test, self.test.WaitKeyPressed,
i18n('Please re-attach the magnet, '
'and press the space key on the test host.'), test_ui.SPACE_KEY)
def test_setUp_StartCharging_UseFixture(self):
self.test.args = FakeArgs(start_charging=True, use_charge_fixture=True) # type: ignore #TODO(b/338318729) Fixit! # pylint: disable=line-too-long
self.test.setUp()
self.mock_add_task.assert_called_once_with(
self.test, self.test.FixtureControl, 'START_CHARGING')
def test_setUp_StartCharging_DoNotUseFixture(self):
self.test.args = FakeArgs(start_charging=True, use_charge_fixture=False) # type: ignore #TODO(b/338318729) Fixit! # pylint: disable=line-too-long
self.test.setUp()
self.mock_add_task.assert_called_once_with(
self.test, self.test.WaitKeyPressed,
i18n('Turn on charging by pressing the green button, '
'take the keyboard out and put it back, '
'and press the space key on the test host.'), test_ui.SPACE_KEY)
def test_setUp_CheckPairKeys(self):
self.test.args = FakeArgs( # type: ignore #TODO(b/338318729) Fixit! # pylint: disable=line-too-long
check_shift_pair_keys=True, input_device_mac='AB:CD:EF:01:23:45')
self.test.setUp()
self.mock_add_task.assert_called_once_with(
self.test, self.test.CheckDisconnectionOfPairedDevice,
'AB:CD:EF:01:23:45')
def test_setUp_Unpair(self):
self.test.args = FakeArgs( # type: ignore #TODO(b/338318729) Fixit! # pylint: disable=line-too-long
unpair=True, input_device_mac='AB:CD:EF:01:23:45',
keyword='fake_keyword')
self.test.setUp()
self.mock_add_task.assert_called_once_with(
self.test, self.test.Unpair, 'AB:CD:EF:01:23:45', 'fake_keyword')
def test_setUp_CheckFirmwareRevision(self):
self.test.args = FakeArgs( # type: ignore #TODO(b/338318729) Fixit! # pylint: disable=line-too-long
firmware_revision_string='fake_fw_rev_str',
input_device_mac='AB:CD:EF:01:23:45')
self.test.setUp()
self.mock_add_task.assert_called_once_with(
self.test, self.test.CheckFirmwareRevision, 'AB:CD:EF:01:23:45')
def test_setUp_PairWithMatch(self):
self.test.args = FakeArgs(pair_with_match=True, finish_after_pair=True) # type: ignore #TODO(b/338318729) Fixit! # pylint: disable=line-too-long
self.test.setUp()
self.mock_add_task.assert_called_once_with(self.test, self.test.TestInput,
True)
def test_setUp_ReadBatteryLevel_2(self):
self.test.args = FakeArgs( # type: ignore #TODO(b/338318729) Fixit! # pylint: disable=line-too-long
read_battery_level=2, input_device_mac='AB:CD:EF:01:23:45')
self.test.setUp()
self.mock_add_task.assert_called_once_with(
self.test, self.test.ReadBatteryLevel, 'AB:CD:EF:01:23:45',
'read_battery_2')
def test_setUp_CheckBatteryLevel(self):
self.test.args = FakeArgs(check_battery_level=True) # type: ignore #TODO(b/338318729) Fixit! # pylint: disable=line-too-long
self.test.setUp()
self.mock_add_task.assert_called_once_with(self.test,
self.test.CheckBatteryLevel)
def test_setUp_StopCharging_UseFixture(self):
self.test.args = FakeArgs(stop_charging=True, use_charge_fixture=True) # type: ignore #TODO(b/338318729) Fixit! # pylint: disable=line-too-long
self.test.setUp()
self.mock_add_task.assert_called_once_with(
self.test, self.test.FixtureControl, 'STOP_CHARGING')
def test_setUp_StopCharging_DoNotUseFixture(self):
self.test.args = FakeArgs(stop_charging=True, use_charge_fixture=False) # type: ignore #TODO(b/338318729) Fixit! # pylint: disable=line-too-long
self.test.setUp()
self.mock_add_task.assert_called_once_with(
self.test, self.test.WaitKeyPressed,
i18n('Press the green button again to stop charging, '
'and press the space key on the test host.'), test_ui.SPACE_KEY)
@mock.patch.object(shutil, 'copyfile', autospec=True)
@mock.patch.object(testlog, 'AttachFile', autospec=True)
@mock.patch.object(os, 'remove', autospec=True)
def test_tearDown(self, mock_remove, mock_attach_file, mock_copy_file):
self.test.args = FakeArgs( # type: ignore #TODO(b/338318729) Fixit! # pylint: disable=line-too-long
use_charge_fixture=True, base_enclosure_serial_number='fake_serial_num',
test_host_id_file='fake_id_file', log_path='fake_log_path',
keep_raw_logs=True)
self.mock_is_file.return_value = True
self.test.setUp()
self.test.fixture = mock.Mock()
self.test.tearDown()
self.test.fixture.Close.assert_called_once()
mock_copy_file.assert_called_once_with(self.mock_log_tmp_file,
self.mock_log_file)
mock_attach_file.assert_called_once_with(
path=self.mock_log_tmp_file, mime_type='text/plain',
name='bluetooth.log', description='plain text log of bluetooth',
delete=False)
mock_remove.assert_called_once_with(self.mock_log_tmp_file)
def test_WaitKeyPressed(self):
self.test.WaitKeyPressed('message', 'key')
self.ui.SetState.assert_called_once_with('message')
self.ui.WaitKeysOnce.assert_called_once_with('key')
@mock.patch.object(bluetooth.BluetoothTest, 'RetryWithProgress',
autospec=True)
@mock.patch.object(bluetooth, '_AppendLog', autospec=True)
def test_CheckFirmwareRevision(self, mock_append_log, mock_retry):
self.test.args = FakeArgs( # type: ignore #TODO(b/338318729) Fixit! # pylint: disable=line-too-long
read_bluetooth_uuid_timeout_secs=5,
firmware_revision_string_key='fake_fw_rev_key',
firmware_revision_string='fake_fw_rev_str')
mock_retry.return_value = 'fake_fw'
self.test.setUp()
self.test.CheckFirmwareRevision('mac')
self.ui.SetState.assert_called_once_with(
i18n('Read firmware revision string.'))
mock_retry.assert_called_once_with(
self.test, 'reading firmware', 10, 1,
bluetooth_utils.GattTool.GetDeviceInfo, 'mac',
'firmware revision string', hci_device=self.mock_hci_device, timeout=5)
self.assertEqual(self.fake_data_shelf['fake_fw_rev_key'], 'fake_fw')
mock_append_log.assert_called_once_with(None, 'FW: fake_fw\n')
self.mock_assert_equal.assert_called_once_with(
self.test, 'fake_fw_rev_str', 'fake_fw',
'Expected firmware: fake_fw_rev_str, actual firmware: fake_fw')
def test_CheckBatteryLevel(self):
self.test.args = FakeArgs(expected_battery_level=5) # type: ignore #TODO(b/338318729) Fixit! # pylint: disable=line-too-long
self.fake_data_shelf['read_battery_1'] = 10
self.fake_data_shelf['read_battery_2'] = 20
self.test.CheckBatteryLevel()
self.ui.SetState.assert_called_once_with(
i18n('Check if the battery has charged to a higher percentage'))
self.mock_fail_task.assert_not_called()
def test_CheckBatteryLevel_Fail_OnlyReadOneValue(self):
self.test.args = FakeArgs(expected_battery_level=5) # type: ignore #TODO(b/338318729) Fixit! # pylint: disable=line-too-long
self.fake_data_shelf['read_battery_1'] = 10
self.test.CheckBatteryLevel()
self.mock_fail_task.assert_called_once_with(
self.test,
'Battery levels should be read twice. read_1: 10, read_2: None')
def test_CheckBatteryLevel_Fail_NotChargeUp(self):
self.test.args = FakeArgs(expected_battery_level=5) # type: ignore #TODO(b/338318729) Fixit! # pylint: disable=line-too-long
self.fake_data_shelf['read_battery_1'] = 10
self.fake_data_shelf['read_battery_2'] = 9
self.test.CheckBatteryLevel()
self.mock_fail_task.assert_called_once_with(
self.test, 'Base battery is not charged up. read_1: 10, read_2: 9')
def test_CheckBatteryLevel_Fail_LessThanExpect(self):
self.test.args = FakeArgs(expected_battery_level=15) # type: ignore #TODO(b/338318729) Fixit! # pylint: disable=line-too-long
self.fake_data_shelf['read_battery_1'] = 10
self.fake_data_shelf['read_battery_2'] = 20
self.test.CheckBatteryLevel()
self.mock_fail_task.assert_called_once_with(
self.test,
'Measured battery level 10 is less than the expected level 15.')
del self.fake_data_shelf['read_battery_1']
del self.fake_data_shelf['read_battery_2']
@mock.patch.object(bluetooth.BluetoothTest, 'RetryWithProgress',
autospec=True)
@mock.patch.object(bluetooth, '_AppendLog', autospec=True)
def test_ReadBatteryLevel(self, mock_append_log, mock_retry):
with mock.patch("builtins.open", mock.mock_open()) as mock_file:
self.test.args = FakeArgs( # type: ignore #TODO(b/338318729) Fixit! # pylint: disable=line-too-long
expected_battery_level=15, read_bluetooth_uuid_timeout_secs=3,
battery_log='fake_battery_log',
base_enclosure_serial_number='fake_serial_num')
mock_retry.return_value = 10.0
self.fake_data_shelf['read_battery_2'] = 20
mock_log = mock_file.return_value
self.mock_strftime.return_value = 'fake_time'
self.test.setUp()
self.test.ReadBatteryLevel('mac', 'read_battery_2')
self.ui.SetState.assert_called_once_with(
i18n(('Read battery level for the 2nd time.')))
mock_retry.assert_called_once_with(
self.test, 'read_battery_2', 10, 1,
bluetooth_utils.GattTool.GetDeviceInfo, 'mac', 'battery level',
hci_device=self.mock_hci_device, timeout=3)
self.assertEqual(self.fake_data_shelf['read_battery_2'], 10)
mock_append_log.assert_called_once_with(self.mock_log_tmp_file,
'read_battery_2: 10\n')
mock_file.assert_called_once_with('fake_battery_log', 'a',
encoding='utf8')
mock_log.write.assert_called_once_with('fake_time fake_serial_num mac'
' [read_battery_2]: 10\n')
@mock.patch.object(test_case.TestCase, 'Sleep', autospec=True)
def test_FixtureControl(self, mock_sleep):
self.test.fixture = mock.MagicMock()
mock_obj = mock.MagicMock()
fake_func = mock_obj.func
fake_func.__name__ = ''
self.test.fixture.StartCharging = fake_func
self.test.FixtureControl('START_CHARGING', 0)
fake_func.assert_called_once()
mock_sleep.assert_called_once_with(self.test, 0)
def test_DetectAdapter(self):
self.test.args = FakeArgs( # type: ignore #TODO(b/338318729) Fixit! # pylint: disable=line-too-long
detect_adapters_retry_times=3, detect_adapters_interval_secs=1)
self.mock_bt_manager.GetAdapters.return_value = ['adapter1', 'adapter2']
self.test.setUp()
self.test.DetectAdapter(2)
self.ui.SetState.assert_called_once_with(i18n('Detect bluetooth adapter'))
self.mock_bt_manager.GetAdapters.assert_called_once_with(3, 1)
self.mock_assert_equal.assert_called_once_with(
self.test, 2, 2, 'DetectAdapter: expect 2 and find 2 adapter(s).')
@mock.patch.object(bluetooth, 'GetInputCount', autospec=True)
@mock.patch.object(bluetooth, 'WaitForInputCount', autospec=True)
def test_Unpair(self, mock_wait, mock_get_input_count):
mock_get_input_count.return_value = 2
self.mock_bt_manager.GetFirstAdapter.return_value = 'fake_adapter'
self.mock_bt_manager.GetAllDevices.return_value = {
'fake_device_1': {
'Address': 123,
'Paired': True
},
'fake_device_2': {
'Address': 456,
'Paired': True
}
}
self.test.setUp()
self.test.Unpair(None, None)
self.ui.SetState.assert_called_once_with(i18n('Unpairing'))
self.mock_bt_manager.GetFirstAdapter.assert_called_once_with(
self.mock_host_mac)
self.mock_bt_manager.GetAllDevices.assert_called_once_with('fake_adapter')
self.mock_bt_manager.DisconnectAndUnpairDevice.assert_has_calls(
[mock.call('fake_adapter', 123),
mock.call('fake_adapter', 456)])
self.mock_bt_manager.RemovePairedDevice.assert_has_calls(
[mock.call('fake_adapter', 123),
mock.call('fake_adapter', 456)])
mock_wait.assert_called_once_with(0)
@mock.patch.object(bluetooth.BluetoothTest, 'TimedProgressBar', autospec=True)
@mock.patch.object(event_log, 'Log', autospec=True)
@mock.patch.object(testlog, 'LogParam', autospec=True)
@mock.patch.object(testlog, 'CheckNumericParam', autospec=True)
def test_ScanDevices(self, mock_check_param, mock_testlog, mock_event_log,
mock_time_bar):
self.test.args = FakeArgs( # type: ignore #TODO(b/338318729) Fixit! # pylint: disable=line-too-long
keyword='fake_keyword', average_rssi_threshold=-50.0, scan_counts=1,
scan_timeout_secs=10)
self.mock_bt_manager.GetFirstAdapter.return_value = 'fake_adapter'
self.mock_bt_manager.ScanDevices.return_value = {
'fake_mac_1': {
'Name': 'fake_keyword_name_1',
'RSSI': -46.0
},
'fake_mac_2': {
'Name': 'fake_keyword_name_2',
'RSSI': -48.0
}
}
self.test.setUp()
self.test.ScanDevices()
self.mock_bt_manager.GetFirstAdapter.assert_called_once_with(
self.mock_host_mac)
self.ui.SetState.assert_called_once_with(i18n('Scanning...'))
mock_time_bar.assert_called_once_with(self.test, 10)
self.mock_bt_manager.ScanDevices.assert_called_once_with('fake_adapter', 10)
mock_event_log.assert_has_calls([
mock.call('avg_rssi', mac='fake_mac_1', average_rssi=-46),
mock.call('avg_rssi', mac='fake_mac_2', average_rssi=-48),
mock.call('bluetooth_scan_device', mac='fake_mac_1', rssi=-46,
meet=True)
])
mock_testlog.assert_has_calls([
mock.call('mac', 'fake_mac_1'),
mock.call('average_rssi', -46.0),
mock.call('mac', 'fake_mac_2'),
mock.call('average_rssi', -48.0),
])
mock_check_param.assert_called_once_with('max_average_rssi', -46, min=-50.0)
@mock.patch.object(bluetooth.BluetoothTest, 'TimedProgressBar', autospec=True)
@mock.patch.object(event_log, 'Log', autospec=True)
@mock.patch.object(testlog, 'LogParam', autospec=True)
@mock.patch.object(testlog, 'CheckNumericParam', autospec=True)
def test_ScanDevices_Fail_LessThanThreshold(
self, unused_mock_check_param, unused_mock_testlog, unused_mock_event_log,
unused_mock_time_bar):
self.test.args = FakeArgs( # type: ignore #TODO(b/338318729) Fixit! # pylint: disable=line-too-long
keyword='fake_keyword', average_rssi_threshold=-45.0, scan_counts=1,
scan_timeout_secs=10)
self.mock_bt_manager.GetFirstAdapter.return_value = 'fake_adapter'
self.mock_bt_manager.ScanDevices.return_value = {
'fake_mac_1': {
'Name': 'fake_keyword_name_1',
'RSSI': -46.0
},
'fake_mac_2': {
'Name': 'fake_keyword_name_2',
'RSSI': -48.0
}
}
self.test.setUp()
self.test.ScanDevices()
self.mock_fail_task.assert_called_once_with(
self.test, 'ScanDeviceTask: The largest average RSSI -46.000000 of '
'device fake_mac_1 does not meet threshold -45.000000.')
@mock.patch.object(bluetooth.BluetoothTest, 'RetryWithProgress',
autospec=True)
@mock.patch.object(bluetooth, '_AppendLog', autospec=True)
def test_CheckDisconnectionOfPairedDevice(self, mock_append_log, mock_retry):
mock_retry.return_value = True
self.test.setUp()
self.test.CheckDisconnectionOfPairedDevice('fake_mac')
self.ui.SetState.assert_called_once_with(
i18n('Press shift-p-a-i-r simultaneously on the base.'))
mock_append_log.assert_called_once_with(None, 'Shift-P-A-I-R: done')
@mock.patch.object(bluetooth.BluetoothTest, 'RetryWithProgress',
autospec=True)
@mock.patch.object(bluetooth, '_AppendLog', autospec=True)
def test_CheckDisconnectionOfPairedDevice_Fail(self, mock_append_log,
mock_retry):
mock_retry.return_value = False
self.test.setUp()
self.test.CheckDisconnectionOfPairedDevice('fake_mac')
mock_append_log.assert_called_once_with(None, 'Shift-P-A-I-R: not done')
self.mock_fail_task.assert_called_once_with(self.test,
'Shift-P-A-I-R: not done')
@mock.patch.object(session, 'GetDeviceID', autospec=True)
@mock.patch.object(bluetooth.BluetoothTest, 'TimedProgressBar', autospec=True)
@mock.patch.object(bluetooth, '_AppendLog', autospec=True)
def test_DetectRSSIofTargetMAC(self, mock_append_log, mock_time_bar,
mock_get_id):
self.test.args = FakeArgs( # type: ignore #TODO(b/338318729) Fixit! # pylint: disable=line-too-long
input_device_mac='fake_mac_1', scan_counts=1, scan_timeout_secs=10,
input_device_rssi_key='fake_rssi_key',
average_rssi_lower_threshold=-50.0, average_rssi_upper_threshold=-40.0)
mock_get_id.return_value = 'fake_fid'
self.mock_bt_manager.GetFirstAdapter.return_value = 'fake_adapter'
self.mock_bt_manager.ScanDevices.return_value = {
'fake_mac_1': {
'RSSI': -46.0
},
'fake_mac_2': {
'RSSI': -48.0
}
}
self.test.setUp()
self.test.DetectRSSIofTargetMAC()
mock_get_id.assert_called_once()
self.mock_bt_manager.GetFirstAdapter.assert_called_once_with(
self.mock_host_mac)
self.ui.SetState.assert_called_once_with(i18n('Detect RSSI (count 1/1)'))
mock_time_bar.assert_called_once_with(self.test, 10)
self.mock_bt_manager.ScanDevices.assert_called_once_with(
'fake_adapter', timeout_secs=10, match_address='fake_mac_1')
self.assertEqual(self.fake_data_shelf['fake_rssi_key'], -46.0)
mock_append_log.assert_called_once_with(
None, 'Average RSSI: -46.00 [-46] '
'(pass exp: [-50.00, -40.00])\n')
self.mock_fail_task.assert_not_called()
@mock.patch.object(session, 'GetDeviceID', autospec=True)
@mock.patch.object(bluetooth.BluetoothTest, 'TimedProgressBar', autospec=True)
@mock.patch.object(bluetooth, '_AppendLog', autospec=True)
def test_DetectRSSIofTargetMAC_NoRssis(self, unused_mock_append_log,
unused_mock_time_bar, mock_get_id):
self.test.args = FakeArgs( # type: ignore #TODO(b/338318729) Fixit! # pylint: disable=line-too-long
input_device_mac='fake_mac_1', scan_counts=1, scan_timeout_secs=10,
input_device_rssi_key='fake_rssi_key',
average_rssi_lower_threshold=-50.0, average_rssi_upper_threshold=-40.0)
mock_get_id.return_value = 'fake_fid'
self.mock_bt_manager.GetFirstAdapter.return_value = 'fake_adapter'
self.mock_bt_manager.ScanDevices.return_value = {
'fake_mac_1': {},
'fake_mac_2': {}
}
self.test.setUp()
with self.assertRaises(Exception):
self.test.DetectRSSIofTargetMAC()
self.mock_fail_task.assert_called_once_with(
self.test,
'DetectRSSIofTargetMAC: Fail to get RSSI from device fake_mac_1.')
@mock.patch.object(session, 'GetDeviceID', autospec=True)
@mock.patch.object(bluetooth.BluetoothTest, 'TimedProgressBar', autospec=True)
@mock.patch.object(bluetooth, '_AppendLog', autospec=True)
def test_DetectRSSIofTargetMAC_LessThanThreshold(
self, unused_mock_append_log, unused_mock_time_bar, mock_get_id):
self.test.args = FakeArgs( # type: ignore #TODO(b/338318729) Fixit! # pylint: disable=line-too-long
input_device_mac='fake_mac_1', scan_counts=1, scan_timeout_secs=10,
input_device_rssi_key='fake_rssi_key',
average_rssi_lower_threshold=-50.0, average_rssi_upper_threshold=-40.0)
mock_get_id.return_value = 'fake_fid'
self.mock_bt_manager.GetFirstAdapter.return_value = 'fake_adapter'
self.mock_bt_manager.ScanDevices.return_value = {
'fake_mac_1': {
'RSSI': -56.0
},
'fake_mac_2': {
'RSSI': -48.0
}
}
self.test.setUp()
self.test.DetectRSSIofTargetMAC()
self.mock_fail_task.assert_called_once_with(
self.test, 'Average RSSI -56.00 less than the lower threshold -50.00\n')
@mock.patch.object(session, 'GetDeviceID', autospec=True)
@mock.patch.object(bluetooth.BluetoothTest, 'TimedProgressBar', autospec=True)
@mock.patch.object(bluetooth, '_AppendLog', autospec=True)
def test_DetectRSSIofTargetMAC_GreaterThanThreshold(
self, unused_mock_append_log, unused_mock_time_bar, mock_get_id):
self.test.args = FakeArgs( # type: ignore #TODO(b/338318729) Fixit! # pylint: disable=line-too-long
input_device_mac='fake_mac_1', scan_counts=1, scan_timeout_secs=10,
input_device_rssi_key='fake_rssi_key',
average_rssi_lower_threshold=-50.0, average_rssi_upper_threshold=-40.0)
mock_get_id.return_value = 'fake_fid'
self.mock_bt_manager.GetFirstAdapter.return_value = 'fake_adapter'
self.mock_bt_manager.ScanDevices.return_value = {
'fake_mac_1': {
'RSSI': -36.0
},
'fake_mac_2': {
'RSSI': -48.0
}
}
self.test.setUp()
self.test.DetectRSSIofTargetMAC()
self.mock_fail_task.assert_called_once_with(
self.test,
'Average RSSI -36.00 greater than the upper threshold -40.00\n')
@mock.patch.object(bluetooth, 'GetInputCount', autospec=True)
@mock.patch.object(bluetooth, 'WaitForInputCount', autospec=True)
@mock.patch.object(bluetooth.BluetoothTest, 'RetryWithProgress',
autospec=True)
@mock.patch.object(bluetooth, '_AppendLog', autospec=True)
def test_TestInput_FinishAfterPair(self, mock_append_log, mock_retry,
mock_wait, mock_input_count):
self.test.args = FakeArgs(input_device_mac='fake_mac') # type: ignore #TODO(b/338318729) Fixit! # pylint: disable=line-too-long
mock_input_count.return_value = 3
self.mock_bt_manager.GetFirstAdapter.return_value = 'fake_adapter'
mock_retry.side_effect = [True] * 2
self.test.setUp()
self.test.TestInput(True)
self.mock_bt_manager.GetFirstAdapter.assert_called_once_with(
self.mock_host_mac)
self.mock_bt_manager.DisconnectAndUnpairDevice.assert_called_once_with(
'fake_adapter', 'fake_mac')
self.ui.SetState.assert_has_calls([
mock.call(i18n('Pairing to input device now...')),
mock.call(i18n('Connecting to input device now...'))
])
mock_wait.assert_called_once_with(4)
mock_append_log.assert_called_once_with(None, 'Pairing finished\n')
self.mock_fail_task.assert_not_called()
@mock.patch.object(bluetooth, 'GetInputCount', autospec=True)
@mock.patch.object(bluetooth, 'WaitForInputCount', autospec=True)
@mock.patch.object(bluetooth.BluetoothTest, 'RetryWithProgress',
autospec=True)
@mock.patch.object(bluetooth, '_AppendLog', autospec=True)
def test_TestInput_NotFinishAfterPair(self, unused_mock_append_log,
mock_retry, unused_mock_wait,
mock_input_count):
self.test.args = FakeArgs(input_device_mac='fake_mac') # type: ignore #TODO(b/338318729) Fixit! # pylint: disable=line-too-long
mock_input_count.return_value = 3
self.mock_bt_manager.GetFirstAdapter.return_value = 'fake_adapter'
mock_retry.side_effect = [True] * 2
self.ui.WaitKeysOnce.return_value = test_ui.ENTER_KEY
self.test.setUp()
self.test.TestInput(False)
self.ui.SetState.assert_has_calls([
mock.call(i18n('Pairing to input device now...')),
mock.call(i18n('Connecting to input device now...')),
mock.call(
i18n('Please test input. Press Escape to fail and Enter to pass'))
])
self.ui.WaitKeysOnce.assert_called_once_with(
[test_ui.ENTER_KEY, test_ui.ESCAPE_KEY])
self.mock_bt_manager.SetDeviceConnected.assert_called_once_with(
'fake_adapter', 'fake_mac', False)
self.mock_bt_manager.RemovePairedDevice.assert_called_once_with(
'fake_adapter', 'fake_mac')
self.mock_fail_task.assert_not_called()
@mock.patch.object(bluetooth, 'GetInputCount', autospec=True)
@mock.patch.object(bluetooth, 'WaitForInputCount', autospec=True)
@mock.patch.object(bluetooth.BluetoothTest, 'RetryWithProgress',
autospec=True)
@mock.patch.object(bluetooth, '_AppendLog', autospec=True)
def test_TestInput_Fail_NoMac(self, mock_append_log, mock_retry,
unused_mock_wait, unused_mock_input_count):
self.test.args = FakeArgs(input_device_mac='') # type: ignore #TODO(b/338318729) Fixit! # pylint: disable=line-too-long
mock_retry.side_effect = [True] * 2
self.ui.WaitKeysOnce.return_value = test_ui.ENTER_KEY
self.test.setUp()
self.test.TestInput(False)
mock_append_log.assert_called_once_with(
None, 'Pairing fail: InputTestTask: No MAC with which to pair\n')
self.mock_fail_task.assert_called_once_with(
self.test, 'InputTestTask: No MAC with which to pair')
@mock.patch.object(bluetooth, 'GetInputCount', autospec=True)
@mock.patch.object(bluetooth, 'WaitForInputCount', autospec=True)
@mock.patch.object(bluetooth.BluetoothTest, 'RetryWithProgress',
autospec=True)
@mock.patch.object(bluetooth, '_AppendLog', autospec=True)
def test_TestInput_FailCreateDevice(self, mock_append_log, mock_retry,
unused_mock_wait,
unused_mock_input_count):
self.test.args = FakeArgs(input_device_mac='fake_mac') # type: ignore #TODO(b/338318729) Fixit! # pylint: disable=line-too-long
mock_retry.side_effect = [False, True]
self.ui.WaitKeysOnce.return_value = test_ui.ENTER_KEY
self.test.setUp()
self.test.TestInput(False)
mock_append_log.assert_called_once_with(
None, 'Pairing fail: InputTestTask: Fail to create paired device.\n')
self.mock_fail_task.assert_called_once_with(
self.test, 'InputTestTask: Fail to create paired device.')
@mock.patch.object(bluetooth, 'GetInputCount', autospec=True)
@mock.patch.object(bluetooth, 'WaitForInputCount', autospec=True)
@mock.patch.object(bluetooth.BluetoothTest, 'RetryWithProgress',
autospec=True)
@mock.patch.object(bluetooth, '_AppendLog', autospec=True)
def test_TestInput_FailConnectDevice(self, mock_append_log, mock_retry,
unused_mock_wait,
unused_mock_input_count):
self.test.args = FakeArgs(input_device_mac='fake_mac') # type: ignore #TODO(b/338318729) Fixit! # pylint: disable=line-too-long
mock_retry.side_effect = [True, False]
self.ui.WaitKeysOnce.return_value = test_ui.ENTER_KEY
self.test.setUp()
self.test.TestInput(False)
mock_append_log.assert_called_once_with(
None, 'Pairing fail: InputTestTask: Fail to connect device.\n')
self.mock_fail_task.assert_called_once_with(
self.test, 'InputTestTask: Fail to connect device.')
@mock.patch.object(bluetooth, 'GetInputCount', autospec=True)
@mock.patch.object(bluetooth, 'WaitForInputCount', autospec=True)
@mock.patch.object(bluetooth.BluetoothTest, 'RetryWithProgress',
autospec=True)
@mock.patch.object(bluetooth, '_AppendLog', autospec=True)
def test_TestInput_FailRemove(self, unused_mock_append_log, mock_retry,
unused_mock_wait, unused_mock_input_count):
self.test.args = FakeArgs(input_device_mac='fake_mac') # type: ignore #TODO(b/338318729) Fixit! # pylint: disable=line-too-long
mock_retry.side_effect = [True] * 2
self.ui.WaitKeysOnce.return_value = test_ui.ENTER_KEY
self.mock_bt_manager.Error = Exception
self.mock_bt_manager.SetDeviceConnected.side_effect = (
self.mock_bt_manager.Error)
self.test.setUp()
self.test.TestInput(False)
self.mock_fail_task.assert_called_once_with(
self.test, 'InputTestTask: Fail to remove input')
@mock.patch.object(bluetooth, 'GetInputCount', autospec=True)
@mock.patch.object(bluetooth, 'WaitForInputCount', autospec=True)
@mock.patch.object(bluetooth.BluetoothTest, 'RetryWithProgress',
autospec=True)
@mock.patch.object(bluetooth, '_AppendLog', autospec=True)
def test_TestInput_FailByOperator(self, unused_mock_append_log, mock_retry,
unused_mock_wait, unused_mock_input_count):
self.test.args = FakeArgs(input_device_mac='fake_mac') # type: ignore #TODO(b/338318729) Fixit! # pylint: disable=line-too-long
mock_retry.side_effect = [True] * 2
self.ui.WaitKeysOnce.return_value = test_ui.ESCAPE_KEY
self.test.setUp()
self.test.TestInput(False)
self.mock_fail_task.assert_called_once_with(self.test, 'Failed by operator')
def test_TimedProgressBar(self):
self.test.setUp()
with self.test.TimedProgressBar(10):
pass
self.ui.DrawProgressBar.assert_called_once_with(10)
self.test.event_loop.AddTimedHandler.assert_called_once() # type: ignore #TODO(b/338318729) Fixit! # pylint: disable=line-too-long
def test_RetryWithProgress(self):
self.fake_data_shelf['fake_key'] = 'fake_val'
self.test.setUp()
result = self.test.RetryWithProgress('fake_action_string', 3, 0.1,
state.DataShelfGetValue, 'fake_key')
self.ui.DrawProgressBar.assert_called_once_with(3)
self.mock_datashelf_get.assert_called_once_with('fake_key')
self.ui.AdvanceProgress.assert_called_once()
self.ui.SetProgress.assert_called_once_with(3)
self.assertEqual(result, 'fake_val')
if __name__ == '__main__':
unittest.main()