diff --git a/checkbox-ng/checkbox_ng/launcher/merge_reports.py b/checkbox-ng/checkbox_ng/launcher/merge_reports.py index 43c0a4d5da..5435cfbccf 100644 --- a/checkbox-ng/checkbox_ng/launcher/merge_reports.py +++ b/checkbox-ng/checkbox_ng/launcher/merge_reports.py @@ -141,7 +141,7 @@ def _populate_session_state(self, job, state): "category_id", "com.canonical.plainbox::uncategorised" ) job_state.effective_certification_status = job.get_record_value( - "certification_status", "unspecified" + "certification_status", "non-blocker" ) def _create_exporter(self, exporter_id): diff --git a/checkbox-ng/checkbox_ng/launcher/subcommands.py b/checkbox-ng/checkbox_ng/launcher/subcommands.py index aa00538772..55d4666f80 100644 --- a/checkbox-ng/checkbox_ng/launcher/subcommands.py +++ b/checkbox-ng/checkbox_ng/launcher/subcommands.py @@ -1378,7 +1378,7 @@ def get_effective_certification_status(self, unit): return value if hasattr(unit, "certification_status"): return unit.certification_status - return "unspecified" + return "non-blocker" class ListBootstrapped: diff --git a/checkbox-ng/checkbox_ng/launcher/test_merge_reports.py b/checkbox-ng/checkbox_ng/launcher/test_merge_reports.py index f37b3370a8..c05c373571 100644 --- a/checkbox-ng/checkbox_ng/launcher/test_merge_reports.py +++ b/checkbox-ng/checkbox_ng/launcher/test_merge_reports.py @@ -16,21 +16,22 @@ # You should have received a copy of the GNU General Public License # along with Checkbox. If not, see . -from unittest import TestCase, mock +from unittest import TestCase +from unittest.mock import patch, MagicMock from functools import partial from checkbox_ng.launcher.merge_reports import MergeReports class MergeReportsTests(TestCase): - @mock.patch("checkbox_ng.launcher.merge_reports.TemporaryDirectory") - @mock.patch("checkbox_ng.launcher.merge_reports.SessionManager") - @mock.patch("checkbox_ng.launcher.merge_reports.JobDefinition") - @mock.patch("checkbox_ng.launcher.merge_reports.CategoryUnit") - @mock.patch("builtins.print") - @mock.patch("os.path.join") - @mock.patch("tarfile.open") - @mock.patch("json.load") + @patch("checkbox_ng.launcher.merge_reports.TemporaryDirectory") + @patch("checkbox_ng.launcher.merge_reports.SessionManager") + @patch("checkbox_ng.launcher.merge_reports.JobDefinition") + @patch("checkbox_ng.launcher.merge_reports.CategoryUnit") + @patch("builtins.print") + @patch("os.path.join") + @patch("tarfile.open") + @patch("json.load") # used to load an empty launcher with no error def test_invoked_ok( self, @@ -43,11 +44,11 @@ def test_invoked_ok( session_manager_mock, temp_dir_mock, ): - ctx_mock = mock.MagicMock() + ctx_mock = MagicMock() ctx_mock.args.submission = ["submission"] ctx_mock.args.output_file = "file_location" - self_mock = mock.MagicMock() + self_mock = MagicMock() self_mock._parse_submission = partial( MergeReports._parse_submission, self_mock ) @@ -65,7 +66,7 @@ def test_invoked_ok( } json_mock.return_value = sub_to_read - with mock.patch("builtins.open"): + with patch("builtins.open"): MergeReports.invoked(self_mock, ctx_mock) # output path was printed @@ -73,3 +74,10 @@ def test_invoked_ok( exporter = self_mock._create_exporter.return_value # exporter was created and dumped self.assertTrue(exporter.dump_from_session_manager_list.called) + + def test_populate_session_state(self): + job_mock = MagicMock() + state_mock = MagicMock() + self_mock = MagicMock() + MergeReports._populate_session_state(self_mock, job_mock, state_mock) + self.assertTrue(job_mock.get_record_value.called) diff --git a/checkbox-ng/checkbox_ng/launcher/test_subcommands.py b/checkbox-ng/checkbox_ng/launcher/test_subcommands.py index 96297912a2..949a5b9004 100644 --- a/checkbox-ng/checkbox_ng/launcher/test_subcommands.py +++ b/checkbox-ng/checkbox_ng/launcher/test_subcommands.py @@ -734,7 +734,7 @@ def setUp(self): "summary": "fake-job1", "plugin": "manual", "description": "fake-description1", - "certification_status": "unspecified", + "certification_status": "non-blocker", }, id="namespace1::test-job1", partial_id="test-job1", @@ -745,7 +745,7 @@ def setUp(self): "summary": "fake-job2", "plugin": "shell", "command": "ls", - "certification_status": "unspecified", + "certification_status": "non-blocker", }, id="namespace2::test-job2", partial_id="test-job2", @@ -903,7 +903,7 @@ def test_get_effective_certificate_status(self): ) self.assertEqual( self.launcher.get_effective_certification_status(template1), - "unspecified", + "non-blocker", ) diff --git a/checkbox-ng/plainbox/impl/exporter/test_html.py b/checkbox-ng/plainbox/impl/exporter/test_html.py index a2b7c64ee1..7cce67b74e 100644 --- a/checkbox-ng/plainbox/impl/exporter/test_html.py +++ b/checkbox-ng/plainbox/impl/exporter/test_html.py @@ -162,23 +162,12 @@ def _get_all_exporter_units(self): def prepare_manager_without_certification_status(self): return self._get_session_manager( - "unspecified", "unspecified", "unspecified" + "non-blocker", "non-blocker", "non-blocker" ) def prepare_manager_with_certification_blocker(self): return self._get_session_manager( - "blocker", "unspecified", "unspecified" - ) - - def prepare_manager_with_certification_non_blocker(self): - return self._get_session_manager( - "non-blocker", "unspecified", "unspecified" - ) - - def prepare_manager_with_both_certification_status(self): - self.session_state.update_job_result(self.job2, self.result_fail) - return self._get_session_manager( - "blocker", "non-blocker", "unspecified" + "blocker", "non-blocker", "non-blocker" ) def test_perfect_match_without_certification_status(self): @@ -226,49 +215,3 @@ def test_perfect_match_with_certification_blocker(self): "test-data/html-exporter/with_certification_blocker.html", ) # unintuitively, resource_string returns bytes self.assertEqual(actual_result, expected_result) - - def test_perfect_match_with_certification_non_blocker(self): - """ - Test that output from the exporter exactly matches known - good HTML output, inlining and everything included. - """ - exporter = Jinja2SessionStateExporter( - system_id="", - timestamp="2012-12-21T12:00:00", - client_version="Checkbox 1.0", - exporter_unit=self.exporter_unit, - ) - stream = io.BytesIO() - exporter.dump_from_session_manager( - self.prepare_manager_with_certification_non_blocker(), stream - ) - actual_result = stream.getvalue() # This is bytes - self.assertIsInstance(actual_result, bytes) - expected_result = resource_string( - "plainbox", - "test-data/html-exporter/with_certification_non_blocker.html", - ) # unintuitively, resource_string returns bytes - self.assertEqual(actual_result, expected_result) - - def test_perfect_match_with_both_certification_status(self): - """ - Test that output from the exporter exactly matches known - good HTML output, inlining and everything included. - """ - exporter = Jinja2SessionStateExporter( - system_id="", - timestamp="2012-12-21T12:00:00", - client_version="Checkbox 1.0", - exporter_unit=self.exporter_unit, - ) - stream = io.BytesIO() - exporter.dump_from_session_manager( - self.prepare_manager_with_both_certification_status(), stream - ) - actual_result = stream.getvalue() # This is bytes - self.assertIsInstance(actual_result, bytes) - expected_result = resource_string( - "plainbox", - "test-data/html-exporter/with_both_certification_status.html", - ) # unintuitively, resource_string returns bytes - self.assertEqual(actual_result, expected_result) diff --git a/checkbox-ng/plainbox/impl/exporter/test_init.py b/checkbox-ng/plainbox/impl/exporter/test_init.py index f92beb3b79..dfe9eae034 100644 --- a/checkbox-ng/plainbox/impl/exporter/test_init.py +++ b/checkbox-ng/plainbox/impl/exporter/test_init.py @@ -258,7 +258,7 @@ def test_all_at_once(self): ("requires", 'job_b.ready == "yes"'), ("command", "echo testing && true"), ("io_log", ["dGVzdGluZwo="]), - ("certification_status", "unspecified"), + ("certification_status", "non-blocker"), ] ), "job_b": OrderedDict( @@ -278,7 +278,7 @@ def test_all_at_once(self): ("plugin", "resource"), ("command", "echo ready: yes"), ("io_log", ["cmVhZHk6IHllcwo="]), - ("certification_status", "unspecified"), + ("certification_status", "non-blocker"), ] ), }, diff --git a/checkbox-ng/plainbox/impl/exporter/test_xlsx.py b/checkbox-ng/plainbox/impl/exporter/test_xlsx.py new file mode 100644 index 0000000000..9e580c77a2 --- /dev/null +++ b/checkbox-ng/plainbox/impl/exporter/test_xlsx.py @@ -0,0 +1,106 @@ +# This file is part of Checkbox. +# +# Copyright 2024 Canonical Ltd. +# Written by: +# Pierre Equoy +# +# 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 . + +from collections import OrderedDict +from unittest import TestCase +from unittest.mock import MagicMock, ANY + +from plainbox.impl.exporter.xlsx import XLSXSessionStateExporter +from plainbox.impl.session import SessionState +from plainbox.impl.unit.job import JobDefinition +from plainbox.impl.unit.category import CategoryUnit + + +class XLSXSessionStateExporterTests(TestCase): + def test_write_job(self): + self_mock = MagicMock() + tree = {"job1": {}} + result_map = { + "job1": OrderedDict( + [ + ("summary", "job1"), + ("category_id", "com.canonical.plainbox::uncategorised"), + ("outcome", "pass"), + ("plugin", "shell"), + ("io_log", ""), + ("comments", ""), + ("command", 'echo "This is job1"'), + ("certification_status", "non-blocker"), + ] + ), + "Uncategorised": { + "category_status": "pass", + "plugin": "local", + "summary": "Uncategorised", + }, + } + XLSXSessionStateExporter._write_job(self_mock, tree, result_map, 2) + self_mock.worksheet3.write.assert_any_call(ANY, ANY, "", ANY) + + tree = {"Uncategorised": {"job1": {}}} + XLSXSessionStateExporter._write_job(self_mock, tree, result_map, 2) + self.assertTrue(self_mock._write_job.called) + + def test_category_map(self): + self_mock = MagicMock() + A = JobDefinition({"id": "A", "category_id": "test"}) + B = JobDefinition({"id": "B", "certification-status": "blocker"}) + job_list = [A, B] + unit = MagicMock(name="unit", spec_set=CategoryUnit) + unit.id = "test" + unit.tr_name.return_value = "Test" + unit.Meta.name = "category" + + state = SessionState(job_list) + state.update_desired_job_list(job_list) + state.unit_list.append(unit) + + self.assertEqual( + XLSXSessionStateExporter._category_map(self_mock, state), + {"test": "Test"}, + ) + + def test_write_tp_export(self): + self_mock = MagicMock() + self_mock._category_map.return_value = { + "com.canonical.plainbox::uncategorised": "test" + } + data = MagicMock() + A = JobDefinition({"id": "A"}) + B = JobDefinition({"id": "B", "certification-status": "blocker"}) + job_list = [A, B] + unit = MagicMock(name="unit", spec_set=CategoryUnit) + unit.Meta.name = "category" + + state = SessionState(job_list) + data["manager"].default_device_context.state = state + XLSXSessionStateExporter.write_tp_export(self_mock, data) + self_mock.worksheet4.write_row.assert_called_with( + ANY, 0, ["test", "", ""], ANY + ) + state.update_desired_job_list(job_list) + state.unit_list.append(unit) + + data["manager"].default_device_context.state = state + XLSXSessionStateExporter.write_tp_export(self_mock, data) + self_mock.worksheet4.write_row.assert_any_call( + ANY, 0, ["A", "", "A"], ANY + ) + self_mock.worksheet4.write_row.assert_any_call( + ANY, 0, ["B", "blocker", "B"], ANY + ) diff --git a/checkbox-ng/plainbox/impl/exporter/xlsx.py b/checkbox-ng/plainbox/impl/exporter/xlsx.py index 1c45bc7168..297f0d7362 100644 --- a/checkbox-ng/plainbox/impl/exporter/xlsx.py +++ b/checkbox-ng/plainbox/impl/exporter/xlsx.py @@ -752,7 +752,7 @@ def _write_job(self, tree, result_map, max_level, level=0): cert_status = "" if "certification_status" in result_map[job]: cert_status = result_map[job]["certification_status"] - if cert_status == "unspecified": + if cert_status == "non-blocker": cert_status = "" self.worksheet3.write( self._lineno, @@ -877,24 +877,23 @@ def write_results(self, data): ) self.worksheet3.autofilter(5, max_level, self._lineno, max_level + 3) - def write_tp_export(self, data): - def _category_map(state): - """Map from category id to their corresponding translated names.""" - wanted_category_ids = frozenset( - { - job_state.effective_category_id - for job_state in state.job_state_map.values() - if job_state.job in state.run_list - and job_state.job.plugin not in ("resource", "attachment") - } - ) - return { - unit.id: unit.tr_name() - for unit in state.unit_list - if unit.Meta.name == "category" - and unit.id in wanted_category_ids + def _category_map(self, state): + """Map from category id to their corresponding translated names.""" + wanted_category_ids = frozenset( + { + job_state.effective_category_id + for job_state in state.job_state_map.values() + if job_state.job in state.run_list + and job_state.job.plugin not in ("resource", "attachment") } + ) + return { + unit.id: unit.tr_name() + for unit in state.unit_list + if unit.Meta.name == "category" and unit.id in wanted_category_ids + } + def write_tp_export(self, data): self.worksheet4.set_header( "&C{}".format(data["manager"].test_plans[0]) ) @@ -912,7 +911,7 @@ def _category_map(state): self.worksheet4.repeat_rows(0) self._lineno = 0 state = data["manager"].default_device_context.state - cat_map = _category_map(state) + cat_map = self._category_map(state) run_list_ids = [job.id for job in state.run_list] for cat_id in sorted(cat_map, key=lambda x: cat_map[x].casefold()): self._lineno += 1 @@ -931,7 +930,7 @@ def _category_map(state): certification_status = ( job_state.effective_certification_status ) - if certification_status == "unspecified": + if certification_status == "non-blocker": certification_status = "" description = job_state.job.description if not description: diff --git a/checkbox-ng/plainbox/impl/providers/exporters/data/checkbox.html b/checkbox-ng/plainbox/impl/providers/exporters/data/checkbox.html index 451afb4ddb..9fc8999311 100644 --- a/checkbox-ng/plainbox/impl/providers/exporters/data/checkbox.html +++ b/checkbox-ng/plainbox/impl/providers/exporters/data/checkbox.html @@ -182,7 +182,7 @@

{{ cat_name }}