From 23cfc25f4c47516230584050a7e7541f8d38ebb9 Mon Sep 17 00:00:00 2001 From: Jessica Matsuoka Date: Thu, 6 Mar 2025 17:32:03 +0100 Subject: [PATCH 1/2] DEVEXP-758: SinchClient Configuration - Update unit tests to validate all credentials - Update README to explain which credentials must be set for each API Signed-off-by: Jessica Matsuoka --- README.md | 53 +++++++++++++++++++++----------- tests/unit/test_client.py | 18 +++++++++++ tests/unit/test_configuration.py | 53 ++++++++++++++++++++++++-------- 3 files changed, 93 insertions(+), 31 deletions(-) diff --git a/README.md b/README.md index 750fc3f6..7381f6e3 100644 --- a/README.md +++ b/README.md @@ -33,47 +33,64 @@ For more information on the Sinch APIs on which this SDK is based, refer to the You can install this package by typing: `pip install sinch` +## Products + +Sinch client provides access to the following Sinch products: +- Numbers +- SMS +- Verification +- Voice API +- Conversation API (beta release) + + ## Getting started + ### Client initialization -To initialize communication with Sinch backed, credentials obtained from Sinch portal have to be provided to the main client class of this SDK. -It's highly advised to not hardcode those credentials, but to fetch them from environment variables: +To establish a connection with the Sinch backend, you must provide the appropriate credentials based on the API +you intend to use. For security best practices, avoid hardcoding credentials. +Instead, retrieve them from environment variables. + +#### Verification and Voice APIs + +To initialize the client for the **Verification** and **Voice** APIs, use the following credentials: ```python from sinch import SinchClient sinch_client = SinchClient( - key_id="key_id", - key_secret="key_secret", - project_id="some_project", application_key="application_key", application_secret="application_secret" ) ``` +#### SMS API +For the SMS API in **Australia (AU)**, **Brazil (BR)**, **Canada (CA)**, **the United States (US)**, +and **the European Union (EU)**, provide the following parameters: + ```python -import os from sinch import SinchClient sinch_client = SinchClient( - key_id=os.getenv("KEY_ID"), - key_secret=os.getenv("KEY_SECRET"), - project_id=os.getenv("PROJECT_ID"), - application_key=os.getenv("APPLICATION_KEY"), - application_secret=os.getenv("APPLICATION_SECRET") + service_plan_id="service_plan_id", + sms_api_token="api_token" ) ``` -## Products +#### All Other Sinch APIs +For all other Sinch APIs, including SMS in US and EU regions, use the following parameters: -Sinch client provides access to the following Sinch products: -- Numbers -- SMS -- Verification -- Voice API -- Conversation API (beta release) +```python +from sinch import SinchClient + +sinch_client = SinchClient( + key_id="key_id", + key_secret="key_secret", + project_id="project_id", +) +``` ## Logging diff --git a/tests/unit/test_client.py b/tests/unit/test_client.py index 24907c27..0ae159d0 100644 --- a/tests/unit/test_client.py +++ b/tests/unit/test_client.py @@ -20,18 +20,36 @@ def test_sinch_client_async_initialization(): assert sinch_client_async +def test_sinch_client_empty_expects_initialization(): + """ Test that SinchClient can be initialized with no parameters """ + sinch_client_sync = SinchClient() + assert sinch_client_sync + + +def test_sinch_client_async_empty_expects_initialization(): + """ Test that SinchClientAsync can be initialized with no parameters """ + sinch_client_async = SinchClientAsync() + assert sinch_client_async + + def test_sinch_client_has_all_business_domains(sinch_client_sync): + """ Test that SinchClient has all domains """ assert hasattr(sinch_client_sync, "authentication") assert hasattr(sinch_client_sync, "sms") assert hasattr(sinch_client_sync, "conversation") assert hasattr(sinch_client_sync, "numbers") + assert hasattr(sinch_client_sync, "verification") + assert hasattr(sinch_client_sync, "voice") def test_sinch_client_async_has_all_business_domains(sinch_client_async): + """ Test that SinchClientAsync has all domains """ assert hasattr(sinch_client_async, "authentication") assert hasattr(sinch_client_async, "sms") assert hasattr(sinch_client_async, "conversation") assert hasattr(sinch_client_async, "numbers") + assert hasattr(sinch_client_async, "verification") + assert hasattr(sinch_client_async, "voice") def test_sinch_client_has_configuration_object(sinch_client_sync): diff --git a/tests/unit/test_configuration.py b/tests/unit/test_configuration.py index 010660b1..d10871cf 100644 --- a/tests/unit/test_configuration.py +++ b/tests/unit/test_configuration.py @@ -1,21 +1,48 @@ +import pytest +from logging import Logger, getLogger from sinch.core.clients.sinch_client_configuration import Configuration from sinch.core.adapters.requests_http_transport import HTTPTransportRequests -from sinch.core.token_manager import TokenManager +from sinch.core.adapters.httpx_adapter import HTTPXTransport +from sinch.core.token_manager import TokenManager, TokenManagerAsync + + +@pytest.mark.parametrize( + "transport_class, token_manager_class, client_fixture", + [ + (HTTPTransportRequests, TokenManager, "sinch_client_sync"), + (HTTPXTransport, TokenManagerAsync, "sinch_client_async") + ] +) +def test_configuration_happy_capy_expects_initialization( + request, transport_class, token_manager_class, client_fixture + ): + """ Test that Configuration can be initialized with all parameters """ + sinch_client = request.getfixturevalue(client_fixture) - -def test_configuration_initialization_happy_path(sinch_client_sync): client_configuration = Configuration( - key_id="Rodney", - key_secret="Mullen", - project_id="Is the King!", - transport=HTTPTransportRequests(sinch_client_sync), - token_manager=TokenManager(sinch_client_sync) + key_id="CapyKey", + key_secret="CapybaraWhisper", + project_id="CapybaraProjectX", + logger=getLogger("CapyTrace"), + connection_timeout=10, + application_key="AppybaraKey", + application_secret="SecretHabitatEntry", + service_plan_id="CappyPremiumPlan", + sms_api_token="HappyCappyToken", + transport=transport_class(sinch_client), + token_manager=token_manager_class(sinch_client) ) - assert client_configuration.key_id == "Rodney" - assert client_configuration.key_secret == "Mullen" - assert client_configuration.project_id == "Is the King!" - assert isinstance(client_configuration.transport, HTTPTransportRequests) - assert isinstance(client_configuration.token_manager, TokenManager) + + assert client_configuration.key_id == "CapyKey" + assert client_configuration.key_secret == "CapybaraWhisper" + assert client_configuration.project_id == "CapybaraProjectX" + assert isinstance(client_configuration.logger, Logger) + assert client_configuration.application_key == "AppybaraKey" + assert client_configuration.application_secret == "SecretHabitatEntry" + assert client_configuration.service_plan_id == "CappyPremiumPlan" + assert client_configuration.sms_api_token == "HappyCappyToken" + assert isinstance(client_configuration.transport, transport_class) + assert isinstance(client_configuration.token_manager, token_manager_class) def test_set_sms_region_property_and_check_that_sms_origin_was_updated(sinch_client_sync): From b02b46abc755b4383dbf8743f25faf172608ad9e Mon Sep 17 00:00:00 2001 From: Jessica Matsuoka Date: Fri, 7 Mar 2025 08:52:52 +0100 Subject: [PATCH 2/2] chore: unify and clean up unit tests --- README.md | 12 +++--- tests/unit/test_client.py | 78 ++++++++++++--------------------------- 2 files changed, 29 insertions(+), 61 deletions(-) diff --git a/README.md b/README.md index 7381f6e3..ebf9ad93 100644 --- a/README.md +++ b/README.md @@ -35,10 +35,10 @@ You can install this package by typing: ## Products -Sinch client provides access to the following Sinch products: -- Numbers -- SMS -- Verification +The Sinch client provides access to the following Sinch products: +- Numbers API +- SMS API +- Verification API - Voice API - Conversation API (beta release) @@ -86,9 +86,9 @@ For all other Sinch APIs, including SMS in US and EU regions, use the following from sinch import SinchClient sinch_client = SinchClient( - key_id="key_id", - key_secret="key_secret", project_id="project_id", + key_id="key_id", + key_secret="key_secret" ) ``` diff --git a/tests/unit/test_client.py b/tests/unit/test_client.py index 0ae159d0..da3b947c 100644 --- a/tests/unit/test_client.py +++ b/tests/unit/test_client.py @@ -1,62 +1,30 @@ +import pytest from sinch import SinchClient, SinchClientAsync from sinch.core.clients.sinch_client_configuration import Configuration - -def test_sinch_client_initialization(): - sinch_client_sync = SinchClient( - key_id="test", - key_secret="test_secret", - project_id="test_project_id" - ) - assert sinch_client_sync - - -def test_sinch_client_async_initialization(): - sinch_client_async = SinchClientAsync( +@pytest.mark.parametrize("client", [SinchClient, SinchClientAsync]) +def test_sinch_client_initialization(client): + """ Test that SinchClient and SinchClientAsync can be initialized with or without parameters """ + sinch_client = client( key_id="test", key_secret="test_secret", project_id="test_project_id" ) - assert sinch_client_async - - -def test_sinch_client_empty_expects_initialization(): - """ Test that SinchClient can be initialized with no parameters """ - sinch_client_sync = SinchClient() - assert sinch_client_sync - - -def test_sinch_client_async_empty_expects_initialization(): - """ Test that SinchClientAsync can be initialized with no parameters """ - sinch_client_async = SinchClientAsync() - assert sinch_client_async - - -def test_sinch_client_has_all_business_domains(sinch_client_sync): - """ Test that SinchClient has all domains """ - assert hasattr(sinch_client_sync, "authentication") - assert hasattr(sinch_client_sync, "sms") - assert hasattr(sinch_client_sync, "conversation") - assert hasattr(sinch_client_sync, "numbers") - assert hasattr(sinch_client_sync, "verification") - assert hasattr(sinch_client_sync, "voice") - - -def test_sinch_client_async_has_all_business_domains(sinch_client_async): - """ Test that SinchClientAsync has all domains """ - assert hasattr(sinch_client_async, "authentication") - assert hasattr(sinch_client_async, "sms") - assert hasattr(sinch_client_async, "conversation") - assert hasattr(sinch_client_async, "numbers") - assert hasattr(sinch_client_async, "verification") - assert hasattr(sinch_client_async, "voice") - - -def test_sinch_client_has_configuration_object(sinch_client_sync): - assert hasattr(sinch_client_sync, "configuration") - assert isinstance(sinch_client_sync.configuration, Configuration) - - -def test_sinch_client_async_has_configuration_object(sinch_client_async): - assert hasattr(sinch_client_async, "configuration") - assert isinstance(sinch_client_async.configuration, Configuration) + assert sinch_client + + sinch_client_empty = client() + assert sinch_client_empty + + +@pytest.mark.parametrize("client", ["sinch_client_sync", "sinch_client_async"]) +def test_sinch_client_expects_all_attributes(request, client): + """ Test that SinchClient and SinchClientAsync have all attributes""" + client_instance = request.getfixturevalue(client) + assert hasattr(client_instance, "authentication") + assert hasattr(client_instance, "sms") + assert hasattr(client_instance, "conversation") + assert hasattr(client_instance, "numbers") + assert hasattr(client_instance, "verification") + assert hasattr(client_instance, "voice") + assert hasattr(client_instance, "configuration") + assert isinstance(client_instance.configuration, Configuration)