summaryrefslogtreecommitdiff
diff options
authorSylvain Pineau <sylvain.pineau@canonical.com>2018-07-23 16:31:15 +0200
committerSylvain Pineau <sylvain.pineau@canonical.com>2018-07-23 16:31:15 +0200
commitff430da678446384effe5c71b4f6593566e4877f (patch)
treed6a549ac27789f2a5deb456c75671c9c60429711
parent269bdb527cbcbebd7345f03e8fcc89d22b24c8f7 (diff)
parent6ca200fedf88bf8fba57b3f2eda59799d6f574cd (diff)
record new upstream branch created by importing plainbox-provider-checkbox_0.46.0~rc1.orig.tar.gz and merge it
-rwxr-xr-xbin/accelerometer_test6
-rwxr-xr-xbin/audio_test1
-rwxr-xr-xbin/battery_test2
-rwxr-xr-xbin/boot_mode_test_snappy.py125
-rwxr-xr-xbin/camera_test_legacy578
-rwxr-xr-xbin/check-prerelease137
-rwxr-xr-xbin/cycle_vts6
-rwxr-xr-xbin/disk_info2
-rwxr-xr-xbin/disk_read_performance_test2
-rwxr-xr-xbin/efi-pxeboot3
-rwxr-xr-xbin/fde_tests.py101
-rwxr-xr-xbin/gatt-notify-test.py241
-rwxr-xr-xbin/gpu_test2
-rwxr-xr-xbin/graphics_driver5
-rwxr-xr-xbin/graphics_env2
-rwxr-xr-xbin/gst_pipeline_test3
-rwxr-xr-xbin/ipmi_test8
-rwxr-xr-xbin/key_test4
-rwxr-xr-xbin/keyboard_test4
-rwxr-xr-xbin/lock_screen_watcher2
-rwxr-xr-xbin/manage_compiz_plugin9
-rwxr-xr-xbin/net_if_watcher.py43
-rwxr-xr-xbin/network_restart3
-rwxr-xr-xbin/pm_test93
-rwxr-xr-xbin/removable_storage_test18
-rwxr-xr-xbin/resolution_test3
-rwxr-xr-xbin/socketcan_test.py199
-rwxr-xr-xbin/touchpad_test4
-rwxr-xr-xbin/xrandr_cycle7
-rw-r--r--debian/.git-dpm14
-rwxr-xr-xmanage.py2
-rw-r--r--units/audio/jobs.pxu5
-rw-r--r--units/bluetooth/jobs.pxu22
-rw-r--r--units/bluetooth/test-plan.pxu10
-rw-r--r--units/camera/jobs.pxu30
-rw-r--r--units/cpu/jobs.pxu33
-rw-r--r--units/disk/encryption.pxu21
-rw-r--r--units/disk/jobs.pxu23
-rw-r--r--units/disk/test-plan.pxu21
-rw-r--r--units/ethernet/jobs.pxu272
-rw-r--r--units/graphics/jobs.pxu4
-rw-r--r--units/mediacard/jobs.pxu122
-rw-r--r--units/miscellanea/jobs.pxu30
-rw-r--r--units/monitor/jobs.pxu47
-rw-r--r--units/monitor/test-plan.pxu66
-rw-r--r--units/networking/test-plan.pxu5
-rw-r--r--units/power-management/jobs.pxu4
-rw-r--r--units/socketcan/category.pxu3
-rw-r--r--units/socketcan/jobs.pxu166
-rw-r--r--units/socketcan/manifest.pxu5
-rw-r--r--units/socketcan/test-plan.pxu28
-rw-r--r--units/stress/jobs.pxu9
-rw-r--r--units/submission/jobs.pxu1
-rw-r--r--units/suspend/suspend.pxu81
-rw-r--r--units/thunderbolt/jobs.pxu2
-rw-r--r--units/thunderbolt/test-plan.pxu18
-rw-r--r--units/usb/test-plan.pxu1
-rw-r--r--units/usb/usb-c.pxu16
-rw-r--r--units/wireless/jobs.pxu4
59 files changed, 1868 insertions, 810 deletions
diff --git a/bin/accelerometer_test b/bin/accelerometer_test
index 93130fc..2d95ca8 100755
--- a/bin/accelerometer_test
+++ b/bin/accelerometer_test
@@ -24,13 +24,17 @@ accelerometer, and check to be sure that the x, y, z axis respond
to physical movement of hardware.
'''
from argparse import ArgumentParser
-from gi.repository import Gdk, GLib, Gtk
+import gi
import logging
import os
import re
import sys
import threading
import time
+gi.require_version('Gdk', '3.0')
+gi.require_version('GLib', '2.0')
+gi.require_version("Gtk", "3.0")
+from gi.repository import Gdk, GLib, Gtk
from subprocess import Popen, PIPE, check_output, STDOUT, CalledProcessError
from checkbox_support.parsers.modinfo import ModinfoParser
diff --git a/bin/audio_test b/bin/audio_test
index f0b73a4..466b760 100755
--- a/bin/audio_test
+++ b/bin/audio_test
@@ -12,6 +12,7 @@ import sys
import time
try:
import gi
+ gi.require_version('GLib', '2.0')
gi.require_version('Gst','1.0')
from gi.repository import GObject
from gi.repository import Gst
diff --git a/bin/battery_test b/bin/battery_test
index cdfd227..b2682c7 100755
--- a/bin/battery_test
+++ b/bin/battery_test
@@ -1,11 +1,13 @@
#!/usr/bin/env python3
+import gi
import os
import time
import re
import subprocess
import sys
import argparse
+gi.require_version('Gio', '2.0')
from gi.repository import Gio
diff --git a/bin/boot_mode_test_snappy.py b/bin/boot_mode_test_snappy.py
new file mode 100755
index 0000000..46bed92
--- /dev/null
+++ b/bin/boot_mode_test_snappy.py
@@ -0,0 +1,125 @@
+#!/usr/bin/env python3
+# Copyright 2018 Canonical Ltd.
+# Written by:
+# Jonathan Cave <jonathan.cave@canonical.com>
+
+import io
+import os
+import re
+import sys
+import subprocess as sp
+
+import yaml
+
+
+def fitdumpimage(filename):
+ cmd = 'dumpimage -l {}'.format(filename)
+ out = sp.check_output(cmd, shell=True).decode(sys.stdout.encoding)
+ buf = io.StringIO(out)
+
+ # first line should identify FIT file
+ if not buf.readline().startswith('FIT description'):
+ raise SystemExit('ERROR: expected FIT image description')
+
+ # second line contains some metadata, skip it
+ buf.readline()
+
+ # from then on should get blocks of text describing the objects that were
+ # combined in to the FIT image e.g. kernel, ramdisk, device tree
+ image_re = re.compile(r'(?:^\ Image)\ \d+\ \((\S+)\)$')
+ config_re = re.compile(r'^\ Default Configuration|^\ Configuration')
+ objects = {}
+ name = ''
+ while True:
+ line = buf.readline()
+ # stop at end
+ if line == '':
+ break
+ # interested in storing image information
+ match = image_re.search(line)
+ if match:
+ name = match.group(1)
+ objects[name] = {}
+ continue
+ # not interested in configurations
+ if config_re.search(line):
+ name = ''
+ continue
+ # while in an image section store the info
+ if name != '':
+ entries = [s.strip() for s in line.split(':', 1)]
+ objects[name][entries[0]] = entries[1]
+ return objects
+
+
+def main():
+ if len(sys.argv) != 3:
+ raise SystemExit('ERROR: please supply gadget & kernel name')
+ gadget = sys.argv[1]
+ kernel = sys.argv[2]
+
+ gadget_yaml = os.path.join('/snap', gadget, 'current/meta/gadget.yaml')
+
+ if not os.path.exists(gadget_yaml):
+ raise SystemExit(
+ 'ERROR: failed to find gadget.yaml at {}'.format(gadget_yaml))
+
+ with open(gadget_yaml) as f:
+ data = yaml.load(f)
+ for k in data['volumes'].keys():
+ bootloader = data['volumes'][k]['bootloader']
+ if not bootloader:
+ raise SystemExit('ERROR: could not find name of bootloader')
+
+ if bootloader not in ('u-boot', 'grub'):
+ raise SystemExit(
+ 'ERROR: Unexpected bootloader name {}'.format(bootloader))
+ print('Bootloader is {}\n'.format(bootloader))
+
+ if bootloader == 'u-boot':
+ print('Parsing FIT image information...\n')
+
+ kernel_rev = os.path.basename(
+ os.path.realpath('/snap/{}/current'.format(kernel)))
+ boot_kernel = '/boot/uboot/{}_{}.snap/kernel.img'.format(
+ kernel, kernel_rev)
+ boot_objects = fitdumpimage(boot_kernel)
+
+ for obj, attrs in boot_objects.items():
+ print('Checking object {}'.format(obj))
+ if 'Sign value' not in attrs:
+ raise SystemExit('ERROR: no sign value found for object')
+ print('Found "Sign value"')
+ if len(attrs['Sign value']) != 512:
+ raise SystemExit('ERROR: unexpected sign value size')
+ if all(s in attrs['Sign algo'] for s in ['sha256', 'rsa2048']):
+ print('Found expected signing algorithms')
+ else:
+ raise SystemExit(
+ 'ERROR: unexpected signing algorithms {}'.format(
+ attrs['Sign algo']))
+ print()
+
+ # check that all parts of the fit image have
+ snap_kernel = '/snap/{}/current/kernel.img'.format(kernel)
+ snap_objects = fitdumpimage(snap_kernel)
+ if snap_objects != boot_objects:
+ raise SystemExit(
+ 'ERROR: boot kernel and current snap kernel do not match')
+ print('Kernel images in current snap and u-boot match\n')
+
+ print('Secure Boot appears to be enabled on this system')
+
+ if bootloader == 'grub':
+ cmd = 'mokutil --sb-state'
+ print('+', cmd, flush=True)
+ out = sp.check_output(cmd, shell=True).decode(sys.stdout.encoding)
+ print(out, flush=True)
+ if out != 'SecureBoot enabled\n':
+ raise SystemExit('ERROR: mokutil reports Secure Boot not in use')
+
+ print('Secure Boot appears to be enabled on this system')
+
+
+if __name__ == '__main__':
+ main()
diff --git a/bin/camera_test_legacy b/bin/camera_test_legacy
deleted file mode 100755
index 794578b..0000000
--- a/bin/camera_test_legacy
+++ /dev/null
@@ -1,578 +0,0 @@
-#!/usr/bin/env python3
-#
-# This file is part of Checkbox.
-#
-# Copyright 2008-2012 Canonical Ltd.
-#
-# The v4l2 ioctl code comes from the Python bindings for the v4l2
-# userspace api (http://pypi.python.org/pypi/v4l2):
-# Copyright (C) 1999-2009 the contributors
-#
-# The JPEG metadata parser is a part of bfg-pages:
-# http://code.google.com/p/bfg-pages/source/browse/trunk/pages/getimageinfo.py
-# Copyright (C) Tim Hoffman
-#
-# 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 argparse
-import ctypes
-import errno
-import fcntl
-import imghdr
-import logging
-import os
-import re
-import struct
-import sys
-import time
-
-from gi.repository import GObject
-from glob import glob
-from subprocess import check_call, CalledProcessError, STDOUT
-from tempfile import NamedTemporaryFile
-
-
-_IOC_NRBITS = 8
-_IOC_TYPEBITS = 8
-_IOC_SIZEBITS = 14
-
-_IOC_NRSHIFT = 0
-_IOC_TYPESHIFT = _IOC_NRSHIFT + _IOC_NRBITS
-_IOC_SIZESHIFT = _IOC_TYPESHIFT + _IOC_TYPEBITS
-_IOC_DIRSHIFT = _IOC_SIZESHIFT + _IOC_SIZEBITS
-
-_IOC_WRITE = 1
-_IOC_READ = 2
-
-
-def _IOC(dir_, type_, nr, size):
- return (
- ctypes.c_int32(dir_ << _IOC_DIRSHIFT).value |
- ctypes.c_int32(ord(type_) << _IOC_TYPESHIFT).value |
- ctypes.c_int32(nr << _IOC_NRSHIFT).value |
- ctypes.c_int32(size << _IOC_SIZESHIFT).value)
-
-
-def _IOC_TYPECHECK(t):
- return ctypes.sizeof(t)
-
-
-def _IOR(type_, nr, size):
- return _IOC(_IOC_READ, type_, nr, ctypes.sizeof(size))
-
-
-def _IOWR(type_, nr, size):
- return _IOC(_IOC_READ | _IOC_WRITE, type_, nr, _IOC_TYPECHECK(size))
-
-
-class v4l2_capability(ctypes.Structure):
- """
- Driver capabilities
- """
- _fields_ = [
- ('driver', ctypes.c_char * 16),
- ('card', ctypes.c_char * 32),
- ('bus_info', ctypes.c_char * 32),
- ('version', ctypes.c_uint32),
- ('capabilities', ctypes.c_uint32),
- ('reserved', ctypes.c_uint32 * 4),
- ]
-
-
-# Values for 'capabilities' field
-V4L2_CAP_VIDEO_CAPTURE = 0x00000001
-V4L2_CAP_VIDEO_OVERLAY = 0x00000004
-V4L2_CAP_READWRITE = 0x01000000
-V4L2_CAP_STREAMING = 0x04000000
-
-v4l2_frmsizetypes = ctypes.c_uint
-(
- V4L2_FRMSIZE_TYPE_DISCRETE,
- V4L2_FRMSIZE_TYPE_CONTINUOUS,
- V4L2_FRMSIZE_TYPE_STEPWISE,
-) = range(1, 4)
-
-
-class v4l2_frmsize_discrete(ctypes.Structure):
- _fields_ = [
- ('width', ctypes.c_uint32),
- ('height', ctypes.c_uint32),
- ]
-
-
-class v4l2_frmsize_stepwise(ctypes.Structure):
- _fields_ = [
- ('min_width', ctypes.c_uint32),
- ('min_height', ctypes.c_uint32),
- ('step_width', ctypes.c_uint32),
- ('min_height', ctypes.c_uint32),
- ('max_height', ctypes.c_uint32),
- ('step_height', ctypes.c_uint32),
- ]
-
-
-class v4l2_frmsizeenum(ctypes.Structure):
- class _u(ctypes.Union):
- _fields_ = [
- ('discrete', v4l2_frmsize_discrete),
- ('stepwise', v4l2_frmsize_stepwise),
- ]
-
- _fields_ = [
- ('index', ctypes.c_uint32),
- ('pixel_format', ctypes.c_uint32),
- ('type', ctypes.c_uint32),
- ('_u', _u),
- ('reserved', ctypes.c_uint32 * 2)
- ]
-
- _anonymous_ = ('_u',)
-
-
-class v4l2_fmtdesc(ctypes.Structure):
- _fields_ = [
- ('index', ctypes.c_uint32),
- ('type', ctypes.c_int),
- ('flags', ctypes.c_uint32),
- ('description', ctypes.c_char * 32),
- ('pixelformat', ctypes.c_uint32),
- ('reserved', ctypes.c_uint32 * 4),
- ]
-
-V4L2_FMT_FLAG_COMPRESSED = 0x0001
-V4L2_FMT_FLAG_EMULATED = 0x0002
-
-# ioctl code for video devices
-VIDIOC_QUERYCAP = _IOR('V', 0, v4l2_capability)
-VIDIOC_ENUM_FRAMESIZES = _IOWR('V', 74, v4l2_frmsizeenum)
-VIDIOC_ENUM_FMT = _IOWR('V', 2, v4l2_fmtdesc)
-
-
-class CameraTest:
- """
- A simple class that displays a test image via GStreamer.
- """
- def __init__(self, args, gst_plugin=None, gst_video_type=None):
- self.args = args
- self._mainloop = GObject.MainLoop()
- self._width = 640
- self._height = 480
- self._gst_plugin = gst_plugin
- self._gst_video_type = gst_video_type
-
- def detect(self):
- """
- Display information regarding webcam hardware
- """
- cap_status = dev_status = 1
- for i in range(10):
- cp = v4l2_capability()
- device = '/dev/video%d' % i
- try:
- with open(device, 'r') as vd:
- fcntl.ioctl(vd, VIDIOC_QUERYCAP, cp)
- except IOError:
- continue
- dev_status = 0
- print("%s: OK" % device)
- print(" name : %s" % cp.card.decode('UTF-8'))
- print(" driver : %s" % cp.driver.decode('UTF-8'))
- print(" version: %s.%s.%s"
- % (cp.version >> 16,
- (cp.version >> 8) & 0xff,
- cp.version & 0xff))
- print(" flags : 0x%x [" % cp.capabilities,
- ' CAPTURE' if cp.capabilities & V4L2_CAP_VIDEO_CAPTURE
- else '',
- ' OVERLAY' if cp.capabilities & V4L2_CAP_VIDEO_OVERLAY
- else '',
- ' READWRITE' if cp.capabilities & V4L2_CAP_READWRITE
- else '',
- ' STREAMING' if cp.capabilities & V4L2_CAP_STREAMING
- else '',
- ' ]', sep="")
-
- resolutions = self._get_supported_resolutions(device)
- print(' ',
- self._supported_resolutions_to_string(resolutions).replace(
- "\n", " "),
- sep="")
-
- if cp.capabilities & V4L2_CAP_VIDEO_CAPTURE:
- cap_status = 0
- return dev_status | cap_status
-
- def led(self):
- """
- Activate camera (switch on led), but don't display any output
- """
- pipespec = ("v4l2src device=%(device)s "
- "! %(type)s "
- "! %(plugin)s "
- "! testsink"
- % {'device': self.args.device,
- 'type': self._gst_video_type,
- 'plugin': self._gst_plugin})
- logging.debug("LED test with pipeline %s", pipespec)
- self._pipeline = Gst.parse_launch(pipespec)
- self._pipeline.set_state(Gst.State.PLAYING)
- time.sleep(3)
- self._pipeline.set_state(Gst.State.NULL)
-
- def display(self):
- """
- Displays the preview window
- """
- pipespec = ("v4l2src device=%(device)s "
- "! %(type)s,width=%(width)d,height=%(height)d "
- "! %(plugin)s "
- "! autovideosink"
- % {'device': self.args.device,
- 'type': self._gst_video_type,
- 'width': self._width,
- 'height': self._height,
- 'plugin': self._gst_plugin})
- logging.debug("display test with pipeline %s", pipespec)
- self._pipeline = Gst.parse_launch(pipespec)
- self._pipeline.set_state(Gst.State.PLAYING)
- time.sleep(10)
- self._pipeline.set_state(Gst.State.NULL)
-
- def still(self):
- """
- Captures an image to a file
- """
- if self.args.filename:
- self._still_helper(self.args.filename, self._width, self._height,
- self.args.quiet)
- else:
- with NamedTemporaryFile(prefix='camera_test_', suffix='.jpg') as f:
- self._still_helper(f.name, self._width, self._height,
- self.args.quiet)
-
- def _still_helper(self, filename, width, height, quiet, pixelformat=None):
- """
- Captures an image to a given filename. width and height specify the
- image size and quiet controls whether the image is displayed to the
- user (quiet = True means do not display image).
- """
- command = ["fswebcam", "-D 1", "-S 50", "--no-banner",
- "-d", self.args.device,
- "-r", "%dx%d"
- % (width, height), filename]
- use_gstreamer = False
- if pixelformat:
- if 'MJPG' == pixelformat: # special tweak for fswebcam
- pixelformat = 'MJPEG'
- command.extend(["-p", pixelformat])
-
- try:
- check_call(command, stdout=open(os.devnull, 'w'), stderr=STDOUT)
- except (CalledProcessError, OSError):
- use_gstreamer = True
-
- if use_gstreamer:
- pipespec = ("v4l2src device=%(device)s "
- "! %(type)s,width=%(width)d,height=%(height)d "
- "! %(plugin)s "
- "! jpegenc "
- "! filesink location=%(filename)s"
- % {'device': self.args.device,
- 'type': self._gst_video_type,
- 'width': width,
- 'height': height,
- 'plugin': self._gst_plugin,
- 'filename': filename})
- logging.debug("still test with gstreamer and "
- "pipeline %s", pipespec)
- self._pipeline = Gst.parse_launch(pipespec)
- self._pipeline.set_state(Gst.State.PLAYING)
- time.sleep(3)
- self._pipeline.set_state(Gst.State.NULL)
-
- if not quiet:
- import imghdr
- image_type = imghdr.what(filename)
- pipespec = ("filesrc location=%(filename)s ! "
- "%(type)sdec ! "
- "videoscale ! "
- "imagefreeze ! autovideosink"
- % {'filename': filename,
- 'type': image_type})
- self._pipeline = Gst.parse_launch(pipespec)
- self._pipeline.set_state(Gst.State.PLAYING)
- time.sleep(10)
- self._pipeline.set_state(Gst.State.NULL)
-
- def _supported_resolutions_to_string(self, supported_resolutions):
- """
- Return a printable string representing a list of supported resolutions
- """
- ret = ""
- for resolution in supported_resolutions:
- ret += "Format: %s (%s)\n" % (resolution['pixelformat'],
- resolution['description'])
- ret += "Resolutions: "
- for res in resolution['resolutions']:
- ret += "%sx%s," % (res[0], res[1])
- # truncate the extra comma with :-1
- ret = ret[:-1] + "\n"
- return ret
-
- def resolutions(self):
- """
- After querying the webcam for supported formats and resolutions,
- take multiple images using the first format returned by the driver,
- and see if they are valid
- """
- resolutions = self._get_supported_resolutions(self.args.device)
- # print supported formats and resolutions for the logs
- print(self._supported_resolutions_to_string(resolutions))
-
- # pick the first format, which seems to be what the driver wants for a
- # default. This also matches the logic that fswebcam uses to select
- # a default format.
- resolution = resolutions[0]
- if resolution:
- print("Taking multiple images using the %s format"
- % resolution['pixelformat'])
- for res in resolution['resolutions']:
- w = res[0]
- h = res[1]
- f = NamedTemporaryFile(prefix='camera_test_%s%sx%s' %
- (resolution['pixelformat'], w, h),
- suffix='.jpg', delete=False)
- print("Taking a picture at %sx%s" % (w, h))
- self._still_helper(f.name, w, h, True,
- pixelformat=resolution['pixelformat'])
- if self._validate_image(f.name, w, h):
- print("Validated image %s" % f.name)
- os.remove(f.name)
- else:
- print("Failed to validate image %s" % f.name,
- file=sys.stderr)
- os.remove(f.name)
- return 1
- return 0
-
- def _get_pixel_formats(self, device, maxformats=5):
- """
- Query the camera to see what pixel formats it supports. A list of
- dicts is returned consisting of format and description. The caller
- should check whether this camera supports VIDEO_CAPTURE before
- calling this function.
- """
- supported_formats = []
- fmt = v4l2_fmtdesc()
- fmt.index = 0
- fmt.type = V4L2_CAP_VIDEO_CAPTURE
- try:
- while fmt.index < maxformats:
- with open(device, 'r') as vd:
- if fcntl.ioctl(vd, VIDIOC_ENUM_FMT, fmt) == 0:
- pixelformat = {}
- # save the int type for re-use later
- pixelformat['pixelformat_int'] = fmt.pixelformat
- pixelformat['pixelformat'] = "%s%s%s%s" % \
- (chr(fmt.pixelformat & 0xFF),
- chr((fmt.pixelformat >> 8) & 0xFF),
- chr((fmt.pixelformat >> 16) & 0xFF),
- chr((fmt.pixelformat >> 24) & 0xFF))
- pixelformat['description'] = fmt.description.decode()
- supported_formats.append(pixelformat)
- fmt.index = fmt.index + 1
- except IOError as e:
- # EINVAL is the ioctl's way of telling us that there are no
- # more formats, so we ignore it
- if e.errno != errno.EINVAL:
- print("Unable to determine Pixel Formats, this may be a "
- "driver issue.")
- return supported_formats
- return supported_formats
-
- def _get_supported_resolutions(self, device):
- """
- Query the camera for supported resolutions for a given pixel_format.
- Data is returned in a list of dictionaries with supported pixel
- formats as the following example shows:
- resolution['pixelformat'] = "YUYV"
- resolution['description'] = "(YUV 4:2:2 (YUYV))"
- resolution['resolutions'] = [[width, height], [640, 480], [1280, 720] ]
-
- If we are unable to gather any information from the driver, then we
- return YUYV and 640x480 which seems to be a safe default.
- Per the v4l2 spec the ioctl used here is experimental
- but seems to be well supported.
- """
- supported_formats = self._get_pixel_formats(device)
- if not supported_formats:
- resolution = {}
- resolution['description'] = "YUYV"
- resolution['pixelformat'] = "YUYV"
- resolution['resolutions'] = [[640, 480]]
- supported_formats.append(resolution)
- return supported_formats
-
- for supported_format in supported_formats:
- resolutions = []
- framesize = v4l2_frmsizeenum()
- framesize.index = 0
- framesize.pixel_format = supported_format['pixelformat_int']
- with open(device, 'r') as vd:
- try:
- while fcntl.ioctl(vd,
- VIDIOC_ENUM_FRAMESIZES,
- framesize) == 0:
- if framesize.type == V4L2_FRMSIZE_TYPE_DISCRETE:
- resolutions.append([framesize.discrete.width,
- framesize.discrete.height])
- # for continuous and stepwise, let's just use min and
- # max they use the same structure and only return
- # one result
- elif (framesize.type in (V4L2_FRMSIZE_TYPE_CONTINUOUS,
- V4L2_FRMSIZE_TYPE_STEPWISE)):
- resolutions.append([framesize.stepwise.min_width,
- framesize.stepwise.min_height]
- )
- resolutions.append([framesize.stepwise.max_width,
- framesize.stepwise.max_height]
- )
- break
- framesize.index = framesize.index + 1
- except IOError as e:
- # EINVAL is the ioctl's way of telling us that there are no
- # more formats, so we ignore it
- if e.errno != errno.EINVAL:
- print("Unable to determine supported framesizes "
- "(resolutions), this may be a driver issue.")
- supported_format['resolutions'] = resolutions
- return supported_formats
-
- def _validate_image(self, filename, width, height):
- """
- Given a filename, ensure that the image is the width and height
- specified and is a valid image file.
- """
- if imghdr.what(filename) != 'jpeg':
- return False
-
- outw = outh = 0
- with open(filename, mode='rb') as jpeg:
- jpeg.seek(2)
- b = jpeg.read(1)
- try:
- while (b and ord(b) != 0xDA):
- while (ord(b) != 0xFF):
- b = jpeg.read(1)
- while (ord(b) == 0xFF):
- b = jpeg.read(1)
- if (ord(b) >= 0xC0 and ord(b) <= 0xC3):
- jpeg.seek(3, 1)
- h, w = struct.unpack(">HH", jpeg.read(4))
- break
- b = jpeg.read(1)
- outw, outh = int(w), int(h)
- except (struct.error, ValueError):
- pass
-
- if outw != width:
- print("Image width does not match, was %s should be %s" %
- (outw, width), file=sys.stderr)
- return False
- if outh != height:
- print("Image width does not match, was %s should be %s" %
- (outh, height), file=sys.stderr)
- return False
-
- return True
-
- return True
-
-
-def parse_arguments(argv):
- """
- Parse command line arguments
- """
- parser = argparse.ArgumentParser(description="Run a camera-related test")
- subparsers = parser.add_subparsers(dest='test',
- title='test',
- description='Available camera tests')
-
- parser.add_argument('--debug', dest='log_level',
- action="store_const", const=logging.DEBUG,
- default=logging.INFO, help="Show debugging messages")
-
- def add_device_parameter(parser):
- group = parser.add_mutually_exclusive_group()
- group.add_argument("-d", "--device", default="/dev/video0",
- help="Device for the webcam to use")
- group.add_argument("--highest-device", action="store_true",
- help=("Use the /dev/videoN "
- "where N is the highest value available"))
- group.add_argument("--lowest-device", action="store_true",
- help=("Use the /dev/videoN "
- "where N is the lowest value available"))
- subparsers.add_parser('detect')
- led_parser = subparsers.add_parser('led')
- add_device_parameter(led_parser)
- display_parser = subparsers.add_parser('display')
- add_device_parameter(display_parser)
- still_parser = subparsers.add_parser('still')
- add_device_parameter(still_parser)
- still_parser.add_argument("-f", "--filename",
- help="Filename to store the picture")
- still_parser.add_argument("-q", "--quiet", action="store_true",
- help=("Don't display picture, "
- "just write the picture to a file"))
- resolutions_parser = subparsers.add_parser('resolutions')
- add_device_parameter(resolutions_parser)
- args = parser.parse_args(argv)
-
- def get_video_devices():
- devices = sorted(glob('/dev/video[0-9]'),
- key=lambda d: re.search(r'\d', d).group(0))
- assert len(devices) > 0, "No video devices found"
- return devices
-
- if hasattr(args, 'highest_device') and args.highest_device:
- args.device = get_video_devices()[-1]
- elif hasattr(args, 'lowest_device') and args.lowest_device:
- args.device = get_video_devices()[0]
- return args
-
-
-if __name__ == "__main__":
- args = parse_arguments(sys.argv[1:])
-
- if not args.test:
- args.test = 'detect'
-
- logging.basicConfig(level=args.log_level)
-
- # Import Gst only for the test cases that will need it
- if args.test in ['display', 'still', 'led', 'resolutions']:
- from gi.repository import Gst
- if Gst.version()[0] > 0:
- gst_plugin = 'videoconvert'
- gst_video_type = 'video/x-raw'
- else:
- gst_plugin = 'ffmpegcolorspace'
- gst_video_type = 'video/x-raw-yuv'
- Gst.init(None)
- camera = CameraTest(args, gst_plugin, gst_video_type)
- else:
- camera = CameraTest(args)
-
- sys.exit(getattr(camera, args.test)())
diff --git a/bin/check-prerelease b/bin/check-prerelease
new file mode 100755
index 0000000..1f3d017
--- /dev/null
+++ b/bin/check-prerelease
@@ -0,0 +1,137 @@
+#!/usr/bin/env python3
+
+"""
+Script to test that the system is NOT running prerelease software
+
+Copyright (c) 2018 Canonical Ltd.
+
+Authors
+ 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/>.
+
+The purpose of this script is to identify whether an EFI-based
+system booted from the network (test passes) or from a local disk
+(test fails).
+
+Usage:
+ check-prerelease
+"""
+
+import platform
+import shlex
+import sys
+
+from subprocess import Popen, PIPE
+
+
+def check_kernel_status():
+ """Check kernel to see if it's supported for certification
+
+ :returns:
+ True if OK, False if not
+ """
+ kernel_release = platform.release()
+
+ retval = False
+ command = "apt-cache show linux-image-{}".format(kernel_release)
+ aptinfo = []
+ aptinfo_bytes = (Popen(shlex.split(command), stdout=PIPE)
+ .communicate()[0])
+ aptinfo = (aptinfo_bytes.decode(encoding="utf-8", errors="ignore")
+ .splitlines())
+
+ """Kernel apt-cache info includes a 'Supported:' line on release
+ kernels to identify the period of support. This line is missing on
+ pre-release kernels. Thus, we return a True value only if this
+ line is present and shows a 5-year support period."""
+ if any("Supported: 5y" in s for s in aptinfo):
+ retval = True
+ if any("Supported: 9m" in s for s in aptinfo):
+ print("* Kernel is supported for 9 months; it is an interim release!")
+ if not any("Supported:" in s for s in aptinfo):
+ print("* Could not find a kernel support period; "
+ "may be a pre-release kernel!")
+
+ """We also want to exclude 'edge' kernels, which are identified via
+ the 'Source:' line in the apt-cache output...."""
+ if any("Source: linux-signed-hwe-edge" in s for s in aptinfo):
+ print("* Kernel is an 'edge' kernel!")
+ retval = False
+ if any("Source: linux-hwe-edge" in s for s in aptinfo):
+ print("* Kernel is an 'edge' kernel!")
+ retval = False
+
+ """We also want to exclude low-latency kernels, which are identified
+ via the kernel name string itself...."""
+ if "lowlatency" in kernel_release:
+ print("* Kernel is a low-latency kernel!")
+ retval = False
+
+ if (not retval):
+ print("* Kernel release is {}".format(kernel_release))
+ print("* Kernel is ineligible for certification!")
+
+ return retval
+
+
+def check_os_status():
+ """Check OS to see if it's supported for certification. Note that this
+ passes any release version (even a non-LTS version), but not pre-release
+ versions.
+
+ :returns:
+ True if OK, False if not
+ """
+ retval = True
+ command = "lsb_release -s -d"
+ lsbinfo = []
+ lsbinfo_bytes = (Popen(shlex.split(command), stdout=PIPE)
+ .communicate()[0])
+ lsbinfo = (lsbinfo_bytes.decode(encoding="utf-8", errors="ignore")
+ .rstrip())
+
+ """OS information include '(development branch)' on pre-release
+ installations. Such installations should fail this test."""
+ if "(development branch)" in lsbinfo:
+ print("* 'lsb_release -s -d' result is '{}'".format(lsbinfo))
+ print("* OS is reported as a development branch:")
+ print("* {}".format(lsbinfo))
+ retval = False
+ print("")
+
+ return retval
+
+
+def main():
+ """Check to see if the machine is running pre-release kernel or OS."""
+
+ retval = 0
+ if (not check_kernel_status()):
+ retval = 1
+ if (not check_os_status()):
+ retval += 2
+ if (retval == 0):
+ print("** All OK; production kernel and OS.")
+ elif (retval == 1):
+ print("** Test FAILS; running ineligible kernel!")
+ elif (retval == 2):
+ print("** Test FAILS; running pre-release OS!")
+ else:
+ print("** Test FAILS; running pre-release OS with ineligible kernel!")
+
+ return(retval)
+
+
+if __name__ == '__main__':
+ sys.exit(main())
diff --git a/bin/cycle_vts b/bin/cycle_vts
index 8b7f5bc..c5e1677 100755
--- a/bin/cycle_vts
+++ b/bin/cycle_vts
@@ -12,14 +12,14 @@ then
exit 1
fi
-if [ "$CURRENT_VT" -ne "1" ]
+if [ "$CURRENT_VT" == "7" ]
then
chvt 1
else
- chvt 2
+ chvt 3
fi
-sleep 2
+sleep 5
chvt "$CURRENT_VT"
sleep 2
diff --git a/bin/disk_info b/bin/disk_info
index 5efedbd..0b45443 100755
--- a/bin/disk_info
+++ b/bin/disk_info
@@ -53,7 +53,7 @@ def main():
disks = 0
for line in lsblk.splitlines():
m = pattern.match(line)
- if not m or m.group('TYPE') != 'disk':
+ if not m or m.group('TYPE') not in ('disk', 'crypt'):
continue
# Only consider MMC block devices if one of their mounted partitions is
# root (/)
diff --git a/bin/disk_read_performance_test b/bin/disk_read_performance_test
index e2a219d..00810a5 100755
--- a/bin/disk_read_performance_test
+++ b/bin/disk_read_performance_test
@@ -4,7 +4,7 @@
#
#Default to a lower bound of 15 MB/s
-DEFAULT_BUF_READ=15
+DEFAULT_BUF_READ=${DISK_READ_PERF:-15}
for disk in $@; do
diff --git a/bin/efi-pxeboot b/bin/efi-pxeboot
index 724fefb..24ac231 100755
--- a/bin/efi-pxeboot
+++ b/bin/efi-pxeboot
@@ -49,6 +49,7 @@ def discover_data():
.splitlines())
boot_entries = {}
boot_order = []
+ boot_current = ""
if len(bootinfo) > 1:
for s in bootinfo:
if "BootOrder" in s:
@@ -103,7 +104,7 @@ def is_pxe_booted(boot_entries, boot_order, boot_current):
or "refind_" in desc:
# This string indicates a boot directly from the normal Ubuntu GRUB
# or rEFInd installation on the hard disk.
- print("The system seems to have booted directly from the hard disk!")
+ print("FAIL: The system has booted directly from the hard disk!")
retval = 1
elif "SATA" in desc or "Sata" in desc or "Hard Drive" in desc:
# These strings indicate booting with a "generic" disk entry (one
diff --git a/bin/fde_tests.py b/bin/fde_tests.py
new file mode 100755
index 0000000..3008735
--- /dev/null
+++ b/bin/fde_tests.py
@@ -0,0 +1,101 @@
+#!/usr/bin/env python3
+# Copyright 2018 Canonical Ltd.
+# Written by:
+# Jonathan Cave <jonathan.cave@canonical.com>
+
+"""Test that Full Disk Encryption is in use.
+
+$ fde_tests.py
+Canonical has a reference implementation of full disk encryption for IoT
+devices. With no arguments passed this test checks this implementation is in
+operation on the device under test.
+
+$ fde_tests.py desktop
+Checks if the system appears to be using full disk encryption as configured by
+the desktop installer.
+"""
+
+import os
+import re
+import subprocess as sp
+import sys
+
+
+def main():
+ on_desktop = len(sys.argv) > 1 and sys.argv[1] == 'desktop'
+
+ # the mountpoint corresponding to the on disk encrypted partition
+ base_mount = '/' if on_desktop else '/writable'
+
+ # discover the underlying mount point for the encrypted part
+ cmd = 'findmnt {} -n -o SOURCE'.format(base_mount)
+ print('+ {}'.format(cmd))
+ try:
+ source = sp.check_output(cmd, shell=True).decode(
+ sys.stdout.encoding).strip()
+ except sp.CalledProcessError:
+ raise SystemExit(
+ 'ERROR: could not find mountpoint for {}'.format(base_mount))
+ print(source, '\n')
+
+ # resolve the source to an actual device node
+ print('+ realpath {}'.format(source))
+ device = os.path.realpath(source)
+ print(device, '\n')
+
+ # work upwards through the tree of devices until we find the one that has
+ # the type 'crypt'
+ kname = os.path.basename(device)
+ while True:
+ cmd = 'lsblk -r -n -i -o KNAME,TYPE,PKNAME | grep "^{}"'.format(kname)
+ print('+ {}'.format(cmd))
+ try:
+ lsblk = sp.check_output(cmd, shell=True).decode(
+ sys.stdout.encoding).strip()
+ except sp.CalledProcessError:
+ raise SystemExit('ERROR: lsblk call failed')
+ _, devtype, parent = lsblk.split(maxsplit=2)
+ print(devtype, '\n')
+ if devtype == 'crypt':
+ # found the device
+ break
+ if devtype == 'disk':
+ # reached the physical device, end the search
+ raise SystemExit(
+ 'ERROR: could not find a block device of type "crypt"')
+ kname = parent
+
+ # the presence of device with type 'crypt' is probably confirmation enough
+ # but to be really sure lets check to see it is found by cryptsetup
+
+ # first we need to know its mapper name
+ cmd = 'dmsetup info /dev/{} | grep "^Name:"'.format(kname)
+ print('+ {}'.format(cmd))
+ try:
+ mapper_name = sp.check_output(cmd, shell=True).decode(
+ sys.stdout.encoding).strip().split()[-1]
+ except sp.CalledProcessError:
+ raise SystemExit(
+ 'ERROR: dmsetup info on device {} failed'.format(kname))
+ print(mapper_name, '\n')
+
+ # then query the info in cryptsetup
+ cmd = 'cryptsetup status {}'.format(mapper_name)
+ print('+ {}'.format(cmd))
+ try:
+ cryptinfo = sp.check_output(cmd, shell=True).decode(
+ sys.stdout.encoding).strip()
+ except sp.CalledProcessError:
+ raise SystemExit('ERROR: dmsetup failed')
+ print(cryptinfo, '\n')
+
+ # use the type as the final arbiter of success
+ regexp = re.compile(r'type:\ *LUKS1')
+ if regexp.search(cryptinfo):
+ print('Full Disk Encryption is operational on this device')
+ else:
+ raise SystemExit('ERROR: cryptsetup did not report LUKS1 in use')
+
+
+if __name__ == "__main__":
+ main()
diff --git a/bin/gatt-notify-test.py b/bin/gatt-notify-test.py
new file mode 100755
index 0000000..9923a93
--- /dev/null
+++ b/bin/gatt-notify-test.py
@@ -0,0 +1,241 @@
+#!/usr/bin/env python3
+#
+# Copyright 2018 Canonical Ltd.
+# Written by:
+# Sylvain Pineau <sylvain.pineau@canonical.com>
+#
+# This 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 file 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 file. If not, see <http://www.gnu.org/licenses/>.
+
+import argparse
+import logging
+import os
+import sys
+import time
+
+import dbus
+import dbus.service
+import dbus.mainloop.glib
+from gi.repository import GObject
+
+logger = logging.getLogger(__file__)
+logger.addHandler(logging.StreamHandler(sys.stdout))
+
+ADAPTER_INTERFACE = 'org.bluez.Adapter1'
+DEVICE_INTERFACE = 'org.bluez.Device1'
+PROP_INTERFACE = 'org.freedesktop.DBus.Properties'
+OM_INTERFACE = 'org.freedesktop.DBus.ObjectManager'
+GATT_SERVICE_INTERFACE = 'org.bluez.GattService1'
+GATT_CHRC_INTERFACE = 'org.bluez.GattCharacteristic1'
+
+dbus.mainloop.glib.DBusGMainLoop(set_as_default=True)
+
+
+class BtAdapter:
+ """Bluetooth LE Adapter class."""
+ def __init__(self, pattern):
+ self._pattern = os.path.basename(pattern)
+ self._bus = dbus.SystemBus()
+ self._manager = dbus.Interface(
+ self._bus.get_object("org.bluez", "/"), OM_INTERFACE)
+ self._main_loop = GObject.MainLoop()
+ self._adapter = self._find_adapter()
+ self._path = self._adapter.object_path
+ self._props = dbus.Interface(self._adapter, PROP_INTERFACE)
+ self._name = self._props.Get(ADAPTER_INTERFACE, "Name")
+ self._addr = self._props.Get(ADAPTER_INTERFACE, "Address")
+ self._alias = self._props.Get(ADAPTER_INTERFACE, "Alias")
+ logger.info('Adapter found: [ {} ] {} - {}'.format(
+ self._path, self._addr, self._alias))
+
+ def _get_managed_objects(self):
+ return self._manager.GetManagedObjects()
+
+ def _find_adapter(self):
+ for path, ifaces in self._get_managed_objects().items():
+ adapter = ifaces.get(ADAPTER_INTERFACE)
+ if adapter is None:
+ continue
+ if (self._pattern == adapter["Address"] or
+ path.endswith(self._pattern)):
+ obj = self._bus.get_object("org.bluez", path)
+ return dbus.Interface(obj, ADAPTER_INTERFACE)
+ raise SystemExit("Bluetooth adapter not found!")
+
+ def ensure_powered(self):
+ """Turn the adapter on."""
+ self._props.Set(ADAPTER_INTERFACE, "Powered", dbus.Boolean(1))
+ logger.info('Adapter powered on')
+
+ def scan(self, timeout=10):
+ """Scan for BT devices."""
+ dbus.Interface(self._adapter, ADAPTER_INTERFACE).StartDiscovery()
+ logger.info('Adapter scan on ({}s)'.format(timeout))
+ GObject.timeout_add_seconds(timeout, self._scan_timeout)
+ self._main_loop.run()
+
+ def _scan_timeout(self):
+ dbus.Interface(self._adapter, ADAPTER_INTERFACE).StopDiscovery()
+ logger.info('Adapter scan completed')
+ self._main_loop.quit()
+
+ def find_device_with_service(self, ADV_SVC_UUID):
+ """Find a device with a given remote service."""
+ for path, ifaces in self._get_managed_objects().items():
+ device = ifaces.get(DEVICE_INTERFACE)
+ if device is None:
+ continue
+ logger.debug("{} {} {}".format(
+ path, device["Address"], device["Alias"]))
+ if ADV_SVC_UUID in device["UUIDs"] and path.startswith(self._path):
+ obj = self._bus.get_object("org.bluez", path)
+ logger.info('Device found: [ {} ] {} - {}'.format(
+ path, device["Name"], device["Address"]))
+ return dbus.Interface(obj, DEVICE_INTERFACE)
+ raise SystemExit("Bluetooth device not found!")
+
+ def remove_device(self, device):
+ """Remove the remote device object at the given path."""
+ try:
+ self._adapter.RemoveDevice(device)
+ except dbus.exceptions.DBusException as msg:
+ logging.error(msg)
+ raise SystemExit(1)
+ logger.info('Device properly removed')
+
+
+class BtGATTRemoteService:
+ """Bluetooth LE GATT Remote Service class."""
+ def __init__(self, SVC_UUID, adapter, device, max_notif):
+ self.SVC_UUID = SVC_UUID
+ self._adapter = adapter
+ self.device = device
+ self._max_notif = max_notif
+ self._notifications = 0
+ self._bus = dbus.SystemBus()
+ self._manager = dbus.Interface(
+ self._bus.get_object("org.bluez", "/"), OM_INTERFACE)
+ self._main_loop = GObject.MainLoop()
+ self._service = self._find_service()
+ self._path = self._service.object_path
+
+ def _get_managed_objects(self):
+ return self._manager.GetManagedObjects()
+
+ def _find_service(self):
+ for path, ifaces in self._get_managed_objects().items():
+ if GATT_SERVICE_INTERFACE not in ifaces.keys():
+ continue
+ service = self._bus.get_object('org.bluez', path)
+ props = dbus.Interface(service, PROP_INTERFACE)
+ if props.Get(GATT_SERVICE_INTERFACE, "UUID") == self.SVC_UUID:
+ logger.info('Service found: {}'.format(path))
+ return service
+ self._adapter.remove_device(self._device)
+ raise SystemExit("Bluetooth Service not found!")
+
+ def find_chrc(self, MSRMT_UUID):
+ for path, ifaces in self._get_managed_objects().items():
+ if GATT_CHRC_INTERFACE not in ifaces.keys():
+ continue
+ chrc = self._bus.get_object('org.bluez', path)
+ props = dbus.Interface(chrc, PROP_INTERFACE)
+ if props.Get(GATT_CHRC_INTERFACE, "UUID") == MSRMT_UUID:
+ logger.info('Characteristic found: {}'.format(path))
+ return chrc
+ self._adapter.remove_device(self._device)
+ raise SystemExit("Bluetooth Characteristic not found!")
+
+ def _generic_error_cb(self, error):
+ self._adapter.remove_device(self._device)
+ self._main_loop.quit()
+ raise SystemExit('D-Bus call failed: ' + str(error))
+
+ def _start_notify_cb(self):
+ logger.info('Notifications enabled')
+
+ def _notify_timeout(self):
+ self._adapter.remove_device(self._device)
+ self._main_loop.quit()
+ raise SystemExit('Notification test failed')
+
+ def _changed_cb(self, iface, changed_props, invalidated_props):
+ if iface != GATT_CHRC_INTERFACE:
+ return
+ if not len(changed_props):
+ return
+ value = changed_props.get('Value', None)
+ if not value:
+ return
+ logger.debug('New Notification')
+ self._notifications += 1
+ if self._notifications >= self._max_notif:
+ logger.info('Notification test succeeded')
+ self._main_loop.quit()
+
+ def check_notification(self, chrc, timeout=20):
+ # Listen to PropertiesChanged signals from the BLE Measurement
+ # Characteristic.
+ prop_iface = dbus.Interface(chrc, PROP_INTERFACE)
+ prop_iface.connect_to_signal("PropertiesChanged", self._changed_cb)
+
+ # Subscribe to BLE Measurement notifications.
+ chrc.StartNotify(reply_handler=self._start_notify_cb,
+ error_handler=self._generic_error_cb,
+ dbus_interface=GATT_CHRC_INTERFACE)
+ GObject.timeout_add_seconds(timeout, self._notify_timeout)
+ self._main_loop.run()
+
+
+def main():
+ logger.setLevel(logging.DEBUG)
+ parser = argparse.ArgumentParser()
+ parser.add_argument(
+ "id",
+ help='Address, udev path or name (hciX) of the BT adapter')
+ parser.add_argument(
+ "ADV_SVC_UUID", help='Beacon Gatt configuration service UUID')
+ parser.add_argument(
+ "SVC_UUID", help='Beacon Gatt notification service UUID')
+ parser.add_argument("MSRMT_UUID", help='Beacon Gatt measurement UUID')
+ parser.add_argument(
+ "--max-notif", "-m", type=int, default=5,
+ help="Maximum notification threshold")
+ args = parser.parse_args()
+ adapter = BtAdapter(args.id)
+ adapter.ensure_powered()
+ adapter.scan()
+ device = adapter.find_device_with_service(args.ADV_SVC_UUID)
+ try:
+ device.Connect()
+ except dbus.exceptions.DBusException as msg:
+ logging.error(msg)
+ adapter.remove_device(device)
+ raise SystemExit(1)
+ logger.info('Device connected, waiting 10s for services to be available')
+ time.sleep(10) # Let all the services to broadcast their UUIDs
+ service = BtGATTRemoteService(
+ args.SVC_UUID, adapter, device, args.max_notif)
+ chrc = service.find_chrc(args.MSRMT_UUID)
+ service.check_notification(chrc)
+ try:
+ device.Disconnect()
+ except dbus.exceptions.DBusException as msg:
+ logging.error(msg)
+ adapter.remove_device(device)
+ raise SystemExit(1)
+ logger.info('Device properly disconnected')
+ adapter.remove_device(device)
+
+
+if __name__ == "__main__":
+ sys.exit(main())
diff --git a/bin/gpu_test b/bin/gpu_test
index bd22acc..49ea31a 100755
--- a/bin/gpu_test
+++ b/bin/gpu_test
@@ -23,11 +23,13 @@ lockups.
Inspired by the workload directory of the xdiagnose package.
"""
+import gi
import os
import re
import subprocess
import sys
import time
+gi.require_version('Gio', '2.0')
from gi.repository import Gio
from math import cos, sin
from threading import Thread
diff --git a/bin/graphics_driver b/bin/graphics_driver
index dfb5522..6d28f5a 100755
--- a/bin/graphics_driver
+++ b/bin/graphics_driver
@@ -361,7 +361,10 @@ def hybrid_graphics_check(xlog):
def main():
- xlog = XorgLog("/var/log/Xorg.0.log")
+ if os.path.isfile("/var/log/Xorg.0.log"):
+ xlog = XorgLog("/var/log/Xorg.0.log")
+ else:
+ xlog = XorgLog(os.path.expanduser("~/.local/share/xorg/Xorg.0.log"))
results = []
results.append(get_driver_info(xlog))
diff --git a/bin/graphics_env b/bin/graphics_env
index 9511560..89c761d 100755
--- a/bin/graphics_env
+++ b/bin/graphics_env
@@ -19,7 +19,7 @@ if [[ $DRIVER == "amdgpu" || $DRIVER == "radeon" ]]; then
if [ $INDEX -gt 1 ]; then
# See https://wiki.archlinux.org/index.php/PRIME
echo "Setting up PRIME GPU offloading for AMD discrete GPU"
- if ! grep -q DRI3 /var/log/Xorg.0.log; then
+ if ! cat /var/log/Xorg.0.log ~/.local/share/xorg/Xorg.0.log 2>&1 | grep -q DRI3; then
PROVIDER_ID=`xrandr --listproviders | grep "Sink Output" | awk {'print $4'} | tail -1`
SINK_ID=`xrandr --listproviders | grep "Source Output" | awk {'print $4'} | tail -1`
xrandr --setprovideroffloadsink ${PROVIDER_ID} ${SINK_ID}
diff --git a/bin/gst_pipeline_test b/bin/gst_pipeline_test
index cde7fbb..4d9f3c4 100755
--- a/bin/gst_pipeline_test
+++ b/bin/gst_pipeline_test
@@ -1,11 +1,14 @@
#!/usr/bin/env python3
from argparse import ArgumentParser
+import gi
import logging
import re
import os
import sys
import time
+gi.require_version('Gst', '1.0')
+gi.require_version('GLib', '2.0')
from gi.repository import Gst
from gi.repository import GLib
from subprocess import check_output
diff --git a/bin/ipmi_test b/bin/ipmi_test
index 8be8b96..71e7f36 100755
--- a/bin/ipmi_test
+++ b/bin/ipmi_test
@@ -28,13 +28,15 @@ done
echo
echo "Checking for chassis status"
ipmitool chassis status && echo "Successfully got chassis status" && chassis=0 || chassis=1
-echo "Checking to see if we can get sensor data"
-ipmitool sdr list full && echo "Successfully got sensor data" && sensor=0 || sensor=1
+echo "Checking to see if we can get power status"
+ipmitool power status && echo "Successfully got power status" && power=0 || power=1
+echo "Checking to see if we can get user data"
+ipmitool user list && echo "Successfully got user data" && user=0 || user=1
echo "Checking to see if we can get info on the BMC"
ipmitool bmc info && echo "Successfully got BMC information" && bmc=0 || bmc=1
# if everything passes, exit 0
-[ $chassis -eq 0 ] && [ $sensor -eq 0 ] && [ $bmc -eq 0 ] && exit 0 || echo "FAILURE: chassis: $chassis sensor: $sensor bmc: $bmc"
+[ $chassis -eq 0 ] && [ $power -eq 0 ] && [ $user -eq 0 ] && [ $bmc -eq 0 ] && exit 0 || echo "FAILURE: chassis: $chassis power: $power user: $user bmc: $bmc"
# otherwise exit 1
exit 1
diff --git a/bin/key_test b/bin/key_test
index 3cf7ae0..2bd95f9 100755
--- a/bin/key_test
+++ b/bin/key_test
@@ -18,6 +18,7 @@
# along with Checkbox. If not, see <http://www.gnu.org/licenses/>.
+import gi
import os
import sys
@@ -27,6 +28,7 @@ import struct
import termios
from gettext import gettext as _
+
from gi.repository import GObject
from optparse import OptionParser
@@ -221,6 +223,8 @@ class GtkReporter(Reporter):
def __init__(self, *args, **kwargs):
super(GtkReporter, self).__init__(*args, **kwargs)
+ gi.require_version('Gdk', '3.0')
+ gi.require_version("Gtk", "3.0")
from gi.repository import Gdk, Gtk
# Initialize GTK constants
diff --git a/bin/keyboard_test b/bin/keyboard_test
index 309b845..1615106 100755
--- a/bin/keyboard_test
+++ b/bin/keyboard_test
@@ -33,8 +33,10 @@ def cli_prompt():
def gtk_prompt():
+ import gi
+ gi.require_version('Gdk', '3.0')
+ gi.require_version("Gtk", "3.0")
from gi.repository import Gtk, Gdk
-
# create a new window
window = Gtk.Window()
window.set_type_hint(Gdk.WindowType.TOPLEVEL)
diff --git a/bin/lock_screen_watcher b/bin/lock_screen_watcher
index 4e9847e..1c30270 100755
--- a/bin/lock_screen_watcher
+++ b/bin/lock_screen_watcher
@@ -17,7 +17,9 @@
# along with Checkbox. If not, see <http://www.gnu.org/licenses/>.
import dbus
+import gi
from dbus.mainloop.glib import DBusGMainLoop
+gi.require_version('GLib', '2.0')
from gi.repository import GObject
from gi.repository import GLib
diff --git a/bin/manage_compiz_plugin b/bin/manage_compiz_plugin
index a1236ea..9650a9d 100755
--- a/bin/manage_compiz_plugin
+++ b/bin/manage_compiz_plugin
@@ -1,7 +1,7 @@
#!/usr/bin/env python3
# This file is part of Checkbox.
#
-# Copyright 2014-2015 Canonical Ltd.
+# Copyright 2014-2018 Canonical Ltd.
# Written by:
# Daniel Manrique <roadmr@ubuntu.com>
# Sylvain Pineau <sylvain.pineau@canonical.com>
@@ -33,14 +33,13 @@ import sys
import subprocess
import time
-PATH="org.compiz.core:/org/compiz/profiles/unity/plugins/core/"
-KEY="active-plugins"
+KEY="/org/compiz/profiles/unity/plugins/core/active-plugins"
gettext.textdomain("com.canonical.certification.checkbox")
gettext.bindtextdomain("com.canonical.certification.checkbox",
os.getenv("CHECKBOX_PROVIDER_LOCALE_DIR", None))
-plugins = eval(subprocess.check_output(["gsettings", "get", PATH, KEY]))
+plugins = eval(subprocess.check_output(["dconf", "read", KEY]))
parser = argparse.ArgumentParser(description=_("enable/disable compiz plugins"),
epilog=_("Available plugins: {}").format(plugins))
@@ -58,6 +57,6 @@ else:
if args.plugin not in plugins:
raise SystemExit(_("Plugin {} doesn't exist").format(args.plugin))
plugins.remove(args.plugin)
-subprocess.call(["gsettings", "set", PATH, KEY, str(plugins)])
+subprocess.call(["dconf", "write", KEY, str(plugins)])
time.sleep(3)
diff --git a/bin/net_if_watcher.py b/bin/net_if_watcher.py
new file mode 100755
index 0000000..0ba61df
--- /dev/null
+++ b/bin/net_if_watcher.py
@@ -0,0 +1,43 @@
+#!/usr/bin/env python3
+# Copyright 2018 Canonical Ltd.
+# All rights reserved.
+#
+# Written by:
+# Maciej Kisielewski <maciej.kisielewski@canonical.com>
+"""
+Detect insertion of a new network interface.
+"""
+
+from pathlib import Path
+import time
+
+
+def get_ifaces():
+ return set([i.name for i in Path("/sys/class/net").iterdir()])
+
+
+def main():
+ print("INSERT NOW")
+ starting_ifaces = get_ifaces()
+ attempts = 20
+ while attempts > 0:
+ now_ifaces = get_ifaces()
+ # check if something disappeared
+ if not starting_ifaces == now_ifaces & starting_ifaces:
+ raise SystemExit("Interface(s) disappeared: {}".format(
+ ", ".join(list(starting_ifaces - now_ifaces))))
+ new_ifaces = now_ifaces - starting_ifaces
+ if new_ifaces:
+ print()
+ print("New interface(s) detected: {}".format(
+ ", ".join(list(new_ifaces))))
+ return
+ time.sleep(1)
+ print('.', end='', flush=True)
+ attempts -= 1
+ print()
+ raise SystemExit("Failed to detect new network interface")
+
+
+if __name__ == '__main__':
+ main()
diff --git a/bin/network_restart b/bin/network_restart
index 31f1da7..d01e983 100755
--- a/bin/network_restart
+++ b/bin/network_restart
@@ -14,6 +14,9 @@ from subprocess import check_output, check_call, CalledProcessError, STDOUT
from argparse import ArgumentParser
try:
+ import gi
+ gi.require_version('GLib', '2.0')
+ gi.require_version("Gtk", "3.0")
from gi.repository import Gtk, GObject, GLib
GLib.threads_init()
GObject.threads_init()
diff --git a/bin/pm_test b/bin/pm_test
index d1bd3b1..70cd121 100755
--- a/bin/pm_test
+++ b/bin/pm_test
@@ -1,4 +1,10 @@
#!/usr/bin/env python3
+"""
+If you're debugging this program, set PM_TEST_DRY_RUN in your environment.
+It will make the script not run actual S3, S4, reboot and poweroff commands.
+"""
+import gi
+import json
import logging
import logging.handlers
import os
@@ -13,7 +19,7 @@ from calendar import timegm
from configparser import ConfigParser
from datetime import datetime, timedelta
from time import localtime, time
-
+gi.require_version("Gtk", "3.0")
from gi.repository import GObject, Gtk
@@ -41,8 +47,13 @@ def main():
logging.debug('Arguments: {0!r}'.format(args))
logging.debug('Extra Arguments: {0!r}'.format(extra_args))
+ dry_run = os.environ.get('PM_TEST_DRY_RUN', False)
+ if dry_run:
+ logging.info("Running in dry-run mode")
+
try:
- operation = PowerManagementOperation(args, extra_args, user=username)
+ operation = PowerManagementOperation(
+ args, extra_args, user=username, dry_run=dry_run)
operation.setup()
operation.run()
except (TestCancelled, TestFailed) as exception:
@@ -64,10 +75,11 @@ def main():
class PowerManagementOperation():
SLEEP_TIME = 5
- def __init__(self, args, extra_args, user=None):
+ def __init__(self, args, extra_args, user=None, dry_run=False):
self.args = args
self.extra_args = extra_args
self.user = user
+ self.dry_run = dry_run
def setup(self):
"""
@@ -128,11 +140,17 @@ class PowerManagementOperation():
logging.info('Executing new {0!r} operation...'
.format(self.args.pm_operation))
logging.debug('Executing: {0!r}...'.format(command_str))
- # The PM operation is performed asynchronously so let's just wait
- # indefinitely until it happens and someone comes along to kill us.
- # This addresses LP: #1413134
- subprocess.check_call(command_str, shell=True)
- signal.pause()
+ if self.dry_run:
+ print("\n\nRUNNING IN DRY-RUN MODE")
+ print("Normally the program would run: {}".format(command_str))
+ print("Waiting for Enter instead")
+ input()
+ else:
+ # The PM operation is performed asynchronously so let's just wait
+ # indefinitely until it happens and someone comes along to kill us.
+ # This addresses LP: #1413134
+ subprocess.check_call(command_str, shell=True)
+ signal.pause()
def run_suspend_cycles(self, cycles_count, fwts):
"""Run suspend and resume cycles."""
@@ -155,15 +173,21 @@ class PowerManagementOperation():
command_str = command_tpl.format(script_path, cycles_count)
logging.info('Running suspend/resume cycles')
logging.debug('Executing: {0!r}...'.format(command_str))
- try:
- # We call sleep_test or fwts_test script and log its output as it
- # contains average times we need to compute global average times
- # later.
- logging.info(subprocess.check_output(
- command_str, universal_newlines=True, shell=True))
- except subprocess.CalledProcessError as e:
- logging.error('Error while running {0}:'.format(e.cmd))
- logging.error(e.output)
+ if self.dry_run:
+ print("\n\nRUNNING IN DRY-RUN MODE")
+ print("Normally the program would run: {}".format(command_str))
+ print("Waiting for Enter instead")
+ input()
+ else:
+ try:
+ # We call sleep_test or fwts_test script and log its output as
+ # it contains average times we need to compute global average
+ # times later.
+ logging.info(subprocess.check_output(
+ command_str, universal_newlines=True, shell=True))
+ except subprocess.CalledProcessError as e:
+ logging.error('Error while running {0}:'.format(e.cmd))
+ logging.error(e.output)
def summary(self):
"""
@@ -199,6 +223,29 @@ class PowerManagementOperation():
message = ('{0} test complete'
.format(self.args.pm_operation.capitalize()))
+ total_suspends_expected = (
+ self.args.suspends_before_reboot * self.args.total)
+ problems = ''
+ fwts_log_path = os.path.join(self.args.log_dir, 'fwts.log')
+ try:
+ with open(fwts_log_path, 'rt') as f:
+ magic_line = 'Completed S3 cycle(s) \n'
+ count = f.readlines().count(magic_line)
+ if count != total_suspends_expected:
+ problems = (
+ "Found {} occurrences of '{}'. Expected {}".format(
+ count, magic_line.strip(),
+ total_suspends_expected))
+ except FileNotFoundError:
+ problems = "Error opening {}".format(fwts_log_path)
+ if problems:
+ result = {
+ 'outcome': 'fail' if problems else 'pass',
+ 'comment': problems,
+ }
+ with open(os.path.join(self.args.log_dir, '__result'), 'wt') as f:
+ json.dump(result, f)
+
if self.args.silent:
logging.info(message)
else:
@@ -206,6 +253,8 @@ class PowerManagementOperation():
MessageDialog(title, message).run()
if self.args.checkbox_respawn_cmd:
subprocess.run(
+ r'unset LD_LIBRARY_PATH;'
+ r'unset PYTHONPATH; unset PYTHONHOME;'
r'DISPLAY=:0 x-terminal-emulator -e "sudo -u '
r'{} bash -c \"source {}; exec bash\""'.format(
self.user, self.args.checkbox_respawn_cmd), shell=True)
@@ -572,11 +621,11 @@ autologin-user-timeout=0
shutil.copystat(self.config_filename, backup_filename)
break
- with open(self.config_filename, 'w') as f:
- if self.config_filename == '/etc/lightdm/lightdm.conf':
- f.write(self.template.format(username=self.user))
- elif self.config_filename == '/etc/gdm3/custom.conf':
- self.parser.write(f)
+ with open(self.config_filename, 'w') as f:
+ if self.config_filename == '/etc/lightdm/lightdm.conf':
+ f.write(self.template.format(username=self.user))
+ elif self.config_filename == '/etc/gdm3/custom.conf':
+ self.parser.write(f)
def disable(self):
"""
diff --git a/bin/removable_storage_test b/bin/removable_storage_test
index 42e197a..6de3f97 100755
--- a/bin/removable_storage_test
+++ b/bin/removable_storage_test
@@ -841,20 +841,10 @@ def main():
# This will raise KeyError for no
# associated disk device was found.
xhci_disks = test.get_disks_xhci()
- # pep8 style suggest to limit the try clause
- # to the absolute minimum amount of code necessary
- try:
- disk_xhci_flag = xhci_disks[disk]
- except KeyError:
- print("\t\tDisk does not use xhci_hci.")
- return 1
- else:
- if('xhci' == disk_xhci_flag):
- print("\t\tDriver Detected: xhci_hcd")
- else:
- print("\t\tDisk does not use xhci_hci.")
- logging.debug("disk_xhci_flag is not xhci")
- return 1
+ if test.get_disks_xhci().get(disk, '') != 'xhci':
+ raise SystemExit(
+ "\t\tDisk does not use xhci_hcd.")
+ print("\t\tDriver Detected: xhci_hcd")
else:
# Give it a hint for the detection failure.
# LP: #1362902
diff --git a/bin/resolution_test b/bin/resolution_test
index a50868b..55a7828 100755
--- a/bin/resolution_test
+++ b/bin/resolution_test
@@ -1,9 +1,10 @@
#!/usr/bin/env python3
+import gi
import sys
from argparse import ArgumentParser
-
+gi.require_version('Gdk', '3.0')
from gi.repository import Gdk
diff --git a/bin/socketcan_test.py b/bin/socketcan_test.py
new file mode 100755
index 0000000..232fc2c
--- /dev/null
+++ b/bin/socketcan_test.py
@@ -0,0 +1,199 @@
+#!/usr/bin/env python3
+# This file is part of Checkbox.
+#
+# Copyright 2018 Canonical Ltd.
+# Written by:
+# Jonathan Cave <jonathan.cave@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 argparse
+import os
+import socket
+import struct
+import sys
+import textwrap
+import threading
+import time
+
+
+class CANSocket():
+
+ # struct module format strings for CAN packets
+ # Normal format:
+ # < little-endian
+ # I unsigned int (4) : CAN-ID + EFF/RTR/ERR Flags
+ # B unsigned char (1) : Data length
+ # 3x padding (3 * 1) : -
+ # 8s char array (8 * 1) : Data
+ FORMAT = "<IB3x8s"
+ # Flexible Data (FD) rate format:
+ # < little-endian
+ # I unsigned int (4) : CAN-ID + EFF/RTR/ERR Flags
+ # B unsigned char (1) : Data length
+ # B unsigned char (1) : FD Flags
+ # 2x padding (2 * 1) : -
+ # 64s char array (64 * 1) : Data
+ FD_FORMAT = "<IBB2x64s"
+
+ CAN_MTU = struct.Struct(FORMAT).size
+ CANFD_MTU = struct.Struct(FD_FORMAT).size
+
+ # Socket options from <linux/can/raw.h>
+ CAN_RAW_FILTER = 1 # set 0 .. n can_filter(s)
+ CAN_RAW_ERR_FILTER = 2 # set filter for error frames
+ CAN_RAW_LOOPBACK = 3 # local loopback (default:on)
+ CAN_RAW_RECV_OWN_MSGS = 4 # receive my own msgs (default:off)
+ CAN_RAW_FD_FRAMES = 5 # allow CAN FD frames (default:off)
+ CAN_RAW_JOIN_FILTERS = 6 # all filters must match to trigger
+
+ def __init__(self, interface=None, fdmode=False, loopback=True):
+ self.sock = socket.socket(socket.PF_CAN, # protocol family
+ socket.SOCK_RAW,
+ socket.CAN_RAW)
+ self._fdmode = fdmode
+ self._loopback = loopback
+ if interface is not None:
+ self._bind(interface)
+
+ def __enter__(self):
+ return self
+
+ def __exit__(self, *args):
+ self.close()
+
+ def close(self):
+ self.sock.close()
+
+ def _bind(self, interface):
+ self.sock.bind((interface,))
+ if self._fdmode: # default is off
+ self.sock.setsockopt(socket.SOL_CAN_RAW, self.CAN_RAW_FD_FRAMES, 1)
+ if not self._loopback: # default is on
+ self.sock.setsockopt(socket.SOL_CAN_RAW, self.CAN_RAW_LOOPBACK, 0)
+
+ def send(self, can_id, data, id_flags=0, fd_flags=0):
+ can_id = can_id | id_flags
+ if self._fdmode:
+ can_pkt = struct.pack(self.FD_FORMAT, can_id, len(data), fd_flags,
+ data)
+ else:
+ can_pkt = struct.pack(self.FORMAT, can_id, len(data), data)
+ self.sock.send(can_pkt)
+
+ def recv(self):
+ if self._fdmode:
+ can_pkt = self.sock.recv(self.CANFD_MTU)
+ can_id, length, fd_flags, data = struct.unpack(self.FD_FORMAT,
+ can_pkt)
+ else:
+ can_pkt = self.sock.recv(self.CAN_MTU)
+ can_id, length, data = struct.unpack(self.FORMAT, can_pkt)
+ can_id &= socket.CAN_EFF_MASK
+ return (can_id, data[:length])
+
+
+def echo_test(args):
+ # ID conversion and size check
+ print('Using source ID: {}'.format(args.can_id))
+ can_id_i = int(args.can_id, 16)
+ if can_id_i > 2047 and not args.effid:
+ raise SystemExit('ERROR: CAN ID to high for SFF')
+ id_flags = 0
+ if args.effid:
+ print('Setting EFF CAN ID flag')
+ id_flags = socket.CAN_EFF_FLAG
+
+ # Whether to enable local loopback, required for local only test
+ # but only want to parse packets from other end if remote
+ loopback = not args.remote
+
+ # Default data size is 8 bytes but if testing FD Mode use 64
+ data_size = 8
+ if args.fdmode:
+ data_size = 64
+ data_b = os.urandom(data_size)
+ print('Sending data: {}'.format(data_b.hex()))
+
+ recv_id_i = None
+ recv_data_b = None
+
+ def receive():
+ nonlocal recv_id_i
+ nonlocal recv_data_b
+ print('Opening read socket on {}'.format(args.interface))
+ with CANSocket(args.interface, fdmode=args.fdmode,
+ loopback=loopback) as recv_s:
+ recv_id_i, recv_data_b = recv_s.recv()
+
+ # Create a receive thread
+ recv_t = threading.Thread(target=receive, daemon=True)
+ recv_t.start()
+ time.sleep(1)
+
+ print('Opening send socket on {}'.format(args.interface))
+ # Open socket, will raise OSError on failure
+ with CANSocket(args.interface, fdmode=args.fdmode,
+ loopback=loopback) as send_s:
+ print('Sending data...', flush=True)
+ try:
+ send_s.send(can_id_i, data_b, id_flags=id_flags)
+ except OSError as e:
+ print(e, file=sys.stderr)
+ if e.errno == 90:
+ raise SystemExit('ERROR: interface does not support FD Mode')
+ else:
+ raise SystemExit('ERROR: OSError on attempt to send')
+
+ recv_t.join(10)
+ if recv_t.is_alive():
+ raise SystemExit('ERROR: Timeout waiting to receive data')
+
+ print('Received packet')
+ print(' ID : {:x}'.format(recv_id_i))
+ print(' Data: {}'.format(recv_data_b.hex()))
+ if recv_id_i != can_id_i or recv_data_b != data_b:
+ raise SystemExit('ERROR: ID/Data received does not match sent')
+
+ print('\nPASSED')
+
+
+def main():
+ parser = argparse.ArgumentParser(
+ formatter_class=argparse.RawDescriptionHelpFormatter,
+ description='SocketCAN Tests',
+ epilog=textwrap.dedent('''
+ Examples:
+ socketcan_test.py can0 123
+ socketcan_test.py can0 212 --remote
+ socketcan_test.py can0 FA123 --effid
+ socketcan_test.py can0 E407DB --effid --fdmode''').lstrip())
+ parser.add_argument('interface', type=str, help='Interface name e.g. can0')
+ parser.add_argument('can_id', type=str, help=textwrap.dedent('''
+ CAN ID of source in Hex, max of 11 bits using Standard Frame
+ Format (SFF). Specifying use of Extended Frame Format (EFF)
+ allows the use of up to 29 bit IDs.''').lstrip())
+ parser.add_argument('--remote', action='store_true',
+ help='Expect a remote device to echo the test packet')
+ parser.add_argument('--effid', action='store_true',
+ help='Use EFF ID (CAN 2.0 B)')
+ parser.add_argument('--fdmode', action='store_true',
+ help='Attempt to send 64 bytes of data i.e. FD mode')
+ parser.set_defaults(func=echo_test)
+
+ args = parser.parse_args()
+ args.func(args)
+
+
+if __name__ == "__main__":
+ main()
diff --git a/bin/touchpad_test b/bin/touchpad_test
index 7152745..bc6a474 100755
--- a/bin/touchpad_test
+++ b/bin/touchpad_test
@@ -1,9 +1,13 @@
#!/usr/bin/env python3
+import gi
import sys
import gettext
from gettext import gettext as _
+gi.require_version('Gdk', '3.0')
+gi.require_version('Gio', '2.0')
+gi.require_version("Gtk", "3.0")
from gi.repository import Gio, Gtk, Gdk
from optparse import OptionParser
diff --git a/bin/xrandr_cycle b/bin/xrandr_cycle
index b9f615b..34f953c 100755
--- a/bin/xrandr_cycle
+++ b/bin/xrandr_cycle
@@ -87,6 +87,13 @@ for adapter, mode in modes:
highest_modes = []
for adapter, params in top_res_per_aspect.items():
for aspect, width in params.items():
+ # xrandr can list modes that are unsupported, unity-control-center
+ # defines minimum width and height, below which the resolution
+ # is not listed as a choice in display settings panel in UCC
+ # see should_show_resolution function in cc-display-panel.c
+ # from lp:unity-control-center
+ if width < 675 or width / aspect < 530:
+ continue
mode = '{}x{}'.format(width, width/aspect)
highest_modes.append((adapter, mode))
diff --git a/debian/.git-dpm b/debian/.git-dpm
index 24742a6..9b320b0 100644
--- a/debian/.git-dpm
+++ b/debian/.git-dpm
@@ -1,8 +1,8 @@
# see git-dpm(1) from git-dpm package
-22b317e6019e8aa8f46783bb17d59b220a764fbd
-22b317e6019e8aa8f46783bb17d59b220a764fbd
-22b317e6019e8aa8f46783bb17d59b220a764fbd
-22b317e6019e8aa8f46783bb17d59b220a764fbd
-plainbox-provider-checkbox_0.45.0.orig.tar.gz
-f48a6319d5cdc242ef34c6fce7dbce58c88d90a2
-1739413
+6ca200fedf88bf8fba57b3f2eda59799d6f574cd
+6ca200fedf88bf8fba57b3f2eda59799d6f574cd
+6ca200fedf88bf8fba57b3f2eda59799d6f574cd
+6ca200fedf88bf8fba57b3f2eda59799d6f574cd
+plainbox-provider-checkbox_0.46.0~rc1.orig.tar.gz
+2385f8bb672cc0c6552661f065f9d55b817f3bfb
+1745746
diff --git a/manage.py b/manage.py
index 8e98964..f2f241c 100755
--- a/manage.py
+++ b/manage.py
@@ -5,7 +5,7 @@ from plainbox.provider_manager import N_
setup(
name='plainbox-provider-checkbox',
namespace='com.canonical.certification',
- version="0.45.0",
+ version="0.46.0rc1",
description=N_("Checkbox provider"),
gettext_domain='plainbox-provider-checkbox',
strict=False, deprecated=False,
diff --git a/units/audio/jobs.pxu b/units/audio/jobs.pxu
index fa75447..120a9bd 100644
--- a/units/audio/jobs.pxu
+++ b/units/audio/jobs.pxu
@@ -49,6 +49,7 @@ requires:
package.name == 'alsa-base'
package.name == 'gir1.2-gst-plugins-base-0.10' or package.name == 'gir1.2-gst-plugins-base-1.0'
package.name == 'pulseaudio-utils'
+flags: also-after-suspend-manual
command:
audio_settings store --verbose --file=$PLAINBOX_SESSION_SHARE/pulseaudio_settings
audio_settings set --verbose --device=hdmi --volume=50
@@ -77,6 +78,7 @@ requires:
package.name == 'alsa-base'
package.name == 'gir1.2-gst-plugins-base-0.10' or package.name == 'gir1.2-gst-plugins-base-1.0'
package.name == 'pulseaudio-utils'
+flags: also-after-suspend-manual
command:
audio_settings store --verbose --file=$PLAINBOX_SESSION_SHARE/pulseaudio_settings
audio_settings set --verbose --device=hdmi --volume=50
@@ -106,6 +108,7 @@ requires:
package.name == 'alsa-base'
package.name == 'gir1.2-gst-plugins-base-0.10' or package.name == 'gir1.2-gst-plugins-base-1.0'
package.name == 'pulseaudio-utils'
+flags: also-after-suspend-manual
command:
audio_settings store --verbose --file=$PLAINBOX_SESSION_SHARE/pulseaudio_settings
audio_settings set --verbose --device=hdmi --volume=50
@@ -135,6 +138,7 @@ requires:
package.name == 'alsa-base'
package.name == 'gir1.2-gst-plugins-base-0.10' or package.name == 'gir1.2-gst-plugins-base-1.0'
package.name == 'pulseaudio-utils'
+flags: also-after-suspend-manual
command:
audio_settings store --verbose --file=$PLAINBOX_SESSION_SHARE/pulseaudio_settings
audio_settings set --verbose --device=hdmi --volume=50
@@ -165,6 +169,7 @@ requires:
package.name == 'alsa-base'
package.name == 'gir1.2-gst-plugins-base-0.10' or package.name == 'gir1.2-gst-plugins-base-1.0'
package.name == 'pulseaudio-utils'
+flags: also-after-suspend-manual
command:
audio_settings store --verbose --file=$PLAINBOX_SESSION_SHARE/pulseaudio_settings
audio_settings set --verbose --device=hdmi --volume=50
diff --git a/units/bluetooth/jobs.pxu b/units/bluetooth/jobs.pxu
index 0a246df..1f85fa6 100644
--- a/units/bluetooth/jobs.pxu
+++ b/units/bluetooth/jobs.pxu
@@ -132,7 +132,7 @@ id: bluetooth/file_transfer_stress
estimated_duration: 300.0
requires:
package.name == 'bluez'
- package.name == 'obexftp'
+ executable.name == 'obexftp'
device.category == 'BLUETOOTH'
command:
if [ -z "$BTDEVADDR" ]
@@ -194,3 +194,23 @@ _steps:
3. After it's paired and connected, enter some text with your keyboard and close the small input test tool.
_verification:
Did the Bluetooth Smart keyboard work as expected?
+
+unit: template
+template-resource: device
+template-filter: device.category == 'BLUETOOTH'
+template-engine: jinja2
+template-unit: job
+id: bluetooth4/beacon_notification_{{ path }}
+_summary: Test system can get beacon notifications on the {{ path.split('/')[-1] }} adapter
+environ: ADV_SVC_UUID SVC_UUID MSRMT_UUID
+command:
+ gatt-notify-test.py {{ path.split('/')[-1] }} $ADV_SVC_UUID $SVC_UUID $MSRMT_UUID
+plugin: shell
+user: root
+category_id: com.canonical.plainbox::bluetooth
+estimated_duration: 30
+requires:
+ package.name == 'bluez' or snap.name == 'bluez'
+ {%- if __on_ubuntucore__ %}
+ connections.slot == 'bluez:service' and connections.plug == '{{ __system_env__["SNAP_NAME"] }}:bluez'
+ {% endif -%}
diff --git a/units/bluetooth/test-plan.pxu b/units/bluetooth/test-plan.pxu
index ae2c305..498a4ce 100644
--- a/units/bluetooth/test-plan.pxu
+++ b/units/bluetooth/test-plan.pxu
@@ -14,10 +14,10 @@ _name: Bluetooth tests (Manual)
_description:
Bluetooth tests (Manual)
include:
- bluetooth/audio-a2dp certification-status=blocker
+ bluetooth/audio-a2dp certification-status=non-blocker
bluetooth/HID
- bluetooth4/HOGP-mouse certification-status=non-blocker
- bluetooth4/HOGP-keyboard certification-status=non-blocker
+ bluetooth4/HOGP-mouse certification-status=blocker
+ bluetooth4/HOGP-keyboard certification-status=blocker
id: bluetooth-cert-automated
@@ -32,5 +32,5 @@ unit: test plan
_name: Bluetooth tests (certification blockers only)
_description: Bluetooth tests (certification blockers only)
include:
- bluetooth/detect-output certification-status=blocker
- bluetooth/audio-a2dp certification-status=blocker
+ bluetooth4/HOGP-mouse certification-status=blocker
+ bluetooth4/HOGP-keyboard certification-status=blocker
diff --git a/units/camera/jobs.pxu b/units/camera/jobs.pxu
index 4db5222..4219462 100644
--- a/units/camera/jobs.pxu
+++ b/units/camera/jobs.pxu
@@ -4,7 +4,8 @@ id: camera/detect
estimated_duration: 1.2
requires:
device.category == 'CAPTURE'
-command: if [ "`lsb_release -c | awk {'print $2'}`" == "precise" ]; then camera_test_legacy detect; else camera_test detect; fi
+command:
+ camera_test detect
_description: This Automated test attempts to detect a camera.
plugin: user-interact-verify
@@ -14,7 +15,8 @@ estimated_duration: 120.0
depends: camera/detect
requires:
device.category == 'CAPTURE'
-command: if [ "`lsb_release -c | awk {'print $2'}`" == "precise" ]; then camera_test_legacy display; else camera_test display; fi
+command:
+ camera_test display
_description:
PURPOSE:
This test will check that the built-in camera works
@@ -24,16 +26,23 @@ _description:
Did you see the video capture?
plugin: user-interact-verify
+template-engine: jinja2
category_id: com.canonical.plainbox::camera
id: camera/still
estimated_duration: 120.0
depends: camera/detect
requires:
- package.name == 'gir1.2-gst-plugins-base-0.10' or package.name == 'gir1.2-gst-plugins-base-1.0'
+ {%- if __on_ubuntucore__ %}
+ executable.name == 'fswebcam'
+ device.category == 'CAPTURE'
+ {%- else %}
+ package.name == 'gir1.2-gst-plugins-base-1.0'
package.name == 'eog'
- package.name == 'fswebcam' or package.name == 'gir1.2-gst-plugins-base-0.10' or package.name == 'gir1.2-gst-plugins-base-1.0'
+ package.name == 'fswebcam' or package.name == 'gir1.2-gst-plugins-base-1.0'
device.category == 'CAPTURE'
-command: if [ "`lsb_release -c | awk {'print $2'}`" == "precise" ]; then camera_test_legacy still; else camera_test still; fi
+ {% endif -%}
+command:
+ camera_test still
_description:
PURPOSE:
This test will check that the built-in camera works
@@ -43,14 +52,21 @@ _description:
Did you see the image?
plugin: shell
+template-engine: jinja2
category_id: com.canonical.plainbox::camera
id: camera/multiple-resolution-images
estimated_duration: 1.2
depends: camera/detect
requires:
- package.name == 'fswebcam' or package.name == 'gir1.2-gst-plugins-base-0.10' or package.name == 'gir1.2-gst-plugins-base-1.0'
+ {%- if __on_ubuntucore__ %}
+ executable.name == 'fswebcam'
+ device.category == 'CAPTURE'
+ {%- else %}
+ package.name == 'fswebcam' or package.name == 'gir1.2-gst-plugins-base-1.0'
device.category == 'CAPTURE'
-command: if [ "`lsb_release -c | awk {'print $2'}`" == "precise" ]; then camera_test_legacy resolutions; else camera_test resolutions; fi
+ {% endif -%}
+command:
+ camera_test resolutions
_description:
Takes multiple pictures based on the resolutions supported by the camera and
validates their size and that they are of a valid format.
diff --git a/units/cpu/jobs.pxu b/units/cpu/jobs.pxu
index db0dd8f..a64757e 100644
--- a/units/cpu/jobs.pxu
+++ b/units/cpu/jobs.pxu
@@ -77,7 +77,7 @@ _summary:
Test offlining of each CPU core
_description:
Attempts to offline each core in a multicore system.
-requires: cpuinfo.platform not in ("aarch64", "armhf")
+requires: cpuinfo.platform not in ("aarch64", "armv7l")
plugin: shell
category_id: com.canonical.plainbox::cpu
@@ -100,18 +100,37 @@ command: nice -n -20 frequency_governors_test --debug
_description:
This test checks that CPU frequency governors are obeyed when set.
+unit: template
+template-resource: cpuinfo
+template-filter: cpuinfo.platform == 'armv7l'
+template-unit: job
plugin: shell
category_id: com.canonical.plainbox::cpu
-id: cpu/arm_vfp_support
+id: cpu/arm_vfp_support_{platform}
estimated_duration: 1.0
-requires:
- cpuinfo.platform in ("armv7l", "aarch64")
user: root
-command: grep VFP /var/log/syslog
+command:
+ echo "{other}" | grep "vfp\|vfpv3\|vfpv4\|vfpd32"
+_summary:
+ Validate that the Vector Floating Point Unit is running on {platform} device
+_description:
+ Validate that the Vector Floating Point Unit is running on {platform} device.
+
+unit: template
+template-resource: cpuinfo
+template-filter: cpuinfo.platform == 'aarch64'
+template-unit: job
+plugin: shell
+category_id: com.canonical.plainbox::cpu
+id: cpu/arm_vfp_support_{platform}
+estimated_duration: 1.0
+user: root
+command:
+ echo "{other}" | grep "fp"
_summary:
- Validate that the Vector Floating Point Unit is running on ARM device
+ Validate that the Floating Point Unit is running on {platform} device
_description:
- Validate that the Vector Floating Point Unit is running on ARM device.
+ Validate that the Floating Point Unit is running on {platform} device.
plugin:shell
id: cpu/cstates
diff --git a/units/disk/encryption.pxu b/units/disk/encryption.pxu
new file mode 100644
index 0000000..b7d41c8
--- /dev/null
+++ b/units/disk/encryption.pxu
@@ -0,0 +1,21 @@
+
+id: disk/encryption/detect
+category_id: com.canonical.plainbox::disk
+plugin: shell
+template-engine: jinja2
+user: root
+requires:
+ executable.name == 'lsblk'
+ executable.name == 'dmsetup'
+ executable.name == 'cryptsetup'
+_summary: Test that Full Disk Encryption is in use
+_description:
+ Examine the system to detect if one of the standard full disk encryption
+ implementations is in use
+command:
+ {%- if __on_ubuntucore__ %}
+ fde_tests.py
+ {%- else %}
+ fde_tests.py desktop
+ {% endif -%}
+estimated_duration: 2.0 \ No newline at end of file
diff --git a/units/disk/jobs.pxu b/units/disk/jobs.pxu
index 072ac52..3de5532 100644
--- a/units/disk/jobs.pxu
+++ b/units/disk/jobs.pxu
@@ -21,7 +21,7 @@ flags: deprecated
user: root
estimated_duration: 10.0
command: disk_stats_test {name}
-_summary: Disk statistics for {product}
+_summary: Disk statistics for {product_slug}
_description:
This test checks disk stats, generates some activity and rechecks stats to
verify they've changed. It also verifies that disks appear in the various
@@ -29,7 +29,7 @@ _description:
.
This test will inspect the following disk:
.
- product name: {product}
+ product name: {product_slug}
sysfs path: {path}
device node path: /dev/{name}
@@ -44,9 +44,9 @@ requires:
package.name == 'smartmontools' or executable.name == 'smartctl'
block_device.smart == 'True' and block_device.name == '{name}'
_summary:
- Test SMART capabilities for {product}
+ Test SMART capabilities for {product_slug}
_description:
- This tests the SMART capabilities for {product} (Note that this test may not work against hardware RAID)
+ This tests the SMART capabilities for {product_slug} (Note that this test may not work against hardware RAID)
user: root
command: disk_smart -b /dev/{name} -s 130 -t 530
@@ -58,9 +58,10 @@ category_id: com.canonical.plainbox::disk
id: disk/read_performance_{name}
estimated_duration: 65.0
requires:
-_summary: Disk performance test for {product}
+_summary: Disk performance test for {product_slug}
_description: Verify that disk storage performs at or above baseline performance
user: root
+environ: DISK_READ_PERF
command: disk_read_performance_test {name}
unit: template
@@ -72,7 +73,7 @@ id: disk/storage_device_{name}
estimated_duration: 375.0
user: root
requires:
-_summary: Disk I/O stress test for {product}
+_summary: Disk I/O stress test for {product_slug}
_description: Take the path of the storage device and test is it a block device
command: storage_test {name}
@@ -87,8 +88,8 @@ user: root
requires:
package.name == 'stress-ng' or executable.name == 'stress-ng'
package.name == 'uuid-runtime' or executable.name == 'uuidgen'
-_summary: Disk stress_ng test for {product}
-_description: Disk stress_ng test for {product}
+_summary: Disk stress_ng test for {product_slug}
+_description: Disk stress_ng test for {product_slug}
command: disk_stress_ng {name} --base-time 240 --really-run
unit: template
@@ -102,8 +103,8 @@ user: root
requires:
block_device.state != 'removable' and block_device.name == '{name}'
package.name == 'bc' or executable.name == 'bc'
-_summary: Check of CPU load imposed by {product}
-_description: Check to ensure CPU load of {product} is not too high
+_summary: Check of CPU load imposed by {product_slug}
+_description: Check to ensure CPU load of {product_slug} is not too high
command: disk_cpu_load {name}
plugin: shell
@@ -124,7 +125,7 @@ id: disk/hdd-parking
estimated_duration: 60.0
requires:
device.category == 'DISK'
- package.name == 'hdapsd'
+ executable.name == 'hdapsd'
depends: input/accelerometer
user: root
command: hdd_parking
diff --git a/units/disk/test-plan.pxu b/units/disk/test-plan.pxu
index 08974cb..b080966 100644
--- a/units/disk/test-plan.pxu
+++ b/units/disk/test-plan.pxu
@@ -27,3 +27,24 @@ include:
disk/detect certification-status=blocker
disk/read_performance_.* certification-status=blocker
disk/storage_device_.* certification-status=blocker
+
+id: disk-full
+unit: test plan
+_name: Disks tests
+_description: QA disk tests for Ubuntu Core devices
+include:
+nested_part:
+ disk-automated
+
+id: disk-automated
+unit: test plan
+_name: Automated disk tests
+_description: Automated disk tests for Ubuntu Core devices
+estimated_duration: 1h30m
+include:
+ disk/detect
+ disk/stats_.*
+ disk/read_performance_.*
+ disk/storage_device_.*
+bootstrap_include:
+ device
diff --git a/units/ethernet/jobs.pxu b/units/ethernet/jobs.pxu
index 90e0edf..c6e679a 100644
--- a/units/ethernet/jobs.pxu
+++ b/units/ethernet/jobs.pxu
@@ -129,3 +129,275 @@ requires:
command: network test -i {interface} -t stress
_description:
Automated test that tests performance of ethernet device {__index__} ({interface}).
+
+unit: template
+template-resource: device
+template-filter: device.category == 'NETWORK' and device.interface != 'UNKNOWN'
+id: ethernet/ping_{interface}
+_summary: Can ping another machine over Ethernet port {interface}
+_description: Check Ethernet works by pinging another machine
+plugin: shell
+command:
+ gateway_ping_test -v --interface {interface}
+category_id: com.canonical.plainbox::ethernet
+estimated_duration: 4.0
+flags: preserve-locale also-after-suspend
+
+unit: template
+template-resource: device
+template-filter: device.category == 'NETWORK' and device.mac != 'UNKNOWN'
+id: ethernet/wol_S5_{interface}
+_summary: Wake on LAN (WOL) test from S5 - {interface}
+_purpose:
+ Check that another system can wake up from S5 the SUT using ethernet port {interface} WOL function.
+_steps:
+ 1. Ensure there is an ethernet cable attached to port {interface}.
+ 2. Press Enter for S5 (Soft Off).
+ 3. From another computer on the same network run the following command:
+ $ wakeonlan {mac}
+ If wakeonlan tool is not installed run:
+ $ sudo apt install wakeonlan
+ 4. Resume Checkbox
+_verification:
+ Did the SUT wake up from S5?
+plugin: user-interact-verify
+command: poweroff
+user: root
+category_id: com.canonical.plainbox::ethernet
+estimated_duration: 120
+flags: preserve-locale
+
+unit: template
+template-resource: device
+template-filter: device.category == 'NETWORK' and device.mac != 'UNKNOWN'
+id: ethernet/wol_S4_{interface}
+_summary: Wake on LAN (WOL) test from S4 - {interface}
+_purpose:
+ Check that another system can wake up from S4 the SUT using ethernet port {interface} WOL function.
+_steps:
+ 1. Ensure there is an ethernet cable attached to port {interface}.
+ 2. Press Enter to hibernate the system.
+ 3. From another computer on the same network run the following command:
+ $ wakeonlan {mac}
+ If wakeonlan tool is not installed run:
+ $ sudo apt install wakeonlan
+_verification:
+ Did the SUT wake up from S4?
+plugin: user-interact-verify
+requires:
+ sleep.disk == 'supported'
+command: systemctl hibernate
+user: root
+category_id: com.canonical.plainbox::ethernet
+estimated_duration: 120
+flags: preserve-locale
+
+unit: template
+template-resource: device
+template-filter: device.category == 'NETWORK' and device.mac != 'UNKNOWN' and device.interface != 'UNKNOWN'
+id: ethernet/wol_S3_{interface}
+_summary: Wake on LAN (WOL) test from S3 - {interface}
+_purpose:
+ Check that another system can wake up from S3 the SUT using ethernet port {interface} WOL function.
+_steps:
+ 1. Ensure there is an ethernet cable attached to port {interface}.
+ 2. Press Enter to suspend the system.
+ 3. From another computer on the same network run the following command:
+ $ wakeonlan {mac}
+ If wakeonlan tool is not installed run:
+ $ sudo apt install wakeonlan
+_verification:
+ Did the SUT wake up from S3?
+plugin: user-interact-verify
+requires:
+ sleep.mem == 'supported'
+command: systemctl suspend
+user: root
+category_id: com.canonical.plainbox::ethernet
+estimated_duration: 120
+flags: preserve-locale
+
+unit: template
+template-resource: device
+template-filter: device.category == 'NETWORK' and device.interface != 'UNKNOWN'
+template-engine: jinja2
+id: ethernet/hotplug-{{ interface }}-check-disconnected
+_summary: Ensure ethernet port {{ interface }} is physically disconnected
+_purpose:
+ Check that ethernet port {{ interface }} is detected as being in the correct state
+ to begin a hotplug connection test.
+_steps:
+ 1. Ensure there is no ethernet cable attached to port {{ interface }}.
+ 2. Begin test.
+plugin: user-interact
+command:
+ if [ $(cat /sys/class/net/{{ interface }}/carrier) -ne 0 ]; then
+ # carrier indicating cable present
+ exit 1
+ fi
+ exit 0
+category_id: com.canonical.plainbox::ethernet
+estimated_duration: 1.0
+flags: preserve-locale
+after:
+ {%- if __index__ > 1 %}ethernet/hotplug-{{ __index__ - 1 }}-end-cycle{%- endif %}
+
+unit: template
+template-resource: device
+template-filter: device.category == 'NETWORK' and device.interface != 'UNKNOWN'
+id: ethernet/hotplug-{interface}-connect
+_summary: Ethernet port {interface} hotplug detection test
+_purpose:
+ Check ethernet port {interface} connects when cable inserted. Assumes an IP
+ address will be assigned by DHCP. Connection asserted by pinging the network
+ defined gateway.
+_steps:
+ 1. Begin the test.
+ 2. Insert the ethernet cable in to ethernet port {interface}.
+ 3. This test will timeout and fail if the insertion and connection
+ establishment has not been detected (10 second timeout for each check).
+plugin: user-interact
+command:
+ LOOP=0
+ CABLE_DETECT=0
+ while [ $LOOP -lt 10 ] && [ $CABLE_DETECT -eq 0 ]
+ do
+ sleep 1
+ CABLE_DETECT=$(cat /sys/class/net/{interface}/carrier)
+ LOOP=$((LOOP=LOOP+1))
+ done
+ if [ $CABLE_DETECT -eq 0 ]; then
+ echo "Didn't detect a cable insertion"
+ exit 1
+ fi
+ echo "Detected a cable insertion"
+ LOOP=0
+ OPSTATE="unknown"
+ while [ $LOOP -lt 10 ] && [ "$OPSTATE" != "up" ]
+ do
+ sleep 1
+ OPSTATE=$(cat /sys/class/net/{interface}/operstate)
+ LOOP=$((LOOP=LOOP+1))
+ done
+ if [ "$OPSTATE" != "up" ]; then
+ echo "Interface did not up"
+ exit 1
+ fi
+ echo "Interface up"
+ gateway_ping_test -v --interface {interface}
+ PING_TEST=$?
+ if [ $PING_TEST -ne 0 ]; then
+ echo "Ping test failed"
+ exit 1
+ fi
+ exit 0
+category_id: com.canonical.plainbox::ethernet
+estimated_duration: 60.0
+depends: ethernet/hotplug-{interface}-check-disconnected
+
+unit: template
+template-resource: device
+template-filter: device.category == 'NETWORK' and device.interface != 'UNKNOWN'
+id: ethernet/hotplug-{interface}-disconnect
+_summary: Ethernet port {interface} hotplug disconnect step
+_purpose:
+ Check that when cable removed from ethernet port {interface} the system
+ detects this correctly.
+_steps:
+ 1. Depends on previous hotplug connection test passing. We will now test
+ cable disconnection.
+ 2. Begin the test.
+ 3. Remove the ethernet cable from ethernet port {interface}.
+ 4. This test will timeout and fail if the removal has not been detected and
+ interface marked as down (10 second timeout for each check).
+plugin: user-interact
+command:
+ LOOP=0
+ CABLE_DETECT=1
+ while [ $LOOP -lt 10 ] && [ $CABLE_DETECT -ne 0 ]
+ do
+ sleep 1
+ CABLE_DETECT=$(cat /sys/class/net/{interface}/carrier)
+ LOOP=$((LOOP=LOOP+1))
+ done
+ if [ $CABLE_DETECT -ne 0 ]; then
+ echo "Didn't detect a cable removal"
+ exit 1
+ fi
+ echo "Detected a cable removal"
+ LOOP=0
+ OPSTATE="up"
+ while [ $LOOP -lt 10 ] && [ "$OPSTATE" == "up" ]
+ do
+ sleep 1
+ OPSTATE=$(cat /sys/class/net/{interface}/operstate)
+ LOOP=$((LOOP=LOOP+1))
+ done
+ if [ "$OPSTATE" == "up" ]; then
+ echo "Interface did not go down"
+ exit 1
+ fi
+ echo "Interface went down"
+ exit 0
+category_id: com.canonical.plainbox::ethernet
+estimated_duration: 20.0
+depends: ethernet/hotplug-{interface}-connect
+
+unit: template
+template-resource: device
+template-filter: device.category == 'NETWORK' and device.interface != 'UNKNOWN'
+id: ethernet/hotplug-{__index__}-end-cycle
+after: ethernet/hotplug-{interface}-disconnect
+command: true
+flags: simple
+
+unit: template
+template-resource: device
+template-filter: device.category == 'NETWORK' and device.interface != 'UNKNOWN'
+template-unit: job
+id: ethernet/iperf3_{interface}
+plugin: shell
+_summary: Iperf3 stress testing for {interface}
+category_id: com.canonical.plainbox::ethernet
+estimated_duration: 740.0
+user: root
+environ:
+ TEST_TARGET_IPERF
+ LD_LIBRARY_PATH
+command: checkbox-support-network test -i {interface} -t iperf --iperf3 --scan-timeout 3600 --fail-threshold 80 --cpu-load-fail-threshold 90 --runtime 90 --num_runs 4
+_description:
+ This test uses iperf3 to ensure network devices pass data at an acceptable
+ minimum percentage of advertized speed.
+
+unit: template
+template-resource: device
+template-filter: device.category == 'NETWORK' and device.interface != 'UNKNOWN'
+template-engine: jinja2
+template-unit: job
+id: ethernet/check-{{ interface }}-static-configuration
+_summary: Check that {{ interface }} has a static configuration
+_description:
+ This job is intended to be used on particular devices where an interface has
+ been identified for configuration with a static IP address. As such, this is
+ not suitable for inclusion in the ethernet nested test plans, but should be
+ specifically included where required.
+category_id: com.canonical.plainbox::ethernet
+plugin: shell
+estimated_duration: 2s
+command: check_static {{ interface }}
+requires:
+ snap.name == 'network-manager'
+ connections.slot == 'network-manager:service' and connections.plug == '{{ __system_env__["SNAP_NAME"] }}:network-manager'
+
+plugin: shell
+category_id: com.canonical.plainbox::ethernet
+id: after-suspend-ethernet/network_resume_time_auto
+depends: suspend/suspend_advanced_auto
+estimated_duration: 1.2
+requires:
+ device.category == 'NETWORK'
+command: network_reconnect_resume_test -t 10 -d wired
+_summary: Network reconnect resume test (wired)
+_description:
+ Checks the length of time it takes to reconnect an existing wired connection
+ after a suspend/resume cycle.
diff --git a/units/graphics/jobs.pxu b/units/graphics/jobs.pxu
index 08bc7b3..88efe86 100644
--- a/units/graphics/jobs.pxu
+++ b/units/graphics/jobs.pxu
@@ -8,7 +8,7 @@ command:
source graphics_env {driver} {index}
graphics_driver
estimated_duration: 0.5
-_description: Parses Xorg.0.Log and discovers the running X driver and version for the {vendor} {product} graphics card
+_description: Parses Xorg.0.log and discovers the running X driver and version for the {vendor} {product} graphics card
_summary: Test X driver/version for {vendor} {product}
plugin: shell
@@ -205,7 +205,7 @@ _description:
plugin: shell
category_id: com.canonical.plainbox::graphics
id: graphics/VESA_drivers_not_in_use
-command: cat /var/log/Xorg.0.log | perl -e '$a=0;while(<>){$a++ if /Loading.*vesa_drv\.so/;$a-- if /Unloading.*vesa/&&$a}exit 1 if $a'
+command: cat /var/log/Xorg.0.log ~/.local/share/xorg/Xorg.0.log 2>&1 | perl -e '$a=0;while(<>){$a++ if /Loading.*vesa_drv\.so/;$a-- if /Unloading.*vesa/&&$a}exit 1 if $a'
estimated_duration: 0.011
_description: Check that VESA drivers are not in use
_summary: Test that VESA drivers are not in use
diff --git a/units/mediacard/jobs.pxu b/units/mediacard/jobs.pxu
index ab00396..7bbfded 100644
--- a/units/mediacard/jobs.pxu
+++ b/units/mediacard/jobs.pxu
@@ -1,13 +1,14 @@
plugin: user-interact
+template-engine: jinja2
category_id: com.canonical.plainbox::mediacard
id: mediacard/mmc-insert
estimated_duration: 30.0
command:
- if [[ -v SNAP ]]; then
+ {%- if __on_ubuntucore__ %}
timeout 20s bash -c 'grep -m 1 -oP "\Kadd.*?mmc.*?\s" <( exec journalctl -u snap.udisks2.udisksd -f -q -S -1s ); kill $!'
- else
+ {%- else %}
removable_storage_watcher --memorycard insert sdio usb scsi
- fi
+ {% endif -%}
imports: from com.canonical.plainbox import manifest
requires:
package.name == 'udisks2' or snap.name == 'udisks2'
@@ -40,16 +41,17 @@ _description:
test is run. It tests 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 [[ -v SNAP ]]; then
+ {%- if __on_ubuntucore__ %}
timeout 20s bash -c 'grep -m 1 -oP "\Kremove.*?mmc.*?\s" <( exec journalctl -u snap.udisks2.udisksd -f -q -S -1s ); kill $!'
- else
+ {%- else %}
removable_storage_watcher --memorycard remove sdio usb scsi
- fi
+ {% endif -%}
user: root
_description:
PURPOSE:
@@ -63,20 +65,22 @@ _description:
automatically selected result.
plugin: user-interact
+template-engine: jinja2
category_id: com.canonical.plainbox::mediacard
id: mediacard/sd-insert
estimated_duration: 30.0
command:
- if [[ -v SNAP ]]; then
+ {%- if __on_ubuntucore__ %}
timeout 20s bash -c 'grep -m 1 -oP "\Kadd.*?mmc.*?\s" <( exec journalctl -u snap.udisks2.udisksd -f -q -S -1s ); kill $!'
- else
+ {%- else %}
removable_storage_watcher --memorycard insert sdio usb scsi
- fi
+ {% endif -%}
imports: from com.canonical.plainbox import manifest
requires:
package.name == 'udisks2' or snap.name == 'udisks2'
manifest.has_card_reader == 'True'
user: root
+_summary: Test that insertion of an SD card is detected (udisks2)
_description:
PURPOSE:
This test will check that the systems media card reader can
@@ -99,22 +103,25 @@ flags: preserve-cwd
command: removable_storage_test -s 268400000 --memorycard sdio usb scsi
requires:
package.name == 'udisks2' or (snap.name == 'core' and int(snap.revision) >= 1804)
+_summary: Test reading & writing to a SD Card (udisks2)
_description:
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 [[ -v SNAP ]]; then
+ {%- if __on_ubuntucore__ %}
timeout 20s bash -c 'grep -m 1 -oP "\Kremove.*?mmc.*?\s" <( exec journalctl -u snap.udisks2.udisksd -f -q -S -1s ); kill $!'
- else
+ {%- else %}
removable_storage_watcher --memorycard remove sdio usb scsi
- fi
+ {% endif -%}
user: root
+_summary: Test that removal of an SD card is detected
_description:
PURPOSE:
This test will check that the system correctly detects
@@ -138,26 +145,29 @@ requires:
package.name == 'udisks2' or snap.name == 'udisks2'
package.name == 'udisks2' or (snap.name == 'core' and int(snap.revision) >= 1804)
manifest.has_card_reader == 'True'
+_summary: Automated test of SD Card reading & writing (udisk2)
_description:
This is a fully automated version of mediacard/sd-automated and assumes that the
system under test has a memory card device plugged in prior to checkbox execution.
It is intended for SRU automated testing.
plugin: user-interact
+template-engine: jinja2
category_id: com.canonical.plainbox::mediacard
id: mediacard/sdhc-insert
estimated_duration: 30.0
command:
- if [[ -v SNAP ]]; then
+ {%- if __on_ubuntucore__ %}
timeout 20s bash -c 'grep -m 1 -oP "\Kadd.*?mmc.*?\s" <( exec journalctl -u snap.udisks2.udisksd -f -q -S -1s ); kill $!'
- else
+ {%- else %}
removable_storage_watcher --memorycard insert sdio usb scsi
- fi
+ {% endif -%}
imports: from com.canonical.plainbox import manifest
requires:
package.name == 'udisks2' or snap.name == 'udisks2'
manifest.has_card_reader == 'True'
user: root
+_summary: Test that insertion of an SDHC card is detected (udisks2)
_description:
PURPOSE:
This test will check that the systems media card reader can
@@ -181,22 +191,25 @@ flags: preserve-cwd
command: removable_storage_test -s 268400000 --memorycard sdio usb scsi
requires:
package.name == 'udisks2' or (snap.name == 'core' and int(snap.revision) >= 1804)
+_summary: Test that insertion of an SDHC card is detected (udisks2)
_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
estimated_duration: 30.0
depends: mediacard/sdhc-insert
command:
- if [[ -v SNAP ]]; then
+ {%- if __on_ubuntucore__ %}
timeout 20s bash -c 'grep -m 1 -oP "\Kremove.*?mmc.*?\s" <( exec journalctl -u snap.udisks2.udisksd -f -q -S -1s ); kill $!'
- else
+ {%- else %}
removable_storage_watcher --memorycard remove sdio usb scsi
- fi
+ {% endif -%}
user: root
+_summary: Test that removal of an SDHC card is detected
_description:
PURPOSE:
This test will check that the system correctly detects
@@ -209,15 +222,16 @@ _description:
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 [[ -v SNAP ]]; then
+ {%- if __on_ubuntucore__ %}
timeout 20s bash -c 'grep -m 1 -oP "\Kadd.*?mmc.*?\s" <( exec journalctl -u snap.udisks2.udisksd -f -q -S -1s ); kill $!'
- else
+ {%- else %}
removable_storage_watcher --memorycard insert sdio usb scsi
- fi
+ {% endif -%}
imports: from com.canonical.plainbox import manifest
requires:
package.name == 'udisks2' or snap.name == 'udisks2'
@@ -249,16 +263,17 @@ _description:
test is run. It tests reading and writing to the CF card.
plugin: user-interact
+template-engine: jinja2
category_id: com.canonical.plainbox::mediacard
id: mediacard/cf-remove
depends: mediacard/cf-storage
estimated_duration: 30.0
command:
- if [[ -v SNAP ]]; then
+ {%- if __on_ubuntucore__ %}
timeout 20s bash -c 'grep -m 1 -oP "\Kremove.*?mmc.*?\s" <( exec journalctl -u snap.udisks2.udisksd -f -q -S -1s ); kill $!'
- else
+ {%- else %}
removable_storage_watcher --memorycard remove sdio usb scsi
- fi
+ {% endif -%}
user: root
_description:
PURPOSE:
@@ -272,20 +287,22 @@ _description:
automatically selected result.
plugin: user-interact
+template-engine: jinja2
category_id: com.canonical.plainbox::mediacard
id: mediacard/sdxc-insert
estimated_duration: 30.0
command:
- if [[ -v SNAP ]]; then
+ {%- if __on_ubuntucore__ %}
timeout 20s bash -c 'grep -m 1 -oP "\Kadd.*?mmc.*?\s" <( exec journalctl -u snap.udisks2.udisksd -f -q -S -1s ); kill $!'
- else
+ {%- else %}
removable_storage_watcher --memorycard insert sdio usb scsi
- fi
+ {% endif -%}
imports: from com.canonical.plainbox import manifest
requires:
package.name == 'udisks2' or snap.name == 'udisks2'
manifest.has_card_reader == 'True'
user: root
+_summary: Test that insertion of an SDXC card is detected (udisks2)
_description:
PURPOSE:
This test will check that the systems media card reader can
@@ -307,22 +324,25 @@ user: root
command: removable_storage_test -s 268400000 --memorycard sdio usb scsi
requires:
package.name == 'udisks2' or (snap.name == 'core' and int(snap.revision) >= 1804)
+_summary: Test reading & writing to a SDXC Card (udisks2)
_description:
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 [[ -v SNAP ]]; then
+ {%- if __on_ubuntucore__ %}
timeout 20s bash -c 'grep -m 1 -oP "\Kremove.*?mmc.*?\s" <( exec journalctl -u snap.udisks2.udisksd -f -q -S -1s ); kill $!'
- else
+ {%- else %}
removable_storage_watcher --memorycard remove sdio usb scsi
- fi
+ {% endif -%}
user: root
+_summary: Test that removal of an SDXC card is detected
_description:
PURPOSE:
This test will check that the system correctly detects
@@ -335,15 +355,16 @@ _description:
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 [[ -v SNAP ]]; then
+ {%- if __on_ubuntucore__ %}
timeout 20s bash -c 'grep -m 1 -oP "\Kadd.*?mmc.*?\s" <( exec journalctl -u snap.udisks2.udisksd -f -q -S -1s ); kill $!'
- else
+ {%- else %}
removable_storage_watcher --memorycard insert sdio usb scsi
- fi
+ {% endif -%}
imports: from com.canonical.plainbox import manifest
requires:
package.name == 'udisks2' or snap.name == 'udisks2'
@@ -375,16 +396,17 @@ _description:
test is run. It tests reading and writing to the MS card.
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 [[ -v SNAP ]]; then
+ {%- if __on_ubuntucore__ %}
timeout 20s bash -c 'grep -m 1 -oP "\Kremove.*?mmc.*?\s" <( exec journalctl -u snap.udisks2.udisksd -f -q -S -1s ); kill $!'
- else
+ {%- else %}
removable_storage_watcher --memorycard remove sdio usb scsi
- fi
+ {% endif -%}
user: root
_description:
PURPOSE:
@@ -398,15 +420,16 @@ _description:
automatically selected result.
plugin: user-interact
+template-engine: jinja2
category_id: com.canonical.plainbox::mediacard
id: mediacard/msp-insert
estimated_duration: 30.0
command:
- if [[ -v SNAP ]]; then
+ {%- if __on_ubuntucore__ %}
timeout 20s bash -c 'grep -m 1 -oP "\Kadd.*?mmc.*?\s" <( exec journalctl -u snap.udisks2.udisksd -f -q -S -1s ); kill $!'
- else
+ {%- else %}
removable_storage_watcher --memorycard insert sdio usb scsi
- fi
+ {% endif -%}
user: root
imports: from com.canonical.plainbox import manifest
requires:
@@ -438,16 +461,17 @@ _description:
test is run. It tests reading and writing to the MSP card.
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 [[ -v SNAP ]]; then
+ {%- if __on_ubuntucore__ %}
timeout 20s bash -c 'grep -m 1 -oP "\Kremove.*?mmc.*?\s" <( exec journalctl -u snap.udisks2.udisksd -f -q -S -1s ); kill $!'
- else
+ {%- else %}
removable_storage_watcher --memorycard remove sdio usb scsi
- fi
+ {% endif -%}
user: root
_description:
PURPOSE:
@@ -461,15 +485,16 @@ _description:
automatically selected result.
plugin: user-interact
+template-engine: jinja2
category_id: com.canonical.plainbox::mediacard
id: mediacard/xd-insert
estimated_duration: 30.0
command:
- if [[ -v SNAP ]]; then
+ {%- if __on_ubuntucore__ %}
timeout 20s bash -c 'grep -m 1 -oP "\Kadd.*?mmc.*?\s" <( exec journalctl -u snap.udisks2.udisksd -f -q -S -1s ); kill $!'
- else
+ {%- else %}
removable_storage_watcher --memorycard insert sdio usb scsi
- fi
+ {% endif -%}
imports: from com.canonical.plainbox import manifest
requires:
package.name == 'udisks2' or snap.name == 'udisks2'
@@ -501,16 +526,17 @@ _description:
test is run. It tests reading and writing to the xD card.
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 [[ -v SNAP ]]; then
+ {%- if __on_ubuntucore__ %}
timeout 20s bash -c 'grep -m 1 -oP "\Kremove.*?mmc.*?\s" <( exec journalctl -u snap.udisks2.udisksd -f -q -S -1s ); kill $!'
- else
+ {%- else %}
removable_storage_watcher --memorycard remove sdio usb scsi
- fi
+ {% endif -%}
user: root
_description:
PURPOSE:
diff --git a/units/miscellanea/jobs.pxu b/units/miscellanea/jobs.pxu
index 59e41c2..7ddcc1b 100644
--- a/units/miscellanea/jobs.pxu
+++ b/units/miscellanea/jobs.pxu
@@ -81,7 +81,7 @@ id: miscellanea/fwupdate
estimated_duration: 1.0
depends: miscellanea/efi_boot_mode
requires:
- cpuinfo.platform in ("i386", "x86_64", "aarch64", "armhf")
+ cpuinfo.platform in ("i386", "x86_64", "aarch64", "armv7l")
package.name == 'fwupdate' or executable.name == 'fwupdate'
_description:
Determine if EFI firmware supports update from OS.
@@ -148,6 +148,22 @@ command: boot_mode_test secureboot
plugin: shell
category_id: com.canonical.plainbox::miscellanea
estimated_duration: 0.5
+unit: template
+template-resource: model_assertion
+template-unit: job
+requires:
+ executable.name == 'dumpimage'
+ executable.name == 'mokutil'
+id: miscellanea/secure_boot_mode_{gadget}
+_summary: Test that {gadget} Ubuntu Core system booted with Secure Boot active
+_description:
+ Test to verify that the system booted with Secure Boot active.
+command:
+ boot_mode_test_snappy.py {gadget} {kernel}
+
+plugin: shell
+category_id: com.canonical.plainbox::miscellanea
+estimated_duration: 0.5
user: root
id: miscellanea/efi_pxeboot
requires:
@@ -161,6 +177,16 @@ command: efi-pxeboot
plugin: shell
category_id: com.canonical.plainbox::miscellanea
+estimated_duration: 0.5
+id: miscellanea/check_prerelease
+_summary: Test that system is not a pre-release version
+_description:
+ Test to verify that the system uses production, rather
+ than pre-release, versions of the kernel and the OS.
+command: check-prerelease
+
+plugin: shell
+category_id: com.canonical.plainbox::miscellanea
id: miscellanea/bmc_info
requires:
package.name == 'ipmitool' or executable.name == 'ipmitool'
@@ -196,7 +222,7 @@ requires:
dmi_present.state == 'supported'
estimated_duration: 0.5
user: root
-command: dmitest --test_versions server
+command: dmitest server
_description:
Sanity check of DMI system identification data (for servers)
_summary:
diff --git a/units/monitor/jobs.pxu b/units/monitor/jobs.pxu
index 6c1ac58..255d74c 100644
--- a/units/monitor/jobs.pxu
+++ b/units/monitor/jobs.pxu
@@ -3,6 +3,7 @@ template-resource: graphics_card
template-filter: graphics_card.prime_gpu_offload == 'Off'
id: monitor/{index}_vga_{product_slug}
requires: display.vga == 'supported' or display.dp == 'supported'
+flags: also-after-suspend-manual
plugin: manual
category_id: com.canonical.plainbox::monitor
_purpose:
@@ -18,6 +19,7 @@ template-resource: graphics_card
template-filter: graphics_card.prime_gpu_offload == 'Off'
id: monitor/{index}_dvi_{product_slug}
requires: display.dvi == 'supported'
+flags: also-after-suspend-manual
plugin: manual
category_id: com.canonical.plainbox::monitor
_purpose:
@@ -33,6 +35,7 @@ template-resource: graphics_card
template-filter: graphics_card.prime_gpu_offload == 'Off'
id: monitor/{index}_displayport_{product_slug}
requires: display.dp == 'supported'
+flags: also-after-suspend-manual
plugin: manual
category_id: com.canonical.plainbox::monitor
_purpose:
@@ -48,6 +51,7 @@ template-resource: graphics_card
template-filter: graphics_card.prime_gpu_offload == 'Off'
id: monitor/{index}_hdmi_{product_slug}
requires: display.hdmi == 'supported'
+flags: also-after-suspend-manual
plugin: manual
category_id: com.canonical.plainbox::monitor
_purpose:
@@ -93,6 +97,7 @@ template-resource: graphics_card
template-filter: graphics_card.prime_gpu_offload == 'Off'
id: monitor/{index}_multi-head_{product_slug}
requires: dmi.product in ['Desktop','Low Profile Desktop','Tower','Mini Tower', 'Space-saving']
+flags: also-after-suspend-manual
plugin: manual
category_id: com.canonical.plainbox::monitor
_purpose:
@@ -109,6 +114,7 @@ _verification:
unit: template
template-resource: graphics_card
template-filter: graphics_card.prime_gpu_offload == 'Off'
+flags: also-after-suspend-manual
id: monitor/{index}_powersaving_{product_slug}
plugin: user-interact-verify
category_id: com.canonical.plainbox::monitor
@@ -146,6 +152,7 @@ template-filter: graphics_card.prime_gpu_offload == 'Off'
id: monitor/{index}_thunderbolt_{product_slug}
imports: from com.canonical.plainbox import manifest
requires: manifest.has_thunderbolt == 'True'
+flags: also-after-suspend-manual
estimated_duration: 15.0
plugin: manual
category_id: com.canonical.plainbox::monitor
@@ -167,6 +174,7 @@ template-filter: graphics_card.prime_gpu_offload == 'Off'
id: monitor/{index}_thunderbolt3_{product_slug}
imports: from com.canonical.plainbox import manifest
requires: manifest.has_thunderbolt3 == 'True'
+flags: also-after-suspend-manual
estimated_duration: 15.0
plugin: manual
category_id: com.canonical.plainbox::monitor
@@ -188,6 +196,7 @@ id: monitor/{index}_type-c_displayport_{product_slug}
template-filter: graphics_card.prime_gpu_offload == 'Off'
imports: from com.canonical.plainbox import manifest
requires: manifest.has_usb_type_c == 'True'
+flags: also-after-suspend-manual
estimated_duration: 15.0
plugin: manual
category_id: com.canonical.plainbox::monitor
@@ -202,3 +211,41 @@ _steps:
_verification:
Was the desktop displayed correctly with {vendor} {product} on the screen
connected using a "USB Type-C to DisplayPort" adapter in every mode?
+
+id: monitor/type-c-to-hdmi
+imports: from com.canonical.plainbox import manifest
+requires: manifest.has_usb_type_c == 'True'
+flags: also-after-suspend-manual
+estimated_duration: 15.0
+plugin: manual
+category_id: com.canonical.plainbox::monitor
+_summary: Display connected via HDMI using an USB Type-C port
+_purpose:
+ This test will check the connection of a screen using a "USB Type-C to HDMI" adapter
+_steps:
+ 1. Connect a display (if not already connected) to the USB Type-C port on
+ your system using a "USB Type-C to HDMI" adapter
+ 2. Switch display modes between in your Display Settings, check if it can be
+ set to mirrored, extended, displayed on external or onboard only
+_verification:
+ Was the desktop displayed correctly with on the screen connected using a
+ "USB Type-C to HDMI" adapter in every mode?
+
+id: monitor/type-c-to-vga
+imports: from com.canonical.plainbox import manifest
+requires: manifest.has_usb_type_c == 'True'
+flags: also-after-suspend-manual
+estimated_duration: 15.0
+plugin: manual
+category_id: com.canonical.plainbox::monitor
+_summary: Display connected via VGA using an USB Type-C port
+_purpose:
+ This test will check the connection of a screen using a "USB Type-C to VGA" adapter
+_steps:
+ 1. Connect a display (if not already connected) to the USB Type-C port on
+ your system using a "USB Type-C to VGA" adapter
+ 2. Switch display modes between in your Display Settings, check if it can be
+ set to mirrored, extended, displayed on external or onboard only
+_verification:
+ Was the desktop displayed correctly with on the screen connected using a
+ "USB Type-C to VGA" adapter in every mode?
diff --git a/units/monitor/test-plan.pxu b/units/monitor/test-plan.pxu
index 344b304..ca90299 100644
--- a/units/monitor/test-plan.pxu
+++ b/units/monitor/test-plan.pxu
@@ -16,23 +16,25 @@ _name: Monitor tests (integrated GPU) (Manual)
_description:
Monitor tests (integrated GPU) (Manual)
include:
- monitor/1_powersaving_.* certification-status=blocker
- monitor/1_dim_brightness_.* certification-status=blocker
- monitor/1_displayport_.* certification-status=blocker
- monitor/1_type-c_displayport_.* certification-status=blocker
- audio/1_playback_displayport_.* certification-status=blocker
- audio/1_playback_type-c_displayport_.* certification-status=blocker
- monitor/1_dvi_.* certification-status=blocker
- monitor/1_hdmi_.* certification-status=blocker
- audio/1_playback_hdmi_.* certification-status=blocker
- monitor/1_thunderbolt_.* certification-status=blocker
- monitor/1_thunderbolt3_.* certification-status=non-blocker
- audio/1_playback_thunderbolt_.* certification-status=blocker
- audio/1_playback_thunderbolt3_.* certification-status=non-blocker
- thunderbolt/daisy-chain certification-status=blocker
- thunderbolt3/daisy-chain certification-status=non-blocker
- monitor/1_vga_.* certification-status=blocker
- monitor/1_multi-head_.* certification-status=blocker
+ (after-suspend-manual-)?monitor/1_powersaving_.* certification-status=blocker
+ monitor/1_dim_brightness_.* certification-status=blocker
+ (after-suspend-manual-)?monitor/1_displayport_.* certification-status=blocker
+ (after-suspend-manual-)?monitor/1_type-c_displayport_.* certification-status=blocker
+ (after-suspend-manual-)?monitor/type-c-to-hdmi certification-status=blocker
+ (after-suspend-manual-)?monitor/type-c-to-vga certification-status=blocker
+ (after-suspend-manual-)?audio/1_playback_displayport_.* certification-status=blocker
+ (after-suspend-manual-)?audio/1_playback_type-c_displayport_.* certification-status=blocker
+ (after-suspend-manual-)?monitor/1_dvi_.* certification-status=blocker
+ (after-suspend-manual-)?monitor/1_hdmi_.* certification-status=blocker
+ (after-suspend-manual-)?audio/1_playback_hdmi_.* certification-status=blocker
+ (after-suspend-manual-)?monitor/1_thunderbolt_.* certification-status=blocker
+ (after-suspend-manual-)?monitor/1_thunderbolt3_.* certification-status=non-blocker
+ (after-suspend-manual-)?audio/1_playback_thunderbolt_.* certification-status=blocker
+ (after-suspend-manual-)?audio/1_playback_thunderbolt3_.* certification-status=non-blocker
+ (after-suspend-manual-)?thunderbolt/daisy-chain certification-status=blocker
+ (after-suspend-manual-)?thunderbolt3/daisy-chain certification-status=non-blocker
+ (after-suspend-manual-)?monitor/1_vga_.* certification-status=blocker
+ (after-suspend-manual-)?monitor/1_multi-head_.* certification-status=blocker
bootstrap_include:
graphics_card
@@ -97,20 +99,22 @@ unit: test plan
_name: Monitor tests (integrated GPU, certification blockers only)
_description: Monitor tests (integrated GPU, certification blockers only)
include:
- monitor/1_powersaving_.* certification-status=blocker
- monitor/1_dim_brightness_.* certification-status=blocker
- monitor/1_displayport_.* certification-status=blocker
- monitor/1_type-c_displayport_.* certification-status=blocker
- audio/1_playback_displayport_.* certification-status=blocker
- audio/1_playback_type-c_displayport_.* certification-status=blocker
- monitor/1_dvi_.* certification-status=blocker
- monitor/1_hdmi_.* certification-status=blocker
- audio/1_playback_hdmi_.* certification-status=blocker
- monitor/1_thunderbolt_.* certification-status=blocker
- audio/1_playback_thunderbolt_.* certification-status=blocker
- thunderbolt/daisy-chain certification-status=blocker
- monitor/1_vga_.* certification-status=blocker
- monitor/1_multi-head_.* certification-status=blocker
+ (after-suspend-manual-)?monitor/1_powersaving_.* certification-status=blocker
+ monitor/1_dim_brightness_.* certification-status=blocker
+ (after-suspend-manual-)?monitor/1_displayport_.* certification-status=blocker
+ (after-suspend-manual-)?monitor/1_type-c_displayport_.* certification-status=blocker
+ (after-suspend-manual-)?monitor/type-c-to-hdmi certification-status=blocker
+ (after-suspend-manual-)?monitor/type-c-to-vga certification-status=blocker
+ (after-suspend-manual-)?audio/1_playback_displayport_.* certification-status=blocker
+ (after-suspend-manual-)?audio/1_playback_type-c_displayport_.* certification-status=blocker
+ (after-suspend-manual-)?monitor/1_dvi_.* certification-status=blocker
+ (after-suspend-manual-)?monitor/1_hdmi_.* certification-status=blocker
+ (after-suspend-manual-)?audio/1_playback_hdmi_.* certification-status=blocker
+ (after-suspend-manual-)?monitor/1_thunderbolt_.* certification-status=blocker
+ (after-suspend-manual-)?audio/1_playback_thunderbolt_.* certification-status=blocker
+ (after-suspend-manual-)?thunderbolt/daisy-chain certification-status=blocker
+ (after-suspend-manual-)?monitor/1_vga_.* certification-status=blocker
+ (after-suspend-manual-)?monitor/1_multi-head_.* certification-status=blocker
bootstrap_include:
graphics_card
diff --git a/units/networking/test-plan.pxu b/units/networking/test-plan.pxu
index e9e61e2..d6a3ddb 100644
--- a/units/networking/test-plan.pxu
+++ b/units/networking/test-plan.pxu
@@ -13,6 +13,9 @@ _name: Networking tests (manual)
_description: Networking tests (manual)
include:
networking/info_device.* certification-status=blocker
+ ethernet/hotplug-.* certification-status=blocker
+bootstrap_include:
+ device
id: networking-cert-automated
unit: test plan
@@ -32,3 +35,5 @@ include:
networking/gateway_ping certification-status=blocker
networking/info_device.* certification-status=blocker
networking/ntp certification-status=blocker
+bootstrap_include:
+ device
diff --git a/units/power-management/jobs.pxu b/units/power-management/jobs.pxu
index be640c3..9f8f62e 100644
--- a/units/power-management/jobs.pxu
+++ b/units/power-management/jobs.pxu
@@ -36,7 +36,7 @@ id: power-management/poweroff
estimated_duration: 120.0
depends: power-management/fwts_wakealarm
user: root
-environ: PLAINBOX_SESSION_SHARE
+environ: PLAINBOX_SESSION_SHARE PM_TEST_DRY_RUN
requires: executable.name == 'fwts'
command: pm_test --silent --checkbox-respawn-cmd $PLAINBOX_SESSION_SHARE/__respawn_checkbox poweroff --log-level=debug --log-dir=$PLAINBOX_SESSION_SHARE
flags: noreturn
@@ -58,7 +58,7 @@ category_id: com.canonical.plainbox::power-management
id: power-management/reboot
estimated_duration: 120.0
user: root
-environ: PLAINBOX_SESSION_SHARE
+environ: PLAINBOX_SESSION_SHARE PM_TEST_DRY_RUN
requires: executable.name == 'fwts'
command: pm_test --silent --checkbox-respawn-cmd $PLAINBOX_SESSION_SHARE/__respawn_checkbox reboot --log-level=debug --log-dir=$PLAINBOX_SESSION_SHARE
flags: noreturn
diff --git a/units/socketcan/category.pxu b/units/socketcan/category.pxu
new file mode 100644
index 0000000..169d966
--- /dev/null
+++ b/units/socketcan/category.pxu
@@ -0,0 +1,3 @@
+unit: category
+id: socketcan
+_name: SocketCAN interface tests
diff --git a/units/socketcan/jobs.pxu b/units/socketcan/jobs.pxu
new file mode 100644
index 0000000..0bf22a1
--- /dev/null
+++ b/units/socketcan/jobs.pxu
@@ -0,0 +1,166 @@
+
+id: socketcan/modprobe_vcan
+category_id: socketcan
+_summary: Create virtual CAN device
+_description:
+ Add a virtual CAN interface for testing kernel CAN support
+plugin: shell
+user: root
+estimated_duration: 2.0
+command:
+ BASH_XTRACEFD=1
+ set -ex
+ if lsmod | grep -v "vcan" &> /dev/null ; then
+ modprobe vcan
+ fi
+ if ! ip link show vcan0 &> /dev/null ; then
+ ip link add vcan0 type vcan
+ fi
+ ip link set vcan0 up
+
+
+id: socketcan/send_packet_local_sff_virtual
+depends: socketcan/modprobe_vcan
+_summary: Virtual CAN device support test (Raw, Local)
+_description:
+ Test that the kernel supports CAN networking by sending packets to a
+ virtual device using a raw socket, this is only a local test as
+ the broadcast packet is received on the same device
+category_id: socketcan
+plugin: shell
+estimated_duration: 2.0
+command:
+ socketcan_test.py vcan0 111
+
+
+id: socketcan/send_packet_local_eff_virtual
+depends: socketcan/modprobe_vcan
+_summary: Virtual CAN device support test (Raw, Local, EFF)
+_description:
+ Test that the kernel supports CAN networking by sending packets to a
+ virtual device using a raw socket, this is only a local test as
+ the broadcast packet is received on the same device
+category_id: socketcan
+plugin: shell
+estimated_duration: 2.0
+command:
+ socketcan_test.py vcan0 1F334455 --effid
+
+
+id: socketcan/send_packet_local_fd_virtual
+depends: socketcan/modprobe_vcan
+_summary: Virtual CAN device support test (Raw, Local, FD)
+_description:
+ Test that the kernel supports CAN networking by sending packets to a
+ virtual device using a raw socket, this is only a local test as
+ the broadcast packet is received on the same device
+category_id: socketcan
+plugin: shell
+estimated_duration: 2.0
+command:
+ socketcan_test.py vcan0 1A --fdmode
+
+
+unit: template
+template-resource: device
+template-filter: device.category == 'SOCKETCAN'
+id: socketcan/send_packet_local_sff_{interface}
+_summary: CAN device support test {interface} (Raw, Local)
+_description:
+ Test a CAN device by sending packets using a raw socket, this is only a
+ local test as the broadcast packet is received on the same device
+category_id: socketcan
+plugin: shell
+estimated_duration: 2.0
+imports: from com.canonical.plainbox import manifest
+requires: manifest.socket_can_echo_server_running == 'False'
+command:
+ socketcan_test.py {interface} 111
+
+
+unit: template
+template-resource: device
+template-filter: device.category == 'SOCKETCAN'
+id: socketcan/send_packet_local_eff_{interface}
+_summary: CAN device support test {interface} (Raw, Local, EFF)
+_description:
+ Test a CAN device by sending packets using a raw socket, this is only a
+ local test as the broadcast packet is received on the same device
+category_id: socketcan
+plugin: shell
+estimated_duration: 2.0
+imports: from com.canonical.plainbox import manifest
+requires: manifest.socket_can_echo_server_running == 'False'
+command:
+ socketcan_test.py {interface} FA123 --effid
+
+
+unit: template
+template-resource: device
+template-filter: device.category == 'SOCKETCAN'
+id: socketcan/send_packet_local_fd_{interface}
+_summary: CAN device support test {interface} (Raw, Local, FD)
+_description:
+ Test a CAN device by sending packets using a raw socket, this is only a
+ local test as the broadcast packet is received on the same device
+category_id: socketcan
+plugin: shell
+estimated_duration: 2.0
+imports: from com.canonical.plainbox import manifest
+requires: manifest.socket_can_echo_server_running == 'False'
+command:
+ socketcan_test.py {interface} 1B --fdmode
+
+
+unit: template
+template-resource: device
+template-filter: device.category == 'SOCKETCAN'
+id: socketcan/send_packet_remote_sff_{interface}
+_summary: CAN device support test {interface} (Raw, Remote)
+_description:
+ Test a CAN device by sending packets using a raw socket to a remote device.
+ As a prerequisite the remote device should have can-echo-server installed so
+ as to return the predicted packet.
+category_id: socketcan
+plugin: shell
+estimated_duration: 5.0
+imports: from com.canonical.plainbox import manifest
+requires: manifest.socket_can_echo_server_running == 'True'
+command:
+ socketcan_test.py {interface} 111 --remote
+
+
+unit: template
+template-resource: device
+template-filter: device.category == 'SOCKETCAN'
+id: socketcan/send_packet_remote_eff_{interface}
+_summary: CAN device support test {interface} (Raw, Remote, EFF)
+_description:
+ Test a CAN device by sending packets using a raw socket to a remote device.
+ As a prerequisite the remote device should have can-echo-server installed so
+ as to return the predicted packet.
+category_id: socketcan
+plugin: shell
+estimated_duration: 5.0
+imports: from com.canonical.plainbox import manifest
+requires: manifest.socket_can_echo_server_running == 'True'
+command:
+ socketcan_test.py {interface} E407DB --remote --effid
+
+
+unit: template
+template-resource: device
+template-filter: device.category == 'SOCKETCAN'
+id: socketcan/send_packet_remote_fd_{interface}
+_summary: CAN device support test {interface} (Raw, Remote, FD)
+_description:
+ Test a CAN device by sending packets using a raw socket to a remote device.
+ As a prerequisite the remote device should have can-echo-server installed so
+ as to return the predicted packet.
+category_id: socketcan
+plugin: shell
+estimated_duration: 5.0
+imports: from com.canonical.plainbox import manifest
+requires: manifest.socket_can_echo_server_running == 'True'
+command:
+ socketcan_test.py {interface} 19F --remote --fdmode
diff --git a/units/socketcan/manifest.pxu b/units/socketcan/manifest.pxu
new file mode 100644
index 0000000..bb140c4
--- /dev/null
+++ b/units/socketcan/manifest.pxu
@@ -0,0 +1,5 @@
+
+unit: manifest entry
+id: socket_can_echo_server_running
+_name: SocketCAN Echo Server Running
+value-type: bool
diff --git a/units/socketcan/test-plan.pxu b/units/socketcan/test-plan.pxu
new file mode 100644
index 0000000..c4e343e
--- /dev/null
+++ b/units/socketcan/test-plan.pxu
@@ -0,0 +1,28 @@
+
+id: socketcan-auto-remote
+unit: test plan
+_name: SocketCAN Tests (Automated, Remote)
+_description:
+ SocketCAN Tests (Automated, Remote)
+include:
+ socketcan/send_packet_remote_.*
+
+
+id: socketcan-auto-local
+unit: test plan
+_name: SocketCAN Tests, (Automated, Local)
+_description:
+ SocketCAN Tests, (Automated, Local)
+include:
+ socketcan/send_packet_local_.*
+
+
+id: socketcan-full
+unit: test plan
+_name: SocketCAN Tests
+_description:
+ SocketCAN Tests
+include:
+nested_part:
+ socketcan-auto-remote
+ socketcan-auto-local
diff --git a/units/stress/jobs.pxu b/units/stress/jobs.pxu
index 8d25af9..e0c2e0a 100644
--- a/units/stress/jobs.pxu
+++ b/units/stress/jobs.pxu
@@ -76,6 +76,7 @@ requires:
executable.name == 'x-terminal-emulator'
flags: noreturn
user: root
+environ: PM_TEST_DRY_RUN
command:
pm_test reboot --checkbox-respawn-cmd $PLAINBOX_SESSION_SHARE/__respawn_checkbox --fwts --log-level=debug --log-dir=$PLAINBOX_SESSION_SHARE --suspends-before-reboot=30 -r 3 --silent
_description:
@@ -226,7 +227,7 @@ requires: executable.name == 'fwts'
command: pm_test --checkbox-respawn-cmd $PLAINBOX_SESSION_SHARE/__respawn_checkbox -r 100 --silent --log-level=notset reboot --log-dir=$PLAINBOX_SESSION_SHARE
flags: noreturn
user: root
-environ: PLAINBOX_SESSION_SHARE
+environ: PLAINBOX_SESSION_SHARE PM_TEST_DRY_RUN
_description:
Stress reboot system (100 cycles)
@@ -248,7 +249,7 @@ command: pm_test --checkbox-respawn-cmd $PLAINBOX_SESSION_SHARE/__respawn_checkb
flags: noreturn
estimated_duration: 2700
user: root
-environ: PLAINBOX_SESSION_SHARE
+environ: PLAINBOX_SESSION_SHARE PM_TEST_DRY_RUN
_description:
Stress reboot system (30 cycles)
@@ -270,7 +271,7 @@ requires:
command: pm_test --checkbox-respawn-cmd $PLAINBOX_SESSION_SHARE/__respawn_checkbox -r 100 --silent --log-level=notset poweroff --log-dir=$PLAINBOX_SESSION_SHARE
flags: noreturn
user: root
-environ: PLAINBOX_SESSION_SHARE
+environ: PLAINBOX_SESSION_SHARE PM_TEST_DRY_RUN
_description:
Stress poweroff system (100 cycles)
@@ -293,7 +294,7 @@ command: pm_test --checkbox-respawn-cmd $PLAINBOX_SESSION_SHARE/__respawn_checkb
flags: noreturn
estimated_duration: 3600
user: root
-environ: PLAINBOX_SESSION_SHARE
+environ: PLAINBOX_SESSION_SHARE PM_TEST_DRY_RUN
_description:
Stress poweroff system (30 cycles)
diff --git a/units/submission/jobs.pxu b/units/submission/jobs.pxu
index 43defe3..9ee5a55 100644
--- a/units/submission/jobs.pxu
+++ b/units/submission/jobs.pxu
@@ -12,6 +12,7 @@ plugin: attachment
category_id: com.canonical.plainbox::info
command: udevadm info --export-db | python3 -m plainbox dev parse udevadm
_description: Attaches json dumps of udev_resource
+_summary: Attaches json dumps of udev_resource
id: raw_devices_dmi_json
plugin: attachment
diff --git a/units/suspend/suspend.pxu b/units/suspend/suspend.pxu
index 34d1957..1ab5829 100644
--- a/units/suspend/suspend.pxu
+++ b/units/suspend/suspend.pxu
@@ -3,14 +3,14 @@ category_id: com.canonical.plainbox::suspend
id: suspend/network_before_suspend
depends: ethernet/detect
estimated_duration: 1.2
-_description: Record the current network before suspending.
+_summary: Record the current network before suspending.
command: set -o pipefail; gateway_ping_test | tee $PLAINBOX_SESSION_SHARE/network_before_suspend.txt
plugin: shell
category_id: com.canonical.plainbox::suspend
id: suspend/resolution_before_suspend
estimated_duration: 1.2
-_description: Record the current resolution before suspending.
+_summary: Record the current resolution before suspending.
command: xrandr -q |grep '*'| awk '{print $1}' > $PLAINBOX_SESSION_SHARE/resolution_before_suspend.txt
unit: template
@@ -21,7 +21,7 @@ category_id: com.canonical.plainbox::suspend
id: suspend/{index}_resolution_before_suspend_{product_slug}
depends: graphics/{index}_switch_card_{product_slug}
estimated_duration: 1.2
-_description: Record the current resolution before suspending.
+_summary: Record the current resolution before suspending.
command: xrandr -q |grep '*'| awk '{{print $1}}' > $PLAINBOX_SESSION_SHARE/{index}_resolution_before_suspend.txt
plugin: shell
@@ -31,22 +31,21 @@ estimated_duration: 1.0
requires:
device.category == 'AUDIO'
package.name == 'alsa-base'
-_description: Record mixer settings before suspending.
+_summary: Record mixer settings before suspending.
command: audio_settings store --file=$PLAINBOX_SESSION_SHARE/audio_settings_before_suspend
plugin: shell
category_id: com.canonical.plainbox::suspend
id: suspend/cpu_before_suspend
estimated_duration: 1.2
-_description: Verify that all the CPUs are online before suspending
+_summary: Verify that all the CPUs are online before suspending
command: cpuinfo_resource > $PLAINBOX_SESSION_SHARE/cpuinfo_before_suspend
plugin: shell
category_id: com.canonical.plainbox::suspend
id: suspend/memory_before_suspend
estimated_duration: 1.2
-_description:
- Dumps memory info to a file for comparison after suspend test has been run
+_summary: Dumps memory info to a file for comparison after suspend
command: meminfo_resource > $PLAINBOX_SESSION_SHARE/meminfo_before_suspend
unit: template
@@ -61,7 +60,8 @@ requires:
package.name == 'iperf'
user: root
environ: TEST_TARGET_FTP TEST_TARGET_IPERF TEST_USER TEST_PASS
-command: network -i {interface} -t iperf
+command: network test -i {interface} -t iperf
+_summary: Before suspend iperf test ethernet {interface}
_description:
This test executes iperf connection performance/stability against device {__index__} ({interface}) before suspend.
@@ -76,6 +76,7 @@ command:
INTERFACE=`(nmcli -t -f GENERAL -m tabular dev list 2>/dev/null || nmcli -t -f GENERAL -m tabular dev show) |grep gsm |cut -d ":" -f 13`
[ -z $INTERFACE ] && exit 1
network test -i $INTERFACE -t iperf
+_summary: Before suspend iperf test GSM mobilebroadband
_description:
This test executes iperf connection performance/stability against the broadband device found on the system before suspend.
@@ -90,6 +91,7 @@ command:
INTERFACE=`(nmcli -t -f GENERAL -m tabular dev list 2>/dev/null || nmcli -t -f GENERAL -m tabular dev show) |grep cdma |cut -d ":" -f 13`
[ -z $INTERFACE ] && exit 1
network test -i $INTERFACE -t iperf
+_summary: Before suspend iperf test CDMA mobilebroadband
_description:
This test executes iperf connection performance/stability against the broadband device found on the system before suspend.
@@ -99,12 +101,12 @@ id: suspend/bluetooth_obex_send_before_suspend
estimated_duration: 10.0
requires:
package.name == 'bluez'
- package.name == 'obexftp'
+ executable.name == 'obexftp'
device.category == 'BLUETOOTH'
command:
if [ -z "$BTDEVADDR" ]
then
- echo "btdevaddr option not set to device address of Bluetooth target in checkbox.ini"
+ echo "btdevaddr option not set to device address of Bluetooth target in checkbox.conf"
exit 1
fi
if rfkill list bluetooth | grep -q 'Hard blocked: yes'
@@ -118,6 +120,7 @@ command:
sleep 3
fi
set -o pipefail; bluetooth_test $PLAINBOX_PROVIDER_DATA/images/JPEG_Color_Image_Ubuntu.jpg $BTDEVADDR send 2>&1 | ansi_parser
+_summary: Bluetooth OBEX send before suspend
_description:
This is an automated Bluetooth file transfer test. It sends an image to the device specified by the BTDEVADDR environment variable.
@@ -127,12 +130,12 @@ id: suspend/bluetooth_obex_browse_before_suspend
estimated_duration: 10.0
requires:
package.name == 'bluez'
- package.name == 'obexftp'
+ executable.name == 'obexftp'
device.category == 'BLUETOOTH'
command:
if [ -z "$BTDEVADDR" ]
then
- echo "btdevaddr option not set to device address of Bluetooth target in checkbox.ini"
+ echo "btdevaddr option not set to device address of Bluetooth target in checkbox.conf"
exit 1
fi
if rfkill list bluetooth | grep -q 'Hard blocked: yes'
@@ -146,6 +149,7 @@ command:
sleep 3
fi
set -o pipefail; bluetooth_test $PLAINBOX_PROVIDER_DATA/images/JPEG_Color_Image_Ubuntu.jpg $BTDEVADDR browse 2>&1 | ansi_parser
+_summary: Bluetooth OBEX browse before suspend
_description:
This is an automated Bluetooth test. It emulates browsing on a remote device specified by the BTDEVADDR environment variable.
@@ -155,12 +159,12 @@ id: suspend/bluetooth_obex_get_before_suspend
estimated_duration: 20.0
requires:
package.name == 'bluez'
- package.name == 'obexftp'
+ executable.name == 'obexftp'
device.category == 'BLUETOOTH'
command:
if [ -z "$BTDEVADDR" ]
then
- echo "btdevaddr option not set to device address of Bluetooth target in checkbox.ini"
+ echo "btdevaddr option not set to device address of Bluetooth target in checkbox.conf"
exit 1
fi
if rfkill list bluetooth | grep -q 'Hard blocked: yes'
@@ -174,6 +178,7 @@ command:
sleep 3
fi
set -o pipefail; bluetooth_test $PLAINBOX_PROVIDER_DATA/images/JPEG_Color_Image_Ubuntu.jpg $BTDEVADDR get 2>&1 | ansi_parser
+_summary: Bluetooth OBEX get before suspend
_description:
This is an automated Bluetooth test. It receives the given file from a remote host specified by the BTDEVADDR environment variable
@@ -197,6 +202,7 @@ command:
set -o pipefail; sleep_test -p | tee $PLAINBOX_SESSION_SHARE/2_suspend_single_times.log
fi
estimated_duration: 90.0
+_summary: Manual test of suspend function
_description:
PURPOSE:
This test will check suspend and resume
@@ -253,6 +259,7 @@ id: suspend/suspend_advanced_auto
requires:
sleep.mem == 'supported'
rtc.state == 'supported'
+_summary: Automated test of suspend function
_description:
This is the automated version of suspend/suspend_advanced.
user: root
@@ -276,6 +283,7 @@ command:
fi
set -o pipefail; checkbox-support-fwts_test -f none -l $PLAINBOX_SESSION_SHARE/{index}_hybrid_sleep_single -s s3 --s3-hybrid --s3-sleep-delay=30 --s3-device-check --s3-device-check-delay=45 --pm-method=pm-utils | tee $PLAINBOX_SESSION_SHARE/{index}_hybrid_sleep_single_times.log
estimated_duration: 90.0
+_summary: This test will check hybrid sleep and resume
_description:
PURPOSE:
This test will check hybrid sleep and resume
@@ -293,16 +301,14 @@ id: suspend/suspend-single-log-check
depends: suspend/suspend_advanced_auto
estimated_duration: 1.2
command: [ -e $PLAINBOX_SESSION_SHARE/suspend_single.log ] && sleep_test_log_check -v s3 $PLAINBOX_SESSION_SHARE/suspend_single.log
-_description:
- Automated check of the suspend log to look for errors reported by fwts
+_summary: Automated check of the suspend log for errors reported by fwts
plugin: attachment
category_id: com.canonical.plainbox::suspend
id: suspend/suspend-single-log-attach
depends: suspend/suspend_advanced_auto
command: [ -e $PLAINBOX_SESSION_SHARE/suspend_single.log ] && cat $PLAINBOX_SESSION_SHARE/suspend_single.log
-_description:
- Attaches the log from the single suspend/resume test to the results
+_summary: Attaches the log from the single suspend/resume test
unit: template
template-resource: graphics_card
@@ -312,8 +318,7 @@ category_id: com.canonical.plainbox::suspend
id: suspend/{index}_suspend-single-log-attach_{product_slug}
depends: suspend/{index}_suspend_after_switch_to_card_{product_slug}
command: [ -e $PLAINBOX_SESSION_SHARE/{index}_suspend_single.log ] && cat $PLAINBOX_SESSION_SHARE/{index}_suspend_single.log
-_description:
- Attaches the log from the single suspend/resume test to the results
+_summary: Attaches the log from the single suspend/resume test
unit: template
template-resource: graphics_card
@@ -323,8 +328,7 @@ id: suspend/{index}_hybrid-sleep-single-log-check
depends: suspend/{index}_hybrid_sleep_{product_slug}
estimated_duration: 1.2
command: [ -e $PLAINBOX_SESSION_SHARE/{index}_hybrid_sleep_single.log ] && sleep_test_log_check -v s3 $PLAINBOX_SESSION_SHARE/{index}_hybrid_sleep_single.log
-_description:
- Automated check of the hybrid sleep log to look for errors reported by fwts
+_summary: Automated check of the hybrid sleep log for errors reported by fwts
unit: template
template-resource: graphics_card
@@ -333,14 +337,14 @@ category_id: com.canonical.plainbox::suspend
id: suspend/{index}_hybrid-sleep-single-log-attach_{product_slug}
depends: suspend/{index}_hybrid_sleep_{product_slug}
command: [ -e $PLAINBOX_SESSION_SHARE/{index}_hybrid_sleep_single.log ] && cat $PLAINBOX_SESSION_SHARE/{index}_hybrid_sleep_single.log
-_description:
- Attaches the log from the single hybrid sleep/resume test to the results
+_summary: Attaches the log from the single hybrid sleep/resume test
plugin: shell
category_id: com.canonical.plainbox::suspend
id: suspend/suspend-time-check
estimated_duration: 1.2
command: [ -e $PLAINBOX_SESSION_SHARE/suspend_single_times.log ] && sleep_time_check $PLAINBOX_SESSION_SHARE/suspend_single_times.log
+_summary: Ensure time to suspend/resume is under threshold
_description:
Checks the sleep times to ensure that a machine suspends and resumes within a given threshold
@@ -353,6 +357,7 @@ id: suspend/{index}_suspend-time-check_{product_slug}
depends: suspend/{index}_suspend_after_switch_to_card_{product_slug}
estimated_duration: 1.2
command: [ -e $PLAINBOX_SESSION_SHARE/{index}_suspend_single_times.log ] && sleep_time_check $PLAINBOX_SESSION_SHARE/{index}_suspend_single_times.log
+_summary: Ensure time to suspend/resume is under threshold
_description: Checks the sleep times to ensure that a machine suspends and resumes within a given threshold
plugin: user-interact-verify
@@ -615,7 +620,7 @@ requires:
package.name == 'iperf'
user: root
environ: TEST_TARGET_FTP TEST_TARGET_IPERF TEST_USER TEST_PASS
-command: network -i {interface} -t iperf
+command: network test -i {interface} -t iperf
_description:
This test executes iperf connection performance/stability against device {__index__} ({interface}) after suspend.
@@ -631,7 +636,7 @@ requires:
package.name == 'iperf'
user: root
environ: TEST_TARGET_FTP TEST_TARGET_IPERF TEST_USER TEST_PASS
-command: network -i {interface} -t iperf
+command: network test -i {interface} -t iperf
_description:
This test executes iperf connection performance/stability against device {__index__} ({interface}) after suspend.
@@ -936,12 +941,12 @@ depends: suspend/suspend_advanced
estimated_duration: 10.0
requires:
package.name == 'bluez'
- package.name == 'obexftp'
+ executable.name == 'obexftp'
device.category == 'BLUETOOTH'
command:
if [ -z "$BTDEVADDR" ]
then
- echo "btdevaddr option not set to device address of Bluetooth target in checkbox.ini"
+ echo "btdevaddr option not set to device address of Bluetooth target in checkbox.conf"
exit 1
fi
if rfkill list bluetooth | grep -q 'Hard blocked: yes'
@@ -965,12 +970,12 @@ depends: suspend/suspend_advanced_auto
estimated_duration: 10.0
requires:
package.name == 'bluez'
- package.name == 'obexftp'
+ executable.name == 'obexftp'
device.category == 'BLUETOOTH'
command:
if [ -z "$BTDEVADDR" ]
then
- echo "btdevaddr option not set to device address of Bluetooth target in checkbox.ini"
+ echo "btdevaddr option not set to device address of Bluetooth target in checkbox.conf"
exit 1
fi
if rfkill list bluetooth | grep -q 'Hard blocked: yes'
@@ -994,12 +999,12 @@ depends: suspend/suspend_advanced
estimated_duration: 10.0
requires:
package.name == 'bluez'
- package.name == 'obexftp'
+ executable.name == 'obexftp'
device.category == 'BLUETOOTH'
command:
if [ -z "$BTDEVADDR" ]
then
- echo "btdevaddr option not set to device address of Bluetooth target in checkbox.ini"
+ echo "btdevaddr option not set to device address of Bluetooth target in checkbox.conf"
exit 1
fi
if rfkill list bluetooth | grep -q 'Hard blocked: yes'
@@ -1023,12 +1028,12 @@ depends: suspend/suspend_advanced_auto
estimated_duration: 20.0
requires:
package.name == 'bluez'
- package.name == 'obexftp'
+ executable.name == 'obexftp'
device.category == 'BLUETOOTH'
command:
if [ -z "$BTDEVADDR" ]
then
- echo "btdevaddr option not set to device address of Bluetooth target in checkbox.ini"
+ echo "btdevaddr option not set to device address of Bluetooth target in checkbox.conf"
exit 1
fi
if rfkill list bluetooth | grep -q 'Hard blocked: yes'
@@ -1052,12 +1057,12 @@ estimated_duration: 20.0
depends: suspend/suspend_advanced
requires:
package.name == 'bluez'
- package.name == 'obexftp'
+ executable.name == 'obexftp'
device.category == 'BLUETOOTH'
command:
if [ -z "$BTDEVADDR" ]
then
- echo "btdevaddr option not set to device address of Bluetooth target in checkbox.ini"
+ echo "btdevaddr option not set to device address of Bluetooth target in checkbox.conf"
exit 1
fi
if rfkill list bluetooth | grep -q 'Hard blocked: yes'
@@ -1081,12 +1086,12 @@ depends: suspend/suspend_advanced_auto
estimated_duration: 20.0
requires:
package.name == 'bluez'
- package.name == 'obexftp'
+ executable.name == 'obexftp'
device.category == 'BLUETOOTH'
command:
if [ -z "$BTDEVADDR" ]
then
- echo "btdevaddr option not set to device address of Bluetooth target in checkbox.ini"
+ echo "btdevaddr option not set to device address of Bluetooth target in checkbox.conf"
exit 1
fi
if rfkill list bluetooth | grep -q 'Hard blocked: yes'
diff --git a/units/thunderbolt/jobs.pxu b/units/thunderbolt/jobs.pxu
index 188b2f6..14fa3f8 100644
--- a/units/thunderbolt/jobs.pxu
+++ b/units/thunderbolt/jobs.pxu
@@ -57,6 +57,7 @@ category_id: com.canonical.plainbox::disk
id: thunderbolt/daisy-chain
imports: from com.canonical.plainbox import manifest
requires: manifest.has_thunderbolt == 'True'
+flags: also-after-suspend-manual
estimated_duration: 45.0
command: removable_storage_test -s 268400000 scsi
_summary: Daisy-chain testing for Thunderbolt storage and display device
@@ -133,6 +134,7 @@ category_id: com.canonical.plainbox::disk
id: thunderbolt3/daisy-chain
imports: from com.canonical.plainbox import manifest
requires: manifest.has_thunderbolt3 == 'True'
+flags: also-after-suspend-manual
estimated_duration: 45.0
command: removable_storage_test -s 268400000 scsi
_summary: Daisy-chain testing for Thunderbolt 3 storage and display device
diff --git a/units/thunderbolt/test-plan.pxu b/units/thunderbolt/test-plan.pxu
index d5dc001..a0efcda 100644
--- a/units/thunderbolt/test-plan.pxu
+++ b/units/thunderbolt/test-plan.pxu
@@ -14,12 +14,12 @@ _name: Thunderbolt tests (Manual)
_description:
Thunderbolt tests (Manual)
include:
- thunderbolt/insert certification-status=blocker
- thunderbolt/storage-test certification-status=blocker
- thunderbolt/remove certification-status=blocker
- thunderbolt3/insert certification-status=non-blocker
- thunderbolt3/storage-test certification-status=non-blocker
- thunderbolt3/remove certification-status=non-blocker
+ thunderbolt/insert certification-status=non-blocker
+ thunderbolt/storage-test certification-status=non-blocker
+ thunderbolt/remove certification-status=non-blocker
+ thunderbolt3/insert certification-status=blocker
+ thunderbolt3/storage-test certification-status=blocker
+ thunderbolt3/remove certification-status=blocker
id: thunderbolt-cert-automated
unit: test plan
@@ -34,6 +34,6 @@ unit: test plan
_name: Thunderbolt tests (certification blockers only)
_description: Thunderbolt tests (certification blockers only)
include:
- thunderbolt/insert certification-status=blocker
- thunderbolt/storage-test certification-status=blocker
- thunderbolt/remove certification-status=blocker
+ thunderbolt3/insert certification-status=blocker
+ thunderbolt3/storage-test certification-status=blocker
+ thunderbolt3/remove certification-status=blocker
diff --git a/units/usb/test-plan.pxu b/units/usb/test-plan.pxu
index 27a0616..63c62b8 100644
--- a/units/usb/test-plan.pxu
+++ b/units/usb/test-plan.pxu
@@ -69,6 +69,7 @@ include:
usb-c/insert certification-status=blocker
usb-c/storage-automated certification-status=blocker
usb-c/remove certification-status=blocker
+ usb-c/c-to-ethernet-adapter-insert
id: after-suspend-usb-cert-full
unit: test plan
diff --git a/units/usb/usb-c.pxu b/units/usb/usb-c.pxu
index d2004c2..cf7c5f6 100644
--- a/units/usb/usb-c.pxu
+++ b/units/usb/usb-c.pxu
@@ -187,3 +187,19 @@ requires:
manifest.has_usb_type_c == 'True'
estimated_duration: 30
+id: usb-c/c-to-ethernet-adapter-insert
+plugin: user-interact
+category_id: com.canonical.plainbox::usb
+imports: from com.canonical.plainbox import manifest
+requires: manifest.has_usb_type_c == 'True'
+command:
+ net_if_watcher.py
+_summary: Check if USB Type-C to Ethernet adapter works
+_purpose:
+ This test will check if system detects network interface of the Type-C to
+ ethernet adapter.
+_steps:
+ 1. Prepare USB Type-C to Ethernet adapter
+ 2. Start the test
+ 3. When the message "INSERT NOW" is shown, plug in the adapter to Type-C port
+estimated_duration: 20
diff --git a/units/wireless/jobs.pxu b/units/wireless/jobs.pxu
index 363984a..52b2b01 100644
--- a/units/wireless/jobs.pxu
+++ b/units/wireless/jobs.pxu
@@ -389,7 +389,7 @@ plugin: shell
category_id: com.canonical.plainbox::wireless
id: wireless/monitor_wireless_connection
requires:
- package.name == 'iperf'
+ executable.name == 'iperf'
device.category == 'WIRELESS'
user: root
environ: WPA_BG_SSID WPA_BG_PSK SERVER_IPERF
@@ -418,7 +418,7 @@ plugin: shell
category_id: com.canonical.plainbox::wireless
id: wireless/monitor_wireless_connection_udp
requires:
- package.name == 'iperf'
+ executable.name == 'iperf'
device.category == 'WIRELESS'
user: root
environ: WPA_BG_SSID WPA_BG_PSK SERVER_IPERF