diff --git a/README.md b/README.md index 73d8b093..d90de69d 100644 --- a/README.md +++ b/README.md @@ -66,6 +66,10 @@ account [here](https://www.checkout.com/get-test-account). **PLEASE NEVER SHARE OR PUBLISH YOUR CHECKOUT CREDENTIALS.** +### Subdomain value + +Requests must be made through your merchant-specific subdomain (MSSD): the first 8 characters of your client ID (excluding `cli_`). For example, if your client ID is `cli_vkuhvk4vjn2edkps7dfsq6emqm`, your subdomain is `vkuhvk4v`. When `environment_subdomain` is set the SDK sends requests to `https://vkuhvk4v.api.checkout.com`. See [Base URLs](https://api-reference.checkout.com/#section/Base-URLs) and [API endpoints](https://www.checkout.com/docs/developer-resources/api/api-endpoints) for further details, and for where to find your unique client ID. + ### Default Default keys client instantiation can be done as follows: @@ -82,7 +86,7 @@ def default(): .secret_key('secret_key') .public_key('public_key') # optional, only required for operations related with tokens .environment(Environment.sandbox()) # or production() - .environment_subdomain("subdomain") # optional, Merchant-specific DNS name + .environment_subdomain("subdomain") # required, Merchant-specific DNS name, the first 8 characters of your client ID .build() payments_client = checkout_api.payments @@ -105,7 +109,7 @@ def oauth(): .oauth() .client_credentials(client_id='client_id', client_secret='client_secret') .environment(Environment.sandbox()) # or production() - .environment_subdomain("subdomain") # optional, Merchant-specific DNS name + .environment_subdomain("subdomain") # required, Merchant-specific DNS name, the first 8 characters of your client ID .scopes([OAuthScopes.GATEWAY_PAYMENT_REFUNDS, OAuthScopes.FILES]) # optional, array of scopes .build() @@ -129,7 +133,7 @@ def previous(): .secret_key('secret_key') .public_key('public_key') # optional, only required for operations related with tokens .environment(Environment.sandbox()) # or production() - .environment_subdomain("subdomain") # optional, Merchant-specific DNS name + .environment_subdomain("subdomain") # optional for the Previous platform, Merchant-specific DNS name .build() payments_client = checkout_api.payments @@ -175,7 +179,7 @@ def oauth(): .oauth() .client_credentials(client_id='client_id', client_secret='client_secret') .environment(Environment.sandbox()) # or production() - .environment_subdomain("subdomain") # optional, Merchant-specific DNS name + .environment_subdomain("subdomain") # required, Merchant-specific DNS name, the first 8 characters of your client ID .http_client_builder(CustomHttpClientBuilder()) # optional .scopes([OAuthScopes.GATEWAY_PAYMENT_REFUNDS, OAuthScopes.FILES]) # optional, array of scopes .build() @@ -267,6 +271,22 @@ The execution of integration tests require the following environment variables s * For Previous account systems: `CHECKOUT_PREVIOUS_PUBLIC_KEY` & `CHECKOUT_PREVIOUS_SECRET_KEY` * Processing channel: `CHECKOUT_PROCESSING_CHANNEL_ID` +## Legacy domain (emergency use only) + +> :warning: **Only use if merchant specific sub domains are causing issues.** Connecting through your merchant-specific subdomain (see [Subdomain value](#subdomain-value)) is the supported way of using the Checkout.com API, and non-subdomain usage will be deprecated. + +If, in exceptional circumstances, you cannot use your merchant-specific subdomain, you can explicitly opt out by calling `use_legacy_domain()` instead of `environment_subdomain(...)`: + +```python +checkout_api = CheckoutSdk.builder() \ + .secret_key("secret_key") \ + .environment(Environment.sandbox()) \ + .use_legacy_domain() \ + .build() +``` + +This routes requests to `api.checkout.com` (or `api.sandbox.checkout.com`) and `access.checkout.com` (or `access.sandbox.checkout.com`). The method raises a `DeprecationWarning`, so `python -W error::DeprecationWarning` and most linters will flag it. Exactly one of `environment_subdomain(...)` or `use_legacy_domain()` must be set: the SDK raises a `CheckoutArgumentException` if both, or neither, are. The Previous (ABC) platform predates merchant-specific subdomains and is exempt from this requirement. + ## Code of Conduct Please refer to [Code of Conduct](CODE_OF_CONDUCT.md) diff --git a/checkout_sdk/checkout_sdk_builder.py b/checkout_sdk/checkout_sdk_builder.py index 3f0b8e96..3d7f4946 100644 --- a/checkout_sdk/checkout_sdk_builder.py +++ b/checkout_sdk/checkout_sdk_builder.py @@ -1,10 +1,12 @@ from __future__ import absolute_import +import warnings from typing import Optional from checkout_sdk.default_http_client import DefaultHttpClientBuilder from checkout_sdk.environment import Environment from checkout_sdk.environment_subdomain import EnvironmentSubdomain +from checkout_sdk.exception import CheckoutArgumentException from checkout_sdk.http_client_interface import HttpClientBuilderInterface @@ -12,7 +14,8 @@ class CheckoutSdkBuilder: def __init__(self): self._environment = Environment.sandbox() - self._environment_subdomain = None + self._subdomain = None + self._use_legacy_domain = False self._http_client = DefaultHttpClientBuilder().get_client() def environment(self, environment: Environment): @@ -20,15 +23,59 @@ def environment(self, environment: Environment): return self def environment_subdomain(self, subdomain: Optional[str]): - if subdomain: - self._environment_subdomain = EnvironmentSubdomain(self._environment, subdomain) - else: - self._environment_subdomain = None + self._subdomain = subdomain + return self + + def use_legacy_domain(self): + """ + Opts out of the merchant-specific subdomain, sending every request to the shared hosts + instead (api.checkout.com and access.checkout.com, or their sandbox equivalents). + + Deprecated: this is an emergency fallback for the rare case where the merchant-specific + subdomain cannot be used, and will be removed in a future release. Call + environment_subdomain() instead. + See https://api-reference.checkout.com/#section/Base-URLs + """ + warnings.warn( + 'use_legacy_domain() is deprecated and will be removed in a future release. It is ' + 'intended only as an emergency fallback when the merchant-specific subdomain cannot ' + 'be used. Call environment_subdomain() instead. See ' + 'https://api-reference.checkout.com/#section/Base-URLs', + DeprecationWarning, + stacklevel=2) + self._use_legacy_domain = True return self def http_client_builder(self, http_client_builder: HttpClientBuilderInterface): self._http_client = http_client_builder.get_client() return self + @property + def _environment_subdomain(self) -> Optional[EnvironmentSubdomain]: + if self._subdomain is None: + return None + return EnvironmentSubdomain(self._environment, self._subdomain) + + def _requires_environment_subdomain(self) -> bool: + """ + Whether this builder requires the merchant-specific subdomain to be configured. The + Previous (ABC) platform predates merchant-specific subdomains, so it overrides this to + False. + """ + return True + + def _validate_environment_settings(self): + if self._subdomain is not None and self._use_legacy_domain: + raise CheckoutArgumentException( + 'environment_subdomain and use_legacy_domain cannot both be set - provide only ' + 'your merchant-specific subdomain') + if self._subdomain is None and not self._use_legacy_domain and self._requires_environment_subdomain(): + raise CheckoutArgumentException( + 'environment_subdomain is required - provide your merchant-specific subdomain ' + '(the first 8 characters of your client ID, see ' + 'https://api-reference.checkout.com/#section/Base-URLs), or call ' + 'use_legacy_domain() to opt out only if merchant specific sub domains are ' + 'causing issues') + def build(self): raise NotImplementedError() diff --git a/checkout_sdk/default_sdk.py b/checkout_sdk/default_sdk.py index 3305ee42..700efeea 100644 --- a/checkout_sdk/default_sdk.py +++ b/checkout_sdk/default_sdk.py @@ -39,15 +39,10 @@ def oauth(): def build(self): validate_secret_key(self._SECRET_KEY_PATTERN, self._secret_key) validate_public_key(self._PUBLIC_KEY_PATTERN, self._public_key) - if self._environment_subdomain is not None: - configuration = CheckoutConfiguration( - credentials=DefaultKeysSdkCredentials(secret_key=self._secret_key, public_key=self._public_key), - environment=self._environment, - http_client=self._http_client, - environment_subdomain=self._environment_subdomain) - else: - configuration = CheckoutConfiguration( - credentials=DefaultKeysSdkCredentials(secret_key=self._secret_key, public_key=self._public_key), - environment=self._environment, - http_client=self._http_client) + self._validate_environment_settings() + configuration = CheckoutConfiguration( + credentials=DefaultKeysSdkCredentials(secret_key=self._secret_key, public_key=self._public_key), + environment=self._environment, + http_client=self._http_client, + environment_subdomain=self._environment_subdomain) return CheckoutApi(configuration) diff --git a/checkout_sdk/environment_subdomain.py b/checkout_sdk/environment_subdomain.py index ff6be2d8..7d60de4e 100644 --- a/checkout_sdk/environment_subdomain.py +++ b/checkout_sdk/environment_subdomain.py @@ -2,6 +2,7 @@ from urllib.parse import urlparse, urlunparse from checkout_sdk.environment import Environment +from checkout_sdk.exception import CheckoutArgumentException class EnvironmentSubdomain: @@ -12,39 +13,41 @@ def __init__(self, environment: Environment, subdomain: str): @staticmethod def create_url_with_subdomain(original_url: str, subdomain: str): """ - Applies subdomain transformation to any given URL. - If the subdomain is valid (alphanumeric pattern), prepends it to the host. - Otherwise, returns the original URL unchanged. + Applies subdomain transformation to any given URL, prepending the subdomain to the host. Args: original_url: the original URL to transform subdomain: the subdomain to prepend Returns: - the transformed URL with subdomain, or original URL if subdomain is invalid - """ - new_environment = original_url + the transformed URL with subdomain + Raises: + CheckoutArgumentException: if the subdomain is not a valid merchant-specific subdomain + """ regex = r'^(?:pl-)?[a-z0-9]+$' - if re.match(regex, subdomain): - url_parts = urlparse(original_url) - if url_parts.port: - new_host = subdomain + '.' + url_parts.hostname + ':' + str(url_parts.port) - else: - new_host = subdomain + '.' + url_parts.hostname - - new_url_parts = ( - url_parts.scheme, - new_host, - url_parts.path, - url_parts.params, - url_parts.query, - url_parts.fragment - ) - - new_environment = urlunparse(new_url_parts) - - return new_environment + if subdomain is None or not re.match(regex, subdomain): + raise CheckoutArgumentException( + 'invalid environment subdomain - provide your merchant-specific subdomain, the ' + 'first 8 characters of your client ID (see ' + 'https://api-reference.checkout.com/#section/Base-URLs)') + + url_parts = urlparse(original_url) + if url_parts.port: + new_host = subdomain + '.' + url_parts.hostname + ':' + str(url_parts.port) + else: + new_host = subdomain + '.' + url_parts.hostname + + new_url_parts = ( + url_parts.scheme, + new_host, + url_parts.path, + url_parts.params, + url_parts.query, + url_parts.fragment + ) + + return urlunparse(new_url_parts) def base_uri(self) -> str: return self.base_uri diff --git a/checkout_sdk/oauth_sdk.py b/checkout_sdk/oauth_sdk.py index 0ec97a63..aa45ca9d 100644 --- a/checkout_sdk/oauth_sdk.py +++ b/checkout_sdk/oauth_sdk.py @@ -31,9 +31,12 @@ def scopes(self, scopes: list): return self def build(self): + self._validate_environment_settings() + environment_subdomain = self._environment_subdomain + # Determine the authorization URI based on subdomain configuration - if self._environment_subdomain is not None: - authorization_uri = self._environment_subdomain.authorization_uri + if environment_subdomain is not None: + authorization_uri = environment_subdomain.authorization_uri else: authorization_uri = self._environment.authorization_uri @@ -41,25 +44,14 @@ def build(self): if self._authorization_uri: authorization_uri = self._authorization_uri - if self._environment_subdomain is not None: - configuration = CheckoutConfiguration( - credentials=OAuthSdkCredentials.init(http_client=self._http_client, - environment=self._environment, - client_id=self._client_id, - client_secret=self._client_secret, - scopes=self._scopes, - authorization_uri=authorization_uri), - environment=self._environment, - http_client=self._http_client, - environment_subdomain=self._environment_subdomain) - else: - configuration = CheckoutConfiguration( - credentials=OAuthSdkCredentials.init(http_client=self._http_client, - environment=self._environment, - client_id=self._client_id, - client_secret=self._client_secret, - scopes=self._scopes, - authorization_uri=authorization_uri), - environment=self._environment, - http_client=self._http_client) + configuration = CheckoutConfiguration( + credentials=OAuthSdkCredentials.init(http_client=self._http_client, + environment=self._environment, + client_id=self._client_id, + client_secret=self._client_secret, + scopes=self._scopes, + authorization_uri=authorization_uri), + environment=self._environment, + http_client=self._http_client, + environment_subdomain=environment_subdomain) return CheckoutApi(configuration) diff --git a/checkout_sdk/previous/previous_sdk.py b/checkout_sdk/previous/previous_sdk.py index 38c093d1..7dd4f3f9 100644 --- a/checkout_sdk/previous/previous_sdk.py +++ b/checkout_sdk/previous/previous_sdk.py @@ -27,18 +27,18 @@ class PreviousSdk(PreviousStaticKeys): def __init__(self): super().__init__() + # The Previous (ABC) platform predates merchant-specific subdomains, so it is exempt from + # the mandatory environment_subdomain/use_legacy_domain configuration. + def _requires_environment_subdomain(self) -> bool: + return False + def build(self): validate_secret_key(self._SECRET_KEY_PATTERN, self._secret_key) validate_public_key(self._PUBLIC_KEY_PATTERN, self._public_key) - if self._environment_subdomain is not None: - configuration = CheckoutConfiguration( - credentials=PreviousKeysSdkCredentials(secret_key=self._secret_key, public_key=self._public_key), - environment=self._environment, - http_client=self._http_client, - environment_subdomain=self._environment_subdomain) - else: - configuration = CheckoutConfiguration( - credentials=PreviousKeysSdkCredentials(secret_key=self._secret_key, public_key=self._public_key), - environment=self._environment, - http_client=self._http_client) + self._validate_environment_settings() + configuration = CheckoutConfiguration( + credentials=PreviousKeysSdkCredentials(secret_key=self._secret_key, public_key=self._public_key), + environment=self._environment, + http_client=self._http_client, + environment_subdomain=self._environment_subdomain) return CheckoutApi(ApiClient(configuration, configuration.environment.base_uri), configuration) diff --git a/tests/accounts/accounts_integration_test.py b/tests/accounts/accounts_integration_test.py index 3fd14c1f..175a12ec 100644 --- a/tests/accounts/accounts_integration_test.py +++ b/tests/accounts/accounts_integration_test.py @@ -1,5 +1,6 @@ from __future__ import absolute_import +import warnings import os from datetime import datetime, timedelta, timezone @@ -21,13 +22,17 @@ @pytest.fixture(scope='class') def accounts_checkout_api(): - return CheckoutSdk \ + builder = CheckoutSdk \ .builder() \ .oauth() \ .client_credentials(client_id=os.environ.get('CHECKOUT_DEFAULT_OAUTH_ACCOUNTS_CLIENT_ID'), client_secret=os.environ.get('CHECKOUT_DEFAULT_OAUTH_ACCOUNTS_CLIENT_SECRET')) \ - .scopes([OAuthScopes.ACCOUNTS, OAuthScopes.FILES]) \ - .build() + .scopes([OAuthScopes.ACCOUNTS, OAuthScopes.FILES]) + # The sandbox OAuth clients are not provisioned for the merchant-specific subdomain, so the + # token request would come back invalid_client. Opting out explicitly until they are. + with warnings.catch_warnings(): + warnings.simplefilter('ignore', DeprecationWarning) + return builder.use_legacy_domain().build() def test_should_create_get_and_update_onboard_entity(accounts_checkout_api): diff --git a/tests/accounts/accounts_payout_schedules_integration_test.py b/tests/accounts/accounts_payout_schedules_integration_test.py index 35498b38..c511eb2e 100644 --- a/tests/accounts/accounts_payout_schedules_integration_test.py +++ b/tests/accounts/accounts_payout_schedules_integration_test.py @@ -1,5 +1,6 @@ from __future__ import absolute_import +import warnings import os import pytest @@ -14,13 +15,17 @@ @pytest.fixture(scope='class') def payout_schedules_api(): - return CheckoutSdk \ + builder = CheckoutSdk \ .builder() \ .oauth() \ .client_credentials(client_id=os.environ.get('CHECKOUT_DEFAULT_OAUTH_PAYOUT_SCHEDULE_CLIENT_ID'), client_secret=os.environ.get('CHECKOUT_DEFAULT_OAUTH_PAYOUT_SCHEDULE_CLIENT_SECRET')) \ - .scopes([OAuthScopes.MARKETPLACE]) \ - .build() + .scopes([OAuthScopes.MARKETPLACE]) + # The sandbox OAuth clients are not provisioned for the merchant-specific subdomain, so the + # token request would come back invalid_client. Opting out explicitly until they are. + with warnings.catch_warnings(): + warnings.simplefilter('ignore', DeprecationWarning) + return builder.use_legacy_domain().build() @pytest.mark.skip(reason='not available') diff --git a/tests/checkout_configuration_test.py b/tests/checkout_configuration_test.py index db197d2b..20237fc5 100644 --- a/tests/checkout_configuration_test.py +++ b/tests/checkout_configuration_test.py @@ -6,6 +6,7 @@ from checkout_sdk.checkout_configuration import CheckoutConfiguration from checkout_sdk.environment import Environment +from checkout_sdk.exception import CheckoutArgumentException from checkout_sdk.environment_subdomain import EnvironmentSubdomain from checkout_sdk.default_keys_credentials import DefaultKeysSdkCredentials from checkout_sdk.http_client_interface import HttpClientBuilderInterface @@ -83,43 +84,13 @@ def test_should_create_configuration_with_subdomain(subdomain, expected_url): @pytest.mark.parametrize( - "subdomain, expected_url", - [ - ("", "https://api.sandbox.checkout.com/"), - (" ", "https://api.sandbox.checkout.com/"), - (" ", "https://api.sandbox.checkout.com/"), - (" - ", "https://api.sandbox.checkout.com/"), - ("a b", "https://api.sandbox.checkout.com/"), - ("ab c1.", "https://api.sandbox.checkout.com/"), - ("foo-", "https://api.sandbox.checkout.com/"), - ("-foo", "https://api.sandbox.checkout.com/"), - ("FooBar", "https://api.sandbox.checkout.com/"), - ("test-123", "https://api.sandbox.checkout.com/"), - ("foo-bar", "https://api.sandbox.checkout.com/"), - ("pl-", "https://api.sandbox.checkout.com/") - ] + "subdomain", + ["", " ", " ", " - ", "a b", "ab c1.", "foo-", "-foo", "FooBar", "test-123", "foo-bar", "pl-"] ) -def test_should_create_configuration_with_bad_subdomain(subdomain, expected_url): - credentials = DefaultKeysSdkCredentials( - os.environ.get("CHECKOUT_DEFAULT_SECRET_KEY"), - os.environ.get("CHECKOUT_DEFAULT_PUBLIC_KEY") - ) - http_client = Mock(spec=HttpClientBuilderInterface) - - environment_subdomain = EnvironmentSubdomain(Environment.sandbox(), subdomain) - - configuration = CheckoutConfiguration( - credentials=credentials, - environment=Environment.sandbox(), - http_client=http_client, - environment_subdomain=environment_subdomain - ) - - assert configuration.credentials == credentials - assert configuration.environment.base_uri == Environment.sandbox().base_uri - assert configuration.http_client == http_client - assert configuration.environment_subdomain.base_uri == expected_url - assert configuration.environment_subdomain.authorization_uri == "https://access.sandbox.checkout.com/connect/token" +def test_should_fail_with_bad_subdomain(subdomain): + with pytest.raises(CheckoutArgumentException) as excinfo: + EnvironmentSubdomain(Environment.sandbox(), subdomain) + assert "invalid environment subdomain" in str(excinfo.value) def test_should_create_configuration_with_subdomain_for_production(): diff --git a/tests/checkout_default_sdk_test.py b/tests/checkout_default_sdk_test.py index 3bf63059..0f47a7cb 100644 --- a/tests/checkout_default_sdk_test.py +++ b/tests/checkout_default_sdk_test.py @@ -13,6 +13,7 @@ def test_should_create_default_sdk(): .secret_key(os.environ.get("CHECKOUT_DEFAULT_SECRET_KEY")) \ .public_key(os.environ.get("CHECKOUT_DEFAULT_PUBLIC_KEY")) \ .environment(Environment.sandbox()) \ + .environment_subdomain('123domain') \ .build() sdk = CheckoutSdk \ @@ -20,12 +21,66 @@ def test_should_create_default_sdk(): .secret_key(os.environ.get("CHECKOUT_DEFAULT_SECRET_KEY")) \ .public_key(os.environ.get("CHECKOUT_DEFAULT_PUBLIC_KEY")) \ .environment(Environment.production()) \ + .environment_subdomain('123domain') \ .build() assert sdk is not None assert sdk.tokens is not None +def test_should_create_default_sdk_with_legacy_domain(): + with pytest.deprecated_call(): + sdk = CheckoutSdk \ + .builder() \ + .secret_key(os.environ.get("CHECKOUT_DEFAULT_SECRET_KEY")) \ + .public_key(os.environ.get("CHECKOUT_DEFAULT_PUBLIC_KEY")) \ + .environment(Environment.sandbox()) \ + .use_legacy_domain() \ + .build() + + assert sdk is not None + assert sdk.tokens is not None + + +def test_should_fail_without_subdomain_or_legacy_domain(): + with pytest.raises(CheckoutArgumentException) as excinfo: + CheckoutSdk \ + .builder() \ + .secret_key(os.environ.get("CHECKOUT_DEFAULT_SECRET_KEY")) \ + .public_key(os.environ.get("CHECKOUT_DEFAULT_PUBLIC_KEY")) \ + .environment(Environment.sandbox()) \ + .build() + + assert "environment_subdomain is required" in str(excinfo.value) + + +def test_should_fail_with_both_subdomain_and_legacy_domain(): + with pytest.raises(CheckoutArgumentException) as excinfo, pytest.deprecated_call(): + CheckoutSdk \ + .builder() \ + .secret_key(os.environ.get("CHECKOUT_DEFAULT_SECRET_KEY")) \ + .public_key(os.environ.get("CHECKOUT_DEFAULT_PUBLIC_KEY")) \ + .environment(Environment.sandbox()) \ + .environment_subdomain('123domain') \ + .use_legacy_domain() \ + .build() + + assert "cannot both be set" in str(excinfo.value) + + +def test_should_fail_with_invalid_subdomain(): + with pytest.raises(CheckoutArgumentException) as excinfo: + CheckoutSdk \ + .builder() \ + .secret_key(os.environ.get("CHECKOUT_DEFAULT_SECRET_KEY")) \ + .public_key(os.environ.get("CHECKOUT_DEFAULT_PUBLIC_KEY")) \ + .environment(Environment.sandbox()) \ + .environment_subdomain('not a subdomain') \ + .build() + + assert "invalid environment subdomain" in str(excinfo.value) + + def test_should_create_default_sdk_with_subdomain(): sdk_1 = CheckoutSdk \ .builder() \ diff --git a/tests/conftest.py b/tests/conftest.py index fd0953f1..d098ca4a 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -1,5 +1,6 @@ import logging import os +import warnings import pytest import requests @@ -30,16 +31,21 @@ def previous_api(): @pytest.fixture(scope='session', autouse=True) def default_api(): - return CheckoutSdk() \ - .builder() \ - .secret_key(os.environ.get('CHECKOUT_DEFAULT_SECRET_KEY')) \ - .public_key(os.environ.get('CHECKOUT_DEFAULT_PUBLIC_KEY')) \ - .build() + # The sandbox OAuth clients are not provisioned for the merchant-specific subdomain, so the + # token request would come back invalid_client. Opting out explicitly until they are. + with warnings.catch_warnings(): + warnings.simplefilter('ignore', DeprecationWarning) + return CheckoutSdk() \ + .builder() \ + .secret_key(os.environ.get('CHECKOUT_DEFAULT_SECRET_KEY')) \ + .public_key(os.environ.get('CHECKOUT_DEFAULT_PUBLIC_KEY')) \ + .use_legacy_domain() \ + .build() @pytest.fixture(scope='session', autouse=True) def oauth_api(): - return CheckoutSdk() \ + builder = CheckoutSdk() \ .builder() \ .oauth() \ .client_credentials(client_id=os.environ.get('CHECKOUT_DEFAULT_OAUTH_CLIENT_ID'), @@ -50,8 +56,11 @@ def oauth_api(): OAuthScopes.FILES, OAuthScopes.TRANSFERS, OAuthScopes.BALANCES_VIEW, OAuthScopes.VAULT_CARD_METADATA, OAuthScopes.FINANCIAL_ACTIONS, OAuthScopes.VAULT_REAL_TIME_ACCOUNT_UPDATER, OAuthScopes.PAYMENTS_SEARCH, - OAuthScopes.GATEWAY_PAYMENT_CANCELLATIONS]) \ - .build() + OAuthScopes.GATEWAY_PAYMENT_CANCELLATIONS]) + # See default_api above for why the legacy domain is used here. + with warnings.catch_warnings(): + warnings.simplefilter('ignore', DeprecationWarning) + return builder.use_legacy_domain().build() @pytest.fixture(scope='session', autouse=True) diff --git a/tests/issuing/conftest.py b/tests/issuing/conftest.py index b097c165..e8437caa 100644 --- a/tests/issuing/conftest.py +++ b/tests/issuing/conftest.py @@ -1,3 +1,4 @@ +import warnings import os import pytest @@ -15,15 +16,18 @@ @pytest.fixture(scope='module', autouse=True) def issuing_checkout_api(): - api = CheckoutSdk \ + builder = CheckoutSdk \ .builder() \ .oauth() \ .client_credentials(client_id=os.environ.get('CHECKOUT_DEFAULT_OAUTH_ISSUING_CLIENT_ID'), client_secret=os.environ.get('CHECKOUT_DEFAULT_OAUTH_ISSUING_CLIENT_SECRET')) \ .scopes([OAuthScopes.ISSUING_CLIENT, OAuthScopes.ISSUING_CARD_MGMT, - OAuthScopes.ISSUING_CONTROLS_READ, OAuthScopes.ISSUING_CONTROLS_WRITE]) \ - .build() - return api + OAuthScopes.ISSUING_CONTROLS_READ, OAuthScopes.ISSUING_CONTROLS_WRITE]) + # The sandbox OAuth clients are not provisioned for the merchant-specific subdomain, so the + # token request would come back invalid_client. Opting out explicitly until they are. + with warnings.catch_warnings(): + warnings.simplefilter('ignore', DeprecationWarning) + return builder.use_legacy_domain().build() @pytest.fixture(scope='module') diff --git a/tests/oauth_integration_test.py b/tests/oauth_integration_test.py index 179eab7c..edc3dbb3 100644 --- a/tests/oauth_integration_test.py +++ b/tests/oauth_integration_test.py @@ -1,3 +1,4 @@ +import warnings from checkout_sdk.checkout_sdk import CheckoutSdk from checkout_sdk.customers.customers import CustomerRequest from checkout_sdk.environment import Environment @@ -18,14 +19,18 @@ def test_should_create_customer_with_oauth(oauth_api): def test_should_fail_init_authorization_invalid_credentials(): try: - CheckoutSdk \ + builder = CheckoutSdk \ .builder() \ .oauth() \ .client_credentials(client_id='fake_id', client_secret='fake_secret') \ .environment(Environment.sandbox()) \ - .scopes([OAuthScopes.GATEWAY, OAuthScopes.VAULT]) \ - .build() + .scopes([OAuthScopes.GATEWAY, OAuthScopes.VAULT]) + # The sandbox OAuth clients are not provisioned for the merchant-specific subdomain, so + # the token request would come back invalid_client. Opting out explicitly until they are. + with warnings.catch_warnings(): + warnings.simplefilter('ignore', DeprecationWarning) + builder.use_legacy_domain().build() except CheckoutException as err: assert err.args[0] == 'OAuth client_credentials authentication failed with error: (invalid_client)' @@ -39,6 +44,7 @@ def test_should_fail_init_authorization_invalid_credentials_and_host(): client_secret='fake_secret') \ .authorization_uri('https://test.checkout.com') \ .environment(Environment.sandbox()) \ + .environment_subdomain('123domain') \ .scopes([OAuthScopes.GATEWAY, OAuthScopes.VAULT]) \ .build() except CheckoutException as err: diff --git a/tests/payments/request_apm_payments_integration_test.py b/tests/payments/request_apm_payments_integration_test.py index 445d5621..14458eba 100644 --- a/tests/payments/request_apm_payments_integration_test.py +++ b/tests/payments/request_apm_payments_integration_test.py @@ -1,5 +1,6 @@ from __future__ import absolute_import +import warnings import os import pytest @@ -10,7 +11,8 @@ from checkout_sdk.exception import CheckoutApiException from checkout_sdk.payments.payment_apm import RequestIdealSource, RequestTamaraSource, \ PaymentRequestWeChatPaySource, RequestAlipayPlusSource, RequestP24Source, RequestKnetSource, \ - RequestBancontactSource, RequestMultiBancoSource, RequestPostFinanceSource, RequestStcPaySource, RequestAlmaSource, \ + RequestBancontactSource, RequestMultiBancoSource, RequestPostFinanceSource, RequestStcPaySource, \ + RequestAlmaSource, \ RequestKlarnaSource, RequestFawrySource, RequestTrustlySource, RequestCvConnectSource, RequestIllicadoSource, \ RequestSepaSource, RequestGiropaySource, RequestEpsSource, RequestBizumSource, RequestOctopusSource, \ RequestPlaidSource, RequestSequraSource @@ -143,12 +145,16 @@ def test_should_request_tamara_payment(): payment_request.reference = 'ORD-5023-4E89' payment_request.items = [product] - preview_api = CheckoutSdk \ + preview_builder = CheckoutSdk \ .builder() \ .oauth() \ .client_credentials(client_id=os.environ.get('CHECKOUT_PREVIEW_OAUTH_CLIENT_ID'), - client_secret=os.environ.get('CHECKOUT_PREVIEW_OAUTH_CLIENT_SECRET')) \ - .build() + client_secret=os.environ.get('CHECKOUT_PREVIEW_OAUTH_CLIENT_SECRET')) + # The sandbox OAuth clients are not provisioned for the merchant-specific subdomain, so the + # token request would come back invalid_client. Opting out explicitly until they are. + with warnings.catch_warnings(): + warnings.simplefilter('ignore', DeprecationWarning) + preview_api = preview_builder.use_legacy_domain().build() payment_response = retriable(callback=preview_api.payments.request_payment, payment_request=payment_request)