From 9b29ecb7e0c066bebe91f40fd997f59e43afc56a Mon Sep 17 00:00:00 2001 From: Alberto Bellotti Date: Tue, 28 Nov 2023 14:20:38 -0500 Subject: [PATCH] test(insights): Preferring to patch.object sys.argv - Preferring to do a patch.object on sys.argv instead of overwriting the argument list. - Using get defaults instead of or for expires_in and interval. - Rebasing with main/updated rst manpage generation --- docs/_build/QPC_VAR_PROGRAM_NAME.1 | 24 ++++--------- docs/_build/man-qpc.rst | 2 +- docs/_build/qpc.1 | 26 ++++---------- poetry.lock | 2 +- qpc/insights/auth.py | 4 +-- qpc/insights/test_insights_configure.py | 48 +++++++++++++++---------- qpc/insights/test_insights_login.py | 19 +++++----- qpc/insights/test_insights_publish.py | 44 ++++++++++++----------- 8 files changed, 82 insertions(+), 87 deletions(-) diff --git a/docs/_build/QPC_VAR_PROGRAM_NAME.1 b/docs/_build/QPC_VAR_PROGRAM_NAME.1 index beaf1623..d6f09ac4 100644 --- a/docs/_build/QPC_VAR_PROGRAM_NAME.1 +++ b/docs/_build/QPC_VAR_PROGRAM_NAME.1 @@ -877,25 +877,13 @@ Optional. Sets the port to use to connect to Insights. The default port is \fB44 Optional. Determines whether to use HTTP instead of HTTPS. The default value is \fBFalse\fP\&. .UNINDENT .UNINDENT -.SS Adding Insights credentials information +.SS Login to Insights .sp -To configure Insights credentials, simply provide the appropriate username and password associated with your Insights account. +To be able to publish reports to Insights, one must be authorized and successfully logged into Insights. .sp -\fBQPC_VAR_PROGRAM_NAME insights add_login [\-\-username=\fP \fIusername\fP \fB] [\-\-password=\fP \fIpassword\fP \fB]\fP +\fBQPC_VAR_PROGRAM_NAME insights login\fP .sp -\fB\-\-username=username\fP -.INDENT 0.0 -.INDENT 3.5 -Required. Sets the username that is used to log in to Insights. -.UNINDENT -.UNINDENT -.sp -\fB\-\-password=password\fP -.INDENT 0.0 -.INDENT 3.5 -Required. Prompts for the password for the \fB\-\-username\fP identity. -.UNINDENT -.UNINDENT +This command requests the authorization of the user to Insights. A user code and associated authorization URL is displayed that the user can access in a separate browser window to login to Insights and be authorized to use {{QPC_VAR_PROGRAM_NAME}} to publish reports. .SS Publishing to Insights .sp The \fBQPC_VAR_PROGRAM_NAME insights publish\fP command allows you to publish an Insights report to Red Hat Insights and its services. You have two options for publishing a report: use the associated report identifier from the generating scan, or provide a previously downloaded report as an input file. @@ -1095,9 +1083,9 @@ Configuring Insights .sp \fBQPC_VAR_PROGRAM_NAME insights config \-\-host stage.console.redhat.com \-\-port 8080\fP .IP \(bu 2 -Adding Insights credentials +Login to Insights .sp -\fBQPC_VAR_PROGRAM_NAME insights add_login \-\-username insights\-user \-\-password\fP +\fBQPC_VAR_PROGRAM_NAME insights login\fP .IP \(bu 2 Publishing to Insights using a report id .sp diff --git a/docs/_build/man-qpc.rst b/docs/_build/man-qpc.rst index d5f5a07c..b229778a 100644 --- a/docs/_build/man-qpc.rst +++ b/docs/_build/man-qpc.rst @@ -696,7 +696,7 @@ To be able to publish reports to Insights, one must be authorized and successful **qpc insights login** -This command requests the authorization of the user to Insights. A user code and associated authorization URL is displayed that the user can access in a separate browser window to login to Insights and be authorized to use qpc to publish reports. +This command requests the authorization of the user to Insights. A user code and associated authorization URL is displayed that the user can access in a separate browser window to login to Insights and be authorized to use {{qpc}} to publish reports. Publishing to Insights diff --git a/docs/_build/qpc.1 b/docs/_build/qpc.1 index bc9a646e..bb1631bc 100644 --- a/docs/_build/qpc.1 +++ b/docs/_build/qpc.1 @@ -27,7 +27,7 @@ level margin: \\n[rst2man-indent\\n[rst2man-indent-level]] .\" new: \\n[rst2man-indent\\n[rst2man-indent-level]] .in \\n[rst2man-indent\\n[rst2man-indent-level]]u .. -.TH "qpc" "1" "November 27, 2023" "" "qpc" +.TH "qpc" "1" "November 28, 2023" "" "qpc" .SH NAME .sp qpc \- Inspect and report on product entitlement metadata from various sources, including networks and systems management solutions. @@ -877,25 +877,13 @@ Optional. Sets the port to use to connect to Insights. The default port is \fB44 Optional. Determines whether to use HTTP instead of HTTPS. The default value is \fBFalse\fP\&. .UNINDENT .UNINDENT -.SS Adding Insights credentials information +.SS Login to Insights .sp -To configure Insights credentials, simply provide the appropriate username and password associated with your Insights account. +To be able to publish reports to Insights, one must be authorized and successfully logged into Insights. .sp -\fBqpc insights add_login [\-\-username=\fP \fIusername\fP \fB] [\-\-password=\fP \fIpassword\fP \fB]\fP +\fBqpc insights login\fP .sp -\fB\-\-username=username\fP -.INDENT 0.0 -.INDENT 3.5 -Required. Sets the username that is used to log in to Insights. -.UNINDENT -.UNINDENT -.sp -\fB\-\-password=password\fP -.INDENT 0.0 -.INDENT 3.5 -Required. Prompts for the password for the \fB\-\-username\fP identity. -.UNINDENT -.UNINDENT +This command requests the authorization of the user to Insights. A user code and associated authorization URL is displayed that the user can access in a separate browser window to login to Insights and be authorized to use {{qpc}} to publish reports. .SS Publishing to Insights .sp The \fBqpc insights publish\fP command allows you to publish an Insights report to Red Hat Insights and its services. You have two options for publishing a report: use the associated report identifier from the generating scan, or provide a previously downloaded report as an input file. @@ -1095,9 +1083,9 @@ Configuring Insights .sp \fBqpc insights config \-\-host stage.console.redhat.com \-\-port 8080\fP .IP \(bu 2 -Adding Insights credentials +Login to Insights .sp -\fBqpc insights add_login \-\-username insights\-user \-\-password\fP +\fBqpc insights login\fP .IP \(bu 2 Publishing to Insights using a report id .sp diff --git a/poetry.lock b/poetry.lock index 05cbe95b..ba1f955d 100644 --- a/poetry.lock +++ b/poetry.lock @@ -1348,4 +1348,4 @@ files = [ [metadata] lock-version = "2.0" python-versions = "^3.11" -content-hash = "bd8eae5dd89ef642f943f23f9cd21f44d1694a75c8c19a1deb216e3ca2ec1faf" +content-hash = "d1a67a54bd3a2b9f8e5db016e3feb2f5d40437c6c35c232f6d28293a8beb34c9" diff --git a/qpc/insights/auth.py b/qpc/insights/auth.py index 5dead0a4..55805097 100644 --- a/qpc/insights/auth.py +++ b/qpc/insights/auth.py @@ -95,8 +95,8 @@ def wait_for_authorization(self): # noqa: C901 PLR0912 """ if self.auth_request: device_code = self.auth_request["device_code"] - interval = self.auth_request.get("interval") or 5 # SSO default - expires_in = self.auth_request.get("expires_in") or 600 # SSO default + interval = self.auth_request.get("interval", 5) # SSO default + expires_in = self.auth_request.get("expires_in", 600) # SSO default elapsed_time = 0 self.auth_token = None diff --git a/qpc/insights/test_insights_configure.py b/qpc/insights/test_insights_configure.py index 937bb50c..b2ee7e05 100644 --- a/qpc/insights/test_insights_configure.py +++ b/qpc/insights/test_insights_configure.py @@ -1,5 +1,6 @@ """Test the CLI module.""" import sys +from unittest import mock import pytest @@ -21,26 +22,26 @@ class TestInsightsConfigure: def test_insights_config_bad_port(self): """Testing insights configure when receiving bad port.""" - sys.argv = ["/bin/qpc", "insights", "config", "--port", "abc"] - with pytest.raises(SystemExit): + test_argv = ["/bin/qpc", "insights", "config", "--port", "abc"] + with pytest.raises(SystemExit), mock.patch.object(sys, "argv", test_argv): CLI().main() def test_insights_config_empty_host(self): """Testing insights configure when receiving empty host.""" - sys.argv = ["/bin/qpc", "insights", "config", "--host", ""] - with pytest.raises(SystemExit): + test_argv = ["/bin/qpc", "insights", "config", "--host", ""] + with pytest.raises(SystemExit), mock.patch.object(sys, "argv", test_argv): CLI().main() def test_insights_config_bad_host(self): """Testing insights configure when receiving bad host.""" - sys.argv = ["/bin/qpc", "insights", "config", "--host", None] - with pytest.raises(SystemExit): + test_argv = ["/bin/qpc", "insights", "config", "--host", None] + with pytest.raises(SystemExit), mock.patch.object(sys, "argv", test_argv): CLI().main() def test_insights_config_bad_sso_host(self): """Testing insights configure when receiving bad sso host.""" - sys.argv = ["/bin/qpc", "insights", "config", "--sso-host", None] - with pytest.raises(SystemExit): + test_argv = ["/bin/qpc", "insights", "config", "--sso-host", None] + with pytest.raises(SystemExit), mock.patch.object(sys, "argv", test_argv): CLI().main() def test_success_default_config_no_args(self): @@ -51,7 +52,7 @@ def test_success_default_config_no_args(self): def test_success_config_insights(self): """Testing insights configure green path.""" - sys.argv = [ + test_argv = [ "/bin/qpc", "insights", "config", @@ -61,7 +62,8 @@ def test_success_config_insights(self): "200", "--use-http", ] - CLI().main() + with mock.patch.object(sys, "argv", test_argv): + CLI().main() config = read_insights_config() assert config["host"] == "console.insights.test" assert config["port"] == 200 @@ -69,7 +71,7 @@ def test_success_config_insights(self): def test_success_config_insights_with_sso_host(self): """Testing insights configure green path with sso host.""" - sys.argv = [ + test_argv = [ "/bin/qpc", "insights", "config", @@ -81,7 +83,8 @@ def test_success_config_insights_with_sso_host(self): "--sso-host", "sso.insights.test", ] - CLI().main() + with mock.patch.object(sys, "argv", test_argv): + CLI().main() config = read_insights_config() assert config["host"] == "console.insights.test" assert config["port"] == 200 @@ -90,8 +93,9 @@ def test_success_config_insights_with_sso_host(self): def test_insights_config_default_host(self): """Testing insights configure default host.""" - sys.argv = ["/bin/qpc", "insights", "config", "--port", "200"] - CLI().main() + test_argv = ["/bin/qpc", "insights", "config", "--port", "200"] + with mock.patch.object(sys, "argv", test_argv): + CLI().main() config = read_insights_config() assert config["host"] == DEFAULT_HOST_INSIGHTS_CONFIG assert config["port"] == 200 @@ -99,8 +103,15 @@ def test_insights_config_default_host(self): def test_insights_config_default_port(self): """Testing insights configure default port.""" - sys.argv = ["/bin/qpc", "insights", "config", "--host", "console.insights.test"] - CLI().main() + test_argv = [ + "/bin/qpc", + "insights", + "config", + "--host", + "console.insights.test", + ] + with mock.patch.object(sys, "argv", test_argv): + CLI().main() config = read_insights_config() assert config["host"] == "console.insights.test" assert config["port"] == DEFAULT_PORT_INSIGHTS_CONFIG @@ -108,7 +119,7 @@ def test_insights_config_default_port(self): def test_insights_config_default_sso_host(self): """Testing insights configure default sso host.""" - sys.argv = [ + test_argv = [ "/bin/qpc", "insights", "config", @@ -117,7 +128,8 @@ def test_insights_config_default_sso_host(self): "--port", "200", ] - CLI().main() + with mock.patch.object(sys, "argv", test_argv): + CLI().main() config = read_insights_config() assert config["host"] == "console.insights.test" assert config["port"] == 200 diff --git a/qpc/insights/test_insights_login.py b/qpc/insights/test_insights_login.py index a0e211cc..bb85c2eb 100644 --- a/qpc/insights/test_insights_login.py +++ b/qpc/insights/test_insights_login.py @@ -1,6 +1,7 @@ """Test the CLI module's Insights Login command.""" import sys +from unittest import mock from unittest.mock import MagicMock import pytest @@ -16,8 +17,8 @@ class TestInsightsLogin: def test_insights_login_invalid_username_args_err(self, capsys): """Testing that insights login rejects older username args.""" - sys.argv = ["/bin/qpc", "insights", "login", "--username", "invalid-user"] - with pytest.raises(SystemExit): + test_argv = ["/bin/qpc", "insights", "login", "--username", "invalid-user"] + with pytest.raises(SystemExit), mock.patch.object(sys, "argv", test_argv): CLI().main() out, err = capsys.readouterr() assert out == "" @@ -25,8 +26,8 @@ def test_insights_login_invalid_username_args_err(self, capsys): def test_insights_login_invalid_password_args_err(self, capsys): """Testing that insights login rejects older password args.""" - sys.argv = ["/bin/qpc", "insights", "login", "--password"] - with pytest.raises(SystemExit): + test_argv = ["/bin/qpc", "insights", "login", "--password"] + with pytest.raises(SystemExit), mock.patch.object(sys, "argv", test_argv): CLI().main() out, err = capsys.readouterr() assert out == "" @@ -44,8 +45,9 @@ def test_insights_login_normal_behavior(self, faker, mocker, capsys): } insights_auth.wait_for_authorization.return_value = auth_token mocker.patch.object(InsightsAuth, "request_auth", return_value=insights_auth) - sys.argv = ["/bin/qpc", "insights", "login"] - CLI().main() + test_argv = ["/bin/qpc", "insights", "login"] + with mock.patch.object(sys, "argv", test_argv): + CLI().main() out, err = capsys.readouterr() stdout_lines = out.splitlines() assert "Insights login authorization requested" in stdout_lines[0] @@ -60,7 +62,8 @@ def test_insights_login_auth_error(self, faker, mocker, capsys): mocker.patch.object( InsightsAuth, "request_auth", side_effect=InsightsAuthError(err_message) ) - sys.argv = ["/bin/qpc", "insights", "login"] - CLI().main() + test_argv = ["/bin/qpc", "insights", "login"] + with mock.patch.object(sys, "argv", test_argv): + CLI().main() out, err = capsys.readouterr() assert err_message in err diff --git a/qpc/insights/test_insights_publish.py b/qpc/insights/test_insights_publish.py index 6163610c..3904cb60 100644 --- a/qpc/insights/test_insights_publish.py +++ b/qpc/insights/test_insights_publish.py @@ -109,8 +109,8 @@ class TestInsightsPublishCommand: def test_insights_publish_req_args_err(self): """Testing if insights publish command requires args.""" - sys.argv = ["/bin/qpc", "insights", "publish"] - with pytest.raises(SystemExit): + test_argv = ["/bin/qpc", "insights", "publish"] + with pytest.raises(SystemExit), mock.patch.object(sys, "argv", test_argv): CLI().main() def test_insights_publish_args_are_mutually_exclusive(self, mocker): @@ -118,7 +118,7 @@ def test_insights_publish_args_are_mutually_exclusive(self, mocker): mocker.patch.object( InsightsPublishCommand, "_publish_to_ingress", side_effect=RuntimeError() ) - sys.argv = [ + test_argv = [ "/bin/qpc", "insights", "publish", @@ -127,7 +127,9 @@ def test_insights_publish_args_are_mutually_exclusive(self, mocker): "--report", "1", ] - with pytest.raises(SystemExit) as exc_info: + with pytest.raises(SystemExit) as exc_info, mock.patch.object( + sys, "argv", test_argv + ): CLI().main() # argparse will always exit with value 2 assert exc_info.value.code == 2 @@ -139,14 +141,14 @@ def test_validate_report_name_if_invalid_name( ): """Testing if--input-file will accept files with inappropriate extensions.""" caplog.set_level("ERROR") - sys.argv = [ + test_argv = [ "/bin/qpc", "insights", "publish", "--input-file", inapropriate_payload_file.name, ] - with pytest.raises(SystemExit): + with pytest.raises(SystemExit), mock.patch.object(sys, "argv", test_argv): CLI().main() assert ( caplog.messages[-1] @@ -157,14 +159,14 @@ def test_validate_report_name_if_invalid_name( def test_validate_report_name_if_not_file(self, tmp_path, caplog): """Testing if insights publish --input-file will accept dir as file.""" caplog.set_level("ERROR") - sys.argv = [ + test_argv = [ "/bin/qpc", "insights", "publish", "--input-file", tmp_path.name, ] - with pytest.raises(SystemExit): + with pytest.raises(SystemExit), mock.patch.object(sys, "argv", test_argv): CLI().main() assert caplog.messages[-1] == messages.INSIGHTS_LOCAL_REPORT_NOT % tmp_path.name @@ -182,14 +184,15 @@ def test_insights_publish_successful( f"https://insights.test:1111{INGRESS_REPORT_URI}", status_code=202, ) - sys.argv = [ + test_argv = [ "/bin/qpc", "insights", "publish", "--input-file", str(payload_file), ] - CLI().main() + with mock.patch.object(sys, "argv", test_argv): + CLI().main() assert caplog.messages[-1] == messages.INSIGHTS_PUBLISH_SUCCESSFUL assert payload_file.exists(), "Input file should not be removed." @@ -217,14 +220,14 @@ def test_insights_publish_returning_error( f"https://insights.test:1111{INGRESS_REPORT_URI}", status_code=status_code, ) - sys.argv = [ + test_argv = [ "/bin/qpc", "insights", "publish", "--input-file", str(payload_file), ] - with pytest.raises(SystemExit): + with pytest.raises(SystemExit), mock.patch.object(sys, "argv", test_argv): CLI().main() assert caplog.messages[-1] == log_message assert payload_file.exists(), "Input file should not be removed." @@ -255,14 +258,14 @@ def test_insights_publish_token_authentication_errors( status_code=status_code, json=error_json, ) - sys.argv = [ + test_argv = [ "/bin/qpc", "insights", "publish", "--input-file", str(payload_file), ] - with pytest.raises(SystemExit): + with pytest.raises(SystemExit), mock.patch.object(sys, "argv", test_argv): CLI().main() assert caplog.messages[-1] == log_message assert payload_file.exists(), "Input file should not be removed." @@ -295,14 +298,14 @@ def test_insights_publish_token_authentication_errors( def test_invalid_payload_file(self, payload, caplog, log_message): """Test invalid tar.gz payloads.""" caplog.set_level("INFO") - sys.argv = [ + test_argv = [ "/bin/qpc", "insights", "publish", "--input-file", str(payload), ] - with pytest.raises(SystemExit): + with pytest.raises(SystemExit), mock.patch.object(sys, "argv", test_argv): CLI().main() assert caplog.messages[-1] == log_message @@ -358,14 +361,14 @@ def test_insights_publish_download_error( url=f"{REPORT_URI}1{INSIGHTS_PATH_SUFFIX}", status_code=status_code, ) - sys.argv = [ + test_argv = [ "/bin/qpc", "insights", "publish", "--report", "1", ] - with pytest.raises(SystemExit): + with pytest.raises(SystemExit), mock.patch.object(sys, "argv", test_argv): CLI().main() assert caplog.messages[-1] == error_message @@ -393,14 +396,15 @@ def test_if_file_is_successfully_created_and_deleted( InsightsPublishCommand, "_make_publish_request", return_value=True ) - sys.argv = [ + test_argv = [ "/bin/qpc", "insights", "publish", "--report", "1", ] - CLI().main() + with mock.patch.object(sys, "argv", test_argv): + CLI().main() mock_validate_report_name.assert_called_with(payload_file) mock_validate_report_content.assert_called_with(payload_file)