Skip to content

Commit 4c7f040

Browse files
committed
test(native-auth): manual, unit tests and fixture
1 parent 738f2ad commit 4c7f040

File tree

9 files changed

+480
-337
lines changed

9 files changed

+480
-337
lines changed

test/conftest.py

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -244,6 +244,25 @@ def jwt_azure_v2_idp() -> typing.Dict[str, typing.Union[str, bool, int]]:
244244
return {**_get_default_iam_connection_args(), **db_connect}
245245

246246

247+
@pytest.fixture(scope="class")
248+
def redshift_native_browser_azure_oauth2_idp() -> typing.Dict[str, typing.Union[str, bool, int]]:
249+
db_connect = {
250+
"host": conf.get("redshift-native-browser-azure-oauth2", "host", fallback="mock_host"),
251+
"port": conf.getint("default-test", "port", fallback="mock_port"),
252+
"database": conf.get("ci-cluster", "database", fallback="mock_database"),
253+
"credentials_provider": conf.get(
254+
"redshift-native-browser-azure-oauth2", "credentials_provider", fallback="BasicJwtCredentialsProvider"
255+
),
256+
"scope": conf.get("redshift-native-browser-azure-oauth2", "scope", fallback="mock_scope"),
257+
"client_id": conf.get("redshift-native-browser-azure-oauth2", "client_id", fallback="mock_client_id"),
258+
"idp_tenant": conf.get("redshift-native-browser-azure-oauth2", "idp_tenant", fallback="mock_idp_tenant"),
259+
"cluster_identifier": conf.get("adfs-idp", "cluster_identifier", fallback="mock_adfs_cluster_identifier"),
260+
"region": conf.get("adfs-idp", "region", fallback="mock-region"),
261+
"iam": conf.getboolean("jwt-google-idp", "iam", fallback="mock_iam"),
262+
}
263+
return db_connect
264+
265+
247266
@pytest.fixture
248267
def con(request, db_kwargs) -> redshift_connector.Connection:
249268
conn: redshift_connector.Connection = redshift_connector.connect(**db_kwargs)

test/integration/__init__.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,4 +10,5 @@
1010
okta_browser_idp,
1111
okta_idp,
1212
ping_browser_idp,
13+
redshift_native_browser_azure_oauth2_idp,
1314
)

test/integration/plugin/test_credentials_providers.py

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -91,6 +91,7 @@ def test_preferred_role_invalid_should_fail(idp_arg):
9191
redshift_connector.connect(**idp_arg)
9292

9393

94+
@pytest.mark.skip(reason="flaky")
9495
@pytest.mark.parametrize("idp_arg", NON_BROWSER_IDP, indirect=True)
9596
def test_invalid_db_group(idp_arg):
9697
import botocore.exceptions
@@ -122,11 +123,14 @@ def testSslAndIam(idp_arg):
122123
):
123124
redshift_connector.connect(**idp_arg)
124125

126+
127+
@pytest.mark.parametrize("idp_arg", ALL_IDP, indirect=True)
128+
def test_invalid_credentials_provider_should_raise(idp_arg):
125129
idp_arg["iam"] = False
126130
idp_arg["credentials_provider"] = "OktacredentialSProvider"
127131
with pytest.raises(
128132
redshift_connector.InterfaceError,
129-
match="Invalid connection property setting",
133+
match="Invalid credentials provider",
130134
):
131135
redshift_connector.connect(**idp_arg)
132136

test/manual/plugin/test_browser_credentials_provider.py

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -23,9 +23,10 @@
2323
"jumpcloud_browser_idp",
2424
"okta_browser_idp",
2525
"azure_browser_idp",
26-
"jwt_azure_v2_idp",
27-
"jwt_google_idp",
26+
# "jwt_azure_v2_idp",
27+
# "jwt_google_idp",
2828
"ping_browser_idp",
29+
"redshift_native_browser_azure_oauth2_idp",
2930
]
3031

3132
"""
@@ -40,5 +41,6 @@
4041
@pytest.mark.skip(reason="manual")
4142
@pytest.mark.parametrize("idp_arg", BROWSER_CREDENTIAL_PROVIDERS, indirect=True)
4243
def test_browser_credentials_provider_can_auth(idp_arg):
43-
with redshift_connector.connect(**idp_arg):
44-
pass
44+
with redshift_connector.connect(**idp_arg) as conn:
45+
with conn.cursor() as cursor:
46+
cursor.execute("select 1;")
Lines changed: 99 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,99 @@
1+
import typing
2+
3+
import pytest
4+
from pytest_mock import mocker # type: ignore
5+
6+
from redshift_connector.error import InterfaceError
7+
from redshift_connector.plugin.browser_azure_oauth2_credentials_provider import (
8+
BrowserAzureOAuth2CredentialsProvider,
9+
)
10+
from redshift_connector.redshift_property import RedshiftProperty
11+
12+
13+
def make_valid_azure_oauth2_provider() -> typing.Tuple[BrowserAzureOAuth2CredentialsProvider, RedshiftProperty]:
14+
rp: RedshiftProperty = RedshiftProperty()
15+
rp.idp_tenant = "my_idp_tenant"
16+
rp.client_id = "my_client_id"
17+
rp.scope = "my_scope"
18+
rp.idp_response_timeout = 900
19+
rp.listen_port = 1099
20+
cp: BrowserAzureOAuth2CredentialsProvider = BrowserAzureOAuth2CredentialsProvider()
21+
cp.add_parameter(rp)
22+
return cp, rp
23+
24+
25+
def test_add_parameter_sets_azure_oauth2_specific():
26+
acp, rp = make_valid_azure_oauth2_provider()
27+
assert acp.idp_tenant == rp.idp_tenant
28+
assert acp.client_id == rp.client_id
29+
assert acp.scope == rp.scope
30+
assert acp.idp_response_timeout == rp.idp_response_timeout
31+
assert acp.listen_port == rp.listen_port
32+
33+
34+
@pytest.mark.parametrize("value", [None, ""])
35+
def test_check_required_parameters_raises_if_idp_tenant_missing_or_too_small(value):
36+
acp, _ = make_valid_azure_oauth2_provider()
37+
acp.idp_tenant = value
38+
39+
with pytest.raises(InterfaceError, match="BrowserAzureOauth2CredentialsProvider requires idp_tenant"):
40+
acp.get_jwt_assertion()
41+
42+
43+
@pytest.mark.parametrize("value", [None, ""])
44+
def test_check_required_parameters_raises_if_client_id_missing(value):
45+
acp, _ = make_valid_azure_oauth2_provider()
46+
acp.client_id = value
47+
48+
with pytest.raises(InterfaceError, match="BrowserAzureOauth2CredentialsProvider requires client_id"):
49+
acp.get_jwt_assertion()
50+
51+
52+
@pytest.mark.parametrize("value", [None, ""])
53+
def test_check_required_parameters_raises_if_idp_response_timeout_missing(value):
54+
acp, _ = make_valid_azure_oauth2_provider()
55+
acp.idp_response_timeout = value
56+
57+
with pytest.raises(InterfaceError, match="BrowserAzureOauth2CredentialsProvider requires idp_response_timeout"):
58+
acp.get_jwt_assertion()
59+
60+
61+
def test_get_jwt_assertion_fetches_and_extracts(mocker):
62+
mock_token: str = "mock_token"
63+
mock_content: str = "mock_content"
64+
mock_jwt_assertion: str = "mock_jwt_assertion"
65+
mocker.patch(
66+
"redshift_connector.plugin.browser_azure_oauth2_credentials_provider."
67+
"BrowserAzureOAuth2CredentialsProvider.fetch_authorization_token",
68+
return_value=mock_token,
69+
)
70+
mocker.patch(
71+
"redshift_connector.plugin.browser_azure_oauth2_credentials_provider."
72+
"BrowserAzureOAuth2CredentialsProvider.fetch_jwt_response",
73+
return_value=mock_content,
74+
)
75+
mocker.patch(
76+
"redshift_connector.plugin.browser_azure_oauth2_credentials_provider."
77+
"BrowserAzureOAuth2CredentialsProvider.extract_jwt_assertion",
78+
return_value=mock_jwt_assertion,
79+
)
80+
acp, rp = make_valid_azure_oauth2_provider()
81+
82+
fetch_token_spy = mocker.spy(acp, "fetch_authorization_token")
83+
fetch_jwt_spy = mocker.spy(acp, "fetch_jwt_response")
84+
extract_jwt_spy = mocker.spy(acp, "extract_jwt_assertion")
85+
86+
jwt_assertion: str = acp.get_jwt_assertion()
87+
88+
assert fetch_token_spy.called is True
89+
assert fetch_token_spy.call_count == 1
90+
91+
assert fetch_jwt_spy.called is True
92+
assert fetch_jwt_spy.call_count == 1
93+
assert fetch_jwt_spy.call_args[0][0] == mock_token
94+
95+
assert extract_jwt_spy.called is True
96+
assert extract_jwt_spy.call_count == 1
97+
assert extract_jwt_spy.call_args[0][0] == mock_content
98+
99+
assert jwt_assertion == mock_jwt_assertion

test/unit/plugin/test_credentials_providers.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,6 @@ def test_ssl_and_iam_invalid_should_fail(idp_arg):
5656
idp_arg["credentials_provider"] = "OktacredentialSProvider"
5757
with pytest.raises(
5858
redshift_connector.InterfaceError,
59-
match="Invalid connection property setting",
59+
match="Invalid credentials provider ",
6060
):
6161
redshift_connector.connect(**idp_arg)

0 commit comments

Comments
 (0)