From 02bedc619aeda2d5fcc794a938952f2622f795d4 Mon Sep 17 00:00:00 2001 From: stanley31huang Date: Mon, 26 Feb 2024 17:52:54 +0800 Subject: [PATCH 01/13] Add: implement iio sensors test implement iio sensor tests --- .../bin/iio_sensor_test.py | 138 ++++++++++++++++++ .../units/iio-sensors/category.pxu | 3 + .../units/iio-sensors/jobs.pxu | 35 +++++ .../units/iio-sensors/manifest.pxu | 4 + .../units/iio-sensors/test-plan.pxu | 40 +++++ 5 files changed, 220 insertions(+) create mode 100755 contrib/checkbox-provider-ce-oem/bin/iio_sensor_test.py create mode 100644 contrib/checkbox-provider-ce-oem/units/iio-sensors/category.pxu create mode 100644 contrib/checkbox-provider-ce-oem/units/iio-sensors/jobs.pxu create mode 100644 contrib/checkbox-provider-ce-oem/units/iio-sensors/manifest.pxu create mode 100644 contrib/checkbox-provider-ce-oem/units/iio-sensors/test-plan.pxu diff --git a/contrib/checkbox-provider-ce-oem/bin/iio_sensor_test.py b/contrib/checkbox-provider-ce-oem/bin/iio_sensor_test.py new file mode 100755 index 000000000..f78b5d30b --- /dev/null +++ b/contrib/checkbox-provider-ce-oem/bin/iio_sensor_test.py @@ -0,0 +1,138 @@ +#!/usr/bin/env python3 +import logging +import argparse +from pathlib import Path + + +IIO_PATH = "/sys/bus/iio/devices/iio:device" + + +def _check_root_node(path): + + iio_node = Path(path) + if not iio_node.exists(): + raise FileNotFoundError("{} file not exists".format(str(iio_node))) + + return iio_node + + +def check_pressure_sensor(index): + + iio_node = _check_root_node(IIO_PATH + index) + sub_nodes = [ + "in_pressure_input", + "in_pressure_oversampling_ratio", + "in_pressure_sampling_frequency" + ] + for sub_node in sub_nodes: + tmp_node = iio_node.joinpath(sub_node) + if tmp_node.exists(): + value = tmp_node.read_text().strip("\n") + print("the value of {} node is {}".format(str(tmp_node), value)) + + try: + float(value) + except ValueError: + print("The accelerometer sensor test failed") + raise ValueError("The accelerometer value is not valid") + else: + print("The pressure sensor test failed") + raise FileNotFoundError( + "{} file not exists".format(str(tmp_node))) + + +def check_accelerometer_sensor(index): + + iio_node = _check_root_node(IIO_PATH + index) + sub_nodes = [ + "in_accel_sampling_frequency", + "in_accel_scale", + "in_accel_x_calibbias", + "in_accel_x_raw", + "in_accel_y_calibbias", + "in_accel_y_raw", + "in_accel_z_calibbias", + "in_accel_z_raw" + ] + for sub_node in sub_nodes: + tmp_node = iio_node.joinpath(sub_node) + if tmp_node.exists(): + value = tmp_node.read_text().strip("\n") + print("the value of {} node is {}".format(str(tmp_node), value)) + + try: + float(value) + except ValueError: + print("The accelerometer sensor test failed") + raise ValueError("The accelerometer value is not valid") + else: + print("The accelerometer sensor test failed") + raise FileNotFoundError( + "{} file not exists".format(str(tmp_node))) + + +def check_humidity_sensor(index): + + iio_node = _check_root_node(IIO_PATH + index) + sub_nodes = [ + "in_humidityrelative_integration_time", + "in_humidityrelative_scale", + "in_humidityrelative_raw", + ] + for sub_node in sub_nodes: + tmp_node = iio_node.joinpath(sub_node) + if tmp_node.exists(): + value = tmp_node.read_text().strip("\n") + print("the value of {} node is {}".format(str(tmp_node), value)) + + try: + value = float(value) + except ValueError: + print("The accelerometer sensor test failed") + raise ValueError("The accelerometer value is not valid") + else: + print("The humidity sensor test failed") + raise FileNotFoundError( + "{} file not exists".format(str(tmp_node))) + + +def register_arguments(): + parser = argparse.ArgumentParser( + formatter_class=argparse.RawDescriptionHelpFormatter, + description='Industrial IO sensor tests') + parser.add_argument( + "-t", "--type", + required=True, + choices=["pressure", "accelerometer", "humidityrelative"], + type=str + ) + parser.add_argument( + "-i", "--index", + required=True, + type=str, + ) + + args = parser.parse_args() + return args + + +if __name__ == "__main__": + + args = register_arguments() + + test_funcs = { + "pressure": check_pressure_sensor, + "accelerometer": check_accelerometer_sensor, + "humidityrelative": check_humidity_sensor + } + + try: + print("# Perform {} sensor test - index {}".format( + args.type, args.index + )) + test_funcs[args.type](args.index) + + print("# The {} sensor test passed".format(args.type)) + + except Exception as err: + logging.error(err) diff --git a/contrib/checkbox-provider-ce-oem/units/iio-sensors/category.pxu b/contrib/checkbox-provider-ce-oem/units/iio-sensors/category.pxu new file mode 100644 index 000000000..c016a1814 --- /dev/null +++ b/contrib/checkbox-provider-ce-oem/units/iio-sensors/category.pxu @@ -0,0 +1,3 @@ +unit: category +id: iio-sensors +_name: Industrial IO sensors Test diff --git a/contrib/checkbox-provider-ce-oem/units/iio-sensors/jobs.pxu b/contrib/checkbox-provider-ce-oem/units/iio-sensors/jobs.pxu new file mode 100644 index 000000000..05fe1aa13 --- /dev/null +++ b/contrib/checkbox-provider-ce-oem/units/iio-sensors/jobs.pxu @@ -0,0 +1,35 @@ +id: ce-oem-iio-sensors/resource +_summary: Generates a IIO sensors mapping for IIO sensor test +_description: + A IIO sensors mapping. By giving an IIO sensors on machnie to generates test jobs. + Usage of parameter: + IIO_SENSORS=device:sensor_type device:sensor_type ... + e.g. IIO_SENSORS=0:pressure 1:accelerometer 2:humidityrelative +estimated_duration: 0.02 +category_id: iio-sensors +plugin: resource +environ: IIO_SENSORS +command: + awk '{ + split($0, record, " ") + for (i in record) { + split(record[i], data, ":") + printf "INDEX: %s\nSENSOR_TYPE: %s\n\n", data[1], data[2] + } + }' <<< "$IIO_SENSORS" + +unit: template +template-resource: ce-oem-iio-sensors/resource +template-unit: job +id: ce-oem-iio-sensors/check-{SENSOR_TYPE}-{INDEX} +_summary: To test industrial IO {SENSOR_TYPE}-{INDEX} +plugin: shell +user: root +category_id: iio-sensors +estimated_duration: 40s +imports: from com.canonical.plainbox import manifest +requires: manifest.has_iio_sensors == 'True' +flags: also-after-suspend +command: + echo "## Perform the industrial I/O {SENSOR_TYPE}-{INDEX} sensor test" + iio_sensor_test.py -t {SENSOR_TYPE} -i {INDEX} diff --git a/contrib/checkbox-provider-ce-oem/units/iio-sensors/manifest.pxu b/contrib/checkbox-provider-ce-oem/units/iio-sensors/manifest.pxu new file mode 100644 index 000000000..e3e36478d --- /dev/null +++ b/contrib/checkbox-provider-ce-oem/units/iio-sensors/manifest.pxu @@ -0,0 +1,4 @@ +unit: manifest entry +id: has_iio_sensors +_name: Does platform support industrial IO sensor? +value-type: bool diff --git a/contrib/checkbox-provider-ce-oem/units/iio-sensors/test-plan.pxu b/contrib/checkbox-provider-ce-oem/units/iio-sensors/test-plan.pxu new file mode 100644 index 000000000..6f49b49a7 --- /dev/null +++ b/contrib/checkbox-provider-ce-oem/units/iio-sensors/test-plan.pxu @@ -0,0 +1,40 @@ +id: ce-oem-iio-sensors-full +unit: test plan +_name: Industrial I/O sensor tests +_description: Full tests for Industrial I/O sensors +include: +nested_part: + ce-oem-iio-sensors-manual + ce-oem-iio-sensors-automated + after-suspend-ce-oem-iio-sensors-manual + after-suspend-ce-oem-iio-sensors-automated + +id: ce-oem-iio-sensors-manual +unit: test plan +_name: Industrial I/O sensor manual tests +_description: Manual tests for Industrial I/O sensors +include: + +id: ce-oem-iio-sensors-automated +unit: test plan +_name: Industrial I/O sensor auto tests +_description: Automated tests for Industrial I/O sensors +bootstrap_include: + ce-oem-iio-sensors/resource +include: + ce-oem-iio-sensors/check-.*-.* + +id: after-suspend-ce-oem-iio-sensors-manual +unit: test plan +_name: Post suspend Industrial I/O sensor manual tests +_description: Manual tests for Industrial I/O sensors +include: + +id: after-suspend-ce-oem-iio-sensors-automated +unit: test plan +_name: Post suspend Industrial I/O sensor auto tests +_description: Automated tests for Industrial I/O sensors +bootstrap_include: + ce-oem-iio-sensors/resource +include: + after-suspend-ce-oem-iio-sensors/check-.*-.* From 4e08c382441de3e194b7fb44da2f429ef42f26f2 Mon Sep 17 00:00:00 2001 From: stanley31huang Date: Fri, 1 Mar 2024 11:51:16 +0800 Subject: [PATCH 02/13] add dump resource function add sub parser to support dump iio sensor resource --- .../bin/iio_sensor_test.py | 54 +++++++++++++------ .../units/iio-sensors/jobs.pxu | 10 +--- 2 files changed, 41 insertions(+), 23 deletions(-) diff --git a/contrib/checkbox-provider-ce-oem/bin/iio_sensor_test.py b/contrib/checkbox-provider-ce-oem/bin/iio_sensor_test.py index f78b5d30b..cccc2396b 100755 --- a/contrib/checkbox-provider-ce-oem/bin/iio_sensor_test.py +++ b/contrib/checkbox-provider-ce-oem/bin/iio_sensor_test.py @@ -96,21 +96,57 @@ def check_humidity_sensor(index): "{} file not exists".format(str(tmp_node))) +def validate_iio_sensor(args): + test_funcs = { + "pressure": check_pressure_sensor, + "accelerometer": check_accelerometer_sensor, + "humidityrelative": check_humidity_sensor + } + + print("# Perform {} sensor test - index {}".format(args.type, args.index)) + test_funcs[args.type](args.index) + print("# The {} sensor test passed".format(args.type)) + + +def dump_sensor_resource(args): + output = "" + resource_text = "index: {}\nsensor_type: {}\n\n" + for sensor in args.mapping.split(): + index, sensor_type = sensor.split(":") + output += resource_text.format(index, sensor_type) + print(output) + + def register_arguments(): parser = argparse.ArgumentParser( formatter_class=argparse.RawDescriptionHelpFormatter, description='Industrial IO sensor tests') - parser.add_argument( + + sub_parsers = parser.add_subparsers(dest="test_func") + sub_parsers.required = True + + iio_test_parser = sub_parsers.add_parser("test") + iio_test_parser.add_argument( "-t", "--type", required=True, choices=["pressure", "accelerometer", "humidityrelative"], type=str ) - parser.add_argument( + iio_test_parser.add_argument( "-i", "--index", required=True, type=str, ) + iio_test_parser.set_defaults(test_func=validate_iio_sensor) + + iio_arg_parser = sub_parsers.add_parser("sensor-resource") + iio_arg_parser.add_argument( + "mapping", + help=("Usage of parameter: IIO_SENSORS=" + "{index}:{sensor_type} {index}:{sensor_type}") + ) + + iio_arg_parser.set_defaults(test_func=dump_sensor_resource) args = parser.parse_args() return args @@ -120,19 +156,7 @@ def register_arguments(): args = register_arguments() - test_funcs = { - "pressure": check_pressure_sensor, - "accelerometer": check_accelerometer_sensor, - "humidityrelative": check_humidity_sensor - } - try: - print("# Perform {} sensor test - index {}".format( - args.type, args.index - )) - test_funcs[args.type](args.index) - - print("# The {} sensor test passed".format(args.type)) - + args.test_func(args) except Exception as err: logging.error(err) diff --git a/contrib/checkbox-provider-ce-oem/units/iio-sensors/jobs.pxu b/contrib/checkbox-provider-ce-oem/units/iio-sensors/jobs.pxu index 05fe1aa13..bec8c7927 100644 --- a/contrib/checkbox-provider-ce-oem/units/iio-sensors/jobs.pxu +++ b/contrib/checkbox-provider-ce-oem/units/iio-sensors/jobs.pxu @@ -10,13 +10,7 @@ category_id: iio-sensors plugin: resource environ: IIO_SENSORS command: - awk '{ - split($0, record, " ") - for (i in record) { - split(record[i], data, ":") - printf "INDEX: %s\nSENSOR_TYPE: %s\n\n", data[1], data[2] - } - }' <<< "$IIO_SENSORS" + iio_sensor_test.py sensor-resource "$IIO_SENSORS" unit: template template-resource: ce-oem-iio-sensors/resource @@ -32,4 +26,4 @@ requires: manifest.has_iio_sensors == 'True' flags: also-after-suspend command: echo "## Perform the industrial I/O {SENSOR_TYPE}-{INDEX} sensor test" - iio_sensor_test.py -t {SENSOR_TYPE} -i {INDEX} + iio_sensor_test.py test -t {SENSOR_TYPE} -i {INDEX} From 512875c04303d80cdb0548af0a58e09856d6cba7 Mon Sep 17 00:00:00 2001 From: stanley31huang Date: Tue, 5 Mar 2024 13:38:56 +0800 Subject: [PATCH 03/13] add unittest and refactor iio sensor test add unittest and refactor iio sensor test --- .../bin/iio_sensor_test.py | 200 ++++++++++++------ .../tests/test_iio_sensor_test.py | 176 +++++++++++++++ 2 files changed, 306 insertions(+), 70 deletions(-) create mode 100755 contrib/checkbox-provider-ce-oem/tests/test_iio_sensor_test.py diff --git a/contrib/checkbox-provider-ce-oem/bin/iio_sensor_test.py b/contrib/checkbox-provider-ce-oem/bin/iio_sensor_test.py index cccc2396b..6a6fd7aac 100755 --- a/contrib/checkbox-provider-ce-oem/bin/iio_sensor_test.py +++ b/contrib/checkbox-provider-ce-oem/bin/iio_sensor_test.py @@ -1,14 +1,46 @@ #!/usr/bin/env python3 -import logging +import re import argparse from pathlib import Path IIO_PATH = "/sys/bus/iio/devices/iio:device" - -def _check_root_node(path): - +pressure_nodes = [ + "in_pressure_input", + "in_pressure_oversampling_ratio", + "in_pressure_sampling_frequency" +] +accelerometer_nodes = [ + "in_accel_sampling_frequency", + "in_accel_scale", + "in_accel_x_calibbias", + "in_accel_x_raw", + "in_accel_y_calibbias", + "in_accel_y_raw", + "in_accel_z_calibbias", + "in_accel_z_raw" +] +humidity_nodes = [ + "in_humidityrelative_integration_time", + "in_humidityrelative_scale", + "in_humidityrelative_raw", +] + + +def _check_node(path): + """ + Initial a Path object for the industrial I/O sensor + + Args: + path (str): the full path of the industrial I/O sensor + + Raises: + FileNotFoundError: the sysfs of sensor not exists + + Returns: + iio_node: the node of the industrial I/O sensor. (Path object) + """ iio_node = Path(path) if not iio_node.exists(): raise FileNotFoundError("{} file not exists".format(str(iio_node))) @@ -16,87 +48,111 @@ def _check_root_node(path): return iio_node +def _check_reading(values): + """ + Check the format of sensor reading + + Args: + values (list): a list of sensor reading + + Returns: + bool: True if all reading match expected format + """ + result = True + reading_pattern = r"^[+-]?\d+(\.[0-9]+)?$" + for value in values: + if re.search(reading_pattern, value) is None: + result = False + + return result + + def check_pressure_sensor(index): + """ + Validate the sysfs of industrial I/O pressure sensor + + Args: + index (str): the index of sensor + + Raises: + ValueError: the reading of sensor is not expected format + """ + iio_node = _check_node(IIO_PATH + index) + readings = [] - iio_node = _check_root_node(IIO_PATH + index) - sub_nodes = [ - "in_pressure_input", - "in_pressure_oversampling_ratio", - "in_pressure_sampling_frequency" - ] - for sub_node in sub_nodes: + for sub_node in pressure_nodes: tmp_node = iio_node.joinpath(sub_node) - if tmp_node.exists(): - value = tmp_node.read_text().strip("\n") - print("the value of {} node is {}".format(str(tmp_node), value)) + _check_node(tmp_node) + value = tmp_node.read_text().strip("\n") + print("the value of {} node is {}".format(str(tmp_node), value)) + readings.append(value) - try: - float(value) - except ValueError: - print("The accelerometer sensor test failed") - raise ValueError("The accelerometer value is not valid") - else: - print("The pressure sensor test failed") - raise FileNotFoundError( - "{} file not exists".format(str(tmp_node))) + if readings and _check_reading(readings): + print("The pressure sensor test passed") + else: + raise ValueError("ERROR: The pressure value is not valid") def check_accelerometer_sensor(index): + """ + Validate the sysfs of industrial I/O accelerometer sensor - iio_node = _check_root_node(IIO_PATH + index) - sub_nodes = [ - "in_accel_sampling_frequency", - "in_accel_scale", - "in_accel_x_calibbias", - "in_accel_x_raw", - "in_accel_y_calibbias", - "in_accel_y_raw", - "in_accel_z_calibbias", - "in_accel_z_raw" - ] - for sub_node in sub_nodes: + Args: + index (str): the index of sensor + + Raises: + ValueError: the reading of sensor is not expected format + """ + readings = [] + iio_node = _check_node(IIO_PATH + index) + + for sub_node in accelerometer_nodes: tmp_node = iio_node.joinpath(sub_node) - if tmp_node.exists(): - value = tmp_node.read_text().strip("\n") - print("the value of {} node is {}".format(str(tmp_node), value)) + _check_node(tmp_node) - try: - float(value) - except ValueError: - print("The accelerometer sensor test failed") - raise ValueError("The accelerometer value is not valid") - else: - print("The accelerometer sensor test failed") - raise FileNotFoundError( - "{} file not exists".format(str(tmp_node))) + value = tmp_node.read_text().strip("\n") + print("the value of {} node is {}".format(str(tmp_node), value)) + readings.append(value) + + if readings and _check_reading(readings): + print("The accelerometer sensor test passed") + else: + raise ValueError("ERROR: The accelerometer value is not valid") def check_humidity_sensor(index): + """ + Validate the sysfs of industrial I/O humidity sensor + + Args: + index (str): the index of sensor - iio_node = _check_root_node(IIO_PATH + index) - sub_nodes = [ - "in_humidityrelative_integration_time", - "in_humidityrelative_scale", - "in_humidityrelative_raw", - ] - for sub_node in sub_nodes: + Raises: + ValueError: the reading of sensor is not expected format + """ + readings = [] + iio_node = _check_node(IIO_PATH + index) + + for sub_node in humidity_nodes: tmp_node = iio_node.joinpath(sub_node) - if tmp_node.exists(): - value = tmp_node.read_text().strip("\n") - print("the value of {} node is {}".format(str(tmp_node), value)) + _check_node(tmp_node) + value = tmp_node.read_text().strip("\n") + print("the value of {} node is {}".format(str(tmp_node), value)) + readings.append(value) - try: - value = float(value) - except ValueError: - print("The accelerometer sensor test failed") - raise ValueError("The accelerometer value is not valid") - else: - print("The humidity sensor test failed") - raise FileNotFoundError( - "{} file not exists".format(str(tmp_node))) + if readings and _check_reading(readings): + print("The humidity sensor test passed") + else: + raise ValueError("ERROR: The humidity value is not valid") def validate_iio_sensor(args): + """ + Check sensor and validate the format of reading + + Args: + args (Namespace): the arguments includes type and index of sensor + """ test_funcs = { "pressure": check_pressure_sensor, "accelerometer": check_accelerometer_sensor, @@ -109,6 +165,12 @@ def validate_iio_sensor(args): def dump_sensor_resource(args): + """ + Print out the sensor index and sensor type + + Args: + args (Namespace): the arguments includes type and index of sensor + """ output = "" resource_text = "index: {}\nsensor_type: {}\n\n" for sensor in args.mapping.split(): @@ -156,7 +218,5 @@ def register_arguments(): args = register_arguments() - try: - args.test_func(args) - except Exception as err: - logging.error(err) + args.test_func(args) + diff --git a/contrib/checkbox-provider-ce-oem/tests/test_iio_sensor_test.py b/contrib/checkbox-provider-ce-oem/tests/test_iio_sensor_test.py new file mode 100755 index 000000000..2250c714e --- /dev/null +++ b/contrib/checkbox-provider-ce-oem/tests/test_iio_sensor_test.py @@ -0,0 +1,176 @@ +import unittest +import sys +from pathlib import Path +from io import StringIO +from contextlib import redirect_stdout +from unittest.mock import patch + +import iio_sensor_test + + +class TestIndustrialIOSensorTest(unittest.TestCase): + + @patch("pathlib.Path.exists") + def test_check_root_node_exists(self, mock_path): + mock_path.return_value = True + node = iio_sensor_test._check_node("iio_sensor1") + + self.assertIsInstance(node, Path) + + @patch("pathlib.Path.exists") + def test_check_root_node_not_exists(self, mock_path): + mock_path.return_value = False + + with self.assertRaises(FileNotFoundError): + iio_sensor_test._check_node("iio_sensor1") + + def test_check_reading_is_expected(self): + readings = ["20.1", "-255", "+123.3"] + + self.assertTrue(iio_sensor_test._check_reading(readings)) + + def test_check_reading_not_expected(self): + readings = ["20.1", "-255", "+a"] + + self.assertFalse(iio_sensor_test._check_reading(readings)) + + @patch("iio_sensor_test._check_reading") + @patch("pathlib.Path.read_text") + @patch("iio_sensor_test._check_node") + def test_check_pressure_sensor( + self, mock_check_node, mock_read, mock_check_reading): + mock_check_node.return_value = Path("fake") + + mock_check_node.return_value = Path("fake") + mock_read.side_effect = ["20.1", "-255", "+123.3"] + + with redirect_stdout(StringIO()): + iio_sensor_test.check_pressure_sensor("iio_sensor1") + + self.assertEqual(mock_check_node.call_count, 4) + self.assertEqual(mock_read.call_count, 3) + self.assertEqual(mock_check_reading.call_count, 1) + + @patch("pathlib.Path.read_text") + @patch("iio_sensor_test._check_node") + def test_check_pressure_sensor_unexpected_value( + self, mock_check_node, mock_read): + + mock_check_node.return_value = Path("fake") + mock_read.side_effect = ["20.1", "-255", "+a"] + with redirect_stdout(StringIO()): + with self.assertRaises(ValueError): + iio_sensor_test.check_pressure_sensor("iio_sensor1") + + @patch("iio_sensor_test._check_reading") + @patch("pathlib.Path.read_text") + @patch("iio_sensor_test._check_node") + def test_check_accelerometer_sensor( + self, mock_check_node, mock_read, mock_check_reading): + + mock_check_node.return_value = Path("fake") + mock_read.side_effect = [ + "20.1", "-255", "+123.3", "1", + "509", "-0.1235", "+0.2222", "6666" + ] + + with redirect_stdout(StringIO()): + iio_sensor_test.check_accelerometer_sensor("iio_sensor1") + + self.assertEqual(mock_check_node.call_count, 9) + self.assertEqual(mock_read.call_count, 8) + self.assertEqual(mock_check_reading.call_count, 1) + + @patch("pathlib.Path.read_text") + @patch("iio_sensor_test._check_node") + def test_check_accelerometer_sensor_unexpected_value( + self, mock_check_node, mock_read): + + mock_check_node.return_value = Path("fake") + mock_read.side_effect = [ + "d20.1", "-255", "+123.3", "1", + "5d09", "-0a.1235", "+0.2222", "6666" + ] + with redirect_stdout(StringIO()): + with self.assertRaises(ValueError): + iio_sensor_test.check_accelerometer_sensor( + "iio_sensor1") + + @patch("iio_sensor_test._check_reading") + @patch("pathlib.Path.read_text") + @patch("iio_sensor_test._check_node") + def test_check_humidity_sensor( + self, mock_check_node, mock_read, mock_check_reading): + + mock_check_node.return_value = Path("fake") + mock_read.side_effect = ["20.1", "-255", "+123.3"] + + with redirect_stdout(StringIO()): + iio_sensor_test.check_humidity_sensor("iio_sensor1") + + self.assertEqual(mock_check_node.call_count, 4) + self.assertEqual(mock_read.call_count, 3) + self.assertEqual(mock_check_reading.call_count, 1) + + @patch("pathlib.Path.read_text") + @patch("iio_sensor_test._check_node") + def test_check_humidity_sensor_unexpected_value( + self, mock_check_node, mock_read): + + mock_check_node.return_value = Path("fake") + mock_read.side_effect = ["20.d1", "-255", "+a"] + with redirect_stdout(StringIO()): + with self.assertRaises(ValueError): + iio_sensor_test.check_humidity_sensor("iio_sensor1") + + +class TestArgumentParser(unittest.TestCase): + + def test_pressure_parser(self): + sys.argv = [ + "iio_sensor_test.py", "test", "-t", "pressure", + "-i", "3" + ] + args = iio_sensor_test.register_arguments() + + self.assertEqual(args.test_func, + iio_sensor_test.validate_iio_sensor) + self.assertEqual(args.type, "pressure") + self.assertEqual(args.index, "3") + + def test_accelerometer_parser(self): + sys.argv = [ + "iio_sensor_test.py", "test", "-t", "accelerometer", + "-i", "3" + ] + args = iio_sensor_test.register_arguments() + + self.assertEqual(args.test_func, + iio_sensor_test.validate_iio_sensor) + self.assertEqual(args.type, "accelerometer") + self.assertEqual(args.index, "3") + + def test_humidityrelative_parser(self): + sys.argv = [ + "iio_sensor_test.py", "test", + "--type", "humidityrelative", + "--index", "3" + ] + args = iio_sensor_test.register_arguments() + + self.assertEqual(args.test_func, + iio_sensor_test.validate_iio_sensor) + self.assertEqual(args.type, "humidityrelative") + self.assertEqual(args.index, "3") + + def test_iio_sensore_resource_parser(self): + sys.argv = [ + "iio_sensor_test.py", + "sensor-resource", + "0:pressure 1:accelerometer 2:humidityrelative" + ] + args = iio_sensor_test.register_arguments() + + self.assertEqual(args.test_func, + iio_sensor_test.dump_sensor_resource) + self.assertEqual(args.mapping, sys.argv[2]) From 3321b1e425ae97eb46450cabe11679fe1ce5031b Mon Sep 17 00:00:00 2001 From: stanley31huang Date: Tue, 5 Mar 2024 15:10:01 +0800 Subject: [PATCH 04/13] Fix: fixed template job issue fixed template job issue --- .../checkbox-provider-ce-oem/units/iio-sensors/jobs.pxu | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/contrib/checkbox-provider-ce-oem/units/iio-sensors/jobs.pxu b/contrib/checkbox-provider-ce-oem/units/iio-sensors/jobs.pxu index bec8c7927..257a80f73 100644 --- a/contrib/checkbox-provider-ce-oem/units/iio-sensors/jobs.pxu +++ b/contrib/checkbox-provider-ce-oem/units/iio-sensors/jobs.pxu @@ -15,8 +15,8 @@ command: unit: template template-resource: ce-oem-iio-sensors/resource template-unit: job -id: ce-oem-iio-sensors/check-{SENSOR_TYPE}-{INDEX} -_summary: To test industrial IO {SENSOR_TYPE}-{INDEX} +id: ce-oem-iio-sensors/check-{sensor_type}-{index} +_summary: To test industrial IO {sensor_type}-{index} plugin: shell user: root category_id: iio-sensors @@ -25,5 +25,5 @@ imports: from com.canonical.plainbox import manifest requires: manifest.has_iio_sensors == 'True' flags: also-after-suspend command: - echo "## Perform the industrial I/O {SENSOR_TYPE}-{INDEX} sensor test" - iio_sensor_test.py test -t {SENSOR_TYPE} -i {INDEX} + echo "## Perform the industrial I/O {sensor_type}-{index} sensor test" + iio_sensor_test.py test -t {sensor_type} -i {index} From d888e872cdc7e83159e240fd8dcaae0ffd738afc Mon Sep 17 00:00:00 2001 From: stanley31huang Date: Tue, 5 Mar 2024 15:16:52 +0800 Subject: [PATCH 05/13] Fix: PEP8 issue fixed PEP8 issue --- contrib/checkbox-provider-ce-oem/bin/iio_sensor_test.py | 1 - 1 file changed, 1 deletion(-) diff --git a/contrib/checkbox-provider-ce-oem/bin/iio_sensor_test.py b/contrib/checkbox-provider-ce-oem/bin/iio_sensor_test.py index 6a6fd7aac..829cb7a65 100755 --- a/contrib/checkbox-provider-ce-oem/bin/iio_sensor_test.py +++ b/contrib/checkbox-provider-ce-oem/bin/iio_sensor_test.py @@ -219,4 +219,3 @@ def register_arguments(): args = register_arguments() args.test_func(args) - From 94c98d11ff932c279596759900a980fdd6df6333 Mon Sep 17 00:00:00 2001 From: stanley31huang Date: Tue, 5 Mar 2024 15:57:31 +0800 Subject: [PATCH 06/13] improve unittest coverage improve unittest coverage --- .../tests/test_iio_sensor_test.py | 51 ++++++++++++++++++- 1 file changed, 50 insertions(+), 1 deletion(-) diff --git a/contrib/checkbox-provider-ce-oem/tests/test_iio_sensor_test.py b/contrib/checkbox-provider-ce-oem/tests/test_iio_sensor_test.py index 2250c714e..f203179a3 100755 --- a/contrib/checkbox-provider-ce-oem/tests/test_iio_sensor_test.py +++ b/contrib/checkbox-provider-ce-oem/tests/test_iio_sensor_test.py @@ -1,9 +1,10 @@ import unittest import sys +import argparse from pathlib import Path from io import StringIO from contextlib import redirect_stdout -from unittest.mock import patch +from unittest.mock import patch, Mock import iio_sensor_test @@ -123,6 +124,54 @@ def test_check_humidity_sensor_unexpected_value( with self.assertRaises(ValueError): iio_sensor_test.check_humidity_sensor("iio_sensor1") + @patch("iio_sensor_test.check_pressure_sensor") + def test_validate_iio_sensor_test(self, mock_func): + mock_args = Mock( + return_value=argparse.Namespace( + type="pressure", + index="0") + ) + mock_func.return_value = True + + with redirect_stdout(StringIO()): + iio_sensor_test.validate_iio_sensor(mock_args()) + mock_func.assert_called_once_with( + mock_args().index) + + def test_sensor_resource(self): + mock_args = Mock( + return_value=argparse.Namespace( + mapping="0:pressure 1:accelerometer 2:humidityrelative") + ) + with redirect_stdout(StringIO()) as stdout: + iio_sensor_test.dump_sensor_resource(mock_args()) + + self.assertEqual( + stdout.getvalue(), + ( + "index: 0\n" + "sensor_type: pressure\n\n" + "index: 1\n" + "sensor_type: accelerometer\n\n" + "index: 2\n" + "sensor_type: humidityrelative\n\n\n" + ) + ) + + def test_sensor_resource_with_unexpected_format(self): + mock_args = Mock( + return_value=argparse.Namespace( + mapping="0:pressure:error") + ) + + with self.assertRaises(ValueError) as context: + iio_sensor_test.dump_sensor_resource(mock_args()) + + self.assertEqual( + str(context.exception), + "too many values to unpack (expected 2)" + ) + class TestArgumentParser(unittest.TestCase): From 0b5016d335ff2aaec56cdd5b51492ca320b273c7 Mon Sep 17 00:00:00 2001 From: stanley31huang Date: Tue, 5 Mar 2024 23:03:06 +0800 Subject: [PATCH 07/13] add iio sensors test plan as nested part of ce-oem add iio sensors test plan as part of nested test plan of ce-oem plans --- contrib/checkbox-provider-ce-oem/units/test-plan-ce-oem.pxu | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/contrib/checkbox-provider-ce-oem/units/test-plan-ce-oem.pxu b/contrib/checkbox-provider-ce-oem/units/test-plan-ce-oem.pxu index 877767ca5..e97fdc881 100644 --- a/contrib/checkbox-provider-ce-oem/units/test-plan-ce-oem.pxu +++ b/contrib/checkbox-provider-ce-oem/units/test-plan-ce-oem.pxu @@ -44,6 +44,7 @@ nested_part: ce-oem-touchscreen-evdev ce-oem-socketcan-manual com.canonical.certification::led-indicator-manual + ce-oem-iio-sensors-manual id: ce-oem-automated unit: test plan @@ -76,6 +77,7 @@ nested_part: ce-oem-ethernet-tcp-automated com.canonical.certification::eeprom-automated com.canonical.certification::rtc-automated + ce-oem-iio-sensors-automated id: after-suspend-ce-oem-manual unit: test plan @@ -104,6 +106,7 @@ nested_part: after-suspend-ce-oem-touchscreen-evdev after-suspend-ce-oem-socketcan-manual com.canonical.certification::after-suspend-led-indicator-manual + after-suspend-ce-oem-iio-sensors-manual id: after-suspend-ce-oem-automated unit: test plan @@ -134,6 +137,7 @@ nested_part: after-suspend-ce-oem-ethernet-tcp-automated com.canonical.certification::after-suspend-eeprom-automated com.canonical.certification::after-suspend-rtc-automated + after-suspend-ce-oem-iio-sensors-automated id: ce-oem-stress unit: test plan From cfe645afa903ace26abe9fde567786f06aa0bf30 Mon Sep 17 00:00:00 2001 From: stanley31huang Date: Fri, 8 Mar 2024 16:22:36 +0800 Subject: [PATCH 08/13] Add author information into python scripts add author information into python scripts --- .../bin/iio_sensor_test.py | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/contrib/checkbox-provider-ce-oem/bin/iio_sensor_test.py b/contrib/checkbox-provider-ce-oem/bin/iio_sensor_test.py index 829cb7a65..ce6de8156 100755 --- a/contrib/checkbox-provider-ce-oem/bin/iio_sensor_test.py +++ b/contrib/checkbox-provider-ce-oem/bin/iio_sensor_test.py @@ -1,4 +1,21 @@ #!/usr/bin/env python3 +# This file is part of Checkbox. +# +# Copyright 2024 Canonical Ltd. +# Written by: +# Stanley Huang +# +# Checkbox is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License version 3, +# as published by the Free Software Foundation. +# +# Checkbox is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with Checkbox. If not, see . import re import argparse from pathlib import Path From adbde40cce1ca0fd9fc37bb73e5cb6b2acacf8d2 Mon Sep 17 00:00:00 2001 From: stanley31huang Date: Mon, 11 Mar 2024 16:09:08 +0800 Subject: [PATCH 09/13] Fix: applied template id for iio sensor tests applied templdate id for iio sensor tests --- .../bin/iio_sensor_test.py | 2 +- .../tests/test_iio_sensor_test.py | 6 ++--- .../units/iio-sensors/jobs.pxu | 10 ++++---- .../units/iio-sensors/test-plan.pxu | 23 +++---------------- 4 files changed, 13 insertions(+), 28 deletions(-) diff --git a/contrib/checkbox-provider-ce-oem/bin/iio_sensor_test.py b/contrib/checkbox-provider-ce-oem/bin/iio_sensor_test.py index ce6de8156..966bbda59 100755 --- a/contrib/checkbox-provider-ce-oem/bin/iio_sensor_test.py +++ b/contrib/checkbox-provider-ce-oem/bin/iio_sensor_test.py @@ -189,7 +189,7 @@ def dump_sensor_resource(args): args (Namespace): the arguments includes type and index of sensor """ output = "" - resource_text = "index: {}\nsensor_type: {}\n\n" + resource_text = "index: {}\ntype: {}\n\n" for sensor in args.mapping.split(): index, sensor_type = sensor.split(":") output += resource_text.format(index, sensor_type) diff --git a/contrib/checkbox-provider-ce-oem/tests/test_iio_sensor_test.py b/contrib/checkbox-provider-ce-oem/tests/test_iio_sensor_test.py index f203179a3..c2db93214 100755 --- a/contrib/checkbox-provider-ce-oem/tests/test_iio_sensor_test.py +++ b/contrib/checkbox-provider-ce-oem/tests/test_iio_sensor_test.py @@ -150,11 +150,11 @@ def test_sensor_resource(self): stdout.getvalue(), ( "index: 0\n" - "sensor_type: pressure\n\n" + "type: pressure\n\n" "index: 1\n" - "sensor_type: accelerometer\n\n" + "type: accelerometer\n\n" "index: 2\n" - "sensor_type: humidityrelative\n\n\n" + "type: humidityrelative\n\n\n" ) ) diff --git a/contrib/checkbox-provider-ce-oem/units/iio-sensors/jobs.pxu b/contrib/checkbox-provider-ce-oem/units/iio-sensors/jobs.pxu index 257a80f73..8354887a7 100644 --- a/contrib/checkbox-provider-ce-oem/units/iio-sensors/jobs.pxu +++ b/contrib/checkbox-provider-ce-oem/units/iio-sensors/jobs.pxu @@ -13,10 +13,12 @@ command: iio_sensor_test.py sensor-resource "$IIO_SENSORS" unit: template +template-engine: jinja2 template-resource: ce-oem-iio-sensors/resource template-unit: job -id: ce-oem-iio-sensors/check-{sensor_type}-{index} -_summary: To test industrial IO {sensor_type}-{index} +template-id: ce-oem-iio-sensors/check_sensor_type_index +id: ce-oem-iio-sensors/check-{{ type }}-{{ index }} +_summary: To test industrial IO {{ type }}-{{ index }} plugin: shell user: root category_id: iio-sensors @@ -25,5 +27,5 @@ imports: from com.canonical.plainbox import manifest requires: manifest.has_iio_sensors == 'True' flags: also-after-suspend command: - echo "## Perform the industrial I/O {sensor_type}-{index} sensor test" - iio_sensor_test.py test -t {sensor_type} -i {index} + echo "## Perform the industrial I/O {{ type }}-{{ index }} sensor test" + iio_sensor_test.py test -t {{ type }} -i {{ index }} diff --git a/contrib/checkbox-provider-ce-oem/units/iio-sensors/test-plan.pxu b/contrib/checkbox-provider-ce-oem/units/iio-sensors/test-plan.pxu index 6f49b49a7..96a97c65e 100644 --- a/contrib/checkbox-provider-ce-oem/units/iio-sensors/test-plan.pxu +++ b/contrib/checkbox-provider-ce-oem/units/iio-sensors/test-plan.pxu @@ -6,35 +6,18 @@ include: nested_part: ce-oem-iio-sensors-manual ce-oem-iio-sensors-automated - after-suspend-ce-oem-iio-sensors-manual - after-suspend-ce-oem-iio-sensors-automated id: ce-oem-iio-sensors-manual unit: test plan _name: Industrial I/O sensor manual tests -_description: Manual tests for Industrial I/O sensors +_description: Manual tests for Industrial I/O sensors in before suspend and post suspend stage include: id: ce-oem-iio-sensors-automated unit: test plan _name: Industrial I/O sensor auto tests -_description: Automated tests for Industrial I/O sensors +_description: Automated tests for Industrial I/O sensors in before suspend and post suspend stage bootstrap_include: ce-oem-iio-sensors/resource include: - ce-oem-iio-sensors/check-.*-.* - -id: after-suspend-ce-oem-iio-sensors-manual -unit: test plan -_name: Post suspend Industrial I/O sensor manual tests -_description: Manual tests for Industrial I/O sensors -include: - -id: after-suspend-ce-oem-iio-sensors-automated -unit: test plan -_name: Post suspend Industrial I/O sensor auto tests -_description: Automated tests for Industrial I/O sensors -bootstrap_include: - ce-oem-iio-sensors/resource -include: - after-suspend-ce-oem-iio-sensors/check-.*-.* + ce-oem-iio-sensors/check_sensor_type_index From 19c0b8739f2e61bfd54fb2e9ef100c0b13c089ec Mon Sep 17 00:00:00 2001 From: stanley31huang Date: Wed, 13 Mar 2024 09:32:21 +0800 Subject: [PATCH 10/13] Add new iio-sensors test plans add new iio-sensors test plans --- .../units/iio-sensors/test-plan.pxu | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/contrib/checkbox-provider-ce-oem/units/iio-sensors/test-plan.pxu b/contrib/checkbox-provider-ce-oem/units/iio-sensors/test-plan.pxu index 96a97c65e..ee8c860b7 100644 --- a/contrib/checkbox-provider-ce-oem/units/iio-sensors/test-plan.pxu +++ b/contrib/checkbox-provider-ce-oem/units/iio-sensors/test-plan.pxu @@ -17,7 +17,26 @@ id: ce-oem-iio-sensors-automated unit: test plan _name: Industrial I/O sensor auto tests _description: Automated tests for Industrial I/O sensors in before suspend and post suspend stage + # Not nested this test plan for now due to it leads the mismatch job order bootstrap_include: ce-oem-iio-sensors/resource include: ce-oem-iio-sensors/check_sensor_type_index + +id: before-suspend-ce-oem-iio-sensors-automated +unit: test plan +_name: Industrial I/O sensor auto tests +_description: Automated tests for Industrial I/O sensors in before suspend stage +bootstrap_include: + ce-oem-iio-sensors/resource +include: + ce-oem-iio-sensors/check-.* + +id: after-suspend-ce-oem-iio-sensors-automated +unit: test plan +_name: Industrial I/O sensor auto tests +_description: Automated tests for Industrial I/O sensors in post suspend stage +bootstrap_include: + ce-oem-iio-sensors/resource +include: + after-suspend-ce-oem-iio-sensors/check-.* From 4add0b02339487837d9e7212a3f064bd47795347 Mon Sep 17 00:00:00 2001 From: stanley31huang Date: Mon, 18 Mar 2024 15:11:18 +0800 Subject: [PATCH 11/13] Fixed: fixed bugs fixed bugs --- contrib/checkbox-provider-ce-oem/bin/iio_sensor_test.py | 8 ++++---- .../checkbox-provider-ce-oem/units/test-plan-ce-oem.pxu | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/contrib/checkbox-provider-ce-oem/bin/iio_sensor_test.py b/contrib/checkbox-provider-ce-oem/bin/iio_sensor_test.py index 966bbda59..901702f64 100755 --- a/contrib/checkbox-provider-ce-oem/bin/iio_sensor_test.py +++ b/contrib/checkbox-provider-ce-oem/bin/iio_sensor_test.py @@ -60,7 +60,7 @@ def _check_node(path): """ iio_node = Path(path) if not iio_node.exists(): - raise FileNotFoundError("{} file not exists".format(str(iio_node))) + raise FileNotFoundError("{} file not exists".format(iio_node)) return iio_node @@ -101,7 +101,7 @@ def check_pressure_sensor(index): tmp_node = iio_node.joinpath(sub_node) _check_node(tmp_node) value = tmp_node.read_text().strip("\n") - print("the value of {} node is {}".format(str(tmp_node), value)) + print("the value of {} node is {}".format(tmp_node, value)) readings.append(value) if readings and _check_reading(readings): @@ -128,7 +128,7 @@ def check_accelerometer_sensor(index): _check_node(tmp_node) value = tmp_node.read_text().strip("\n") - print("the value of {} node is {}".format(str(tmp_node), value)) + print("the value of {} node is {}".format(tmp_node, value)) readings.append(value) if readings and _check_reading(readings): @@ -154,7 +154,7 @@ def check_humidity_sensor(index): tmp_node = iio_node.joinpath(sub_node) _check_node(tmp_node) value = tmp_node.read_text().strip("\n") - print("the value of {} node is {}".format(str(tmp_node), value)) + print("the value of {} node is {}".format(tmp_node, value)) readings.append(value) if readings and _check_reading(readings): diff --git a/contrib/checkbox-provider-ce-oem/units/test-plan-ce-oem.pxu b/contrib/checkbox-provider-ce-oem/units/test-plan-ce-oem.pxu index e97fdc881..da9c46f18 100644 --- a/contrib/checkbox-provider-ce-oem/units/test-plan-ce-oem.pxu +++ b/contrib/checkbox-provider-ce-oem/units/test-plan-ce-oem.pxu @@ -76,8 +76,8 @@ nested_part: ce-oem-socketcan-stress-automated ce-oem-ethernet-tcp-automated com.canonical.certification::eeprom-automated - com.canonical.certification::rtc-automated ce-oem-iio-sensors-automated + com.canonical.certification::rtc-automated id: after-suspend-ce-oem-manual unit: test plan From 7aefd1ca754c5099c529017a848cbc403e7ebaae Mon Sep 17 00:00:00 2001 From: stanley31huang Date: Mon, 18 Mar 2024 16:12:06 +0800 Subject: [PATCH 12/13] Update contrib/checkbox-provider-ce-oem/units/test-plan-ce-oem.pxu correct test plan Co-authored-by: LiaoU3 <58060146+LiaoU3@users.noreply.github.com> --- contrib/checkbox-provider-ce-oem/units/test-plan-ce-oem.pxu | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/contrib/checkbox-provider-ce-oem/units/test-plan-ce-oem.pxu b/contrib/checkbox-provider-ce-oem/units/test-plan-ce-oem.pxu index da9c46f18..5431e8e27 100644 --- a/contrib/checkbox-provider-ce-oem/units/test-plan-ce-oem.pxu +++ b/contrib/checkbox-provider-ce-oem/units/test-plan-ce-oem.pxu @@ -76,7 +76,7 @@ nested_part: ce-oem-socketcan-stress-automated ce-oem-ethernet-tcp-automated com.canonical.certification::eeprom-automated - ce-oem-iio-sensors-automated + before-suspend-ce-oem-iio-sensors-automated com.canonical.certification::rtc-automated id: after-suspend-ce-oem-manual From f21568fd856610e3a154c61dca285bfc2736a2da Mon Sep 17 00:00:00 2001 From: stanley31huang Date: Mon, 18 Mar 2024 16:12:26 +0800 Subject: [PATCH 13/13] Update contrib/checkbox-provider-ce-oem/bin/iio_sensor_test.py updated log Co-authored-by: LiaoU3 <58060146+LiaoU3@users.noreply.github.com> --- contrib/checkbox-provider-ce-oem/bin/iio_sensor_test.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/contrib/checkbox-provider-ce-oem/bin/iio_sensor_test.py b/contrib/checkbox-provider-ce-oem/bin/iio_sensor_test.py index 901702f64..7636ac28e 100755 --- a/contrib/checkbox-provider-ce-oem/bin/iio_sensor_test.py +++ b/contrib/checkbox-provider-ce-oem/bin/iio_sensor_test.py @@ -101,7 +101,7 @@ def check_pressure_sensor(index): tmp_node = iio_node.joinpath(sub_node) _check_node(tmp_node) value = tmp_node.read_text().strip("\n") - print("the value of {} node is {}".format(tmp_node, value)) + print("The value of {} node is {}".format(tmp_node, value)) readings.append(value) if readings and _check_reading(readings):