Skip to content

Commit

Permalink
tests(insights): Adding new insights device auth workflow tests
Browse files Browse the repository at this point in the history
- Tests the new device auth workflow with insights login
- Tests for Insights Auth request_auth
  • Loading branch information
abellotti committed Nov 17, 2023
1 parent 0a1f41e commit a8d7e30
Show file tree
Hide file tree
Showing 9 changed files with 196 additions and 7 deletions.
30 changes: 29 additions & 1 deletion poetry.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ requests = ">=2.28.1"
cryptography = ">=37.0.4"
packaging = "^23.1"
setuptools = "^67.8.0"
faker = "^20.0.3"

[tool.poetry.group.dev.dependencies]
coverage = ">=6.4.2"
Expand Down
45 changes: 45 additions & 0 deletions qpc/insights/test_insights_auth.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
"""Test the CLI module's Insights Auth support."""

import pytest

from qpc.insights.auth import DEVICE_AUTH_ENDPOINT, InsightsAuth
from qpc.insights.exceptions import InsightsAuthError
from qpc.utils import CONFIG_SSO_HOST_KEY, read_insights_config, write_insights_config


class TestInsightsAuth:
"""Class for testing Insights Device Auth support."""

def test_insights_request_auth(self, faker, requests_mock):
"""Testing that insights auth targets the right endpoint."""
auth_response = {"device_code": faker.slug()}
sso_host = read_insights_config().get(CONFIG_SSO_HOST_KEY)
sso_url = f"https://{sso_host}{DEVICE_AUTH_ENDPOINT}"
requests_mock.post(sso_url, json=auth_response)
assert InsightsAuth().request_auth() == auth_response

def test_insights_request_auth_alt_sso_host(self, faker, requests_mock):
"""Testing that insights auth targets alternate sso hosts."""
alt_sso_host = faker.slug()
write_insights_config({CONFIG_SSO_HOST_KEY: alt_sso_host})
auth_response = {"device_code": faker.slug()}
sso_url = f"https://{alt_sso_host}{DEVICE_AUTH_ENDPOINT}"
requests_mock.post(sso_url, json=auth_response)
assert InsightsAuth().request_auth() == auth_response

def test_insights_request_auth_connection_error(self, faker):
"""Testing that insights auth handles connection errors."""
alt_sso_host = faker.slug()
write_insights_config({CONFIG_SSO_HOST_KEY: alt_sso_host})
with pytest.raises(InsightsAuthError) as err:
InsightsAuth().request_auth()
assert "Failed to request login authorization" in err.value

def test_insights_wait_for_authorization(self):
"""Testing that insights wait for authorization returns the auth token."""

def test_insights_wait_for_authorization_connection_error(self):
"""Testing that insights wait for authorization handles connection errors."""

def test_insights_wait_for_authorization_http_error(self):
"""Testing that insights wait for authorization handles http errors."""
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
DEFAULT_HOST_INSIGHTS_CONFIG,
DEFAULT_INSIGHTS_CONFIG,
DEFAULT_PORT_INSIGHTS_CONFIG,
DEFAULT_SSO_HOST_INSIGHTS_CONFIG,
DEFAULT_USE_HTTP_INSIGHTS_CONFIG,
read_insights_config,
write_insights_config,
Expand Down Expand Up @@ -36,6 +37,12 @@ def test_insights_config_bad_host(self):
with pytest.raises(SystemExit):
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):
CLI().main()

def test_success_default_config_no_args(self):
"""Testing if method returns default config dict when no arguments."""
config = read_insights_config()
Expand All @@ -60,6 +67,27 @@ def test_success_config_insights(self):
assert config["port"] == 200
assert config["use_http"]

def test_success_config_insights_with_sso_host(self):
"""Testing insights configure green path with sso host."""
sys.argv = [
"/bin/qpc",
"insights",
"config",
"--host",
"console.insights.test",
"--port",
"200",
"--use-http",
"--sso-host",
"sso.insights.test",
]
CLI().main()
config = read_insights_config()
assert config["host"] == "console.insights.test"
assert config["port"] == 200
assert config["use_http"]
assert config["sso_host"] == "sso.insights.test"

def test_insights_config_default_host(self):
"""Testing insights configure default host."""
sys.argv = ["/bin/qpc", "insights", "config", "--port", "200"]
Expand All @@ -78,6 +106,24 @@ def test_insights_config_default_port(self):
assert config["port"] == DEFAULT_PORT_INSIGHTS_CONFIG
assert config["use_http"] == DEFAULT_USE_HTTP_INSIGHTS_CONFIG

def test_insights_config_default_sso_host(self):
"""Testing insights configure default sso host."""
sys.argv = [
"/bin/qpc",
"insights",
"config",
"--host",
"console.insights.test",
"--port",
"200",
]
CLI().main()
config = read_insights_config()
assert config["host"] == "console.insights.test"
assert config["port"] == 200
assert config["use_http"] == DEFAULT_USE_HTTP_INSIGHTS_CONFIG
assert config["sso_host"] == DEFAULT_SSO_HOST_INSIGHTS_CONFIG

def test_invalid_configuration(self):
"""Test reading bad JSON on cli start."""
write_insights_config({})
Expand All @@ -86,3 +132,4 @@ def test_invalid_configuration(self):
assert config["host"] == DEFAULT_HOST_INSIGHTS_CONFIG
assert config["port"] == DEFAULT_PORT_INSIGHTS_CONFIG
assert config["use_http"] == DEFAULT_USE_HTTP_INSIGHTS_CONFIG
assert config["sso_host"] == DEFAULT_SSO_HOST_INSIGHTS_CONFIG
66 changes: 66 additions & 0 deletions qpc/insights/test_insights_login.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
"""Test the CLI module's Insights Login command."""

import sys
from unittest.mock import MagicMock

import pytest

from qpc import messages
from qpc.cli import CLI
from qpc.insights.auth import InsightsAuth
from qpc.insights.exceptions import InsightsAuthError


class TestInsightsLogin:
"""Class for testing insights login command."""

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):
CLI().main()
out, err = capsys.readouterr()
assert out == ""
assert "error: unrecognized arguments: --username invalid-user" in err

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):
CLI().main()
out, err = capsys.readouterr()
assert out == ""
assert "error: unrecognized arguments: --password" in err

def test_insights_login_normal_behavior(self, faker, mocker, capsys):
"""Testing that insights login displays the expected messages."""
auth_token = faker.md5()
user_code = faker.slug()
verification_uri_complete = faker.url()
insights_auth = MagicMock()
insights_auth.request_auth.return_value = {
"user_code": user_code,
"verification_uri_complete": verification_uri_complete,
}
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()
out, err = capsys.readouterr()
stdout_lines = out.splitlines()
assert "Insights login authorization requested" in stdout_lines[0]
assert "User Code: " in stdout_lines[1]
assert "Authorization URL: " in stdout_lines[2]
assert "Waiting for login authorization ..." in stdout_lines[3]
assert "Login authorization successful." in stdout_lines[4]

def test_insights_login_auth_error(self, faker, mocker, capsys):
"""Testing that insights login catches auth errors."""
err_message = messages.INSIGHTS_LOGIN_REQUEST_FAILED % "Network Error"
mocker.patch.object(
InsightsAuth, "request_auth", side_effect=InsightsAuthError(err_message)
)
sys.argv = ["/bin/qpc", "insights", "login"]
CLI().main()
out, err = capsys.readouterr()
assert err_message in err
File renamed without changes.
5 changes: 0 additions & 5 deletions qpc/insights/tests_insights_login.py

This file was deleted.

6 changes: 5 additions & 1 deletion requirements-build.txt
Original file line number Diff line number Diff line change
Expand Up @@ -37,13 +37,16 @@ setuptools-rust==1.8.1
setuptools-scm==8.0.4
# via
# pluggy
# python-dateutil
# setuptools-rust
trove-classifiers==2023.11.14
# via hatchling
typing-extensions==4.8.0
# via setuptools-scm
wheel==0.41.3
# via cryptography
# via
# cryptography
# python-dateutil

# The following packages are considered to be unsafe in a requirements file:
setuptools==68.2.2 ; python_version >= "3.11" and python_version < "4.0"
Expand All @@ -53,6 +56,7 @@ setuptools==68.2.2 ; python_version >= "3.11" and python_version < "4.0"
# cryptography
# pathspec
# pluggy
# python-dateutil
# setuptools-rust
# setuptools-scm
# trove-classifiers
3 changes: 3 additions & 0 deletions requirements.txt
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,12 @@ certifi==2023.7.22 ; python_version >= "3.11" and python_version < "4.0"
cffi==1.16.0 ; python_version >= "3.11" and python_version < "4.0"
charset-normalizer==3.3.0 ; python_version >= "3.11" and python_version < "4.0"
cryptography==41.0.4 ; python_version >= "3.11" and python_version < "4.0"
faker==20.0.3 ; python_version >= "3.11" and python_version < "4.0"
idna==3.4 ; python_version >= "3.11" and python_version < "4.0"
packaging==23.2 ; python_version >= "3.11" and python_version < "4.0"
pycparser==2.21 ; python_version >= "3.11" and python_version < "4.0"
python-dateutil==2.8.2 ; python_version >= "3.11" and python_version < "4.0"
requests==2.31.0 ; python_version >= "3.11" and python_version < "4.0"
setuptools==67.8.0 ; python_version >= "3.11" and python_version < "4.0"
six==1.16.0 ; python_version >= "3.11" and python_version < "4.0"
urllib3==2.0.7 ; python_version >= "3.11" and python_version < "4.0"

0 comments on commit a8d7e30

Please sign in to comment.