diff --git a/docs/messaging.rst b/docs/messaging.rst index faf93ba2..66b380d6 100644 --- a/docs/messaging.rst +++ b/docs/messaging.rst @@ -37,7 +37,7 @@ new test result message from ResultsDB. "applicable_policies": ["osci_compose_modules"], "policies_satisfied": false, - "summary": "Of 2 required test(s), 1 result(s) missing", + "summary": "Of 2 required tests, 1 result missing", "satisfied_requirements": [{ "result_id": 7483048, "testcase": "osci.redhat-module.installability.functional", @@ -58,7 +58,7 @@ new test result message from ResultsDB. "previous": { "applicable_policies": ["osci_compose_modules"], "policies_satisfied": false, - "summary": "Of 2 required test(s), 1 test(s) failed", + "summary": "Of 2 required tests, 1 test failed", "satisfied_requirements": [{ "result_id": 7483048, "testcase": "osci.redhat-module.installability.functional", diff --git a/docs/package-specific-policies.rst b/docs/package-specific-policies.rst index 5776db6d..a0f08296 100644 --- a/docs/package-specific-policies.rst +++ b/docs/package-specific-policies.rst @@ -98,7 +98,7 @@ For such policy, missing remote rule file could result in the following decision "applicable_policies": ["some_policy"], "policies_satisfied": false, "satisfied_requirements": [] - "summary": "Of 1 required test(s), 1 test(s) failed", + "summary": "Of 1 required test, 1 test failed", "unsatisfied_requirements": [{ "subject_identifier": "nethack-1.2.3-1.f31", "subject_type": "koji_build", diff --git a/functional-tests/consumers/test_resultsdb.py b/functional-tests/consumers/test_resultsdb.py index ffcc202d..dbad384c 100644 --- a/functional-tests/consumers/test_resultsdb.py +++ b/functional-tests/consumers/test_resultsdb.py @@ -89,7 +89,7 @@ def test_consume_new_result( 'source': None, } ], - 'summary': 'Of 3 required test(s), 2 result(s) missing', + 'summary': 'Of 3 required tests, 2 results missing', 'subject': [ {'item': nvr, 'type': 'koji_build'}, ], @@ -101,7 +101,7 @@ def test_consume_new_result( 'applicable_policies': ['taskotron_release_critical_tasks_with_blocklist', 'taskotron_release_critical_tasks'], 'policies_satisfied': False, - 'summary': 'Of 3 required test(s), 3 result(s) missing', + 'summary': 'Of 3 required tests, 3 results missing', 'satisfied_requirements': [], 'unsatisfied_requirements': [ { @@ -162,7 +162,7 @@ def test_consume_new_result( 'previous': { 'applicable_policies': ['taskotron_release_critical_tasks_for_testing'], 'policies_satisfied': False, - 'summary': 'Of 1 required test(s), 1 result(s) missing', + 'summary': 'Of 1 required test, 1 result missing', 'satisfied_requirements': [], 'unsatisfied_requirements': [ { @@ -260,7 +260,7 @@ def test_consume_compose_id_result( 'subject': [{'productmd.compose.id': compose_id}], 'subject_type': 'compose', 'subject_identifier': compose_id, - 'summary': 'Of 2 required test(s), 1 result(s) missing', + 'summary': 'Of 2 required tests, 1 result missing', 'previous': old_decision, 'satisfied_requirements': [{ 'subject_type': 'compose', @@ -380,7 +380,7 @@ def test_consume_legacy_result( 'source': None, } ], - 'summary': 'Of 3 required test(s), 2 result(s) missing', + 'summary': 'Of 3 required tests, 2 results missing', 'subject': [ { 'item': nvr, diff --git a/functional-tests/consumers/test_waiverdb.py b/functional-tests/consumers/test_waiverdb.py index ed2588e3..ad963091 100644 --- a/functional-tests/consumers/test_waiverdb.py +++ b/functional-tests/consumers/test_waiverdb.py @@ -77,7 +77,7 @@ def test_consume_new_waiver( 'applicable_policies': ['taskotron_release_critical_tasks_with_blocklist', 'taskotron_release_critical_tasks'], 'policies_satisfied': False, - 'summary': 'Of 3 required test(s), 1 test(s) failed', + 'summary': 'Of 3 required tests, 1 test failed', 'satisfied_requirements': [ { 'subject_type': 'koji_build', diff --git a/functional-tests/test_api_v1.py b/functional-tests/test_api_v1.py index c7aca0c6..d858b7a9 100644 --- a/functional-tests/test_api_v1.py +++ b/functional-tests/test_api_v1.py @@ -391,7 +391,7 @@ def test_make_a_decision_on_failed_result(requests_session, greenwave_server, te assert res_data['policies_satisfied'] is False assert 'taskotron_release_critical_tasks' in res_data['applicable_policies'] assert 'taskotron_release_critical_tasks_with_blocklist' in res_data['applicable_policies'] - expected_summary = 'Of 3 required test(s), 1 test(s) failed, 2 result(s) missing' + expected_summary = 'Of 3 required tests, 1 test failed, 2 results missing' assert res_data['summary'] == expected_summary expected_unsatisfied_requirements = [ { @@ -437,7 +437,7 @@ def test_make_a_decision_on_queued_result(requests_session, greenwave_server, te assert res_data['policies_satisfied'] is False assert 'taskotron_release_critical_tasks' in res_data['applicable_policies'] assert 'taskotron_release_critical_tasks_with_blocklist' in res_data['applicable_policies'] - expected_summary = 'Of 3 required test(s), 1 test(s) incomplete, 2 result(s) missing' + expected_summary = 'Of 3 required tests, 1 test incomplete, 2 results missing' assert res_data['summary'] == expected_summary expected_unsatisfied_requirements = [ { @@ -483,7 +483,7 @@ def test_make_a_decision_on_running_result(requests_session, greenwave_server, t assert res_data['policies_satisfied'] is False assert 'taskotron_release_critical_tasks' in res_data['applicable_policies'] assert 'taskotron_release_critical_tasks_with_blocklist' in res_data['applicable_policies'] - expected_summary = 'Of 3 required test(s), 1 test(s) incomplete, 2 result(s) missing' + expected_summary = 'Of 3 required tests, 1 test incomplete, 2 results missing' assert res_data['summary'] == expected_summary expected_unsatisfied_requirements = [ { @@ -526,7 +526,7 @@ def test_make_a_decision_on_no_results(requests_session, greenwave_server, testd assert res_data['policies_satisfied'] is False assert 'taskotron_release_critical_tasks' in res_data['applicable_policies'] assert 'taskotron_release_critical_tasks_with_blocklist' in res_data['applicable_policies'] - expected_summary = 'Of 3 required test(s), 3 result(s) missing' + expected_summary = 'Of 3 required tests, 3 results missing' assert res_data['summary'] == expected_summary expected_unsatisfied_requirements = [ { @@ -571,7 +571,7 @@ def test_make_a_decision_on_redhat_cont_image(requests_session, greenwave_server assert r.status_code == 200 res_data = r.json() assert res_data['policies_satisfied'] is False - expected_summary = 'Of 2 required test(s), 2 test(s) failed' + expected_summary = 'Of 2 required tests, 2 tests failed' assert res_data['summary'] == expected_summary expected_unsatisfied_requirements = [ { @@ -723,7 +723,7 @@ def test_multiple_results_in_a_subject( assert res_data['policies_satisfied'] is False assert 'taskotron_release_critical_tasks' in res_data['applicable_policies'] assert 'taskotron_release_critical_tasks_with_blocklist' in res_data['applicable_policies'] - assert res_data['summary'] == 'Of 3 required test(s), 1 test(s) failed' + assert res_data['summary'] == 'Of 3 required tests, 1 test failed' expected_unsatisfied_requirements = [ { 'item': {'item': nvr, 'type': 'koji_build'}, @@ -859,7 +859,7 @@ def test_make_a_decision_on_failing_result_with_scenario( res_data = r.json() assert res_data['policies_satisfied'] is False assert res_data['applicable_policies'] == ['openqa_important_stuff_for_rawhide'] - expected_summary = 'Of 2 required test(s), 1 test(s) failed' + expected_summary = 'Of 2 required tests, 1 test failed' assert res_data['summary'] == expected_summary expected_unsatisfied_requirements = [{ 'item': {'productmd.compose.id': compose_id}, diff --git a/greenwave/policies.py b/greenwave/policies.py index 4fc7a5eb..01f1bea6 100644 --- a/greenwave/policies.py +++ b/greenwave/policies.py @@ -141,7 +141,7 @@ class RuleNotSatisfied(Answer): """ is_satisfied = False - summary_text = "unexpected unsatisfied requirement(s)" + summary_text = "unexpected unsatisfied requirement{s}" def to_json(self): raise NotImplementedError() @@ -165,7 +165,7 @@ class TestResultMissing(RuleNotSatisfied): ResultsDB with a matching item and test case name). """ - summary_text = "result(s) missing" + summary_text = "result{s} missing" def __init__(self, subject, test_case_name, scenario, source): self.subject = subject @@ -196,7 +196,7 @@ class TestResultIncomplete(RuleNotSatisfied): result outcomes in ResultsDB with a matching item and test case name). """ - summary_text = "test(s) incomplete" + summary_text = "test{s} incomplete" def __init__(self, subject, test_case_name, source, result_id, data): self.subject = subject @@ -257,7 +257,7 @@ class TestResultFailed(RuleNotSatisfied): not passing). """ - summary_text = "test(s) failed" + summary_text = "test{s} failed" def __init__(self, subject, test_case_name, source, result_id, data): self.subject = subject @@ -298,7 +298,7 @@ class TestResultErrored(RuleNotSatisfied): was an error). """ - summary_text = "test(s) errored" + summary_text = "test{s} errored" def __init__( self, @@ -348,7 +348,7 @@ class InvalidRemoteRuleYaml(RuleNotSatisfied): scenario = None is_test_result = False - summary_text = "non-test-result unsatisfied requirement(s) (gating.yaml issues)" + summary_text = "non-test-result unsatisfied requirement{s} (gating.yaml is invalid)" def __init__(self, subject, test_case_name, details, source): self.subject = subject @@ -379,7 +379,7 @@ class MissingRemoteRuleYaml(RuleNotSatisfied): test_case_name = 'missing-gating-yaml' scenario = None is_test_result = False - summary_text = "non-test-result unsatisfied requirement(s) (gating.yaml issues)" + summary_text = "non-test-result unsatisfied requirement{s} (gating.yaml was not found)" def __init__(self, subject, sources): self.subject = subject @@ -407,7 +407,7 @@ class FailedFetchRemoteRuleYaml(RuleNotSatisfied): test_case_name = 'failed-fetch-gating-yaml' scenario = None is_test_result = False - summary_text = "non-test-result unsatisfied requirement(s) (gating.yaml issues)" + summary_text = "non-test-result unsatisfied requirement{s} (failed to fetch gating.yaml)" def __init__(self, subject, sources, error): self.subject = subject @@ -506,16 +506,24 @@ def __init__(self): def to_text(self, test_count): msgstr = "" if self.non_test_msgs: - msgstr = ", ".join(f"{num} {msg}" for (msg, num) in self.non_test_msgs.items()) + msgstr = ", ".join( + self.sformat(f"{{num}} {msg}", num) for (msg, num) in self.non_test_msgs.items() + ) if self.test_msgs: - addmsg = f"Of {test_count} required test(s), " - addmsg += ", ".join(f"{num} {msg}" for (msg, num) in self.test_msgs.items()) + addmsg = self.sformat("Of {num} required test{s}, ", test_count) + addmsg += ", ".join( + self.sformat(f"{{num}} {msg}", num) for (msg, num) in self.test_msgs.items() + ) if msgstr: msgstr = f"{msgstr}. {addmsg}" else: msgstr = addmsg return msgstr + @staticmethod + def sformat(text: str, number: int) -> str: + return text.format(num=number, s='s' if number != 1 else '') + def summarize_answers(answers): """ diff --git a/greenwave/tests/test_api_v1.py b/greenwave/tests/test_api_v1.py index f12ecba1..8d39a883 100644 --- a/greenwave/tests/test_api_v1.py +++ b/greenwave/tests/test_api_v1.py @@ -72,7 +72,7 @@ def test_make_decision_retrieves_waivers_on_missing(mock_results, mock_waivers, mock_waivers.return_value = [] response = make_decision() assert 200 == response.status_code - assert 'Of 1 required test(s), 1 result(s) missing' == response.json['summary'] + assert 'Of 1 required test, 1 result missing' == response.json['summary'] mock_waivers.assert_called_once() @@ -81,7 +81,7 @@ def test_make_decision_retrieves_waivers_on_failed(mock_results, mock_waivers, m mock_waivers.return_value = [] response = make_decision() assert 200 == response.status_code - assert 'Of 1 required test(s), 1 test(s) failed' == response.json['summary'] + assert 'Of 1 required test, 1 test failed' == response.json['summary'] mock_waivers.assert_called_once() @@ -100,7 +100,7 @@ def test_make_decision_retrieves_waivers_on_errored(mock_results, mock_waivers, mock_waivers.return_value = [] response = make_decision() assert 200 == response.status_code - assert 'Of 1 required test(s), 1 test(s) errored' == response.json['summary'] + assert 'Of 1 required test, 1 test errored' == response.json['summary'] mock_waivers.assert_called_once() @@ -110,7 +110,7 @@ def test_make_decision_retrieves_waivers_once_on_verbose_and_missing( mock_waivers.return_value = [] response = make_decision(verbose=True) assert 200 == response.status_code - assert 'Of 1 required test(s), 1 result(s) missing' == response.json['summary'] + assert 'Of 1 required test, 1 result missing' == response.json['summary'] mock_waivers.assert_called_once() @@ -245,7 +245,7 @@ def test_make_decision_with_missing_required_gating_yaml(mock_results, mock_waiv response = make_decision(policies=policies) assert 200 == response.status_code assert not response.json['policies_satisfied'] - exp = '1 non-test-result unsatisfied requirement(s) (gating.yaml issues)' + exp = '1 non-test-result unsatisfied requirement (gating.yaml was not found)' assert exp == response.json['summary'] mock_waivers.assert_called_once() @@ -283,7 +283,7 @@ def test_make_decision_multiple_contexts(mock_results, mock_waivers, make_decisi """ response = make_decision(policies=policies, decision_context=["test_policies", "test_2"]) assert 200 == response.status_code - assert 'Of 2 required test(s), 2 test(s) failed' == response.json['summary'] + assert 'Of 2 required tests, 2 tests failed' == response.json['summary'] assert ['test_policy', 'test_policy_2'] == response.json['applicable_policies'] mock_waivers.assert_called_once() diff --git a/greenwave/tests/test_policies.py b/greenwave/tests/test_policies.py index 05f8dd2b..506edf7e 100644 --- a/greenwave/tests/test_policies.py +++ b/greenwave/tests/test_policies.py @@ -86,15 +86,15 @@ def test_summarize_answers(): assert summarize_answers([testResultPassed]) == \ 'All required tests passed or waived' assert summarize_answers([testResultFailed, testResultPassed]) == \ - 'Of 2 required test(s), 1 test(s) failed' + 'Of 2 required tests, 1 test failed' assert summarize_answers([testResultMissing]) == \ - 'Of 1 required test(s), 1 result(s) missing' + 'Of 1 required test, 1 result missing' assert summarize_answers([testResultFailed, testResultMissing]) == \ - 'Of 2 required test(s), 1 test(s) failed, 1 result(s) missing' + 'Of 2 required tests, 1 test failed, 1 result missing' assert summarize_answers([testResultFailed, testResultMissing, testResultMissing]) == \ - 'Of 3 required test(s), 1 test(s) failed, 2 result(s) missing' + 'Of 3 required tests, 1 test failed, 2 results missing' assert summarize_answers([testResultMissing, testResultPassed]) == \ - 'Of 2 required test(s), 1 result(s) missing' + 'Of 2 required tests, 1 result missing' def test_decision_with_missing_result(tmpdir): diff --git a/greenwave/tests/test_summary.py b/greenwave/tests/test_summary.py index 58ccf82b..1192f223 100644 --- a/greenwave/tests/test_summary.py +++ b/greenwave/tests/test_summary.py @@ -44,21 +44,21 @@ def test_summary_failed(): answers = [ testResultFailed, ] - assert summarize_answers(answers) == 'Of 1 required test(s), 1 test(s) failed' + assert summarize_answers(answers) == 'Of 1 required test, 1 test failed' def test_summary_incomplete(): answers = [ testResultIncomplete, ] - assert summarize_answers(answers) == 'Of 1 required test(s), 1 test(s) incomplete' + assert summarize_answers(answers) == 'Of 1 required test, 1 test incomplete' def test_summary_missing(): answers = [ testResultMissing, ] - assert summarize_answers(answers) == 'Of 1 required test(s), 1 result(s) missing' + assert summarize_answers(answers) == 'Of 1 required test, 1 result missing' def test_summary_missing_waived(): @@ -72,7 +72,7 @@ def test_summary_errored(): answers = [ testResultErrored, ] - assert summarize_answers(answers) == 'Of 1 required test(s), 1 test(s) errored' + assert summarize_answers(answers) == 'Of 1 required test, 1 test errored' def test_summary_one_passed_one_failed(): @@ -80,7 +80,7 @@ def test_summary_one_passed_one_failed(): testResultPassed, testResultFailed, ] - assert summarize_answers(answers) == 'Of 2 required test(s), 1 test(s) failed' + assert summarize_answers(answers) == 'Of 2 required tests, 1 test failed' def test_summary_one_passed_one_missing(): @@ -88,7 +88,7 @@ def test_summary_one_passed_one_missing(): testResultPassed, testResultMissing, ] - assert summarize_answers(answers) == 'Of 2 required test(s), 1 result(s) missing' + assert summarize_answers(answers) == 'Of 2 required tests, 1 result missing' def test_summary_one_passed_one_missing_waived(): @@ -104,7 +104,7 @@ def test_summary_one_failed_one_missing(): testResultFailed, testResultMissing, ] - exp = 'Of 2 required test(s), 1 test(s) failed, 1 result(s) missing' + exp = 'Of 2 required tests, 1 test failed, 1 result missing' assert summarize_answers(answers) == exp @@ -114,7 +114,7 @@ def test_summary_one_passed_one_failed_one_missing(): testResultFailed, testResultMissing, ] - exp = 'Of 3 required test(s), 1 test(s) failed, 1 result(s) missing' + exp = 'Of 3 required tests, 1 test failed, 1 result missing' assert summarize_answers(answers) == exp @@ -126,7 +126,7 @@ def test_summary_one_passed_one_failed_one_missing_two_errored(): testResultMissing, testResultErrored, ] - exp = 'Of 5 required test(s), 2 test(s) errored, 1 test(s) failed, 1 result(s) missing' + exp = 'Of 5 required tests, 2 tests errored, 1 test failed, 1 result missing' assert summarize_answers(answers) == exp @@ -134,7 +134,7 @@ def test_summary_invalid_gating_yaml(): answers = [ testInvalidGatingYaml, ] - exp = '1 non-test-result unsatisfied requirement(s) (gating.yaml issues)' + exp = '1 non-test-result unsatisfied requirement (gating.yaml is invalid)' assert summarize_answers(answers) == exp @@ -144,6 +144,6 @@ def test_summary_one_passed_one_invalid_gating_yaml_one_missing(): testResultMissing, testInvalidGatingYaml, ] - exp = '1 non-test-result unsatisfied requirement(s) (gating.yaml issues). ' - exp += 'Of 2 required test(s), 1 result(s) missing' + exp = '1 non-test-result unsatisfied requirement (gating.yaml is invalid). ' + exp += 'Of 2 required tests, 1 result missing' assert summarize_answers(answers) == exp