From 7b2cbae292187dafdd0ea9a694562781c20adf24 Mon Sep 17 00:00:00 2001 From: Debarati Basu-Nag Date: Tue, 11 Nov 2025 15:16:50 -0500 Subject: [PATCH 1/4] Add new polarion tests Signed-off-by: Debarati Basu-Nag Assisted-by: Claude code --- .../test_polarion_set_automated_coverage.py | 435 ++++++++++++++++++ 1 file changed, 435 insertions(+) create mode 100644 tests/polarion/test_polarion_set_automated_coverage.py diff --git a/tests/polarion/test_polarion_set_automated_coverage.py b/tests/polarion/test_polarion_set_automated_coverage.py new file mode 100644 index 0000000..ba39c9f --- /dev/null +++ b/tests/polarion/test_polarion_set_automated_coverage.py @@ -0,0 +1,435 @@ +""" +Comprehensive test coverage for polarion_set_automated.py module. +This file provides extensive test coverage to improve overall test coverage. +""" + +from __future__ import annotations + +import logging +from unittest.mock import MagicMock, patch + +from click.testing import CliRunner + +from apps.polarion.polarion_set_automated import ( + approve_tests, + polarion_approve_automate, + remove_approved_tests, +) + + +class TestApproveTests: + """Test the approve_tests function""" + + @patch("apps.polarion.polarion_set_automated.update_polarion_ids") + def test_approve_tests_success(self, mock_update): + """Test approve_tests with successful update""" + # Arrange + project_id = "TEST_PROJECT" + test_ids = ["TEST-001", "TEST-002"] + expected_result = {"updated": test_ids, "failed": []} + mock_update.return_value = expected_result + + # Act + result = approve_tests(project_id, test_ids) + + # Assert + mock_update.assert_called_once_with( + polarion_ids=test_ids, project_id=project_id, is_automated=True, is_approved=True + ) + assert result == expected_result + + @patch("apps.polarion.polarion_set_automated.update_polarion_ids") + def test_approve_tests_with_failures(self, mock_update): + """Test approve_tests when some updates fail""" + # Arrange + project_id = "TEST_PROJECT" + test_ids = ["TEST-001", "TEST-002"] + expected_result = {"updated": ["TEST-001"], "failed": ["TEST-002"]} + mock_update.return_value = expected_result + + # Act + result = approve_tests(project_id, test_ids) + + # Assert + assert result == expected_result + mock_update.assert_called_once_with( + polarion_ids=test_ids, project_id=project_id, is_automated=True, is_approved=True + ) + + @patch("apps.polarion.polarion_set_automated.update_polarion_ids") + def test_approve_tests_empty_ids(self, mock_update): + """Test approve_tests with empty ID list""" + # Arrange + project_id = "TEST_PROJECT" + test_ids = [] + expected_result = {"updated": [], "failed": []} + mock_update.return_value = expected_result + + # Act + result = approve_tests(project_id, test_ids) + + # Assert + mock_update.assert_called_once_with(polarion_ids=[], project_id=project_id, is_automated=True, is_approved=True) + assert result == expected_result + + +class TestRemoveApprovedTests: + """Test the remove_approved_tests function""" + + @patch("apps.polarion.polarion_set_automated.find_polarion_ids") + @patch("apps.polarion.polarion_set_automated.update_polarion_ids") + def test_remove_approved_tests_with_removals(self, mock_update, mock_find): + """Test remove_approved_tests when IDs are found for removal""" + # Arrange + project_id = "TEST_PROJECT" + branch = "main" + prev_commit = "abc123" + curr_commit = "def456" + added_ids = ["TEST-001"] + found_removed_ids = ["TEST-002", "TEST-003", "TEST-001"] # Include overlap + + mock_find.return_value = found_removed_ids + mock_update.return_value = {"updated": ["TEST-002", "TEST-003"], "failed": []} + + # Act + result = remove_approved_tests(project_id, branch, prev_commit, curr_commit, added_ids) + + # Assert + mock_find.assert_called_once_with( + polarion_project_id=project_id, + string_to_match="removed", + branch=branch, + previous_commit=prev_commit, + current_commit=curr_commit, + ) + mock_update.assert_called_once_with( + polarion_ids=["TEST-002", "TEST-003"], # Should exclude added_ids overlap + project_id=project_id, + is_automated=False, + ) + assert result == {"updated": ["TEST-002", "TEST-003"], "failed": []} + + @patch("apps.polarion.polarion_set_automated.find_polarion_ids") + def test_remove_approved_tests_no_removals(self, mock_find): + """Test remove_approved_tests when no IDs found for removal""" + # Arrange + project_id = "TEST_PROJECT" + mock_find.return_value = [] + + # Act + result = remove_approved_tests(project_id) + + # Assert + assert result == {} + mock_find.assert_called_once_with( + polarion_project_id=project_id, + string_to_match="removed", + branch=None, + previous_commit=None, + current_commit=None, + ) + + @patch("apps.polarion.polarion_set_automated.find_polarion_ids") + def test_remove_approved_tests_all_overlap_with_added(self, mock_find): + """Test when all removed IDs overlap with added IDs""" + # Arrange + project_id = "TEST_PROJECT" + added_ids = ["TEST-001", "TEST-002"] + mock_find.return_value = added_ids # All found IDs are in added_ids + + # Act + result = remove_approved_tests(project_id, added_ids=added_ids) + + # Assert + assert result == {} # Nothing should be removed + + @patch("apps.polarion.polarion_set_automated.find_polarion_ids") + def test_remove_approved_tests_none_added_ids(self, mock_find): + """Test remove_approved_tests with None added_ids parameter""" + # This tests the added_ids = added_ids or [] line + project_id = "TEST_PROJECT" + mock_find.return_value = [] + + # Act + result = remove_approved_tests(project_id, added_ids=None) + + # Assert + assert result == {} + + @patch("apps.polarion.polarion_set_automated.find_polarion_ids") + @patch("apps.polarion.polarion_set_automated.update_polarion_ids") + def test_remove_approved_tests_with_failures(self, mock_update, mock_find): + """Test remove_approved_tests when update operation fails""" + # Arrange + project_id = "TEST_PROJECT" + found_ids = ["TEST-001", "TEST-002"] + mock_find.return_value = found_ids + mock_update.return_value = {"updated": ["TEST-001"], "failed": ["TEST-002"]} + + # Act + result = remove_approved_tests(project_id) + + # Assert + assert result == {"updated": ["TEST-001"], "failed": ["TEST-002"]} + + +class TestPolarionApproveAutomateCommand: + """Test the Click command function""" + + def setup_method(self): + """Setup test runner""" + self.runner = CliRunner() + + @patch("apps.polarion.polarion_set_automated.get_polarion_project_id") + @patch("apps.polarion.polarion_set_automated.find_polarion_ids") + @patch("apps.polarion.polarion_set_automated.approve_tests") + @patch("apps.polarion.polarion_set_automated.remove_approved_tests") + def test_command_success_flow(self, mock_remove, mock_approve, mock_find, mock_get_project): + """Test successful command execution""" + # Arrange + mock_get_project.return_value = "TEST_PROJECT" + mock_find.return_value = ["TEST-001", "TEST-002"] + mock_approve.return_value = {"updated": ["TEST-001", "TEST-002"], "failed": []} + mock_remove.return_value = {"updated": [], "failed": []} + + # Act + result = self.runner.invoke( + polarion_approve_automate, + ["--previous-commit", "abc123", "--current-commit", "def456", "--project-id", "TEST_PROJECT"], + ) + + # Assert + assert result.exit_code == 0 + mock_find.assert_called_once_with( + polarion_project_id="TEST_PROJECT", + string_to_match="added", + branch=None, + previous_commit="abc123", + current_commit="def456", + ) + mock_approve.assert_called_once_with(polarion_project_id="TEST_PROJECT", added_ids=["TEST-001", "TEST-002"]) + mock_remove.assert_called_once() + + @patch("apps.polarion.polarion_set_automated.get_polarion_project_id") + @patch("apps.polarion.polarion_set_automated.find_polarion_ids") + @patch("apps.polarion.polarion_set_automated.approve_tests") + @patch("apps.polarion.polarion_set_automated.remove_approved_tests") + def test_command_with_added_failures_exits_1(self, mock_remove, mock_approve, mock_find, mock_get_project): + """Test command exits with code 1 when there are added failures""" + # Arrange + mock_get_project.return_value = "TEST_PROJECT" + mock_find.return_value = ["TEST-001"] + mock_approve.return_value = {"updated": [], "failed": ["TEST-001"]} + mock_remove.return_value = {"updated": [], "failed": []} + + # Act + result = self.runner.invoke( + polarion_approve_automate, + ["--previous-commit", "abc123", "--current-commit", "def456", "--project-id", "TEST_PROJECT"], + ) + + # Assert + assert result.exit_code == 1 + + @patch("apps.polarion.polarion_set_automated.get_polarion_project_id") + @patch("apps.polarion.polarion_set_automated.find_polarion_ids") + @patch("apps.polarion.polarion_set_automated.approve_tests") + @patch("apps.polarion.polarion_set_automated.remove_approved_tests") + def test_command_with_removed_failures_exits_1(self, mock_remove, mock_approve, mock_find, mock_get_project): + """Test command exits with code 1 when there are removed failures""" + # Arrange + mock_get_project.return_value = "TEST_PROJECT" + mock_find.return_value = ["TEST-001"] + mock_approve.return_value = {"updated": ["TEST-001"], "failed": []} + mock_remove.return_value = {"updated": [], "failed": ["TEST-002"]} + + # Act + result = self.runner.invoke( + polarion_approve_automate, + ["--previous-commit", "abc123", "--current-commit", "def456", "--project-id", "TEST_PROJECT"], + ) + + # Assert + assert result.exit_code == 1 + + def test_command_missing_required_params(self): + """Test command fails with missing required parameters""" + result = self.runner.invoke(polarion_approve_automate, []) + assert result.exit_code != 0 + assert "Missing option" in result.output + + def test_command_missing_previous_commit(self): + """Test command fails when missing previous-commit""" + result = self.runner.invoke(polarion_approve_automate, ["--current-commit", "def456"]) + assert result.exit_code != 0 + assert "Missing option" in result.output + + def test_command_missing_current_commit(self): + """Test command fails when missing current-commit""" + result = self.runner.invoke(polarion_approve_automate, ["--previous-commit", "abc123"]) + assert result.exit_code != 0 + assert "Missing option" in result.output + + @patch("apps.polarion.polarion_set_automated.get_polarion_project_id") + @patch("apps.polarion.polarion_set_automated.find_polarion_ids") + @patch("apps.polarion.polarion_set_automated.remove_approved_tests") + def test_command_no_added_ids(self, mock_remove, mock_find, mock_get_project): + """Test command when no IDs are found to add""" + # Arrange + mock_get_project.return_value = "TEST_PROJECT" + mock_find.return_value = [] # No added IDs found + mock_remove.return_value = {"updated": [], "failed": []} + + with patch("apps.polarion.polarion_set_automated.approve_tests") as mock_approve: + # Act + result = self.runner.invoke( + polarion_approve_automate, + ["--previous-commit", "abc123", "--current-commit", "def456", "--project-id", "TEST_PROJECT"], + ) + + # Assert + assert result.exit_code == 0 + # approve_tests should not be called when no added IDs + mock_approve.assert_not_called() + + @patch("apps.polarion.polarion_set_automated.get_polarion_project_id") + @patch("apps.polarion.polarion_set_automated.find_polarion_ids") + @patch("apps.polarion.polarion_set_automated.remove_approved_tests") + def test_command_verbose_logging(self, mock_remove, mock_find, mock_get_project): + """Test verbose flag enables debug logging""" + # Arrange + mock_get_project.return_value = "TEST_PROJECT" + mock_find.return_value = [] + mock_remove.return_value = {"updated": [], "failed": []} + + with patch("apps.polarion.polarion_set_automated.LOGGER") as mock_logger: + with patch("logging.getLogger") as mock_get_logger: + mock_utils_logger = MagicMock() + mock_get_logger.return_value = mock_utils_logger + + # Act + result = self.runner.invoke( + polarion_approve_automate, + [ + "--previous-commit", + "abc123", + "--current-commit", + "def456", + "--project-id", + "TEST_PROJECT", + "--verbose", + ], + ) + + # Assert + assert result.exit_code == 0 + # Verify logging level was set + mock_logger.setLevel.assert_called_with(logging.DEBUG) + mock_get_logger.assert_called_with("apps.polarion.polarion_utils") + mock_utils_logger.setLevel.assert_called_with(logging.DEBUG) + + @patch("apps.polarion.polarion_set_automated.get_polarion_project_id") + def test_command_uses_config_file_project_id(self, mock_get_project): + """Test command uses project ID from config file when not provided""" + # Arrange + mock_get_project.return_value = "CONFIG_PROJECT" + + with patch("apps.polarion.polarion_set_automated.find_polarion_ids") as mock_find: + mock_find.return_value = [] + with patch("apps.polarion.polarion_set_automated.remove_approved_tests") as mock_remove: + mock_remove.return_value = {"updated": [], "failed": []} + + # Act + result = self.runner.invoke( + polarion_approve_automate, + [ + "--previous-commit", + "abc123", + "--current-commit", + "def456", + # No --project-id provided + ], + ) + + # Assert + assert result.exit_code == 0 + # Check that get_polarion_project_id was called with default config path + args, kwargs = mock_get_project.call_args + assert kwargs["util_name"] == "pyutils-polarion-set-automated" + assert kwargs["config_file_path"].endswith("/.config/python-utility-scripts/config.yaml") + + @patch("apps.polarion.polarion_set_automated.get_polarion_project_id") + @patch("apps.polarion.polarion_set_automated.find_polarion_ids") + @patch("apps.polarion.polarion_set_automated.remove_approved_tests") + def test_command_both_add_and_remove_failures(self, mock_remove, mock_find, mock_get_project): + """Test command when both add and remove operations have failures""" + # Arrange + mock_get_project.return_value = "TEST_PROJECT" + mock_find.return_value = ["TEST-001"] + mock_remove.return_value = {"updated": [], "failed": ["TEST-002"]} + + with patch("apps.polarion.polarion_set_automated.approve_tests") as mock_approve: + mock_approve.return_value = {"updated": [], "failed": ["TEST-001"]} + + # Act + result = self.runner.invoke( + polarion_approve_automate, + ["--previous-commit", "abc123", "--current-commit", "def456", "--project-id", "TEST_PROJECT"], + ) + + # Assert + assert result.exit_code == 1 + + @patch("apps.polarion.polarion_set_automated.get_polarion_project_id") + @patch("apps.polarion.polarion_set_automated.find_polarion_ids") + @patch("apps.polarion.polarion_set_automated.approve_tests") + @patch("apps.polarion.polarion_set_automated.remove_approved_tests") + def test_command_custom_config_file_path(self, mock_remove, mock_approve, mock_find, mock_get_project): + """Test command with custom config file path""" + # Arrange + custom_config_path = "/custom/path/config.yaml" + mock_get_project.return_value = "TEST_PROJECT" + mock_find.return_value = [] + mock_remove.return_value = {"updated": [], "failed": []} + + # Act + result = self.runner.invoke( + polarion_approve_automate, + ["--config-file-path", custom_config_path, "--previous-commit", "abc123", "--current-commit", "def456"], + ) + + # Assert + assert result.exit_code == 0 + mock_get_project.assert_called_once_with( + config_file_path=custom_config_path, util_name="pyutils-polarion-set-automated" + ) + + @patch("apps.polarion.polarion_set_automated.get_polarion_project_id") + @patch("apps.polarion.polarion_set_automated.find_polarion_ids") + @patch("apps.polarion.polarion_set_automated.approve_tests") + @patch("apps.polarion.polarion_set_automated.remove_approved_tests") + def test_command_project_id_override_config(self, mock_remove, mock_approve, mock_find, mock_get_project): + """Test that command line project ID overrides config file""" + # Arrange + cli_project_id = "CLI_PROJECT" + mock_find.return_value = [] + mock_remove.return_value = {"updated": [], "failed": []} + + # Act + result = self.runner.invoke( + polarion_approve_automate, + ["--project-id", cli_project_id, "--previous-commit", "abc123", "--current-commit", "def456"], + ) + + # Assert + assert result.exit_code == 0 + # get_polarion_project_id should not be called when project-id is provided + mock_get_project.assert_not_called() + # find_polarion_ids should be called with the CLI project ID + mock_find.assert_called_once_with( + polarion_project_id=cli_project_id, + string_to_match="added", + branch=None, + previous_commit="abc123", + current_commit="def456", + ) From 3328089daa4460a0d3c40aca6952cee4caf078ee Mon Sep 17 00:00:00 2001 From: Debarati Basu-Nag Date: Tue, 11 Nov 2025 16:16:03 -0500 Subject: [PATCH 2/4] update to tests --- pyproject.toml | 2 +- .../test_polarion_set_automated_coverage.py | 11 +- ...olarion_verify_tc_requirements_coverage.py | 392 ++++++++++++++++++ 3 files changed, 399 insertions(+), 6 deletions(-) create mode 100644 tests/polarion/test_polarion_verify_tc_requirements_coverage.py diff --git a/pyproject.toml b/pyproject.toml index b7c465e..5243775 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -40,7 +40,7 @@ pyutils-jira = "apps.jira_utils.jira_information:get_jira_mismatch" omit = ["tests/*"] [tool.coverage.report] -fail_under = 60 +fail_under = 70 skip_empty = true [tool.coverage.html] diff --git a/tests/polarion/test_polarion_set_automated_coverage.py b/tests/polarion/test_polarion_set_automated_coverage.py index ba39c9f..793fd25 100644 --- a/tests/polarion/test_polarion_set_automated_coverage.py +++ b/tests/polarion/test_polarion_set_automated_coverage.py @@ -102,11 +102,12 @@ def test_remove_approved_tests_with_removals(self, mock_update, mock_find): previous_commit=prev_commit, current_commit=curr_commit, ) - mock_update.assert_called_once_with( - polarion_ids=["TEST-002", "TEST-003"], # Should exclude added_ids overlap - project_id=project_id, - is_automated=False, - ) + # Verify the call was made with the correct IDs (order-independent) + args, kwargs = mock_update.call_args + assert set(kwargs["polarion_ids"]) == {"TEST-002", "TEST-003"} # Should exclude added_ids overlap + assert kwargs["project_id"] == project_id + assert kwargs["is_automated"] is False + assert result == {"updated": ["TEST-002", "TEST-003"], "failed": []} @patch("apps.polarion.polarion_set_automated.find_polarion_ids") diff --git a/tests/polarion/test_polarion_verify_tc_requirements_coverage.py b/tests/polarion/test_polarion_verify_tc_requirements_coverage.py new file mode 100644 index 0000000..e00bb41 --- /dev/null +++ b/tests/polarion/test_polarion_verify_tc_requirements_coverage.py @@ -0,0 +1,392 @@ +""" +Comprehensive test coverage for polarion_verify_tc_requirements.py module. +This file provides extensive test coverage to improve overall test coverage. +""" + +from __future__ import annotations + +import logging +import sys +from unittest.mock import MagicMock, patch + +from click.testing import CliRunner + +from apps.polarion.polarion_verify_tc_requirements import has_verify + + +class TestHasVerifyCommand: + """Test the has_verify Click command function""" + + def setup_method(self): + """Setup test runner""" + self.runner = CliRunner() + + @patch("apps.polarion.polarion_verify_tc_requirements.get_polarion_project_id") + @patch("apps.polarion.polarion_verify_tc_requirements.find_polarion_ids") + @patch("apps.polarion.polarion_verify_tc_requirements.validate_polarion_requirements") + def test_command_success_no_missing_requirements(self, mock_validate, mock_find, mock_get_project): + """Test successful command execution with no missing requirements""" + # Arrange + mock_get_project.return_value = "TEST_PROJECT" + mock_find.return_value = ["TEST-001", "TEST-002"] + mock_validate.return_value = [] # No missing requirements + + # Act + result = self.runner.invoke( + has_verify, + ["--project-id", "TEST_PROJECT", "--branch", "origin/develop"], + ) + + # Assert + assert result.exit_code == 0 + mock_find.assert_called_once_with( + polarion_project_id="TEST_PROJECT", + string_to_match="added", + branch="origin/develop", + ) + mock_validate.assert_called_once_with( + polarion_test_ids=["TEST-001", "TEST-002"], + polarion_project_id="TEST_PROJECT", + ) + + @patch("apps.polarion.polarion_verify_tc_requirements.get_polarion_project_id") + @patch("apps.polarion.polarion_verify_tc_requirements.find_polarion_ids") + @patch("apps.polarion.polarion_verify_tc_requirements.validate_polarion_requirements") + @patch("sys.exit") + def test_command_fails_with_missing_requirements(self, mock_exit, mock_validate, mock_find, mock_get_project): + """Test command exits with code 1 when there are missing requirements""" + # Arrange + mock_get_project.return_value = "TEST_PROJECT" + mock_find.return_value = ["TEST-001", "TEST-002"] + mock_validate.return_value = ["TEST-001"] # Has missing requirements + + # Act + result = self.runner.invoke( + has_verify, + ["--project-id", "TEST_PROJECT"], + ) + + # Assert + # sys.exit(1) should be called due to missing requirements + assert mock_exit.call_count >= 1 + assert 1 in [call.args[0] for call in mock_exit.call_args_list] + mock_find.assert_called_once_with( + polarion_project_id="TEST_PROJECT", + string_to_match="added", + branch="origin/main", # Default branch + ) + mock_validate.assert_called_once_with( + polarion_test_ids=["TEST-001", "TEST-002"], + polarion_project_id="TEST_PROJECT", + ) + + @patch("apps.polarion.polarion_verify_tc_requirements.get_polarion_project_id") + @patch("apps.polarion.polarion_verify_tc_requirements.find_polarion_ids") + def test_command_no_added_ids_found(self, mock_find, mock_get_project): + """Test command when no added IDs are found""" + # Arrange + mock_get_project.return_value = "TEST_PROJECT" + mock_find.return_value = [] # No added IDs found + + with patch("apps.polarion.polarion_verify_tc_requirements.validate_polarion_requirements") as mock_validate: + # Act + result = self.runner.invoke( + has_verify, + ["--project-id", "TEST_PROJECT"], + ) + + # Assert + assert result.exit_code == 0 + mock_find.assert_called_once_with( + polarion_project_id="TEST_PROJECT", + string_to_match="added", + branch="origin/main", + ) + # validate_polarion_requirements should not be called when no added IDs + mock_validate.assert_not_called() + + @patch("apps.polarion.polarion_verify_tc_requirements.get_polarion_project_id") + @patch("apps.polarion.polarion_verify_tc_requirements.find_polarion_ids") + @patch("apps.polarion.polarion_verify_tc_requirements.validate_polarion_requirements") + def test_command_verbose_logging(self, mock_validate, mock_find, mock_get_project): + """Test verbose flag enables debug logging""" + # Arrange + mock_get_project.return_value = "TEST_PROJECT" + mock_find.return_value = [] + mock_validate.return_value = [] + + with patch("apps.polarion.polarion_verify_tc_requirements.LOGGER") as mock_logger: + with patch("logging.getLogger") as mock_get_logger: + mock_utils_logger = MagicMock() + mock_get_logger.return_value = mock_utils_logger + + # Act + result = self.runner.invoke( + has_verify, + ["--project-id", "TEST_PROJECT", "--verbose"], + ) + + # Assert + assert result.exit_code == 0 + # Verify logging level was set + mock_logger.setLevel.assert_called_with(logging.DEBUG) + mock_get_logger.assert_called_with("apps.polarion.polarion_utils") + mock_utils_logger.setLevel.assert_called_with(logging.DEBUG) + + @patch("apps.polarion.polarion_verify_tc_requirements.get_polarion_project_id") + def test_command_uses_config_file_project_id(self, mock_get_project): + """Test command uses project ID from config file when not provided""" + # Arrange + mock_get_project.return_value = "CONFIG_PROJECT" + + with patch("apps.polarion.polarion_verify_tc_requirements.find_polarion_ids") as mock_find: + mock_find.return_value = [] + + # Act + result = self.runner.invoke( + has_verify, + ["--branch", "origin/feature"], + ) + + # Assert + assert result.exit_code == 0 + # Check that get_polarion_project_id was called with default config path + args, kwargs = mock_get_project.call_args + assert kwargs["util_name"] == "pyutils-polarion-verify-tc-requirements" + assert kwargs["config_file_path"].endswith("/.config/python-utility-scripts/config.yaml") + + @patch("apps.polarion.polarion_verify_tc_requirements.get_polarion_project_id") + @patch("apps.polarion.polarion_verify_tc_requirements.find_polarion_ids") + def test_command_custom_config_file_path(self, mock_find, mock_get_project): + """Test command with custom config file path""" + # Arrange + custom_config_path = "/custom/path/config.yaml" + mock_get_project.return_value = "TEST_PROJECT" + mock_find.return_value = [] + + # Act + result = self.runner.invoke( + has_verify, + ["--config-file-path", custom_config_path], + ) + + # Assert + assert result.exit_code == 0 + mock_get_project.assert_called_once_with( + config_file_path=custom_config_path, util_name="pyutils-polarion-verify-tc-requirements" + ) + + @patch("apps.polarion.polarion_verify_tc_requirements.get_polarion_project_id") + @patch("apps.polarion.polarion_verify_tc_requirements.find_polarion_ids") + def test_command_project_id_override_config(self, mock_find, mock_get_project): + """Test that command line project ID overrides config file""" + # Arrange + cli_project_id = "CLI_PROJECT" + mock_find.return_value = [] + + # Act + result = self.runner.invoke( + has_verify, + ["--project-id", cli_project_id], + ) + + # Assert + assert result.exit_code == 0 + # get_polarion_project_id should not be called when project-id is provided + mock_get_project.assert_not_called() + # find_polarion_ids should be called with the CLI project ID + mock_find.assert_called_once_with( + polarion_project_id=cli_project_id, + string_to_match="added", + branch="origin/main", + ) + + @patch("apps.polarion.polarion_verify_tc_requirements.get_polarion_project_id") + @patch("apps.polarion.polarion_verify_tc_requirements.find_polarion_ids") + @patch("apps.polarion.polarion_verify_tc_requirements.validate_polarion_requirements") + def test_command_default_branch_parameter(self, mock_validate, mock_find, mock_get_project): + """Test command uses default branch when not specified""" + # Arrange + mock_get_project.return_value = "TEST_PROJECT" + mock_find.return_value = ["TEST-001"] + mock_validate.return_value = [] + + # Act + result = self.runner.invoke( + has_verify, + ["--project-id", "TEST_PROJECT"], + ) + + # Assert + assert result.exit_code == 0 + mock_find.assert_called_once_with( + polarion_project_id="TEST_PROJECT", + string_to_match="added", + branch="origin/main", # Default branch + ) + + @patch("apps.polarion.polarion_verify_tc_requirements.get_polarion_project_id") + @patch("apps.polarion.polarion_verify_tc_requirements.find_polarion_ids") + @patch("apps.polarion.polarion_verify_tc_requirements.validate_polarion_requirements") + def test_command_custom_branch_parameter(self, mock_validate, mock_find, mock_get_project): + """Test command with custom branch parameter""" + # Arrange + custom_branch = "origin/feature-branch" + mock_get_project.return_value = "TEST_PROJECT" + mock_find.return_value = ["TEST-001"] + mock_validate.return_value = [] + + # Act + result = self.runner.invoke( + has_verify, + ["--project-id", "TEST_PROJECT", "--branch", custom_branch], + ) + + # Assert + assert result.exit_code == 0 + mock_find.assert_called_once_with( + polarion_project_id="TEST_PROJECT", + string_to_match="added", + branch=custom_branch, + ) + + @patch("apps.polarion.polarion_verify_tc_requirements.get_polarion_project_id") + @patch("apps.polarion.polarion_verify_tc_requirements.find_polarion_ids") + @patch("apps.polarion.polarion_verify_tc_requirements.validate_polarion_requirements") + def test_command_short_option_flags(self, mock_validate, mock_find, mock_get_project): + """Test command with short option flags""" + # Arrange + mock_get_project.return_value = "TEST_PROJECT" + mock_find.return_value = ["TEST-001"] + mock_validate.return_value = [] + + # Act + result = self.runner.invoke( + has_verify, + ["-p", "TEST_PROJECT", "-b", "origin/develop"], + ) + + # Assert + assert result.exit_code == 0 + mock_find.assert_called_once_with( + polarion_project_id="TEST_PROJECT", + string_to_match="added", + branch="origin/develop", + ) + + @patch("apps.polarion.polarion_verify_tc_requirements.get_polarion_project_id") + @patch("apps.polarion.polarion_verify_tc_requirements.find_polarion_ids") + @patch("apps.polarion.polarion_verify_tc_requirements.validate_polarion_requirements") + @patch("sys.exit") + def test_command_with_multiple_missing_requirements(self, mock_exit, mock_validate, mock_find, mock_get_project): + """Test command with multiple test cases having missing requirements""" + # Arrange + mock_get_project.return_value = "TEST_PROJECT" + mock_find.return_value = ["TEST-001", "TEST-002", "TEST-003"] + mock_validate.return_value = ["TEST-001", "TEST-003"] # Multiple missing requirements + + # Act + result = self.runner.invoke( + has_verify, + ["--project-id", "TEST_PROJECT"], + ) + + # Assert + # sys.exit(1) should be called due to missing requirements + assert mock_exit.call_count >= 1 + assert 1 in [call.args[0] for call in mock_exit.call_args_list] + mock_validate.assert_called_once_with( + polarion_test_ids=["TEST-001", "TEST-002", "TEST-003"], + polarion_project_id="TEST_PROJECT", + ) + + @patch("apps.polarion.polarion_verify_tc_requirements.get_polarion_project_id") + @patch("apps.polarion.polarion_verify_tc_requirements.find_polarion_ids") + @patch("apps.polarion.polarion_verify_tc_requirements.validate_polarion_requirements") + def test_command_with_logger_debug_calls(self, mock_validate, mock_find, mock_get_project): + """Test that debug logging is called when verbose is enabled and IDs are found""" + # Arrange + mock_get_project.return_value = "TEST_PROJECT" + test_ids = ["TEST-001", "TEST-002"] + mock_find.return_value = test_ids + mock_validate.return_value = [] + + with patch("apps.polarion.polarion_verify_tc_requirements.LOGGER") as mock_logger: + # Act + result = self.runner.invoke( + has_verify, + ["--project-id", "TEST_PROJECT", "--verbose"], + ) + + # Assert + assert result.exit_code == 0 + # Verify debug logging was called with the test IDs + mock_logger.debug.assert_called_once_with(f"Checking following ids: {test_ids}") + + @patch("apps.polarion.polarion_verify_tc_requirements.get_polarion_project_id") + @patch("apps.polarion.polarion_verify_tc_requirements.find_polarion_ids") + @patch("apps.polarion.polarion_verify_tc_requirements.validate_polarion_requirements") + @patch("sys.exit") + def test_command_with_logger_error_calls(self, mock_exit, mock_validate, mock_find, mock_get_project): + """Test that error logging is called when missing requirements are found""" + # Arrange + mock_get_project.return_value = "TEST_PROJECT" + test_ids = ["TEST-001", "TEST-002"] + missing_requirements = ["TEST-001"] + mock_find.return_value = test_ids + mock_validate.return_value = missing_requirements + + with patch("apps.polarion.polarion_verify_tc_requirements.LOGGER") as mock_logger: + # Act + result = self.runner.invoke( + has_verify, + ["--project-id", "TEST_PROJECT"], + ) + + # Assert + # sys.exit(1) should be called due to missing requirements + assert mock_exit.call_count >= 1 + assert 1 in [call.args[0] for call in mock_exit.call_args_list] + # Verify error logging was called with the missing requirements + mock_logger.error.assert_called_once_with(f"TestCases with missing requirement: {missing_requirements}") + + def test_command_missing_required_params_not_applicable(self): + """Test that the command can run without explicit project-id (uses config)""" + # This command doesn't have required parameters since project-id can come from config + # So we test that it attempts to run (but may fail due to missing config) + + # We expect the command to run but potentially fail due to missing config file + result = self.runner.invoke(has_verify, []) + + # The exit code may vary depending on whether the default config file exists + # But the command should not fail due to missing required CLI parameters + assert result.exit_code in [0, 1] # May succeed or fail due to config, but not parameter validation + + @patch("apps.polarion.polarion_verify_tc_requirements.get_polarion_project_id") + @patch("apps.polarion.polarion_verify_tc_requirements.find_polarion_ids") + @patch("apps.polarion.polarion_verify_tc_requirements.validate_polarion_requirements") + def test_command_mixed_logging_scenarios(self, mock_validate, mock_find, mock_get_project): + """Test command behavior with mixed logging scenarios (debug and error)""" + # Arrange + mock_get_project.return_value = "TEST_PROJECT" + test_ids = ["TEST-001", "TEST-002"] + missing_requirements = ["TEST-002"] + mock_find.return_value = test_ids + mock_validate.return_value = missing_requirements + + with patch("apps.polarion.polarion_verify_tc_requirements.LOGGER") as mock_logger: + with patch("sys.exit") as mock_exit: + # Act + result = self.runner.invoke( + has_verify, + ["--project-id", "TEST_PROJECT", "--verbose"], + ) + + # Assert + # sys.exit(1) should be called due to missing requirements + assert mock_exit.call_count >= 1 + assert 1 in [call.args[0] for call in mock_exit.call_args_list] + # Verify both debug and error logging were called + mock_logger.debug.assert_called_once_with(f"Checking following ids: {test_ids}") + mock_logger.error.assert_called_once_with(f"TestCases with missing requirement: {missing_requirements}") + mock_logger.setLevel.assert_called_with(logging.DEBUG) \ No newline at end of file From 6f81565d57e370fd60c054848d6b9ea0dc11b040 Mon Sep 17 00:00:00 2001 From: Debarati Basu-Nag Date: Wed, 12 Nov 2025 09:00:01 -0500 Subject: [PATCH 3/4] updates to address precommit issues --- .../test_polarion_verify_tc_requirements_coverage.py | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/tests/polarion/test_polarion_verify_tc_requirements_coverage.py b/tests/polarion/test_polarion_verify_tc_requirements_coverage.py index e00bb41..deb8f36 100644 --- a/tests/polarion/test_polarion_verify_tc_requirements_coverage.py +++ b/tests/polarion/test_polarion_verify_tc_requirements_coverage.py @@ -6,7 +6,6 @@ from __future__ import annotations import logging -import sys from unittest.mock import MagicMock, patch from click.testing import CliRunner @@ -61,7 +60,7 @@ def test_command_fails_with_missing_requirements(self, mock_exit, mock_validate, mock_validate.return_value = ["TEST-001"] # Has missing requirements # Act - result = self.runner.invoke( + self.runner.invoke( has_verify, ["--project-id", "TEST_PROJECT"], ) @@ -286,7 +285,7 @@ def test_command_with_multiple_missing_requirements(self, mock_exit, mock_valida mock_validate.return_value = ["TEST-001", "TEST-003"] # Multiple missing requirements # Act - result = self.runner.invoke( + self.runner.invoke( has_verify, ["--project-id", "TEST_PROJECT"], ) @@ -338,7 +337,7 @@ def test_command_with_logger_error_calls(self, mock_exit, mock_validate, mock_fi with patch("apps.polarion.polarion_verify_tc_requirements.LOGGER") as mock_logger: # Act - result = self.runner.invoke( + self.runner.invoke( has_verify, ["--project-id", "TEST_PROJECT"], ) @@ -377,7 +376,7 @@ def test_command_mixed_logging_scenarios(self, mock_validate, mock_find, mock_ge with patch("apps.polarion.polarion_verify_tc_requirements.LOGGER") as mock_logger: with patch("sys.exit") as mock_exit: # Act - result = self.runner.invoke( + self.runner.invoke( has_verify, ["--project-id", "TEST_PROJECT", "--verbose"], ) @@ -389,4 +388,4 @@ def test_command_mixed_logging_scenarios(self, mock_validate, mock_find, mock_ge # Verify both debug and error logging were called mock_logger.debug.assert_called_once_with(f"Checking following ids: {test_ids}") mock_logger.error.assert_called_once_with(f"TestCases with missing requirement: {missing_requirements}") - mock_logger.setLevel.assert_called_with(logging.DEBUG) \ No newline at end of file + mock_logger.setLevel.assert_called_with(logging.DEBUG) From 8a34d04899af5a9b5e02102191b757c5b09c8572 Mon Sep 17 00:00:00 2001 From: Debarati Basu-Nag Date: Wed, 12 Nov 2025 16:05:29 -0500 Subject: [PATCH 4/4] code rabbit's comments were addressed --- .../test_polarion_set_automated_coverage.py | 8 ++++---- ...est_polarion_verify_tc_requirements_coverage.py | 14 +------------- 2 files changed, 5 insertions(+), 17 deletions(-) diff --git a/tests/polarion/test_polarion_set_automated_coverage.py b/tests/polarion/test_polarion_set_automated_coverage.py index 793fd25..f47e276 100644 --- a/tests/polarion/test_polarion_set_automated_coverage.py +++ b/tests/polarion/test_polarion_set_automated_coverage.py @@ -103,7 +103,7 @@ def test_remove_approved_tests_with_removals(self, mock_update, mock_find): current_commit=curr_commit, ) # Verify the call was made with the correct IDs (order-independent) - args, kwargs = mock_update.call_args + _, kwargs = mock_update.call_args assert set(kwargs["polarion_ids"]) == {"TEST-002", "TEST-003"} # Should exclude added_ids overlap assert kwargs["project_id"] == project_id assert kwargs["is_automated"] is False @@ -355,7 +355,7 @@ def test_command_uses_config_file_project_id(self, mock_get_project): # Assert assert result.exit_code == 0 # Check that get_polarion_project_id was called with default config path - args, kwargs = mock_get_project.call_args + _, kwargs = mock_get_project.call_args assert kwargs["util_name"] == "pyutils-polarion-set-automated" assert kwargs["config_file_path"].endswith("/.config/python-utility-scripts/config.yaml") @@ -385,7 +385,7 @@ def test_command_both_add_and_remove_failures(self, mock_remove, mock_find, mock @patch("apps.polarion.polarion_set_automated.find_polarion_ids") @patch("apps.polarion.polarion_set_automated.approve_tests") @patch("apps.polarion.polarion_set_automated.remove_approved_tests") - def test_command_custom_config_file_path(self, mock_remove, mock_approve, mock_find, mock_get_project): + def test_command_custom_config_file_path(self, mock_remove, _mock_approve, mock_find, mock_get_project): """Test command with custom config file path""" # Arrange custom_config_path = "/custom/path/config.yaml" @@ -409,7 +409,7 @@ def test_command_custom_config_file_path(self, mock_remove, mock_approve, mock_f @patch("apps.polarion.polarion_set_automated.find_polarion_ids") @patch("apps.polarion.polarion_set_automated.approve_tests") @patch("apps.polarion.polarion_set_automated.remove_approved_tests") - def test_command_project_id_override_config(self, mock_remove, mock_approve, mock_find, mock_get_project): + def test_command_project_id_override_config(self, mock_remove, _mock_approve, mock_find, mock_get_project): """Test that command line project ID overrides config file""" # Arrange cli_project_id = "CLI_PROJECT" diff --git a/tests/polarion/test_polarion_verify_tc_requirements_coverage.py b/tests/polarion/test_polarion_verify_tc_requirements_coverage.py index deb8f36..15ede07 100644 --- a/tests/polarion/test_polarion_verify_tc_requirements_coverage.py +++ b/tests/polarion/test_polarion_verify_tc_requirements_coverage.py @@ -150,7 +150,7 @@ def test_command_uses_config_file_project_id(self, mock_get_project): # Assert assert result.exit_code == 0 # Check that get_polarion_project_id was called with default config path - args, kwargs = mock_get_project.call_args + _, kwargs = mock_get_project.call_args assert kwargs["util_name"] == "pyutils-polarion-verify-tc-requirements" assert kwargs["config_file_path"].endswith("/.config/python-utility-scripts/config.yaml") @@ -349,18 +349,6 @@ def test_command_with_logger_error_calls(self, mock_exit, mock_validate, mock_fi # Verify error logging was called with the missing requirements mock_logger.error.assert_called_once_with(f"TestCases with missing requirement: {missing_requirements}") - def test_command_missing_required_params_not_applicable(self): - """Test that the command can run without explicit project-id (uses config)""" - # This command doesn't have required parameters since project-id can come from config - # So we test that it attempts to run (but may fail due to missing config) - - # We expect the command to run but potentially fail due to missing config file - result = self.runner.invoke(has_verify, []) - - # The exit code may vary depending on whether the default config file exists - # But the command should not fail due to missing required CLI parameters - assert result.exit_code in [0, 1] # May succeed or fail due to config, but not parameter validation - @patch("apps.polarion.polarion_verify_tc_requirements.get_polarion_project_id") @patch("apps.polarion.polarion_verify_tc_requirements.find_polarion_ids") @patch("apps.polarion.polarion_verify_tc_requirements.validate_polarion_requirements")