-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #42 from canvas-medical/michela/auth-scope
Add plugin scope to oauth token request. and tests
- Loading branch information
Showing
2 changed files
with
151 additions
and
94 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,81 +1,142 @@ | ||
# def test_get_api_token_without_existing_host_or_client_credentials_raises_exception() -> None: | ||
# """Test getting an api token with no default host or client credentials.""" | ||
|
||
# runner.invoke(app, "auth remove-api-client-credentials http://george.com") | ||
|
||
# result_without_host = runner.invoke(app, "auth get-api-token") | ||
# assert result_without_host.exit_code == 2 | ||
# assert ( | ||
# "Invalid value: Please specify a host or set a default via the `auth` command" | ||
# in result_without_host.stdout | ||
# ) | ||
|
||
# result_without_client_id = runner.invoke(app, "auth get-api-token --host http://george.com") | ||
# assert result_without_client_id.exit_code == 2 | ||
# print(result_without_client_id.stdout) | ||
# assert ( | ||
# "Invalid value: Please specify a client_id and client_secret or add them via" | ||
# in result_without_client_id.stdout | ||
# ) | ||
|
||
# result_without_client_secret = runner.invoke( | ||
# app, "auth get-api-token --host http://george.com --client-id mock-client-id" | ||
# ) | ||
# assert result_without_client_secret.exit_code == 2 | ||
# assert ( | ||
# "Invalid value: Please specify a client_id and client_secret or add them via" | ||
# in result_without_client_secret.stdout | ||
# ) | ||
|
||
|
||
# @patch("requests.post") | ||
# def test_get_api_token_requests_token_from_the_host_if_not_stored_in_context( | ||
# mock_post: MagicMock, | ||
# ) -> None: | ||
# class FakeResponse: | ||
# status_code = 200 | ||
|
||
# def json(self) -> dict: | ||
# return {"access_token": "a-valid-api-token", "expires_in": 3600} | ||
|
||
# mock_post.return_value = FakeResponse() | ||
|
||
# result = runner.invoke( | ||
# app, | ||
# "auth get-api-token --host http://george.com --client-id mock-client-id --client-secret mock-client-secret", | ||
# ) | ||
# mock_post.assert_called_once() | ||
# assert result.exit_code == 0 | ||
# assert '{"success": true, "token": "a-valid-api-token"}' in result.stdout | ||
# assert context.token_expiration_date is not None | ||
# assert datetime.fromisoformat(context.token_expiration_date) > datetime.now() | ||
|
||
|
||
# @patch("keyring.get_password") | ||
# @patch("requests.post") | ||
# def test_get_api_token_uses_token_stored_in_context_first( | ||
# mock_post: MagicMock, | ||
# mock_get_password: MagicMock, | ||
# ) -> None: | ||
# mock_get_password.return_value = "a-valid-api-token" | ||
# result = runner.invoke( | ||
# app, | ||
# "auth get-api-token --host http://george.com --client-id mock-client-id --client-secret mock-client-secret", | ||
# ) | ||
# assert result.exit_code == 0 | ||
# mock_get_password.assert_called_once_with( | ||
# "canvas_cli.apps.auth.utils", "http://george.com|token" | ||
# ) | ||
# mock_post.assert_not_called() | ||
|
||
|
||
# def test_get_api_token_uses_credentials_stored_in_context() -> None: | ||
# runner.invoke( | ||
# app, | ||
# "auth add-api-client-credentials --host http://george.com --client-id mock-client-id --client-secret mock-client-secret --is-default", | ||
# ) | ||
# assert context.default_host == "http://george.com" | ||
|
||
# result = runner.invoke(app, "auth get-api-token") | ||
# assert result.exit_code == 0 | ||
# assert '{"success": true, "token": "a-valid-api-token"}' in result.stdout | ||
from typing import Any | ||
from unittest.mock import MagicMock, patch | ||
|
||
import pytest | ||
|
||
from canvas_cli.apps.auth import get_or_request_api_token | ||
|
||
|
||
@pytest.fixture | ||
def valid_token_response() -> Any: | ||
class TokenResponse: | ||
status_code = 200 | ||
|
||
def json(self) -> dict: | ||
return {"access_token": "a-valid-api-token", "expires_in": 3600} | ||
|
||
return TokenResponse() | ||
|
||
|
||
@pytest.fixture | ||
def error_token_response() -> Any: | ||
class TokenResponse: | ||
status_code = 500 | ||
|
||
return TokenResponse() | ||
|
||
|
||
@pytest.fixture | ||
def expired_token_response() -> Any: | ||
class TokenResponse: | ||
status_code = 200 | ||
|
||
def json(self) -> dict: | ||
return {"access_token": "a-valid-api-token", "expires_in": -1} | ||
|
||
return TokenResponse() | ||
|
||
|
||
@patch("keyring.get_password") | ||
@patch("requests.Session.post") | ||
@patch("canvas_cli.apps.auth.utils.is_token_valid") | ||
def test_get_or_request_api_token_uses_stored_token( | ||
mock_is_token_valid: MagicMock, | ||
mock_post: MagicMock, | ||
mock_get_password: MagicMock, | ||
valid_token_response: Any, | ||
) -> None: | ||
mock_is_token_valid.return_value = True | ||
mock_get_password.return_value = "a-stored-valid-token" | ||
mock_post.return_value = valid_token_response | ||
|
||
token = get_or_request_api_token("http://localhost:8000") | ||
|
||
assert token == "a-stored-valid-token" | ||
mock_post.assert_not_called() | ||
|
||
|
||
@patch("keyring.set_password") | ||
@patch("keyring.get_password") | ||
@patch("requests.Session.post") | ||
@patch("canvas_cli.apps.auth.utils.get_api_client_credentials") | ||
def test_get_or_request_api_token_requests_token_if_none_stored( | ||
mock_client_credentials: MagicMock, | ||
mock_post: MagicMock, | ||
mock_get_password: MagicMock, | ||
mock_set_password: MagicMock, | ||
valid_token_response: Any, | ||
) -> None: | ||
mock_client_credentials.return_value = "client_id=id&client_secret=secret" | ||
mock_get_password.return_value = None | ||
mock_post.return_value = valid_token_response | ||
|
||
token = get_or_request_api_token("http://localhost:8000") | ||
|
||
assert token == "a-valid-api-token" | ||
mock_post.assert_called_once_with( | ||
"http://localhost:8000/auth/token/", | ||
headers={"Content-Type": "application/x-www-form-urlencoded"}, | ||
json=None, | ||
data="grant_type=client_credentials&scope=system/Plugins.*&client_id=id&client_secret=secret", | ||
) | ||
mock_set_password.assert_called_with( | ||
"canvas_cli.apps.auth.utils", | ||
username="http://localhost:8000|token", | ||
password="a-valid-api-token", | ||
) | ||
|
||
|
||
@patch("keyring.get_password") | ||
@patch("requests.Session.post") | ||
@patch("canvas_cli.apps.auth.utils.get_api_client_credentials") | ||
def test_get_or_request_api_token_raises_exception_if_error_token_response( | ||
mock_client_credentials: MagicMock, | ||
mock_post: MagicMock, | ||
mock_get_password: MagicMock, | ||
error_token_response: Any, | ||
) -> None: | ||
mock_client_credentials.return_value = "client_id=id&client_secret=secret" | ||
mock_get_password.return_value = None | ||
mock_post.return_value = error_token_response | ||
|
||
with pytest.raises(Exception) as e: | ||
get_or_request_api_token("http://localhost:8000") | ||
|
||
assert "Unable to get a valid access token from the given host 'http://localhost:8000'" in repr( | ||
e | ||
) | ||
|
||
mock_post.assert_called_once_with( | ||
"http://localhost:8000/auth/token/", | ||
headers={"Content-Type": "application/x-www-form-urlencoded"}, | ||
json=None, | ||
data="grant_type=client_credentials&scope=system/Plugins.*&client_id=id&client_secret=secret", | ||
) | ||
|
||
|
||
@patch("keyring.get_password") | ||
@patch("requests.Session.post") | ||
@patch("canvas_cli.apps.auth.utils.get_api_client_credentials") | ||
def test_get_or_request_api_token_raises_exception_if_expired_token( | ||
mock_client_credentials: MagicMock, | ||
mock_post: MagicMock, | ||
mock_get_password: MagicMock, | ||
expired_token_response: Any, | ||
) -> None: | ||
mock_client_credentials.return_value = "client_id=id&client_secret=secret" | ||
mock_get_password.return_value = None | ||
mock_post.return_value = expired_token_response | ||
|
||
with pytest.raises(Exception) as e: | ||
get_or_request_api_token("http://localhost:8000") | ||
|
||
assert ( | ||
"A valid token could not be acquired from the given host 'http://localhost:8000'" in repr(e) | ||
) | ||
|
||
mock_post.assert_called_once_with( | ||
"http://localhost:8000/auth/token/", | ||
headers={"Content-Type": "application/x-www-form-urlencoded"}, | ||
json=None, | ||
data="grant_type=client_credentials&scope=system/Plugins.*&client_id=id&client_secret=secret", | ||
) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters