blob: aa891e00f5b22b6cf024d7001080eeefb971bb8c [file] [log] [blame]
#!/usr/bin/env python
# Copyright 2017 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.
"""A pytest to wait operators setup network connection.
The interface settings are saved in a JSON config file, the JSON schema for this
config file is `py/test/pytests/network_setup/network_config.schema.json`.
Usage::
--- py/test/pytests/network_setup/fft_network_config.json ---
{
"eth1": {
"address": "10.0.1.3",
"prefixlen": 24
},
"/sys/devices/pci0000:00/0000:00:14.0/usb1/1-1/1-1:1.0/net": {
"address": "10.0.2.1",
"prefixlen": 24,
"gateway": "10.0.2.254"
}
}
--- in test list ---
OperatorTest(
id='NetworkSetup',
pytest_name='network_setup.network_setup',
dargs={
'config_name': 'fft_network_config'
})
"""
import logging
import threading
import traceback
import unittest
import factory_common # pylint: disable=unused-import
from cros.factory.test.i18n import test_ui as i18n_test_ui
from cros.factory.test import state
from cros.factory.test import test_ui
from cros.factory.test import ui_templates
from cros.factory.test.utils import connection_manager
from cros.factory.utils import arg_utils
from cros.factory.utils import config_utils
from cros.factory.utils import process_utils
from cros.factory.utils import sync_utils
_TITLE = i18n_test_ui.MakeI18nLabel('Setup network connection')
_ID_SUBTITLE_DIV = 'subtitle'
_ID_MESSAGE_DIV = 'message'
_ID_INSTRUCTION_DIV = 'instruction'
_STATE_HTML = """
<div id='%s'></div>
<div id='%s'></div>
<div id='%s'></div>
""" % (_ID_SUBTITLE_DIV, _ID_MESSAGE_DIV, _ID_INSTRUCTION_DIV)
def _GetSubtitleForInterface(interface):
interface = '<b>%s</b>' % interface
return i18n_test_ui.MakeI18nLabel(
'Setting up interface {interface}', interface=interface)
_PRESS_SPACE = i18n_test_ui.MakeI18nLabel('Press space to continue')
ErrorCode = connection_manager.ConnectionManagerException.ErrorCode
def _ErrorCodeToMessage(error_code, interface):
interface = '<b>%s</b>' % interface
if error_code == ErrorCode.NO_PHYSICAL_LINK:
return i18n_test_ui.MakeI18nLabel(
'No physical link on {interface}', interface=interface),
if error_code == ErrorCode.INTERFACE_NOT_FOUND:
return i18n_test_ui.MakeI18nLabel(
'Interface {interface} not found', interface=interface),
if error_code == ErrorCode.NO_SELECTED_SERVICE:
return i18n_test_ui.MakeI18nLabel(
'Interface {interface} not initialized', interface=interface),
class NetworkConnectionSetup(unittest.TestCase):
ARGS = [
arg_utils.Arg('config_name', str, 'path to the config file'),
arg_utils.Arg('timeout_secs', float,
'timeout seconds for each interface, default is no timeout',
default=None),
]
def setUp(self):
self.ui = test_ui.UI()
self.ui_template = ui_templates.OneSection(self.ui)
self.space_pressed = threading.Event()
def runTest(self):
self.ui_template.SetTitle(_TITLE)
self.ui_template.SetState(_STATE_HTML)
self.ui.BindKey(test_ui.SPACE_KEY, lambda _: self.space_pressed.set())
process_utils.StartDaemonThread(target=self.SetInterfaces)
self.ui.Run()
def SetInterfaces(self):
try:
settings = config_utils.LoadConfig(config_name=self.args.config_name,
schema_name='network_config')
proxy = state.get_instance()
if not proxy.IsPluginRunning('connection_manager'):
logging.info('Goofy plugin %r is not running, create our own instance')
proxy = connection_manager.ConnectionManager()
for interface in settings:
interface_name = settings[interface].pop('interface_name', interface)
self.ui.SetHTML(_GetSubtitleForInterface(interface),
id=_ID_SUBTITLE_DIV)
def _TryOnce(interface=interface, interface_name=interface_name):
error_code = proxy.SetStaticIP(interface_or_path=interface,
**settings[interface])
if error_code is None:
return True
# Hint operators what might go wrong.
self.ui.SetHTML(_ErrorCodeToMessage(error_code, interface_name),
id=_ID_MESSAGE_DIV)
# Try once first, if we success, we don't need to ask operators to do
# anything.
try:
success = _TryOnce()
except Exception:
success = False
if not success:
# Failed, wait operators to press space when they think cables are
# connected correctly.
self.ui.SetHTML(_PRESS_SPACE, id=_ID_INSTRUCTION_DIV)
self.space_pressed.clear()
self.space_pressed.wait()
# Polling until success or timeout (operators don't need to press
# space anymore).
sync_utils.PollForCondition(_TryOnce,
timeout_secs=self.args.timeout_secs)
self.ui.Pass()
except: # pylint: disable=bare-except
self.ui.Fail(traceback.format_exc())