diff --git a/.github/workflows/tox-checkbox-support.yaml b/.github/workflows/tox-checkbox-support.yaml index 5aac5e3ad2..56e6b82600 100644 --- a/.github/workflows/tox-checkbox-support.yaml +++ b/.github/workflows/tox-checkbox-support.yaml @@ -49,6 +49,10 @@ jobs: PIP_TRUSTED_HOST: pypi.python.org pypi.org files.pythonhosted.org - name: Install tox run: pip install tox + - name: Install libsystemd-dev + run: | + sudo apt-get update + sudo apt-get install -y libsystemd-dev - name: Run tox run: tox -e${{ matrix.tox_env_name }} - name: Upload coverage reports to Codecov diff --git a/.github/workflows/tox-provider-base.yaml b/.github/workflows/tox-provider-base.yaml index db8dde3b11..160beb40fb 100644 --- a/.github/workflows/tox-provider-base.yaml +++ b/.github/workflows/tox-provider-base.yaml @@ -47,6 +47,10 @@ jobs: python-version: ${{ matrix.python }} env: PIP_TRUSTED_HOST: pypi.python.org pypi.org files.pythonhosted.org + - name: Install libsystemd-dev + run: | + sudo apt-get update + sudo apt-get install -y libsystemd-dev - name: Install tox run: pip install tox - name: Run tox diff --git a/.github/workflows/tox-provider-genio.yaml b/.github/workflows/tox-provider-genio.yaml index a3ea250090..291a148e19 100644 --- a/.github/workflows/tox-provider-genio.yaml +++ b/.github/workflows/tox-provider-genio.yaml @@ -48,6 +48,10 @@ jobs: python-version: ${{ matrix.python }} env: PIP_TRUSTED_HOST: pypi.python.org pypi.org files.pythonhosted.org + - name: Install libsystemd-dev + run: | + sudo apt-get update + sudo apt-get install -y libsystemd-dev - name: Install tox run: pip install tox - name: Run tox diff --git a/checkbox-support/checkbox_support/scripts/run_watcher.py b/checkbox-support/checkbox_support/scripts/run_watcher.py index e631851cce..ddf915dbd8 100644 --- a/checkbox-support/checkbox_support/scripts/run_watcher.py +++ b/checkbox-support/checkbox_support/scripts/run_watcher.py @@ -9,17 +9,17 @@ this script monitors the systemd journal to catch insert/removal USB events """ import argparse -import contextlib import logging import os +import pathlib import re import select -import signal import sys import time from systemd import journal from abc import ABC, abstractmethod +from checkbox_support.helpers.timeout import timeout from checkbox_support.scripts.zapper_proxy import zapper_run @@ -27,6 +27,8 @@ logger.setLevel(logging.INFO) logger.addHandler(logging.StreamHandler(sys.stdout)) +ACTION_TIMEOUT = 30 + class StorageInterface(ABC): """ @@ -35,362 +37,349 @@ class StorageInterface(ABC): """ @abstractmethod - def do_callback(self, line_str): + def _parse_journal_line(self, line_str): """ - do_callback handles the line string from journal. + Parse the journal line and update the attributes based on the line + content. + + :param line_str: str of the scanned log lines. """ pass @abstractmethod - def report_insertion(self): + def _validate_insertion(self): + """ + Check if the that the storage was inserted correctly. + """ pass @abstractmethod - def report_removal(self): + def _validate_removal(self): + """ + Check if the that the storage was removed correctly. + """ pass -class StorageWatcher: +class StorageWatcher(StorageInterface): """ - StorageWatcher watches the journal message and triggeres the callback + StorageWatcher watches the journal message and triggers the callback function to detect the insertion and removal of storage. - """ - ACTION_TIMEOUT = 30 # sec - logger.info("Timeout: {} seconds".format(ACTION_TIMEOUT)) - - def __init__(self, args, storage_strategy): - self.args = args - self._storage_strategy = storage_strategy - signal.signal(signal.SIGALRM, self._no_storage_timeout) - signal.alarm(self.ACTION_TIMEOUT) + def __init__(self, testcase, storage_type, zapper_usb_address): + self.testcase = testcase + self.storage_type = storage_type + self.zapper_usb_address = zapper_usb_address def run(self): j = journal.Reader() j.seek_realtime(time.time()) p = select.poll() p.register(j, j.get_events()) - if self.args.zapper_usb_address: + if self.zapper_usb_address: zapper_host = os.environ.get("ZAPPER_ADDRESS") if not zapper_host: raise SystemExit( "ZAPPER_ADDRESS environment variable not found!" ) - usb_address = self.args.zapper_usb_address - if self.args.testcase == "insertion": + usb_address = self.zapper_usb_address + if self.testcase == "insertion": print("Calling zapper to connect the USB device") zapper_run( zapper_host, "typecmux_set_state", usb_address, "DUT" ) - elif self.args.testcase == "removal": + elif self.testcase == "removal": print("Calling zapper to disconnect the USB device") zapper_run( zapper_host, "typecmux_set_state", usb_address, "OFF" ) else: - if self.args.testcase == "insertion": + if self.testcase == "insertion": print("\n\nINSERT NOW\n\n", flush=True) - elif self.args.testcase == "removal": + elif self.testcase == "removal": print("\n\nREMOVE NOW\n\n", flush=True) + else: + raise SystemExit("Invalid test case") + print("Timeout: {} seconds".format(ACTION_TIMEOUT), flush=True) while p.poll(): if j.process() != journal.APPEND: continue - self._callback([e["MESSAGE"] for e in j if e and "MESSAGE" in e]) + self._process_lines( + [e["MESSAGE"] for e in j if e and "MESSAGE" in e] + ) - def _callback(self, lines): + def _process_lines(self, lines): + """ + Process the lines from the journal and call the callback function to + validate the insertion or removal of the storage. + """ for line in lines: line_str = str(line) logger.debug(line_str) - self._storage_strategy.do_callback(line_str) - - def _no_storage_timeout(self, signum, frame): + if self.testcase == "insertion": + self._parse_journal_line(line_str) + self._validate_insertion() + elif self.testcase == "removal": + self._parse_journal_line(line_str) + self._validate_removal() + + def _store_storage_info(self, mounted_partition=""): """ - define timeout feature. - - timeout and return failure if there is no usb insertion/removal - detected after ACTION_TIMEOUT secs + Store the mounted partition info to the shared directory. """ - logger.error( - "no {} storage {} was reported in systemd journal".format( - self.args.storage_type, self.args.testcase + + plainbox_session_share = os.environ.get("PLAINBOX_SESSION_SHARE") + # TODO: Should name the file by the value of storage_type variable as + # prefix. e.g. thunderbolt_insert_info, mediacard_insert_info. + # Since usb_insert_info is used by usb_read_write script, we + # should refactor usb_read_write script to adopt different files + file_name = "usb_insert_info" + + if not plainbox_session_share: + logger.error("no env var PLAINBOX_SESSION_SHARE") + sys.exit(1) + + # backup the storage partition info + if mounted_partition: + logger.info( + "cache file {} is at: {}".format( + file_name, plainbox_session_share + ) ) - ) - sys.exit(1) + file_path = pathlib.Path(plainbox_session_share, file_name) + with open(file_path, "w") as file_to_share: + file_to_share.write(mounted_partition + "\n") + + def _remove_storage_info(self): + """Remove the file containing the storage info from the shared + directory. + """ + + plainbox_session_share = os.environ.get("PLAINBOX_SESSION_SHARE") + file_name = "usb_insert_info" + if not plainbox_session_share: + logger.error("no env var PLAINBOX_SESSION_SHARE") + sys.exit(1) -class USBStorage(StorageInterface): + file_path = pathlib.Path(plainbox_session_share, file_name) + if pathlib.Path(file_path).exists(): + os.remove(file_path) + logger.info("cache file {} removed".format(file_name)) + else: + logger.error("cache file {} not found".format(file_name)) + + +class USBStorage(StorageWatcher): """ - USBStorage hanldes the insertion and removal of usb2, usb3 and mediacard. + USBStorage handles the insertion and removal of usb2 and usb3. """ - MOUNTED_PARTITION = None - FLAG_DETECTION = { - "device": { - "new high-speed USB device number": False, - "new SuperSpeed USB device number": False, - "new SuperSpeed Gen 1 USB device number": False, - }, - "driver": {"using ehci_hcd": False, "using xhci_hcd": False}, - "insertion": {"USB Mass Storage device detected": False}, - "removal": {"USB disconnect, device number": False}, - } - - def __init__(self, args): - self.args = args - - def do_callback(self, line_str): - self._refresh_detection(line_str) - self._get_partition_info(line_str) - self._report_detection() - - def report_insertion(self): - if ( - self.MOUNTED_PARTITION - and self.FLAG_DETECTION["insertion"][ - "USB Mass Storage device detected" - ] - ): - device = "" - driver = "" - for key in self.FLAG_DETECTION["device"]: - if self.FLAG_DETECTION["device"][key]: - device = key - for key in self.FLAG_DETECTION["driver"]: - if self.FLAG_DETECTION["driver"][key]: - driver = key - logger.info("{} was inserted {} controller".format(device, driver)) - logger.info("usable partition: {}".format(self.MOUNTED_PARTITION)) - # judge the detection by the expection - if ( - self.args.storage_type == "usb2" - and device == "new high-speed USB device number" - ): - logger.info("USB2 insertion test passed.") - - if self.args.storage_type == "usb3" and ( - device - in ( - "new SuperSpeed USB device number", - "new SuperSpeed Gen 1 USB device number", + def __init__(self, *args): + super().__init__(*args) + self.mounted_partition = None + self.device = None + self.number = None + self.driver = None + self.action = None + + def _validate_insertion(self): + if self.mounted_partition and self.action == "insertion": + logger.info( + "{} was inserted. Controller: {}, Number: {}".format( + self.device, self.driver, self.number ) - ): + ) + logger.info("usable partition: {}".format(self.mounted_partition)) + # judge the detection by the expectation + if self.storage_type == "usb2" and self.device == "high_speed_usb": + logger.info("USB2 insertion test passed.") + elif self.storage_type == "usb3" and self.device in [ + "super_speed_usb", + "super_speed_gen1_usb", + ]: logger.info("USB3 insertion test passed.") + else: + sys.exit("Wrong USB type detected.") # backup the storage info - storage_info_helper( - reserve=True, - storage_type=self.args.storage_type, - mounted_partition=self.MOUNTED_PARTITION, - ) + self._store_storage_info(self.mounted_partition) sys.exit() - def report_removal(self): - if self.FLAG_DETECTION["removal"]["USB disconnect, device number"]: + def _validate_removal(self): + if self.action == "removal": logger.info("Removal test passed.") - # remove the storage info - storage_info_helper(reserve=False, storage_type=self.args.storage_type) - sys.exit() - - def _get_partition_info(self, line_str): - """get partition info.""" - # looking for string like "sdb: sdb1" - part_re = re.compile("sd\w+:.*(?Psd\w+)") - match = re.search(part_re, line_str) - if match: - self.MOUNTED_PARTITION = match.group("part_name") + # remove the storage info + self._remove_storage_info() + sys.exit() - def _refresh_detection(self, line_str): + def _parse_journal_line(self, line_str): """ - refresh values of the dictionary FLAG_DETECTION. + Gets one of the lines from the journal and updates values of the + device, driver, number and action attributes based on the line content. - :param line_str: str of the scanned log lines. + It uses dictionaries to match the expected log lines with the + attributes. """ - for key in self.FLAG_DETECTION.keys(): - for sub_key in self.FLAG_DETECTION[key].keys(): - if sub_key in line_str: - self.FLAG_DETECTION[key][sub_key] = True - def _report_detection(self): - """report detection status.""" - if self.args.testcase == "insertion": - self.report_insertion() - elif self.args.testcase == "removal": - self.report_removal() + device_log_dict = { + "high_speed_usb": "new high-speed USB device", + "super_speed_usb": "new SuperSpeed USB device", + "super_speed_gen1_usb": "new SuperSpeed Gen 1 USB device", + } + + driver_log_dict = { + "ehci_hcd": "using ehci_hcd", + "xhci_hcd": "using xhci_hcd", + } + + # Match the log line with the expected log lines and update the + # corresponding attributes. + for device_type, device_log in device_log_dict.items(): + if device_log in line_str: + self.device = device_type + + for driver_type, driver_log in driver_log_dict.items(): + if driver_log in line_str: + self.driver = driver_type + self.number = re.search( + r"device number (\d+)", line_str + ).group(1) + + # Look for insertion action + if "USB Mass Storage device detected" in line_str: + self.action = "insertion" + + # Look for removal action + if "USB disconnect, device" in line_str: + self.action = "removal" + + # Extract the partition name. Looking for string like "sdb: sdb1" + part_re = re.compile(r"sd\w+:.*(?Psd\w+)") + match = re.search(part_re, line_str) + if match: + self.mounted_partition = match.group("part_name") -class MediacardStorage(StorageInterface): +class MediacardStorage(StorageWatcher): """ MediacardStorage handles the insertion and removal of sd, sdhc, mmc etc... """ - MOUNTED_PARTITION = None - - def __init__(self, args): - self.args = args - - def do_callback(self, line_str): - if self.args.testcase == "insertion": - self._get_partition_info(line_str) - self.report_insertion() - elif self.args.testcase == "removal": - self.report_removal(line_str) - - def report_insertion(self): - if self.MOUNTED_PARTITION: - logger.info("usable partition: {}".format(self.MOUNTED_PARTITION)) + def __init__(self, *args): + super().__init__(*args) + self.mounted_partition = None + self.action = None + self.device = None + self.address = None + + def _validate_insertion(self): + if self.mounted_partition and self.action == "insertion": + logger.info("usable partition: {}".format(self.mounted_partition)) + logger.info( + "{} card inserted. Address: {}".format( + self.device, self.address + ) + ) logger.info("Mediacard insertion test passed.") - sys.exit() - def report_removal(self, line_str): - MMC_RE = re.compile("card [0-9a-fA-F]+ removed") - # since the mmc addr in kernel message is not static, so use - # regex to judge it - match = re.search(MMC_RE, line_str) + # backup the storage info + self._store_storage_info(self.mounted_partition) + sys.exit() - if match: + def _validate_removal(self): + if self.action == "removal": logger.info("Mediacard removal test passed.") - # remove the storage info - storage_info_helper(reserve=False, storage_type=self.args.storage_type) - sys.exit() + # remove the storage info + self._remove_storage_info() + sys.exit() - def _get_partition_info(self, line_str): - """get partition info.""" + def _parse_journal_line(self, line_str): + """ + Gets one of the lines from the journal and updates values of the + mounted_partition attribute based on the line content. + """ - # Match something like "mmcblk0: p1". - part_re = re.compile("mmcblk(?P\d)+: (?Pp\d+)") + # Extract the partition name. Looking for string like "mmcblk0: p1" + part_re = re.compile(r"mmcblk(?P\d)+: (?Pp\d+)") match = re.search(part_re, line_str) if match: - self.MOUNTED_PARTITION = "mmcblk{}{}".format( + self.mounted_partition = "mmcblk{}{}".format( match.group("dev_num"), match.group("part_name") ) - # backup the storage info - storage_info_helper( - reserve=True, - storage_type=self.args.storage_type, - mounted_partition=self.MOUNTED_PARTITION, - ) + # Look for insertion action + insertion_re = re.compile( + r"new (?P.*) card at address (?P
[0-9a-fA-F]+)" + ) + insertion_match = re.search(insertion_re, line_str) + if re.search(insertion_re, line_str): + self.action = "insertion" + self.device = insertion_match.group("device") + self.address = insertion_match.group("address") + + # Look for removal action + removal_re = re.compile(r"card ([0-9a-fA-F]+) removed") + if re.search(removal_re, line_str): + self.action = "removal" -class ThunderboltStorage(StorageInterface): + +class ThunderboltStorage(StorageWatcher): """ ThunderboltStorage handles the insertion and removal of thunderbolt storage. """ - RE_PREFIX = "thunderbolt \d+-\d+:" - - def __init__(self, args): - self.args = args - self.find_insertion_string = 0 - self.find_partition = 0 - - def do_callback(self, line_str): - if self.args.testcase == "insertion": - self._get_partition_info(line_str) - self.report_insertion(line_str) - # The new device string be shown quite early than partition name - # in journal. Thererfore, the insertion will be considered as - # success until the requirement of new device string and partition - # marked as true - if self.find_insertion_string and self.find_partition: - logger.info("Tunderbolt insertion test passed.") - sys.exit() - elif self.args.testcase == "removal": - self.report_removal(line_str) - - def report_insertion(self, line_str): - """ - Find the expected string while thunderbolt storage be inserted. - """ - insert_re = re.compile("{} new device found".format(self.RE_PREFIX)) - match = re.search(insert_re, line_str) - if match: - self.find_insertion_string = 1 - logger.debug("find new thunderbolt device string in journal") + def __init__(self, *args): + super().__init__(*args) + self.mounted_partition = None + self.action = None - def report_removal(self, line_str): - """ - Find the expected string while thunderbolt storage be removed. - """ - remove_re = re.compile("{} device disconnected".format(self.RE_PREFIX)) - match = re.search(remove_re, line_str) - if match: + def _validate_insertion(self): + # The insertion will be valid if the insertion action is detected and + # the mounted partition is found. + if self.action == "insertion" and self.mounted_partition: + logger.info("usable partition: {}".format(self.mounted_partition)) + logger.info("Thunderbolt insertion test passed.") + + # backup the storage info + self._store_storage_info(self.mounted_partition) + sys.exit() + + def _validate_removal(self): + if self.action == "removal": logger.info("Thunderbolt removal test passed.") + # remove the storage info - storage_info_helper( - reserve=False, storage_type=self.args.storage_type - ) + self._remove_storage_info() sys.exit() - def _get_partition_info(self, line_str): - """get partition info.""" - # looking for string like "nvme0n1: p1" - part_re = re.compile("(?Pnvme\w+): (?Pp\d+)") + def _parse_journal_line(self, line_str): + + # Extract the partition name. Looking for string like "nvme0n1: p1" + part_re = re.compile(r"(?Pnvme\w+): (?Pp\d+)") match = re.search(part_re, line_str) if match: - self.find_partition = 1 - # backup the storage info - storage_info_helper( - reserve=True, - storage_type=self.args.storage_type, - mounted_partition="{}{}".format( - match.group("dev_num"), match.group("part_name") - ), + self.mounted_partition = "{}{}".format( + match.group("dev_num"), match.group("part_name") ) + # Prefix of the thunderbolt device for regex matching + RE_PREFIX = r"thunderbolt \d+-\d+:" -def storage_info_helper(reserve, storage_type, mounted_partition=""): - """ - Reserve or removal the detected storage info. - - write the info we got in this script to $PLAINBOX_SESSION_SHARE - so the other jobs, e.g. read/write test, could know more information, - for example the partition it want to try to mount. - - :param reserve: - type: Boolean - - True: backup the info of storage partition to PLAINBOX_SESSION_SHARE - - False: remove the backup file from PLAINBOX_SESSION_SHARE - :param storage_type: - type: String - - Type of storage. e.g. usb, mediacard and thunderbolt - :param mounted_partition: - type: String - - The name of partition. e.g. sda1, nvme1n1p1 etc... - """ - plainbox_session_share = os.environ.get("PLAINBOX_SESSION_SHARE") - if not plainbox_session_share: - logger.error("no env var PLAINBOX_SESSION_SHARE") - sys.exit(1) - - # TODO: Should name the file by the value of storage_type variable as - # prefix. e.g. thunderbolt_insert_info, mediacard_insert_info. - # Since usb_insert_info is used by usb_read_write script, we - # should refactor usb_read_write script to adopt different files - file_name = "usb_insert_info" - - # backup the storage partition info - if reserve and mounted_partition: - logger.info( - "cache file {} is at: {}".format(file_name, plainbox_session_share) - ) - file_to_share = open( - os.path.join(plainbox_session_share, file_name), "w" - ) - file_to_share.write(mounted_partition + "\n") - file_to_share.close() + insertion_re = re.compile(r"{} new device found".format(RE_PREFIX)) + if re.search(insertion_re, line_str): + self.action = "insertion" - # remove the back info - if not reserve: - file_to_share = os.path.join(plainbox_session_share, file_name) - with contextlib.suppress(FileNotFoundError): - os.remove(file_to_share) + removal_re = re.compile(r"{} device disconnected".format(RE_PREFIX)) + if re.search(removal_re, line_str): + self.action = "removal" -def main(): +def launch_watcher(): parser = argparse.ArgumentParser() parser.add_argument( "testcase", @@ -411,13 +400,24 @@ def main(): watcher = None if args.storage_type == "thunderbolt": - watcher = StorageWatcher(args, ThunderboltStorage(args)) + watcher = ThunderboltStorage( + args.testcase, args.storage_type, args.zapper_usb_address + ) elif args.storage_type == "mediacard": - watcher = StorageWatcher(args, MediacardStorage(args)) + watcher = MediacardStorage( + args.testcase, args.storage_type, args.zapper_usb_address + ) else: - watcher = StorageWatcher(args, USBStorage(args)) + watcher = USBStorage( + args.testcase, args.storage_type, args.zapper_usb_address + ) watcher.run() +@timeout(ACTION_TIMEOUT) # 30 seconds timeout +def main(): + launch_watcher() + + if __name__ == "__main__": main() diff --git a/checkbox-support/checkbox_support/scripts/usb_read_write.py b/checkbox-support/checkbox_support/scripts/usb_read_write.py index 0b69ca80ef..0668e8f10d 100644 --- a/checkbox-support/checkbox_support/scripts/usb_read_write.py +++ b/checkbox-support/checkbox_support/scripts/usb_read_write.py @@ -292,6 +292,7 @@ def write_test_unit(random_file, idx=""): ], stderr=subprocess.STDOUT, stdout=subprocess.PIPE, + env={"LC_NUMERIC": "C"}, ) logging.debug("Apply command: %s" % process.args) # will get something like @@ -299,15 +300,16 @@ def write_test_unit(random_file, idx=""): # '1049076 bytes (1.0 MB) copied, 0.00473357 s, 222 MB/s', ''] list_dd_message = process.communicate()[0].decode().split("\n") logging.debug(list_dd_message) - try: - dd_speed = float(list_dd_message[2].split(" ")[-2]) - except: - # Example: - # ['dd: writing to ‘/tmp/tmp08osy45j/tmpnek46on30’: Input/output error' - # , '38913+0 records in', '38912+0 records out', '19922944 bytes - # (20 MB) copied, 99.647 s, 200 kB/s', ''] - print("ERROR: {}".format(list_dd_message)) - sys.exit(1) + + dd_speed = float(list_dd_message[2].split(" ")[-2]) + units = list_dd_message[2].split(" ")[-1] + units_dict = {"kB/s": 1024, "MB/s": 1024**2, "GB/s": 1024**3} + if units in units_dict: + dd_speed_b = dd_speed * units_dict[units] + dd_speed_mb = dd_speed_b / (1024**2) + else: + sys.exit("Unknown units in dd output.") + dmesg = subprocess.run(["dmesg"], stdout=subprocess.PIPE) # lp:1852510 - check there weren't any i/o errors sent to dmesg when the # test files were sync'ed to the disk @@ -317,7 +319,8 @@ def write_test_unit(random_file, idx=""): else: logging.debug("No I/O errors found in dmesg") print("PASS: WRITING TEST: %s" % target_file) - return dd_speed + + return dd_speed_mb @contextlib.contextmanager diff --git a/checkbox-support/checkbox_support/tests/test_run_watcher.py b/checkbox-support/checkbox_support/tests/test_run_watcher.py new file mode 100644 index 0000000000..64d8a65b32 --- /dev/null +++ b/checkbox-support/checkbox_support/tests/test_run_watcher.py @@ -0,0 +1,452 @@ +#!/usr/bin/env python3 +# This file is part of Checkbox. +# +# Copyright 2024 Canonical Ltd. +# Authors: +# Fernando Bravo +# +# Checkbox is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License version 3, +# as published by the Free Software Foundation. +# +# Checkbox is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with Checkbox. If not, see . + +import unittest +from unittest.mock import patch, call, MagicMock, mock_open + +import pathlib +from systemd import journal + +from checkbox_support.scripts.run_watcher import ( + StorageWatcher, + USBStorage, + MediacardStorage, + ThunderboltStorage, + launch_watcher, +) + + +class TestRunWatcher(unittest.TestCase): + + @patch("systemd.journal.Reader") + @patch("select.poll") + def test_storage_watcher_run_insertion(self, mock_poll, mock_journal): + mock_journal.return_value.process.side_effect = [journal.APPEND, None] + mock_journal.return_value.__iter__.return_value = [ + {"MESSAGE": "line1"} + ] + mock_poll.return_value.poll.side_effect = [True, True, False] + + mock_storage_watcher = MagicMock() + mock_storage_watcher.zapper_usb_address = "" + + # Test insertion + mock_storage_watcher.testcase = "insertion" + StorageWatcher.run(mock_storage_watcher) + mock_storage_watcher._process_lines.assert_called_with(["line1"]) + + @patch("systemd.journal.Reader") + @patch("select.poll") + def test_storage_watcher_run_removal(self, mock_poll, mock_journal): + mock_journal.return_value.process.return_value = journal.APPEND + mock_journal.return_value.__iter__.return_value = [ + {"MESSAGE": "line1"} + ] + mock_poll.return_value.poll.side_effect = [True, False] + + mock_storage_watcher = MagicMock() + mock_storage_watcher.zapper_usb_address = "" + + # Test removal + mock_storage_watcher.testcase = "removal" + StorageWatcher.run(mock_storage_watcher) + mock_storage_watcher._process_lines.assert_called_with(["line1"]) + + def test_storage_watcher_run_invalid_testcase(self): + mock_storage_watcher = MagicMock() + mock_storage_watcher.testcase = "invalid" + + with self.assertRaises(SystemExit): + StorageWatcher.run(mock_storage_watcher) + + @patch("systemd.journal.Reader") + @patch("select.poll") + @patch("os.environ.get") + @patch("checkbox_support.scripts.run_watcher.zapper_run") + def test_storage_watcher_run_insertion_with_zapper( + self, mock_zapper_run, mock_get, mock_poll, mock_journal + ): + mock_journal.return_value.process.return_value = journal.APPEND + mock_journal.return_value.__iter__.return_value = [ + {"MESSAGE": "line1"} + ] + mock_poll.return_value.poll.side_effect = [True, False] + mock_get.return_value = "zapper_addr" + + mock_storage_watcher = MagicMock() + mock_storage_watcher.zapper_usb_address = "usb_address" + + # Test insertion with zapper + mock_storage_watcher.testcase = "insertion" + StorageWatcher.run(mock_storage_watcher) + mock_zapper_run.assert_called_with( + "zapper_addr", "typecmux_set_state", "usb_address", "DUT" + ) + mock_storage_watcher._process_lines.assert_called_with(["line1"]) + + @patch("systemd.journal.Reader") + @patch("select.poll") + @patch("os.environ.get") + @patch("checkbox_support.scripts.run_watcher.zapper_run") + def test_storage_watcher_run_removal_with_zapper( + self, mock_zapper_run, mock_get, mock_poll, mock_journal + ): + mock_journal.return_value.process.return_value = journal.APPEND + mock_journal.return_value.__iter__.return_value = [ + {"MESSAGE": "line1"} + ] + mock_poll.return_value.poll.side_effect = [True, False] + mock_get.return_value = "zapper_addr" + + mock_storage_watcher = MagicMock() + mock_storage_watcher.zapper_usb_address = "usb_address" + + # Test removal with zapper + mock_storage_watcher.testcase = "removal" + StorageWatcher.run(mock_storage_watcher) + mock_zapper_run.assert_called_with( + "zapper_addr", "typecmux_set_state", "usb_address", "OFF" + ) + mock_storage_watcher._process_lines.assert_called_with(["line1"]) + + def test_storage_watcher_process_lines_insertion(self): + lines = ["line1", "line2", "line3"] + + mock_insertion_watcher = MagicMock() + mock_insertion_watcher._parse_journal_line = MagicMock() + mock_insertion_watcher.testcase = "insertion" + StorageWatcher._process_lines(mock_insertion_watcher, lines) + mock_insertion_watcher._parse_journal_line.assert_has_calls( + [call("line1"), call("line2"), call("line3")] + ) + + def test_storage_watcher_process_lines_removal(self): + lines = ["line1", "line2", "line3"] + + mock_removal_watcher = MagicMock() + mock_removal_watcher._parse_journal_line = MagicMock() + mock_removal_watcher.testcase = "removal" + StorageWatcher._process_lines(mock_removal_watcher, lines) + mock_removal_watcher._parse_journal_line.assert_has_calls( + [call("line1"), call("line2"), call("line3")] + ) + + @patch("os.environ.get") + def test_storage_watcher_store_storage_info(self, mock_get): + mock_storage_watcher = MagicMock() + mock_get.return_value = "/tmp" + + mock_storage_watcher.storage_type = "usb2" + mounted_partition = "sda1" + + m = mock_open() + with patch("builtins.open", m): + StorageWatcher._store_storage_info( + mock_storage_watcher, mounted_partition + ) + + m.assert_called_with(pathlib.Path("/tmp", "usb_insert_info"), "w") + m().write.assert_called_with("sda1\n") + + @patch("os.environ.get") + def test_storage_watcher_store_storage_info_no_session(self, mock_get): + mock_storage_watcher = MagicMock() + mock_get.return_value = None + + with self.assertRaises(SystemExit): + StorageWatcher._store_storage_info(mock_storage_watcher) + + @patch("pathlib.Path.exists") + @patch("os.remove") + @patch("os.environ.get") + def test_storage_watcher_remove_storage_info( + self, mock_get, mock_remove, mock_exists + ): + mock_storage_watcher = MagicMock() + mock_get.return_value = "/tmp" + mock_exists.return_value = True + + StorageWatcher._remove_storage_info(mock_storage_watcher) + + mock_remove.assert_called_with(pathlib.Path("/tmp", "usb_insert_info")) + + @patch("pathlib.Path.exists") + @patch("os.remove") + @patch("os.environ.get") + def test_storage_watcher_remove_storage_info_no_file( + self, mock_get, mock_remove, mock_exists + ): + mock_storage_watcher = MagicMock() + mock_get.return_value = "/tmp" + mock_exists.return_value = False + + StorageWatcher._remove_storage_info(mock_storage_watcher) + + mock_remove.assert_not_called() + + @patch("os.environ.get") + def test_storage_watcher_remove_storage_info_no_session(self, mock_get): + mock_storage_watcher = MagicMock() + mock_get.return_value = None + + with self.assertRaises(SystemExit): + StorageWatcher._remove_storage_info(mock_storage_watcher) + + def test_usb_storage_init(self): + usb_storage = USBStorage("insertion", "usb2", "zapper_addr") + self.assertEqual(usb_storage.testcase, "insertion") + self.assertEqual(usb_storage.storage_type, "usb2") + self.assertEqual(usb_storage.zapper_usb_address, "zapper_addr") + self.assertIsNone(usb_storage.mounted_partition) + self.assertIsNone(usb_storage.device) + self.assertIsNone(usb_storage.number) + self.assertIsNone(usb_storage.driver) + self.assertIsNone(usb_storage.action) + + def test_usb2_storage_validate_insertion(self): + mock_usb_storage = MagicMock() + mock_usb_storage.storage_type = "usb2" + mock_usb_storage.device = "high_speed_usb" + mock_usb_storage.mounted_partition = "mounted_partition" + mock_usb_storage.action = "insertion" + mock_usb_storage.driver = "ehci_hcd" + with self.assertRaises(SystemExit) as cm: + USBStorage._validate_insertion(mock_usb_storage) + self.assertEqual(cm.exception.code, None) + + def test_usb3_storage_validate_insertion(self): + mock_usb_storage = MagicMock() + mock_usb_storage.storage_type = "usb3" + mock_usb_storage.device = "super_speed_usb" + mock_usb_storage.mounted_partition = "mounted_partition" + mock_usb_storage.action = "insertion" + mock_usb_storage.driver = "xhci_hcd" + with self.assertRaises(SystemExit) as cm: + USBStorage._validate_insertion(mock_usb_storage) + self.assertEqual(cm.exception.code, None) + + def test_usb_storage_validate_insertion_wrong_usb_type(self): + mock_usb_storage = MagicMock() + mock_usb_storage.storage_type = "usb2" + mock_usb_storage.device = "super_speed_usb" + mock_usb_storage.mounted_partition = "mounted_partition" + mock_usb_storage.action = "insertion" + mock_usb_storage.driver = "ehci_hcd" + with self.assertRaises(SystemExit) as cm: + USBStorage._validate_insertion(mock_usb_storage) + cm.exception.args[0] == "Wrong USB type detected." + + def test_usb_storage_validate_removal(self): + mock_usb_storage = MagicMock() + mock_usb_storage.action = "removal" + with self.assertRaises(SystemExit) as cm: + USBStorage._validate_removal(mock_usb_storage) + self.assertEqual(cm.exception.code, None) + + def test_usb_storage_no_insertion(self): + mock_usb_storage = MagicMock() + mock_usb_storage.mounted_partition = None + mock_usb_storage.action = "" + USBStorage._validate_insertion(mock_usb_storage) + + def test_usb_storage_no_removal(self): + mock_usb_storage = MagicMock() + mock_usb_storage.action = "" + USBStorage._validate_removal(mock_usb_storage) + + def test_usb_storage_parse_journal_line(self): + mock_usb_storage = MagicMock() + + line_str = "new high-speed USB device" + USBStorage._parse_journal_line(mock_usb_storage, line_str) + self.assertEqual(mock_usb_storage.device, "high_speed_usb") + + line_str = "new SuperSpeed USB device" + USBStorage._parse_journal_line(mock_usb_storage, line_str) + self.assertEqual(mock_usb_storage.device, "super_speed_usb") + + line_str = "new SuperSpeed Gen 1 USB device" + USBStorage._parse_journal_line(mock_usb_storage, line_str) + self.assertEqual(mock_usb_storage.device, "super_speed_gen1_usb") + + line_str = "new high-speed USB device number 1 using ehci_hcd" + USBStorage._parse_journal_line(mock_usb_storage, line_str) + self.assertEqual(mock_usb_storage.driver, "ehci_hcd") + + line_str = "new high-speed USB device number 4 using xhci_hcd" + USBStorage._parse_journal_line(mock_usb_storage, line_str) + self.assertEqual(mock_usb_storage.driver, "xhci_hcd") + + line_str = "USB Mass Storage device detected" + USBStorage._parse_journal_line(mock_usb_storage, line_str) + self.assertEqual(mock_usb_storage.action, "insertion") + + line_str = "USB disconnect, device" + USBStorage._parse_journal_line(mock_usb_storage, line_str) + self.assertEqual(mock_usb_storage.action, "removal") + + line_str = "sdb: sdb1" + USBStorage._parse_journal_line(mock_usb_storage, line_str) + self.assertEqual(mock_usb_storage.mounted_partition, "sdb1") + + def test_mediacard_storage_init(self): + mediacard_storage = MediacardStorage( + "insertion", "mediacard", "zapper_addr" + ) + self.assertEqual(mediacard_storage.testcase, "insertion") + self.assertEqual(mediacard_storage.storage_type, "mediacard") + self.assertEqual(mediacard_storage.zapper_usb_address, "zapper_addr") + self.assertIsNone(mediacard_storage.mounted_partition) + + def test_mediacard_storage_validate_insertion(self): + mock_mediacard_storage = MagicMock() + mock_mediacard_storage.mounted_partition = "mmcblk0p1" + mock_mediacard_storage.action = "insertion" + mock_mediacard_storage.device = "SD" + mock_mediacard_storage.address = "123456" + with self.assertRaises(SystemExit) as cm: + MediacardStorage._validate_insertion(mock_mediacard_storage) + self.assertEqual(cm.exception.code, None) + + def test_mediacard_storage_validate_removal(self): + mock_mediacard_storage = MagicMock() + mock_mediacard_storage.action = "removal" + with self.assertRaises(SystemExit) as cm: + MediacardStorage._validate_removal(mock_mediacard_storage) + self.assertEqual(cm.exception.code, None) + + def test_mediacard_storage_no_insertion(self): + mock_mediacard_storage = MagicMock() + mock_mediacard_storage.mounted_partition = None + mock_mediacard_storage.action = "" + MediacardStorage._validate_insertion(mock_mediacard_storage) + + def test_mediacard_storage_no_removal(self): + mock_mediacard_storage = MagicMock() + mock_mediacard_storage.action = "" + MediacardStorage._validate_removal(mock_mediacard_storage) + + def test_mediacard_storage_parse_journal_line(self): + mock_mediacard_storage = MagicMock() + + line_str = "mmcblk0: p1" + MediacardStorage._parse_journal_line(mock_mediacard_storage, line_str) + self.assertEqual(mock_mediacard_storage.mounted_partition, "mmcblk0p1") + + line_str = "new SD card at address 123456" + MediacardStorage._parse_journal_line(mock_mediacard_storage, line_str) + self.assertEqual(mock_mediacard_storage.action, "insertion") + self.assertEqual(mock_mediacard_storage.device, "SD") + self.assertEqual(mock_mediacard_storage.address, "123456") + + line_str = "card 123456 removed" + MediacardStorage._parse_journal_line(mock_mediacard_storage, line_str) + self.assertEqual(mock_mediacard_storage.action, "removal") + + def test_thunderbolt_storage_init(self): + thunderbolt_storage = ThunderboltStorage( + "insertion", "thunderbolt", "zapper_addr" + ) + self.assertEqual(thunderbolt_storage.testcase, "insertion") + self.assertEqual(thunderbolt_storage.storage_type, "thunderbolt") + self.assertEqual(thunderbolt_storage.zapper_usb_address, "zapper_addr") + self.assertIsNone(thunderbolt_storage.mounted_partition) + self.assertIsNone(thunderbolt_storage.action) + + def test_thunderbolt_storage_validate_insertion(self): + mock_thunderbolt_storage = MagicMock() + mock_thunderbolt_storage.mounted_partition = "nvme0n1p1" + mock_thunderbolt_storage.action = "insertion" + with self.assertRaises(SystemExit) as cm: + ThunderboltStorage._validate_insertion(mock_thunderbolt_storage) + self.assertEqual(cm.exception.code, None) + + def test_thunderbolt_storage_validate_removal(self): + mock_thunderbolt_storage = MagicMock() + mock_thunderbolt_storage.action = "removal" + with self.assertRaises(SystemExit) as cm: + ThunderboltStorage._validate_removal(mock_thunderbolt_storage) + self.assertEqual(cm.exception.code, None) + + def test_thunderbolt_storage_no_insertion(self): + mock_thunderbolt_storage = MagicMock() + mock_thunderbolt_storage.mounted_partition = None + mock_thunderbolt_storage.action = "" + ThunderboltStorage._validate_insertion(mock_thunderbolt_storage) + + def test_thunderbolt_storage_no_removal(self): + mock_thunderbolt_storage = MagicMock() + mock_thunderbolt_storage.action = "" + ThunderboltStorage._validate_removal(mock_thunderbolt_storage) + + def test_thunderbolt_storage_parse_journal_line(self): + mock_thunderbolt_storage = MagicMock() + + line_str = "nvme0n1: p1" + ThunderboltStorage._parse_journal_line( + mock_thunderbolt_storage, line_str + ) + self.assertEqual( + mock_thunderbolt_storage.mounted_partition, "nvme0n1p1" + ) + + line_str = "thunderbolt 1-1: new device found" + ThunderboltStorage._parse_journal_line( + mock_thunderbolt_storage, line_str + ) + self.assertEqual(mock_thunderbolt_storage.action, "insertion") + + line_str = "thunderbolt 1-1: device disconnected" + ThunderboltStorage._parse_journal_line( + mock_thunderbolt_storage, line_str + ) + self.assertEqual(mock_thunderbolt_storage.action, "removal") + + @patch("checkbox_support.scripts.run_watcher.USBStorage", spec=USBStorage) + def test_main_usb(self, mock_usb_storage): + with patch("sys.argv", ["run_watcher.py", "insertion", "usb2"]): + launch_watcher() + # get the watcher object from main + watcher = mock_usb_storage.return_value + # check that the watcher is an USBStorage object + self.assertIsInstance(watcher, USBStorage) + + @patch( + "checkbox_support.scripts.run_watcher.MediacardStorage", + spec=MediacardStorage, + ) + def test_main_mediacard(self, mock_mediacard_storage): + with patch("sys.argv", ["run_watcher.py", "insertion", "mediacard"]): + launch_watcher() + # get the watcher object from main + watcher = mock_mediacard_storage.return_value + # check that the watcher is an MediacardStorage object + self.assertIsInstance(watcher, MediacardStorage) + + @patch( + "checkbox_support.scripts.run_watcher.ThunderboltStorage", + spec=ThunderboltStorage, + ) + def test_main_thunderbolt(self, mock_thunderbolt_storage): + with patch("sys.argv", ["run_watcher.py", "insertion", "thunderbolt"]): + launch_watcher() + # get the watcher object from main + watcher = mock_thunderbolt_storage.return_value + # check that the watcher is an ThunderboltStorage object + self.assertIsInstance(watcher, ThunderboltStorage) diff --git a/checkbox-support/checkbox_support/tests/test_usb_read_write.py b/checkbox-support/checkbox_support/tests/test_usb_read_write.py new file mode 100644 index 0000000000..fab3f588c5 --- /dev/null +++ b/checkbox-support/checkbox_support/tests/test_usb_read_write.py @@ -0,0 +1,113 @@ +#!/usr/bin/env python3 +# This file is part of Checkbox. +# +# Copyright 2024 Canonical Ltd. +# Authors: +# Fernando Bravo +# +# Checkbox is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License version 3, +# as published by the Free Software Foundation. +# +# Checkbox is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with Checkbox. If not, see . + +import unittest +from unittest.mock import patch, MagicMock +import subprocess + + +from checkbox_support.scripts.usb_read_write import ( + write_test_unit, +) + + +class TestUsbReadWrite(unittest.TestCase): + + @patch("os.path") + @patch("subprocess.Popen") + @patch("subprocess.check_output") + @patch("subprocess.run") + def test_write_test_unit( + self, mock_run, mock_check_output, mock_popen, mock_os + ): + mock_os.join.return_value = "output_file" + + mock_process = MagicMock() + mock_process.communicate.return_value = ( + b"2048+1 records in\n2048+1 records out\n1049076 bytes (1.0 MB) " + b"copied, 0.00473357 s, 222 MB/s\n", + None, + ) + mock_popen.return_value = mock_process + + random_file = MagicMock() + random_file.tfile.name = "random_file" + write_test_unit(random_file) + + mock_popen.assert_called_once_with( + [ + "dd", + "if=random_file", + "of=output_file", + "bs=1M", + "oflag=sync", + ], + stderr=subprocess.STDOUT, + stdout=subprocess.PIPE, + env={"LC_NUMERIC": "C"}, + ) + mock_popen.return_value.communicate.assert_called_with() + + @patch("os.path") + @patch("subprocess.Popen") + @patch("subprocess.check_output") + @patch("subprocess.run") + def test_write_test_unit_wrong_units( + self, mock_run, mock_check_output, mock_popen, mock_os + ): + mock_os.join.return_value = "output_file" + + mock_process = MagicMock() + mock_process.communicate.return_value = ( + b"2048+1 records in\n2048+1 records out\n1049076 bytes (1.0 MB) " + b"copied, 0.00473357 s, 222 ***/s\n", + None, + ) + mock_popen.return_value = mock_process + + random_file = MagicMock() + random_file.tfile.name = "random_file" + with self.assertRaises(SystemExit): + write_test_unit(random_file) + + @patch("os.path") + @patch("subprocess.Popen") + @patch("subprocess.check_output") + @patch("subprocess.run") + def test_write_test_unit_io_error( + self, mock_run, mock_check_output, mock_popen, mock_os + ): + mock_os.join.return_value = "output_file" + + mock_process = MagicMock() + mock_process.communicate.return_value = ( + b"2048+1 records in\n2048+1 records out\n1049076 bytes (1.0 MB) " + b"copied, 0.00473357 s, 222 MBs\n", + None, + ) + mock_popen.return_value = mock_process + + dmesg = MagicMock() + dmesg.stdout.decode.return_value = "I/O error" + mock_run.return_value = dmesg + + random_file = MagicMock() + random_file.tfile.name = "random_file" + with self.assertRaises(SystemExit): + write_test_unit(random_file) diff --git a/checkbox-support/debian/control b/checkbox-support/debian/control index fb37ac38ca..9eaf3461a0 100644 --- a/checkbox-support/debian/control +++ b/checkbox-support/debian/control @@ -40,6 +40,7 @@ Depends: gir1.2-gudev-1.0, python3-yaml, udev, udisks2, + libsystemd-dev ${misc:Depends}, ${python3:Depends} Description: collection of Python modules used by PlainBox providers diff --git a/checkbox-support/pyproject.toml b/checkbox-support/pyproject.toml index a41a668f68..9ef6f6c7af 100644 --- a/checkbox-support/pyproject.toml +++ b/checkbox-support/pyproject.toml @@ -17,6 +17,8 @@ 'requests_unixsocket>=0.1.2; python_version>="3.5" and python_version<="3.11"', 'requests_unixsocket2; python_version>="3.12"', 'importlib_metadata; python_version<"3.8"', + 'systemd-python==232; python_version=="3.5"', + 'systemd-python>=235; python_version>="3.6"', 'pyyaml', ] [metadata] diff --git a/checkbox-support/setup.cfg b/checkbox-support/setup.cfg index 6096dcf18d..9380f633a8 100644 --- a/checkbox-support/setup.cfg +++ b/checkbox-support/setup.cfg @@ -11,6 +11,8 @@ install_requires= requests_unixsocket >= 0.1.2; python_version>="3.5" and python_version<="3.11" requests_unixsocket2; python_version>="3.12" importlib_metadata; python_version<"3.8" + systemd-python == 232; python_version=="3.5" + systemd-python == 235; python_version>="3.6" [metadata] name=checkbox-support [options.entry_points] diff --git a/checkbox-support/tox.ini b/checkbox-support/tox.ini index 5985aa6dca..61a591e6c9 100644 --- a/checkbox-support/tox.ini +++ b/checkbox-support/tox.ini @@ -14,6 +14,7 @@ commands = [testenv:py35] deps = pytest + systemd-python == 232 coverage == 5.5 pytest-cov == 2.12.1 requests == 2.9.1 @@ -29,6 +30,7 @@ setenv= [testenv:py36] deps = pytest + systemd-python == 235 coverage == 5.5 pytest-cov == 3.0.0 requests == 2.18.4 @@ -40,6 +42,7 @@ deps = [testenv:py38] deps = pytest + systemd-python == 235 coverage == 7.3.0 pytest-cov == 4.1.0 requests == 2.22.0 @@ -50,6 +53,7 @@ deps = [testenv:py310] deps = pytest + systemd-python == 235 coverage == 7.3.0 pytest-cov == 4.1.0 requests == 2.25.1 diff --git a/providers/base/units/dock/jobs.pxu b/providers/base/units/dock/jobs.pxu index 8da880709e..47f2f3ace5 100644 --- a/providers/base/units/dock/jobs.pxu +++ b/providers/base/units/dock/jobs.pxu @@ -2082,7 +2082,7 @@ depends: dock/cold-plug imports: from com.canonical.plainbox import manifest requires: manifest.has_thunderbolt3 == 'True' flags: also-after-suspend -command: removable_storage_watcher.py insert --timeout 40 scsi +command: checkbox-support-run_watcher insertion thunderbolt _summary: Thunderbolt3 storage insertion detection _purpose: This test will check if the connection of a Thunderbolt3 HDD to the dock could be detected @@ -2104,7 +2104,7 @@ depends: dock/thunderbolt3-insert imports: from com.canonical.plainbox import manifest requires: manifest.has_thunderbolt3 == 'True' flags: also-after-suspend -command: removable_storage_test.py -s 268400000 scsi +command: checkbox-support-usb_read_write _summary: Thunderbolt3 storage test _description: This is an automated test which performs read/write operations on an attached @@ -2118,7 +2118,7 @@ depends: dock/thunderbolt3-insert imports: from com.canonical.plainbox import manifest requires: manifest.has_thunderbolt3 == 'True' flags: also-after-suspend -command: removable_storage_watcher.py remove scsi +command: checkbox-support-run_watcher removal thunderbolt _summary: Thunderbolt3 storage removal detection _purpose: This test will check the system can detect the removal of a Thunderbolt3 HDD @@ -2642,7 +2642,7 @@ plugin: user-interact imports: from com.canonical.plainbox import manifest requires: manifest.has_thunderbolt3 == 'True' flags: also-after-suspend -command: removable_storage_watcher.py insert --timeout 40 scsi +command: checkbox-support-run_watcher insertion thunderbolt _summary: Thunderbolt3 storage insertion detection _purpose: This test will check if the connection of a Thunderbolt3 HDD to the dock could be detected @@ -2669,7 +2669,7 @@ depends: dock/all-init-thunderbolt3-insert imports: from com.canonical.plainbox import manifest requires: manifest.has_thunderbolt3 == 'True' flags: also-after-suspend -command: removable_storage_test.py -s 268400000 scsi +command: checkbox-support-usb_read_write _summary: Thunderbolt3 storage test _description: This is an automated test which performs read/write operations on an attached @@ -2692,7 +2692,7 @@ depends: dock/all-init-thunderbolt3-insert imports: from com.canonical.plainbox import manifest requires: manifest.has_thunderbolt3 == 'True' flags: also-after-suspend -command: removable_storage_watcher.py remove scsi +command: checkbox-support-run_watcher removal thunderbolt _summary: Thunderbolt3 storage removal detection _purpose: This test will check the system can detect the removal of a Thunderbolt3 storage. diff --git a/providers/base/units/mediacard/jobs.pxu b/providers/base/units/mediacard/jobs.pxu index 861c6cbb9a..4b466cb468 100644 --- a/providers/base/units/mediacard/jobs.pxu +++ b/providers/base/units/mediacard/jobs.pxu @@ -1,14 +1,9 @@ plugin: user-interact -template-engine: jinja2 category_id: com.canonical.plainbox::mediacard id: mediacard/mmc-insert estimated_duration: 30.0 command: - {%- if __on_ubuntucore__ %} - checkbox-support-run_watcher insertion mediacard - {%- else %} - removable_storage_watcher.py --memorycard insert sdio usb scsi - {% endif -%} + checkbox-support-run_watcher insertion mediacard imports: from com.canonical.plainbox import manifest requires: manifest.has_card_reader == 'True' @@ -26,7 +21,6 @@ _verification: _summary: Test the system's media card reader for MMC insertion detection. plugin: shell -template-engine: jinja2 category_id: com.canonical.plainbox::mediacard id: mediacard/mmc-storage estimated_duration: 30.0 @@ -34,11 +28,7 @@ depends: mediacard/mmc-insert user: root flags: preserve-cwd reset-locale command: - {%- if __on_ubuntucore__ %} - checkbox-support-usb_read_write - {%- else %} - removable_storage_test.py -s 67120000 --memorycard sdio usb scsi --auto-reduce-size - {% endif -%} + checkbox-support-usb_read_write _purpose: This test is automated and executes after the mediacard/mmc-insert test is run. It tests reading and writing to the MMC card. @@ -46,17 +36,12 @@ _summary: Test automated execution for reading and writing to the MMC card. plugin: user-interact -template-engine: jinja2 category_id: com.canonical.plainbox::mediacard id: mediacard/mmc-remove estimated_duration: 30.0 depends: mediacard/mmc-insert command: - {%- if __on_ubuntucore__ %} - checkbox-support-run_watcher removal mediacard - {%- else %} - removable_storage_watcher.py --memorycard remove sdio usb scsi - {% endif -%} + checkbox-support-run_watcher removal mediacard user: root _purpose: This test will check that the system correctly detects @@ -70,16 +55,11 @@ _verification: _summary: Test the detection of MMC card removal from the system's card reader. plugin: user-interact -template-engine: jinja2 category_id: com.canonical.plainbox::mediacard id: mediacard/sd-insert estimated_duration: 30.0 command: - {%- if __on_ubuntucore__ %} - checkbox-support-run_watcher insertion mediacard - {%- else %} - removable_storage_watcher.py --memorycard insert sdio usb scsi --unmounted - {% endif -%} + checkbox-support-run_watcher insertion mediacard imports: from com.canonical.plainbox import manifest requires: manifest.has_card_reader == 'True' @@ -97,7 +77,6 @@ _verification: automatically selected result. plugin: shell -template-engine: jinja2 category_id: com.canonical.plainbox::mediacard id: mediacard/sd-storage estimated_duration: 30.0 @@ -105,28 +84,19 @@ depends: mediacard/sd-insert user: root flags: preserve-cwd reset-locale command: - {%- if __on_ubuntucore__ %} - checkbox-support-usb_read_write - {%- else %} - removable_storage_test.py -s 268400000 --memorycard sdio usb scsi --auto-reduce-size - {% endif -%} + checkbox-support-usb_read_write _summary: Test reading & writing to an SD Card _purpose: This test is automated and executes after the mediacard/sd-insert test is run. It tests reading and writing to the SD card. plugin: user-interact -template-engine: jinja2 category_id: com.canonical.plainbox::mediacard id: mediacard/sd-remove estimated_duration: 30.0 depends: mediacard/sd-insert command: - {%- if __on_ubuntucore__ %} - checkbox-support-run_watcher removal mediacard - {%- else %} - removable_storage_watcher.py --memorycard remove sdio usb scsi --unmounted - {% endif -%} + checkbox-support-run_watcher removal mediacard user: root _summary: Test that removal of an SD card is detected _purpose: @@ -158,17 +128,12 @@ _purpose: It is intended for SRU automated testing. plugin: user-interact -template-engine: jinja2 category_id: com.canonical.plainbox::mediacard id: mediacard/sdhc-insert flags: also-after-suspend estimated_duration: 30.0 command: - {%- if __on_ubuntucore__ %} - checkbox-support-run_watcher insertion mediacard - {%- else %} - removable_storage_watcher.py --memorycard insert sdio usb scsi --unmounted - {% endif -%} + checkbox-support-run_watcher insertion mediacard imports: from com.canonical.plainbox import manifest requires: manifest.has_card_reader == 'True' @@ -187,7 +152,6 @@ _verification: automatically selected result. plugin: shell -template-engine: jinja2 category_id: com.canonical.plainbox::mediacard id: mediacard/sdhc-storage estimated_duration: 30.0 @@ -195,29 +159,20 @@ depends: mediacard/sdhc-insert user: root flags: preserve-cwd reset-locale also-after-suspend command: - {%- if __on_ubuntucore__ %} - checkbox-support-usb_read_write - {%- else %} - removable_storage_test.py -s 268400000 --memorycard sdio usb scsi --auto-reduce-size - {% endif -%} + checkbox-support-usb_read_write _summary: Test reading & writing to a SDHC Card _description: This test is automated and executes after the mediacard/sdhc-insert test is run. It tests reading and writing to the SDHC card. plugin: user-interact -template-engine: jinja2 category_id: com.canonical.plainbox::mediacard id: mediacard/sdhc-remove flags: also-after-suspend estimated_duration: 30.0 depends: mediacard/sdhc-insert command: - {%- if __on_ubuntucore__ %} - checkbox-support-run_watcher removal mediacard - {%- else %} - removable_storage_watcher.py --memorycard remove sdio usb scsi --unmounted - {% endif -%} + checkbox-support-run_watcher removal mediacard user: root _summary: Test that removal of an SDHC card is detected _purpose: @@ -231,16 +186,11 @@ _verification: automatically selected result. plugin: user-interact -template-engine: jinja2 category_id: com.canonical.plainbox::mediacard id: mediacard/cf-insert estimated_duration: 30.0 command: - {%- if __on_ubuntucore__ %} - checkbox-support-run_watcher insertion mediacard - {%- else %} - removable_storage_watcher.py --memorycard insert sdio usb scsi - {% endif -%} + checkbox-support-run_watcher insertion mediacard imports: from com.canonical.plainbox import manifest requires: manifest.has_card_reader == 'True' @@ -258,7 +208,6 @@ _verification: _summary: Verify the system's media card reader can detect a Compact Flash card insertion. plugin: shell -template-engine: jinja2 category_id: com.canonical.plainbox::mediacard id: mediacard/cf-storage estimated_duration: 30.0 @@ -266,28 +215,19 @@ depends: mediacard/cf-insert user: root flags: preserve-cwd reset-locale command: - {%- if __on_ubuntucore__ %} - checkbox-support-usb_read_write - {%- else %} - removable_storage_test.py -s 268400000 --memorycard sdio usb scsi --auto-reduce-size - {% endif -%} + checkbox-support-usb_read_write _purpose: This test is automated and executes after the mediacard/cf-insert test is run. It tests reading and writing to the CF card. _summary: Automate testing for reading and writing to the CF card after mediacard/cf-insert test. plugin: user-interact -template-engine: jinja2 category_id: com.canonical.plainbox::mediacard id: mediacard/cf-remove -depends: mediacard/cf-storage +depends: mediacard/cf-insert estimated_duration: 30.0 command: - {%- if __on_ubuntucore__ %} - checkbox-support-run_watcher removal mediacard - {%- else %} - removable_storage_watcher.py --memorycard remove sdio usb scsi - {% endif -%} + checkbox-support-run_watcher removal mediacard user: root _purpose: This test will check that the system correctly detects @@ -301,16 +241,11 @@ _verification: _summary: Ensure the system detects CF card removal from the card reader correctly. plugin: user-interact -template-engine: jinja2 category_id: com.canonical.plainbox::mediacard id: mediacard/sdxc-insert estimated_duration: 30.0 command: - {%- if __on_ubuntucore__ %} - checkbox-support-run_watcher insertion mediacard - {%- else %} - removable_storage_watcher.py --memorycard insert sdio usb scsi --unmounted - {% endif -%} + checkbox-support-run_watcher insertion mediacard imports: from com.canonical.plainbox import manifest requires: manifest.has_card_reader == 'True' @@ -328,7 +263,6 @@ _verification: automatically selected result. plugin: shell -template-engine: jinja2 category_id: com.canonical.plainbox::mediacard id: mediacard/sdxc-storage estimated_duration: 30.0 @@ -336,28 +270,19 @@ depends: mediacard/sdxc-insert user: root flags: preserve-cwd reset-locale command: - {%- if __on_ubuntucore__ %} - checkbox-support-usb_read_write - {%- else %} - removable_storage_test.py -s 268400000 --memorycard sdio usb scsi --auto-reduce-size - {% endif -%} + checkbox-support-usb_read_write _summary: Test reading & writing to an SDXC Card _purpose: This test is automated and executes after the mediacard/sdxc-insert test is run. It tests reading and writing to the SDXC card. plugin: user-interact -template-engine: jinja2 category_id: com.canonical.plainbox::mediacard id: mediacard/sdxc-remove estimated_duration: 30.0 depends: mediacard/sdxc-insert command: - {%- if __on_ubuntucore__ %} - checkbox-support-run_watcher removal mediacard - {%- else %} - removable_storage_watcher.py --memorycard remove sdio usb scsi --unmounted - {% endif -%} + checkbox-support-run_watcher removal mediacard user: root _summary: Test that removal of an SDXC card is detected _purpose: @@ -371,16 +296,11 @@ _verification: automatically selected result. plugin: user-interact -template-engine: jinja2 category_id: com.canonical.plainbox::mediacard id: mediacard/ms-insert estimated_duration: 30.0 command: - {%- if __on_ubuntucore__ %} - checkbox-support-run_watcher insertion mediacard - {%- else %} - removable_storage_watcher.py --memorycard insert sdio usb scsi - {% endif -%} + checkbox-support-run_watcher insertion mediacard imports: from com.canonical.plainbox import manifest requires: manifest.has_card_reader == 'True' @@ -399,7 +319,6 @@ _summary: Verify the detection of Memory Stick (MS) card insertion by the system's media card reader. plugin: shell -template-engine: jinja2 category_id: com.canonical.plainbox::mediacard id: mediacard/ms-storage estimated_duration: 30.0 @@ -407,28 +326,19 @@ depends: mediacard/ms-insert user: root flags: preserve-cwd reset-locale command: - {%- if __on_ubuntucore__ %} - checkbox-support-usb_read_write - {%- else %} - removable_storage_test.py -s 268400000 --memorycard sdio usb scsi --auto-reduce-size - {% endif -%} + checkbox-support-usb_read_write _purpose: This test is automated and executes after the mediacard/ms-insert test is run. It tests reading and writing to the MS card. _summary: Automated test for reading and writing to the MS card after mediacard/ms-insert test. plugin: user-interact -template-engine: jinja2 category_id: com.canonical.plainbox::mediacard id: mediacard/ms-remove estimated_duration: 30.0 depends: mediacard/ms-insert command: - {%- if __on_ubuntucore__ %} - checkbox-support-run_watcher removal mediacard - {%- else %} - removable_storage_watcher.py --memorycard remove sdio usb scsi - {% endif -%} + checkbox-support-run_watcher removal mediacard user: root _description: _purpose: @@ -443,16 +353,11 @@ _verification: _summary: Test if the system detects the removal of an MS card correctly. plugin: user-interact -template-engine: jinja2 category_id: com.canonical.plainbox::mediacard id: mediacard/msp-insert estimated_duration: 30.0 command: - {%- if __on_ubuntucore__ %} - checkbox-support-run_watcher insertion mediacard - {%- else %} - removable_storage_watcher.py --memorycard insert sdio usb scsi - {% endif -%} + checkbox-support-run_watcher insertion mediacard user: root imports: from com.canonical.plainbox import manifest requires: @@ -471,7 +376,6 @@ _verification: _summary: Verify the system's media card reader can detect a Memory Stick Pro (MSP) card insertion. plugin: shell -template-engine: jinja2 category_id: com.canonical.plainbox::mediacard id: mediacard/msp-storage estimated_duration: 30.0 @@ -479,28 +383,19 @@ depends: mediacard/msp-insert user: root flags: preserve-cwd reset-locale command: - {%- if __on_ubuntucore__ %} - checkbox-support-usb_read_write - {%- else %} - removable_storage_test.py -s 268400000 --memorycard sdio usb scsi --auto-reduce-size - {% endif -%} + checkbox-support-usb_read_write _purpose: This test is automated and executes after the mediacard/msp-insert test is run. It tests reading and writing to the MSP card. _summary: Automated test for reading and writing to the MSP card after mediacard/msp-insert test. plugin: user-interact -template-engine: jinja2 category_id: com.canonical.plainbox::mediacard id: mediacard/msp-remove estimated_duration: 30.0 depends: mediacard/msp-insert command: - {%- if __on_ubuntucore__ %} - checkbox-support-run_watcher removal mediacard - {%- else %} - removable_storage_watcher.py --memorycard remove sdio usb scsi - {% endif -%} + checkbox-support-run_watcher removal mediacard user: root _description: _purpose: @@ -515,16 +410,11 @@ _verification: _summary: Ensure MSP card removal is correctly detected by the system. plugin: user-interact -template-engine: jinja2 category_id: com.canonical.plainbox::mediacard id: mediacard/xd-insert estimated_duration: 30.0 command: - {%- if __on_ubuntucore__ %} - checkbox-support-run_watcher insertion mediacard - {%- else %} - removable_storage_watcher.py --memorycard insert sdio usb scsi - {% endif -%} + checkbox-support-run_watcher insertion mediacard imports: from com.canonical.plainbox import manifest requires: manifest.has_card_reader == 'True' @@ -542,7 +432,6 @@ _verification: _summary: Ensure the system's media card reader detects the insertion of an xD media card. plugin: shell -template-engine: jinja2 category_id: com.canonical.plainbox::mediacard id: mediacard/xd-storage estimated_duration: 30.0 @@ -550,27 +439,18 @@ depends: mediacard/xd-insert user: root flags: preserve-cwd reset-locale command: - {%- if __on_ubuntucore__ %} - checkbox-support-usb_read_write - {%- else %} - removable_storage_test.py -s 268400000 --memorycard sdio usb scsi --auto-reduce-size - {% endif -%} + checkbox-support-usb_read_write _purpose: This test is automated and executes after the mediacard/xd-insert test is run. It tests reading and writing to the xD card. _summary: Automated test to verify reading and writing functionality of the xD card after mediacard/xd-insert test. plugin: user-interact -template-engine: jinja2 category_id: com.canonical.plainbox::mediacard id: mediacard/xd-remove estimated_duration: 30.0 depends: mediacard/xd-insert command: - {%- if __on_ubuntucore__ %} - checkbox-support-run_watcher removal mediacard - {%- else %} - removable_storage_watcher.py --memorycard remove sdio usb scsi - {% endif -%} + checkbox-support-run_watcher removal mediacard user: root _purpose: This test will check that the system correctly detects diff --git a/providers/base/units/thunderbolt/jobs.pxu b/providers/base/units/thunderbolt/jobs.pxu index 69041b5823..ce19c1f70f 100644 --- a/providers/base/units/thunderbolt/jobs.pxu +++ b/providers/base/units/thunderbolt/jobs.pxu @@ -5,7 +5,6 @@ user: root imports: from com.canonical.plainbox import manifest requires: manifest.has_thunderbolt == 'True' estimated_duration: 20.0 -template-engine: jinja2 command: checkbox-support-run_watcher insertion thunderbolt _siblings: [ @@ -33,13 +32,8 @@ imports: from com.canonical.plainbox import manifest requires: manifest.has_thunderbolt == 'True' depends: thunderbolt/insert estimated_duration: 45.0 -template-engine: jinja2 command: - {%- if __on_ubuntucore__ %} - checkbox-support-usb_read_write - {%- else %} - removable_storage_test.py -s 268400000 scsi - {% endif -%} + checkbox-support-usb_read_write _siblings: [ { "id": "after-suspend-thunderbolt/storage-test", "_summary": "thunderbolt/storage-test after suspend", @@ -56,7 +50,6 @@ imports: from com.canonical.plainbox import manifest requires: manifest.has_thunderbolt == 'True' depends: thunderbolt/insert estimated_duration: 10.0 -template-engine: jinja2 command: checkbox-support-run_watcher insertion thunderbolt _summary: Storage removal detection on Thunderbolt @@ -105,7 +98,6 @@ user: root imports: from com.canonical.plainbox import manifest requires: manifest.has_thunderbolt3 == 'True' estimated_duration: 20.0 -template-engine: jinja2 command: checkbox-support-run_watcher insertion thunderbolt _summary: Storage insert detection on Thunderbolt 3 port @@ -129,13 +121,8 @@ imports: from com.canonical.plainbox import manifest requires: manifest.has_thunderbolt3 == 'True' depends: thunderbolt3/insert estimated_duration: 45.0 -template-engine: jinja2 command: - {%- if __on_ubuntucore__ %} - checkbox-support-usb_read_write - {%- else %} - removable_storage_test.py -s 268400000 scsi - {% endif -%} + checkbox-support-usb_read_write _summary: Storage test on Thunderbolt 3 _purpose: This is an automated test which performs read/write operations on an attached Thunderbolt HDD @@ -161,7 +148,6 @@ imports: from com.canonical.plainbox import manifest requires: manifest.has_thunderbolt3 == 'True' depends: thunderbolt3/insert estimated_duration: 10.0 -template-engine: jinja2 command: checkbox-support-run_watcher removal thunderbolt _summary: Storage removal detection on Thunderbolt 3 port diff --git a/providers/base/units/usb/test-plan.pxu b/providers/base/units/usb/test-plan.pxu index cbf24cf7d6..091daeb7c8 100644 --- a/providers/base/units/usb/test-plan.pxu +++ b/providers/base/units/usb/test-plan.pxu @@ -370,7 +370,7 @@ include: id: after-suspend-usb-automated unit: test plan -_name: Automated USB tests +_name: Automated USB tests (after suspend) _description: Automated USB tests for Ubuntu Core devices include: after-suspend-usb/storage-detect diff --git a/providers/base/units/usb/usb-c.pxu b/providers/base/units/usb/usb-c.pxu index 92bf0005be..cf386f7717 100644 --- a/providers/base/units/usb/usb-c.pxu +++ b/providers/base/units/usb/usb-c.pxu @@ -35,11 +35,7 @@ plugin: user-interact flags: also-after-suspend user: root command: - if [[ -v SNAP ]]; then - checkbox-support-run_watcher insertion usb3 - else - removable_storage_watcher.py -m 500000000 insert usb - fi + checkbox-support-run_watcher insertion usb3 category_id: com.canonical.plainbox::usb imports: from com.canonical.plainbox import manifest requires: @@ -56,11 +52,7 @@ plugin: shell flags: also-after-suspend user: root command: - if [[ -v SNAP ]]; then - checkbox-support-usb_read_write - else - removable_storage_test.py -s 268400000 -m 500000000 usb --driver xhci_hcd - fi + checkbox-support-usb_read_write category_id: com.canonical.plainbox::usb imports: from com.canonical.plainbox import manifest requires: @@ -86,11 +78,7 @@ plugin: user-interact flags: also-after-suspend user: root command: - if [[ -v SNAP ]]; then - checkbox-support-run_watcher removal usb3 - else - removable_storage_watcher.py -m 500000000 remove usb - fi + checkbox-support-run_watcher removal usb3 category_id: com.canonical.plainbox::usb depends: usb-c/c-to-a-adapter/insert imports: from com.canonical.plainbox import manifest @@ -135,11 +123,7 @@ plugin: user-interact flags: also-after-suspend user: root command: - if [[ -v SNAP ]]; then - checkbox-support-run_watcher insertion usb3 - else - removable_storage_watcher.py -m 500000000 insert usb - fi + checkbox-support-run_watcher insertion usb3 category_id: com.canonical.plainbox::usb imports: from com.canonical.plainbox import manifest requires: @@ -155,11 +139,7 @@ plugin: shell flags: also-after-suspend user: root command: - if [[ -v SNAP ]]; then - checkbox-support-usb_read_write - else - removable_storage_test.py -s 268400000 -m 500000000 usb --driver xhci_hcd - fi + checkbox-support-usb_read_write category_id: com.canonical.plainbox::usb imports: from com.canonical.plainbox import manifest requires: @@ -183,11 +163,7 @@ plugin: user-interact flags: also-after-suspend user: root command: - if [[ -v SNAP ]]; then - checkbox-support-run_watcher removal usb3 - else - removable_storage_watcher.py -m 500000000 remove usb - fi + checkbox-support-run_watcher removal usb3 category_id: com.canonical.plainbox::usb depends: usb-c/insert imports: from com.canonical.plainbox import manifest diff --git a/providers/base/units/usb/usb.pxu b/providers/base/units/usb/usb.pxu index adc74f03f3..7d181e7704 100644 --- a/providers/base/units/usb/usb.pxu +++ b/providers/base/units/usb/usb.pxu @@ -53,11 +53,6 @@ _summary: Verify USB HID devices functionality by performing specified actions. id: usb/insert flags: also-after-suspend fail-on-resource -template-engine: jinja2 -requires: - {%- if not __on_ubuntucore__ %} - package.name == 'udisks2' or snap.name == 'udisks2' - {% endif -%} _summary: USB 2.0 storage device insertion detected _purpose: Check system can detect USB 2.0 storage when inserted. @@ -73,17 +68,12 @@ _verification: plugin: user-interact user: root command: - {%- if __on_ubuntucore__ %} - checkbox-support-run_watcher insertion usb2 - {%- else %} - removable_storage_watcher.py --unmounted insert usb - {% endif -%} + checkbox-support-run_watcher insertion usb2 category_id: com.canonical.plainbox::usb estimated_duration: 120 id: usb3/insert flags: also-after-suspend -template-engine: jinja2 requires: usb.usb3 == 'supported' _summary: USB 3.0 storage device insertion detected @@ -101,17 +91,12 @@ _verification: plugin: user-interact user: root command: - {%- if __on_ubuntucore__ %} - checkbox-support-run_watcher insertion usb3 - {%- else %} - removable_storage_watcher.py --unmounted -m 500000000 insert usb - {% endif -%} + checkbox-support-run_watcher insertion usb3 category_id: com.canonical.plainbox::usb estimated_duration: 120 id: usb/remove flags: also-after-suspend -template-engine: jinja2 _summary: USB 2.0 storage device removal detected _purpose: Check system can detect removal of a USB 2.0 storage device @@ -126,17 +111,12 @@ plugin: user-interact depends: usb/insert user: root command: - {%- if __on_ubuntucore__ %} - checkbox-support-run_watcher removal usb2 - {%- else %} - removable_storage_watcher.py --unmounted remove usb - {% endif -%} + checkbox-support-run_watcher removal usb2 category_id: com.canonical.plainbox::usb estimated_duration: 120 id: usb3/remove flags: also-after-suspend -template-engine: jinja2 _summary: USB 3.0 storage device removal detected _purpose: Check system can detect removal of a USB 3.0 storage device @@ -151,11 +131,7 @@ plugin: user-interact depends: usb3/insert user: root command: - {%- if __on_ubuntucore__ %} - checkbox-support-run_watcher removal usb3 - {%- else %} - removable_storage_watcher.py --unmounted -m 500000000 remove usb - {% endif -%} + checkbox-support-run_watcher removal usb3 category_id: com.canonical.plainbox::usb estimated_duration: 120 @@ -201,7 +177,6 @@ _summary: Check the USB 3.0 connection and data transfer capability. id: usb/storage-automated flags: also-after-suspend -template-engine: jinja2 _summary: USB 2.0 storage device read & write works _purpose: Check system can read/write to USB 2.0 storage correctly @@ -213,17 +188,12 @@ plugin: shell depends: usb/insert user: root command: - {%- if __on_ubuntucore__ %} - checkbox-support-usb_read_write - {%- else %} - removable_storage_test.py -s 268400000 usb - {% endif -%} + checkbox-support-usb_read_write category_id: com.canonical.plainbox::usb estimated_duration: 300 id: usb3/storage-automated flags: also-after-suspend -template-engine: jinja2 _summary: USB 3.0 storage device read & write works _purpose: Check system can read/write to USB 3.0 storage devices correctly @@ -235,11 +205,7 @@ plugin: shell depends: usb3/insert user: root command: - {%- if __on_ubuntucore__ %} - checkbox-support-usb_read_write - {%- else %} - removable_storage_test.py -s 268400000 -m 500000000 usb --driver xhci_hcd - {% endif -%} + checkbox-support-usb_read_write category_id: com.canonical.plainbox::usb estimated_duration: 300 diff --git a/providers/genio/bin/boot_partition.py b/providers/genio/bin/boot_partition.py index 2cb2482c22..112f5299e5 100755 --- a/providers/genio/bin/boot_partition.py +++ b/providers/genio/bin/boot_partition.py @@ -4,7 +4,7 @@ # Copyright 2024 Canonical Ltd. # Authors: # Patrick Chang -# Fernando Bravo +# Fernando Bravo # # Checkbox is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License version 3, diff --git a/providers/genio/bin/brightness_test.py b/providers/genio/bin/brightness_test.py index 0c79e75dca..9518fa400a 100755 --- a/providers/genio/bin/brightness_test.py +++ b/providers/genio/bin/brightness_test.py @@ -6,7 +6,7 @@ # Alberto Milone # Sylvain Pineau # Patrick Chang -# Fernando Bravo +# Fernando Bravo # # Checkbox is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License version 3, diff --git a/providers/genio/bin/cpu_idle.py b/providers/genio/bin/cpu_idle.py index f9b503abd6..ff17920826 100755 --- a/providers/genio/bin/cpu_idle.py +++ b/providers/genio/bin/cpu_idle.py @@ -4,7 +4,7 @@ # Copyright 2024 Canonical Ltd. # Authors: # Patrick Chang -# Fernando Bravo +# Fernando Bravo # # Checkbox is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License version 3, diff --git a/providers/genio/bin/dvfs_gpu_check_governors.py b/providers/genio/bin/dvfs_gpu_check_governors.py index fbcf1a8ded..4945dd0ae7 100755 --- a/providers/genio/bin/dvfs_gpu_check_governors.py +++ b/providers/genio/bin/dvfs_gpu_check_governors.py @@ -4,7 +4,7 @@ # Copyright 2024 Canonical Ltd. # Authors: # Patrick Chang -# Fernando Bravo +# Fernando Bravo # # Checkbox is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License version 3, diff --git a/providers/genio/bin/gpio_loopback_test.py b/providers/genio/bin/gpio_loopback_test.py index 9bbca3d184..139947c804 100755 --- a/providers/genio/bin/gpio_loopback_test.py +++ b/providers/genio/bin/gpio_loopback_test.py @@ -4,7 +4,7 @@ # Copyright 2024 Canonical Ltd. # Authors: # Patrick Chang -# Fernando Bravo +# Fernando Bravo # # Checkbox is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License version 3, diff --git a/providers/genio/bin/hdmirx_output_checker.sh b/providers/genio/bin/hdmirx_output_checker.sh index 2fc094d649..ab4c121d4a 100755 --- a/providers/genio/bin/hdmirx_output_checker.sh +++ b/providers/genio/bin/hdmirx_output_checker.sh @@ -4,7 +4,7 @@ # Copyright 2014 Canonical Ltd. # Authors: # Patrick Chang -# Fernando Bravo +# Fernando Bravo # # Checkbox is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License version 3, diff --git a/providers/genio/bin/hdmirx_tool_runner.sh b/providers/genio/bin/hdmirx_tool_runner.sh index 916c5aec7d..cbe28d7cee 100755 --- a/providers/genio/bin/hdmirx_tool_runner.sh +++ b/providers/genio/bin/hdmirx_tool_runner.sh @@ -4,7 +4,7 @@ # Copyright 2014 Canonical Ltd. # Authors: # Patrick Chang -# Fernando Bravo +# Fernando Bravo # # Checkbox is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License version 3, diff --git a/providers/genio/bin/linux_ccf.py b/providers/genio/bin/linux_ccf.py index d33880f29f..c36fb8db30 100755 --- a/providers/genio/bin/linux_ccf.py +++ b/providers/genio/bin/linux_ccf.py @@ -4,7 +4,7 @@ # Copyright 2024 Canonical Ltd. # Authors: # Patrick Chang -# Fernando Bravo +# Fernando Bravo # # Checkbox is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License version 3, diff --git a/providers/genio/bin/pmic_regulator.py b/providers/genio/bin/pmic_regulator.py index 3e456c75e6..95eb7fc287 100755 --- a/providers/genio/bin/pmic_regulator.py +++ b/providers/genio/bin/pmic_regulator.py @@ -4,7 +4,7 @@ # Copyright 2024 Canonical Ltd. # Authors: # Patrick Chang -# Fernando Bravo +# Fernando Bravo # # Checkbox is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License version 3, diff --git a/providers/genio/bin/serialcheck.py b/providers/genio/bin/serialcheck.py index 825c194c9c..854d3ade75 100755 --- a/providers/genio/bin/serialcheck.py +++ b/providers/genio/bin/serialcheck.py @@ -4,7 +4,7 @@ # Copyright 2024 Canonical Ltd. # Authors: # Patrick Chang -# Fernando Bravo +# Fernando Bravo # # Checkbox is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License version 3, diff --git a/providers/genio/bin/set_as_performance_mode.sh b/providers/genio/bin/set_as_performance_mode.sh index 4169c97138..1ab62c899b 100755 --- a/providers/genio/bin/set_as_performance_mode.sh +++ b/providers/genio/bin/set_as_performance_mode.sh @@ -4,7 +4,7 @@ # Copyright 2014 Canonical Ltd. # Authors: # Patrick Chang -# Fernando Bravo +# Fernando Bravo # # Checkbox is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License version 3, diff --git a/providers/genio/bin/spidev_test.py b/providers/genio/bin/spidev_test.py index bd8e56d54e..9b9998b5c8 100755 --- a/providers/genio/bin/spidev_test.py +++ b/providers/genio/bin/spidev_test.py @@ -4,7 +4,7 @@ # Copyright 2024 Canonical Ltd. # Authors: # Patrick Chang -# Fernando Bravo +# Fernando Bravo # # Checkbox is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License version 3, diff --git a/providers/genio/bin/verify-mt8188-ccf.sh b/providers/genio/bin/verify-mt8188-ccf.sh index 03337cd422..a0aa0358b5 100755 --- a/providers/genio/bin/verify-mt8188-ccf.sh +++ b/providers/genio/bin/verify-mt8188-ccf.sh @@ -5,7 +5,7 @@ # Authors: # Amjad Ouled-Ameur # Patrick Chang -# Fernando Bravo +# Fernando Bravo # # Checkbox is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License version 3, diff --git a/providers/genio/bin/verify-mt8195-ccf.sh b/providers/genio/bin/verify-mt8195-ccf.sh index 9271c9b774..0767c0a936 100755 --- a/providers/genio/bin/verify-mt8195-ccf.sh +++ b/providers/genio/bin/verify-mt8195-ccf.sh @@ -5,7 +5,7 @@ # Authors: # Amjad Ouled-Ameur # Patrick Chang -# Fernando Bravo +# Fernando Bravo # # Checkbox is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License version 3,