diff options
author | Jenkins <jenkins@cert-jenkins-master-201506-18558.maas> | 2022-06-16 08:23:24 +0000 |
---|---|---|
committer | Jenkins <jenkins@cert-jenkins-master-201506-18558.maas> | 2022-06-16 08:23:24 +0000 |
commit | ffede27215f97a474c6c37d2236a9315acc58605 (patch) | |
tree | d0ddc8da2deacba9b98b188ca1eb20e58d8ffedd | |
parent | c1d9cada2c76f18581940937aedb7409a758b8e0 (diff) |
Import plainbox-provider-checkbox_0.65.0~rc1.orig.tar.gzupstream-0.65.0_rc1patched-0.65.0_rc1-1
-rwxr-xr-x | bin/graphics_max_resolution.py | 148 | ||||
-rwxr-xr-x | bin/graphics_modes_info.py | 74 | ||||
-rwxr-xr-x | bin/install-method-check.sh | 149 | ||||
-rwxr-xr-x | bin/maas-version-check.sh | 75 | ||||
-rwxr-xr-x | bin/removable_storage_watcher.py | 45 | ||||
-rwxr-xr-x | bin/screenoff.sh | 1 | ||||
-rwxr-xr-x | bin/snap_tests.py | 5 | ||||
-rwxr-xr-x | bin/touchpad_test.py | 72 | ||||
-rwxr-xr-x | bin/virtualization.py | 371 | ||||
-rwxr-xr-x | bin/wifi_nmcli_test.py | 4 | ||||
-rwxr-xr-x | manage.py | 2 | ||||
-rw-r--r-- | units/graphics/jobs.pxu | 18 | ||||
-rw-r--r-- | units/graphics/legacy.pxu | 8 | ||||
-rw-r--r-- | units/graphics/test-plan.pxu | 6 | ||||
-rw-r--r-- | units/miscellanea/jobs.pxu | 10 | ||||
-rw-r--r-- | units/monitor/jobs.pxu | 10 | ||||
-rw-r--r-- | units/touchpad/jobs.pxu | 34 | ||||
-rw-r--r-- | units/touchpad/test-plan.pxu | 12 | ||||
-rw-r--r-- | units/virtualization/jobs.pxu | 21 | ||||
-rw-r--r-- | units/virtualization/test-plan.pxu | 4 | ||||
-rw-r--r-- | units/zapper/jobs.pxu | 38 | ||||
-rw-r--r-- | units/zapper/resource.pxu | 11 | ||||
-rw-r--r-- | units/zapper/test-plan.pxu | 6 |
23 files changed, 685 insertions, 439 deletions
diff --git a/bin/graphics_max_resolution.py b/bin/graphics_max_resolution.py new file mode 100755 index 0000000..56628a4 --- /dev/null +++ b/bin/graphics_max_resolution.py @@ -0,0 +1,148 @@ +#!/usr/bin/env python3 +# +# This file is part of Checkbox. +# +# Copyright 2022 Canonical Ltd. +# +# Authors: +# Pierre Equoy <pierre.equoy@canonical.com> +# +# 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 <http://www.gnu.org/licenses/>. + +import gi +from glob import glob +import os +import sys +from pathlib import Path + +gi.require_versions({"Gtk": "3.0", "Gdk": "3.0"}) +from gi.repository import Gdk, Gtk # noqa: E402 + + +def get_sysfs_info(): + """ + Go through each graphics cards sysfs entries to find max resolution if + connected to a monitor. + Return a list of ports with information about them. + """ + ports = glob("/sys/class/drm/card*-*") + entries = [] + for p in ports: + with open(Path(p) / "modes") as f: + # Topmost line in the modes file is the max resolution + max_resolution = f.readline().strip() + if max_resolution: + # e.g. "/sys/class/drm/card0-HDMI-A-1" + port = p.split("/")[-1] + width, height = max_resolution.split("x") + with open(Path(p) / "enabled") as f: + enabled = f.readline().strip() + with open(Path(p) / "dpms") as f: + dpms = f.readline().strip() + with open(Path(p) / "status") as f: + status = f.readline().strip() + port_info = { + "port": port, + "width": int(width), + "height": int(height), + "enabled": enabled, # "enabled" or "disabled" + "status": status, # "connected" or "disconnected" + "dpms": dpms, # "On" or "Off" + } + entries.append(port_info) + return entries + + +def get_monitors_info(): + """ + Get information (model, manufacturer, resolution) from each connected + monitors using Gtk. + Return a list of monitors with their information. + """ + Gtk.init() + display = Gdk.Display.get_default() + monitors = [] + for i in range(display.get_n_monitors()): + mon = display.get_monitor(i) + monitor = { + "model": mon.get_model(), + "manufacturer": mon.get_manufacturer(), + "width": mon.get_geometry().width, + "height": mon.get_geometry().height, + "scale_factor": mon.get_scale_factor(), + } + monitors.append(monitor) + return monitors + + +if __name__ == "__main__": + sysfs_entries = get_sysfs_info() + mons_entries = get_monitors_info() + total_sysfs_res = 0 + total_mons_res = 0 + compositor = os.environ.get("XDG_SESSION_TYPE") + print("Current compositor: {}".format(compositor)) + print() + print("Maximum resolution found for each connected monitors:") + for p in sysfs_entries: + port = p["port"] + width = p["width"] + height = p["height"] + enabled = p["enabled"] + status = p["status"] + dpms = p["dpms"].lower() + print( + "\t{}: {}x{} ({}, {}, {})".format( + port, width, height, dpms, status, enabled + ) + ) + # If the monitor is disabled (e.g. "Single Display" mode), don't take + # its surface into account. + if enabled == "enabled": + total_sysfs_res += width * height + print() + print("Current resolution found for each connected monitors:") + for m in mons_entries: + model = m["model"] + manufacturer = m["manufacturer"] + scale = m["scale_factor"] + # Under X11, the returned width and height are in "application pixels", + # not "device pixels", so it has to be multiplied by the scale factor. + # However, Wayland always returns the "device pixels" width and height. + # + # Example: a 3840x2160 screen set to 200% scale will have + # width = 1920, height = 1080, scale_factor = 2 on X11 + # width = 3840, height = 2160, scale_factor = 2 on Wayland + if compositor == "x11": + width = m["width"] * m["scale_factor"] + height = m["height"] * m["scale_factor"] + else: + width = m["width"] + height = m["height"] + print( + "\t{} ({}): {}x{} @{}%".format( + model, manufacturer, width, height, scale * 100 + ) + ) + total_mons_res += width * height + print() + if total_sysfs_res == total_mons_res: + print("The displays are configured at their maximum resolution.") + else: + sys.exit( + ( + "The displays do not seem to be configured at their maximum " + "resolution.\nPlease switch to the maximum resolution before " + "continuing." + ) + ) diff --git a/bin/graphics_modes_info.py b/bin/graphics_modes_info.py deleted file mode 100755 index f92cd76..0000000 --- a/bin/graphics_modes_info.py +++ /dev/null @@ -1,74 +0,0 @@ -#!/usr/bin/env python3 -# -*- coding: utf-8 -*- -# -# graphics_modes_info.py -# -# This file is part of Checkbox. -# -# Copyright 2012 Canonical Ltd. -# -# Authors: Alberto Milone <alberto.milone@canonical.com> -# -# 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 <http://www.gnu.org/licenses/>. - -from __future__ import print_function -from __future__ import unicode_literals -import sys - -from checkbox_support.contrib import xrandr - - -def print_modes_info(screen): - """Print some information about the detected screen and its outputs""" - xrandr._check_required_version((1, 0)) - print("Screen %s: minimum %s x %s, current %s x %s, maximum %s x %s" % - (screen._screen, - screen._width_min, screen._height_min, - screen._width, screen._height, - screen._width_max, screen._height_max)) - print(" %smm x %smm" % (screen._width_mm, screen._height_mm)) - print("Outputs:") - for o in list(screen.outputs.keys()): - output = screen.outputs[o] - print(" %s" % o, end=' ') - if output.is_connected(): - print("(%smm x %smm)" % (output.get_physical_width(), - output.get_physical_height())) - modes = output.get_available_modes() - print(" Modes:") - for m in range(len(modes)): - mode = modes[m] - refresh = mode.dotClock / (mode.hTotal * mode.vTotal) - print( - " [%s] %s x %s @ %s Hz" % - (m, mode.width, mode.height, refresh), end=' ') - if mode.id == output._mode: - print("(current)", end=' ') - if m == output.get_preferred_mode(): - print("(preferred)", end=' ') - print("") - else: - print("(not connected)") - - -def main(): - screen = xrandr.get_current_screen() - try: - print_modes_info(screen) - except(xrandr.UnsupportedRRError): - print('Error: RandR version lower than 1.0', file=sys.stderr) - - -if __name__ == '__main__': - main() diff --git a/bin/install-method-check.sh b/bin/install-method-check.sh new file mode 100755 index 0000000..20c0e61 --- /dev/null +++ b/bin/install-method-check.sh @@ -0,0 +1,149 @@ +#!/bin/bash + +# Copyright (C) 2012-2022 Canonical Ltd. + +# Authors +# Jeff Lane <jeff@ubuntu.com> +# Rod Smith <rod.smith@canonical.com> + +# This program 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. + +# This program 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 this program. If not, see <http://www.gnu.org/licenses/>. + +MAAS_FILE="/etc/installed-by-maas" +DATASOURCE_FILE="/var/lib/cloud/instance/datasource" +INSTALL_DATASOURCE="" +SUBIQUITY_LOG_FILE1="/var/log/installer/subiquity-info.log" # Observed on 20.04 +SUBIQUITY_LOG_FILE2="/var/log/installer/subiquity-server-info.log" # Observed on 22.04 +CONFIRM_INSTALL_TYPE="maas" # or "subiquity", maybe others in future +RETVAL="0" + +get_params() { + # Default to equivalent of --maas; the option is provided for clarity + # in calling script. + while [[ $# -gt 0 ]]; do + case $1 in + --maas|-m) + CONFIRM_INSTALL_TYPE="maas" # should already be set + ;; + --iso|-i) + CONFIRM_INSTALL_TYPE="subiquity" + ;; + *) echo "Usage: $0 [ -m, --maas ] | [ -i, --iso ]" + ;; + esac + shift + done + INSTALL_DATASOURCE_FOUND=0 # Should be found for both MAAS & subiquity + MAAS_IP_FOUND=0 # Should be found for MAAS but not subiquity + MAAS_VERSION_FOUND=0 # Should be found for MAAS but not subiquity + SUBIQUITY_LOG_FOUND=0 # Should be found for subiquity but not MAAS +} + +# Context-sensitive echo() function; prints the message only if the program +# is launched to confirm a MAAS installation +conditional_print() { + if [[ "$CONFIRM_INSTALL_TYPE" == "$2" ]] ; then + echo "$1" + fi +} + +# Find the installation data source, as recorded in cloud installer files. +# This should be present for both MAAS and subiquity installs. +get_install_datasource() { + # Is the file there? + if [ -s $DATASOURCE_FILE ]; then + INSTALL_DATASOURCE=$(cut -d "[" -f 2 $DATASOURCE_FILE | cut -d "]" -f 1) + echo "Installation data source is $INSTALL_DATASOURCE" + INSTALL_DATASOURCE_FOUND=1 + else + echo "ERROR: The installation data source file ($DATASOURCE_FILE)" + echo "cannot be found." + fi +} + +# Verify that the $INSTALL_DATASOURCE points to a valid IP address. +# Note: Function assumes that $INSTALL_DATASOURCE is already set, as is +# done by the get_install_datasource() function. +verify_maas_ip() { + if [[ $INSTALL_DATASOURCE_FOUND == 1 ]]; then + MAAS_HOSTNAME=$(echo "$INSTALL_DATASOURCE" | cut -d "/" -f 3 | cut -d ":" -f 1) + HOST_OUTPUT=$(host "$MAAS_HOSTNAME" | grep "has address") + status=$? + if [[ $status -eq 0 ]]; then + MAAS_IP=$(echo "$HOST_OUTPUT" | cut -d " " -f 4) + conditional_print "MAAS server's IP address is $MAAS_IP" "maas" + conditional_print "ERROR: MAAS server's IP address is $MAAS_IP" "subiquity" + MAAS_IP_FOUND=1 + else + conditional_print "ERROR: Unable to determine MAAS server's IP address" "maas" + fi + fi +} + +# Pull the MAAS version information from a file left here by the +# Server Certification pre-seed file +get_maas_version() { + # Is the file there? + if [ -s $MAAS_FILE ]; then + maas_version=$(cat $MAAS_FILE) + conditional_print "MAAS version is $maas_version" "maas" + conditional_print "ERROR: Server Certification MAAS version file found; MAAS version is $maas_version" "subiquity" + MAAS_VERSION_FOUND=1 + else + conditional_print "ERROR: The MAAS version cannot be determined" "maas" + fi +} + +find_subiquity_log() { + if [[ -f "$SUBIQUITY_LOG_FILE1" || -f "$SUBIQUITY_LOG_FILE2" ]]; then + conditional_print "ERROR: Subiquity log file found" "maas" + conditional_print "subiquity log file found" "subiquity" + SUBIQUITY_LOG_FOUND=1 + else + conditional_print "ERROR: Subiquity log file not found" "subiquity" + fi +} + +####################### +# +# Main program begins here.... +# +####################### + +get_params "$@" + +# Check for various installation signatures.... +get_install_datasource +verify_maas_ip +get_maas_version +find_subiquity_log + +MAAS_FOUND=$((INSTALL_DATASOURCE_FOUND && MAAS_IP_FOUND && MAAS_VERSION_FOUND)) +SUBIQUITY_FOUND=$((INSTALL_DATASOURCE_FOUND && SUBIQUITY_LOG_FOUND)) + +if [[ $CONFIRM_INSTALL_TYPE == "maas" ]] ; then + RETVAL=$((! MAAS_FOUND)) || SUBIQUITY_FOUND + if [[ $RETVAL == 0 ]] ; then + echo "PASS: System appears to have been installed by MANIACS-compliant MAAS." + else + echo "FAIL: System appears to have not been installed by MANIACS-compliant MAAS." + fi +elif [[ $CONFIRM_INSTALL_TYPE == "subiquity" ]] ; then + RETVAL=$((! SUBIQUITY_FOUND)) || MAAS_FOUND + if [[ $RETVAL == 0 ]] ; then + echo "PASS: System appears to have been installed by a Subiquity ISO." + else + echo "FAIL: System appears to have not been installed by a Subiquity ISO." + fi +fi + +exit $RETVAL diff --git a/bin/maas-version-check.sh b/bin/maas-version-check.sh deleted file mode 100755 index 7d97f0b..0000000 --- a/bin/maas-version-check.sh +++ /dev/null @@ -1,75 +0,0 @@ -#!/bin/bash - -# Copyright (C) 2012-2022 Canonical Ltd. - -# Authors -# Jeff Lane <jeff@ubuntu.com> -# Rod Smith <rod.smith@canonical.com> - -# This program 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. - -# This program 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 this program. If not, see <http://www.gnu.org/licenses/>. - -MAAS_FILE="/etc/installed-by-maas" -DATASOURCE_FILE="/var/lib/cloud/instance/datasource" -MAAS_DATASOURCE="" -RETVAL="0" - -# Find the MAAS data source, as recorded in cloud installer files -get_maas_datasource() { - # Is the file there? - if [ -s $DATASOURCE_FILE ]; then - MAAS_DATASOURCE=$(cut -d "[" -f 2 $DATASOURCE_FILE | cut -d "]" -f 1) - echo "MAAS data source is $MAAS_DATASOURCE" - else - echo "ERROR: This system does not appear to have been installed by MAAS" - echo "ERROR: " "$(ls -l $DATASOURCE_FILE 2>&1)" - RETVAL="1" - fi -} - -# Verify that the $MAAS_DATASOURCE points to a valid IP address. -# Note: Function assumes that $MAAS_DATASOURCE is already set, as is -# done by the get_maas_datasource() function. -verify_maas_ip() { - if [[ $RETVAL == 0 ]]; then - MAAS_HOSTNAME=$(echo "$MAAS_DATASOURCE" | cut -d "/" -f 3 | cut -d ":" -f 1) - HOST_OUTPUT=$(host "$MAAS_HOSTNAME" | grep "has address") - status=$? - if [[ $status -eq 0 ]]; then - MAAS_IP=$(echo "$HOST_OUTPUT" | cut -d " " -f 4) - echo "MAAS server's IP address is $MAAS_IP" - else - echo "ERROR: Unable to determine MAAS server's IP address" - RETVAL=1 - fi - fi -} - -# Pull the MAAS version information from a file left here by the -# Server Certification pre-seed file -get_maas_version() { - # Is the file there? - if [ -s $MAAS_FILE ]; then - maas_version=$(cat $MAAS_FILE) - echo "MAAS version is $maas_version" - else - echo "ERROR: The MAAS version cannot be determined" - echo "ERROR: " "$(ls -l $MAAS_FILE 2>&1)" - RETVAL="1" - fi -} - -get_maas_datasource -verify_maas_ip -get_maas_version - -exit $RETVAL diff --git a/bin/removable_storage_watcher.py b/bin/removable_storage_watcher.py index c13439e..7208954 100755 --- a/bin/removable_storage_watcher.py +++ b/bin/removable_storage_watcher.py @@ -5,7 +5,9 @@ import collections import copy import dbus import logging +import os import sys +import threading import gi gi.require_version('GUdev', '1.0') @@ -16,12 +18,14 @@ from checkbox_support.dbus.udisks2 import UDisks2Model # noqa: E402 from checkbox_support.dbus.udisks2 import UDisks2Observer # noqa: E402 from checkbox_support.dbus.udisks2 import is_udisks2_supported # noqa: E402 from checkbox_support.dbus.udisks2 import lookup_udev_device # noqa: E402 -from checkbox_support.dbus.udisks2 import ( +from checkbox_support.dbus.udisks2 import ( # noqa: E402 map_udisks1_connection_bus) # noqa: E402 from checkbox_support.heuristics.udisks2 import is_memory_card # noqa: E402 from checkbox_support.parsers.udevadm import CARD_READER_RE # noqa: E402 from checkbox_support.parsers.udevadm import GENERIC_RE # noqa: E402 from checkbox_support.parsers.udevadm import FLASH_RE # noqa: E402 +from checkbox_support.scripts.zapper_proxy import ( # noqa: E402 + ControlVersionDecider) from checkbox_support.udev import get_interconnect_speed # noqa: E402 from checkbox_support.udev import get_udev_block_devices # noqa: E402 @@ -877,6 +881,8 @@ def main(): dest='logging_level', help="Enable debugging") parser.add_argument('--unmounted', action='store_true', help="Don't require drive being automounted") + parser.add_argument('--zapper-usb-address', type=str, + help="Zapper's USB switch address to use") parser.set_defaults(logging_level=logging.WARNING) args = parser.parse_args() @@ -910,11 +916,38 @@ def main(): args.action, args.device, args.minimum_speed, args.memorycard) # Run the actual listener and wait till it either times out of discovers # the appropriate media changes - print("\n\n{} NOW\n\n".format(args.action.upper()), flush=True) - try: - return listener.check(args.timeout) - except KeyboardInterrupt: - return 1 + if args.zapper_usb_address: + zapper_host = os.environ.get('ZAPPER_ADDRESS') + if not zapper_host: + raise SystemExit( + "ZAPPER_ADDRESS environment variable not found!") + zapper_control = ControlVersionDecider().decide(zapper_host) + usb_address = args.zapper_usb_address + delay = 5 # in seconds + + def do_the_insert(): + logging.info("Calling zapper to connect the USB device") + zapper_control.usb_set_state(usb_address, 'dut') + insert_timer = threading.Timer(delay, do_the_insert) + + def do_the_remove(): + logging.info("Calling zapper to disconnect the USB device") + zapper_control.usb_set_state(usb_address, 'off') + remove_timer = threading.Timer(delay, do_the_remove) + if args.action == "insert": + logging.info("Starting timer for delayed insertion") + insert_timer.start() + elif args.action == "remove": + logging.info("Starting timer for delayed removal") + remove_timer.start() + try: + res = listener.check(args.timeout) + return res + except KeyboardInterrupt: + return 1 + + else: + print("\n\n{} NOW\n\n".format(args.action.upper()), flush=True) if __name__ == "__main__": diff --git a/bin/screenoff.sh b/bin/screenoff.sh index 0769e58..7c07f7d 100755 --- a/bin/screenoff.sh +++ b/bin/screenoff.sh @@ -34,3 +34,4 @@ evemu-event "${device}" --type EV_MSC --code MSC_SCAN --value 28 evemu-event --sync "${device}" --type EV_KEY --code KEY_ENTER --value 1 evemu-event "${device}" --type EV_MSC --code MSC_SCAN --value 28 evemu-event --sync "${device}" --type EV_KEY --code KEY_ENTER --value 0 +loginctl unlock-session diff --git a/bin/snap_tests.py b/bin/snap_tests.py index 1cc84bf..b20cd1c 100755 --- a/bin/snap_tests.py +++ b/bin/snap_tests.py @@ -22,6 +22,8 @@ except KeyError: TEST_SNAP = 'test-snapd-tools-core18' elif 'checkbox20' in runtime: TEST_SNAP = 'test-snapd-tools-core20' + elif 'checkbox22' in runtime: + TEST_SNAP = 'test-snapd-tools-core22' else: TEST_SNAP = 'test-snapd-tools' SNAPD_TASK_TIMEOUT = int(os.getenv('SNAPD_TASK_TIMEOUT', 30)) @@ -36,7 +38,8 @@ class SnapList(): """snap list should show the core package is installed.""" data = Snapd().list() for snap in data: - if snap['name'] in ('core', 'core16', 'core18', 'core20'): + if snap['name'] in ('core', 'core16', 'core18', 'core20', + 'core22'): print("Found a core snap") print(snap['name'], snap['version'], snap['revision']) return 0 diff --git a/bin/touchpad_test.py b/bin/touchpad_test.py index 6ecde92..83940ec 100755 --- a/bin/touchpad_test.py +++ b/bin/touchpad_test.py @@ -3,6 +3,7 @@ import gi import sys import gettext +from time import sleep from gettext import gettext as _ gi.require_version('Gdk', '3.0') @@ -43,7 +44,7 @@ class GtkScroller(object): # Initialize GTK constants self.ICON_SIZE = Gtk.IconSize.BUTTON self.ICON_TESTED = Gtk.STOCK_YES - self.ICON_UNTESTED = Gtk.STOCK_INDEX + self.ICON_UNTESTED = Gtk.STOCK_DIALOG_QUESTION self.ICON_NOT_REQUIRED = Gtk.STOCK_REMOVE self.button_factory = Gtk.Button @@ -70,7 +71,7 @@ class GtkScroller(object): button_hbox = self._add_hbox(vbox) validation_hbox = self._add_hbox(vbox) self.status = self._add_label(vbox) - self.exit_button = self._add_button(vbox, Gtk.STOCK_CLOSE) + self.exit_button = self._add_button(vbox, "_Close") self.exit_button.connect("clicked", lambda w: self.quit()) # Add widgets for each direction. @@ -78,15 +79,15 @@ class GtkScroller(object): for direction in self.directions: self._add_label(button_hbox, direction.name) self.icons[direction] = self._add_image( - validation_hbox, Gtk.STOCK_INDEX) + validation_hbox, self.ICON_UNTESTED) self.show_text( _("Please move the mouse cursor to this window.") + "\n" + _("Then scroll in each direction on your touchpad.")) - def _add_button(self, context, stock): - button = self.button_factory(stock=stock) + def _add_button(self, context, label): + button = self.button_factory.new_with_mnemonic(label) context.add(button) button.show() return button @@ -124,29 +125,33 @@ class GtkScroller(object): def run(self): # Save touchpad settings. - if self.horiz_scroll_key: - self.saved_horiz_scroll_enabled = \ - self.touchpad_settings.get_boolean("horiz-scroll-enabled") - self.saved_scroll_method = self.touchpad_settings.get_string( - "scroll-method") + self.saved_edge_scrolling_enabled = self.touchpad_settings.get_boolean( + "edge-scrolling-enabled") + self.saved_two_finger_enabled = self.touchpad_settings.get_boolean( + "two-finger-scrolling-enabled") # Set touchpad settings. - if self.horiz_scroll_key: - self.touchpad_settings.set_boolean("horiz-scroll-enabled", True) if self.edge_scroll: - self.touchpad_settings.set_string( - "scroll-method", "edge-scrolling") - + self.touchpad_settings.set_boolean( + "edge-scrolling-enabled", True) + self.touchpad_settings.set_boolean( + "two-finger-scrolling-enabled", False) + else: + self.touchpad_settings.set_boolean( + "two-finger-scrolling-enabled", True) + self.touchpad_settings.set_boolean( + "edge-scrolling-enabled", False) Gtk.main() def quit(self): # Reset touchpad settings. - if self.horiz_scroll_key: - self.touchpad_settings.set_boolean( - "horiz-scroll-enabled", self.saved_horiz_scroll_enabled) - self.touchpad_settings.set_string( - "scroll-method", self.saved_scroll_method) - + self.touchpad_settings.set_boolean( + "two-finger-scrolling-enabled", self.saved_two_finger_enabled) + # GNOME does not like when both settings are set at the same time, so + # waiting a bit. + sleep(0.1) + self.touchpad_settings.set_boolean( + "edge-scrolling-enabled", self.saved_edge_scrolling_enabled) Gtk.main_quit() def show_text(self, text, widget=None): @@ -156,7 +161,7 @@ class GtkScroller(object): def found_direction(self, direction): direction.tested = True - self.icons[direction].set_from_stock( + self.icons[direction].set_from_icon_name( self.ICON_TESTED, size=self.ICON_SIZE) self.check_directions() @@ -169,10 +174,25 @@ class GtkScroller(object): def on_scroll(self, window, event): for direction in self.directions: - if direction.value == event.direction: - self.found_direction(direction) - break - + scroll_delta, delta_x, delta_y = event.get_scroll_deltas() + if scroll_delta: + event_direction = None + # Arbitrarily using 0.8, which requires a little bit of hand + # movement on the touchpads used for testing. + # Note that the directions are based on the default natural + # scrolling settings in GNOME settings. + if delta_x > 0.8: + event_direction = Direction("left") + elif delta_x < -0.8: + event_direction = Direction("right") + if delta_y > 0.8: + event_direction = Direction("up") + elif delta_y < -0.8: + event_direction = Direction("down") + if event_direction: + if direction.value == event_direction.value: + self.found_direction(direction) + break return True diff --git a/bin/virtualization.py b/bin/virtualization.py index a3794de..034554b 100755 --- a/bin/virtualization.py +++ b/bin/virtualization.py @@ -557,149 +557,6 @@ class RunCommand(object): self.returncode = proc.returncode -class UVTKVMTest(object): - - def __init__(self, image=None): - self.image = image - self.release = get_codename_to_test() - self.arch = check_output(['dpkg', '--print-architecture'], - universal_newlines=True).strip() - # max len(name) is 8 chars for use with test-snapd-uvtool snap - self.name = tempfile.mktemp()[-8:] - - def run_command(self, cmd): - task = RunCommand(cmd) - if task.returncode != 0: - logging.error('Command {} returnd a code of {}'.format( - task.cmd, task.returncode)) - logging.error(' STDOUT: {}'.format(task.stdout)) - logging.error(' STDERR: {}'.format(task.stderr)) - return False - else: - logging.debug('Command {}:'.format(task.cmd)) - if task.stdout != '': - logging.debug(' STDOUT: {}'.format(task.stdout)) - elif task.stderr != '': - logging.debug(' STDERR: {}'.format(task.stderr)) - else: - logging.debug(' Command returned no output') - return True - - def ssh_command(self, private_key_file, cmd): - task = RunCommand("uvt-kvm ip {}".format(self.name)) - if task.returncode != 0: - logging.error('Command {} returnd a code of {}'.format( - task.cmd, task.returncode)) - return False - vm_ip = task.stdout - - ssh_cmd = ('ssh ubuntu@{} ' - '-o UserKnownHostsFile=/dev/null ' - '-o StrictHostKeyChecking=no ' - '-i {} {}').format(vm_ip, private_key_file, cmd) - return self.run_command(ssh_cmd) - - def get_image_or_source(self): - """ - An image can be specifed in a filesytem path and used directly in - uvt-create with the backing-image option or a url can be - specifed and used in uvt-simplestreams to generate an image. - """ - url = urlparse(self.image) - - if url.scheme == 'file' or os.path.isfile(url.path): - logging.debug("Cloud image exists locally at %s" % url.path) - self.image = url.path - else: - cmd = ("uvt-simplestreams-libvirt sync release={} " - "arch={}".format(self.release, self.arch)) - - if url.scheme == 'http': - # Path specified to use -source option - logging.debug("Using --source option for uvt-simpletreams") - cmd = cmd + " --source {} ".format(self.image) - - logging.debug("uvt-simplestreams-libvirt sync") - if not self.run_command(cmd): - return False - return True - - def cleanup(self): - """ - A combination of virsh destroy/undefine is used instead of - uvt-kvm destroy. When using uvt-kvm destroy the following bug - is seen: - https://bugs.launchpad.net/ubuntu/+source/uvtool/+bug/1452095 - """ - # Destroy vm - logging.debug("Destroy VM") - if not self.run_command('virsh destroy {}'.format(self.name)): - return False - - # Virsh undefine - logging.debug("Undefine VM") - if not self.run_command('virsh undefine {}'.format(self.name)): - return False - - # Purge/Remove simplestreams image - if not self.run_command("uvt-simplestreams-libvirt purge"): - return False - return True - - def start(self): - # Generate ssh key if needed - with tempfile.TemporaryDirectory( - dir=os.path.expandvars("$PLAINBOX_SESSION_SHARE")) as tmp_dir: - ssh_private_key_file = "{}/id_rsa".format(tmp_dir) - ssh_public_key_file = "{}/id_rsa.pub".format(tmp_dir) - - if not os.path.exists(ssh_private_key_file): - cmd = ('ssh-keygen -f {} -t rsa -N \'\''.format( - ssh_private_key_file)) - if not self.run_command(cmd): - return False - - # Create vm - logging.debug("Creating VM") - cmd = ('uvt-kvm create --ssh-public-key-file {} {} arch={}'.format( - ssh_public_key_file, self.name, self.arch)) - - logging.debug("Checking for local image") - try: - self.image.find(".img") > 0 - except AttributeError: - logging.debug("No user provided image found.") - logging.debug( - "I will attempt to sync the image from ubuntu.com") - else: - cmd = cmd + " --backing-image-file {} ".format(self.image) - - if not self.run_command(cmd): - return False - - logging.debug("Wait for VM to complete creation") - cmd = 'uvt-kvm wait --ssh-private-key-file {} {}'.format( - ssh_private_key_file, self.name) - if not self.run_command(cmd): - return False - - logging.debug("List newly created vm") - cmd = ("uvt-kvm list") - if not self.run_command(cmd): - return False - - logging.debug("Verify VM was created with ssh") - if not self.ssh_command(ssh_private_key_file, ""): - return False - - logging.debug("Verify VM was created with ssh and run a command") - cmd = "lsb_release -a" - if not self.ssh_command(ssh_private_key_file, cmd): - return False - - return True - - class LXDTest(object): def __init__(self, template=None, rootfs=None): @@ -865,25 +722,208 @@ class LXDTest(object): return True -def test_uvtkvm(args): - logging.debug("Executing UVT KVM Test") - # if args.image is not set and UVT_IMAGE_OR_SOURCE does not exist, a key - # error is generated we need to handle. - try: - image = args.image or os.environ['UVT_IMAGE_OR_SOURCE'] - except KeyError: - logging.warning("UVT_IMAGE_OR_SOURCE is not set") - image = None - uvt_test = UVTKVMTest(image) - uvt_test.get_image_or_source() - result = uvt_test.start() - uvt_test.cleanup() +class LXDTest_vm(object): + + def __init__(self, template=None, image=None): + self.image_url = image + self.template_url = template + self.image_tarball = None + self.template_tarball = None + self.name = 'testbed' + self.image_alias = uuid4().hex + self.default_remote = "ubuntu:" + self.os_version = get_release_to_test() + + def run_command(self, cmd): + task = RunCommand(cmd) + if task.returncode != 0: + logging.error('Command {} returnd a code of {}'.format( + task.cmd, task.returncode)) + logging.error(' STDOUT: {}'.format(task.stdout)) + logging.error(' STDERR: {}'.format(task.stderr)) + return False + else: + logging.debug('Command {}:'.format(task.cmd)) + if task.stdout != '': + logging.debug(' STDOUT: {}'.format(task.stdout)) + elif task.stderr != '': + logging.debug(' STDERR: {}'.format(task.stderr)) + else: + logging.debug(' Command returned no output') + return True + + def setup(self): + # Initialize LXD + result = True + logging.debug("Attempting to initialize LXD") + # TODO: Need a method to see if LXD is already initialized + if not self.run_command('lxd init --auto'): + logging.debug('Error encounterd while initializing LXD') + result = False + + # Retrieve and insert LXD images + if self.template_url is not None: + logging.debug("Downloading template.") + targetfile = urlparse(self.template_url).path.split('/')[-1] + filename = os.path.join('/tmp', targetfile) + if not os.path.isfile(filename): + self.template_tarball = self.download_images(self.template_url, + filename) + if not self.template_tarball: + logging.error("Unable to download {} from " + "{}".format(self.template_tarball, + self.template_url)) + logging.error("Aborting") + result = False + else: + logging.debug("Template file {} already exists. " + "Skipping Download.".format(filename)) + self.template_tarball = filename + + if self.image_url is not None: + logging.debug("Downloading image.") + targetfile = urlparse(self.image_url).path.split('/')[-1] + filename = os.path.join('/tmp', targetfile) + if not os.path.isfile(filename): + self.image_tarball = self.download_images(self.image_url, + filename) + if not self.image_tarball: + logging.error("Unable to download {} from{}".format( + self.image_tarball, self.image_url)) + logging.error("Aborting") + result = False + else: + logging.debug("Template file {} already exists. " + "Skipping Download.".format(filename)) + self.image_tarball = filename + + # Insert images + if self.template_url is not None and self.image_url is not None: + logging.debug("Importing images into LXD") + cmd = 'lxc image import {} {} --alias {}'.format( + self.template_tarball, self.image_tarball, + self.image_alias) + result = self.run_command(cmd) + if not result: + logging.error('Error encountered while attempting to ' + 'import images into LXD') + result = False + return result + + def download_images(self, url, filename): + """ + Downloads LXD files for same release as host machine + """ + # TODO: Clean this up to use a non-internet simplestream on MAAS server + logging.debug("Attempting download of {} from {}".format(filename, + url)) + try: + urllib.request.urlretrieve(url, filename) + except (IOError, + OSError, + urllib.error.HTTPError, + urllib.error.URLError) as exception: + logging.error("Failed download of image from %s: %s", + url, exception) + return False + except ValueError as verr: + logging.error("Invalid URL %s" % url) + logging.error("%s" % verr) + return False + + if not os.path.isfile(filename): + logging.warn("Can not find {}".format(filename)) + return False + + return filename + def cleanup(self): + """ + Clean up test files an Virtual Machines created + """ + logging.debug('Cleaning up images and VMs created during test') + self.run_command('lxc image delete {}'.format(self.image_alias)) + self.run_command('lxc delete --force {}'.format(self.name)) + + def start_vm(self): + """ + Creates an lxd virtutal machine and performs the test + """ + wait_interval = 5 + test_interval = 300 + + result = self.setup() + if not result: + logging.error("One or more setup stages failed.") + return False + + # Create Virtual Machine + logging.debug("Launching Virtual Machine") + if not self.image_url and not self.template_url: + logging.debug("No local image available, attempting to " + "import from default remote.") + cmd = ('lxc init {}{} {} --vm '.format( + self.default_remote, self.os_version, self.name)) + else: + cmd = ('lxc init {} {} --vm'.format(self.image_alias, self.name)) + + if not self.run_command(cmd): + return False + + logging.debug("Start VM:") + cmd = ("lxc start {} ".format(self.name)) + if not self.run_command(cmd): + return False + + logging.debug("Virtual Machine listing:") + cmd = ("lxc list") + if not self.run_command(cmd): + return False + + logging.debug("Wait for vm to boot") + check_vm = 0 + while check_vm < test_interval: + time.sleep(wait_interval) + cmd = ("lxc exec {} -- lsb_release -a".format(self.name)) + if self.run_command(cmd): + print("Vm started and booted succefully") + return True + else: + logging.debug("Re-verify VM booted") + check_vm = check_vm + wait_interval + + logging.debug("testing vm failed") + if check_vm == test_interval: + return False + + +def test_lxd_vm(args): + logging.debug("Executing LXD VM Test") + + template = None + image = None + + # First in priority are environment variables. + if 'LXD_TEMPLATE' in os.environ: + template = os.environ['LXD_TEMPLATE'] + if 'KVM_IMAGE' in os.environ: + image = os.environ['KVM_IMAGE'] + + # Finally, highest-priority are command line arguments. + if args.template: + template = args.template + if args.image: + image = args.image + + lxd_test = LXDTest_vm(template, image) + + result = lxd_test.start_vm() + lxd_test.cleanup() if result: - print("PASS: VM was succssfully started and checked") + print("PASS: Virtual Machine was succssfully started and checked") sys.exit(0) else: - print("FAIL: VM was not started and/or checked") + print("FAIL: Virtual Machine was not started and checked") sys.exit(1) @@ -961,10 +1001,10 @@ def main(): # Main cli options kvm_test_parser = subparsers.add_parser( 'kvm', help=("Run kvm virtualization test")) - uvt_kvm_test_parser = subparsers.add_parser( - 'uvt', help=("Run uvt kvm virtualization test")) lxd_test_parser = subparsers.add_parser( 'lxd', help=("Run the LXD validation test")) + lxd_test_vm_parser = subparsers.add_parser( + 'lxdvm', help=("Run the LXD VM validation test")) parser.add_argument('--debug', dest='log_level', action="store_const", const=logging.DEBUG, default=logging.INFO) @@ -980,16 +1020,19 @@ def main(): kvm_test_parser.set_defaults(func=test_kvm) # Sub test options - uvt_kvm_test_parser.add_argument( - '-i', '--image', type=str) - uvt_kvm_test_parser.set_defaults(func=test_uvtkvm) - lxd_test_parser.add_argument( '--template', type=str, default=None) lxd_test_parser.add_argument( '--rootfs', type=str, default=None) lxd_test_parser.set_defaults(func=test_lxd) + # Sub test options + lxd_test_vm_parser.add_argument( + '--template', type=str, default=None) + lxd_test_vm_parser.add_argument( + '--image', type=str, default=None) + lxd_test_vm_parser.set_defaults(func=test_lxd_vm) + args = parser.parse_args() try: diff --git a/bin/wifi_nmcli_test.py b/bin/wifi_nmcli_test.py index 936af9a..818d4cf 100755 --- a/bin/wifi_nmcli_test.py +++ b/bin/wifi_nmcli_test.py @@ -48,7 +48,7 @@ def cleanup_nm_connections(): print_cmd(cmd) output = sp.check_output(cmd, shell=True) for line in output.decode(sys.stdout.encoding).splitlines(): - type, uuid, name = line.strip().split(':') + type, uuid, name = line.strip().split(':', 2) if type == '802-11-wireless': print("Deleting connection", name) cmd = "nmcli c delete {}".format(uuid) @@ -83,7 +83,7 @@ def list_aps(args): # lp bug #1723372 - extra line in output on zesty if line.strip() == args.device: continue - ssid, channel, frequency, signal = line.strip().split(':') + ssid, channel, frequency, signal = line.strip().rsplit(':', 3) print("SSID: {} Chan: {} Freq: {} Signal: {}".format( ssid, channel, frequency, signal)) if hasattr(args, 'essid'): @@ -5,7 +5,7 @@ from plainbox.provider_manager import N_ setup( name='plainbox-provider-checkbox', namespace='com.canonical.certification', - version="0.64.0", + version="0.65.0rc1", description=N_("Checkbox provider"), gettext_domain='plainbox-provider-checkbox', strict=False, deprecated=False, diff --git a/units/graphics/jobs.pxu b/units/graphics/jobs.pxu index 4dde304..8206f1a 100644 --- a/units/graphics/jobs.pxu +++ b/units/graphics/jobs.pxu @@ -133,13 +133,7 @@ category_id: com.canonical.plainbox::graphics requires: device.category == 'VIDEO' command: - # shellcheck disable=SC1091 - source graphics_env.sh {driver} {index} - maxi="$(xrandr -q |grep -A 1 "connected\( primary\)* [0-9]" |tail -1 |awk '{{print $1}}')" - now="$(python3 -c 'from gi.repository import Gdk; screen=Gdk.Screen.get_default(); geo = screen.get_monitor_geometry(screen.get_primary_monitor()); print(geo.width, "x", geo.height, sep="")')" - test "$maxi" != "$now" && notify="\nPlease switch to the maximum resolution \nfor every graphic tests" - echo "Maximum resolution: $maxi" - echo "Current resolution: $now $notify" + graphics_max_resolution.py estimated_duration: 10.0 _summary: Test maximum supported resolution for {vendor} {product} _description: @@ -154,16 +148,6 @@ _description: unit: template template-resource: graphics_card -id: graphics/{index}_modes_{product_slug} -plugin: shell -category_id: com.canonical.plainbox::graphics -command: graphics_modes_info.py -estimated_duration: 0.250 -_description: Collect info on graphics modes (screen resolution and refresh rate) for {vendor} {product} -_summary: Test graphic modes info for {vendor} {product} - -unit: template -template-resource: graphics_card id: graphics/{index}_color_depth_{product_slug} plugin: shell category_id: com.canonical.plainbox::graphics diff --git a/units/graphics/legacy.pxu b/units/graphics/legacy.pxu index 14969b0..2b9545d 100644 --- a/units/graphics/legacy.pxu +++ b/units/graphics/legacy.pxu @@ -96,14 +96,6 @@ _description: VERIFICATION: Is this the display's maximum resolution? -id: graphics/modes -plugin: shell -category_id: com.canonical.plainbox::graphics -command: graphics_modes_info.py -estimated_duration: 0.250 -_description: Collect info on graphics modes (screen resolution and refresh rate) -_summary: Collect info on graphics modes - id: graphics/color_depth plugin: shell category_id: com.canonical.plainbox::graphics diff --git a/units/graphics/test-plan.pxu b/units/graphics/test-plan.pxu index 8725b0d..fe7d4a1 100644 --- a/units/graphics/test-plan.pxu +++ b/units/graphics/test-plan.pxu @@ -32,9 +32,6 @@ _description: Graphics tests (integrated GPU) (Automated) include: graphics/1_auto_switch_card_.* certification-status=blocker - graphics/xorg-version certification-status=blocker - graphics/xorg-failsafe certification-status=blocker - graphics/xorg-process certification-status=blocker graphics/VESA_drivers_not_in_use certification-status=blocker graphics/1_driver_version_.* certification-status=blocker graphics/1_gl_support_.* certification-status=blocker @@ -169,9 +166,6 @@ _name: Graphics tests (integrated GPU, certification blockers only) _description: Graphics tests (integrated GPU, certification blockers only) include: graphics/1_auto_switch_card_.* certification-status=blocker - graphics/xorg-version certification-status=blocker - graphics/xorg-failsafe certification-status=blocker - graphics/xorg-process certification-status=blocker graphics/VESA_drivers_not_in_use certification-status=blocker graphics/1_maximum_resolution_.* certification-status=blocker graphics/1_glxgears_.* certification-status=blocker diff --git a/units/miscellanea/jobs.pxu b/units/miscellanea/jobs.pxu index 785eebe..7e13164 100644 --- a/units/miscellanea/jobs.pxu +++ b/units/miscellanea/jobs.pxu @@ -396,12 +396,20 @@ plugin: shell category_id: com.canonical.plainbox::miscellanea estimated_duration: 0.1 id: miscellanea/get_maas_version -command: maas-version-check.sh +command: install-method-check.sh --maas _description: If system was installed via MAAS from a cert server, the MAAS version used should be contained in /etc/installed-by-maas _summary: Verify MAAS version used to deploy the SUT plugin: shell category_id: com.canonical.plainbox::miscellanea +estimated_duration: 0.1 +id: miscellanea/test_iso_install +command: install-method-check.sh --iso +_description: Test that the system was installed via a Subiquity ISO image +_summary: Test that the system was installed via a Subiquity ISO image + +plugin: shell +category_id: com.canonical.plainbox::miscellanea estimated_duration: 30.0 id: miscellanea/get_make_and_model user: root diff --git a/units/monitor/jobs.pxu b/units/monitor/jobs.pxu index 46ecb20..ec57b59 100644 --- a/units/monitor/jobs.pxu +++ b/units/monitor/jobs.pxu @@ -136,14 +136,16 @@ flags: also-after-suspend id: monitor/{index}_powersaving_{product_slug} plugin: user-interact-verify category_id: com.canonical.plainbox::monitor -command: xset dpms force off +command: + busctl --user call org.gnome.Shell /org/gnome/ScreenSaver org.gnome.ScreenSaver SetActive b true + sleep 5 + busctl --user call org.gnome.Shell /org/gnome/ScreenSaver org.gnome.ScreenSaver SetActive b false _purpose: This test will check your monitor power saving capabilities _steps: - 1. Click "Test" to try the power saving capabilities of your monitor - 2. Press any key or move the mouse to recover + 1. Start the test to try the power saving capabilities of your monitor _verification: - Did the monitor go blank and turn on again? + Did the monitor go blank and turn on again after a few seconds? unit: template template-resource: graphics_card diff --git a/units/touchpad/jobs.pxu b/units/touchpad/jobs.pxu index 95dfc5b..11960ee 100644 --- a/units/touchpad/jobs.pxu +++ b/units/touchpad/jobs.pxu @@ -102,37 +102,20 @@ _siblings: plugin: user-interact category_id: com.canonical.plainbox::touchpad -id: touchpad/multitouch-horizontal +id: touchpad/multitouch requires: dmi.product in ['Notebook','Laptop','Portable','Convertible'] -command: touchpad_test.py right left +command: touchpad_test.py up down right left estimated_duration: 120.0 _purpose: - Touchpad 2-touch horizontal scroll verification + Touchpad 2-finger scroll verification _steps: - 1. Select "Test" when ready and place your cursor within the borders of the displayed test window. - 2. Verify that you can move the horizontal slider by moving 2 fingers right and left along the touchpad. -_verification: - Could you scroll right and left? -_siblings: - [{ "id": "touchpad/multitouch-horizontal-after-suspend", - "depends": "suspend/suspend_advanced_auto touchpad/multitouch-horizontal" }] - -plugin: user-interact -category_id: com.canonical.plainbox::touchpad -id: touchpad/multitouch-vertical -requires: dmi.product in ['Notebook','Laptop','Portable','Convertible'] -command: touchpad_test.py up down -estimated_duration: 120.0 -_purpose: - Touchpad 2-touch vertical scroll verification -_steps: - 1. Select "Test" when ready and place your cursor within the borders of the displayed test window. - 2. Verify that you can move the vertical slider by moving 2 fingers up and down along the touchpad. + 1. Press "Enter" when ready and place your cursor within the borders of the displayed test window. + 2. Verify that the scroll events are detected by moving two fingers in all four directions along the touchpad. _verification: - Could you scroll up and down? + Were scroll events detected for all four directions? _siblings: - [{ "id": "touchpad/multitouch-vertical-after-suspend", - "depends": "suspend/suspend_advanced_auto touchpad/multitouch-vertical" }] + [{ "id": "touchpad/multitouch-after-suspend", + "depends": "suspend/suspend_advanced_auto touchpad/multitouch" }] plugin: manual category_id: com.canonical.plainbox::touchpad @@ -238,6 +221,7 @@ _description: id: touchpad/palm-rejection plugin: user-interact category_id: com.canonical.plainbox::touchpad +requires: dmi.product in ['Notebook','Laptop','Portable','Convertible'] command: qmlscene -qt5 --fullscreen "$PLAINBOX_PROVIDER_DATA"/palm_rejection.qml 2>&1 | grep -o PASS _purpose: This test checks if touchpad ignores palm touches diff --git a/units/touchpad/test-plan.pxu b/units/touchpad/test-plan.pxu index e03ea54..74d41a5 100644 --- a/units/touchpad/test-plan.pxu +++ b/units/touchpad/test-plan.pxu @@ -20,8 +20,7 @@ include: touchpad/singletouch-selection certification-status=blocker touchpad/drag-and-drop certification-status=blocker touchpad/multitouch-rightclick certification-status=blocker - touchpad/multitouch-horizontal certification-status=blocker - touchpad/multitouch-vertical certification-status=blocker + touchpad/multitouch certification-status=blocker id: touchpad-cert-automated unit: test plan @@ -45,8 +44,7 @@ include: touchpad/singletouch-selection-after-suspend certification-status=blocker touchpad/drag-and-drop-after-suspend certification-status=blocker touchpad/multitouch-rightclick-after-suspend certification-status=blocker - touchpad/multitouch-horizontal-after-suspend certification-status=blocker - touchpad/multitouch-vertical-after-suspend certification-status=blocker + touchpad/multitouch-after-suspend certification-status=blocker id: touchpad-cert-blockers unit: test plan @@ -59,8 +57,7 @@ include: touchpad/singletouch-selection certification-status=blocker touchpad/drag-and-drop certification-status=blocker touchpad/multitouch-rightclick certification-status=blocker - touchpad/multitouch-horizontal certification-status=blocker - touchpad/multitouch-vertical certification-status=blocker + touchpad/multitouch certification-status=blocker id: after-suspend-touchpad-cert-blockers unit: test plan @@ -73,5 +70,4 @@ include: touchpad/singletouch-selection-after-suspend certification-status=blocker touchpad/drag-and-drop-after-suspend certification-status=blocker touchpad/multitouch-rightclick-after-suspend certification-status=blocker - touchpad/multitouch-horizontal-after-suspend certification-status=blocker - touchpad/multitouch-vertical-after-suspend certification-status=blocker + touchpad/multitouch-after-suspend certification-status=blocker diff --git a/units/virtualization/jobs.pxu b/units/virtualization/jobs.pxu index 2b903c7..f203910 100644 --- a/units/virtualization/jobs.pxu +++ b/units/virtualization/jobs.pxu @@ -1,21 +1,16 @@ plugin: shell category_id: com.canonical.plainbox::virtualization -id: virtualization/kvm_check_vm -user: root -environ: UVT_IMAGE_OR_SOURCE http_proxy https_proxy -estimated_duration: 300.0 +id: virtualization/verify_lxd_vm +environ: LXD_TEMPLATE KVM_IMAGE +estimated_duration: 60.0 requires: - executable.name == 'uvt-kvm' - executable.name == 'uvt-simplestreams-libvirt' - executable.name == 'virsh' - executable.name == 'ssh-keygen' - virtualization.kvm == 'supported' -command: virtualization.py --debug uvt + executable.name == 'lxc' + package.name == 'lxd' or snap.name == 'lxd' +command: virtualization.py --debug lxdvm _description: - Verifies that a KVM guest can be created and booted using an Ubuntu Server - cloud image. + Verifies that an LXD Virtual Machine can be created and launched _summary: - Verify KVM guest boots + Verify LXD Virtual Machine launches plugin: shell category_id: com.canonical.plainbox::virtualization diff --git a/units/virtualization/test-plan.pxu b/units/virtualization/test-plan.pxu index 16f4c73..aae210f 100644 --- a/units/virtualization/test-plan.pxu +++ b/units/virtualization/test-plan.pxu @@ -15,5 +15,5 @@ id: virtualization-automated unit: test plan _name: Automated virtualization tests include: - virtualization/kvm_check_vm - virtualization/verify_lxd \ No newline at end of file + virtualization/verify_lxd + virtualization/verify_lxd_vm diff --git a/units/zapper/jobs.pxu b/units/zapper/jobs.pxu index acf65f1..91d1d38 100644 --- a/units/zapper/jobs.pxu +++ b/units/zapper/jobs.pxu @@ -5,3 +5,41 @@ estimated_duration: 60 _summary: Check if the system automatically changes the resolution based on EDID environ: ZAPPER_HOST command: edid_cycle.py "$ZAPPER_HOST" + +unit: template +template-resource: zapper_capabilities +template-filter: zapper_capabilities.capability == 'USB hotplug' and zapper_capabilities.usb_version == '3' +category_id: com.canonical.plainbox::usb +id: usb3/zapper-usb-insert-{{ port_alias }} +template-engine: jinja2 +_summary: Zapper-driven USB insertion test on port {{ port_alias }} +requires: usb.usb3 == 'supported' +plugin: shell +user: root +environ: ZAPPER_ADDRESS +command: + {%- if __on_ubuntucore__ %} + checkbox-support-run_watcher --zapper-usb-address={{ port_alias }} insertion usb3 + {%- else %} + removable_storage_watcher.py --unmounted -m 500000000 --zapper-usb-address={{ port_alias }} insert usb + {% endif -%} +estimated_duration: 20 + +unit: template +template-resource: zapper_capabilities +template-filter: zapper_capabilities.capability == 'USB hotplug' and zapper_capabilities.usb_version == '3' +category_id: com.canonical.plainbox::usb +id: usb3/zapper-usb-remove-{{ port_alias }} +template-engine: jinja2 +_summary: Zapper-driven USB removal test on port {{ port_alias }} +requires: usb.usb3 == 'supported' +plugin: shell +user: root +environ: ZAPPER_ADDRESS +command: + {%- if __on_ubuntucore__ %} + checkbox-support-run_watcher --zapper-usb-address={{ port_alias }} removal usb3 + {%- else %} + removable_storage_watcher.py --unmounted -m 500000000 --zapper-usb-address={{ port_alias }} remove usb + {% endif -%} +estimated_duration: 20 diff --git a/units/zapper/resource.pxu b/units/zapper/resource.pxu index 81b9d19..fcfe8a8 100644 --- a/units/zapper/resource.pxu +++ b/units/zapper/resource.pxu @@ -1,5 +1,8 @@ -id: pig +id: zapper_capabilities plugin: resource -_summary: Get Pig's capabilities -environ: PIG_HOST -command: ssh -q -o 'StrictHostKeyChecking=no' "$PIG_HOST" /snap/bin/pigbox capabilities +_summary: Get Zapper's setup capabilities +_description: + Connect to Zapper and list functions that the current setup (DUT + Zapper) are + capable off. +environ: ZAPPER_HOST +command: checkbox-support-zapper-proxy get_capabilities diff --git a/units/zapper/test-plan.pxu b/units/zapper/test-plan.pxu index ce287ff..889fb50 100644 --- a/units/zapper/test-plan.pxu +++ b/units/zapper/test-plan.pxu @@ -11,6 +11,8 @@ unit: test plan _name: Tests using Zapper _description: Tests using Zapper include: - monitor/pig-edid + monitor/zapper-edid + usb3/zapper-usb-insert-.* + usb3/zapper-usb-remove-.* bootstrap_include: - pig + zapper_capabilities |