Skip to content

Commit

Permalink
Added zapper-automated testplan to SRU (New) (#764)
Browse files Browse the repository at this point in the history
* Add: zapper-enabled jobs to sru testplans

* Fix: zapper capabilities returns an empty list in case of missing connection/host
  • Loading branch information
p-gentili authored Oct 18, 2023
1 parent 1aa81f0 commit f867f60
Show file tree
Hide file tree
Showing 5 changed files with 90 additions and 37 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,11 @@
from unittest import TestCase
from unittest.mock import Mock, patch

from checkbox_support.scripts.zapper_proxy import get_capabilities, zapper_run
from checkbox_support.scripts.zapper_proxy import (
get_capabilities,
zapper_run,
main,
)


class ZapperProxyV1Tests(TestCase):
Expand All @@ -43,7 +47,6 @@ def test_zapper_run_smoke(self, import_mock):
result = zapper_run("0.0.0.0", "command", *args, **kwargs)
self._mocked_conn.root.command.assert_called_once_with(*args, **kwargs)
assert result == "test"


@patch("checkbox_support.scripts.zapper_proxy.import_module")
def test_zapper_run_wrong_cmd(self, import_mock):
Expand All @@ -55,6 +58,15 @@ def test_zapper_run_wrong_cmd(self, import_mock):
with self.assertRaises(SystemExit):
zapper_run("0.0.0.0", "command")

@patch("checkbox_support.scripts.zapper_proxy.import_module")
def test_zapper_run_missing_rpyc(self, import_mock):
"""
Check if SystemExit is raised when RPyC cannot be imported.
"""
import_mock.side_effect = ImportError
with self.assertRaises(SystemExit):
zapper_run("0.0.0.0", "command")

@patch("checkbox_support.scripts.zapper_proxy.import_module")
def test_zapper_run_service_error(self, import_mock):
"""
Expand All @@ -64,6 +76,7 @@ def test_zapper_run_service_error(self, import_mock):

class TestException(Exception):
pass

self._rpyc_mock.core.vinegar.GenericException = TestException
self._mocked_conn.root.command.side_effect = TestException()

Expand All @@ -83,7 +96,6 @@ def test_zapper_run_connection_error(self, import_mock):
with self.assertRaises(SystemExit):
zapper_run("0.0.0.0", "command")
assert self._rpyc_mock.connect.call_count == 2


@patch("checkbox_support.scripts.zapper_proxy.import_module")
def test_get_capabilities_one_cap(self, import_mock):
Expand All @@ -95,12 +107,26 @@ def test_get_capabilities_one_cap(self, import_mock):
"""
import_mock.return_value = self._rpyc_mock

ret_val = [{'foo': 'bar'}]
ret_val = [{"foo": "bar"}]
self._mocked_conn.root.get_capabilities = Mock(return_value=ret_val)

with patch('builtins.print') as mocked_print:
with patch("builtins.print") as mocked_print:
get_capabilities("0.0.0.0")
mocked_print.assert_called_once_with('foo: bar')
mocked_print.assert_called_once_with("foo: bar")

@patch("checkbox_support.scripts.zapper_proxy.import_module")
def test_get_capabilities_error(self, import_mock):
"""
Check if get_capabilities prints nothing on error while
fetching capabilities.
"""
import_mock.return_value = self._rpyc_mock

self._mocked_conn.root.get_capabilities.side_effect = AttributeError

with patch("builtins.print") as mocked_print:
get_capabilities("0.0.0.0")
mocked_print.assert_called_once_with("")

@patch("checkbox_support.scripts.zapper_proxy.import_module")
def test_get_capabilities_empty(self, import_mock):
Expand All @@ -109,9 +135,9 @@ def test_get_capabilities_empty(self, import_mock):

ret_val = []
self._mocked_conn.root.get_capabilities = Mock(return_value=ret_val)
with patch('builtins.print') as mocked_print:
with patch("builtins.print") as mocked_print:
get_capabilities("0.0.0.0")
mocked_print.assert_called_once_with('')
mocked_print.assert_called_once_with("")

@patch("checkbox_support.scripts.zapper_proxy.import_module")
def test_get_capabilities_multiple_caps(self, import_mock):
Expand All @@ -123,12 +149,12 @@ def test_get_capabilities_multiple_caps(self, import_mock):
"""
import_mock.return_value = self._rpyc_mock

ret_val = [{'foo': 'bar'}, {'baz': 'biz'}]
ret_val = [{"foo": "bar"}, {"baz": "biz"}]
self._mocked_conn.root.get_capabilities = Mock(return_value=ret_val)

with patch('builtins.print') as mocked_print:
with patch("builtins.print") as mocked_print:
get_capabilities("0.0.0.0")
mocked_print.assert_called_once_with('foo: bar\n\nbaz: biz')
mocked_print.assert_called_once_with("foo: bar\n\nbaz: biz")

@patch("checkbox_support.scripts.zapper_proxy.import_module")
def test_get_capabilities_one_cap_multi_rows(self, import_mock):
Expand All @@ -140,9 +166,25 @@ def test_get_capabilities_one_cap_multi_rows(self, import_mock):
"""
import_mock.return_value = self._rpyc_mock

ret_val = [{'foo': 'bar', 'foo2': 'bar2'}]
ret_val = [{"foo": "bar", "foo2": "bar2"}]
self._mocked_conn.root.get_capabilities = Mock(return_value=ret_val)

with patch('builtins.print') as mocked_print:
with patch("builtins.print") as mocked_print:
get_capabilities("0.0.0.0")
mocked_print.assert_called_once_with('foo: bar\nfoo2: bar2')
mocked_print.assert_called_once_with("foo: bar\nfoo2: bar2")

@patch("checkbox_support.scripts.zapper_proxy.zapper_run")
def test_main_run(self, mock_run):
"""
Check if main calls zapper_run with proper parameters.
"""
main(["command", "arg1", "arg2", "--host", "myhost"])
mock_run.assert_called_once_with("myhost", "command", "arg1", "arg2")

@patch("checkbox_support.scripts.zapper_proxy.get_capabilities")
def test_main_capabilities(self, mock_cap):
"""
Check if main calls get_capabilities with zapper host.
"""
main(["get_capabilities", "arg1", "arg2", "--host", "myhost"])
mock_cap.assert_called_once_with("myhost")
54 changes: 31 additions & 23 deletions checkbox-support/checkbox_support/scripts/zapper_proxy.py
Original file line number Diff line number Diff line change
Expand Up @@ -40,18 +40,17 @@ def zapper_run(host, cmd, *args, **kwargs):
or a service error occurs
"""
try:
_rpyc = import_module('rpyc')
_rpyc = import_module("rpyc")
except ImportError:
try:
_rpyc = import_module('plainbox.vendor.rpyc')
_rpyc = import_module("plainbox.vendor.rpyc")
except ImportError as exc:
msg = "RPyC not found. Neither from sys nor from Checkbox"
raise SystemExit(msg) from exc

for _ in range(2):
try:
conn = _rpyc.connect(
host, 60000, config={"allow_all_attrs": True})
conn = _rpyc.connect(host, 60000, config={"allow_all_attrs": True})
break
except ConnectionRefusedError:
time.sleep(1)
Expand All @@ -61,36 +60,45 @@ def zapper_run(host, cmd, *args, **kwargs):
try:
return getattr(conn.root, cmd)(*args, **kwargs)
except AttributeError:
raise SystemExit("Zapper host does not provide a '{}' command.".format(cmd))
raise SystemExit(
"Zapper host does not provide a '{}' command.".format(cmd)
)
except _rpyc.core.vinegar.GenericException as exc:
raise SystemExit("Zapper host failed to process the requested command.") from exc
raise SystemExit(
"Zapper host failed to process the requested command."
) from exc


def get_capabilities(host):
"""Get Zapper capabilities."""
capabilities = zapper_run(host, "get_capabilities")
try:
capabilities = zapper_run(host, "get_capabilities")
except SystemExit:
capabilities = []

def stringify_cap(cap):
return '\n'.join(
'{}: {}'.format(key, val) for key, val in sorted(cap.items()))
print('\n\n'.join(stringify_cap(cap) for cap in capabilities))
return "\n".join(
"{}: {}".format(key, val) for key, val in sorted(cap.items())
)

print("\n\n".join(stringify_cap(cap) for cap in capabilities))


def main():
def main(arguments=None):
"""Entry point."""

parser = argparse.ArgumentParser()
parser.add_argument(
'--host', default=os.environ.get('ZAPPER_HOST'),
help=("Address of Zapper to connect to. If not supplied, "
"ZAPPER_HOST environment variable will be used.")
"--host",
default=os.environ.get("ZAPPER_HOST"),
help=(
"Address of Zapper to connect to. If not supplied, "
"ZAPPER_HOST environment variable will be used."
),
)
parser.add_argument('cmd')
parser.add_argument('args', nargs="*")
args = parser.parse_args()

if args.host is None:
raise SystemExit(
"You have to provide Zapper host, either via '--host' or via "
"ZAPPER_HOST environment variable")
parser.add_argument("cmd")
parser.add_argument("args", nargs="*")
args = parser.parse_args(arguments)

if args.cmd == "get_capabilities":
get_capabilities(args.host)
Expand All @@ -99,5 +107,5 @@ def main():
print(result)


if __name__ == '__main__':
if __name__ == "__main__":
main()
1 change: 1 addition & 0 deletions providers/base/units/zapper/jobs.pxu
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,7 @@ command: bt_a2dp.py "$ZAPPER_HOST"
depends: bluetooth/detect-output

id: input/zapper-keyboard
requires: zapper_capabilities.capability == 'hid'
category_id: com.canonical.plainbox::input
plugin: shell
user: root
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -138,6 +138,7 @@ nested_part:
wireless-automated
wireless-wifi-master-mode-auto
wwan-automated
zapper-enabled-automated
after-suspend-audio-automated
after-suspend-bluez-automated
after-suspend-ethernet-automated
Expand Down
1 change: 1 addition & 0 deletions providers/sru/units/sru.pxu
Original file line number Diff line number Diff line change
Expand Up @@ -150,6 +150,7 @@ nested_part:
monitor-discrete-gpu-cert-automated
graphics-integrated-gpu-cert-automated
graphics-discrete-gpu-cert-automated
zapper-enabled-automated
# start of suspend related tests
before-suspend-reference-cert-full
# suspend point
Expand Down

0 comments on commit f867f60

Please sign in to comment.