-
Notifications
You must be signed in to change notification settings - Fork 11
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
164 changed files
with
10,581 additions
and
6,276 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
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 |
---|---|---|
|
@@ -131,3 +131,9 @@ dmypy.json | |
|
||
# VSCode | ||
.vscode/ | ||
|
||
# macOS | ||
.DS_Store | ||
|
||
# Intellij | ||
.idea/ |
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
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 |
---|---|---|
@@ -0,0 +1,11 @@ | ||
[mypy] | ||
packages = workos | ||
warn_return_any = True | ||
warn_unused_configs = True | ||
warn_unreachable = True | ||
warn_redundant_casts = True | ||
warn_no_return = True | ||
warn_unused_ignores = True | ||
implicit_reexport = False | ||
strict_equality = True | ||
strict = True |
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
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,80 +1,158 @@ | ||
import pytest | ||
import requests | ||
|
||
import workos | ||
|
||
|
||
class MockResponse(object): | ||
def __init__(self, response_dict, status_code, headers=None): | ||
self.response_dict = response_dict | ||
self.status_code = status_code | ||
self.headers = {} if headers is None else headers | ||
|
||
if "content-type" not in self.headers: | ||
self.headers["content-type"] = "application/json" | ||
|
||
def json(self): | ||
return self.response_dict | ||
from typing import Any, Callable, Mapping, Optional | ||
from unittest.mock import AsyncMock, MagicMock | ||
|
||
import httpx | ||
import pytest | ||
|
||
class MockRawResponse(object): | ||
def __init__(self, content, status_code, headers=None): | ||
self.content = content | ||
self.status_code = status_code | ||
self.headers = {} if headers is None else headers | ||
from tests.utils.client_configuration import ClientConfiguration | ||
from tests.utils.list_resource import list_data_to_dicts, list_response_of | ||
from workos.types.list_resource import WorkOSListResource | ||
from workos.utils.http_client import AsyncHTTPClient, HTTPClient, SyncHTTPClient | ||
|
||
|
||
@pytest.fixture | ||
def set_api_key(monkeypatch): | ||
monkeypatch.setattr(workos, "api_key", "sk_test") | ||
def sync_http_client_for_test(): | ||
return SyncHTTPClient( | ||
api_key="sk_test", | ||
base_url="https://api.workos.test/", | ||
client_id="client_b27needthisforssotemxo", | ||
version="test", | ||
) | ||
|
||
|
||
@pytest.fixture | ||
def set_client_id(monkeypatch): | ||
monkeypatch.setattr(workos, "client_id", "client_b27needthisforssotemxo") | ||
def async_http_client_for_test(): | ||
return AsyncHTTPClient( | ||
api_key="sk_test", | ||
base_url="https://api.workos.test/", | ||
client_id="client_b27needthisforssotemxo", | ||
version="test", | ||
) | ||
|
||
|
||
@pytest.fixture | ||
def set_api_key_and_client_id(set_api_key, set_client_id): | ||
pass | ||
def mock_http_client_with_response(monkeypatch): | ||
def inner( | ||
http_client: HTTPClient, | ||
response_dict: Optional[dict] = None, | ||
status_code: int = 200, | ||
headers: Optional[Mapping[str, str]] = None, | ||
): | ||
mock_class = ( | ||
AsyncMock if isinstance(http_client, AsyncHTTPClient) else MagicMock | ||
) | ||
mock = mock_class( | ||
return_value=httpx.Response( | ||
status_code=status_code, headers=headers, json=response_dict | ||
), | ||
) | ||
monkeypatch.setattr(http_client._client, "request", mock) | ||
|
||
return inner | ||
|
||
|
||
@pytest.fixture | ||
def mock_request_method(monkeypatch): | ||
def inner(method, response_dict, status_code, headers=None): | ||
def mock(*args, **kwargs): | ||
return MockResponse(response_dict, status_code, headers=headers) | ||
def capture_and_mock_http_client_request(monkeypatch): | ||
def inner( | ||
http_client: HTTPClient, | ||
response_dict: Optional[dict] = None, | ||
status_code: int = 200, | ||
headers: Optional[Mapping[str, str]] = None, | ||
): | ||
request_kwargs = {} | ||
|
||
monkeypatch.setattr(requests, method, mock) | ||
def capture_and_mock(*args, **kwargs): | ||
request_kwargs.update(kwargs) | ||
|
||
return inner | ||
return httpx.Response( | ||
status_code=status_code, | ||
headers=headers, | ||
json=response_dict, | ||
) | ||
|
||
mock_class = ( | ||
AsyncMock if isinstance(http_client, AsyncHTTPClient) else MagicMock | ||
) | ||
mock = mock_class(side_effect=capture_and_mock) | ||
|
||
@pytest.fixture | ||
def mock_raw_request_method(monkeypatch): | ||
def inner(method, content, status_code, headers=None): | ||
def mock(*args, **kwargs): | ||
return MockRawResponse(content, status_code, headers=headers) | ||
monkeypatch.setattr(http_client._client, "request", mock) | ||
|
||
monkeypatch.setattr(requests, method, mock) | ||
return request_kwargs | ||
|
||
return inner | ||
|
||
|
||
@pytest.fixture | ||
def capture_and_mock_request(monkeypatch): | ||
def inner(method, response_dict, status_code, headers=None): | ||
request_args = [] | ||
request_kwargs = {} | ||
def mock_pagination_request_for_http_client(monkeypatch): | ||
# Mocking pagination correctly requires us to index into a list of data | ||
# and correctly set the before and after metadata in the response. | ||
def inner( | ||
http_client: HTTPClient, | ||
data_list: list, | ||
status_code: int = 200, | ||
headers: Optional[Mapping[str, str]] = None, | ||
): | ||
# For convenient index lookup, store the list of object IDs. | ||
data_ids = list(map(lambda x: x["id"], data_list)) | ||
|
||
def mock_function(*args, **kwargs): | ||
params = kwargs.get("params") or {} | ||
request_after = params.get("after", None) | ||
limit = params.get("limit", 10) | ||
|
||
if request_after is None: | ||
# First page | ||
start = 0 | ||
else: | ||
# A subsequent page, return the first item _after_ the index we locate | ||
start = data_ids.index(request_after) + 1 | ||
data = data_list[start : start + limit] | ||
if len(data) < limit or len(data) == 0: | ||
# No more data, set after to None | ||
after = None | ||
else: | ||
# Set after to the last item in this page of results | ||
after = data[-1]["id"] | ||
|
||
return httpx.Response( | ||
status_code=status_code, | ||
headers=headers, | ||
json=list_response_of(data=data, before=request_after, after=after), | ||
) | ||
|
||
mock_class = ( | ||
AsyncMock if isinstance(http_client, AsyncHTTPClient) else MagicMock | ||
) | ||
mock = mock_class(side_effect=mock_function) | ||
|
||
monkeypatch.setattr(http_client._client, "request", mock) | ||
|
||
def capture_and_mock(*args, **kwargs): | ||
request_args.extend(args) | ||
request_kwargs.update(kwargs) | ||
|
||
return MockResponse(response_dict, status_code, headers=headers) | ||
return inner | ||
|
||
monkeypatch.setattr(requests, method, capture_and_mock) | ||
|
||
return (request_args, request_kwargs) | ||
@pytest.fixture | ||
def test_sync_auto_pagination( | ||
mock_pagination_request_for_http_client, | ||
): | ||
def inner( | ||
http_client: SyncHTTPClient, | ||
list_function: Callable[[], WorkOSListResource], | ||
expected_all_page_data: dict, | ||
list_function_params: Optional[Mapping[str, Any]] = None, | ||
): | ||
mock_pagination_request_for_http_client( | ||
http_client=http_client, | ||
data_list=expected_all_page_data, | ||
status_code=200, | ||
) | ||
|
||
results = list_function(**list_function_params or {}) | ||
all_results = [] | ||
|
||
for result in results: | ||
all_results.append(result) | ||
|
||
assert len(list(all_results)) == len(expected_all_page_data) | ||
assert (list_data_to_dicts(all_results)) == expected_all_page_data | ||
|
||
return inner |
Oops, something went wrong.