diff --git a/.bumpversion.cfg b/.bumpversion.cfg deleted file mode 100644 index 4a44daaa..00000000 --- a/.bumpversion.cfg +++ /dev/null @@ -1,12 +0,0 @@ -[bumpversion] -<<<<<<< HEAD -current_version = 4.0.0b0 -======= -current_version = 3.11.0 ->>>>>>> main -commit = True -tag = False - -[bumpversion:file:src/vonage/__init__.py] - -[bumpversion:file:setup.py] diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md deleted file mode 100644 index 5b653254..00000000 --- a/CONTRIBUTING.md +++ /dev/null @@ -1,19 +0,0 @@ -# Getting Involved - -Thanks for your interest in the project, we'd love to have you involved! Check out the sections below to find out more about what to do next... - -## Documentation -Check out our [Documentaion](https://developer.nexmo.com/documentation) - -## Opening an Issue - -We always welcome issues, if you've seen something that isn't quite right or you have a suggestion for a new feature, please go ahead and open an issue in this project. Include as much information as you have, it really helps. - -## Making a Code Change - -We're always open to pull requests, but these should be small and clearly described so that we can understand what you're trying to do. Feel free to open an issue first and get some discussion going. - -When you're ready to start coding, fork this repository to your own GitHub account and make your changes in a new branch. Once you're happy, open a pull request and explain what the change is and why you think we should include it in our project. - - - diff --git a/README.md b/README.md new file mode 100644 index 00000000..46f7f581 --- /dev/null +++ b/README.md @@ -0,0 +1 @@ +New monorepo structure for the Vonage Python SDK \ No newline at end of file diff --git a/old-version/requirements.txt b/old-version/requirements.txt index cd2fa4cb..7d779ad3 100644 --- a/old-version/requirements.txt +++ b/old-version/requirements.txt @@ -1,5 +1,5 @@ -e . -pytest==7.2.0 +pytest==7.4.2 responses==0.22.0 coverage pydantic>=2.3.0 diff --git a/old-version/setup.py b/old-version/setup.py index 188df601..ababac92 100644 --- a/old-version/setup.py +++ b/old-version/setup.py @@ -21,7 +21,7 @@ package_dir={"": "src"}, platforms=["any"], install_requires=[ - "vonage-jwt>=1.0.0", + "vonage-jwt>=1.1.0", "requests>=2.4.2", "pytz>=2018.5", "pydantic>=2.3.0", @@ -35,5 +35,6 @@ "Programming Language :: Python :: 3.9", "Programming Language :: Python :: 3.10", "Programming Language :: Python :: 3.11", + "Programming Language :: Python :: 3.12", ], ) diff --git a/old-version/src/vonage/_internal.py b/old-version/src/vonage/_internal.py deleted file mode 100644 index 5d6d2d74..00000000 --- a/old-version/src/vonage/_internal.py +++ /dev/null @@ -1,31 +0,0 @@ -from __future__ import annotations -from typing import TYPE_CHECKING - -if TYPE_CHECKING: - from vonage import Client - - -def _format_date_param(params, key, format="%Y-%m-%d %H:%M:%S"): - """ - Utility function to convert datetime values to strings. - - If the value is already a str, or is not in the dict, no change is made. - - :param params: A `dict` of params that may contain a `datetime` value. - :param key: The datetime value to be converted to a `str` - :param format: The `strftime` format to be used to format the date. The default value is '%Y-%m-%d %H:%M:%S' - """ - if key in params: - param = params[key] - if hasattr(param, "strftime"): - params[key] = param.strftime(format) - - -def set_auth_type(client: Client) -> str: - """Sets the authentication type used. If a JWT Client has been created, - it will create a JWT and use JWT authentication.""" - - if hasattr(client, '_jwt_client'): - return 'jwt' - else: - return 'header' diff --git a/old-version/src/vonage/meetings.py b/old-version/src/vonage/meetings.py deleted file mode 100644 index a506bddc..00000000 --- a/old-version/src/vonage/meetings.py +++ /dev/null @@ -1,173 +0,0 @@ -from .errors import MeetingsError - -from typing_extensions import Literal -import logging -import requests - - -logger = logging.getLogger("vonage") - - -class Meetings: - """Class containing methods used to create and manage meetings using the Meetings API.""" - - _auth_type = 'jwt' - - def __init__(self, client): - self._client = client - self._meetings_api_host = client.meetings_api_host() - - def list_rooms(self, page_size: str = 20, start_id: str = None, end_id: str = None): - params = Meetings.set_start_and_end_params(start_id, end_id) - params['page_size'] = page_size - return self._client.get( - self._meetings_api_host, '/rooms', params, auth_type=Meetings._auth_type - ) - - def create_room(self, params: dict = {}): - if 'display_name' not in params: - raise MeetingsError( - 'You must include a value for display_name as a field in the params dict when creating a meeting room.' - ) - if 'type' not in params or 'type' in params and params['type'] != 'long_term': - if 'expires_at' in params: - raise MeetingsError('Cannot set "expires_at" for an instant room.') - elif params['type'] == 'long_term' and 'expires_at' not in params: - raise MeetingsError('You must set a value for "expires_at" for a long-term room.') - - return self._client.post( - self._meetings_api_host, '/rooms', params, auth_type=Meetings._auth_type - ) - - def get_room(self, room_id: str): - return self._client.get( - self._meetings_api_host, f'/rooms/{room_id}', auth_type=Meetings._auth_type - ) - - def update_room(self, room_id: str, params: dict): - return self._client.patch( - self._meetings_api_host, f'/rooms/{room_id}', params, auth_type=Meetings._auth_type - ) - - def add_theme_to_room(self, room_id: str, theme_id: str): - params = {'update_details': {'theme_id': theme_id}} - return self._client.patch( - self._meetings_api_host, f'/rooms/{room_id}', params, auth_type=Meetings._auth_type - ) - - def get_recording(self, recording_id: str): - return self._client.get( - self._meetings_api_host, f'/recordings/{recording_id}', auth_type=Meetings._auth_type - ) - - def delete_recording(self, recording_id: str): - return self._client.delete( - self._meetings_api_host, f'/recordings/{recording_id}', auth_type=Meetings._auth_type - ) - - def get_session_recordings(self, session_id: str): - return self._client.get( - self._meetings_api_host, - f'/sessions/{session_id}/recordings', - auth_type=Meetings._auth_type, - ) - - def list_dial_in_numbers(self): - return self._client.get( - self._meetings_api_host, '/dial-in-numbers', auth_type=Meetings._auth_type - ) - - def list_themes(self): - return self._client.get(self._meetings_api_host, '/themes', auth_type=Meetings._auth_type) - - def create_theme(self, params: dict): - if 'main_color' not in params or 'brand_text' not in params: - raise MeetingsError('Values for "main_color" and "brand_text" must be specified') - - return self._client.post( - self._meetings_api_host, '/themes', params, auth_type=Meetings._auth_type - ) - - def get_theme(self, theme_id: str): - return self._client.get( - self._meetings_api_host, f'/themes/{theme_id}', auth_type=Meetings._auth_type - ) - - def delete_theme(self, theme_id: str, force: bool = False): - params = {'force': force} - return self._client.delete( - self._meetings_api_host, - f'/themes/{theme_id}', - params=params, - auth_type=Meetings._auth_type, - ) - - def update_theme(self, theme_id: str, params: dict): - return self._client.patch( - self._meetings_api_host, f'/themes/{theme_id}', params, auth_type=Meetings._auth_type - ) - - def list_rooms_with_theme_id( - self, theme_id: str, page_size: int = 20, start_id: str = None, end_id: str = None - ): - params = Meetings.set_start_and_end_params(start_id, end_id) - params['page_size'] = page_size - - return self._client.get( - self._meetings_api_host, - f'/themes/{theme_id}/rooms', - params, - auth_type=Meetings._auth_type, - ) - - def update_application_theme(self, theme_id: str): - params = {'update_details': {'default_theme_id': theme_id}} - return self._client.patch( - self._meetings_api_host, '/applications', params, auth_type=Meetings._auth_type - ) - - def upload_logo_to_theme( - self, theme_id: str, path_to_image: str, logo_type: Literal['white', 'colored', 'favicon'] - ): - params = self._get_logo_upload_url(logo_type) - self._upload_to_aws(params, path_to_image) - self._add_logo_to_theme(theme_id, params['fields']['key']) - return f'Logo upload to theme: {theme_id} was successful.' - - def _get_logo_upload_url(self, logo_type): - upload_urls = self._client.get( - self._meetings_api_host, '/themes/logos-upload-urls', auth_type=Meetings._auth_type - ) - for url_object in upload_urls: - if url_object['fields']['logoType'] == logo_type: - return url_object - raise MeetingsError('Cannot find the upload URL for the specified logo type.') - - def _upload_to_aws(self, params, path_to_image): - form = {**params['fields'], 'file': open(path_to_image, 'rb')} - - logger.debug(f"POST to {params['url']} to upload file {path_to_image}") - logo_upload = requests.post( - url=params['url'], - files=form, - ) - if logo_upload.status_code != 204: - raise MeetingsError(f'Logo upload process failed. {logo_upload.content}') - - def _add_logo_to_theme(self, theme_id: str, key: str): - params = {'keys': [key]} - return self._client.put( - self._meetings_api_host, - f'/themes/{theme_id}/finalizeLogos', - params, - auth_type=Meetings._auth_type, - ) - - @staticmethod - def set_start_and_end_params(start_id, end_id): - params = {} - if start_id is not None: - params['start_id'] = start_id - if end_id is not None: - params['end_id'] = end_id - return params diff --git a/old-version/src/vonage/messages.py b/old-version/src/vonage/messages.py deleted file mode 100644 index 2658c0c4..00000000 --- a/old-version/src/vonage/messages.py +++ /dev/null @@ -1,113 +0,0 @@ -from ._internal import set_auth_type -from .errors import MessagesError - -import re - - -class Messages: - valid_message_channels = {'sms', 'mms', 'whatsapp', 'messenger', 'viber_service'} - valid_message_types = { - 'sms': {'text'}, - 'mms': {'image', 'vcard', 'audio', 'video'}, - 'whatsapp': {'text', 'image', 'audio', 'video', 'file', 'template', 'sticker', 'custom'}, - 'messenger': {'text', 'image', 'audio', 'video', 'file'}, - 'viber_service': {'text', 'image', 'video', 'file'}, - } - - def __init__(self, client): - self._client = client - self._auth_type = set_auth_type(self._client) - - def send_message(self, params: dict): - self.validate_send_message_input(params) - - return self._client.post( - self._client.api_host(), - "/v1/messages", - params, - auth_type=self._auth_type, - ) - - def validate_send_message_input(self, params): - self._check_input_is_dict(params) - self._check_valid_message_channel(params) - self._check_valid_message_type(params) - self._check_valid_recipient(params) - self._check_valid_sender(params) - self._channel_specific_checks(params) - self._check_valid_client_ref(params) - - def _check_input_is_dict(self, params): - if type(params) is not dict: - raise MessagesError( - 'Parameters to the send_message method must be specified as a dictionary.' - ) - - def _check_valid_message_channel(self, params): - if params['channel'] not in Messages.valid_message_channels: - raise MessagesError( - f""" - "{params['channel']}" is an invalid message channel. - Must be one of the following types: {self.valid_message_channels}' - """ - ) - - def _check_valid_message_type(self, params): - if params['message_type'] not in self.valid_message_types[params['channel']]: - raise MessagesError( - f""" - "{params['message_type']}" is not a valid message type for channel "{params["channel"]}". - Must be one of the following types: {self.valid_message_types[params["channel"]]} - """ - ) - - def _check_valid_recipient(self, params): - if not isinstance(params['to'], str): - raise MessagesError(f'Message recipient ("to={params["to"]}") not in a valid format.') - elif params['channel'] != 'messenger' and not re.search(r'^[1-9]\d{6,14}$', params['to']): - raise MessagesError( - f'Message recipient number ("to={params["to"]}") not in a valid format.' - ) - elif params['channel'] == 'messenger' and not 0 < len(params['to']) < 50: - raise MessagesError( - f'Message recipient ID ("to={params["to"]}") not in a valid format.' - ) - - def _check_valid_sender(self, params): - if not isinstance(params['from'], str) or params['from'] == "": - raise MessagesError( - f'Message sender ("frm={params["from"]}") set incorrectly. Set a valid name or number for the sender.' - ) - - def _channel_specific_checks(self, params): - if ( - ( - params['channel'] == 'whatsapp' - and params['message_type'] == 'template' - and 'whatsapp' not in params - ) - or ( - params['channel'] == 'whatsapp' - and params['message_type'] == 'sticker' - and 'sticker' not in params - ) - or (params['channel'] == 'viber_service' and 'viber_service' not in params) - ): - raise MessagesError( - f'''You must specify all required properties for message channel "{params["channel"]}".''' - ) - elif params['channel'] == 'whatsapp' and params['message_type'] == 'sticker': - self._check_valid_whatsapp_sticker(params['sticker']) - - def _check_valid_client_ref(self, params): - if 'client_ref' in params: - if len(params['client_ref']) <= 100: - self._client_ref = params['client_ref'] - else: - raise MessagesError('client_ref can be a maximum of 100 characters.') - - def _check_valid_whatsapp_sticker(self, sticker): - if ('id' not in sticker and 'url' not in sticker) or ('id' in sticker and 'url' in sticker): - raise MessagesError( - 'Must specify one, and only one, of "id" or "url" in the "sticker" field.' - ) diff --git a/old-version/src/vonage/ncco_builder/__init__.py b/old-version/src/vonage/ncco_builder/__init__.py deleted file mode 100644 index f1908afe..00000000 --- a/old-version/src/vonage/ncco_builder/__init__.py +++ /dev/null @@ -1 +0,0 @@ -from .ncco import * diff --git a/old-version/src/vonage/proactive_connect.py b/old-version/src/vonage/proactive_connect.py deleted file mode 100644 index a9197a17..00000000 --- a/old-version/src/vonage/proactive_connect.py +++ /dev/null @@ -1,187 +0,0 @@ -from .errors import ProactiveConnectError - -import requests -import logging -from typing import List - -logger = logging.getLogger("vonage") - - -class ProactiveConnect: - def __init__(self, client): - self._client = client - self._auth_type = 'jwt' - - def list_all_lists(self, page: int = None, page_size: int = None): - params = self._check_pagination_params(page, page_size) - return self._client.get( - self._client.proactive_connect_host(), - '/v0.1/bulk/lists', - params, - auth_type=self._auth_type, - ) - - def create_list(self, params: dict): - self._validate_list_params(params) - return self._client.post( - self._client.proactive_connect_host(), - '/v0.1/bulk/lists', - params, - auth_type=self._auth_type, - ) - - def get_list(self, list_id: str): - return self._client.get( - self._client.proactive_connect_host(), - f'/v0.1/bulk/lists/{list_id}', - auth_type=self._auth_type, - ) - - def update_list(self, list_id: str, params: dict): - self._validate_list_params(params) - return self._client.put( - self._client.proactive_connect_host(), - f'/v0.1/bulk/lists/{list_id}', - params, - auth_type=self._auth_type, - ) - - def delete_list(self, list_id: str): - return self._client.delete( - self._client.proactive_connect_host(), - f'/v0.1/bulk/lists/{list_id}', - auth_type=self._auth_type, - ) - - def clear_list(self, list_id: str): - return self._client.post( - self._client.proactive_connect_host(), - f'/v0.1/bulk/lists/{list_id}/clear', - params=None, - auth_type=self._auth_type, - ) - - def sync_list_from_datasource(self, list_id: str): - return self._client.post( - self._client.proactive_connect_host(), - f'/v0.1/bulk/lists/{list_id}/fetch', - params=None, - auth_type=self._auth_type, - ) - - def list_all_items(self, list_id: str, page: int = None, page_size: int = None): - params = self._check_pagination_params(page, page_size) - return self._client.get( - self._client.proactive_connect_host(), - f'/v0.1/bulk/lists/{list_id}/items', - params, - auth_type=self._auth_type, - ) - - def create_item(self, list_id: str, data: dict): - params = {'data': data} - return self._client.post( - self._client.proactive_connect_host(), - f'/v0.1/bulk/lists/{list_id}/items', - params, - auth_type=self._auth_type, - ) - - def get_item(self, list_id: str, item_id: str): - return self._client.get( - self._client.proactive_connect_host(), - f'/v0.1/bulk/lists/{list_id}/items/{item_id}', - auth_type=self._auth_type, - ) - - def update_item(self, list_id: str, item_id: str, data: dict): - params = {'data': data} - return self._client.put( - self._client.proactive_connect_host(), - f'/v0.1/bulk/lists/{list_id}/items/{item_id}', - params, - auth_type=self._auth_type, - ) - - def delete_item(self, list_id: str, item_id: str): - return self._client.delete( - self._client.proactive_connect_host(), - f'/v0.1/bulk/lists/{list_id}/items/{item_id}', - auth_type=self._auth_type, - ) - - def download_list_items(self, list_id: str, file_path: str) -> List[dict]: - uri = f'https://{self._client.proactive_connect_host()}/v0.1/bulk/lists/{list_id}/items/download' - logger.debug( - f'GET request with Proactive Connect to {repr(uri)}, downloading items from list {list_id} to file {file_path}' - ) - headers = {**self._client.headers, 'Authorization': self._client._create_jwt_auth_string()} - response = requests.get( - uri, - headers=headers, - ) - if 200 <= response.status_code < 300: - with open(file_path, 'wb') as file: - file.write(response.content) - else: - return self._client.parse(self._client.proactive_connect_host(), response) - - def upload_list_items(self, list_id: str, file_path: str): - uri = f'https://{self._client.proactive_connect_host()}/v0.1/bulk/lists/{list_id}/items/import' - with open(file_path, 'rb') as csv_file: - logger.debug( - f'POST request with Proactive Connect uploading {file_path} to {repr(uri)}' - ) - headers = { - **self._client.headers, - 'Authorization': self._client._create_jwt_auth_string(), - } - response = requests.post( - uri, - headers=headers, - files={'file': ('list_items.csv', csv_file, 'text/csv')}, - ) - return self._client.parse(self._client.proactive_connect_host(), response) - - def list_events(self, page: int = None, page_size: int = None): - params = self._check_pagination_params(page, page_size) - return self._client.get( - self._client.proactive_connect_host(), - '/v0.1/bulk/events', - params, - auth_type=self._auth_type, - ) - - def _check_pagination_params(self, page: int = None, page_size: int = None) -> dict: - params = {} - if page is not None: - if type(page) == int and page > 0: - params['page'] = page - elif page <= 0: - raise ProactiveConnectError('"page" must be an int > 0.') - if page_size is not None: - if type(page_size) == int and page_size > 0: - params['page_size'] = page_size - elif page_size and page_size <= 0: - raise ProactiveConnectError('"page_size" must be an int > 0.') - return params - - def _validate_list_params(self, params: dict): - if 'name' not in params: - raise ProactiveConnectError('You must supply a name for the new list.') - if ( - 'datasource' in params - and 'type' in params['datasource'] - and params['datasource']['type'] == 'salesforce' - ): - self._check_salesforce_params_correct(params['datasource']) - - def _check_salesforce_params_correct(self, datasource): - if 'integration_id' not in datasource or 'soql' not in datasource: - raise ProactiveConnectError( - 'You must supply a value for "integration_id" and "soql" when creating a list with Salesforce.' - ) - if type(datasource['integration_id']) is not str or type(datasource['soql']) is not str: - raise ProactiveConnectError( - 'You must supply values for "integration_id" and "soql" as strings.' - ) diff --git a/old-version/src/vonage/subaccounts.py b/old-version/src/vonage/subaccounts.py deleted file mode 100644 index bc88fa14..00000000 --- a/old-version/src/vonage/subaccounts.py +++ /dev/null @@ -1,163 +0,0 @@ -from __future__ import annotations -from typing import TYPE_CHECKING, Optional, Union - -from .errors import SubaccountsError - -if TYPE_CHECKING: - from vonage import Client - - -class Subaccounts: - """Class containing methods for working with the Vonage Subaccounts API.""" - - default_start_date = '1970-01-01T00:00:00Z' - - def __init__(self, client: Client): - self._client = client - self._api_key = self._client.api_key - self._api_host = self._client.api_host() - self._auth_type = 'header' - - def list_subaccounts(self): - return self._client.get( - self._api_host, - f'/accounts/{self._api_key}/subaccounts', - auth_type=self._auth_type, - ) - - def create_subaccount( - self, - name: str, - secret: Optional[str] = None, - use_primary_account_balance: Optional[bool] = None, - ): - params = {'name': name, 'secret': secret} - if self._is_boolean(use_primary_account_balance): - params['use_primary_account_balance'] = use_primary_account_balance - - return self._client.post( - self._api_host, - f'/accounts/{self._api_key}/subaccounts', - params=params, - auth_type=self._auth_type, - ) - - def get_subaccount(self, subaccount_key: str): - return self._client.get( - self._api_host, - f'/accounts/{self._api_key}/subaccounts/{subaccount_key}', - auth_type=self._auth_type, - ) - - def modify_subaccount( - self, - subaccount_key: str, - suspended: Optional[bool] = None, - use_primary_account_balance: Optional[bool] = None, - name: Optional[str] = None, - ): - params = {'name': name} - if self._is_boolean(suspended): - params['suspended'] = suspended - if self._is_boolean(use_primary_account_balance): - params['use_primary_account_balance'] = use_primary_account_balance - - return self._client.patch( - self._api_host, - f'/accounts/{self._api_key}/subaccounts/{subaccount_key}', - params=params, - auth_type=self._auth_type, - ) - - def list_credit_transfers( - self, - start_date: str = default_start_date, - end_date: Optional[str] = None, - subaccount: Optional[str] = None, - ): - params = { - 'start_date': start_date, - 'end_date': end_date, - 'subaccount': subaccount, - } - - return self._client.get( - self._api_host, - f'/accounts/{self._api_key}/credit-transfers', - params=params, - auth_type=self._auth_type, - ) - - def transfer_credit( - self, - from_: str, - to: str, - amount: Union[float, int], - reference: str = None, - ): - params = { - 'from': from_, - 'to': to, - 'amount': amount, - 'reference': reference, - } - - return self._client.post( - self._api_host, - f'/accounts/{self._api_key}/credit-transfers', - params=params, - auth_type=self._auth_type, - ) - - def list_balance_transfers( - self, - start_date: str = default_start_date, - end_date: Optional[str] = None, - subaccount: Optional[str] = None, - ): - params = { - 'start_date': start_date, - 'end_date': end_date, - 'subaccount': subaccount, - } - - return self._client.get( - self._api_host, - f'/accounts/{self._api_key}/balance-transfers', - params=params, - auth_type=self._auth_type, - ) - - def transfer_balance( - self, - from_: str, - to: str, - amount: Union[float, int], - reference: str = None, - ): - params = {'from': from_, 'to': to, 'amount': amount, 'reference': reference} - - return self._client.post( - self._api_host, - f'/accounts/{self._api_key}/balance-transfers', - params=params, - auth_type=self._auth_type, - ) - - def transfer_number(self, from_: str, to: str, number: int, country: str): - params = {'from': from_, 'to': to, 'number': number, 'country': country} - return self._client.post( - self._api_host, - f'/accounts/{self._api_key}/transfer-number', - params=params, - auth_type=self._auth_type, - ) - - def _is_boolean(self, var): - if var is not None: - if type(var) == bool: - return True - else: - raise SubaccountsError( - f'If providing a value, it needs to be a boolean. You provided: "{var}"' - ) diff --git a/old-version/src/vonage/users.py b/old-version/src/vonage/users.py deleted file mode 100644 index 444e03d5..00000000 --- a/old-version/src/vonage/users.py +++ /dev/null @@ -1,72 +0,0 @@ -from __future__ import annotations -from typing import TYPE_CHECKING - -if TYPE_CHECKING: - from vonage import Client - -from .errors import UsersError -from ._internal import set_auth_type - - -class Users: - """Class containing methods for user management as part of the Application API.""" - - def __init__(self, client: Client): - self._client = client - self._auth_type = set_auth_type(self._client) - - def list_users( - self, - page_size: int = None, - order: str = 'asc', - cursor: str = None, - name: str = None, - ): - """ - Lists the name and user id of all users associated with the account. - For complete information on a user, call Users.get_user, passing in the user id. - """ - - if order.lower() not in ('asc', 'desc'): - raise UsersError( - 'Invalid order parameter. Must be one of: "asc", "desc", "ASC", "DESC".' - ) - - params = {'page_size': page_size, 'order': order.lower(), 'cursor': cursor, 'name': name} - return self._client.get( - self._client.api_host(), - '/v1/users', - params, - auth_type=self._auth_type, - ) - - def create_user(self, params: dict = None): - self._client.headers['Content-Type'] = 'application/json' - return self._client.post( - self._client.api_host(), - '/v1/users', - params, - auth_type=self._auth_type, - ) - - def get_user(self, user_id: str): - return self._client.get( - self._client.api_host(), - f'/v1/users/{user_id}', - auth_type=self._auth_type, - ) - - def update_user(self, user_id: str, params: dict): - return self._client.patch( - self._client.api_host(), - f'/v1/users/{user_id}', - params, - auth_type=self._auth_type, - ) - - def delete_user(self, user_id: str): - return self._client.delete( - self._client.api_host(), - f'/v1/users/{user_id}', - auth_type=self._auth_type, - ) diff --git a/old-version/src/vonage/voice.py b/old-version/src/vonage/voice.py deleted file mode 100644 index 9ea35597..00000000 --- a/old-version/src/vonage/voice.py +++ /dev/null @@ -1,110 +0,0 @@ -from urllib.parse import urlparse -from vonage_jwt.verify_jwt import verify_signature - - -class Voice: - auth_type = "jwt" - - def __init__(self, client): - self._client = client - - # Creates a new call session - def create_call(self, params, **kwargs): - """ - Adding Random From Number Feature for the Voice API, - if set to `True`, the from number will be randomly selected - from the pool of numbers available to the application making - the call. - - :param params is a dictionary that holds the 'from' and 'random_from_number' - - """ - if not params: - params = kwargs - - key = "from" - if key not in params: - params["random_from_number"] = True - - return self._client.post( - self._client.api_host(), - "/v1/calls", - params or kwargs, - auth_type=Voice.auth_type, - ) - - # Get call history paginated. Pass start and end dates to filter the retrieved information - def get_calls(self, params=None, **kwargs): - return self._client.get( - self._client.api_host(), - "/v1/calls", - params or kwargs, - auth_type=Voice.auth_type, - ) - - # Get a single call record by identifier - def get_call(self, uuid): - return self._client.get( - self._client.api_host(), f"/v1/calls/{uuid}", auth_type=Voice.auth_type - ) - - # Update call data using custom ncco - def update_call(self, uuid, params=None, **kwargs): - return self._client.put( - self._client.api_host(), - f"/v1/calls/{uuid}", - params or kwargs, - auth_type=Voice.auth_type, - ) - - # Plays audio streaming into call in progress - stream_url parameter is required - def send_audio(self, uuid, params=None, **kwargs): - return self._client.put( - self._client.api_host(), - f"/v1/calls/{uuid}/stream", - params or kwargs, - auth_type=Voice.auth_type, - ) - - # Play an speech into specified call - text parameter (text to speech) is required - def send_speech(self, uuid, params=None, **kwargs): - return self._client.put( - self._client.api_host(), - f"/v1/calls/{uuid}/talk", - params or kwargs, - auth_type=Voice.auth_type, - ) - - # plays DTMF tones into the specified call - def send_dtmf(self, uuid, params=None, **kwargs): - return self._client.put( - self._client.api_host(), - f"/v1/calls/{uuid}/dtmf", - params or kwargs, - auth_type=Voice.auth_type, - ) - - # Stops audio recently played into specified call - def stop_audio(self, uuid): - return self._client.delete( - self._client.api_host(), - f"/v1/calls/{uuid}/stream", - auth_type=Voice.auth_type, - ) - - # Stop a speech recently played into specified call - def stop_speech(self, uuid): - return self._client.delete( - self._client.api_host(), f"/v1/calls/{uuid}/talk", auth_type=Voice.auth_type - ) - - def get_recording(self, url): - hostname = urlparse(url).hostname - headers = self._client.headers - headers["Authorization"] = self._client._create_jwt_auth_string() - return self._client.parse( - hostname, self._client.session.get(url, headers=headers) - ) - - def verify_signature(self, token: str, signature: str) -> bool: - return verify_signature(token, signature) diff --git a/old-version/tests/data/account/secret_management/create-validation.json b/old-version/tests/data/account/secret_management/create-validation.json deleted file mode 100644 index c4f50dc4..00000000 --- a/old-version/tests/data/account/secret_management/create-validation.json +++ /dev/null @@ -1,12 +0,0 @@ -{ - "type": "https://developer.nexmo.com/api-errors/account/secret-management#validation", - "title": "Bad Request", - "detail": "The request failed due to validation errors", - "invalid_parameters": [ - { - "name": "secret", - "reason": "Does not meet complexity requirements" - } - ], - "instance": "797a8f199c45014ab7b08bfe9cc1c12c" -} diff --git a/old-version/tests/data/account/secret_management/create.json b/old-version/tests/data/account/secret_management/create.json deleted file mode 100644 index bf204c7c..00000000 --- a/old-version/tests/data/account/secret_management/create.json +++ /dev/null @@ -1,9 +0,0 @@ -{ - "_links": { - "self": { - "href": "/accounts/abcd1234/secrets/ad6dc56f-07b5-46e1-a527-85530e625800" - } - }, - "id": "ad6dc56f-07b5-46e1-a527-85530e625800", - "created_at": "2017-03-02T16:34:49Z" -} diff --git a/old-version/tests/data/account/secret_management/delete.json b/old-version/tests/data/account/secret_management/delete.json deleted file mode 100644 index e69de29b..00000000 diff --git a/old-version/tests/data/account/secret_management/get.json b/old-version/tests/data/account/secret_management/get.json deleted file mode 100644 index bf204c7c..00000000 --- a/old-version/tests/data/account/secret_management/get.json +++ /dev/null @@ -1,9 +0,0 @@ -{ - "_links": { - "self": { - "href": "/accounts/abcd1234/secrets/ad6dc56f-07b5-46e1-a527-85530e625800" - } - }, - "id": "ad6dc56f-07b5-46e1-a527-85530e625800", - "created_at": "2017-03-02T16:34:49Z" -} diff --git a/old-version/tests/data/account/secret_management/last-secret.json b/old-version/tests/data/account/secret_management/last-secret.json deleted file mode 100644 index fe8f85a6..00000000 --- a/old-version/tests/data/account/secret_management/last-secret.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "type": "https://developer.nexmo.com/api-errors/account/secret-management#delete-last-secret", - "title": "Secret Deletion Forbidden", - "detail": "Can not delete the last secret. The account must always have at least 1 secret active at any time", - "instance": "797a8f199c45014ab7b08bfe9cc1c12c" -} diff --git a/old-version/tests/data/account/secret_management/list.json b/old-version/tests/data/account/secret_management/list.json deleted file mode 100644 index 3600f601..00000000 --- a/old-version/tests/data/account/secret_management/list.json +++ /dev/null @@ -1,20 +0,0 @@ -{ - "_links": { - "self": { - "href": "/accounts/abcd1234/secrets" - } - }, - "_embedded": { - "secrets": [ - { - "_links": { - "self": { - "href": "/accounts/abcd1234/secrets/ad6dc56f-07b5-46e1-a527-85530e625800" - } - }, - "id": "ad6dc56f-07b5-46e1-a527-85530e625800", - "created_at": "2017-03-02T16:34:49Z" - } - ] - } -} diff --git a/old-version/tests/data/account/secret_management/max-secrets.json b/old-version/tests/data/account/secret_management/max-secrets.json deleted file mode 100644 index 22916988..00000000 --- a/old-version/tests/data/account/secret_management/max-secrets.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "type": "https://developer.nexmo.com/api-errors/account/secret-management#maximum-secrets-allowed", - "title": "Maxmimum number of secrets already met", - "detail": "This account has reached maximum number of '2' allowed secrets", - "instance": "797a8f199c45014ab7b08bfe9cc1c12c" -} diff --git a/old-version/tests/data/account/secret_management/missing.json b/old-version/tests/data/account/secret_management/missing.json deleted file mode 100644 index 279920e8..00000000 --- a/old-version/tests/data/account/secret_management/missing.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "type": "https://developer.nexmo.com/api-errors#invalid-api-key", - "title": "Invalid API Key", - "detail": "API key 'ABC123' does not exist, or you do not have access", - "instance": "797a8f199c45014ab7b08bfe9cc1c12c" -} diff --git a/old-version/tests/data/account/secret_management/unauthorized.json b/old-version/tests/data/account/secret_management/unauthorized.json deleted file mode 100644 index 8ee31d9a..00000000 --- a/old-version/tests/data/account/secret_management/unauthorized.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "type": "https://developer.nexmo.com/api-errors#unauthorized", - "title": "Invalid credentials supplied", - "detail": "You did not provide correct credentials.", - "instance": "797a8f199c45014ab7b08bfe9cc1c12c" -} diff --git a/old-version/tests/data/meetings/delete_recording_not_found.json b/old-version/tests/data/meetings/delete_recording_not_found.json deleted file mode 100644 index 0e38eb8f..00000000 --- a/old-version/tests/data/meetings/delete_recording_not_found.json +++ /dev/null @@ -1,5 +0,0 @@ -{ - "message": "Could not find recording", - "name": "NotFoundError", - "status": 404 -} \ No newline at end of file diff --git a/old-version/tests/data/meetings/delete_theme_in_use.json b/old-version/tests/data/meetings/delete_theme_in_use.json deleted file mode 100644 index b4ebb38b..00000000 --- a/old-version/tests/data/meetings/delete_theme_in_use.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "message": "could not delete theme", - "name": "BadRequestError", - "errors": [ - "Theme 90a21428-b74a-4221-adc3-783935d654db is used by 1 room" - ], - "status": 400 -} \ No newline at end of file diff --git a/old-version/tests/data/meetings/empty_themes.json b/old-version/tests/data/meetings/empty_themes.json deleted file mode 100644 index 9e26dfee..00000000 --- a/old-version/tests/data/meetings/empty_themes.json +++ /dev/null @@ -1 +0,0 @@ -{} \ No newline at end of file diff --git a/old-version/tests/data/meetings/get_recording.json b/old-version/tests/data/meetings/get_recording.json deleted file mode 100644 index 3f7c28dd..00000000 --- a/old-version/tests/data/meetings/get_recording.json +++ /dev/null @@ -1,12 +0,0 @@ -{ - "id": "e5b73c98-c087-4ee5-b61b-0ea08204fc65", - "session_id": "1_MX40NjMzOTg5Mn5-MTY3NDYxNDI4NjY5M35WM0xaVXBSc1lpT3hKWE1XQ2diM1B3cXB-fn4", - "started_at": "2023-01-25T02:38:31.000Z", - "ended_at": "2023-01-25T02:38:40.000Z", - "status": "uploaded", - "_links": { - "url": { - "href": "https://prod-meetings-recordings.s3.amazonaws.com/46339892/e5b73c98-c087-4ee5-b61b-0ea08204fc65/archive.mp4?AWSAccessKeyId=ASIA5NAYMMB6PXEIQICC&Expires=1674687032&Signature=RosB66sKsizUgoRz%2FWlQD7wUUJY%3D&response-content-disposition=attachment%3B%20filename%3D%22test_recording_room_2023-01-25T02%253A38%253A31.000Z.mp4%22&response-content-type=video%2Fmp4&x-amz-security-token=IQoJb3JpZ2luX2VjEKH%2F%2F%2F%2F%2F%2F%2F%2F%2F%2FwEaCXVzLWVhc3QtMSJHMEUCIQC5%2FrQRRq%2FzlJCqfgI9MN4Bq9kqmJTMPgZCo2KyaJ79IAIgdVVs9eYiuxB%2Bcc7QYJz7X4XQjSPcofAsves5rrjrsDgqiwQIGhAAGgw5MjEzMjE2Mjc3NzIiDHpbvFCfDDlkhb%2FFCyroA7OrSBCZr7MyZHXnHHPHOB99ctR%2F7XMzr3GAqnWfZTR5DY1zSYLkAKavjbS6Uw%2FMZW1PeETwLUrdwvLcvkpkU6EaXh2PZV07ty8AB9wIEyazRR9%2BqrCP9o23dlN1yMKPDnHGKO%2FGvxNFrHC9xJeFmaKrOz3f4oeRlFzJ%2FcMnXOI3vnuMa5jFf2GHDQGYkCWF7ertH%2FnIrdmj80%2BNOGsCb2O5%2BezLLlbJAd12MNj8C4m4xw%2BY0fNHZKKAjrG4UTE8%2BBdZ%2FQrMfbKfHaz736be3mln4ArCL1vUWRdQOQFP8impDXRDSMGS56qIdKgsYhEr6fcT%2Fy5KpYuVXxL4Z8TzVgrWwfcmlTxAJuvDgA6HxQAzY8BN8eQLxbaBWaiq%2BD0z6hDPIHKhZDYLQ4CSsxDRfL1DN%2FB155Os9kmombG5rZb%2BR1poIYTrlC16LjIN2JWgCovI8fRPgcjJ3JYEIdi0oE6Jq%2B0PdXbjbSZlekpkQRny3eOPuKhheFlmpweiEjwabVPq3kGyUeC03ZvOZ6giN34LdtM3m2gblmcO9t%2F1KvJwm49t2LJYqGMX9JnqOf6pSWqAZXERCoeAaE0SLzsI15pIix07e9fSY8HZJ49OL2%2FYdz%2BlY4rmkTTVo2v2iELhXS57S3ihkz3lMLS6xZ4GOqUB%2BLq1xiXSn3RAfctKCWM6fGctNnh77Tmn9cwKd8LZtXSZUIxGNYESIu4k%2BbgPZh%2B%2BLf%2BNAsgj6DtnpicEwoSxnbeMwrM6PWw8IH7GE%2FeHN8HFZqGwWiWSogeOv1YeFGL%2BWlXVS%2F5mx7uNTJx%2FHryd2JSYu3kn3MpY7cBU67jcTyesZQzR%2BTHIhLnNgTMNhdQ4st7lD4RaCsvTGqFkv6EnOV%2BU17hv" - } - } -} \ No newline at end of file diff --git a/old-version/tests/data/meetings/get_recording_not_found.json b/old-version/tests/data/meetings/get_recording_not_found.json deleted file mode 100644 index 9c2f8d66..00000000 --- a/old-version/tests/data/meetings/get_recording_not_found.json +++ /dev/null @@ -1,5 +0,0 @@ -{ - "message": "Recording not-a-real-recording-id was not found", - "name": "NotFoundError", - "status": 404 -} \ No newline at end of file diff --git a/old-version/tests/data/meetings/get_session_recordings.json b/old-version/tests/data/meetings/get_session_recordings.json deleted file mode 100644 index 782effe3..00000000 --- a/old-version/tests/data/meetings/get_session_recordings.json +++ /dev/null @@ -1,18 +0,0 @@ -{ - "_embedded": { - "recordings": [ - { - "id": "e5b73c98-c087-4ee5-b61b-0ea08204fc65", - "session_id": "1_MX40NjMzOTg5Mn5-MTY3NDYxNDI4NjY5M35WM0xaVXBSc1lpT3hKWE1XQ2diM1B3cXB-fn4", - "started_at": "2023-01-25T02:38:31.000Z", - "ended_at": "2023-01-25T02:38:40.000Z", - "status": "uploaded", - "_links": { - "url": { - "href": "https://prod-meetings-recordings.s3.amazonaws.com/46339892/e5b73c98-c087-4ee5-b61b-0ea08204fc65/archive.mp4?AWSAccessKeyId=ASIA5NAYMMB6JPDOLPNO&Expires=1674688058&Signature=0IzgnyLJFMP1TDkOyoBT4M54Le8%3D&response-content-disposition=attachment%3B%20filename%3D%22test_recording_room_2023-01-25T02%253A38%253A31.000Z.mp4%22&response-content-type=video%2Fmp4&x-amz-security-token=IQoJb3JpZ2luX2VjEKL%2F%2F%2F%2F%2F%2F%2F%2F%2F%2FwEaCXVzLWVhc3QtMSJHMEUCIBE0ejVJPxkEDjAF6cMuDC9nIeOU%2BUnUTSnfhi2prlHtAiEA1wiXNTR96lN%2Bgsb2yeQPM%2BF%2F4e6%2BA6%2B5CylWsM1gW%2BMqiwQIGhAAGgw5MjEzMjE2Mjc3NzIiDHEAZDKegwDhiMhj3CroA1%2B2SNg3m%2B%2FCmq3ELZnnEx8t9oYXmlY0dDRovuKNBdy5n4d%2FUhhR5DaoxOj8cAY7Yu8xZRM1oYQCbO2Qrgiy2Nki7FgHNljLldhbMN6txOnf7%2BP8r2XWD6x0D7ZN8hhA4LAoeTGaF4N7ZT3Oabti%2F6z5qw%2Bp85dak9CMd%2BToeUzqcmKlRhB56SrMgTofr2B8BOXgxxmFfdmrKllmJxsi2og5iLwWWdHNExV87fPout%2FMlQ0u5D1vj3F%2FtQGfAjkPnf1RSol%2BIxwIHPmKEiqpUSu0hwtPai8Ra1l4tml2Zv9SGZ1E8AZEAtmROL2fM4rl%2BtUOEAXTUWGO3G%2BcjGs6cPZB4ihzo6TqIFyGJoQ95pPFu6yiRa%2F31Z5DEHcom5Ux4%2Fxs0TMimuLP2CJ%2BuqKRiAb9w20wchouM9MaGjVYvTXs%2BJsVXQIwdGdJACIkK9CKZXNkYAbKnYfAkz8bi7rfFoJT1mZ6hSxG%2BNGp%2FYr7Vk%2FTSvoLO4%2F4%2FpiSyJs2Y7r6QbohXgmCkZTejJW3KxC4tCRGheVwyVwRC%2F%2FCMQpm34wEb0FL0sEfqxhl7Kbkm0RT1HwOlb3N4GmLERJcEcIpmmegEIRPQcbM2ohGq%2BbMrWvD8lmu1qyfu01cSZkl9xe1NtLtEFpxoxVSMOPFxZ4GOqUB69If14rWCah8hqaxxteZbVoDSmXJo7CrMDc8uaRgFQbNR6tj4WC2t21q%2BhTBRd3C%2F5zYTAAbILP3jkDDRt3SanOamRICcOKqOJFlRa6aCz2G%2F175CWu0Bz1wDGokaGAwz3G1CL%2B2t91JH8aPUHQkX87%2FGxJliywZfL2od%2FbyCR6bM%2FGbVPRuPX8fSXsTQZPjCMCt4GJv5%2Fq%2F3h9t0lf0AfCG9Hx%2F" - } - } - } - ] - } -} \ No newline at end of file diff --git a/old-version/tests/data/meetings/get_session_recordings_not_found.json b/old-version/tests/data/meetings/get_session_recordings_not_found.json deleted file mode 100644 index 11ebca44..00000000 --- a/old-version/tests/data/meetings/get_session_recordings_not_found.json +++ /dev/null @@ -1,5 +0,0 @@ -{ - "message": "Failed to find session recordings by id: not-a-real-session-id", - "name": "NotFoundError", - "status": 404 -} \ No newline at end of file diff --git a/old-version/tests/data/meetings/list_dial_in_numbers.json b/old-version/tests/data/meetings/list_dial_in_numbers.json deleted file mode 100644 index b2d4e165..00000000 --- a/old-version/tests/data/meetings/list_dial_in_numbers.json +++ /dev/null @@ -1,12 +0,0 @@ -[ - { - "number": "541139862166", - "locale": "es-AR", - "display_name": "Argentina" - }, - { - "number": "442381924626", - "locale": "en-GB", - "display_name": "United Kingdom" - } -] \ No newline at end of file diff --git a/old-version/tests/data/meetings/list_logo_upload_urls.json b/old-version/tests/data/meetings/list_logo_upload_urls.json deleted file mode 100644 index 8f4526b5..00000000 --- a/old-version/tests/data/meetings/list_logo_upload_urls.json +++ /dev/null @@ -1,47 +0,0 @@ -[ - { - "url": "https://s3.amazonaws.com/roomservice-whitelabel-logos-prod", - "fields": { - "Content-Type": "image/png", - "key": "auto-expiring-temp/logos/white/d92b31ae-fbf1-4709-a729-c0fa75368c25", - "logoType": "white", - "bucket": "roomservice-whitelabel-logos-prod", - "X-Amz-Algorithm": "AWS4-HMAC-SHA256", - "X-Amz-Credential": "some-credential", - "X-Amz-Date": "20230127T024303Z", - "X-Amz-Security-Token": "some-token", - "Policy": "some-policy", - "X-Amz-Signature": "some-signature" - } - }, - { - "url": "https://s3.amazonaws.com/roomservice-whitelabel-logos-prod", - "fields": { - "Content-Type": "image/png", - "key": "auto-expiring-temp/logos/colored/c4e00bac-781b-4bf0-bd5f-b9ff2cbc1b6c", - "logoType": "colored", - "bucket": "roomservice-whitelabel-logos-prod", - "X-Amz-Algorithm": "AWS4-HMAC-SHA256", - "X-Amz-Credential": "some-credential", - "X-Amz-Date": "20230127T024303Z", - "X-Amz-Security-Token": "some-token", - "Policy": "some-policy", - "X-Amz-Signature": "some-signature" - } - }, - { - "url": "https://s3.amazonaws.com/roomservice-whitelabel-logos-prod", - "fields": { - "Content-Type": "image/png", - "key": "auto-expiring-temp/logos/favicon/d7a81477-38f7-460c-b51f-1462b8426df5", - "logoType": "favicon", - "bucket": "roomservice-whitelabel-logos-prod", - "X-Amz-Algorithm": "AWS4-HMAC-SHA256", - "X-Amz-Credential": "some-credential", - "X-Amz-Date": "20230127T024303Z", - "X-Amz-Security-Token": "some-token", - "Policy": "some-policy", - "X-Amz-Signature": "some-signature" - } - } -] \ No newline at end of file diff --git a/old-version/tests/data/meetings/list_rooms_theme_id_not_found.json b/old-version/tests/data/meetings/list_rooms_theme_id_not_found.json deleted file mode 100644 index 410a75c4..00000000 --- a/old-version/tests/data/meetings/list_rooms_theme_id_not_found.json +++ /dev/null @@ -1,5 +0,0 @@ -{ - "message": "Failed to get rooms because theme id 90a21428-b74a-4221-adc3-783935d654dc not found", - "name": "NotFoundError", - "status": 404 -} \ No newline at end of file diff --git a/old-version/tests/data/meetings/list_rooms_with_theme_id.json b/old-version/tests/data/meetings/list_rooms_with_theme_id.json deleted file mode 100644 index 1e791055..00000000 --- a/old-version/tests/data/meetings/list_rooms_with_theme_id.json +++ /dev/null @@ -1,57 +0,0 @@ -{ - "page_size": 5, - "_embedded": [ - { - "id": "33791484-231c-421b-8349-96e1a44e27d2", - "display_name": "test_long_term_room", - "metadata": null, - "type": "long_term", - "expires_at": "2023-01-30T00:47:04.000Z", - "recording_options": { - "auto_record": false, - "record_only_owner": false - }, - "meeting_code": "613804614", - "_links": { - "host_url": { - "href": "https://meetings.vonage.com/updated_company_url/?room_token=613804614&participant_token=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCIsImtpZCI6IjU5N2NmYTAzLTY3NTQtNGE0ZC1hYjU1LWZiMTdkNzc4NzRjMSJ9.eyJwYXJ0aWNpcGFudElkIjoiN2MwYTQyNWQtMGFhZS00YmUxLWE1Y2UtMDNlMTNmNmYyNThiIiwiaWF0IjoxNjc0OTYzODg4fQ.46AYaDgMu_IdNPkmToKFGB_CqWYKM2xFpKU0vc3-E_E" - }, - "guest_url": { - "href": "https://meetings.vonage.com/updated_company_url/613804614" - } - }, - "created_at": "2023-01-25T00:50:37.722Z", - "is_available": true, - "expire_after_use": false, - "theme_id": "90a21428-b74a-4221-adc3-783935d654db", - "initial_join_options": { - "microphone_state": "default" - }, - "join_approval_level": "none", - "ui_settings": { - "language": "default" - }, - "available_features": { - "is_recording_available": false, - "is_chat_available": false, - "is_whiteboard_available": false, - "is_locale_switcher_available": false - } - } - ], - "_links": { - "first": { - "href": "api-eu.vonage.com/meetings/rooms?page_size=20" - }, - "self": { - "href": "api-eu.vonage.com/meetings/rooms?page_size=20&start_id=2009870" - }, - "prev": { - "href": "api-eu.vonage.com/meetings/rooms?page_size=20&end_id=2009869" - }, - "next": { - "href": "api-eu.vonage.com/meetings/rooms?page_size=20&start_id=2009871" - } - }, - "total_items": 1 -} \ No newline at end of file diff --git a/old-version/tests/data/meetings/list_themes.json b/old-version/tests/data/meetings/list_themes.json deleted file mode 100644 index dc8b5f98..00000000 --- a/old-version/tests/data/meetings/list_themes.json +++ /dev/null @@ -1,34 +0,0 @@ -[ - { - "theme_id": "1fc39568-bc50-464f-82dc-01e13bed0908", - "theme_name": "my_other_theme", - "domain": "VCP", - "account_id": "1234", - "application_id": "5678", - "main_color": "#FF0000", - "short_company_url": "my-other-company", - "brand_text": "My Other Company", - "brand_image_colored": null, - "brand_image_white": null, - "branded_favicon": null, - "brand_image_white_url": null, - "brand_image_colored_url": null, - "branded_favicon_url": null - }, - { - "theme_id": "90a21428-b74a-4221-adc3-783935d654db", - "theme_name": "my_theme", - "domain": "VCP", - "account_id": "1234", - "application_id": "5678", - "main_color": "#12f64e", - "short_company_url": "my-company", - "brand_text": "My Company", - "brand_image_colored": null, - "brand_image_white": null, - "branded_favicon": null, - "brand_image_white_url": null, - "brand_image_colored_url": null, - "branded_favicon_url": null - } -] \ No newline at end of file diff --git a/old-version/tests/data/meetings/logo_key_error.json b/old-version/tests/data/meetings/logo_key_error.json deleted file mode 100644 index ea9c9b18..00000000 --- a/old-version/tests/data/meetings/logo_key_error.json +++ /dev/null @@ -1,11 +0,0 @@ -{ - "message": "could not finalize logos", - "name": "BadRequestError", - "errors": [ - { - "logoKey": "not-a-key", - "code": "key_not_found" - } - ], - "status": 400 -} \ No newline at end of file diff --git a/old-version/tests/data/meetings/long_term_room.json b/old-version/tests/data/meetings/long_term_room.json deleted file mode 100644 index b73fcb09..00000000 --- a/old-version/tests/data/meetings/long_term_room.json +++ /dev/null @@ -1,37 +0,0 @@ -{ - "id": "33791484-231c-421b-8349-96e1a44e27d2", - "display_name": "test_long_term_room", - "metadata": null, - "type": "long_term", - "expires_at": "2023-01-30T00:47:04.000Z", - "recording_options": { - "auto_record": false, - "record_only_owner": false - }, - "meeting_code": "613804614", - "_links": { - "host_url": { - "href": "https://meetings.vonage.com/?room_token=613804614&participant_token=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCIsImtpZCI6IjU5N2NmYTAzLTY3NTQtNGE0ZC1hYjU1LWZiMTdkNzc4NzRjMSJ9.eyJwYXJ0aWNpcGFudElkIjoiN2MwYTQyNWQtMGFhZS00YmUxLWE1Y2UtMDNlMTNmNmYyNThiIiwiaWF0IjoxNjc0NjA3ODM3fQ.fm7q551LKnZaUcvZ30AmU62jRnvL94Do2sJKU0mHUmE" - }, - "guest_url": { - "href": "https://meetings.vonage.com/613804614" - } - }, - "created_at": "2023-01-25T00:50:37.722Z", - "is_available": true, - "expire_after_use": false, - "theme_id": null, - "initial_join_options": { - "microphone_state": "default" - }, - "join_approval_level": "none", - "ui_settings": { - "language": "default" - }, - "available_features": { - "is_recording_available": true, - "is_chat_available": true, - "is_whiteboard_available": true, - "is_locale_switcher_available": false - } -} \ No newline at end of file diff --git a/old-version/tests/data/meetings/long_term_room_with_theme.json b/old-version/tests/data/meetings/long_term_room_with_theme.json deleted file mode 100644 index eb8ec86e..00000000 --- a/old-version/tests/data/meetings/long_term_room_with_theme.json +++ /dev/null @@ -1,37 +0,0 @@ -{ - "id": "33791484-231c-421b-8349-96e1a44e27d2", - "display_name": "test_long_term_room", - "metadata": null, - "type": "long_term", - "expires_at": "2023-01-30T00:47:04.000Z", - "recording_options": { - "auto_record": false, - "record_only_owner": false - }, - "meeting_code": "613804614", - "_links": { - "host_url": { - "href": "https://meetings.vonage.com/updated_company_url/?room_token=613804614&participant_token=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCIsImtpZCI6IjU5N2NmYTAzLTY3NTQtNGE0ZC1hYjU1LWZiMTdkNzc4NzRjMSJ9.eyJwYXJ0aWNpcGFudElkIjoiN2MwYTQyNWQtMGFhZS00YmUxLWE1Y2UtMDNlMTNmNmYyNThiIiwiaWF0IjoxNjc0Nzg2NDYwfQ.XFjcJFNZU9Ez_4x-uGIj079TTvttNHkkfA54JTDqglM" - }, - "guest_url": { - "href": "https://meetings.vonage.com/updated_company_url/613804614" - } - }, - "created_at": "2023-01-25T00:50:37.722Z", - "is_available": true, - "expire_after_use": false, - "theme_id": "90a21428-b74a-4221-adc3-783935d654db", - "initial_join_options": { - "microphone_state": "default" - }, - "join_approval_level": "none", - "ui_settings": { - "language": "default" - }, - "available_features": { - "is_recording_available": false, - "is_chat_available": false, - "is_whiteboard_available": false, - "is_locale_switcher_available": false - } -} \ No newline at end of file diff --git a/old-version/tests/data/meetings/meeting_room.json b/old-version/tests/data/meetings/meeting_room.json deleted file mode 100644 index a0b134f7..00000000 --- a/old-version/tests/data/meetings/meeting_room.json +++ /dev/null @@ -1,38 +0,0 @@ -{ - "id": "b3142c46-d1c1-4405-baa6-85683827ed69", - "display_name": "my_test_room", - "metadata": null, - "type": "instant", - "expires_at": "2023-01-24T03:30:38.629Z", - "recording_options": { - "auto_record": false, - "record_only_owner": false - }, - "meeting_code": "412958792", - "_links": { - "host_url": { - "href": "https://meetings.vonage.com/?room_token=412958792&participant_token=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCIsImtpZCI6IjU5N2NmYTAzLTY3NTQtNGE0ZC1hYjU1LWZiMTdkNzc4NzRjMSJ9.eyJwYXJ0aWNpcGFudElkIjoiM2ExNWFkZmYtNDFmYy00NWFjLTg3Y2QtZmM2YjYyYjAwMTczIiwiaWF0IjoxNjc0NTMwNDM4fQ.Q0BPbu3ZyISYf1QaW2bLVNOrZ1tjQJCQ7nsOP_0us1E" - }, - "guest_url": { - "href": "https://meetings.vonage.com/412958792" - } - }, - "created_at": "2023-01-24T03:20:38.629Z", - "is_available": true, - "expire_after_use": false, - "theme_id": null, - "initial_join_options": { - "microphone_state": "default" - }, - "join_approval_level": "none", - "ui_settings": { - "language": "default" - }, - "available_features": { - "is_recording_available": true, - "is_chat_available": true, - "is_whiteboard_available": true, - "is_locale_switcher_available": false, - "is_captions_available": false - } -} \ No newline at end of file diff --git a/old-version/tests/data/meetings/multiple_fewer_rooms.json b/old-version/tests/data/meetings/multiple_fewer_rooms.json deleted file mode 100644 index 4a650eb0..00000000 --- a/old-version/tests/data/meetings/multiple_fewer_rooms.json +++ /dev/null @@ -1,94 +0,0 @@ -{ - "page_size": 2, - "_embedded": [ - { - "id": "4814804d-7c2d-4846-8c7d-4f6fae1f910a", - "display_name": "my_test_room", - "metadata": null, - "type": "instant", - "expires_at": "2023-01-24T03:25:23.341Z", - "recording_options": { - "auto_record": false, - "record_only_owner": false - }, - "meeting_code": "697975707", - "_links": { - "host_url": { - "href": "https://meetings.vonage.com/?room_token=697975707&participant_token=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCIsImtpZCI6IjU5N2NmYTAzLTY3NTQtNGE0ZC1hYjU1LWZiMTdkNzc4NzRjMSJ9.eyJwYXJ0aWNpcGFudElkIjoiZDIxMzM0YmMtNjljNi00MGI2LWE4NmYtNDVjYzRlNmQ5MDVlIiwiaWF0IjoxNjc0NTcyODg1fQ.qOmyuJL1eVqUzdTlAGKZX-h5Q-dTZnoKG4Jto5AzWHs" - }, - "guest_url": { - "href": "https://meetings.vonage.com/697975707" - } - }, - "created_at": "2023-01-24T03:15:23.342Z", - "is_available": true, - "expire_after_use": false, - "theme_id": null, - "initial_join_options": { - "microphone_state": "default" - }, - "join_approval_level": "none", - "ui_settings": { - "language": "default" - }, - "available_features": { - "is_recording_available": true, - "is_chat_available": true, - "is_whiteboard_available": true, - "is_locale_switcher_available": false - } - }, - { - "id": "de34416a-2a4c-4a59-a16a-8cd7d3121ea0", - "display_name": "my_test_room", - "metadata": null, - "type": "instant", - "expires_at": "2023-01-24T03:26:46.521Z", - "recording_options": { - "auto_record": false, - "record_only_owner": false - }, - "meeting_code": "254629696", - "_links": { - "host_url": { - "href": "https://meetings.vonage.com/?room_token=254629696&participant_token=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCIsImtpZCI6IjU5N2NmYTAzLTY3NTQtNGE0ZC1hYjU1LWZiMTdkNzc4NzRjMSJ9.eyJwYXJ0aWNpcGFudElkIjoiZGFhYzQ3YjEtMDZhNS00ZjA0LThjYmEtNDg1Y2VhZDdhYzYxIiwiaWF0IjoxNjc0NTcyODg1fQ.LOyItIhYtKHvhlGNmGFoE6diMH-dODckBVI0OraLB6A" - }, - "guest_url": { - "href": "https://meetings.vonage.com/254629696" - } - }, - "created_at": "2023-01-24T03:16:46.521Z", - "is_available": true, - "expire_after_use": false, - "theme_id": null, - "initial_join_options": { - "microphone_state": "default" - }, - "join_approval_level": "none", - "ui_settings": { - "language": "default" - }, - "available_features": { - "is_recording_available": true, - "is_chat_available": true, - "is_whiteboard_available": true, - "is_locale_switcher_available": false - } - } - ], - "_links": { - "first": { - "href": "api-eu.vonage.com/meetings/rooms?page_size=20" - }, - "self": { - "href": "api-eu.vonage.com/meetings/rooms?page_size=20&start_id=2006648" - }, - "prev": { - "href": "api-eu.vonage.com/meetings/rooms?page_size=20&end_id=2006647" - }, - "next": { - "href": "api-eu.vonage.com/meetings/rooms?page_size=20&start_id=2006655" - } - }, - "total_items": 2 -} \ No newline at end of file diff --git a/old-version/tests/data/meetings/theme.json b/old-version/tests/data/meetings/theme.json deleted file mode 100644 index 63bf8494..00000000 --- a/old-version/tests/data/meetings/theme.json +++ /dev/null @@ -1,16 +0,0 @@ -{ - "theme_id": "90a21428-b74a-4221-adc3-783935d654db", - "theme_name": "my_theme", - "domain": "VCP", - "account_id": "1234", - "application_id": "5678", - "main_color": "#12f64e", - "short_company_url": "my-company", - "brand_text": "My Company", - "brand_image_colored": null, - "brand_image_white": null, - "branded_favicon": null, - "brand_image_white_url": null, - "brand_image_colored_url": null, - "branded_favicon_url": null -} \ No newline at end of file diff --git a/old-version/tests/data/meetings/theme_name_in_use.json b/old-version/tests/data/meetings/theme_name_in_use.json deleted file mode 100644 index f374bb11..00000000 --- a/old-version/tests/data/meetings/theme_name_in_use.json +++ /dev/null @@ -1,5 +0,0 @@ -{ - "message": "theme_name already exists in application", - "name": "ConflictError", - "status": 409 -} \ No newline at end of file diff --git a/old-version/tests/data/meetings/theme_not_found.json b/old-version/tests/data/meetings/theme_not_found.json deleted file mode 100644 index d15a28cb..00000000 --- a/old-version/tests/data/meetings/theme_not_found.json +++ /dev/null @@ -1,5 +0,0 @@ -{ - "message": "could not find theme 90a21428-b74a-4221-adc3-783935d654dc", - "name": "NotFoundError", - "status": 404 -} \ No newline at end of file diff --git a/old-version/tests/data/meetings/transparent_logo.png b/old-version/tests/data/meetings/transparent_logo.png deleted file mode 100644 index 36f9b729..00000000 Binary files a/old-version/tests/data/meetings/transparent_logo.png and /dev/null differ diff --git a/old-version/tests/data/meetings/unauthorized.json b/old-version/tests/data/meetings/unauthorized.json deleted file mode 100644 index b6813760..00000000 --- a/old-version/tests/data/meetings/unauthorized.json +++ /dev/null @@ -1,4 +0,0 @@ -{ - "title": "Unauthorized", - "detail": "You did not provide correct credentials" -} \ No newline at end of file diff --git a/old-version/tests/data/meetings/update_application_theme.json b/old-version/tests/data/meetings/update_application_theme.json deleted file mode 100644 index 2fc0df4a..00000000 --- a/old-version/tests/data/meetings/update_application_theme.json +++ /dev/null @@ -1,5 +0,0 @@ -{ - "application_id": "my-application-id", - "account_id": "my-account-id", - "default_theme_id": "90a21428-b74a-4221-adc3-783935d654db" -} \ No newline at end of file diff --git a/old-version/tests/data/meetings/update_application_theme_id_not_found.json b/old-version/tests/data/meetings/update_application_theme_id_not_found.json deleted file mode 100644 index 329d8a96..00000000 --- a/old-version/tests/data/meetings/update_application_theme_id_not_found.json +++ /dev/null @@ -1,5 +0,0 @@ -{ - "message": "Failed to update application because theme id not-a-real-theme-id not found", - "name": "BadRequestError", - "status": 400 -} \ No newline at end of file diff --git a/old-version/tests/data/meetings/update_no_keys.json b/old-version/tests/data/meetings/update_no_keys.json deleted file mode 100644 index 0b9fc5ce..00000000 --- a/old-version/tests/data/meetings/update_no_keys.json +++ /dev/null @@ -1,5 +0,0 @@ -{ - "message": "\"update_details\" must have at least 1 key", - "name": "InputValidationError", - "status": 400 -} \ No newline at end of file diff --git a/old-version/tests/data/meetings/update_room.json b/old-version/tests/data/meetings/update_room.json deleted file mode 100644 index 64926ff5..00000000 --- a/old-version/tests/data/meetings/update_room.json +++ /dev/null @@ -1,37 +0,0 @@ -{ - "id": "33791484-231c-421b-8349-96e1a44e27d2", - "display_name": "test_long_term_room", - "metadata": null, - "type": "long_term", - "expires_at": "2023-01-30T00:47:04.000Z", - "recording_options": { - "auto_record": false, - "record_only_owner": false - }, - "meeting_code": "613804614", - "_links": { - "host_url": { - "href": "https://meetings.vonage.com/?room_token=613804614&participant_token=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCIsImtpZCI6IjU5N2NmYTAzLTY3NTQtNGE0ZC1hYjU1LWZiMTdkNzc4NzRjMSJ9.eyJwYXJ0aWNpcGFudElkIjoiN2MwYTQyNWQtMGFhZS00YmUxLWE1Y2UtMDNlMTNmNmYyNThiIiwiaWF0IjoxNjc0NjA3ODM3fQ.fm7q551LKnZaUcvZ30AmU62jRnvL94Do2sJKU0mHUmE" - }, - "guest_url": { - "href": "https://meetings.vonage.com/613804614" - } - }, - "created_at": "2023-01-25T00:50:37.722Z", - "is_available": true, - "expire_after_use": false, - "theme_id": null, - "initial_join_options": { - "microphone_state": "default" - }, - "join_approval_level": "none", - "ui_settings": { - "language": "default" - }, - "available_features": { - "is_recording_available": false, - "is_chat_available": false, - "is_whiteboard_available": false, - "is_locale_switcher_available": false - } -} \ No newline at end of file diff --git a/old-version/tests/data/meetings/update_room_type_error.json b/old-version/tests/data/meetings/update_room_type_error.json deleted file mode 100644 index d70fb112..00000000 --- a/old-version/tests/data/meetings/update_room_type_error.json +++ /dev/null @@ -1,5 +0,0 @@ -{ - "message": "The room with id: b3142c46-d1c1-4405-baa6-85683827ed69 could not be updated because of its type: temporary", - "name": "BadRequestError", - "status": 400 -} \ No newline at end of file diff --git a/old-version/tests/data/meetings/update_theme_already_exists.json b/old-version/tests/data/meetings/update_theme_already_exists.json deleted file mode 100644 index f374bb11..00000000 --- a/old-version/tests/data/meetings/update_theme_already_exists.json +++ /dev/null @@ -1,5 +0,0 @@ -{ - "message": "theme_name already exists in application", - "name": "ConflictError", - "status": 409 -} \ No newline at end of file diff --git a/old-version/tests/data/meetings/updated_theme.json b/old-version/tests/data/meetings/updated_theme.json deleted file mode 100644 index 514b7652..00000000 --- a/old-version/tests/data/meetings/updated_theme.json +++ /dev/null @@ -1,16 +0,0 @@ -{ - "theme_id": "90a21428-b74a-4221-adc3-783935d654db", - "theme_name": "updated_theme", - "domain": "VCP", - "account_id": "1234", - "application_id": "5678", - "main_color": "#FF0000", - "short_company_url": "updated_company_url", - "brand_text": "My Updated Company Name", - "brand_image_colored": null, - "brand_image_white": null, - "branded_favicon": null, - "brand_image_white_url": null, - "brand_image_colored_url": null, - "branded_favicon_url": null -} \ No newline at end of file diff --git a/old-version/tests/data/meetings/upload_to_aws_error.xml b/old-version/tests/data/meetings/upload_to_aws_error.xml deleted file mode 100644 index 467b8984..00000000 --- a/old-version/tests/data/meetings/upload_to_aws_error.xml +++ /dev/null @@ -1 +0,0 @@ -\nSignatureDoesNotMatchThe request signature we calculated does not match the signature you provided. Check your key and signing method.ASIA5NAYMMB6M7A2QEARb2f311449e26692a174ab2c7ca2afab24bd19c509cc611a4cef7cb2c5bb2ea9a5ZS7MSFN46X89NXAf+HV7uSpeawLv5lFvN+QiYP6swbiTMd/XaJeVGC+/pqKHlwlgKZ6vg+qBjV/ufb1e5WS/bxBM/Y= \ No newline at end of file diff --git a/old-version/tests/data/no_content.json b/old-version/tests/data/no_content.json deleted file mode 100644 index e69de29b..00000000 diff --git a/old-version/tests/data/private_key.txt b/old-version/tests/data/private_key.txt deleted file mode 100644 index 163ff367..00000000 --- a/old-version/tests/data/private_key.txt +++ /dev/null @@ -1,28 +0,0 @@ ------BEGIN PRIVATE KEY----- -MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQDQdAHqJHs/a+Ra -2ubvSd1vz/aWlJ9BqnMUtB7guTlyggdENAbleIkzep6mUHepDJdQh8Qv6zS3lpUe -K0UkDfr1/FvsvxurGw/YYPagUEhP/HxMbs2rnQTiAdWOT+Ux9vPABoyNYvZB90xN -IVhBDRWgkz1HPQBRNjFcm3NOol83h5Uwp5YroGTWx+rpmIiRhQj3mv6luk102d95 -4ulpPpzcYWKIpJNdclJrEkBZaghDZTOpbv79qd+ds9AVp1j8i9cG/owBJpsJWxfw -StMDpNeEZqopeQWmA121sSEsxpAbKJ5DA7F/lmckx74sulKHX1fDWT76cRhloaEQ -VmETdj0VAgMBAAECggEAZ+SBtchz8vKbsBqtAbM/XcR5Iqi1TR2eWMHDJ/65HpSm -+XuyujjerN0e6EZvtT4Uxmq8QaPJNP0kmhI31hXvsB0UVcUUDa4hshb1pIYO3Gq7 -Kr8I29EZB2mhndm9Ii9yYhEBiVA66zrNeR225kkWr97iqjhBibhoVr8Vc6oiqcIP -nFy5zSFtQSkhucaPge6rW00JSOD3wg2GM+rgS6r22t8YmqTzAwvwfil5pQfUngal -oywqLOf6CUYXPBleJc1KgaIIP/cSvqh6b/t25o2VXnI4rpRhtleORvYBbH6K6xLa -OWgg6B58T+0/QEqtZIAn4miYtVCkYLB78Ormc7Q9ewKBgQDuSytuYqxdZh/L/RDU -CErFcNO5I1e9fkLAs5dQEBvvdQC74+oA1MsDEVv0xehFa1JwPKSepmvB2UznZg9L -CtR7QKMDZWvS5xx4j0E/b+PiNQ/tlcFZB2UZ0JwviSxdd7omOTscq9c3RIhFHar1 -Y38Fixkfm44Ij/K3JqIi2v2QMwKBgQDf8TYOOmAr9UuipUDxMsRSqTGVIY8B+aEJ -W+2aLrqJVkLGTRfrbjzXWYo3+n7kNJjFgNkltDq6HYtufHMYRs/0PPtNR0w0cDPS -Xr7m2LNHTDcBalC/AS4yKZJLNLm+kXA84vkw4qiTjc0LSFxJkouTQzkea0l8EWHt -zRMv/qYVlwKBgBaJOWRJJK/4lo0+M7c5yYh+sSdTNlsPc9Sxp1/FBj9RO26JkXne -pgx2OdIeXWcjTTqcIZ13c71zhZhkyJF6RroZVNFfaCEcBk9IjQ0o0c504jq/7Pc0 -gdU9K2g7etykFBDFXNfLUKFDc/fFZIOskzi8/PVGStp4cqXrm23cdBqNAoGBAKtf -A2bP9ViuVjsZCyGJIAPBxlfBXpa8WSe4WZNrvwPqJx9pT6yyp4yE0OkVoJUyStaZ -S5M24NocUd8zDUC+r9TP9d+leAOI+Z87MgumOUuOX2mN2kzQsnFgrrsulhXnZmSx -rNBkI20HTqobrcP/iSAgiU1l/M4c3zwDe3N3A9HxAoGBAM2hYu0Ij6htSNgo/WWr -IEYYXuwf8hPkiuwzlaiWhD3eocgd4S8SsBu/bTCY19hQ2QbBPaYyFlNem+ynQyXx -IOacrgIHCrYnRCxjPfFF/MxgUHJb8ZoiexprP/FME5p0PoRQIEFYa+jVht3hT5wC -9aedWufq4JJb+akO6MVUjTvs ------END PRIVATE KEY----- diff --git a/old-version/tests/data/proactive_connect/create_list_400.json b/old-version/tests/data/proactive_connect/create_list_400.json deleted file mode 100644 index 307817dd..00000000 --- a/old-version/tests/data/proactive_connect/create_list_400.json +++ /dev/null @@ -1,10 +0,0 @@ -{ - "type": "https://developer.vonage.com/en/api-errors", - "title": "Request data did not validate", - "detail": "Bad Request", - "instance": "b6740287-41ad-41de-b950-f4e2d54cee86", - "errors": [ - "name must be longer than or equal to 1 and shorter than or equal to 255 characters", - "name must be a string" - ] -} \ No newline at end of file diff --git a/old-version/tests/data/proactive_connect/create_list_basic.json b/old-version/tests/data/proactive_connect/create_list_basic.json deleted file mode 100644 index ea3e77c2..00000000 --- a/old-version/tests/data/proactive_connect/create_list_basic.json +++ /dev/null @@ -1,16 +0,0 @@ -{ - "items_count": 0, - "datasource": { - "type": "manual" - }, - "id": "6994fd17-7691-4463-be16-172ab1430d97", - "sync_status": { - "value": "configured", - "metadata_modified": false, - "data_modified": false, - "dirty": false - }, - "name": "my_list", - "created_at": "2023-04-28T13:42:49.031Z", - "updated_at": "2023-04-28T13:42:49.031Z" -} \ No newline at end of file diff --git a/old-version/tests/data/proactive_connect/create_list_manual.json b/old-version/tests/data/proactive_connect/create_list_manual.json deleted file mode 100644 index 1241af8e..00000000 --- a/old-version/tests/data/proactive_connect/create_list_manual.json +++ /dev/null @@ -1,28 +0,0 @@ -{ - "items_count": 0, - "datasource": { - "type": "manual" - }, - "id": "9508e7b8-fe99-4fdf-b022-65d7e461db2d", - "sync_status": { - "value": "configured", - "metadata_modified": false, - "data_modified": false, - "dirty": false - }, - "name": "my_list", - "description": "my description", - "tags": [ - "vip", - "sport" - ], - "attributes": [ - { - "key": false, - "name": "phone_number", - "alias": "phone" - } - ], - "created_at": "2023-04-28T13:56:12.920Z", - "updated_at": "2023-04-28T13:56:12.920Z" -} \ No newline at end of file diff --git a/old-version/tests/data/proactive_connect/create_list_salesforce.json b/old-version/tests/data/proactive_connect/create_list_salesforce.json deleted file mode 100644 index c7729f78..00000000 --- a/old-version/tests/data/proactive_connect/create_list_salesforce.json +++ /dev/null @@ -1,30 +0,0 @@ -{ - "items_count": 0, - "datasource": { - "type": "salesforce", - "integration_id": "salesforce_credentials", - "soql": "select Id, LastName, FirstName, Phone, Email FROM Contact" - }, - "id": "246d17c4-79e6-4a25-8b4e-b777a83f6c30", - "sync_status": { - "value": "configured", - "metadata_modified": true, - "data_modified": true, - "dirty": true - }, - "name": "my_salesforce_list", - "description": "my salesforce description", - "tags": [ - "vip", - "sport" - ], - "attributes": [ - { - "key": false, - "name": "phone_number", - "alias": "phone" - } - ], - "created_at": "2023-04-28T14:16:49.375Z", - "updated_at": "2023-04-28T14:16:49.375Z" -} \ No newline at end of file diff --git a/old-version/tests/data/proactive_connect/csv_to_upload.csv b/old-version/tests/data/proactive_connect/csv_to_upload.csv deleted file mode 100644 index 06cbdfbb..00000000 --- a/old-version/tests/data/proactive_connect/csv_to_upload.csv +++ /dev/null @@ -1,4 +0,0 @@ -user,phone -alice,1234 -bob,5678 -charlie,9012 diff --git a/old-version/tests/data/proactive_connect/fetch_list_400.json b/old-version/tests/data/proactive_connect/fetch_list_400.json deleted file mode 100644 index 7e68f7f6..00000000 --- a/old-version/tests/data/proactive_connect/fetch_list_400.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "type": "https://developer.vonage.com/en/api-errors", - "title": "Request data did not validate", - "detail": "Cannot Fetch a manual list", - "instance": "4c34affd-df25-4bdc-b7c0-30076d3df003" -} \ No newline at end of file diff --git a/old-version/tests/data/proactive_connect/get_list.json b/old-version/tests/data/proactive_connect/get_list.json deleted file mode 100644 index 2920e6f9..00000000 --- a/old-version/tests/data/proactive_connect/get_list.json +++ /dev/null @@ -1,28 +0,0 @@ -{ - "items_count": 0, - "datasource": { - "type": "manual" - }, - "id": "9508e7b8-fe99-4fdf-b022-65d7e461db2d", - "created_at": "2023-04-28T13:56:12.920Z", - "updated_at": "2023-04-28T13:56:12.920Z", - "name": "my_list", - "description": "my description", - "tags": [ - "vip", - "sport" - ], - "attributes": [ - { - "key": false, - "name": "phone_number", - "alias": "phone" - } - ], - "sync_status": { - "value": "configured", - "metadata_modified": false, - "data_modified": false, - "dirty": false - } -} \ No newline at end of file diff --git a/old-version/tests/data/proactive_connect/item.json b/old-version/tests/data/proactive_connect/item.json deleted file mode 100644 index 5c5ecf96..00000000 --- a/old-version/tests/data/proactive_connect/item.json +++ /dev/null @@ -1,11 +0,0 @@ -{ - "id": "d91c39ed-7c34-4803-a139-34bb4b7c6d53", - "list_id": "246d17c4-79e6-4a25-8b4e-b777a83f6c30", - "data": { - "firstName": "John", - "lastName": "Doe", - "phone": "123456789101" - }, - "created_at": "2023-05-02T21:07:25.790Z", - "updated_at": "2023-05-02T21:07:25.790Z" -} \ No newline at end of file diff --git a/old-version/tests/data/proactive_connect/item_400.json b/old-version/tests/data/proactive_connect/item_400.json deleted file mode 100644 index 778065b0..00000000 --- a/old-version/tests/data/proactive_connect/item_400.json +++ /dev/null @@ -1,9 +0,0 @@ -{ - "type": "https://developer.vonage.com/en/api-errors", - "title": "Request data did not validate", - "detail": "Bad Request", - "instance": "8e2dd3f1-1718-48fc-98de-53e1d289d0b4", - "errors": [ - "data must be an object" - ] -} \ No newline at end of file diff --git a/old-version/tests/data/proactive_connect/list_404.json b/old-version/tests/data/proactive_connect/list_404.json deleted file mode 100644 index 80ba7ad7..00000000 --- a/old-version/tests/data/proactive_connect/list_404.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "type": "https://developer.vonage.com/en/api-errors", - "title": "The requested resource does not exist", - "detail": "Not Found", - "instance": "3e661bd2-e429-4887-b0d4-8f37352ab1d3" -} \ No newline at end of file diff --git a/old-version/tests/data/proactive_connect/list_all_items.json b/old-version/tests/data/proactive_connect/list_all_items.json deleted file mode 100644 index 28a6a795..00000000 --- a/old-version/tests/data/proactive_connect/list_all_items.json +++ /dev/null @@ -1,40 +0,0 @@ -{ - "total_items": 2, - "page": 1, - "page_size": 100, - "order": "asc", - "_embedded": { - "items": [ - { - "id": "04c7498c-bae9-40f9-bdcb-c4eabb0418fe", - "created_at": "2023-05-02T21:04:47.507Z", - "updated_at": "2023-05-02T21:04:47.507Z", - "list_id": "246d17c4-79e6-4a25-8b4e-b777a83f6c30", - "data": { - "test": 0, - "test2": 1 - } - }, - { - "id": "d91c39ed-7c34-4803-a139-34bb4b7c6d53", - "created_at": "2023-05-02T21:07:25.790Z", - "updated_at": "2023-05-02T21:07:25.790Z", - "list_id": "246d17c4-79e6-4a25-8b4e-b777a83f6c30", - "data": { - "phone": "123456789101", - "lastName": "Doe", - "firstName": "John" - } - } - ] - }, - "total_pages": 1, - "_links": { - "first": { - "href": "https://api-eu.vonage.com/v0.1/bulk/lists/246d17c4-79e6-4a25-8b4e-b777a83f6c30/items?page_size=100&order=asc&page=1" - }, - "self": { - "href": "https://api-eu.vonage.com/v0.1/bulk/lists/246d17c4-79e6-4a25-8b4e-b777a83f6c30/items?page_size=100&order=asc&page=1" - } - } -} \ No newline at end of file diff --git a/old-version/tests/data/proactive_connect/list_events.json b/old-version/tests/data/proactive_connect/list_events.json deleted file mode 100644 index b00ef80c..00000000 --- a/old-version/tests/data/proactive_connect/list_events.json +++ /dev/null @@ -1,70 +0,0 @@ -{ - "total_items": 1, - "page": 1, - "page_size": 100, - "total_pages": 1, - "_links": { - "self": { - "href": "https://api-eu.vonage.com/v0.1/bulk/events?page_size=100&page=1" - }, - "prev": { - "href": "https://api-eu.vonage.com/v0.1/bulk/events?page_size=100&page=1" - }, - "next": { - "href": "https://api-eu.vonage.com/v0.1/bulk/events?page_size=100&page=1" - }, - "first": { - "href": "https://api-eu.vonage.com/v0.1/bulk/events?page_size=100&page=1" - } - }, - "_embedded": { - "events": [ - { - "occurred_at": "2022-08-07T13:18:21.970Z", - "type": "action-call-succeeded", - "id": "e8e1eb4d-61e0-4099-8fa7-c96f1c0764ba", - "job_id": "c68e871a-c239-474d-a905-7b95f4563b7e", - "src_ctx": "et-e4ab4b75-9e7c-4f26-9328-394a5b842648", - "action_id": "26c5bbe2-113e-4201-bd93-f69e0a03d17f", - "data": { - "url": "https://postman-echo.com/post", - "args": {}, - "data": { - "from": "" - }, - "form": {}, - "json": { - "from": "" - }, - "files": {}, - "headers": { - "host": "postman-echo.com", - "user-agent": "got (https://github.com/sindresorhus/got)", - "content-type": "application/json", - "content-length": "11", - "accept-encoding": "gzip, deflate, br", - "x-amzn-trace-id": "Root=1-62efbb9e-53636b7b794accb87a3d662f", - "x-forwarded-port": "443", - "x-nexmo-trace-id": "8a6fed94-7296-4a39-9c52-348f12b4d61a", - "x-forwarded-proto": "https" - } - }, - "run_id": "7d0d4e5f-6453-4c63-87cf-f95b04377324", - "recipient_id": "14806904549" - }, - { - "occurred_at": "2022-08-07T13:18:20.289Z", - "type": "recipient-response", - "id": "8c8e9894-81be-4f6e-88d4-046b6c70ff8c", - "job_id": "c68e871a-c239-474d-a905-7b95f4563b7e", - "src_ctx": "et-e4ab4b75-9e7c-4f26-9328-394a5b842648", - "data": { - "from": "441632960411", - "text": "hello there" - }, - "run_id": "7d0d4e5f-6453-4c63-87cf-f95b04377324", - "recipient_id": "441632960758" - } - ] - } -} \ No newline at end of file diff --git a/old-version/tests/data/proactive_connect/list_items.csv b/old-version/tests/data/proactive_connect/list_items.csv deleted file mode 100644 index 0c167367..00000000 --- a/old-version/tests/data/proactive_connect/list_items.csv +++ /dev/null @@ -1,4 +0,0 @@ -"favourite_number","least_favourite_number" -0,1 -1,0 -0,0 diff --git a/old-version/tests/data/proactive_connect/list_lists.json b/old-version/tests/data/proactive_connect/list_lists.json deleted file mode 100644 index c734e99e..00000000 --- a/old-version/tests/data/proactive_connect/list_lists.json +++ /dev/null @@ -1,84 +0,0 @@ -{ - "page": 1, - "page_size": 100, - "total_items": 2, - "total_pages": 1, - "_links": { - "self": { - "href": "https://api-eu.vonage.com/v0.1/bulk/lists?page_size=100&page=1" - }, - "prev": { - "href": "https://api-eu.vonage.com/v0.1/bulk/lists?page_size=100&page=1" - }, - "next": { - "href": "https://api-eu.vonage.com/v0.1/bulk/lists?page_size=100&page=1" - }, - "first": { - "href": "https://api-eu.vonage.com/v0.1/bulk/lists?page_size=100&page=1" - } - }, - "_embedded": { - "lists": [ - { - "name": "Recipients for demo", - "description": "List of recipients for demo", - "tags": [ - "vip" - ], - "attributes": [ - { - "name": "firstName" - }, - { - "name": "lastName", - "key": false - }, - { - "name": "number", - "alias": "Phone", - "key": true - } - ], - "datasource": { - "type": "manual" - }, - "items_count": 1000, - "sync_status": { - "value": "configured", - "dirty": false, - "data_modified": false, - "metadata_modified": false - }, - "id": "af8a84b6-c712-4252-ac8d-6e28ac9317ce", - "created_at": "2022-06-23T13:13:16.491Z", - "updated_at": "2022-06-23T13:13:16.491Z" - }, - { - "name": "Salesforce contacts", - "description": "Salesforce contacts for campaign", - "tags": [ - "salesforce" - ], - "attributes": [ - { - "name": "Id", - "key": false - }, - { - "name": "Phone", - "key": true - }, - { - "name": "Email", - "key": false - } - ], - "datasource": { - "type": "salesforce", - "integration_id": "salesforce", - "soql": "SELECT Id, LastName, FirstName, Phone, Email, OtherCountry FROM Contact" - } - } - ] - } -} \ No newline at end of file diff --git a/old-version/tests/data/proactive_connect/not_found.json b/old-version/tests/data/proactive_connect/not_found.json deleted file mode 100644 index 02f8ec01..00000000 --- a/old-version/tests/data/proactive_connect/not_found.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "type": "https://developer.vonage.com/en/api-errors", - "title": "The requested resource does not exist", - "detail": "Not Found", - "instance": "04730b29-c292-4899-9419-f8cad88ec288" -} \ No newline at end of file diff --git a/old-version/tests/data/proactive_connect/update_item.json b/old-version/tests/data/proactive_connect/update_item.json deleted file mode 100644 index 7166b458..00000000 --- a/old-version/tests/data/proactive_connect/update_item.json +++ /dev/null @@ -1,11 +0,0 @@ -{ - "id": "d91c39ed-7c34-4803-a139-34bb4b7c6d53", - "created_at": "2023-05-02T21:07:25.790Z", - "updated_at": "2023-05-03T19:50:33.207Z", - "list_id": "246d17c4-79e6-4a25-8b4e-b777a83f6c30", - "data": { - "first_name": "John", - "last_name": "Doe", - "phone": "447007000000" - } -} \ No newline at end of file diff --git a/old-version/tests/data/proactive_connect/update_list.json b/old-version/tests/data/proactive_connect/update_list.json deleted file mode 100644 index 99df4c42..00000000 --- a/old-version/tests/data/proactive_connect/update_list.json +++ /dev/null @@ -1,29 +0,0 @@ -{ - "items_count": 0, - "datasource": { - "type": "manual" - }, - "id": "9508e7b8-fe99-4fdf-b022-65d7e461db2d", - "created_at": "2023-04-28T13:56:12.920Z", - "updated_at": "2023-04-28T21:39:17.825Z", - "name": "my_list", - "description": "my updated description", - "tags": [ - "vip", - "sport", - "football" - ], - "attributes": [ - { - "key": false, - "name": "phone_number", - "alias": "phone" - } - ], - "sync_status": { - "value": "configured", - "metadata_modified": false, - "data_modified": false, - "dirty": false - } -} \ No newline at end of file diff --git a/old-version/tests/data/proactive_connect/update_list_salesforce.json b/old-version/tests/data/proactive_connect/update_list_salesforce.json deleted file mode 100644 index 7e9eef48..00000000 --- a/old-version/tests/data/proactive_connect/update_list_salesforce.json +++ /dev/null @@ -1,28 +0,0 @@ -{ - "items_count": 0, - "datasource": { - "type": "manual" - }, - "id": "246d17c4-79e6-4a25-8b4e-b777a83f6c30", - "created_at": "2023-04-28T14:16:49.375Z", - "updated_at": "2023-04-28T22:23:37.054Z", - "name": "my_list", - "description": "my updated description", - "tags": [ - "music" - ], - "attributes": [ - { - "key": false, - "name": "phone_number", - "alias": "phone" - } - ], - "sync_status": { - "value": "configured", - "metadata_modified": false, - "data_modified": false, - "details": "failed to get secret: salesforce_credentials", - "dirty": false - } -} \ No newline at end of file diff --git a/old-version/tests/data/proactive_connect/upload_from_csv.json b/old-version/tests/data/proactive_connect/upload_from_csv.json deleted file mode 100644 index bbdfa8fc..00000000 --- a/old-version/tests/data/proactive_connect/upload_from_csv.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "inserted": 3 -} \ No newline at end of file diff --git a/old-version/tests/data/public_key.txt b/old-version/tests/data/public_key.txt deleted file mode 100644 index a1715089..00000000 --- a/old-version/tests/data/public_key.txt +++ /dev/null @@ -1,9 +0,0 @@ ------BEGIN PUBLIC KEY----- -MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA0HQB6iR7P2vkWtrm70nd -b8/2lpSfQapzFLQe4Lk5coIHRDQG5XiJM3qeplB3qQyXUIfEL+s0t5aVHitFJA36 -9fxb7L8bqxsP2GD2oFBIT/x8TG7Nq50E4gHVjk/lMfbzwAaMjWL2QfdMTSFYQQ0V -oJM9Rz0AUTYxXJtzTqJfN4eVMKeWK6Bk1sfq6ZiIkYUI95r+pbpNdNnfeeLpaT6c -3GFiiKSTXXJSaxJAWWoIQ2UzqW7+/anfnbPQFadY/IvXBv6MASabCVsX8ErTA6TX -hGaqKXkFpgNdtbEhLMaQGyieQwOxf5ZnJMe+LLpSh19Xw1k++nEYZaGhEFZhE3Y9 -FQIDAQAB ------END PUBLIC KEY----- diff --git a/old-version/tests/data/subaccounts/balance_transfer.json b/old-version/tests/data/subaccounts/balance_transfer.json deleted file mode 100644 index 70fdbd80..00000000 --- a/old-version/tests/data/subaccounts/balance_transfer.json +++ /dev/null @@ -1,14 +0,0 @@ -{ - "masterAccountId": "1234asdf", - "_links": { - "self": { - "href": "/accounts/1234asdf/balance-transfers/83c4da50-9d42-434d-aaa9-76cf3109e9a5" - } - }, - "from": "1234asdf", - "to": "asdfzxcv", - "amount": 0.5, - "reference": "test balance transfer", - "id": "83c4da50-9d42-434d-aaa9-76cf3109e9a5", - "created_at": "2023-06-12T17:20:00.000Z" -} \ No newline at end of file diff --git a/old-version/tests/data/subaccounts/credit_transfer.json b/old-version/tests/data/subaccounts/credit_transfer.json deleted file mode 100644 index 5687a271..00000000 --- a/old-version/tests/data/subaccounts/credit_transfer.json +++ /dev/null @@ -1,14 +0,0 @@ -{ - "masterAccountId": "1234asdf", - "_links": { - "self": { - "href": "/accounts/1234asdf/credit-transfers/83c4da50-9d42-434d-aaa9-76cf3109e9a5" - } - }, - "from": "1234asdf", - "to": "asdfzxcv", - "amount": 0.5, - "reference": "test credit transfer", - "id": "83c4da50-9d42-434d-aaa9-76cf3109e9a5", - "created_at": "2023-06-12T17:20:00.000Z" -} \ No newline at end of file diff --git a/old-version/tests/data/subaccounts/forbidden.json b/old-version/tests/data/subaccounts/forbidden.json deleted file mode 100644 index 39227a21..00000000 --- a/old-version/tests/data/subaccounts/forbidden.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "type": "https://developer.nexmo.com/api-errors#unprovisioned", - "title": "Authorisation error", - "detail": "Account 1234adsf is not provisioned to access Subaccount Provisioning API", - "instance": "158b8f199c45014ab7b08bfe9cc1c12c" -} \ No newline at end of file diff --git a/old-version/tests/data/subaccounts/insufficient_credit.json b/old-version/tests/data/subaccounts/insufficient_credit.json deleted file mode 100644 index dec73938..00000000 --- a/old-version/tests/data/subaccounts/insufficient_credit.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "type": "https://developer.nexmo.com/api-errors/account/subaccounts#valid-transfers", - "title": "Transfer amount is invalid", - "detail": "Insufficient Credit", - "instance": "70160200-6424-4fa3-a57d-21ed8be2c0b1" -} \ No newline at end of file diff --git a/old-version/tests/data/subaccounts/invalid_credentials.json b/old-version/tests/data/subaccounts/invalid_credentials.json deleted file mode 100644 index 79ff6d15..00000000 --- a/old-version/tests/data/subaccounts/invalid_credentials.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "type": "https://developer.nexmo.com/api-errors#unauthorized", - "title": "Invalid credentials supplied", - "detail": "You did not provide correct credentials", - "instance": "798b8f199c45014ab7b08bfe9cc1c12c" -} \ No newline at end of file diff --git a/old-version/tests/data/subaccounts/invalid_number_transfer.json b/old-version/tests/data/subaccounts/invalid_number_transfer.json deleted file mode 100644 index f5c29518..00000000 --- a/old-version/tests/data/subaccounts/invalid_number_transfer.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "type": "https://developer.nexmo.com/api-errors/account/subaccounts#invalid-number-transfer", - "title": "Invalid Number Transfer", - "detail": "Could not transfer number 12345678901 from account 1234asdf to asdfzxcv - ShortCode is not owned by from account", - "instance": "632768d8-84ea-47e0-91a4-7bda1409a89f" -} \ No newline at end of file diff --git a/old-version/tests/data/subaccounts/invalid_transfer.json b/old-version/tests/data/subaccounts/invalid_transfer.json deleted file mode 100644 index 9726e28e..00000000 --- a/old-version/tests/data/subaccounts/invalid_transfer.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "type": "https://developer.nexmo.com/api-errors/account/subaccounts#valid-transfers", - "title": "Invalid Transfer", - "detail": "Transfers are only allowed between a primary account and its subaccount", - "instance": "85a351ee-a180-4b17-a594-fe1df12616d0" -} \ No newline at end of file diff --git a/old-version/tests/data/subaccounts/list_balance_transfers.json b/old-version/tests/data/subaccounts/list_balance_transfers.json deleted file mode 100644 index 33cadaad..00000000 --- a/old-version/tests/data/subaccounts/list_balance_transfers.json +++ /dev/null @@ -1,27 +0,0 @@ -{ - "_links": { - "self": { - "href": "/accounts/1234asdf/balance-transfers" - } - }, - "_embedded": { - "balance_transfers": [ - { - "from": "1234asdf", - "to": "asdfzxcv", - "amount": 0.5, - "reference": "test transfer", - "id": "7380eecb-b82c-46e8-9478-af6b5793af1b", - "created_at": "2023-06-12T17:31:48.000Z" - }, - { - "from": "1234asdf", - "to": "asdfzxcv", - "amount": 0.5, - "reference": "", - "id": "83c4da50-9d42-434d-aaa9-76cf3109e9a5", - "created_at": "2023-06-12T17:20:01.000Z" - } - ] - } -} \ No newline at end of file diff --git a/old-version/tests/data/subaccounts/list_credit_transfers.json b/old-version/tests/data/subaccounts/list_credit_transfers.json deleted file mode 100644 index 8169cfc1..00000000 --- a/old-version/tests/data/subaccounts/list_credit_transfers.json +++ /dev/null @@ -1,27 +0,0 @@ -{ - "_links": { - "self": { - "href": "/accounts/1234asdf/credit-transfers" - } - }, - "_embedded": { - "credit_transfers": [ - { - "from": "1234asdf", - "to": "asdfzxcv", - "amount": 0.5, - "reference": "test credit transfer", - "id": "7380eecb-b82c-46e8-9478-af6b5793af1b", - "created_at": "2023-06-12T17:31:48.000Z" - }, - { - "from": "1234asdf", - "to": "asdfzxcv", - "amount": 0.5, - "reference": "", - "id": "83c4da50-9d42-434d-aaa9-76cf3109e9a5", - "created_at": "2023-06-12T17:20:01.000Z" - } - ] - } -} \ No newline at end of file diff --git a/old-version/tests/data/subaccounts/list_subaccounts.json b/old-version/tests/data/subaccounts/list_subaccounts.json deleted file mode 100644 index 97836dc7..00000000 --- a/old-version/tests/data/subaccounts/list_subaccounts.json +++ /dev/null @@ -1,31 +0,0 @@ -{ - "_links": { - "self": { - "href": "/accounts/1234asdf/subaccounts" - } - }, - "total_balance": 9.9999, - "total_credit_limit": 0.0, - "_embedded": { - "primary_account": { - "api_key": "1234asdf", - "name": null, - "balance": 9.9999, - "credit_limit": 0.0, - "suspended": false, - "created_at": "2022-03-28T14:16:56.000Z" - }, - "subaccounts": [ - { - "api_key": "qwerasdf", - "primary_account_api_key": "1234asdf", - "use_primary_account_balance": true, - "name": "test_subaccount", - "balance": null, - "credit_limit": null, - "suspended": false, - "created_at": "2023-06-07T10:50:44.000Z" - } - ] - } -} \ No newline at end of file diff --git a/old-version/tests/data/subaccounts/modified_subaccount.json b/old-version/tests/data/subaccounts/modified_subaccount.json deleted file mode 100644 index 1fcdac2f..00000000 --- a/old-version/tests/data/subaccounts/modified_subaccount.json +++ /dev/null @@ -1,10 +0,0 @@ -{ - "api_key": "asdfzxcv", - "primary_account_api_key": "1234asdf", - "use_primary_account_balance": false, - "name": "my modified subaccount", - "balance": 0, - "credit_limit": 0, - "suspended": true, - "created_at": "2023-06-09T14:42:55.000Z" -} \ No newline at end of file diff --git a/old-version/tests/data/subaccounts/must_be_number.json b/old-version/tests/data/subaccounts/must_be_number.json deleted file mode 100644 index ae356b4f..00000000 --- a/old-version/tests/data/subaccounts/must_be_number.json +++ /dev/null @@ -1,12 +0,0 @@ -{ - "type": "https://developer.nexmo.com/api-errors/account/subaccounts#validation", - "title": "Bad Request", - "detail": "The request failed due to validation errors", - "instance": "b4fb726d-0a83-4f97-b4b8-30b64d1aeac7", - "invalid_parameters": [ - { - "reason": "Only positive values of data type JSON number are allowed", - "name": "amount" - } - ] -} \ No newline at end of file diff --git a/old-version/tests/data/subaccounts/not_found.json b/old-version/tests/data/subaccounts/not_found.json deleted file mode 100644 index 7eddfd67..00000000 --- a/old-version/tests/data/subaccounts/not_found.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "type": "https://developer.nexmo.com/api-errors#invalid-api-key", - "title": "Invalid API Key", - "detail": "API key '1234asdf' does not exist, or you do not have access", - "instance": "158b8f199c45014ab7b08bfe9cc1c12c" -} \ No newline at end of file diff --git a/old-version/tests/data/subaccounts/number_not_found.json b/old-version/tests/data/subaccounts/number_not_found.json deleted file mode 100644 index 31d8c771..00000000 --- a/old-version/tests/data/subaccounts/number_not_found.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "type": "https://developer.nexmo.com/api-errors/account/subaccounts#missing-number-transfer", - "title": "Invalid Number Transfer", - "detail": "Could not transfer number 12345678901 from account 1234asdf to asdfzxcv - ShortCode not found", - "instance": "37f2f76c-ade3-4f26-a448-a1adee0ff85e" -} \ No newline at end of file diff --git a/old-version/tests/data/subaccounts/same_from_and_to_accounts.json b/old-version/tests/data/subaccounts/same_from_and_to_accounts.json deleted file mode 100644 index 171a2c1c..00000000 --- a/old-version/tests/data/subaccounts/same_from_and_to_accounts.json +++ /dev/null @@ -1,12 +0,0 @@ -{ - "type": "https://developer.nexmo.com/api-errors/account/subaccounts#validation", - "title": "Bad Request", - "detail": "The request failed due to validation errors", - "instance": "5499d21c-35e2-42c9-a50e-e96bdccdb34c", - "invalid_parameters": [ - { - "reason": "Invalid accounts. From and To accounts should be different", - "name": "from" - } - ] -} \ No newline at end of file diff --git a/old-version/tests/data/subaccounts/subaccount.json b/old-version/tests/data/subaccounts/subaccount.json deleted file mode 100644 index 2ead67ee..00000000 --- a/old-version/tests/data/subaccounts/subaccount.json +++ /dev/null @@ -1,11 +0,0 @@ -{ - "api_key": "asdfzxcv", - "secret": "Password123", - "primary_account_api_key": "1234asdf", - "use_primary_account_balance": true, - "name": "my subaccount", - "balance": null, - "credit_limit": null, - "suspended": false, - "created_at": "2023-06-09T02:23:21.327Z" -} \ No newline at end of file diff --git a/old-version/tests/data/subaccounts/transfer_number.json b/old-version/tests/data/subaccounts/transfer_number.json deleted file mode 100644 index de6c818f..00000000 --- a/old-version/tests/data/subaccounts/transfer_number.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "from": "1234asdf", - "to": "asdfzxcv", - "number": "12345678901", - "country": "US", - "masterAccountId": "1234asdf" -} \ No newline at end of file diff --git a/old-version/tests/data/subaccounts/transfer_validation_error.json b/old-version/tests/data/subaccounts/transfer_validation_error.json deleted file mode 100644 index 229a49df..00000000 --- a/old-version/tests/data/subaccounts/transfer_validation_error.json +++ /dev/null @@ -1,12 +0,0 @@ -{ - "type": "https://developer.nexmo.com/api-errors/account/subaccounts#validation", - "title": "Bad Request", - "detail": "The request failed due to validation errors", - "instance": "c0b6fae7-7c83-4cdc-9c0b-00672e284da9", - "invalid_parameters": [ - { - "reason": "Malformed", - "name": "start_date" - } - ] -} \ No newline at end of file diff --git a/old-version/tests/data/subaccounts/validation_error.json b/old-version/tests/data/subaccounts/validation_error.json deleted file mode 100644 index a4b0aad9..00000000 --- a/old-version/tests/data/subaccounts/validation_error.json +++ /dev/null @@ -1,12 +0,0 @@ -{ - "type": "https://developer.nexmo.com/api-errors/account/subaccounts#validation", - "title": "Bad Request", - "detail": "The request failed due to validation errors", - "instance": "fb97a734-7087-4b3a-8ec3-88d271e27fb2", - "invalid_parameters": [ - { - "reason": "Transitioning from 'use_primary_account_balance = false' to 'use_primary_account_balance = true' is not supported", - "name": "use_primary_account_balance" - } - ] -} \ No newline at end of file diff --git a/old-version/tests/data/users/invalid_content_type.json b/old-version/tests/data/users/invalid_content_type.json deleted file mode 100644 index d818e1a2..00000000 --- a/old-version/tests/data/users/invalid_content_type.json +++ /dev/null @@ -1,13 +0,0 @@ -{ - "title": "Bad request.", - "type": "https://developer.nexmo.com/api/conversation#http:error:validation-fail", - "code": "http:error:validation-fail", - "detail": "Invalid Content-Type.", - "instance": "9d0e245d-fac0-450e-811f-52343041df61", - "invalid_parameters": [ - { - "name": "content-type", - "reason": "content-type \"application/octet-stream\" is not supported. Supported versions are [application/json]" - } - ] -} \ No newline at end of file diff --git a/old-version/tests/data/users/list_users_400.json b/old-version/tests/data/users/list_users_400.json deleted file mode 100644 index 10b68249..00000000 --- a/old-version/tests/data/users/list_users_400.json +++ /dev/null @@ -1,13 +0,0 @@ -{ - "title": "Bad request.", - "type": "https://developer.nexmo.com/api/conversation#http:error:validation-fail", - "code": "http:error:validation-fail", - "detail": "Input validation failure.", - "instance": "04ee4d32-78c9-4acf-bdc1-b7d1fa860c92", - "invalid_parameters": [ - { - "name": "page_size", - "reason": "\"page_size\" must be a number" - } - ] -} \ No newline at end of file diff --git a/old-version/tests/data/users/list_users_404.json b/old-version/tests/data/users/list_users_404.json deleted file mode 100644 index 7e985e23..00000000 --- a/old-version/tests/data/users/list_users_404.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "title": "Not found.", - "type": "https://developer.nexmo.com/api/conversation#user:error:not-found", - "code": "user:error:not-found", - "detail": "User does not exist, or you do not have access.", - "instance": "29c78817-eeb9-4de0-b2f9-a5ca816bc907" -} \ No newline at end of file diff --git a/old-version/tests/data/users/list_users_500.json b/old-version/tests/data/users/list_users_500.json deleted file mode 100644 index 25aa46c5..00000000 --- a/old-version/tests/data/users/list_users_500.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "title": "Internal Error.", - "type": "https://developer.nexmo.com/api/conversation#system:error:internal-error", - "code": "system:error:internal-error", - "detail": "Something went wrong.", - "instance": "00a5916655d650e920ccf0daf40ef4ee" -} \ No newline at end of file diff --git a/old-version/tests/data/users/list_users_basic.json b/old-version/tests/data/users/list_users_basic.json deleted file mode 100644 index ec7bf4ad..00000000 --- a/old-version/tests/data/users/list_users_basic.json +++ /dev/null @@ -1,43 +0,0 @@ -{ - "page_size": 10, - "_embedded": { - "users": [ - { - "id": "USR-2af4d3c5-ec49-4c4a-b74c-ec13ab560af8", - "name": "NAM-6dd4ea1f-3841-47cb-a3d3-e271f5c1e33c", - "_links": { - "self": { - "href": "https://api-us-3.vonage.com/v1/users/USR-2af4d3c5-ec49-4c4a-b74c-ec13ab560af8" - } - } - }, - { - "id": "USR-d3cc6a55-aa7b-4916-8244-2fedb554afd5", - "name": "NAM-ecb938f2-13e0-40c1-9d3b-b16ebb4ef3d1", - "_links": { - "self": { - "href": "https://api-us-3.vonage.com/v1/users/USR-d3cc6a55-aa7b-4916-8244-2fedb554afd5" - } - } - }, - { - "id": "USR-5ab17d58-b8b3-427d-ac42-c31dab7ef422", - "name": "my_user_name", - "display_name": "My User Name", - "_links": { - "self": { - "href": "https://api-us-3.vonage.com/v1/users/USR-5ab17d58-b8b3-427d-ac42-c31dab7ef422" - } - } - } - ] - }, - "_links": { - "first": { - "href": "https://api-us-3.vonage.com/v1/users?order=asc&page_size=10" - }, - "self": { - "href": "https://api-us-3.vonage.com/v1/users?order=asc&page_size=10&cursor=QAuYbTXFALruTxAIRAKiHvdCAqJQjTuYkDNhN9PYWcDajgUTgd9lQPo%3D" - } - } -} \ No newline at end of file diff --git a/old-version/tests/data/users/list_users_options.json b/old-version/tests/data/users/list_users_options.json deleted file mode 100644 index 3c2e74d8..00000000 --- a/old-version/tests/data/users/list_users_options.json +++ /dev/null @@ -1,37 +0,0 @@ -{ - "page_size": 2, - "_embedded": { - "users": [ - { - "id": "USR-5ab17d58-b8b3-427d-ac42-c31dab7ef422", - "name": "my_user_name", - "display_name": "My User Name", - "_links": { - "self": { - "href": "https://api-us-3.vonage.com/v1/users/USR-5ab17d58-b8b3-427d-ac42-c31dab7ef422" - } - } - }, - { - "id": "USR-d3cc6a55-aa7b-4916-8244-2fedb554afd5", - "name": "NAM-ecb938f2-13e0-40c1-9d3b-b16ebb4ef3d1", - "_links": { - "self": { - "href": "https://api-us-3.vonage.com/v1/users/USR-d3cc6a55-aa7b-4916-8244-2fedb554afd5" - } - } - } - ] - }, - "_links": { - "first": { - "href": "https://api-us-3.vonage.com/v1/users?order=desc&page_size=2" - }, - "self": { - "href": "https://api-us-3.vonage.com/v1/users?order=desc&page_size=2&cursor=Tw2iIH8ISR4SuJRJUrK9xC78rhfI10HHRKOZ20zBN9A8SDiczcOqBj8%3D" - }, - "next": { - "href": "https://api-us-3.vonage.com/v1/users?order=desc&page_size=2&cursor=FBWj1Oxid%2FVkxP6BT%2FCwMZZ2C0uOby0QXCrebkNoNo4A3PU%2FQTOOoD%2BWHib6ewsVLygsQBJy7di8HI9m30A3ujVuv1578w4Lqitgbv6CAnxdzPMeLCcAxNYWxl8%3D" - } - } -} \ No newline at end of file diff --git a/old-version/tests/data/users/rate_limit.json b/old-version/tests/data/users/rate_limit.json deleted file mode 100644 index 679dc079..00000000 --- a/old-version/tests/data/users/rate_limit.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "title": "Too Many Requests.", - "type": "https://developer.nexmo.com/api/conversation#http:error:too-many-request", - "code": "http:error:too-many-request", - "detail": "You have exceeded your request limit. You can try again shortly.", - "instance": "00a5916655d650e920ccf0daf40ef4ee" -} \ No newline at end of file diff --git a/old-version/tests/data/users/user_400.json b/old-version/tests/data/users/user_400.json deleted file mode 100644 index 6269d4f7..00000000 --- a/old-version/tests/data/users/user_400.json +++ /dev/null @@ -1,13 +0,0 @@ -{ - "title": "Bad request.", - "type": "https://developer.nexmo.com/api/conversation#http:error:validation-fail", - "code": "http:error:validation-fail", - "detail": "Input validation failure.", - "instance": "00a5916655d650e920ccf0daf40ef4ee", - "invalid_parameters": [ - { - "name": "name", - "reason": "\"name\" must be a string" - } - ] -} \ No newline at end of file diff --git a/old-version/tests/data/users/user_404.json b/old-version/tests/data/users/user_404.json deleted file mode 100644 index cde74ea9..00000000 --- a/old-version/tests/data/users/user_404.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "title": "Not found.", - "type": "https://developer.nexmo.com/api/conversation#user:error:not-found", - "code": "user:error:not-found", - "detail": "User does not exist, or you do not have access.", - "instance": "9b3b0ea8-987a-4117-b75a-8425e04910c4" -} \ No newline at end of file diff --git a/old-version/tests/data/users/user_basic.json b/old-version/tests/data/users/user_basic.json deleted file mode 100644 index 794c3102..00000000 --- a/old-version/tests/data/users/user_basic.json +++ /dev/null @@ -1,13 +0,0 @@ -{ - "id": "USR-d3cc6a55-aa7b-4916-8244-2fedb554afd5", - "name": "NAM-ecb938f2-13e0-40c1-9d3b-b16ebb4ef3d1", - "properties": { - "custom_data": {} - }, - "_links": { - "self": { - "href": "https://api-us-3.vonage.com/v1/users/USR-d3cc6a55-aa7b-4916-8244-2fedb554afd5" - } - }, - "channels": {} -} \ No newline at end of file diff --git a/old-version/tests/data/users/user_options.json b/old-version/tests/data/users/user_options.json deleted file mode 100644 index 1f1f0ce3..00000000 --- a/old-version/tests/data/users/user_options.json +++ /dev/null @@ -1,69 +0,0 @@ -{ - "id": "USR-5ab17d58-b8b3-427d-ac42-c31dab7ef422", - "name": "my_user_name", - "image_url": "https://example.com/image.png", - "display_name": "My User Name", - "properties": { - "custom_data": { - "custom_key": "custom_value" - } - }, - "_links": { - "self": { - "href": "https://api-us-3.vonage.com/v1/users/USR-5ab17d58-b8b3-427d-ac42-c31dab7ef422" - } - }, - "channels": { - "pstn": [ - { - "number": 123457 - } - ], - "sip": [ - { - "uri": "sip:4442138907@sip.example.com;transport=tls", - "username": "New SIP", - "password": "Password" - } - ], - "vbc": [ - { - "extension": "403" - } - ], - "websocket": [ - { - "uri": "wss://example.com/socket", - "content-type": "audio/l16;rate=16000", - "headers": { - "customer_id": "ABC123" - } - } - ], - "sms": [ - { - "number": "447700900000" - } - ], - "mms": [ - { - "number": "447700900000" - } - ], - "whatsapp": [ - { - "number": "447700900000" - } - ], - "viber": [ - { - "number": "447700900000" - } - ], - "messenger": [ - { - "id": "12345abcd" - } - ] - } -} \ No newline at end of file diff --git a/old-version/tests/data/users/user_updated.json b/old-version/tests/data/users/user_updated.json deleted file mode 100644 index be4b884d..00000000 --- a/old-version/tests/data/users/user_updated.json +++ /dev/null @@ -1,19 +0,0 @@ -{ - "id": "USR-d3cc6a55-aa7b-4916-8244-2fedb554afd5", - "name": "updated_name", - "properties": { - "custom_data": {} - }, - "_links": { - "self": { - "href": "https://api-us-3.vonage.com/v1/users/USR-d3cc6a55-aa7b-4916-8244-2fedb554afd5" - } - }, - "channels": { - "whatsapp": [ - { - "number": "447700900000" - } - ] - } -} \ No newline at end of file diff --git a/old-version/tests/data/verify/blocked_with_network_and_request_id.json b/old-version/tests/data/verify/blocked_with_network_and_request_id.json deleted file mode 100644 index 971f276b..00000000 --- a/old-version/tests/data/verify/blocked_with_network_and_request_id.json +++ /dev/null @@ -1 +0,0 @@ -{"request_id":"12345678","status":"7","error_text":"The number you are trying to verify is blacklisted for verification","network":"25503"} \ No newline at end of file diff --git a/old-version/tests/data/verify2/already_verified.json b/old-version/tests/data/verify2/already_verified.json deleted file mode 100644 index c1a557ff..00000000 --- a/old-version/tests/data/verify2/already_verified.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "type": "https://developer.nexmo.com/api-errors#not-found", - "title": "Not Found", - "detail": "Request '5fcc26ef-1e54-48a6-83ab-c47546a19824' was not found or it has been verified already.", - "instance": "02cabfcc-2e09-4b5d-b098-1fa7ccef4607" -} \ No newline at end of file diff --git a/old-version/tests/data/verify2/check_code.json b/old-version/tests/data/verify2/check_code.json deleted file mode 100644 index 2016cb21..00000000 --- a/old-version/tests/data/verify2/check_code.json +++ /dev/null @@ -1,4 +0,0 @@ -{ - "request_id": "e043d872-459b-4750-a20c-d33f91d6959f", - "status": "completed" -} \ No newline at end of file diff --git a/old-version/tests/data/verify2/code_not_supported.json b/old-version/tests/data/verify2/code_not_supported.json deleted file mode 100644 index e690eb1e..00000000 --- a/old-version/tests/data/verify2/code_not_supported.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "title": "Conflict", - "detail": "The current Verify workflow step does not support a code.", - "instance": "690c48de-c5d1-49f2-8712-b3b0a840f911", - "type": "https://developer.nexmo.com/api-errors#conflict" -} \ No newline at end of file diff --git a/old-version/tests/data/verify2/create_request.json b/old-version/tests/data/verify2/create_request.json deleted file mode 100644 index 106dc1cc..00000000 --- a/old-version/tests/data/verify2/create_request.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "request_id": "c11236f4-00bf-4b89-84ba-88b25df97315" -} \ No newline at end of file diff --git a/old-version/tests/data/verify2/create_request_silent_auth.json b/old-version/tests/data/verify2/create_request_silent_auth.json deleted file mode 100644 index d313581a..00000000 --- a/old-version/tests/data/verify2/create_request_silent_auth.json +++ /dev/null @@ -1,4 +0,0 @@ -{ - "request_id": "b3a2f4bd-7bda-4e5e-978a-81514702d2ce", - "check_url": "https://api-eu-3.vonage.com/v2/verify/b3a2f4bd-7bda-4e5e-978a-81514702d2ce/silent-auth/redirect" -} \ No newline at end of file diff --git a/old-version/tests/data/verify2/error_conflict.json b/old-version/tests/data/verify2/error_conflict.json deleted file mode 100644 index 69eebdc7..00000000 --- a/old-version/tests/data/verify2/error_conflict.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "title": "Conflict", - "type": "https://www.developer.vonage.com/api-errors/verify#conflict", - "detail": "Concurrent verifications to the same number are not allowed.", - "instance": "738f9313-418a-4259-9b0d-6670f06fa82d", - "request_id": "575a2054-aaaf-4405-994e-290be7b9a91f" -} \ No newline at end of file diff --git a/old-version/tests/data/verify2/fraud_check_invalid_account.json b/old-version/tests/data/verify2/fraud_check_invalid_account.json deleted file mode 100644 index ee5d7053..00000000 --- a/old-version/tests/data/verify2/fraud_check_invalid_account.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "type": "https://developer.nexmo.com/api-errors#forbidden", - "title": "Forbidden", - "detail": "Your account does not have permission to perform this action.", - "instance": "1995bc0d-c850-4bf0-aa1e-6c40da43d3bf" -} \ No newline at end of file diff --git a/old-version/tests/data/verify2/invalid_code.json b/old-version/tests/data/verify2/invalid_code.json deleted file mode 100644 index 6e6d7b17..00000000 --- a/old-version/tests/data/verify2/invalid_code.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "type": "https://developer.nexmo.com/api-errors#bad-request", - "title": "Invalid Code", - "detail": "The code you provided does not match the expected value.", - "instance": "16d6bca6-c0dc-4add-94b2-0dbc12cba83b" -} \ No newline at end of file diff --git a/old-version/tests/data/verify2/invalid_email.json b/old-version/tests/data/verify2/invalid_email.json deleted file mode 100644 index 34cb0edc..00000000 --- a/old-version/tests/data/verify2/invalid_email.json +++ /dev/null @@ -1,12 +0,0 @@ -{ - "title": "Invalid params", - "detail": "The value of one or more parameters is invalid", - "instance": "e151c892-76b2-4486-8a37-b88faa70babd", - "type": "https://www.nexmo.com/messages/Errors#InvalidParams", - "invalid_parameters": [ - { - "name": "workflow[0]", - "reason": "`to` Email address is invalid" - } - ] -} \ No newline at end of file diff --git a/old-version/tests/data/verify2/invalid_sender.json b/old-version/tests/data/verify2/invalid_sender.json deleted file mode 100644 index dc3cda26..00000000 --- a/old-version/tests/data/verify2/invalid_sender.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "title": "Invalid sender", - "detail": "The `from` parameter is invalid.", - "instance": "1711258a-12e2-48ad-99a2-43fe3315409c", - "type": "https://developer.nexmo.com/api-errors#invalid-param" -} \ No newline at end of file diff --git a/old-version/tests/data/verify2/rate_limit.json b/old-version/tests/data/verify2/rate_limit.json deleted file mode 100644 index ddafeb6f..00000000 --- a/old-version/tests/data/verify2/rate_limit.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "title": "Rate Limit Hit", - "type": "https://www.developer.vonage.com/api-errors#throttled", - "detail": "Please wait, then retry your request", - "instance": "bf0ca0bf927b3b52e3cb03217e1a1ddf" -} \ No newline at end of file diff --git a/old-version/tests/data/verify2/request_not_found.json b/old-version/tests/data/verify2/request_not_found.json deleted file mode 100644 index 45abf814..00000000 --- a/old-version/tests/data/verify2/request_not_found.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "type": "https://developer.nexmo.com/api-errors#not-found", - "title": "Not Found", - "detail": "Request 'c11236f4-00bf-4b89-84ba-88b25df97315' was not found or it has been verified already.", - "instance": "a5f25ba1-c760-4966-81d4-6bdbb19f29d7" -} \ No newline at end of file diff --git a/old-version/tests/data/verify2/too_many_code_attempts.json b/old-version/tests/data/verify2/too_many_code_attempts.json deleted file mode 100644 index 50b05c09..00000000 --- a/old-version/tests/data/verify2/too_many_code_attempts.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "title": "Invalid Code", - "detail": "An incorrect code has been provided too many times. Workflow terminated.", - "instance": "060246db-1c9f-4fdf-b9fa-2bd8b772f5d9", - "type": "https://developer.nexmo.com/api-errors#gone" -} \ No newline at end of file diff --git a/old-version/tests/test_getters_setters.py b/old-version/tests/test_getters_setters.py deleted file mode 100644 index d11caa3b..00000000 --- a/old-version/tests/test_getters_setters.py +++ /dev/null @@ -1,13 +0,0 @@ -def test_getters(client, dummy_data): - assert client.host() == dummy_data.host - assert client.api_host() == dummy_data.api_host - - -def test_setters(client, dummy_data): - try: - client.host('host.vonage.com') - client.api_host('host.vonage.com') - assert client.host() != dummy_data.host - assert client.api_host() != dummy_data.api_host - except: - assert False diff --git a/old-version/tests/test_messages_send_message.py b/old-version/tests/test_messages_send_message.py deleted file mode 100644 index 242ccbc7..00000000 --- a/old-version/tests/test_messages_send_message.py +++ /dev/null @@ -1,42 +0,0 @@ -from util import * - - -@responses.activate -def test_send_sms_with_messages_api(messages, dummy_data): - stub(responses.POST, 'https://api.nexmo.com/v1/messages') - - params = { - 'channel': 'sms', - 'message_type': 'text', - 'to': '447123456789', - 'from': 'Vonage', - 'text': 'Hello from Vonage', - } - - assert isinstance(messages.send_message(params), dict) - assert request_user_agent() == dummy_data.user_agent - assert b'"from": "Vonage"' in request_body() - assert b'"to": "447123456789"' in request_body() - assert b'"text": "Hello from Vonage"' in request_body() - - -@responses.activate -def test_send_whatsapp_image_with_messages_api(messages, dummy_data): - stub(responses.POST, 'https://api.nexmo.com/v1/messages') - - params = { - 'channel': 'whatsapp', - 'message_type': 'image', - 'to': '447123456789', - 'from': '440123456789', - 'image': {'url': 'https://example.com/image.jpg', 'caption': 'fake test image'}, - } - - assert isinstance(messages.send_message(params), dict) - assert request_user_agent() == dummy_data.user_agent - assert b'"from": "440123456789"' in request_body() - assert b'"to": "447123456789"' in request_body() - assert ( - b'"image": {"url": "https://example.com/image.jpg", "caption": "fake test image"}' - in request_body() - ) diff --git a/old-version/tests/test_messages_validate_input.py b/old-version/tests/test_messages_validate_input.py deleted file mode 100644 index 6ee2810d..00000000 --- a/old-version/tests/test_messages_validate_input.py +++ /dev/null @@ -1,315 +0,0 @@ -from util import * -from vonage.errors import MessagesError - - -def test_invalid_send_message_params_object(messages): - with pytest.raises(MessagesError) as err: - messages.send_message('hi') - assert ( - str(err.value) == 'Parameters to the send_message method must be specified as a dictionary.' - ) - - -def test_invalid_message_channel(messages): - with pytest.raises(MessagesError) as err: - messages.send_message( - { - 'channel': 'carrier_pigeon', - 'message_type': 'text', - 'to': '12345678', - 'from': 'vonage', - 'text': 'my important message', - } - ) - assert '"carrier_pigeon" is an invalid message channel.' in str(err.value) - - -def test_invalid_message_type(messages): - with pytest.raises(MessagesError) as err: - messages.send_message( - { - 'channel': 'sms', - 'message_type': 'video', - 'to': '12345678', - 'from': 'vonage', - 'video': 'my_url.com', - } - ) - assert '"video" is not a valid message type for channel "sms".' in str(err.value) - - -def test_invalid_recipient_not_string(messages): - with pytest.raises(MessagesError) as err: - messages.send_message( - { - 'channel': 'sms', - 'message_type': 'text', - 'to': 12345678, - 'from': 'vonage', - 'text': 'my important message', - } - ) - assert str(err.value) == 'Message recipient ("to=12345678") not in a valid format.' - - -def test_invalid_recipient_number(messages): - with pytest.raises(MessagesError) as err: - messages.send_message( - { - 'channel': 'sms', - 'message_type': 'text', - 'to': '+441234567890', - 'from': 'vonage', - 'text': 'my important message', - } - ) - assert str(err.value) == 'Message recipient number ("to=+441234567890") not in a valid format.' - - -def test_invalid_messenger_recipient(messages): - with pytest.raises(MessagesError) as err: - messages.send_message( - { - 'channel': 'messenger', - 'message_type': 'text', - 'to': '', - 'from': 'vonage', - 'text': 'my important message', - } - ) - assert str(err.value) == 'Message recipient ID ("to=") not in a valid format.' - - -def test_invalid_sender(messages): - with pytest.raises(MessagesError) as err: - messages.send_message( - { - 'channel': 'sms', - 'message_type': 'text', - 'to': '441234567890', - 'from': 1234, - 'text': 'my important message', - } - ) - assert ( - str(err.value) - == 'Message sender ("frm=1234") set incorrectly. Set a valid name or number for the sender.' - ) - - -def test_set_client_ref(messages): - messages._check_valid_client_ref( - { - 'channel': 'sms', - 'message_type': 'text', - 'to': '441234567890', - 'from': 'vonage', - 'text': 'my important message', - 'client_ref': 'my client reference', - } - ) - assert messages._client_ref == 'my client reference' - - -def test_invalid_client_ref(messages): - with pytest.raises(MessagesError) as err: - messages._check_valid_client_ref( - { - 'channel': 'sms', - 'message_type': 'text', - 'to': '441234567890', - 'from': 'vonage', - 'text': 'my important message', - 'client_ref': 'my client reference that is, in fact, a small, but significant amount longer than the 100 character limit imposed at this present juncture.', - } - ) - assert str(err.value) == 'client_ref can be a maximum of 100 characters.' - - -def test_whatsapp_template(messages): - messages.validate_send_message_input( - { - 'channel': 'whatsapp', - 'message_type': 'template', - 'to': '4412345678912', - 'from': 'vonage', - 'template': {'name': 'namespace:mytemplate'}, - 'whatsapp': {'policy': 'deterministic', 'locale': 'en-GB'}, - } - ) - - -def test_set_messenger_optional_attribute(messages): - messages.validate_send_message_input( - { - 'channel': 'messenger', - 'message_type': 'text', - 'to': 'user_messenger_id', - 'from': 'vonage', - 'text': 'my important message', - 'messenger': {'category': 'response', 'tag': 'ACCOUNT_UPDATE'}, - } - ) - - -def test_set_viber_service_optional_attribute(messages): - messages.validate_send_message_input( - { - 'channel': 'viber_service', - 'message_type': 'text', - 'to': '44123456789', - 'from': 'vonage', - 'text': 'my important message', - 'viber_service': {'category': 'transaction', 'ttl': 30, 'type': 'text'}, - } - ) - - -def test_viber_service_video(messages): - messages.validate_send_message_input( - { - 'channel': 'viber_service', - 'message_type': 'video', - 'to': '44123456789', - 'from': 'vonage', - 'video': { - 'url': 'https://example.com/video.mp4', - 'caption': 'Look at this video', - 'thumb_url': 'https://example.com/thumbnail.jpg', - }, - 'viber_service': { - 'category': 'transaction', - 'duration': '120', - 'ttl': 30, - 'type': 'string', - }, - } - ) - - -def test_viber_service_file(messages): - messages.validate_send_message_input( - { - 'channel': 'viber_service', - 'message_type': 'file', - 'to': '44123456789', - 'from': 'vonage', - 'video': {'url': 'https://example.com/files', 'name': 'example.pdf'}, - 'viber_service': {'category': 'transaction', 'ttl': 30, 'type': 'string'}, - } - ) - - -def test_viber_service_text_action_button(messages): - messages.validate_send_message_input( - { - 'channel': 'viber_service', - 'message_type': 'text', - 'to': '44123456789', - 'from': 'vonage', - 'text': 'my important message', - 'viber_service': { - 'category': 'transaction', - 'ttl': 30, - 'type': 'string', - 'action': {'url': 'https://example.com/page1.html', 'text': 'Find out more'}, - }, - } - ) - - -def test_viber_service_image_action_button(messages): - messages.validate_send_message_input( - { - 'channel': 'viber_service', - 'message_type': 'image', - 'to': '44123456789', - 'from': 'vonage', - 'image': { - 'url': 'https://example.com/image.jpg', - 'caption': 'Check out this new promotion', - }, - 'viber_service': { - 'category': 'transaction', - 'ttl': 30, - 'type': 'string', - 'action': {'url': 'https://example.com/page1.html', 'text': 'Find out more'}, - }, - } - ) - - -def test_incomplete_input(messages): - with pytest.raises(MessagesError) as err: - messages.validate_send_message_input( - { - 'channel': 'viber_service', - 'message_type': 'text', - 'to': '44123456789', - 'from': 'vonage', - 'text': 'my important message', - } - ) - assert ( - str(err.value) - == 'You must specify all required properties for message channel "viber_service".' - ) - - -def test_whatsapp_sticker_id(messages): - messages.validate_send_message_input( - { - 'channel': 'whatsapp', - 'message_type': 'sticker', - 'sticker': {'id': '13aaecab-2485-4255-a0a7-97a2be6906b9'}, - 'to': '44123456789', - 'from': 'vonage', - } - ) - - -def test_whatsapp_sticker_url(messages): - messages.validate_send_message_input( - { - 'channel': 'whatsapp', - 'message_type': 'sticker', - 'sticker': {'url': 'https://example.com/sticker1.webp'}, - 'to': '44123456789', - 'from': 'vonage', - } - ) - - -def test_whatsapp_sticker_invalid_input_error(messages): - with pytest.raises(MessagesError) as err: - messages.validate_send_message_input( - { - 'channel': 'whatsapp', - 'message_type': 'sticker', - 'sticker': {'my_sticker'}, - 'to': '44123456789', - 'from': 'vonage', - } - ) - assert ( - str(err.value) == 'Must specify one, and only one, of "id" or "url" in the "sticker" field.' - ) - - -def test_whatsapp_sticker_exclusive_keys_error(messages): - with pytest.raises(MessagesError) as err: - messages.validate_send_message_input( - { - 'channel': 'whatsapp', - 'message_type': 'sticker', - 'sticker': { - 'id': '13aaecab-2485-4255-a0a7-97a2be6906b9', - 'url': 'https://example.com/sticker1.webp', - }, - 'to': '44123456789', - 'from': 'vonage', - } - ) - assert ( - str(err.value) == 'Must specify one, and only one, of "id" or "url" in the "sticker" field.' - ) diff --git a/old-version/tests/test_packages.py b/old-version/tests/test_packages.py deleted file mode 100644 index 49d5dbcf..00000000 --- a/old-version/tests/test_packages.py +++ /dev/null @@ -1,14 +0,0 @@ -import os - - -def test_subdirectories_are_python_packages(): - subdirs = [ - os.path.join('src/vonage', o) - for o in os.listdir('src/vonage') - if os.path.isdir(os.path.join('src/vonage', o)) - ] - for subdir in subdirs: - if '__pycache__' in subdir or os.path.isfile(f'{subdir}/__init__.py'): - continue - else: - raise Exception(f'Subfolder {subdir} doesn\'t have an __init__.py file') diff --git a/old-version/tests/test_short_codes.py b/old-version/tests/test_short_codes.py deleted file mode 100644 index 212dfcf6..00000000 --- a/old-version/tests/test_short_codes.py +++ /dev/null @@ -1,64 +0,0 @@ -from util import * - - -@responses.activate -def test_send_2fa_message(short_codes, dummy_data): - stub(responses.POST, "https://rest.nexmo.com/sc/us/2fa/json") - - params = {"to": "16365553226", "pin": "1234"} - - assert isinstance(short_codes.send_2fa_message(params), dict) - assert request_user_agent() == dummy_data.user_agent - assert "to=16365553226" in request_body() - assert "pin=1234" in request_body() - - -@responses.activate -def test_send_event_alert_message(short_codes, dummy_data): - stub(responses.POST, "https://rest.nexmo.com/sc/us/alert/json") - - params = {"to": "16365553226", "server": "host", "link": "http://example.com/"} - - assert isinstance(short_codes.send_event_alert_message(params), dict) - assert request_user_agent() == dummy_data.user_agent - assert "to=16365553226" in request_body() - assert "server=host" in request_body() - assert "link=http%3A%2F%2Fexample.com%2F" in request_body() - - -@responses.activate -def test_send_marketing_message(short_codes, dummy_data): - stub(responses.POST, "https://rest.nexmo.com/sc/us/marketing/json") - - params = { - "from": "short-code", - "to": "16365553226", - "keyword": "NEXMO", - "text": "Hello", - } - - assert isinstance(short_codes.send_marketing_message(params), dict) - assert request_user_agent() == dummy_data.user_agent - assert "from=short-code" in request_body() - assert "to=16365553226" in request_body() - assert "keyword=NEXMO" in request_body() - assert "text=Hello" in request_body() - - -@responses.activate -def test_get_event_alert_numbers(short_codes, dummy_data): - stub(responses.GET, "https://rest.nexmo.com/sc/us/alert/opt-in/query/json") - - assert isinstance(short_codes.get_event_alert_numbers(), dict) - assert request_user_agent() == dummy_data.user_agent - - -@responses.activate -def test_resubscribe_event_alert_number(short_codes, dummy_data): - stub(responses.POST, "https://rest.nexmo.com/sc/us/alert/opt-in/manage/json") - - params = {"msisdn": "441632960960"} - - assert isinstance(short_codes.resubscribe_event_alert_number(params), dict) - assert request_user_agent() == dummy_data.user_agent - assert "msisdn=441632960960" in request_body() diff --git a/old-version/tests/test_signature.py b/old-version/tests/test_signature.py deleted file mode 100644 index 8ae86468..00000000 --- a/old-version/tests/test_signature.py +++ /dev/null @@ -1,86 +0,0 @@ -import vonage -from util import * - - -def test_check_signature(dummy_data): - params = { - "a": "1", - "b": "2", - "timestamp": "1461605396", - "sig": "6af838ef94998832dbfc29020b564830", - } - - client = vonage.Client( - key=dummy_data.api_key, secret=dummy_data.api_secret, signature_secret="secret" - ) - - assert client.check_signature(params) - - -def test_signature(client, dummy_data): - params = {"a": "1", "b": "2", "timestamp": "1461605396"} - client = vonage.Client( - key=dummy_data.api_key, secret=dummy_data.api_secret, signature_secret="secret" - ) - assert client.signature(params) == "6af838ef94998832dbfc29020b564830" - - -def test_signature_adds_timestamp(dummy_data): - params = {"a=7": "1", "b": "2 & 5"} - - client = vonage.Client( - key=dummy_data.api_key, secret=dummy_data.api_secret, signature_secret="secret" - ) - - client.signature(params) - assert params["timestamp"] is not None - - -def test_signature_md5(dummy_data): - params = {"a": "1", "b": "2", "timestamp": "1461605396"} - client = vonage.Client( - key=dummy_data.api_key, - secret=dummy_data.api_secret, - signature_secret=dummy_data.signature_secret, - signature_method="md5", - ) - assert client.signature(params) == "c15c21ced558c93a226c305f58f902f2" - - -def test_signature_sha1(dummy_data): - params = {"a": "1", "b": "2", "timestamp": "1461605396"} - client = vonage.Client( - key=dummy_data.api_key, - secret=dummy_data.api_secret, - signature_secret=dummy_data.signature_secret, - signature_method="sha1", - ) - assert client.signature(params) == "3e19a4e6880fdc2c1426bfd0587c98b9532f0210" - - -def test_signature_sha256(dummy_data): - params = {"a": "1", "b": "2", "timestamp": "1461605396"} - client = vonage.Client( - key=dummy_data.api_key, - secret=dummy_data.api_secret, - signature_secret=dummy_data.signature_secret, - signature_method="sha256", - ) - assert ( - client.signature(params) - == "a321e824b9b816be7c3f28859a31749a098713d39f613c80d455bbaffae1cd24" - ) - - -def test_signature_sha512(dummy_data): - params = {"a": "1", "b": "2", "timestamp": "1461605396"} - client = vonage.Client( - key=dummy_data.api_key, - secret=dummy_data.api_secret, - signature_secret=dummy_data.signature_secret, - signature_method="sha512", - ) - assert ( - client.signature(params) - == "812a18f76680fa0fe1b8bd9ee1625466ceb1bd96242e4d050d2cfd9a7b40166c63ed26ec9702168781b6edcf1633db8ff95af9341701004eec3fcf9550572ee8" - ) diff --git a/old-version/tests/test_users.py b/old-version/tests/test_users.py deleted file mode 100644 index 3a468548..00000000 --- a/old-version/tests/test_users.py +++ /dev/null @@ -1,369 +0,0 @@ -from vonage import Client, Users -from util import * -from vonage.errors import UsersError, ClientError, ServerError - -from pytest import raises -import responses - -client = Client() -users = Users(client) -host = client.api_host() - - -@responses.activate -def test_list_users_basic(): - stub( - responses.GET, - f'https://{host}/v1/users', - fixture_path='users/list_users_basic.json', - ) - - all_users = users.list_users() - assert all_users['page_size'] == 10 - assert all_users['_embedded']['users'][0]['name'] == 'NAM-6dd4ea1f-3841-47cb-a3d3-e271f5c1e33c' - assert all_users['_embedded']['users'][1]['name'] == 'NAM-ecb938f2-13e0-40c1-9d3b-b16ebb4ef3d1' - assert all_users['_embedded']['users'][2]['name'] == 'my_user_name' - - -@responses.activate -def test_list_users_options(): - stub( - responses.GET, - f'https://{host}/v1/users', - fixture_path='users/list_users_options.json', - ) - - all_users = users.list_users(page_size=2, order='desc') - assert all_users['page_size'] == 2 - assert all_users['_embedded']['users'][0]['name'] == 'my_user_name' - assert all_users['_embedded']['users'][1]['name'] == 'NAM-ecb938f2-13e0-40c1-9d3b-b16ebb4ef3d1' - - -def test_list_users_order_error(): - with raises(UsersError) as err: - users.list_users(order='Why, ascending of course!') - assert ( - str(err.value) == 'Invalid order parameter. Must be one of: "asc", "desc", "ASC", "DESC".' - ) - - -@responses.activate -def test_list_users_400(): - stub( - responses.GET, - f'https://{host}/v1/users', - fixture_path='users/list_users_400.json', - status_code=400, - ) - - with raises(ClientError) as err: - users.list_users(page_size='asdf') - assert 'Input validation failure.' in str(err.value) - - -@responses.activate -def test_list_users_404(): - stub( - responses.GET, - f'https://{host}/v1/users', - fixture_path='users/list_users_404.json', - status_code=404, - ) - - with raises(ClientError) as err: - users.list_users(name='asdf') - assert 'User does not exist, or you do not have access.' in str(err.value) - - -@responses.activate -def test_list_users_429(): - stub( - responses.GET, - f'https://{host}/v1/users', - fixture_path='users/rate_limit.json', - status_code=429, - ) - - with raises(ClientError) as err: - users.list_users() - assert 'You have exceeded your request limit. You can try again shortly.' in str(err.value) - - -@responses.activate -def test_list_users_500(): - stub( - responses.GET, - f'https://{host}/v1/users', - fixture_path='users/list_users_500.json', - status_code=500, - ) - - with raises(ServerError) as err: - users.list_users() - assert str(err.value) == '500 response from api.nexmo.com' - - -@responses.activate -def test_create_user_basic(): - stub( - responses.POST, - f'https://{host}/v1/users', - fixture_path='users/user_basic.json', - status_code=201, - ) - - user = users.create_user() - assert user['id'] == 'USR-d3cc6a55-aa7b-4916-8244-2fedb554afd5' - assert user['name'] == 'NAM-ecb938f2-13e0-40c1-9d3b-b16ebb4ef3d1' - assert ( - user['_links']['self']['href'] - == 'https://api-us-3.vonage.com/v1/users/USR-d3cc6a55-aa7b-4916-8244-2fedb554afd5' - ) - - -@responses.activate -def test_create_user_options(): - stub( - responses.POST, - f'https://{host}/v1/users', - fixture_path='users/user_options.json', - status_code=201, - ) - - params = { - "id": "USR-5ab17d58-b8b3-427d-ac42-c31dab7ef422", - "name": "my_user_name", - "image_url": "https://example.com/image.png", - "display_name": "My User Name", - "properties": {"custom_data": {"custom_key": "custom_value"}}, - "_links": { - "self": { - "href": "https://api-us-3.vonage.com/v1/users/USR-5ab17d58-b8b3-427d-ac42-c31dab7ef422" - } - }, - "channels": { - "pstn": [{"number": 123457}], - "sip": [ - { - "uri": "sip:4442138907@sip.example.com;transport=tls", - "username": "New SIP", - "password": "Password", - } - ], - "vbc": [{"extension": "403"}], - "websocket": [ - { - "uri": "wss://example.com/socket", - "content-type": "audio/l16;rate=16000", - "headers": {"customer_id": "ABC123"}, - } - ], - "sms": [{"number": "447700900000"}], - "mms": [{"number": "447700900000"}], - "whatsapp": [{"number": "447700900000"}], - "viber": [{"number": "447700900000"}], - "messenger": [{"id": "12345abcd"}], - }, - } - - user = users.create_user(params) - assert user['id'] == 'USR-5ab17d58-b8b3-427d-ac42-c31dab7ef422' - assert user['name'] == 'my_user_name' - assert user['display_name'] == 'My User Name' - assert user['properties']['custom_data']['custom_key'] == 'custom_value' - assert ( - user['_links']['self']['href'] - == 'https://api-us-3.vonage.com/v1/users/USR-5ab17d58-b8b3-427d-ac42-c31dab7ef422' - ) - assert user['channels']['vbc'][0]['extension'] == '403' - - -@responses.activate -def test_create_user_400(): - stub( - responses.POST, - f'https://{host}/v1/users', - fixture_path='users/user_400.json', - status_code=400, - ) - - with raises(ClientError) as err: - users.create_user(params={'name': 1234}) - assert 'Input validation failure.' in str(err.value) - - -@responses.activate -def test_create_user_429(): - stub( - responses.POST, - f'https://{host}/v1/users', - fixture_path='users/rate_limit.json', - status_code=429, - ) - - with raises(ClientError) as err: - users.create_user() - assert 'You have exceeded your request limit. You can try again shortly.' in str(err.value) - - -@responses.activate -def test_get_user(): - user_id = 'USR-d3cc6a55-aa7b-4916-8244-2fedb554afd5' - stub( - responses.GET, - f'https://{host}/v1/users/{user_id}', - fixture_path='users/user_basic.json', - ) - - user = users.get_user(user_id) - assert user['name'] == 'NAM-ecb938f2-13e0-40c1-9d3b-b16ebb4ef3d1' - assert user['properties']['custom_data'] == {} - assert ( - user['_links']['self']['href'] - == 'https://api-us-3.vonage.com/v1/users/USR-d3cc6a55-aa7b-4916-8244-2fedb554afd5' - ) - - -@responses.activate -def test_get_user_404(): - user_id = 'USR-d3cc6a55-aa7b-4916-8244-2fedb554afd5' - stub( - responses.GET, - f'https://{host}/v1/users/{user_id}', - status_code=404, - fixture_path='users/user_404.json', - ) - - with raises(ClientError) as err: - users.get_user(user_id) - assert 'User does not exist, or you do not have access.' in str(err.value) - - -@responses.activate -def test_get_user_429(): - user_id = 'USR-d3cc6a55-aa7b-4916-8244-2fedb554afd5' - stub( - responses.GET, - f'https://{host}/v1/users/{user_id}', - fixture_path='users/rate_limit.json', - status_code=429, - ) - - with raises(ClientError) as err: - users.get_user(user_id) - assert 'You have exceeded your request limit. You can try again shortly.' in str(err.value) - - -@responses.activate -def test_update_user(): - user_id = 'USR-d3cc6a55-aa7b-4916-8244-2fedb554afd5' - stub( - responses.PATCH, - f'https://{host}/v1/users/{user_id}', - fixture_path='users/user_updated.json', - ) - - params = { - 'name': 'updated_name', - 'channels': { - 'whatsapp': [ - {'number': '447700900000'}, - ] - }, - } - user = users.update_user(user_id, params) - assert user['name'] == 'updated_name' - assert ( - user['_links']['self']['href'] - == 'https://api-us-3.vonage.com/v1/users/USR-d3cc6a55-aa7b-4916-8244-2fedb554afd5' - ) - assert user['channels']['whatsapp'][0]['number'] == '447700900000' - - -@responses.activate -def test_update_user_400(): - user_id = 'USR-d3cc6a55-aa7b-4916-8244-2fedb554afd5' - stub( - responses.PATCH, - f'https://{host}/v1/users/{user_id}', - fixture_path='users/user_400.json', - status_code=400, - ) - - with raises(ClientError) as err: - users.update_user(user_id, params={'name': 1234}) - assert 'Input validation failure.' in str(err.value) - - -@responses.activate -def test_update_user_404(): - user_id = 'USR-d3cc6a55-aa7b-4916-8244-2fedb554afd5' - stub( - responses.PATCH, - f'https://{host}/v1/users/{user_id}', - status_code=404, - fixture_path='users/user_404.json', - ) - - with raises(ClientError) as err: - users.update_user(user_id, params={'name': 'updated_user_name'}) - assert 'User does not exist, or you do not have access.' in str(err.value) - - -@responses.activate -def test_update_user_429(): - user_id = 'USR-d3cc6a55-aa7b-4916-8244-2fedb554afd5' - stub( - responses.PATCH, - f'https://{host}/v1/users/{user_id}', - fixture_path='users/rate_limit.json', - status_code=429, - ) - - with raises(ClientError) as err: - users.update_user(user_id, params={'name': 'updated_user_name'}) - assert 'You have exceeded your request limit. You can try again shortly.' in str(err.value) - - -@responses.activate -def test_delete_user(): - user_id = 'USR-d3cc6a55-aa7b-4916-8244-2fedb554afd5' - stub( - responses.DELETE, - f'https://{host}/v1/users/{user_id}', - status_code=204, - fixture_path='no_content.json', - ) - - response = users.delete_user(user_id) - assert response == None - - -@responses.activate -def test_delete_user_404(): - user_id = 'USR-d3cc6a55-aa7b-4916-8244-2fedb554afd5' - stub( - responses.DELETE, - f'https://{host}/v1/users/{user_id}', - status_code=404, - fixture_path='users/user_404.json', - ) - - with raises(ClientError) as err: - users.delete_user(user_id) - assert 'User does not exist, or you do not have access.' in str(err.value) - - -@responses.activate -def test_delete_user_429(): - user_id = 'USR-d3cc6a55-aa7b-4916-8244-2fedb554afd5' - stub( - responses.DELETE, - f'https://{host}/v1/users/{user_id}', - fixture_path='users/rate_limit.json', - status_code=429, - ) - - with raises(ClientError) as err: - users.delete_user(user_id) - assert 'You have exceeded your request limit. You can try again shortly.' in str(err.value) diff --git a/old-version/tests/test_ussd.py b/old-version/tests/test_ussd.py deleted file mode 100644 index 27fb41a7..00000000 --- a/old-version/tests/test_ussd.py +++ /dev/null @@ -1,27 +0,0 @@ -from util import * - - -@responses.activate -def test_send_ussd_push_message(ussd, dummy_data): - stub(responses.POST, "https://rest.nexmo.com/ussd/json") - - params = {"from": "MyCompany20", "to": "447525856424", "text": "Hello"} - - assert isinstance(ussd.send_ussd_push_message(params), dict) - assert request_user_agent() == dummy_data.user_agent - assert "from=MyCompany20" in request_body() - assert "to=447525856424" in request_body() - assert "text=Hello" in request_body() - - -@responses.activate -def test_send_ussd_prompt_message(ussd, dummy_data): - stub(responses.POST, "https://rest.nexmo.com/ussd-prompt/json") - - params = {"from": "long-virtual-number", "to": "447525856424", "text": "Hello"} - - assert isinstance(ussd.send_ussd_prompt_message(params), dict) - assert request_user_agent() == dummy_data.user_agent - assert "from=long-virtual-number" in request_body() - assert "to=447525856424" in request_body() - assert "text=Hello" in request_body() diff --git a/old-version/tests/test_verify2.py b/old-version/tests/test_verify2.py index 0595c186..2ebc2d7a 100644 --- a/old-version/tests/test_verify2.py +++ b/old-version/tests/test_verify2.py @@ -13,138 +13,141 @@ def test_new_request_sms_basic(dummy_data): stub( responses.POST, - 'https://api.nexmo.com/v2/verify', - fixture_path='verify2/create_request.json', + "https://api.nexmo.com/v2/verify", + fixture_path="verify2/create_request.json", status_code=202, ) - params = {'brand': 'ACME, Inc', 'workflow': [{'channel': 'sms', 'to': '447700900000'}]} + params = { + "brand": "ACME, Inc", + "workflow": [{"channel": "sms", "to": "447700900000"}], + } verify_request = verify2.new_request(params) assert request_user_agent() == dummy_data.user_agent - assert verify_request['request_id'] == 'c11236f4-00bf-4b89-84ba-88b25df97315' + assert verify_request["request_id"] == "c11236f4-00bf-4b89-84ba-88b25df97315" @responses.activate def test_new_request_sms_full(): stub( responses.POST, - 'https://api.nexmo.com/v2/verify', - fixture_path='verify2/create_request.json', + "https://api.nexmo.com/v2/verify", + fixture_path="verify2/create_request.json", status_code=202, ) params = { - 'locale': 'en-gb', - 'channel_timeout': 120, - 'client_ref': 'my client ref', - 'code_length': 10, - 'fraud_check': False, - 'brand': 'ACME, Inc', - 'workflow': [{'channel': 'sms', 'to': '447700900000', 'app_hash': 'asdfghjklqw'}], + "locale": "en-gb", + "channel_timeout": 120, + "client_ref": "my client ref", + "code_length": 10, + "fraud_check": False, + "brand": "ACME, Inc", + "workflow": [{"channel": "sms", "to": "447700900000", "app_hash": "asdfghjklqw"}], } verify_request = verify2.new_request(params) - assert verify_request['request_id'] == 'c11236f4-00bf-4b89-84ba-88b25df97315' + assert verify_request["request_id"] == "c11236f4-00bf-4b89-84ba-88b25df97315" @responses.activate def test_new_request_sms_custom_code(dummy_data): stub( responses.POST, - 'https://api.nexmo.com/v2/verify', - fixture_path='verify2/create_request.json', + "https://api.nexmo.com/v2/verify", + fixture_path="verify2/create_request.json", status_code=202, ) params = { - 'brand': 'ACME, Inc', - 'code': 'asdfghjk', - 'workflow': [{'channel': 'sms', 'to': '447700900000'}], + "brand": "ACME, Inc", + "code": "asdfghjk", + "workflow": [{"channel": "sms", "to": "447700900000"}], } verify_request = verify2.new_request(params) assert request_user_agent() == dummy_data.user_agent - assert verify_request['request_id'] == 'c11236f4-00bf-4b89-84ba-88b25df97315' + assert verify_request["request_id"] == "c11236f4-00bf-4b89-84ba-88b25df97315" @responses.activate def test_new_request_error_fraud_check_invalid_account(dummy_data): stub( responses.POST, - 'https://api.nexmo.com/v2/verify', - fixture_path='verify2/fraud_check_invalid_account.json', + "https://api.nexmo.com/v2/verify", + fixture_path="verify2/fraud_check_invalid_account.json", status_code=403, ) params = { - 'brand': 'ACME, Inc', - 'fraud_check': False, - 'workflow': [{'channel': 'sms', 'to': '447700900000'}], + "brand": "ACME, Inc", + "fraud_check": False, + "workflow": [{"channel": "sms", "to": "447700900000"}], } with raises(ClientError) as err: verify2.new_request(params) - assert 'Your account does not have permission to perform this action.' in str(err.value) + assert "Your account does not have permission to perform this action." in str(err.value) def test_new_request_sms_custom_code_length_error(): params = { - 'code_length': 4, - 'brand': 'ACME, Inc', - 'code': 'a', - 'workflow': [{'channel': 'sms', 'to': '447700900000'}], + "code_length": 4, + "brand": "ACME, Inc", + "code": "a", + "workflow": [{"channel": "sms", "to": "447700900000"}], } with raises(ValidationError) as err: verify2.new_request(params) - assert 'String should have at least 4 characters' in str(err.value) + assert "String should have at least 4 characters" in str(err.value) def test_new_request_sms_custom_code_character_error(): params = { - 'code_length': 4, - 'brand': 'ACME, Inc', - 'code': '?!@%', - 'workflow': [{'channel': 'sms', 'to': '447700900000'}], + "code_length": 4, + "brand": "ACME, Inc", + "code": "?!@%", + "workflow": [{"channel": "sms", "to": "447700900000"}], } with raises(ValidationError) as err: verify2.new_request(params) - assert 'String should match pattern' in str(err.value) + assert "String should match pattern" in str(err.value) def test_new_request_invalid_channel_error(): params = { - 'code_length': 4, - 'brand': 'ACME, Inc', - 'workflow': [{'channel': 'carrier_pigeon', 'to': '447700900000'}], + "code_length": 4, + "brand": "ACME, Inc", + "workflow": [{"channel": "carrier_pigeon", "to": "447700900000"}], } with raises(Verify2Error) as err: verify2.new_request(params) assert ( str(err.value) - == 'You must specify a valid verify channel inside the "workflow" object, one of: "[\'sms\', \'whatsapp\', \'whatsapp_interactive\', \'voice\', \'email\', \'silent_auth\']"' + == "You must specify a valid verify channel inside the \"workflow\" object, one of: \"['sms', 'whatsapp', 'whatsapp_interactive', 'voice', 'email', 'silent_auth']\"" ) def test_new_request_code_length_error(): params = { - 'code_length': 1000, - 'brand': 'ACME, Inc', - 'workflow': [{'channel': 'sms', 'to': '447700900000'}], + "code_length": 1000, + "brand": "ACME, Inc", + "workflow": [{"channel": "sms", "to": "447700900000"}], } with raises(ValidationError) as err: verify2.new_request(params) - assert 'Input should be less than or equal to 10' in str(err.value) + assert "Input should be less than or equal to 10" in str(err.value) def test_new_request_to_error(): params = { - 'brand': 'ACME, Inc', - 'workflow': [{'channel': 'sms', 'to': '123'}], + "brand": "ACME, Inc", + "workflow": [{"channel": "sms", "to": "123"}], } with raises(Verify2Error) as err: @@ -154,8 +157,8 @@ def test_new_request_to_error(): def test_new_request_sms_app_hash_error(): params = { - 'brand': 'ACME, Inc', - 'workflow': [{'channel': 'sms', 'to': '447700900000', 'app_hash': '00'}], + "brand": "ACME, Inc", + "workflow": [{"channel": "sms", "to": "447700900000", "app_hash": "00"}], } with raises(Verify2Error) as err: @@ -165,8 +168,8 @@ def test_new_request_sms_app_hash_error(): def test_new_request_whatsapp_app_hash_error(): params = { - 'brand': 'ACME, Inc', - 'workflow': [{'channel': 'whatsapp', 'to': '447700900000', 'app_hash': 'asdfqwerzxc'}], + "brand": "ACME, Inc", + "workflow": [{"channel": "whatsapp", "to": "447700900000", "app_hash": "asdfqwerzxc"}], } with raises(Verify2Error) as err: @@ -181,66 +184,69 @@ def test_new_request_whatsapp_app_hash_error(): def test_new_request_whatsapp(): stub( responses.POST, - 'https://api.nexmo.com/v2/verify', - fixture_path='verify2/create_request.json', + "https://api.nexmo.com/v2/verify", + fixture_path="verify2/create_request.json", status_code=202, ) - params = {'brand': 'ACME, Inc', 'workflow': [{'channel': 'whatsapp', 'to': '447700900000'}]} + params = { + "brand": "ACME, Inc", + "workflow": [{"channel": "whatsapp", "to": "447700900000"}], + } verify_request = verify2.new_request(params) - assert verify_request['request_id'] == 'c11236f4-00bf-4b89-84ba-88b25df97315' + assert verify_request["request_id"] == "c11236f4-00bf-4b89-84ba-88b25df97315" @responses.activate def test_new_request_whatsapp_custom_code(): stub( responses.POST, - 'https://api.nexmo.com/v2/verify', - fixture_path='verify2/create_request.json', + "https://api.nexmo.com/v2/verify", + fixture_path="verify2/create_request.json", status_code=202, ) params = { - 'brand': 'ACME, Inc', - 'code': 'asdfghjk', - 'workflow': [{'channel': 'whatsapp', 'to': '447700900000'}], + "brand": "ACME, Inc", + "code": "asdfghjk", + "workflow": [{"channel": "whatsapp", "to": "447700900000"}], } verify_request = verify2.new_request(params) - assert verify_request['request_id'] == 'c11236f4-00bf-4b89-84ba-88b25df97315' + assert verify_request["request_id"] == "c11236f4-00bf-4b89-84ba-88b25df97315" @responses.activate def test_new_request_whatsapp_from_field(): stub( responses.POST, - 'https://api.nexmo.com/v2/verify', - fixture_path='verify2/create_request.json', + "https://api.nexmo.com/v2/verify", + fixture_path="verify2/create_request.json", status_code=202, ) params = { - 'brand': 'ACME, Inc', - 'workflow': [{'channel': 'whatsapp', 'to': '447700900000', 'from': '447000000000'}], + "brand": "ACME, Inc", + "workflow": [{"channel": "whatsapp", "to": "447700900000", "from": "447000000000"}], } verify_request = verify2.new_request(params) - assert verify_request['request_id'] == 'c11236f4-00bf-4b89-84ba-88b25df97315' + assert verify_request["request_id"] == "c11236f4-00bf-4b89-84ba-88b25df97315" @responses.activate def test_new_request_whatsapp_invalid_sender_error(): stub( responses.POST, - 'https://api.nexmo.com/v2/verify', - fixture_path='verify2/invalid_sender.json', + "https://api.nexmo.com/v2/verify", + fixture_path="verify2/invalid_sender.json", status_code=422, ) params = { - 'brand': 'ACME, Inc', - 'workflow': [{'channel': 'whatsapp', 'to': '447700900000', 'from': 'asdfghjkl'}], + "brand": "ACME, Inc", + "workflow": [{"channel": "whatsapp", "to": "447700900000", "from": "asdfghjkl"}], } with pytest.raises(Verify2Error) as err: verify2.new_request(params) @@ -251,318 +257,338 @@ def test_new_request_whatsapp_invalid_sender_error(): def test_new_request_whatsapp_sender_unregistered_error(): stub( responses.POST, - 'https://api.nexmo.com/v2/verify', - fixture_path='verify2/invalid_sender.json', + "https://api.nexmo.com/v2/verify", + fixture_path="verify2/invalid_sender.json", status_code=422, ) params = { - 'brand': 'ACME, Inc', - 'workflow': [{'channel': 'whatsapp', 'to': '447700900000', 'from': '447999999999'}], + "brand": "ACME, Inc", + "workflow": [{"channel": "whatsapp", "to": "447700900000", "from": "447999999999"}], } with pytest.raises(ClientError) as err: verify2.new_request(params) - assert 'Invalid sender' in str(err.value) + assert "Invalid sender" in str(err.value) @responses.activate def test_new_request_whatsapp_interactive(): stub( responses.POST, - 'https://api.nexmo.com/v2/verify', - fixture_path='verify2/create_request.json', + "https://api.nexmo.com/v2/verify", + fixture_path="verify2/create_request.json", status_code=202, ) params = { - 'brand': 'ACME, Inc', - 'workflow': [{'channel': 'whatsapp_interactive', 'to': '447700900000'}], + "brand": "ACME, Inc", + "workflow": [{"channel": "whatsapp_interactive", "to": "447700900000"}], } verify_request = verify2.new_request(params) - assert verify_request['request_id'] == 'c11236f4-00bf-4b89-84ba-88b25df97315' + assert verify_request["request_id"] == "c11236f4-00bf-4b89-84ba-88b25df97315" @responses.activate def test_new_request_voice(): stub( responses.POST, - 'https://api.nexmo.com/v2/verify', - fixture_path='verify2/create_request.json', + "https://api.nexmo.com/v2/verify", + fixture_path="verify2/create_request.json", status_code=202, ) - params = {'brand': 'ACME, Inc', 'workflow': [{'channel': 'voice', 'to': '447700900000'}]} + params = { + "brand": "ACME, Inc", + "workflow": [{"channel": "voice", "to": "447700900000"}], + } verify_request = verify2.new_request(params) - assert verify_request['request_id'] == 'c11236f4-00bf-4b89-84ba-88b25df97315' + assert verify_request["request_id"] == "c11236f4-00bf-4b89-84ba-88b25df97315" @responses.activate def test_new_request_voice_custom_code(): stub( responses.POST, - 'https://api.nexmo.com/v2/verify', - fixture_path='verify2/create_request.json', + "https://api.nexmo.com/v2/verify", + fixture_path="verify2/create_request.json", status_code=202, ) params = { - 'brand': 'ACME, Inc', - 'code': 'asdfhjkl', - 'workflow': [{'channel': 'voice', 'to': '447700900000'}], + "brand": "ACME, Inc", + "code": "asdfhjkl", + "workflow": [{"channel": "voice", "to": "447700900000"}], } verify_request = verify2.new_request(params) - assert verify_request['request_id'] == 'c11236f4-00bf-4b89-84ba-88b25df97315' + assert verify_request["request_id"] == "c11236f4-00bf-4b89-84ba-88b25df97315" @responses.activate def test_new_request_email(): stub( responses.POST, - 'https://api.nexmo.com/v2/verify', - fixture_path='verify2/create_request.json', + "https://api.nexmo.com/v2/verify", + fixture_path="verify2/create_request.json", status_code=202, ) params = { - 'brand': 'ACME, Inc', - 'workflow': [{'channel': 'email', 'to': 'recipient@example.com'}], + "brand": "ACME, Inc", + "workflow": [{"channel": "email", "to": "recipient@example.com"}], } verify_request = verify2.new_request(params) - assert verify_request['request_id'] == 'c11236f4-00bf-4b89-84ba-88b25df97315' + assert verify_request["request_id"] == "c11236f4-00bf-4b89-84ba-88b25df97315" @responses.activate def test_new_request_email_additional_fields(): stub( responses.POST, - 'https://api.nexmo.com/v2/verify', - fixture_path='verify2/create_request.json', + "https://api.nexmo.com/v2/verify", + fixture_path="verify2/create_request.json", status_code=202, ) params = { - 'locale': 'en-gb', - 'channel_timeout': 120, - 'client_ref': 'my client ref', - 'code_length': 8, - 'brand': 'ACME, Inc', - 'code': 'asdfhjkl', - 'workflow': [ - {'channel': 'email', 'to': 'recipient@example.com', 'from': 'sender@example.com'} + "locale": "en-gb", + "channel_timeout": 120, + "client_ref": "my client ref", + "code_length": 8, + "brand": "ACME, Inc", + "code": "asdfhjkl", + "workflow": [ + { + "channel": "email", + "to": "recipient@example.com", + "from": "sender@example.com", + } ], } verify_request = verify2.new_request(params) - assert verify_request['request_id'] == 'c11236f4-00bf-4b89-84ba-88b25df97315' + assert verify_request["request_id"] == "c11236f4-00bf-4b89-84ba-88b25df97315" @responses.activate def test_new_request_email_error(): stub( responses.POST, - 'https://api.nexmo.com/v2/verify', - fixture_path='verify2/invalid_email.json', + "https://api.nexmo.com/v2/verify", + fixture_path="verify2/invalid_email.json", status_code=422, ) params = { - 'brand': 'ACME, Inc', - 'workflow': [{'channel': 'email', 'to': 'not-an-email-address'}], + "brand": "ACME, Inc", + "workflow": [{"channel": "email", "to": "not-an-email-address"}], } with pytest.raises(ClientError) as err: verify2.new_request(params) - assert 'Invalid params' in str(err.value) + assert "Invalid params" in str(err.value) @responses.activate def test_new_request_silent_auth(): stub( responses.POST, - 'https://api.nexmo.com/v2/verify', - fixture_path='verify2/create_request.json', + "https://api.nexmo.com/v2/verify", + fixture_path="verify2/create_request_silent_auth.json", status_code=202, ) - params = {'brand': 'ACME, Inc', 'workflow': [{'channel': 'silent_auth', 'to': '447700900000'}]} + params = { + "brand": "ACME, Inc", + "workflow": [{"channel": "silent_auth", "to": "447700900000"}], + } verify_request = verify2.new_request(params) - assert verify_request['request_id'] == 'c11236f4-00bf-4b89-84ba-88b25df97315' + assert verify_request["request_id"] == "b3a2f4bd-7bda-4e5e-978a-81514702d2ce" + assert ( + verify_request["check_url"] + == "https://api-eu-3.vonage.com/v2/verify/b3a2f4bd-7bda-4e5e-978a-81514702d2ce/silent-auth/redirect" + ) @responses.activate def test_new_request_error_conflict(): stub( responses.POST, - 'https://api.nexmo.com/v2/verify', - fixture_path='verify2/error_conflict.json', + "https://api.nexmo.com/v2/verify", + fixture_path="verify2/error_conflict.json", status_code=409, ) - params = {'brand': 'ACME, Inc', 'workflow': [{'channel': 'sms', 'to': '447700900000'}]} + params = { + "brand": "ACME, Inc", + "workflow": [{"channel": "sms", "to": "447700900000"}], + } with raises(ClientError) as err: verify2.new_request(params) - assert 'Concurrent verifications to the same number are not allowed.' in str(err.value) + assert "Concurrent verifications to the same number are not allowed." in str(err.value) @responses.activate def test_new_request_rate_limit(): stub( responses.POST, - 'https://api.nexmo.com/v2/verify', - fixture_path='verify2/rate_limit.json', + "https://api.nexmo.com/v2/verify", + fixture_path="verify2/rate_limit.json", status_code=429, ) - params = {'brand': 'ACME, Inc', 'workflow': [{'channel': 'sms', 'to': '447700900000'}]} + params = { + "brand": "ACME, Inc", + "workflow": [{"channel": "sms", "to": "447700900000"}], + } with raises(ClientError) as err: verify2.new_request(params) - assert 'Rate Limit Hit' in str(err.value) + assert "Rate Limit Hit" in str(err.value) @responses.activate def test_check_code(): stub( responses.POST, - 'https://api.nexmo.com/v2/verify/c11236f4-00bf-4b89-84ba-88b25df97315', - fixture_path='verify2/check_code.json', + "https://api.nexmo.com/v2/verify/c11236f4-00bf-4b89-84ba-88b25df97315", + fixture_path="verify2/check_code.json", ) - response = verify2.check_code('c11236f4-00bf-4b89-84ba-88b25df97315', '1234') - assert response['request_id'] == 'e043d872-459b-4750-a20c-d33f91d6959f' - assert response['status'] == 'completed' + response = verify2.check_code("c11236f4-00bf-4b89-84ba-88b25df97315", "1234") + assert response["request_id"] == "e043d872-459b-4750-a20c-d33f91d6959f" + assert response["status"] == "completed" @responses.activate def test_check_code_invalid_code(): stub( responses.POST, - 'https://api.nexmo.com/v2/verify/c11236f4-00bf-4b89-84ba-88b25df97315', - fixture_path='verify2/invalid_code.json', + "https://api.nexmo.com/v2/verify/c11236f4-00bf-4b89-84ba-88b25df97315", + fixture_path="verify2/invalid_code.json", status_code=400, ) with pytest.raises(ClientError) as err: - verify2.check_code('c11236f4-00bf-4b89-84ba-88b25df97315', '5678') + verify2.check_code("c11236f4-00bf-4b89-84ba-88b25df97315", "5678") - assert 'Invalid Code' in str(err.value) + assert "Invalid Code" in str(err.value) @responses.activate def test_check_code_already_verified(): stub( responses.POST, - 'https://api.nexmo.com/v2/verify/c11236f4-00bf-4b89-84ba-88b25df97315', - fixture_path='verify2/already_verified.json', + "https://api.nexmo.com/v2/verify/c11236f4-00bf-4b89-84ba-88b25df97315", + fixture_path="verify2/already_verified.json", status_code=404, ) with pytest.raises(ClientError) as err: - verify2.check_code('c11236f4-00bf-4b89-84ba-88b25df97315', '5678') + verify2.check_code("c11236f4-00bf-4b89-84ba-88b25df97315", "5678") - assert 'Not Found' in str(err.value) + assert "Not Found" in str(err.value) @responses.activate def test_check_code_workflow_not_supported(): stub( responses.POST, - 'https://api.nexmo.com/v2/verify/c11236f4-00bf-4b89-84ba-88b25df97315', - fixture_path='verify2/code_not_supported.json', + "https://api.nexmo.com/v2/verify/c11236f4-00bf-4b89-84ba-88b25df97315", + fixture_path="verify2/code_not_supported.json", status_code=409, ) with pytest.raises(ClientError) as err: - verify2.check_code('c11236f4-00bf-4b89-84ba-88b25df97315', '5678') + verify2.check_code("c11236f4-00bf-4b89-84ba-88b25df97315", "5678") - assert 'The current Verify workflow step does not support a code.' in str(err.value) + assert "The current Verify workflow step does not support a code." in str(err.value) @responses.activate def test_check_code_too_many_invalid_code_attempts(): stub( responses.POST, - 'https://api.nexmo.com/v2/verify/c11236f4-00bf-4b89-84ba-88b25df97315', - fixture_path='verify2/too_many_code_attempts.json', + "https://api.nexmo.com/v2/verify/c11236f4-00bf-4b89-84ba-88b25df97315", + fixture_path="verify2/too_many_code_attempts.json", status_code=410, ) with pytest.raises(ClientError) as err: - verify2.check_code('c11236f4-00bf-4b89-84ba-88b25df97315', '5678') + verify2.check_code("c11236f4-00bf-4b89-84ba-88b25df97315", "5678") - assert 'Invalid Code' in str(err.value) + assert "Invalid Code" in str(err.value) @responses.activate def test_check_code_rate_limit(): stub( responses.POST, - 'https://api.nexmo.com/v2/verify/c11236f4-00bf-4b89-84ba-88b25df97315', - fixture_path='verify2/rate_limit.json', + "https://api.nexmo.com/v2/verify/c11236f4-00bf-4b89-84ba-88b25df97315", + fixture_path="verify2/rate_limit.json", status_code=429, ) with raises(ClientError) as err: - verify2.check_code('c11236f4-00bf-4b89-84ba-88b25df97315', '5678') - assert 'Rate Limit Hit' in str(err.value) + verify2.check_code("c11236f4-00bf-4b89-84ba-88b25df97315", "5678") + assert "Rate Limit Hit" in str(err.value) @responses.activate def test_cancel_verification(): stub( responses.DELETE, - 'https://api.nexmo.com/v2/verify/c11236f4-00bf-4b89-84ba-88b25df97315', - fixture_path='no_content.json', + "https://api.nexmo.com/v2/verify/c11236f4-00bf-4b89-84ba-88b25df97315", + fixture_path="no_content.json", status_code=204, ) - assert verify2.cancel_verification('c11236f4-00bf-4b89-84ba-88b25df97315') == None + assert verify2.cancel_verification("c11236f4-00bf-4b89-84ba-88b25df97315") == None @responses.activate def test_cancel_verification_error_not_found(): stub( responses.DELETE, - 'https://api.nexmo.com/v2/verify/c11236f4-00bf-4b89-84ba-88b25df97315', - fixture_path='verify2/request_not_found.json', + "https://api.nexmo.com/v2/verify/c11236f4-00bf-4b89-84ba-88b25df97315", + fixture_path="verify2/request_not_found.json", status_code=404, ) with raises(ClientError) as err: - verify2.cancel_verification('c11236f4-00bf-4b89-84ba-88b25df97315') - assert 'Not Found' in str(err.value) + verify2.cancel_verification("c11236f4-00bf-4b89-84ba-88b25df97315") + assert "Not Found" in str(err.value) @responses.activate def test_new_request_multiple_workflows(): stub( responses.POST, - 'https://api.nexmo.com/v2/verify', - fixture_path='verify2/create_request.json', + "https://api.nexmo.com/v2/verify", + fixture_path="verify2/create_request.json", status_code=202, ) params = { - 'brand': 'ACME, Inc', - 'workflow': [ - {'channel': 'whatsapp_interactive', 'to': '447700900000'}, - {'channel': 'sms', 'to': '4477009999999'}, + "brand": "ACME, Inc", + "workflow": [ + {"channel": "whatsapp_interactive", "to": "447700900000"}, + {"channel": "sms", "to": "4477009999999"}, ], } verify_request = verify2.new_request(params) - assert verify_request['request_id'] == 'c11236f4-00bf-4b89-84ba-88b25df97315' + assert verify_request["request_id"] == "c11236f4-00bf-4b89-84ba-88b25df97315" def test_remove_unnecessary_fraud_check(): params = { - 'brand': 'ACME, Inc', - 'workflow': [{'channel': 'sms', 'to': '447700900000'}], - 'fraud_check': True, + "brand": "ACME, Inc", + "workflow": [{"channel": "sms", "to": "447700900000"}], + "fraud_check": True, } verify2._remove_unnecessary_fraud_check(params) - assert 'fraud_check' not in params + assert "fraud_check" not in params diff --git a/old-version/tests/test_voice.py b/old-version/tests/test_voice.py index afac688e..5ccbeaa9 100644 --- a/old-version/tests/test_voice.py +++ b/old-version/tests/test_voice.py @@ -1,10 +1,9 @@ import os.path import time - import jwt +from unittest.mock import patch -import vonage -from vonage import Ncco +from vonage import Client, Voice, Ncco from util import * @@ -43,20 +42,20 @@ def test_create_call_with_ncco_builder(voice, dummy_data): stub(responses.POST, "https://api.nexmo.com/v1/calls") talk = Ncco.Talk( - text='Hello from Vonage!', + text="Hello from Vonage!", bargeIn=True, loop=3, level=0.5, - language='en-GB', + language="en-GB", style=1, premium=True, ) ncco = Ncco.build_ncco(talk) voice.create_call( { - 'to': [{'type': 'phone', 'number': '447449815316'}], - 'from': {'type': 'phone', 'number': '447418370240'}, - 'ncco': ncco, + "to": [{"type": "phone", "number": "447449815316"}], + "from": {"type": "phone", "number": "447418370240"}, + "ncco": ncco, } ) assert ( @@ -149,7 +148,7 @@ def test_user_provided_authorization(dummy_data): stub(responses.GET, "https://api.nexmo.com/v1/calls/xx-xx-xx-xx") application_id = "different-application-id" - client = vonage.Client(application_id=application_id, private_key=dummy_data.private_key) + client = Client(application_id=application_id, private_key=dummy_data.private_key) nbf = int(time.time()) exp = nbf + 3600 @@ -172,13 +171,13 @@ def test_authorization_with_private_key_path(dummy_data): private_key = os.path.join(os.path.dirname(__file__), "data/private_key.txt") - client = vonage.Client( + client = Client( key=dummy_data.api_key, secret=dummy_data.api_secret, application_id=dummy_data.application_id, private_key=private_key, ) - voice = vonage.Voice(client) + voice = Voice(client) voice.get_call("xx-xx-xx-xx") token = jwt.decode( @@ -204,7 +203,7 @@ def test_get_recording(voice, dummy_data): stub_bytes( responses.GET, "https://api.nexmo.com/v1/files/d6e47a2e-3414-11e8-8c2c-2f8b643ed957", - body=b'THISISANMP3', + body=b"THISISANMP3", ) assert isinstance( @@ -212,3 +211,15 @@ def test_get_recording(voice, dummy_data): str, ) assert request_user_agent() == dummy_data.user_agent + + +def test_verify_jwt_signature(voice: Voice): + with patch("vonage.Voice.verify_signature") as mocked_verify_signature: + mocked_verify_signature.return_value = True + assert voice.verify_signature("valid_token", "valid_signature") + + +def test_verify_jwt_invalid_signature(voice: Voice): + with patch("vonage.Voice.verify_signature") as mocked_verify_signature: + mocked_verify_signature.return_value = False + assert voice.verify_signature("token", "invalid_signature") is False diff --git a/old-version/tests/util.py b/old-version/tests/util.py deleted file mode 100644 index e9c8f289..00000000 --- a/old-version/tests/util.py +++ /dev/null @@ -1,63 +0,0 @@ -import os.path -import re - -import pytest - -from urllib.parse import urlparse, parse_qs - -import responses - - -def request_body(): - return responses.calls[0].request.body - - -def request_query(): - return urlparse(responses.calls[0].request.url).query - - -def request_params(): - """Obtain the query params, as a dict.""" - return parse_qs(request_query()) - - -def request_headers(): - return responses.calls[0].request.headers - - -def request_user_agent(): - return responses.calls[0].request.headers["User-Agent"] - - -def request_authorization(): - return responses.calls[0].request.headers["Authorization"].decode("utf-8") - - -def request_content_type(): - return responses.calls[0].request.headers["Content-Type"] - - -def stub(method, url, fixture_path=None, status_code=200): - body = load_fixture(fixture_path) if fixture_path else '{"key":"value"}' - responses.add(method, url, body=body, status=status_code, content_type="application/json") - - -def stub_bytes(method, url, body): - responses.add(method, url, body, status=200) - - -def assert_re(pattern, string): - __tracebackhide__ = True - if not re.search(pattern, string): - pytest.fail(f"Cannot find pattern {repr(pattern)} in {repr(string)}") - - -def assert_basic_auth(): - params = request_params() - assert "api_key" not in params - assert "api_secret" not in params - assert request_headers()["Authorization"] == "Basic bmV4bW8tYXBpLWtleTpuZXhtby1hcGktc2VjcmV0" - - -def load_fixture(fixture_path): - return open(os.path.join(os.path.dirname(__file__), "data", fixture_path)).read() diff --git a/requirements.txt b/requirements.txt deleted file mode 100644 index 7d779ad3..00000000 --- a/requirements.txt +++ /dev/null @@ -1,10 +0,0 @@ --e . -pytest==7.4.2 -responses==0.22.0 -coverage -pydantic>=2.3.0 - -bump2version -build -twine -pre-commit diff --git a/setup.py b/setup.py deleted file mode 100644 index 6c0bc4dc..00000000 --- a/setup.py +++ /dev/null @@ -1,42 +0,0 @@ -import io -import os - -from setuptools import setup, find_packages - - -with io.open( - os.path.join(os.path.dirname(__file__), "README.md"), encoding="utf-8" -) as f: - long_description = f.read() - -setup( - name="vonage", - version="4.0.0b0", - description="Vonage Server SDK for Python", - long_description=long_description, - long_description_content_type="text/markdown", - url="https://github.com/Vonage/vonage-python-sdk", - author="Vonage", - author_email="devrel@vonage.com", - license="Apache", - packages=find_packages(where="src"), - package_dir={"": "src"}, - platforms=["any"], - install_requires=[ - "vonage-jwt>=1.1.0", - "requests>=2.4.2", - "pytz>=2018.5", - "pydantic>=2.3.0", - ], - python_requires=">=3.8", - tests_require=["cryptography>=2.3.1"], - classifiers=[ - "Programming Language :: Python", - "Programming Language :: Python :: 3", - "Programming Language :: Python :: 3.8", - "Programming Language :: Python :: 3.9", - "Programming Language :: Python :: 3.10", - "Programming Language :: Python :: 3.11", - "Programming Language :: Python :: 3.12", - ], -) diff --git a/src/vonage/__init__.py b/src/vonage/__init__.py deleted file mode 100644 index 46ae51c2..00000000 --- a/src/vonage/__init__.py +++ /dev/null @@ -1,4 +0,0 @@ -from .client import * -from .ncco_builder.ncco import * - -__version__ = "4.0.0b0" diff --git a/src/vonage/account.py b/src/vonage/account.py deleted file mode 100644 index 25b66ed4..00000000 --- a/src/vonage/account.py +++ /dev/null @@ -1,103 +0,0 @@ -from .errors import PricingTypeError - - -class Account: - account_auth_type = 'params' - pricing_auth_type = 'params' - secrets_auth_type = 'header' - - account_sent_data_type = 'data' - pricing_sent_data_type = 'query' - secrets_sent_data_type = 'json' - - allowed_pricing_types = {'sms', 'sms-transit', 'voice'} - - def __init__(self, client): - self._client = client - - def get_balance(self): - return self._client.get( - self._client.host(), - "/account/get-balance", - auth_type=Account.account_auth_type, - ) - - def topup(self, params=None, **kwargs): - return self._client.post( - self._client.host(), - "/account/top-up", - params or kwargs, - auth_type=Account.account_auth_type, - sent_data_type=Account.account_sent_data_type, - ) - - def get_country_pricing(self, country_code: str, type: str = 'sms'): - self._check_allowed_pricing_type(type) - return self._client.get( - self._client.host(), - f"/account/get-pricing/outbound/{type}", - {"country": country_code}, - auth_type=Account.pricing_auth_type, - sent_data_type=Account.pricing_sent_data_type, - ) - - def get_all_countries_pricing(self, type: str = 'sms'): - self._check_allowed_pricing_type(type) - return self._client.get( - self._client.host(), - f"/account/get-full-pricing/outbound/{type}", - auth_type=Account.pricing_auth_type, - ) - - def get_prefix_pricing(self, prefix: str, type: str = 'sms'): - self._check_allowed_pricing_type(type) - return self._client.get( - self._client.host(), - f"/account/get-prefix-pricing/outbound/{type}", - {"prefix": prefix}, - auth_type=Account.pricing_auth_type, - sent_data_type=Account.pricing_sent_data_type, - ) - - def update_default_sms_webhook(self, params=None, **kwargs): - return self._client.post( - self._client.host(), - "/account/settings", - params or kwargs, - auth_type=Account.account_auth_type, - sent_data_type=Account.account_sent_data_type, - ) - - def list_secrets(self, api_key): - return self._client.get( - self._client.api_host(), - f"/accounts/{api_key}/secrets", - auth_type=Account.secrets_auth_type, - ) - - def get_secret(self, api_key, secret_id): - return self._client.get( - self._client.api_host(), - f"/accounts/{api_key}/secrets/{secret_id}", - auth_type=Account.secrets_auth_type, - ) - - def create_secret(self, api_key, secret): - body = {"secret": secret} - return self._client.post( - self._client.api_host(), - f"/accounts/{api_key}/secrets", - body, - auth_type=Account.secrets_auth_type, - ) - - def revoke_secret(self, api_key, secret_id): - return self._client.delete( - self._client.api_host(), - f"/accounts/{api_key}/secrets/{secret_id}", - auth_type=Account.secrets_auth_type, - ) - - def _check_allowed_pricing_type(self, type): - if type not in Account.allowed_pricing_types: - raise PricingTypeError('Invalid pricing type specified.') diff --git a/src/vonage/application.py b/src/vonage/application.py deleted file mode 100644 index 18397e69..00000000 --- a/src/vonage/application.py +++ /dev/null @@ -1,84 +0,0 @@ -class Application: - auth_type = 'header' - - def __init__(self, client): - self._client = client - - def create_application(self, application_data): - """ - Create an application using the provided `application_data`. - - :param dict application_data: A JSON-style dict describing the application to be created. - - >>> client.application.create_application({ 'name': 'My Cool App!' }) - - Details of the `application_data` dict are described at https://developer.vonage.com/api/application.v2#createApplication - """ - return self._client.post( - self._client.api_host(), - "/v2/applications", - application_data, - auth_type=Application.auth_type, - ) - - def get_application(self, application_id): - """ - Get application details for the application with `application_id`. - - The format of the returned dict is described at https://developer.vonage.com/api/application.v2#getApplication - - :param str application_id: The application ID. - :rtype: dict - """ - - return self._client.get( - self._client.api_host(), - f"/v2/applications/{application_id}", - auth_type=Application.auth_type, - ) - - def update_application(self, application_id, params): - """ - Update the application with `application_id` using the values provided in `params`. - - - """ - return self._client.put( - self._client.api_host(), - f"/v2/applications/{application_id}", - params, - auth_type=Application.auth_type, - ) - - def delete_application(self, application_id): - """ - Delete the application with `application_id`. - """ - - self._client.delete( - self._client.api_host(), - f"/v2/applications/{application_id}", - auth_type=Application.auth_type, - ) - - def list_applications(self, page_size=None, page=None): - """ - List all applications for your account. - - Results are paged, so each page will need to be requested to see all applications. - - :param int page_size: The number of items in the page to be returned - :param int page: The page number of the page to be returned. - """ - params = _filter_none_values({"page_size": page_size, "page": page}) - - return self._client.get( - self._client.api_host(), - "/v2/applications", - params=params, - auth_type=Application.auth_type, - ) - - -def _filter_none_values(d): - return {k: v for k, v in d.items() if v is not None} diff --git a/src/vonage/client.py b/src/vonage/client.py deleted file mode 100644 index 532b181d..00000000 --- a/src/vonage/client.py +++ /dev/null @@ -1,366 +0,0 @@ -import vonage -from vonage_jwt.jwt import JwtClient - -from .account import Account -from .application import Application -from .errors import * -from .meetings import Meetings -from .messages import Messages -from .number_insight import NumberInsight -from .number_management import Numbers -from .proactive_connect import ProactiveConnect -from .short_codes import ShortCodes -from .sms import Sms -from .subaccounts import Subaccounts -from .users import Users -from .ussd import Ussd -from .video import Video -from .voice import Voice -from .verify import Verify -from .verify2 import Verify2 - -import logging -from platform import python_version - -import base64 -import hashlib -import hmac -import time - -from requests import Response -from requests.adapters import HTTPAdapter -from requests.sessions import Session - -string_types = (str, bytes) - -try: - from json import JSONDecodeError -except ImportError: - JSONDecodeError = ValueError - -logger = logging.getLogger("vonage") - - -class Client: - """ - Create a Client object to start making calls to Vonage/Nexmo APIs. - - The credentials you provide when instantiating a Client determine which - methods can be called. Consult the `Vonage API docs ` - for details of the authentication used by the APIs you wish to use, and instantiate your - client with the appropriate credentials. - - :param str key: Your Vonage API key - :param str secret: Your Vonage API secret. - :param str signature_secret: Your Vonage API signature secret. - You may need to have this enabled by Vonage support. It is only used for SMS authentication. - :param str signature_method: - The encryption method used for signature encryption. This must match the method - configured in the Vonage Dashboard. We recommend `sha256` or `sha512`. - This should be one of `md5`, `sha1`, `sha256`, or `sha512` if using HMAC digests. - If you want to use a simple MD5 hash, leave this as `None`. - :param str application_id: Your application ID if calling methods which use JWT authentication. - :param str private_key: Your private key, for calling methods which use JWT authentication. - This should either be a str containing the key in its PEM form, or a path to a private key file. - :param str app_name: This optional value is added to the user-agent header - provided by this library and can be used to track your app statistics. - :param str app_version: This optional value is added to the user-agent header - provided by this library and can be used to track your app statistics. - :param timeout: (optional) How many seconds to wait for the server to send data - before giving up, as a float, or a (connect timeout, read - timeout) tuple. If set this timeout is used for every call to the Vonage enpoints - :type timeout: float or tuple - """ - - def __init__( - self, - key=None, - secret=None, - signature_secret=None, - signature_method=None, - application_id=None, - private_key=None, - app_name=None, - app_version=None, - timeout=None, - pool_connections=10, - pool_maxsize=10, - max_retries=3, - ): - self.api_key = key - self.api_secret = secret - - self.signature_secret = signature_secret - self.signature_method = signature_method - - self.application_id = application_id - - if self.signature_method in { - "md5", - "sha1", - "sha256", - "sha512", - }: - self.signature_method = getattr(hashlib, signature_method) - - if private_key is not None and application_id is not None: - self._jwt_client = JwtClient(application_id, private_key) - - self._jwt_claims = {} - self._host = "rest.nexmo.com" - self._api_host = "api.nexmo.com" - self._video_host = "video.api.vonage.com" - self._meetings_api_host = "api-eu.vonage.com/v1/meetings" - self._proactive_connect_host = "api-eu.vonage.com" - - user_agent = f"vonage-python/{vonage.__version__} python/{python_version()}" - - if app_name and app_version: - user_agent += f" {app_name}/{app_version}" - - self.headers = { - "User-Agent": user_agent, - "Accept": "application/json", - } - - self.account = Account(self) - self.application = Application(self) - self.meetings = Meetings(self) - self.messages = Messages(self) - self.number_insight = NumberInsight(self) - self.numbers = Numbers(self) - self.proactive_connect = ProactiveConnect(self) - self.short_codes = ShortCodes(self) - self.sms = Sms(self) - self.subaccounts = Subaccounts(self) - self.users = Users(self) - self.ussd = Ussd(self) - self.video = Video(self) - self.verify = Verify(self) - self.verify2 = Verify2(self) - self.voice = Voice(self) - - self.timeout = timeout - self.session = Session() - self.adapter = HTTPAdapter( - pool_connections=pool_connections, - pool_maxsize=pool_maxsize, - max_retries=max_retries, - ) - self.session.mount("https://", self.adapter) - - # Gets and sets _host attribute - def host(self, value=None): - if value is None: - return self._host - else: - self._host = value - - # Gets and sets _api_host attribute - def api_host(self, value=None): - if value is None: - return self._api_host - else: - self._api_host = value - - def video_host(self, value=None): - if value is None: - return self._video_host - else: - self._video_host = value - - # Gets and sets _meetings_api_host attribute - def meetings_api_host(self, value=None): - if value is None: - return self._meetings_api_host - else: - self._meetings_api_host = value - - def proactive_connect_host(self, value=None): - if value is None: - return self._proactive_connect_host - else: - self._proactive_connect_host = value - - def auth(self, params=None, **kwargs): - self._jwt_claims = params or kwargs - - def check_signature(self, params): - params = dict(params) - signature = params.pop("sig", "").lower() - return hmac.compare_digest(signature, self.signature(params)) - - def signature(self, params): - if self.signature_method: - hasher = hmac.new( - self.signature_secret.encode(), - digestmod=self.signature_method, - ) - else: - hasher = hashlib.md5() - - # Add timestamp if not already present - if not params.get("timestamp"): - params["timestamp"] = int(time.time()) - - for key in sorted(params): - value = params[key] - - if isinstance(value, str): - value = value.replace("&", "_").replace("=", "_") - - hasher.update(f"&{key}={value}".encode("utf-8")) - - if self.signature_method is None: - hasher.update(self.signature_secret.encode()) - - return hasher.hexdigest() - - def get(self, host, request_uri, params={}, auth_type=None, sent_data_type='json'): - return self.send_request('GET', host, request_uri, params, auth_type, sent_data_type) - - def post( - self, - host, - request_uri, - params=None, - auth_type=None, - sent_data_type='json', - supports_signature_auth=False, - ): - return self.send_request( - 'POST', host, request_uri, params, auth_type, sent_data_type, supports_signature_auth - ) - - def put(self, host, request_uri, params, auth_type=None): - return self.send_request('PUT', host, request_uri, params, auth_type) - - def patch(self, host, request_uri, params, auth_type=None): - return self.send_request('PATCH', host, request_uri, params, auth_type) - - def delete(self, host, request_uri, params=None, auth_type=None): - return self.send_request('DELETE', host, request_uri, params, auth_type) - - def send_request( - self, - request_type: str, - host: str, - request_uri: str, - params: dict = {}, - auth_type=None, - sent_data_type='json', - supports_signature_auth=False, - ): - """ - Low-level method to make a request to an API server. - The supports_signature_auth parameter lets you preferentially use signature authentication if a - signature_secret was provided when initializing this client (only for the SMS API). - """ - - uri = f"https://{host}{request_uri}" - self._request_headers = self.headers - - if auth_type == 'jwt': - self._request_headers['Authorization'] = self._create_jwt_auth_string() - elif auth_type == 'params': - if supports_signature_auth and self.signature_secret: - params["api_key"] = self.api_key - params["sig"] = self.signature(params) - else: - params = dict( - params, - api_key=self.api_key, - api_secret=self.api_secret, - ) - elif auth_type == 'header': - self._request_headers['Authorization'] = self._create_header_auth_string() - else: - raise InvalidAuthenticationTypeError( - f'Invalid authentication type. Must be one of "jwt", "header" or "params".' - ) - - logger.debug( - f'{request_type} to {repr(uri)} with params {repr(params)}, headers {repr(self._request_headers)}' - ) - if sent_data_type == 'json': - return self.parse( - host, - self.session.request( - request_type, - uri, - json=params, - headers=self._request_headers, - timeout=self.timeout, - ), - ) - elif sent_data_type == 'data': - return self.parse( - host, - self.session.request( - request_type, - uri, - data=params, - headers=self._request_headers, - timeout=self.timeout, - ), - ) - else: - return self.parse( - host, - self.session.request( - request_type, - uri, - params=params, - headers=self._request_headers, - timeout=self.timeout, - ), - ) - - def parse(self, host: str, response: Response): - logger.debug(f'Response headers {repr(response.headers)}') - - if response.status_code == 401: - raise AuthenticationError('Authentication failed.') - if response.status_code == 204: - return None - - try: - content_type = response.headers['Content-Type'].split(';', 1)[0] - except KeyError: - raise ClientError(response, None, host) - - if 200 <= response.status_code < 300: - if content_type == "application/json": - try: - return response.json() - except JSONDecodeError: # Get this when we get a 202 with no content - return None - else: - return response.text - - if 400 <= response.status_code < 500: - logger.warning(f'Client error: {response.status_code} {repr(response.content)}') - raise ClientError(response, content_type, host) - - if 500 <= response.status_code < 600: - logger.warning(f"Server error: {response.status_code} {repr(response.content)}") - message = f"{response.status_code} response from {host}" - raise ServerError(message) - - def _create_jwt_auth_string(self): - return b"Bearer " + self.generate_application_jwt() - - def generate_application_jwt(self): - try: - return self._jwt_client.generate_application_jwt(self._jwt_claims) - except AttributeError as err: - if '_jwt_client' in str(err): - raise VonageError( - 'JWT generation failed. Check that you passed in valid values for "application_id" and "private_key".' - ) - else: - raise err - - def _create_header_auth_string(self): - hash = base64.b64encode(f"{self.api_key}:{self.api_secret}".encode("utf-8")).decode("ascii") - return f"Basic {hash}" diff --git a/src/vonage/errors.py b/src/vonage/errors.py deleted file mode 100644 index 1f2fb4ae..00000000 --- a/src/vonage/errors.py +++ /dev/null @@ -1,117 +0,0 @@ -from requests import Response - - -class VonageError(Exception): - """Base Error Class for all Vonage SDK errors.""" - - -class ServerError(VonageError): - """Indicates an error was reported from a Vonage server.""" - - -class ClientError(VonageError): - """Indicates an error was recieved as part of the response from a Vonage SDK request.""" - - def __init__(self, response: Response, content_type: str, host: str): - if content_type == 'application/json': - self.body = response.json() - else: - self.body = response.text - if self.body: - super().__init__( - f'{response.status_code} response from {host}. \nError Message:\n{self.body}' - ) - else: - super().__init__(f'{response.status_code} response from {host}.') - - -class AuthenticationError(VonageError): - pass - - -class CallbackRequiredError(VonageError): - """Indicates a callback is required but was not present.""" - - -class MessagesError(VonageError): - """ - Indicates an error related to the Messages class which calls the Vonage Messages API. - """ - - -class SmsError(VonageError): - """ - Indicates an error related to the Sms class which calls the Vonage SMS API. - """ - - -class PartialFailureError(VonageError): - """ - Indicates that one or more parts of the message was not sent successfully. - """ - - -class PricingTypeError(VonageError): - """A pricing type was specified that is not allowed.""" - - -class InvalidAuthenticationTypeError(VonageError): - """An authentication method was specified that is not allowed.""" - - -class InvalidRoleError(VonageError): - """The specified role was invalid.""" - - -class TokenExpiryError(VonageError): - """The specified token expiry time was invalid.""" - - -class InvalidOptionsError(VonageError): - """The option(s) that were specified are invalid.""" - - """An authentication method was specified that is not allowed.""" - - -class VerifyError(VonageError): - """Error related to the Verify API.""" - - -class BlockedNumberError(VonageError): - """The number you are trying to verify is blocked for verification.""" - - -class NumberInsightError(VonageError): - """Error related to the Number Insight API.""" - - -class SipError(VonageError): - """Error related to usage of SIP calls.""" - - -class InvalidInputError(VonageError): - """The input that was provided was invalid.""" - - -class InvalidAuthenticationTypeError(VonageError): - """An authentication method was specified that is not allowed.""" - - -class MeetingsError(VonageError): - """An error related to the Meetings class which calls the Vonage Meetings API.""" - - -class Verify2Error(VonageError): - """An error relating to the Verify (V2) API.""" - - -class SubaccountsError(VonageError): - """An error relating to the Subaccounts API.""" - - -class ProactiveConnectError(VonageError): - """An error relating to the Proactive Connect API.""" - - -class UsersError(VonageError): - """An error relating to the Users API.""" diff --git a/src/vonage/ncco_builder/connect_endpoints.py b/src/vonage/ncco_builder/connect_endpoints.py deleted file mode 100644 index cd842c0d..00000000 --- a/src/vonage/ncco_builder/connect_endpoints.py +++ /dev/null @@ -1,49 +0,0 @@ -from pydantic import BaseModel, constr -from typing import Literal - - -class ConnectEndpoints: - class Endpoint(BaseModel): - type: str = None - - class PhoneEndpoint(Endpoint): - number: constr(pattern=r'^[1-9]\d{6,14}$') - dtmfAnswer: constr(pattern='^[0-9*#p]+$') = None - onAnswer: dict = None - type: Literal['phone'] = 'phone' - - class AppEndpoint(Endpoint): - user: str - type: Literal['app'] = 'app' - - class WebsocketEndpoint(Endpoint): - uri: str - contentType: Literal['audio/l16;rate=16000', 'audio/l16;rate=8000'] - headers: dict = None - type: Literal['websocket'] = 'websocket' - - class SipEndpoint(Endpoint): - uri: str - headers: dict = None - type: Literal['sip'] = 'sip' - - class VbcEndpoint(Endpoint): - extension: str - type: Literal['vbc'] = 'vbc' - - @classmethod - def create_endpoint_model_from_dict(cls, d) -> Endpoint: - if d['type'] == 'phone': - return cls.PhoneEndpoint.model_validate(d) - elif d['type'] == 'app': - return cls.AppEndpoint.model_validate(d) - elif d['type'] == 'websocket': - return cls.WebsocketEndpoint.model_validate(d) - elif d['type'] == 'sip': - return cls.WebsocketEndpoint.model_validate(d) - elif d['type'] == 'vbc': - return cls.WebsocketEndpoint.model_validate(d) - else: - raise ValueError( - 'Invalid "type" specified for endpoint object. Cannot create a ConnectEndpoints.Endpoint model.' - ) diff --git a/src/vonage/ncco_builder/input_types.py b/src/vonage/ncco_builder/input_types.py deleted file mode 100644 index 56737f24..00000000 --- a/src/vonage/ncco_builder/input_types.py +++ /dev/null @@ -1,26 +0,0 @@ -from pydantic import BaseModel, confloat, conint -from typing import List - - -class InputTypes: - class Dtmf(BaseModel): - timeOut: conint(ge=0, le=10) = None - maxDigits: conint(ge=1, le=20) = None - submitOnHash: bool = None - - class Speech(BaseModel): - uuid: str = None - endOnSilence: confloat(ge=0.4, le=10.0) = None - language: str = None - context: List[str] = None - startTimeout: conint(ge=1, le=60) = None - maxDuration: conint(ge=1, le=60) = None - saveAudio: bool = None - - @classmethod - def create_dtmf_model(cls, dict) -> Dtmf: - return cls.Dtmf.model_validate(dict) - - @classmethod - def create_speech_model(cls, dict) -> Speech: - return cls.Speech.model_validate(dict) diff --git a/src/vonage/ncco_builder/ncco.py b/src/vonage/ncco_builder/ncco.py deleted file mode 100644 index 42d66da6..00000000 --- a/src/vonage/ncco_builder/ncco.py +++ /dev/null @@ -1,220 +0,0 @@ -from pydantic import ( - BaseModel, - Field, - FieldValidationInfo, - field_validator, - constr, - confloat, - conint, -) -from typing import Union, List, Literal - -from .connect_endpoints import ConnectEndpoints -from .input_types import InputTypes - - -class Ncco: - class Action(BaseModel): - action: str = None - - class Record(Action): - """Use the record action to record a call or part of a call.""" - - format: Literal['mp3', 'wav', 'ogg'] = None - split: Literal['conversation'] = None - channels: conint(ge=1, le=32) = None - endOnSilence: conint(ge=3, le=10) = None - endOnKey: constr(pattern='^[0-9*#]$') = None - timeOut: conint(ge=3, le=7200) = None - beepStart: bool = None - eventUrl: Union[List[str], str] = None - eventMethod: constr(to_upper=True) = None - action: Literal['record'] = 'record' - - @field_validator('channels') - @classmethod - def enable_split(cls, v, field_info: FieldValidationInfo): - if field_info.data['split'] is None: - field_info.data['split'] = 'conversation' - return v - - @field_validator('eventUrl') - @classmethod - def ensure_url_in_list(cls, v): - return Ncco._ensure_object_in_list(v) - - class Conversation(Action): - """You can use the conversation action to create standard or moderated conferences, - while preserving the communication context. - Using conversation with the same name reuses the same persisted conversation.""" - - name: str - musicOnHoldUrl: Union[List[str], str] = None - startOnEnter: bool = None - endOnExit: bool = None - record: bool = None - canSpeak: List[str] = None - canHear: List[str] = None - mute: bool = None - action: Literal['conversation'] = 'conversation' - - @field_validator('musicOnHoldUrl') - @classmethod - def ensure_url_in_list(cls, v): - return Ncco._ensure_object_in_list(v) - - @field_validator('mute') - @classmethod - def can_mute(cls, v, field_info: FieldValidationInfo): - if field_info.data['canSpeak'] is not None: - raise ValueError('Cannot use mute option if canSpeak option is specified.') - return v - - class Connect(Action): - """You can use the connect action to connect a call to endpoints such as phone numbers or a VBC extension. - - If specifying a value for the "from" field, name it with a trailing underscore, i.e. "from_". - """ - - endpoint: Union[dict, ConnectEndpoints.Endpoint, list] - from_: str = Field(default=None, serialization_alias='from', pattern=r'^[1-9]\d{6,14}$') - randomFromNumber: bool = None - eventType: Literal['synchronous'] = None - timeout: int = None - limit: conint(le=7200) = None - machineDetection: Literal['continue', 'hangup'] = None - advancedMachineDetection: dict = None - eventUrl: Union[List[str], str] = None - eventMethod: constr(to_upper=True) = None - ringbackTone: str = None - action: Literal['connect'] = 'connect' - - @field_validator('endpoint') - @classmethod - def validate_endpoint(cls, v): - if type(v) is dict: - return [ConnectEndpoints.create_endpoint_model_from_dict(v)] - elif type(v) is list: - return [ConnectEndpoints.create_endpoint_model_from_dict(v[0])] - else: - return [v] - - @field_validator('randomFromNumber') - @classmethod - def check_from_not_set(cls, v, field_info: FieldValidationInfo): - if v is True and 'from_' in field_info.data: - if field_info.data['from_'] is not None: - raise ValueError( - 'Cannot set a "from" ("from_") field and also the "randomFromNumber" = True option' - ) - return v - - @field_validator('eventUrl') - @classmethod - def ensure_url_in_list(cls, v): - return Ncco._ensure_object_in_list(v) - - @field_validator('advancedMachineDetection') - @classmethod - def validate_advancedMachineDetection(cls, v): - if 'behavior' in v and v['behavior'] not in ('continue', 'hangup'): - raise ValueError( - 'advancedMachineDetection["behavior"] must be one of: "continue", "hangup".' - ) - if 'mode' in v and v['mode'] not in ('detect, detect_beep'): - raise ValueError( - 'advancedMachineDetection["mode"] must be one of: "detect", "detect_beep".' - ) - return v - - class Talk(Action): - """The talk action sends synthesized speech to a Conversation.""" - - text: constr(max_length=1500) - bargeIn: bool = None - loop: conint(ge=0) = None - level: confloat(ge=-1, le=1) = None - language: str = None - style: int = None - premium: bool = None - action: Literal['talk'] = 'talk' - - class Stream(Action): - """The stream action allows you to send an audio stream to a Conversation.""" - - streamUrl: Union[List[str], str] - level: confloat(ge=-1, le=1) = None - bargeIn: bool = None - loop: conint(ge=0) = None - action: Literal['stream'] = 'stream' - - @field_validator('streamUrl') - @classmethod - def ensure_url_in_list(cls, v): - return Ncco._ensure_object_in_list(v) - - class Input(Action): - """Collect digits or speech input by the person you are are calling.""" - - type: Union[ - Literal['dtmf', 'speech'], - List[Literal['dtmf']], - List[Literal['speech']], - List[Literal['dtmf', 'speech']], - ] - dtmf: Union[InputTypes.Dtmf, dict] = None - speech: Union[InputTypes.Speech, dict] = None - eventUrl: Union[List[str], str] = None - eventMethod: constr(to_upper=True) = None - action: Literal['input'] = 'input' - - @field_validator('type', 'eventUrl') - @classmethod - def ensure_value_in_list(cls, v): - return Ncco._ensure_object_in_list(v) - - @field_validator('dtmf') - @classmethod - def ensure_input_object_is_dtmf_model(cls, v): - if type(v) is dict: - return InputTypes.create_dtmf_model(v) - else: - return v - - @field_validator('speech') - @classmethod - def ensure_input_object_is_speech_model(cls, v): - if type(v) is dict: - return InputTypes.create_speech_model(v) - else: - return v - - class Notify(Action): - """Use the notify action to send a custom payload to your event URL.""" - - payload: dict - eventUrl: Union[List[str], str] - eventMethod: constr(to_upper=True) = None - action: Literal['notify'] = 'notify' - - @field_validator('eventUrl') - @classmethod - def ensure_url_in_list(cls, v): - return Ncco._ensure_object_in_list(v) - - @staticmethod - def build_ncco(*args: Action, actions: List[Action] = None) -> str: - ncco = [] - if actions is not None: - for action in actions: - ncco.append(action.model_dump(by_alias=True, exclude_none=True)) - for action in args: - ncco.append(action.model_dump(by_alias=True, exclude_none=True)) - return ncco - - @staticmethod - def _ensure_object_in_list(obj): - if type(obj) != list: - return [obj] - else: - return obj diff --git a/src/vonage/number_insight.py b/src/vonage/number_insight.py deleted file mode 100644 index 6a508da6..00000000 --- a/src/vonage/number_insight.py +++ /dev/null @@ -1,84 +0,0 @@ -from .errors import CallbackRequiredError, NumberInsightError -import json - - -class NumberInsight: - auth_type = 'params' - sent_data_type = 'query' - - def __init__(self, client): - self._client = client - - def get_basic_number_insight(self, params=None, **kwargs): - response = self._client.get( - self._client.api_host(), - "/ni/basic/json", - params or kwargs, - auth_type=NumberInsight.auth_type, - sent_data_type=NumberInsight.sent_data_type, - ) - self.check_for_error(response) - - return response - - def get_standard_number_insight(self, params=None, **kwargs): - response = self._client.get( - self._client.api_host(), - "/ni/standard/json", - params or kwargs, - auth_type=NumberInsight.auth_type, - sent_data_type=NumberInsight.sent_data_type, - ) - self.check_for_error(response) - - return response - - def get_advanced_number_insight(self, params=None, **kwargs): - response = self._client.get( - self._client.api_host(), - "/ni/advanced/json", - params or kwargs, - auth_type=NumberInsight.auth_type, - sent_data_type=NumberInsight.sent_data_type, - ) - self.check_for_error(response) - - return response - - def get_async_advanced_number_insight(self, params=None, **kwargs): - argoparams = params or kwargs - self.check_for_callback(argoparams) - - response = self._client.get( - self._client.api_host(), - "/ni/advanced/async/json", - params or kwargs, - auth_type=NumberInsight.auth_type, - sent_data_type=NumberInsight.sent_data_type, - ) - print(json.dumps(response, indent=4)) - self.check_for_async_error(response) - - return response - - def check_for_error(self, response): - if response['status'] != 0: - raise NumberInsightError( - f'Number Insight API method failed with status: {response["status"]} and error: {response["status_message"]}' - ) - - def check_for_async_error(self, response): - if response['status'] != 0: - raise NumberInsightError( - f'Number Insight API method failed with status: {response["status"]} and error: {response["error_text"]}' - ) - - def check_for_callback(self, argoparams): - if ( - "callback" in argoparams - and type(argoparams["callback"]) == str - and argoparams["callback"] != "" - ): - pass - else: - raise CallbackRequiredError("A callback is needed for async advanced number insight") diff --git a/src/vonage/number_management.py b/src/vonage/number_management.py deleted file mode 100644 index 40a6f812..00000000 --- a/src/vonage/number_management.py +++ /dev/null @@ -1,41 +0,0 @@ -class Numbers: - auth_type = 'header' - sent_data_type_GET = 'query' - sent_data_type_POST = 'data' - defaults = {'auth_type': auth_type, 'sent_data_type': sent_data_type_POST} - - def __init__(self, client): - self._client = client - - def get_account_numbers(self, params=None, **kwargs): - return self._client.get( - self._client.host(), - "/account/numbers", - params or kwargs, - auth_type=Numbers.auth_type, - sent_data_type=Numbers.sent_data_type_GET, - ) - - def get_available_numbers(self, country_code, params=None, **kwargs): - return self._client.get( - self._client.host(), - "/number/search", - dict(params or kwargs, country=country_code), - auth_type=Numbers.auth_type, - sent_data_type=Numbers.sent_data_type_GET, - ) - - def buy_number(self, params=None, **kwargs): - return self._client.post( - self._client.host(), "/number/buy", params or kwargs, **Numbers.defaults - ) - - def cancel_number(self, params=None, **kwargs): - return self._client.post( - self._client.host(), "/number/cancel", params or kwargs, **Numbers.defaults - ) - - def update_number(self, params=None, **kwargs): - return self._client.post( - self._client.host(), "/number/update", params or kwargs, **Numbers.defaults - ) diff --git a/src/vonage/short_codes.py b/src/vonage/short_codes.py deleted file mode 100644 index e4e617fd..00000000 --- a/src/vonage/short_codes.py +++ /dev/null @@ -1,34 +0,0 @@ -class ShortCodes: - auth_type = 'params' - defaults = {'auth_type': auth_type, 'sent_data_type': 'data'} - - def __init__(self, client): - self._client = client - - def send_2fa_message(self, params=None, **kwargs): - return self._client.post( - self._client.host(), "/sc/us/2fa/json", params or kwargs, **ShortCodes.defaults - ) - - def send_event_alert_message(self, params=None, **kwargs): - return self._client.post( - self._client.host(), "/sc/us/alert/json", params or kwargs, **ShortCodes.defaults - ) - - def send_marketing_message(self, params=None, **kwargs): - return self._client.post( - self._client.host(), "/sc/us/marketing/json", params or kwargs, **ShortCodes.defaults - ) - - def get_event_alert_numbers(self): - return self._client.get( - self._client.host(), "/sc/us/alert/opt-in/query/json", auth_type=ShortCodes.auth_type - ) - - def resubscribe_event_alert_number(self, params=None, **kwargs): - return self._client.post( - self._client.host(), - "/sc/us/alert/opt-in/manage/json", - params or kwargs, - **ShortCodes.defaults, - ) diff --git a/src/vonage/sms.py b/src/vonage/sms.py deleted file mode 100644 index b0ab4c9c..00000000 --- a/src/vonage/sms.py +++ /dev/null @@ -1,74 +0,0 @@ -import pytz -from datetime import datetime -from ._internal import _format_date_param -from .errors import SmsError, PartialFailureError - - -class Sms: - defaults = {'auth_type': 'params', 'sent_data_type': 'data'} - - def __init__(self, client): - self._client = client - - def send_message(self, params): - """ - Send an SMS message. - Requires a client initialized with `key` and either `secret` or `signature_secret`. - :param dict params: A dict of values described at `Send an SMS `_ - """ - response_data = self._client.post( - self._client.host(), - "/sms/json", - params, - supports_signature_auth=True, - **Sms.defaults, - ) - - if int(response_data['message-count']) > 1: - self.check_for_partial_failure(response_data) - else: - self.check_for_error(response_data) - - return response_data - - def check_for_partial_failure(self, response_data): - successful_messages = 0 - total_messages = int(response_data['message-count']) - - for message in response_data['messages']: - if message['status'] == '0': - successful_messages += 1 - if successful_messages < total_messages: - raise PartialFailureError( - 'Sms.send_message method partially failed. Not all of the message sent successfully.' - ) - - def check_for_error(self, response_data): - message = response_data['messages'][0] - if int(message['status']) != 0: - raise SmsError( - f'Sms.send_message method failed with error code {message["status"]}: {message["error-text"]}' - ) - - def submit_sms_conversion(self, message_id, delivered=True, timestamp=None): - """ - Notify Vonage that an SMS was successfully received. - - If you are using the Verify API for 2FA, this information is sent to Vonage automatically - so you do not need to use this method to submit conversion data about 2FA messages. - - :param message_id: The `message-id` str returned by the send_message call. - :param delivered: A `bool` indicating that the message was or was not successfully delivered. - :param timestamp: A `datetime` object containing the time the SMS arrived. - :return: The parsed response from the server. On success, the bytestring b'OK' - """ - params = { - "message-id": message_id, - "delivered": delivered, - "timestamp": timestamp or datetime.now(pytz.utc), - } - # Ensure timestamp is a string: - _format_date_param(params, "timestamp") - return self._client.post( - self._client.api_host(), "/conversions/sms", params, **Sms.defaults - ) diff --git a/src/vonage/ussd.py b/src/vonage/ussd.py deleted file mode 100644 index 93df091c..00000000 --- a/src/vonage/ussd.py +++ /dev/null @@ -1,15 +0,0 @@ -class Ussd: - defaults = {'auth_type': 'params', 'sent_data_type': 'data'} - - def __init__(self, client): - self._client = client - - def send_ussd_push_message(self, params=None, **kwargs): - return self._client.post( - self._client.host(), "/ussd/json", params or kwargs, **Ussd.defaults - ) - - def send_ussd_prompt_message(self, params=None, **kwargs): - return self._client.post( - self._client.host(), "/ussd-prompt/json", params or kwargs, **Ussd.defaults - ) diff --git a/src/vonage/verify.py b/src/vonage/verify.py deleted file mode 100644 index 189bd71e..00000000 --- a/src/vonage/verify.py +++ /dev/null @@ -1,99 +0,0 @@ -from .errors import VerifyError, BlockedNumberError - - -class Verify: - auth_type = 'params' - sent_data_type_GET = 'query' - sent_data_type_POST = 'data' - defaults = {'auth_type': auth_type, 'sent_data_type': sent_data_type_POST} - - def __init__(self, client): - self._client = client - - def start_verification(self, params=None, **kwargs): - response = self._client.post( - self._client.api_host(), - "/verify/json", - params or kwargs, - **Verify.defaults, - ) - - self.check_for_error(response) - return response - - def check(self, request_id, code): - response = self._client.post( - self._client.api_host(), - "/verify/check/json", - {"request_id": request_id, "code": code}, - **Verify.defaults, - ) - - self.check_for_error(response) - return response - - def search(self, request=None): - if type(request) == str: - response = self._client.get( - self._client.api_host(), - "/verify/search/json", - {"request_id": request}, - auth_type=Verify.auth_type, - sent_data_type=Verify.sent_data_type_GET, - ) - elif type(request) == list: - response = self._client.get( - self._client.api_host(), - "/verify/search/json", - {"request_ids": request}, - auth_type=Verify.auth_type, - sent_data_type=Verify.sent_data_type_GET, - ) - else: - raise VerifyError('At least one request ID must be provided.') - - self.check_for_error(response) - return response - - def cancel(self, request_id): - response = self._client.post( - self._client.api_host(), - "/verify/control/json", - {"request_id": request_id, "cmd": "cancel"}, - **Verify.defaults, - ) - - self.check_for_error(response) - return response - - def trigger_next_event(self, request_id): - response = self._client.post( - self._client.api_host(), - "/verify/control/json", - {"request_id": request_id, "cmd": "trigger_next_event"}, - **Verify.defaults, - ) - - self.check_for_error(response) - return response - - def psd2(self, params=None, **kwargs): - response = self._client.post( - self._client.api_host(), - "/verify/psd2/json", - params or kwargs, - **Verify.defaults, - ) - - self.check_for_error(response) - return response - - def check_for_error(self, response): - if response['status'] == '7': - raise BlockedNumberError( - 'Error code 7: The number you are trying to verify is blocked for verification.' - ) - elif 'error_text' in response: - raise VerifyError( - f'Verify API method failed with status: {response["status"]} and error: {response["error_text"]}' - ) diff --git a/src/vonage/verify2.py b/src/vonage/verify2.py deleted file mode 100644 index eeb3306f..00000000 --- a/src/vonage/verify2.py +++ /dev/null @@ -1,116 +0,0 @@ -from __future__ import annotations -import locale -from typing import TYPE_CHECKING - -if TYPE_CHECKING: - from vonage import Client - -from pydantic import BaseModel, ValidationError, field_validator, conint, constr -from typing import List - -import copy -import re - -from ._internal import set_auth_type -from .errors import Verify2Error - - -class Verify2: - valid_channels = [ - 'sms', - 'whatsapp', - 'whatsapp_interactive', - 'voice', - 'email', - 'silent_auth', - ] - - def __init__(self, client: Client): - self._client = client - self._auth_type = set_auth_type(self._client) - - def new_request(self, params: dict): - self._remove_unnecessary_fraud_check(params) - try: - params_to_verify = copy.deepcopy(params) - Verify2.VerifyRequest.model_validate(params_to_verify) - except (ValidationError, Verify2Error) as err: - raise err - - return self._client.post( - self._client.api_host(), - '/v2/verify', - params, - auth_type=self._auth_type, - ) - - def check_code(self, request_id: str, code: str): - params = {'code': str(code)} - - return self._client.post( - self._client.api_host(), - f'/v2/verify/{request_id}', - params, - auth_type=self._auth_type, - ) - - def cancel_verification(self, request_id: str): - return self._client.delete( - self._client.api_host(), - f'/v2/verify/{request_id}', - auth_type=self._auth_type, - ) - - def _remove_unnecessary_fraud_check(self, params): - if 'fraud_check' in params and params['fraud_check'] != False: - del params['fraud_check'] - - class VerifyRequest(BaseModel): - brand: str - workflow: List[dict] - locale: str = None - channel_timeout: conint(ge=60, le=900) = None - client_ref: str = None - code_length: conint(ge=4, le=10) = None - fraud_check: bool = None - code: constr(min_length=4, max_length=10, pattern='^[a-zA-Z0-9]{4,10}$') = None - - @field_validator('workflow') - @classmethod - def check_valid_workflow(cls, v): - for workflow in v: - Verify2._check_valid_channel(workflow) - Verify2._check_valid_recipient(workflow) - Verify2._check_app_hash(workflow) - if workflow['channel'] == 'whatsapp' and 'from' in workflow: - Verify2._check_whatsapp_sender(workflow) - - def _check_valid_channel(workflow): - if 'channel' not in workflow or workflow['channel'] not in Verify2.valid_channels: - raise Verify2Error( - f'You must specify a valid verify channel inside the "workflow" object, one of: "{Verify2.valid_channels}"' - ) - - def _check_valid_recipient(workflow): - if 'to' not in workflow or ( - workflow['channel'] != 'email' and not re.search(r'^[1-9]\d{6,14}$', workflow['to']) - ): - raise Verify2Error( - f'You must specify a valid "to" value for channel "{workflow["channel"]}"' - ) - - def _check_app_hash(workflow): - if workflow['channel'] == 'sms' and 'app_hash' in workflow: - if type(workflow['app_hash']) != str or len(workflow['app_hash']) != 11: - raise Verify2Error( - 'Invalid "app_hash" specified. If specifying app_hash, \ - it must be passed as a string and contain exactly 11 characters.' - ) - elif workflow['channel'] != 'sms' and 'app_hash' in workflow: - raise Verify2Error( - 'Cannot specify a value for "app_hash" unless using SMS for authentication.' - ) - - def _check_whatsapp_sender(workflow): - if not re.search(r'^[1-9]\d{6,14}$', workflow['from']): - raise Verify2Error(f'You must specify a valid "from" value if included.') diff --git a/src/vonage/video.py b/src/vonage/video.py deleted file mode 100644 index c28799be..00000000 --- a/src/vonage/video.py +++ /dev/null @@ -1,356 +0,0 @@ -from __future__ import annotations -from typing import TYPE_CHECKING - -if TYPE_CHECKING: - from vonage import Client - -from .errors import ( - InvalidRoleError, - TokenExpiryError, - InvalidOptionsError, - SipError, - InvalidInputError, -) - -import re -from time import time -from uuid import uuid4 - - -class Video: - auth_type = 'jwt' - archive_mode_values = {'manual', 'always'} - media_mode_values = {'routed', 'relayed'} - token_roles = {'subscriber', 'publisher', 'moderator'} - - def __init__(self, client: Client): - self._client = client - - def create_session(self, session_options: dict = None): - if session_options is None: - session_options = {} - - params = {'archiveMode': 'manual', 'p2p.preference': 'disabled', 'location': None} - if ( - 'archive_mode' in session_options - and session_options['archive_mode'] not in Video.archive_mode_values - ): - raise InvalidOptionsError( - f'Invalid archive_mode value. Must be one of {Video.archive_mode_values}.' - ) - elif 'archive_mode' in session_options: - params['archiveMode'] = session_options['archive_mode'] - if ( - 'media_mode' in session_options - and session_options['media_mode'] not in Video.media_mode_values - ): - raise InvalidOptionsError( - f'Invalid media_mode value. Must be one of {Video.media_mode_values}.' - ) - elif 'media_mode' in session_options: - if session_options['media_mode'] == 'routed': - params['p2p.preference'] = 'disabled' - elif session_options['media_mode'] == 'relayed': - if params['archiveMode'] == 'always': - raise InvalidOptionsError( - 'Invalid combination: cannot specify "archive_mode": "always" and "media_mode": "relayed".' - ) - else: - params['p2p.preference'] = 'enabled' - if 'location' in session_options: - params['location'] = session_options['location'] - - session = self._client.post( - self._client.video_host(), - '/session/create', - params, - auth_type=Video.auth_type, - sent_data_type='data', - )[0] - - media_mode = self.get_media_mode(params['p2p.preference']) - session_info = { - 'session_id': session['session_id'], - 'archive_mode': params['archiveMode'], - 'media_mode': media_mode, - 'location': params['location'], - } - - return session_info - - def get_media_mode(self, p2p_preference): - if p2p_preference == 'disabled': - return 'routed' - elif p2p_preference == 'enabled': - return 'relayed' - - def get_stream(self, session_id, stream_id): - return self._client.get( - self._client.video_host(), - f'/v2/project/{self._client.application_id}/session/{session_id}/stream/{stream_id}', - auth_type=Video.auth_type, - ) - - def list_streams(self, session_id): - return self._client.get( - self._client.video_host(), - f'/v2/project/{self._client.application_id}/session/{session_id}/stream', - auth_type=Video.auth_type, - ) - - def set_stream_layout(self, session_id, items): - return self._client.put( - self._client.video_host(), - f'/v2/project/{self._client.application_id}/session/{session_id}/stream', - items, - auth_type=Video.auth_type, - ) - - def send_signal(self, session_id, type, data, connection_id=None): - if connection_id: - request_uri = f'/v2/project/{self._client.application_id}/session/{session_id}/connection/{connection_id}/signal' - else: - request_uri = f'/v2/project/{self._client.application_id}/session/{session_id}/signal' - - params = {'type': type, 'data': data} - - return self._client.post( - self._client.video_host(), request_uri, params, auth_type=Video.auth_type - ) - - def disconnect_client(self, session_id, connection_id): - return self._client.delete( - self._client.video_host(), - f'/v2/project/{self._client.application_id}/session/{session_id}/connection/{connection_id}', - auth_type=Video.auth_type, - ) - - def mute_stream(self, session_id, stream_id): - return self._client.post( - self._client.video_host(), - f'/v2/project/{self._client.application_id}/session/{session_id}/stream/{stream_id}/mute', - params=None, - auth_type=Video.auth_type, - ) - - def mute_all_streams(self, session_id, active=True, excluded_stream_ids: list = []): - params = {'active': active, 'excludedStreamIds': excluded_stream_ids} - - return self._client.post( - self._client.video_host(), - f'/v2/project/{self._client.application_id}/session/{session_id}/mute', - params, - auth_type=Video.auth_type, - ) - - def disable_mute_all_streams(self, session_id, excluded_stream_ids: list = []): - return self.mute_all_streams( - session_id, active=False, excluded_stream_ids=excluded_stream_ids - ) - - def list_archives(self, filter_params=None, **filter_kwargs): - return self._client.get( - self._client.video_host(), - f'/v2/project/{self._client.application_id}/archive', - filter_params or filter_kwargs, - auth_type=Video.auth_type, - ) - - def create_archive(self, params=None, **kwargs): - return self._client.post( - self._client.video_host(), - f'/v2/project/{self._client.application_id}/archive', - params or kwargs, - auth_type=Video.auth_type, - ) - - def get_archive(self, archive_id): - return self._client.get( - self._client.video_host(), - f'/v2/project/{self._client.application_id}/archive/{archive_id}', - auth_type=Video.auth_type, - ) - - def delete_archive(self, archive_id): - return self._client.get( - self._client.video_host(), - f'/v2/project/{self._client.application_id}/archive/{archive_id}', - auth_type=Video.auth_type, - ) - - def add_stream_to_archive(self, archive_id, stream_id, has_audio=True, has_video=True): - params = {'addStream': stream_id, 'hasAudio': has_audio, 'hasvideo': has_video} - - return self._client.patch( - self._client.video_host(), - f'/v2/project/{self._client.application_id}/archive/{archive_id}/streams', - params, - auth_type=Video.auth_type, - ) - - def remove_stream_from_archive(self, archive_id, stream_id): - params = {'removeStream': stream_id} - - return self._client.patch( - self._client.video_host(), - f'/v2/project/{self._client.application_id}/archive/{archive_id}/streams', - params, - auth_type=Video.auth_type, - ) - - def stop_archive(self, archive_id): - return self._client.post( - self._client.video_host(), - f'/v2/project/{self._client.application_id}/archive/{archive_id}/stop', - params=None, - auth_type=Video.auth_type, - ) - - def change_archive_layout(self, archive_id, params=None, **kwargs): - return self._client.put( - self._client.video_host(), - f'/v2/project/{self._client.application_id}/archive/{archive_id}/layout', - params or kwargs, - auth_type=Video.auth_type, - ) - - def create_sip_call(self, session_id: str, token: str, sip: dict): - if 'uri' not in sip: - raise SipError('You must specify a uri when creating a SIP call.') - - params = {'sessionId': session_id, 'token': token, 'sip': sip} - return self._client.post( - self._client.video_host(), - f'/v2/project/{self._client.application_id}/dial', - params, - auth_type=Video.auth_type, - ) - - def play_dtmf(self, session_id: str, digits: str, connection_id: str = None): - if not re.search('^[0-9*#p]+$', digits): - raise InvalidInputError('Only digits 0-9, *, #, and "p" are allowed.') - - params = {'digits': digits} - - if connection_id is not None: - return self._client.post( - self._client.video_host(), - f'/v2/project/{self._client.application_id}/session/{session_id}/connection/{connection_id}/play-dtmf', - params, - auth_type=Video.auth_type, - ) - - return self._client.post( - self._client.video_host(), - f'/v2/project/{self._client.application_id}/session/{session_id}/play-dtmf', - params, - auth_type=Video.auth_type, - ) - - def list_broadcasts(self, offset: int = None, count: int = None, session_id: str = None): - if offset is not None and (type(offset) != int or offset < 0): - raise InvalidOptionsError('Offset must be an int >= 0.') - if count is not None and (type(count) != int or count < 0 or count > 1000): - raise InvalidOptionsError('Count must be an int between 0 and 1000.') - - params = {'offset': str(offset), 'count': str(count), 'sessionId': session_id} - - return self._client.get( - self._client.video_host(), - f'/v2/project/{self._client.application_id}/broadcast', - params, - auth_type=Video.auth_type, - ) - - def start_broadcast(self, params: dict): - return self._client.post( - self._client.video_host(), - f'/v2/project/{self._client.application_id}/broadcast', - params, - auth_type=Video.auth_type, - ) - - def get_broadcast(self, broadcast_id: str): - return self._client.get( - self._client.video_host(), - f'/v2/project/{self._client.application_id}/broadcast/{broadcast_id}', - auth_type=Video.auth_type, - ) - - def stop_broadcast(self, broadcast_id: str): - return self._client.post( - self._client.video_host(), - f'/v2/project/{self._client.application_id}/broadcast/{broadcast_id}', - params={}, - auth_type=Video.auth_type, - ) - - def change_broadcast_layout(self, broadcast_id: str, params: dict): - return self._client.put( - self._client.video_host(), - f'/v2/project/{self._client.application_id}/broadcast/{broadcast_id}/layout', - params=params, - auth_type=Video.auth_type, - ) - - def add_stream_to_broadcast( - self, broadcast_id: str, stream_id: str, has_audio=True, has_video=True - ): - params = {'addStream': stream_id, 'hasAudio': has_audio, 'hasvideo': has_video} - - return self._client.patch( - self._client.video_host(), - f'/v2/project/{self._client.application_id}/broadcast/{broadcast_id}/streams', - params, - auth_type=Video.auth_type, - ) - - def remove_stream_from_broadcast(self, broadcast_id: str, stream_id: str): - params = {'removeStream': stream_id} - - return self._client.patch( - self._client.video_host(), - f'/v2/project/{self._client.application_id}/broadcast/{broadcast_id}/streams', - params, - auth_type=Video.auth_type, - ) - - def generate_client_token(self, session_id, token_options={}): - now = int(time()) - claims = { - 'scope': 'session.connect', - 'session_id': session_id, - 'role': 'publisher', - 'initial_layout_class_list': '', - 'jti': str(uuid4()), - 'iat': now, - } - if 'role' in token_options: - claims['role'] = token_options['role'] - if 'data' in token_options: - claims['data'] = token_options['data'] - if 'initialLayoutClassList' in token_options: - claims['initial_layout_class_list'] = token_options['initialLayoutClassList'] - if 'expireTime' in token_options and token_options['expireTime'] > now: - claims['exp'] = token_options['expireTime'] - if 'jti' in token_options: - claims['jti'] = token_options['jti'] - if 'iat' in token_options: - claims['iat'] = token_options['iat'] - if 'subject' in token_options: - claims['subject'] = token_options['subject'] - if 'acl' in token_options: - claims['acl'] = token_options['acl'] - - self.validate_client_token_options(claims) - self._client.auth(claims) - return self._client.generate_application_jwt() - - def validate_client_token_options(self, claims): - now = int(time()) - if claims['role'] not in Video.token_roles: - raise InvalidRoleError( - f'Invalid role specified for the client token. Valid values are: {Video.token_roles}' - ) - if 'exp' in claims and claims['exp'] > now + 3600 * 24 * 30: - raise TokenExpiryError('Token expiry date must be less than 30 days from now.') diff --git a/tests/conftest.py b/tests/conftest.py deleted file mode 100644 index 851b5e3f..00000000 --- a/tests/conftest.py +++ /dev/null @@ -1,111 +0,0 @@ -import os -import os.path -import platform - -import pytest -import vonage - -# Ensure our client isn't being configured with real values! -os.environ.clear() - - -def read_file(path): - with open(os.path.join(os.path.dirname(__file__), path)) as input_file: - return input_file.read() - - -class DummyData(object): - def __init__(self): - self.api_key = "nexmo-api-key" - self.api_secret = "nexmo-api-secret" - self.signature_secret = "secret" - self.application_id = "nexmo-application-id" - self.private_key = read_file("data/private_key.txt") - self.public_key = read_file("data/public_key.txt") - self.user_agent = f"vonage-python/{vonage.__version__} python/{platform.python_version()}" - self.host = "rest.nexmo.com" - self.api_host = "api.nexmo.com" - self.meetings_api_host = "api-eu.vonage.com/beta/meetings" - - -@pytest.fixture(scope="session") -def dummy_data(): - return DummyData() - - -@pytest.fixture -def client(dummy_data): - return vonage.Client( - key=dummy_data.api_key, - secret=dummy_data.api_secret, - application_id=dummy_data.application_id, - private_key=dummy_data.private_key, - ) - - -# Represents an instance of the Voice class for testing -@pytest.fixture -def voice(client): - return vonage.Voice(client) - - -# Represents an instance of the Sms class for testing -@pytest.fixture -def sms(client): - return vonage.Sms(client) - - -# Represents an instance of the Verify class for testing -@pytest.fixture -def verify(client): - return vonage.Verify(client) - - -@pytest.fixture -def number_insight(client): - return vonage.NumberInsight(client) - - -@pytest.fixture -def account(client): - return vonage.Account(client) - - -@pytest.fixture -def numbers(client): - import vonage - - return vonage.Numbers(client) - - -@pytest.fixture -def ussd(client): - import vonage - - return vonage.Ussd(client) - - -@pytest.fixture -def short_codes(client): - import vonage - - return vonage.ShortCodes(client) - - -@pytest.fixture -def messages(client): - return vonage.Messages(client) - - -@pytest.fixture -def meetings(client): - import vonage - - return vonage.Meetings(client) - - -@pytest.fixture -def proc(client): - import vonage - - return vonage.ProactiveConnect(client) diff --git a/tests/data/application/create_application.json b/tests/data/application/create_application.json deleted file mode 100644 index 18ab0453..00000000 --- a/tests/data/application/create_application.json +++ /dev/null @@ -1,14 +0,0 @@ -{ - "id": "680754a2-86b9-11e9-9729-3200112428c0", - "name": "My Test Application", - "keys": { - "private_key": "-----BEGIN PRIVATE KEY-----\nABCDE\nabcde\n12345\n-----END PRIVATE KEY-----\n", - "public_key": "-----BEGIN PUBLIC KEY-----\nA123BC\n2345ADC\n-----END PUBLIC KEY-----\n" - }, - "capabilities": {}, - "_links": { - "self": { - "href": "/v2/applications/680754a2-86b9-11e9-9729-3200112428c0" - } - } -} \ No newline at end of file diff --git a/tests/data/application/get_application.json b/tests/data/application/get_application.json deleted file mode 100644 index 8f18afcd..00000000 --- a/tests/data/application/get_application.json +++ /dev/null @@ -1,13 +0,0 @@ -{ - "id": "680754a2-86b9-11e9-9729-3200112428c0", - "name": "My Test Application", - "keys": { - "public_key": "-----BEGIN PUBLIC KEY-----\nA123BC\n2345ADC\n-----END PUBLIC KEY-----\n" - }, - "capabilities": {}, - "_links": { - "self": { - "href": "/v2/applications/680754a2-86b9-11e9-9729-3200112428c0" - } - } -} \ No newline at end of file diff --git a/tests/data/application/list_applications.json b/tests/data/application/list_applications.json deleted file mode 100644 index c2f67537..00000000 --- a/tests/data/application/list_applications.json +++ /dev/null @@ -1,45 +0,0 @@ -{ - "page_size": 1, - "page": 1, - "total_items": 30, - "total_pages": 1, - "_embedded": { - "applications": [ - { - "id": "680754a2-86b9-11e9-9729-3200112428c0", - "name": "My Test Application", - "keys": { - "public_key": "-----BEGIN PUBLIC KEY-----\nA123BC\n2345ADC\n-----END PUBLIC KEY-----\n" - }, - "capabilities": { - "voice": { - "webhooks": { - "event_url": { - "address": "https://example.org/event", - "http_method": "POST" - }, - "answer_url": { - "address": "https://example.org/answer", - "http_method": "GET" - } - } - } - } - } - ] - }, - "_links": { - "self": { - "href": "/v2/applications?page_size=10&page=1" - }, - "first": { - "href": "/v2/applications?page_size=10" - }, - "last": { - "href": "/v2/applications?page_size=10&page=3" - }, - "next": { - "href": "/v2/applications?page_size=10&page=2" - } - } -} \ No newline at end of file diff --git a/tests/data/application/update_application.json b/tests/data/application/update_application.json deleted file mode 100644 index 8a268167..00000000 --- a/tests/data/application/update_application.json +++ /dev/null @@ -1,13 +0,0 @@ -{ - "id": "680754a2-86b9-11e9-9729-3200112428c0", - "name": "A Better Name", - "keys": { - "public_key": "-----BEGIN PUBLIC KEY-----\nA123BC\n2345ADC\n-----END PUBLIC KEY-----\n" - }, - "capabilities": {}, - "_links": { - "self": { - "href": "/v2/applications/d678d143-e7fa-465a-9ee3-0b59621967d2" - } - } -} \ No newline at end of file diff --git a/tests/data/meetings/multiple_rooms.json b/tests/data/meetings/multiple_rooms.json deleted file mode 100644 index 40ede2d2..00000000 --- a/tests/data/meetings/multiple_rooms.json +++ /dev/null @@ -1,131 +0,0 @@ -{ - "page_size": 20, - "_embedded": [ - { - "id": "4814804d-7c2d-4846-8c7d-4f6fae1f910a", - "display_name": "my_test_room", - "metadata": null, - "type": "instant", - "expires_at": "2023-01-24T03:25:23.341Z", - "recording_options": { - "auto_record": false, - "record_only_owner": false - }, - "meeting_code": "697975707", - "_links": { - "host_url": { - "href": "https://meetings.vonage.com/?room_token=697975707&participant_token=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCIsImtpZCI6IjU5N2NmYTAzLTY3NTQtNGE0ZC1hYjU1LWZiMTdkNzc4NzRjMSJ9.eyJwYXJ0aWNpcGFudElkIjoiZDIxMzM0YmMtNjljNi00MGI2LWE4NmYtNDVjYzRlNmQ5MDVlIiwiaWF0IjoxNjc0NTcyODg1fQ.qOmyuJL1eVqUzdTlAGKZX-h5Q-dTZnoKG4Jto5AzWHs" - }, - "guest_url": { - "href": "https://meetings.vonage.com/697975707" - } - }, - "created_at": "2023-01-24T03:15:23.342Z", - "is_available": true, - "expire_after_use": false, - "theme_id": null, - "initial_join_options": { - "microphone_state": "default" - }, - "join_approval_level": "none", - "ui_settings": { - "language": "default" - }, - "available_features": { - "is_recording_available": true, - "is_chat_available": true, - "is_whiteboard_available": true, - "is_locale_switcher_available": false - } - }, - { - "id": "de34416a-2a4c-4a59-a16a-8cd7d3121ea0", - "display_name": "my_test_room", - "metadata": null, - "type": "instant", - "expires_at": "2023-01-24T03:26:46.521Z", - "recording_options": { - "auto_record": false, - "record_only_owner": false - }, - "meeting_code": "254629696", - "_links": { - "host_url": { - "href": "https://meetings.vonage.com/?room_token=254629696&participant_token=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCIsImtpZCI6IjU5N2NmYTAzLTY3NTQtNGE0ZC1hYjU1LWZiMTdkNzc4NzRjMSJ9.eyJwYXJ0aWNpcGFudElkIjoiZGFhYzQ3YjEtMDZhNS00ZjA0LThjYmEtNDg1Y2VhZDdhYzYxIiwiaWF0IjoxNjc0NTcyODg1fQ.LOyItIhYtKHvhlGNmGFoE6diMH-dODckBVI0OraLB6A" - }, - "guest_url": { - "href": "https://meetings.vonage.com/254629696" - } - }, - "created_at": "2023-01-24T03:16:46.521Z", - "is_available": true, - "expire_after_use": false, - "theme_id": null, - "initial_join_options": { - "microphone_state": "default" - }, - "join_approval_level": "none", - "ui_settings": { - "language": "default" - }, - "available_features": { - "is_recording_available": true, - "is_chat_available": true, - "is_whiteboard_available": true, - "is_locale_switcher_available": false - } - }, - { - "id": "b3142c46-d1c1-4405-baa6-85683827ed69", - "display_name": "my_test_room", - "metadata": null, - "type": "instant", - "expires_at": "2023-01-24T03:30:38.629Z", - "recording_options": { - "auto_record": false, - "record_only_owner": false - }, - "meeting_code": "412958792", - "_links": { - "host_url": { - "href": "https://meetings.vonage.com/?room_token=412958792&participant_token=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCIsImtpZCI6IjU5N2NmYTAzLTY3NTQtNGE0ZC1hYjU1LWZiMTdkNzc4NzRjMSJ9.eyJwYXJ0aWNpcGFudElkIjoiM2ExNWFkZmYtNDFmYy00NWFjLTg3Y2QtZmM2YjYyYjAwMTczIiwiaWF0IjoxNjc0NTcyODg1fQ.hCAmGR3dxnV7LkSyCXYyUXlXYr-LBfAANMjipm6PumM" - }, - "guest_url": { - "href": "https://meetings.vonage.com/412958792" - } - }, - "created_at": "2023-01-24T03:20:38.629Z", - "is_available": true, - "expire_after_use": false, - "theme_id": null, - "initial_join_options": { - "microphone_state": "default" - }, - "join_approval_level": "none", - "ui_settings": { - "language": "default" - }, - "available_features": { - "is_recording_available": true, - "is_chat_available": true, - "is_whiteboard_available": true, - "is_locale_switcher_available": false - } - } - ], - "_links": { - "first": { - "href": "api-eu.vonage.com/meetings/rooms?page_size=20" - }, - "self": { - "href": "api-eu.vonage.com/meetings/rooms?page_size=20&start_id=2006648" - }, - "prev": { - "href": "api-eu.vonage.com/meetings/rooms?page_size=20&end_id=2006647" - }, - "next": { - "href": "api-eu.vonage.com/meetings/rooms?page_size=20&start_id=2006655" - } - }, - "total_items": 5 -} \ No newline at end of file diff --git a/tests/data/number_insight/advanced_get.json b/tests/data/number_insight/advanced_get.json deleted file mode 100644 index 7e85396c..00000000 --- a/tests/data/number_insight/advanced_get.json +++ /dev/null @@ -1,47 +0,0 @@ -{ - "status": 0, - "status_message": "Success", - "request_id": "aaaaaaaa-bbbb-cccc-dddd-0123456789ab", - "international_format_number": "447700900000", - "national_format_number": "07700 900000", - "country_code": "GB", - "country_code_iso3": "GBR", - "country_name": "United Kingdom", - "country_prefix": "44", - "request_price": "0.04000000", - "refund_price": "0.01500000", - "remaining_balance": "1.23456789", - "current_carrier": { - "network_code": "12345", - "name": "Acme Inc", - "country": "GB", - "network_type": "mobile" - }, - "original_carrier": { - "network_code": "12345", - "name": "Acme Inc", - "country": "GB", - "network_type": "mobile" - }, - "ported": "not_ported", - "roaming": { - "status": "roaming", - "roaming_country_code": "US", - "roaming_network_code": "12345", - "roaming_network_name": "Acme Inc" - }, - "caller_identity": { - "caller_type": "consumer", - "caller_name": "John Smith", - "first_name": "John", - "last_name": "Smith" - }, - "lookup_outcome": 0, - "lookup_outcome_message": "Success", - "valid_number": "valid", - "reachable": "reachable", - "real_time_data": { - "active_status": "true", - "handset_status": "On" - } -} \ No newline at end of file diff --git a/tests/data/number_insight/basic_get.json b/tests/data/number_insight/basic_get.json deleted file mode 100644 index 1a3a3e2b..00000000 --- a/tests/data/number_insight/basic_get.json +++ /dev/null @@ -1,11 +0,0 @@ -{ - "status": 0, - "status_message": "Success", - "request_id": "aaaaaaaa-bbbb-cccc-dddd-0123456789ab", - "international_format_number": "447700900000", - "national_format_number": "07700 900000", - "country_code": "GB", - "country_code_iso3": "GBR", - "country_name": "United Kingdom", - "country_prefix": "44" -} \ No newline at end of file diff --git a/tests/data/number_insight/get_async_error.json b/tests/data/number_insight/get_async_error.json deleted file mode 100644 index 23f9ae77..00000000 --- a/tests/data/number_insight/get_async_error.json +++ /dev/null @@ -1,4 +0,0 @@ -{ - "status": 3, - "error_text": "Invalid request :: Not valid number format detected ['1234']" -} \ No newline at end of file diff --git a/tests/data/number_insight/get_error.json b/tests/data/number_insight/get_error.json deleted file mode 100644 index 6fa5e0f1..00000000 --- a/tests/data/number_insight/get_error.json +++ /dev/null @@ -1,4 +0,0 @@ -{ - "status": 3, - "status_message": "Invalid request :: Not valid number format detected [ 1234 ]" -} \ No newline at end of file diff --git a/tests/data/number_insight/standard_get.json b/tests/data/number_insight/standard_get.json deleted file mode 100644 index 3c110391..00000000 --- a/tests/data/number_insight/standard_get.json +++ /dev/null @@ -1,37 +0,0 @@ -{ - "status": 0, - "status_message": "Success", - "request_id": "aaaaaaaa-bbbb-cccc-dddd-0123456789ab", - "international_format_number": "447700900000", - "national_format_number": "07700 900000", - "country_code": "GB", - "country_code_iso3": "GBR", - "country_name": "United Kingdom", - "country_prefix": "44", - "request_price": "0.04000000", - "refund_price": "0.01500000", - "remaining_balance": "1.23456789", - "current_carrier": { - "network_code": "12345", - "name": "Acme Inc", - "country": "GB", - "network_type": "mobile" - }, - "original_carrier": { - "network_code": "12345", - "name": "Acme Inc", - "country": "GB", - "network_type": "mobile" - }, - "ported": "not_ported", - "caller_identity": { - "caller_type": "consumer", - "caller_name": "John Smith", - "first_name": "John", - "last_name": "Smith" - }, - "caller_name": "John Smith", - "last_name": "Smith", - "first_name": "John", - "caller_type": "consumer" -} \ No newline at end of file diff --git a/tests/data/rest_calls/patch.json b/tests/data/rest_calls/patch.json deleted file mode 100644 index 7bed4dc3..00000000 --- a/tests/data/rest_calls/patch.json +++ /dev/null @@ -1,4 +0,0 @@ -{ - "patch": "test_case", - "successful": true -} \ No newline at end of file diff --git a/tests/data/sms/long_message.txt b/tests/data/sms/long_message.txt deleted file mode 100644 index a2369c2d..00000000 --- a/tests/data/sms/long_message.txt +++ /dev/null @@ -1 +0,0 @@ -Lorem ipsum dolor sit amet, consectetur adipiscing elit. Curabitur efficitur tortor a est pretium scelerisque et nec tortor. Aliquam at rutrum dui. Proin iaculis urna sit amet volutpat sollicitudin. \ No newline at end of file diff --git a/tests/data/sms/send_long_message.json b/tests/data/sms/send_long_message.json deleted file mode 100644 index 28e88771..00000000 --- a/tests/data/sms/send_long_message.json +++ /dev/null @@ -1,21 +0,0 @@ -{ - "messages": [ - { - "to": "447525856424", - "message-id": "b751970b-a923-45ce-b690-d590fc897a9d", - "status": "0", - "remaining-balance": "64.89226001", - "message-price": "0.04120000", - "network": "23420" - }, - { - "to": "447525856424", - "message-id": "28304cb8-15b8-45e6-83b2-805c05364e1e", - "status": "0", - "remaining-balance": "64.89226001", - "message-price": "0.04120000", - "network": "23420" - } - ], - "message-count": "2" - } \ No newline at end of file diff --git a/tests/data/sms/send_long_message_partial_error.json b/tests/data/sms/send_long_message_partial_error.json deleted file mode 100644 index cd546b94..00000000 --- a/tests/data/sms/send_long_message_partial_error.json +++ /dev/null @@ -1,17 +0,0 @@ -{ - "messages": [ - { - "to": "447525856424", - "message-id": "b751970b-a923-45ce-b690-d590fc897a9d", - "status": "0", - "remaining-balance": "64.89226001", - "message-price": "0.04120000", - "network": "23420" - }, - { - "status": "5", - "error-text": "An internal error has occurred in the platform whilst processing this message" - } - ], - "message-count": "2" - } \ No newline at end of file diff --git a/tests/data/sms/send_message.json b/tests/data/sms/send_message.json deleted file mode 100644 index 5758a5cf..00000000 --- a/tests/data/sms/send_message.json +++ /dev/null @@ -1,15 +0,0 @@ -{ - "message-count": "1", - "messages": [ - { - "to": "447700900000", - "message-id": "0A0000000123ABCD1", - "status": "0", - "remaining-balance": "3.14159265", - "message-price": "0.03330000", - "network": "12345", - "client-ref": "my-personal-reference", - "account-ref": "customer1234" - } - ] - } \ No newline at end of file diff --git a/tests/data/sms/send_message_200_error.json b/tests/data/sms/send_message_200_error.json deleted file mode 100644 index a47803b5..00000000 --- a/tests/data/sms/send_message_200_error.json +++ /dev/null @@ -1,9 +0,0 @@ -{ - "message-count": "1", - "messages": [ - { - "status": "2", - "error-text": "Missing to param" - } - ] -} \ No newline at end of file diff --git a/tests/data/verify/cancel_verification.json b/tests/data/verify/cancel_verification.json deleted file mode 100644 index 8bfcf7bf..00000000 --- a/tests/data/verify/cancel_verification.json +++ /dev/null @@ -1,4 +0,0 @@ -{ - "status": "0", - "command": "cancel" -} \ No newline at end of file diff --git a/tests/data/verify/check_verification.json b/tests/data/verify/check_verification.json deleted file mode 100644 index f95e5d52..00000000 --- a/tests/data/verify/check_verification.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "request_id": "abcdef0123456789abcdef0123456789", - "event_id": "0A00000012345678", - "status": "0", - "price": "0.10000000", - "currency": "EUR", - "estimated_price_messages_sent": "0.03330000" -} \ No newline at end of file diff --git a/tests/data/verify/check_verification_error.json b/tests/data/verify/check_verification_error.json deleted file mode 100644 index e1b435d3..00000000 --- a/tests/data/verify/check_verification_error.json +++ /dev/null @@ -1,5 +0,0 @@ -{ - "request_id": "abcdef0123456789abcdef0123456789", - "status": "16", - "error_text": "The code inserted does not match the expected value" -} \ No newline at end of file diff --git a/tests/data/verify/control_verification_error.json b/tests/data/verify/control_verification_error.json deleted file mode 100644 index 9496588b..00000000 --- a/tests/data/verify/control_verification_error.json +++ /dev/null @@ -1,4 +0,0 @@ -{ - "status": "6", - "error_text": "The requestId 'asdf' does not exist or its no longer active." -} \ No newline at end of file diff --git a/tests/data/verify/search_verification.json b/tests/data/verify/search_verification.json deleted file mode 100644 index a7badbf4..00000000 --- a/tests/data/verify/search_verification.json +++ /dev/null @@ -1,28 +0,0 @@ -{ - "request_id": "xxx", - "account_id": "abcdef01", - "status": "IN PROGRESS", - "number": "447700900000", - "price": "0.10000000", - "currency": "EUR", - "sender_id": "mySenderId", - "date_submitted": "2020-01-01 12:00:00", - "date_finalized": "2020-01-01 12:00:00", - "first_event_date": "2020-01-01 12:00:00", - "last_event_date": "2020-01-01 12:00:00", - "checks": [ - { - "date_received": "2020-01-01 12:00:00", - "code": "987654", - "status": "abc123", - "ip_address": "123.0.0.255" - } - ], - "events": [ - { - "type": "abc123", - "id": "abc123" - } - ], - "estimated_price_messages_sent": "0.03330000" -} \ No newline at end of file diff --git a/tests/data/verify/search_verification_200_error.json b/tests/data/verify/search_verification_200_error.json deleted file mode 100644 index fc716972..00000000 --- a/tests/data/verify/search_verification_200_error.json +++ /dev/null @@ -1,5 +0,0 @@ -{ - "request_id": "xxx", - "status": "IN PROGRESS", - "error_text": "No response found" -} \ No newline at end of file diff --git a/tests/data/verify/search_verification_multiple.json b/tests/data/verify/search_verification_multiple.json deleted file mode 100644 index 73030f37..00000000 --- a/tests/data/verify/search_verification_multiple.json +++ /dev/null @@ -1,58 +0,0 @@ -[ - { - "request_id": "xxx", - "account_id": "abcdef01", - "status": "IN PROGRESS", - "number": "447700900000", - "price": "0.10000000", - "currency": "EUR", - "sender_id": "mySenderId", - "date_submitted": "2020-01-01 12:00:00", - "date_finalized": "2020-01-01 12:00:00", - "first_event_date": "2020-01-01 12:00:00", - "last_event_date": "2020-01-01 12:00:00", - "checks": [ - { - "date_received": "2020-01-01 12:00:00", - "code": "987654", - "status": "abc123", - "ip_address": "123.0.0.255" - } - ], - "events": [ - { - "type": "abc123", - "id": "abc123" - } - ], - "estimated_price_messages_sent": "0.03330000" - }, - { - "request_id": "yyy", - "account_id": "abcdef01", - "status": "IN PROGRESS", - "number": "447700900000", - "price": "0.10000000", - "currency": "EUR", - "sender_id": "mySenderId", - "date_submitted": "2020-01-01 12:00:00", - "date_finalized": "2020-01-01 12:00:00", - "first_event_date": "2020-01-01 12:00:00", - "last_event_date": "2020-01-01 12:00:00", - "checks": [ - { - "date_received": "2020-01-01 12:00:00", - "code": "987654", - "status": "abc123", - "ip_address": "123.0.0.255" - } - ], - "events": [ - { - "type": "abc123", - "id": "abc123" - } - ], - "estimated_price_messages_sent": "0.03330000" - } -] \ No newline at end of file diff --git a/tests/data/verify/start_verification.json b/tests/data/verify/start_verification.json deleted file mode 100644 index 74136a5b..00000000 --- a/tests/data/verify/start_verification.json +++ /dev/null @@ -1,4 +0,0 @@ -{ - "request_id": "abcdef0123456789abcdef0123456789", - "status": "0" -} \ No newline at end of file diff --git a/tests/data/verify/start_verification_error.json b/tests/data/verify/start_verification_error.json deleted file mode 100644 index 39371f48..00000000 --- a/tests/data/verify/start_verification_error.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "request_id": "", - "status": "2", - "error_text": "Your request is incomplete and missing the mandatory parameter `number`", - "network": "244523" -} \ No newline at end of file diff --git a/tests/data/verify/trigger_next_event.json b/tests/data/verify/trigger_next_event.json deleted file mode 100644 index 7939ad17..00000000 --- a/tests/data/verify/trigger_next_event.json +++ /dev/null @@ -1,4 +0,0 @@ -{ - "status": "0", - "command": "trigger_next_event" -} \ No newline at end of file diff --git a/tests/data/video/broadcast.json b/tests/data/video/broadcast.json deleted file mode 100644 index 25122cf5..00000000 --- a/tests/data/video/broadcast.json +++ /dev/null @@ -1,39 +0,0 @@ -{ - "id": "1748b7070a81464c9759c46ad10d3734", - "sessionId": "2_MX4xMDBfjE0Mzc2NzY1NDgwMTJ-TjMzfn4", - "multiBroadcastTag": "broadcast_tag_provided", - "applicationId": "abc123", - "createdAt": 1437676551000, - "updatedAt": 1437676551000, - "maxDuration": 5400, - "maxBitrate": 2000000, - "broadcastUrls": { - "hls": "hlsurl", - "rtmp": [ - { - "id": "abc123", - "status": "abc123", - "serverUrl": "abc123", - "streamName": "abc123" - } - ] - }, - "settings": { - "hls": { - "lowLatency": false, - "dvr": false - } - }, - "resolution": "640x480", - "hasAudio": true, - "hasVideo": true, - "streamMode": "auto", - "status": "started", - "streams": [ - { - "streamId": "70a81464c9759c46ad10d3734", - "hasAudio": true, - "hasVideo": true - } - ] -} \ No newline at end of file diff --git a/tests/data/video/create_archive.json b/tests/data/video/create_archive.json deleted file mode 100644 index 725c8eb3..00000000 --- a/tests/data/video/create_archive.json +++ /dev/null @@ -1,17 +0,0 @@ -{ - "createdAt" : 1384221730555, - "duration" : 0, - "hasAudio" : true, - "hasVideo" : true, - "id" : "b40ef09b-3811-4726-b508-e41a0f96c68f", - "name" : "my_new_archive", - "outputMode" : "composed", - "projectId" : 234567, - "reason" : "", - "resolution" : "640x480", - "sessionId" : "my_session_id", - "size" : 0, - "status" : "started", - "streamMode" : "auto", - "url" : null -} \ No newline at end of file diff --git a/tests/data/video/create_session.json b/tests/data/video/create_session.json deleted file mode 100644 index 7c6f4b35..00000000 --- a/tests/data/video/create_session.json +++ /dev/null @@ -1,19 +0,0 @@ -[ - { - "session_id": "my_session_id", - "project_id": "29f760f8-7ce1-46c9-ade3-f2dedee4ed5f", - "partner_id": "29f760f8-7ce1-46c9-ade3-f2dedee4ed5f", - "create_dt": "Tue Aug 09 09:10:17 PDT 2022", - "session_status": null, - "status_invalid": null, - "media_server_hostname": null, - "messaging_server_url": null, - "messaging_url": null, - "symphony_address": null, - "properties": null, - "ice_server": null, - "session_segment_id": "b8c32a6d-faf9-4ec4-a648-a6d382cd650b", - "ice_servers": null, - "ice_credential_expiration": 86100 - } -] diff --git a/tests/data/video/create_sip_call.json b/tests/data/video/create_sip_call.json deleted file mode 100644 index 29cbbab6..00000000 --- a/tests/data/video/create_sip_call.json +++ /dev/null @@ -1,5 +0,0 @@ -{ - "id": "b0a5a8c7-dc38-459f-a48d-a7f2008da853", - "connectionId": "e9f8c166-6c67-440d-994a-04fb6dfed007", - "streamId": "482bce73-f882-40fd-8ca5-cb74ff416036" -} \ No newline at end of file diff --git a/tests/data/video/disable_mute_multiple_streams.json b/tests/data/video/disable_mute_multiple_streams.json deleted file mode 100644 index 878f6eaa..00000000 --- a/tests/data/video/disable_mute_multiple_streams.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "applicationId": "78d335fa-323d-0114-9c3d-d6f0d48968cf", - "status": "ACTIVE", - "name": "Joe Montana", - "environment": "standard", - "createdAt": 1414642898000 -} \ No newline at end of file diff --git a/tests/data/video/get_archive.json b/tests/data/video/get_archive.json deleted file mode 100644 index be0ece31..00000000 --- a/tests/data/video/get_archive.json +++ /dev/null @@ -1,18 +0,0 @@ -{ - "createdAt" : 1384221730000, - "duration" : 5049, - "hasAudio" : true, - "hasVideo" : true, - "id" : "b40ef09b-3811-4726-b508-e41a0f96c68f", - "name" : "Foo", - "outputMode" : "composed", - "projectId" : 123456, - "reason" : "", - "resolution" : "640x480", - "sessionId" : "2_MX40NzIwMzJ-flR1ZSBPY3QgMjkgMTI6MTM6MjMgUERUIDIwMTN-MC45NDQ2MzE2NH4", - "size" : 247748791, - "status" : "available", - "streamMode" : "auto", - "streams" : [], - "url" : "https://tokbox.com.archive2.s3.amazonaws.com/123456/09141e29-8770-439b-b180-337d7e637545/archive.mp4" -} \ No newline at end of file diff --git a/tests/data/video/get_stream.json b/tests/data/video/get_stream.json deleted file mode 100644 index 5e8fb98d..00000000 --- a/tests/data/video/get_stream.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "id": "8b732909-0a06-46a2-8ea8-074e64d43422", - "videoType": "camera", - "name": "", - "layoutClassList": [ - "full" - ] -} \ No newline at end of file diff --git a/tests/data/video/list_archives.json b/tests/data/video/list_archives.json deleted file mode 100644 index 140d59c9..00000000 --- a/tests/data/video/list_archives.json +++ /dev/null @@ -1,28 +0,0 @@ -{ - "count": 1, - "items": [ - { - "createdAt": 1384221730000, - "duration": 5049, - "hasAudio": true, - "hasVideo": true, - "id": "b40ef09b-3811-4726-b508-e41a0f96c68f", - "name": "Foo", - "applicationId": "78d335fa-323d-0114-9c3d-d6f0d48968cf", - "reason": "", - "resolution": "abc123", - "sessionId": "my_session_id", - "size": 247748791, - "status": "available", - "streamMode": "manual", - "streams": [ - { - "streamId": "abc123", - "hasAudio": true, - "hasVideo": true - } - ], - "url": "https://tokbox.com.archive2.s3.amazonaws.com/123456/09141e29-8770-439b-b180-337d7e637545/archive.mp4" - } - ] -} \ No newline at end of file diff --git a/tests/data/video/list_broadcasts.json b/tests/data/video/list_broadcasts.json deleted file mode 100644 index 2d82a315..00000000 --- a/tests/data/video/list_broadcasts.json +++ /dev/null @@ -1,44 +0,0 @@ -{ - "count": "1", - "items": [ - { - "id": "1748b7070a81464c9759c46ad10d3734", - "sessionId": "2_MX4xMDBfjE0Mzc2NzY1NDgwMTJ-TjMzfn4", - "multiBroadcastTag": "broadcast_tag_provided", - "applicationId": "abc123", - "createdAt": 1437676551000, - "updatedAt": 1437676551000, - "maxDuration": 5400, - "maxBitrate": 2000000, - "broadcastUrls": { - "hls": "hlsurl", - "rtmp": [ - { - "id": "abc123", - "status": "abc123", - "serverUrl": "abc123", - "streamName": "abc123" - } - ] - }, - "settings": { - "hls": { - "lowLatency": false, - "dvr": false - } - }, - "resolution": "abc123", - "hasAudio": false, - "hasVideo": false, - "streamMode": "manual", - "status": "abc123", - "streams": [ - { - "streamId": "abc123", - "hasAudio": "abc123", - "hasVideo": "abc123" - } - ] - } - ] -} \ No newline at end of file diff --git a/tests/data/video/list_streams.json b/tests/data/video/list_streams.json deleted file mode 100644 index fe50c8d0..00000000 --- a/tests/data/video/list_streams.json +++ /dev/null @@ -1,13 +0,0 @@ -{ - "count": 1, - "items": [ - { - "id": "8b732909-0a06-46a2-8ea8-074e64d43422", - "videoType": "camera", - "name": "", - "layoutClassList": [ - "full" - ] - } - ] - } \ No newline at end of file diff --git a/tests/data/video/mute_multiple_streams.json b/tests/data/video/mute_multiple_streams.json deleted file mode 100644 index 878f6eaa..00000000 --- a/tests/data/video/mute_multiple_streams.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "applicationId": "78d335fa-323d-0114-9c3d-d6f0d48968cf", - "status": "ACTIVE", - "name": "Joe Montana", - "environment": "standard", - "createdAt": 1414642898000 -} \ No newline at end of file diff --git a/tests/data/video/mute_specific_stream.json b/tests/data/video/mute_specific_stream.json deleted file mode 100644 index 878f6eaa..00000000 --- a/tests/data/video/mute_specific_stream.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "applicationId": "78d335fa-323d-0114-9c3d-d6f0d48968cf", - "status": "ACTIVE", - "name": "Joe Montana", - "environment": "standard", - "createdAt": 1414642898000 -} \ No newline at end of file diff --git a/tests/data/video/null.json b/tests/data/video/null.json deleted file mode 100644 index ec747fa4..00000000 --- a/tests/data/video/null.json +++ /dev/null @@ -1 +0,0 @@ -null \ No newline at end of file diff --git a/tests/data/video/play_dtmf_invalid_error.json b/tests/data/video/play_dtmf_invalid_error.json deleted file mode 100644 index b783100c..00000000 --- a/tests/data/video/play_dtmf_invalid_error.json +++ /dev/null @@ -1,4 +0,0 @@ -{ - "code": 400, - "message": "One of the properties digits or sessionId is invalid." -} \ No newline at end of file diff --git a/tests/data/video/stop_archive.json b/tests/data/video/stop_archive.json deleted file mode 100644 index 630b1d8b..00000000 --- a/tests/data/video/stop_archive.json +++ /dev/null @@ -1,15 +0,0 @@ -{ - "createdAt" : 1384221730555, - "duration" : 60, - "hasAudio" : true, - "hasVideo" : true, - "id" : "b40ef09b-3811-4726-b508-e41a0f96c68f", - "name" : "my_new_archive", - "projectId" : 234567, - "reason" : "", - "resolution" : "640x480", - "sessionId" : "flR1ZSBPY3QgMjkgMTI6MTM6MjMgUERUIDIwMTN", - "size" : 0, - "status" : "stopped", - "url" : null -} \ No newline at end of file diff --git a/tests/test_account.py b/tests/test_account.py deleted file mode 100644 index ccc85458..00000000 --- a/tests/test_account.py +++ /dev/null @@ -1,193 +0,0 @@ -import platform - -from util import * - -import vonage -from vonage.errors import PricingTypeError - - -@responses.activate -def test_get_balance(account, dummy_data): - stub(responses.GET, "https://rest.nexmo.com/account/get-balance") - - assert isinstance(account.get_balance(), dict) - assert request_user_agent() == dummy_data.user_agent - - -@responses.activate -def test_application_info_options(dummy_data): - app_name, app_version = "ExampleApp", "X.Y.Z" - - stub(responses.GET, "https://rest.nexmo.com/account/get-balance") - - client = vonage.Client( - key=dummy_data.api_key, - secret=dummy_data.api_secret, - app_name=app_name, - app_version=app_version, - ) - user_agent = f"vonage-python/{vonage.__version__} python/{platform.python_version()} {app_name}/{app_version}" - - account = client.account - assert isinstance(account.get_balance(), dict) - assert request_user_agent() == user_agent - - -@responses.activate -def test_get_country_pricing(account, dummy_data): - stub(responses.GET, "https://rest.nexmo.com/account/get-pricing/outbound/sms") - - assert isinstance(account.get_country_pricing("GB"), dict) - assert request_user_agent() == dummy_data.user_agent - assert "country=GB" in request_query() - - -@responses.activate -def test_get_all_countries_pricing(account, dummy_data): - stub(responses.GET, "https://rest.nexmo.com/account/get-full-pricing/outbound/sms") - - assert isinstance(account.get_all_countries_pricing(), dict) - assert request_user_agent() == dummy_data.user_agent - - -@responses.activate -def test_get_prefix_pricing(account, dummy_data): - stub(responses.GET, "https://rest.nexmo.com/account/get-prefix-pricing/outbound/sms") - - assert isinstance(account.get_prefix_pricing(44), dict) - assert request_user_agent() == dummy_data.user_agent - assert "prefix=44" in request_query() - - -def test_invalid_pricing_type_throws_error(account): - with pytest.raises(PricingTypeError): - account.get_country_pricing('GB', 'not_a_valid_pricing_type') - - -@responses.activate -def test_update_default_sms_webhook(account, dummy_data): - stub(responses.POST, "https://rest.nexmo.com/account/settings") - - params = {"moCallBackUrl": "http://example.com/callback"} - - assert isinstance(account.update_default_sms_webhook(params), dict) - assert request_user_agent() == dummy_data.user_agent - assert "moCallBackUrl=http%3A%2F%2Fexample.com%2Fcallback" in request_body() - - -@responses.activate -def test_topup(account, dummy_data): - stub(responses.POST, "https://rest.nexmo.com/account/top-up") - - params = {"trx": "00X123456Y7890123Z"} - - assert isinstance(account.topup(params), dict) - assert request_user_agent() == dummy_data.user_agent - assert "trx=00X123456Y7890123Z" in request_body() - - -@responses.activate -def test_list_secrets(account): - stub( - responses.GET, - "https://api.nexmo.com/accounts/myaccountid/secrets", - fixture_path="account/secret_management/list.json", - ) - - secrets = account.list_secrets("myaccountid") - assert_basic_auth() - assert secrets["_embedded"]["secrets"][0]["id"] == "ad6dc56f-07b5-46e1-a527-85530e625800" - - -@responses.activate -def test_list_secrets_missing(account): - stub( - responses.GET, - "https://api.nexmo.com/accounts/myaccountid/secrets", - status_code=404, - fixture_path="account/secret_management/missing.json", - ) - - with pytest.raises(vonage.ClientError) as ce: - account.list_secrets("myaccountid") - assert_basic_auth() - print(ce) - assert 'Invalid API Key' in str(ce.value) - - -@responses.activate -def test_get_secret(account): - stub( - responses.GET, - "https://api.nexmo.com/accounts/meaccountid/secrets/mahsecret", - fixture_path="account/secret_management/get.json", - ) - - secret = account.get_secret("meaccountid", "mahsecret") - assert_basic_auth() - assert secret["id"] == "ad6dc56f-07b5-46e1-a527-85530e625800" - - -@responses.activate -def test_create_secret(account): - stub( - responses.POST, - "https://api.nexmo.com/accounts/meaccountid/secrets", - fixture_path="account/secret_management/create.json", - ) - - secret = account.create_secret("meaccountid", "mahsecret") - assert_basic_auth() - assert secret["id"] == "ad6dc56f-07b5-46e1-a527-85530e625800" - - -@responses.activate -def test_create_secret_max_secrets(account): - stub( - responses.POST, - "https://api.nexmo.com/accounts/meaccountid/secrets", - status_code=403, - fixture_path="account/secret_management/max-secrets.json", - ) - - with pytest.raises(vonage.ClientError) as ce: - account.create_secret("meaccountid", "mahsecret") - assert_basic_auth() - assert 'Maxmimum number of secrets already met' in str(ce.value) - - -@responses.activate -def test_create_secret_validation(account): - stub( - responses.POST, - "https://api.nexmo.com/accounts/meaccountid/secrets", - status_code=400, - fixture_path="account/secret_management/create-validation.json", - ) - - with pytest.raises(vonage.ClientError) as ce: - account.create_secret("meaccountid", "mahsecret") - assert_basic_auth() - assert 'The request failed due to validation errors' in str(ce.value) - - -@responses.activate -def test_delete_secret(account): - stub(responses.DELETE, "https://api.nexmo.com/accounts/meaccountid/secrets/mahsecret") - - account.revoke_secret("meaccountid", "mahsecret") - assert_basic_auth() - - -@responses.activate -def test_delete_secret_last_secret(account): - stub( - responses.DELETE, - "https://api.nexmo.com/accounts/meaccountid/secrets/mahsecret", - status_code=403, - fixture_path="account/secret_management/last-secret.json", - ) - with pytest.raises(vonage.ClientError) as ce: - account.revoke_secret("meaccountid", "mahsecret") - assert_basic_auth() - assert 'Secret Deletion Forbidden' in str(ce.value) diff --git a/tests/test_application.py b/tests/test_application.py deleted file mode 100644 index 66a7b373..00000000 --- a/tests/test_application.py +++ /dev/null @@ -1,84 +0,0 @@ -import json -from util import * - - -@responses.activate -def test_list_applications(client, dummy_data): - stub( - responses.GET, - "https://api.nexmo.com/v2/applications", - fixture_path="application/list_applications.json", - ) - - apps = client.application.list_applications() - assert_basic_auth() - assert isinstance(apps, dict) - assert apps["total_items"] == 30 - assert request_user_agent() == dummy_data.user_agent - - -@responses.activate -def test_get_application(client, dummy_data): - stub( - responses.GET, - "https://api.nexmo.com/v2/applications/xx-xx-xx-xx", - fixture_path="application/get_application.json", - ) - - app = client.application.get_application("xx-xx-xx-xx") - assert_basic_auth() - assert isinstance(app, dict) - assert app["name"] == "My Test Application" - assert request_user_agent() == dummy_data.user_agent - - -@responses.activate -def test_create_application(client, dummy_data): - stub( - responses.POST, - "https://api.nexmo.com/v2/applications", - fixture_path="application/create_application.json", - ) - - params = {"name": "Example App", "type": "voice"} - - app = client.application.create_application(params) - assert_basic_auth() - assert isinstance(app, dict) - assert app["name"] == "My Test Application" - assert request_user_agent() == dummy_data.user_agent - body_data = json.loads(request_body().decode("utf-8")) - assert body_data["type"] == "voice" - - -@responses.activate -def test_update_application(client, dummy_data): - stub( - responses.PUT, - "https://api.nexmo.com/v2/applications/xx-xx-xx-xx", - fixture_path="application/update_application.json", - ) - - params = {"answer_url": "https://example.com/ncco"} - - app = client.application.update_application("xx-xx-xx-xx", params) - assert_basic_auth() - assert isinstance(app, dict) - assert request_user_agent() == dummy_data.user_agent - assert request_content_type() == "application/json" - assert b'"answer_url": "https://example.com/ncco"' in request_body() - - assert app["name"] == "A Better Name" - - -@responses.activate -def test_delete_application(client, dummy_data): - responses.add( - responses.DELETE, - "https://api.nexmo.com/v2/applications/xx-xx-xx-xx", - status=204, - ) - - assert client.application.delete_application("xx-xx-xx-xx") is None - assert_basic_auth() - assert request_user_agent() == dummy_data.user_agent diff --git a/tests/test_client.py b/tests/test_client.py deleted file mode 100644 index 6ce08823..00000000 --- a/tests/test_client.py +++ /dev/null @@ -1,42 +0,0 @@ -import vonage -from util import * -from vonage.errors import InvalidAuthenticationTypeError - - -def test_client_doesnt_require_api_key(dummy_data): - client = vonage.Client(application_id="myid", private_key=dummy_data.private_key) - assert client is not None - assert client.api_key is None - assert client.api_secret is None - - -@responses.activate -def test_client_can_make_application_requests_without_api_key(dummy_data): - stub(responses.POST, "https://api.nexmo.com/v1/calls") - - client = vonage.Client(application_id="myid", private_key=dummy_data.private_key) - voice = vonage.Voice(client) - voice.create_call("123455") - - -def test_invalid_auth_type_raises_error(client): - with pytest.raises(InvalidAuthenticationTypeError): - client.get(client.host(), 'my/request/uri', auth_type='magic') - - -@responses.activate -def test_timeout_is_set_on_client_calls(dummy_data): - stub(responses.POST, "https://api.nexmo.com/v1/calls") - - client = vonage.Client(application_id="myid", private_key=dummy_data.private_key, timeout=1) - voice = vonage.Voice(client) - voice.create_call("123455") - - assert len(responses.calls) == 1 - assert responses.calls[0].request.req_kwargs["timeout"] == 1 - - -def test_setting_video_api_host(client): - assert client._video_host == 'video.api.vonage.com' - client.video_host('new.video.url') - assert client._video_host == 'new.video.url' diff --git a/tests/test_jwt.py b/tests/test_jwt.py deleted file mode 100644 index 4533bbb6..00000000 --- a/tests/test_jwt.py +++ /dev/null @@ -1,54 +0,0 @@ -from time import time -from unittest.mock import patch -from pytest import raises - -from vonage import Client, VonageError - -now = int(time()) - - -def test_auth_sets_claims_from_kwargs(client): - client.auth(jti='asdfzxcv1234', nbf=now + 100, exp=now + 1000) - assert client._jwt_claims['jti'] == 'asdfzxcv1234' - assert client._jwt_claims['nbf'] == now + 100 - assert client._jwt_claims['exp'] == now + 1000 - - -def test_auth_sets_claims_from_dict(client): - custom_jwt_claims = {'jti': 'asdfzxcv1234', 'nbf': now + 100, 'exp': now + 1000} - client.auth(custom_jwt_claims) - assert client._jwt_claims['jti'] == 'asdfzxcv1234' - assert client._jwt_claims['nbf'] == now + 100 - assert client._jwt_claims['exp'] == now + 1000 - - -test_jwt = b'eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJhcHBsaWNhdGlvbl9pZCI6ImFzZGYxMjM0IiwiaWF0IjoxNjg1NzMxMzkxLCJqdGkiOiIwYzE1MDJhZS05YmI5LTQ4YzQtYmQyZC0yOGFhNWUxYjZkMTkiLCJleHAiOjE2ODU3MzIyOTF9.mAkGeVgWOb7Mrzka7DSj32vSM8RaFpYse_2E7jCQ4DuH8i32wq9FxXGgfwdBQDHzgku3RYIjLM1xlVrGjNM3MsnZgR7ymQ6S4bdTTOmSK0dKbk91SrN7ZAC9k2a6JpCC2ZYgXpZ5BzpDTdy9BYu6msHKmkL79_aabFAhrH36Nk26pLvoI0-KiGImEex-aRR4iiaXhOebXBeqiQTRPKoKizREq4-8zBQv_j6yy4AiEYvBatQ8L_sjHsLj9jjITreX8WRvEW-G4TPpPLMaHACHTDMpJSOZAnegAkzTV2frVRmk6DyVXnemm4L0RQD1XZDaH7JPsKk24Hd2WZQyIgHOqQ' - - -def vonage_jwt_mock(self, claims): - return test_jwt - - -def test_generate_application_jwt(client): - with patch('vonage.client.JwtClient.generate_application_jwt', vonage_jwt_mock): - jwt = client.generate_application_jwt() - assert jwt == test_jwt - - -def test_create_jwt_auth_string(client): - headers = client.headers - with patch('vonage.client.JwtClient.generate_application_jwt', vonage_jwt_mock): - headers['Authorization'] = client._create_jwt_auth_string() - assert headers['Accept'] == 'application/json' - assert headers['Authorization'] == b'Bearer ' + test_jwt - - -def test_create_jwt_error_no_application_id_or_private_key(): - empty_client = Client() - - with raises(VonageError) as err: - empty_client.generate_application_jwt() - assert ( - str(err.value) - == 'JWT generation failed. Check that you passed in valid values for "application_id" and "private_key".' - ) diff --git a/tests/test_meetings.py b/tests/test_meetings.py deleted file mode 100644 index f2a3ce6a..00000000 --- a/tests/test_meetings.py +++ /dev/null @@ -1,748 +0,0 @@ -from util import * -from vonage.errors import MeetingsError, ClientError, AuthenticationError - -import responses -import json -from pytest import raises - - -@responses.activate -def test_create_instant_room(meetings, dummy_data): - stub( - responses.POST, - "https://api-eu.vonage.com/v1/meetings/rooms", - fixture_path='meetings/meeting_room.json', - ) - - params = {'display_name': 'my_test_room'} - meeting = meetings.create_room(params) - - assert isinstance(meeting, dict) - assert request_user_agent() == dummy_data.user_agent - assert meeting['id'] == 'b3142c46-d1c1-4405-baa6-85683827ed69' - assert meeting['display_name'] == 'my_test_room' - assert meeting['expires_at'] == '2023-01-24T03:30:38.629Z' - assert meeting['join_approval_level'] == 'none' - - -def test_create_instant_room_error_expiry(meetings, dummy_data): - params = {'display_name': 'my_test_room', 'expires_at': '2023-01-24T03:30:38.629Z'} - with raises(MeetingsError) as err: - meetings.create_room(params) - assert str(err.value) == 'Cannot set "expires_at" for an instant room.' - - -@responses.activate -def test_create_long_term_room(meetings, dummy_data): - stub( - responses.POST, - "https://api-eu.vonage.com/v1/meetings/rooms", - fixture_path='meetings/long_term_room.json', - ) - - params = { - 'display_name': 'test_long_term_room', - 'type': 'long_term', - 'expires_at': '2023-01-30T00:47:04+0000', - } - meeting = meetings.create_room(params) - - assert isinstance(meeting, dict) - assert request_user_agent() == dummy_data.user_agent - assert meeting['id'] == '33791484-231c-421b-8349-96e1a44e27d2' - assert meeting['display_name'] == 'test_long_term_room' - assert meeting['expires_at'] == '2023-01-30T00:47:04.000Z' - - -def test_create_room_error(meetings): - with raises(MeetingsError) as err: - meetings.create_room() - assert ( - str(err.value) - == 'You must include a value for display_name as a field in the params dict when creating a meeting room.' - ) - - -def test_create_long_term_room_error(meetings): - params = { - 'display_name': 'test_long_term_room', - 'type': 'long_term', - } - with raises(MeetingsError) as err: - meetings.create_room(params) - assert str(err.value) == 'You must set a value for "expires_at" for a long-term room.' - - -@responses.activate -def test_get_room(meetings): - stub( - responses.GET, - 'https://api-eu.vonage.com/v1/meetings/rooms/b3142c46-d1c1-4405-baa6-85683827ed69', - fixture_path='meetings/meeting_room.json', - ) - meeting = meetings.get_room(room_id='b3142c46-d1c1-4405-baa6-85683827ed69') - - assert isinstance(meeting, dict) - assert meeting['id'] == 'b3142c46-d1c1-4405-baa6-85683827ed69' - assert meeting['display_name'] == 'my_test_room' - assert meeting['expires_at'] == '2023-01-24T03:30:38.629Z' - assert meeting['join_approval_level'] == 'none' - assert meeting['ui_settings']['language'] == 'default' - assert meeting['available_features']['is_locale_switcher_available'] == False - assert meeting['available_features']['is_captions_available'] == False - - -def test_get_room_error_no_room_specified(meetings): - with raises(TypeError): - meetings.get_room() - - -@responses.activate -def test_list_rooms(meetings): - stub( - responses.GET, - 'https://api-eu.vonage.com/v1/meetings/rooms', - fixture_path='meetings/multiple_rooms.json', - ) - response = meetings.list_rooms() - - assert isinstance(response, dict) - assert response['_embedded'][0]['id'] == '4814804d-7c2d-4846-8c7d-4f6fae1f910a' - assert response['_embedded'][1]['id'] == 'de34416a-2a4c-4a59-a16a-8cd7d3121ea0' - assert response['_embedded'][2]['id'] == 'b3142c46-d1c1-4405-baa6-85683827ed69' - assert response['total_items'] == 5 - - -@responses.activate -def test_list_rooms_with_page_size(meetings): - stub( - responses.GET, - 'https://api-eu.vonage.com/v1/meetings/rooms', - fixture_path='meetings/multiple_fewer_rooms.json', - ) - response = meetings.list_rooms(page_size=2) - - assert isinstance(response, dict) - assert response['_embedded'][0]['id'] == '4814804d-7c2d-4846-8c7d-4f6fae1f910a' - assert response['_embedded'][1]['id'] == 'de34416a-2a4c-4a59-a16a-8cd7d3121ea0' - assert response['page_size'] == 2 - assert response['total_items'] == 2 - - -@responses.activate -def test_error_unauthorized(meetings): - stub( - responses.GET, - 'https://api-eu.vonage.com/v1/meetings/rooms', - fixture_path='meetings/unauthorized.json', - status_code=401, - ) - with raises(AuthenticationError) as err: - meetings.list_rooms() - assert str(err.value) == 'Authentication failed.' - - -@responses.activate -def test_update_room(meetings): - stub( - responses.PATCH, - 'https://api-eu.vonage.com/v1/meetings/rooms/b3142c46-d1c1-4405-baa6-85683827ed69', - fixture_path='meetings/update_room.json', - ) - - params = { - 'update_details': { - "available_features": { - "is_recording_available": False, - "is_chat_available": False, - "is_whiteboard_available": False, - } - } - } - meeting = meetings.update_room(room_id='b3142c46-d1c1-4405-baa6-85683827ed69', params=params) - - assert meeting['id'] == '33791484-231c-421b-8349-96e1a44e27d2' - assert meeting['available_features']['is_recording_available'] == False - assert meeting['available_features']['is_chat_available'] == False - assert meeting['available_features']['is_whiteboard_available'] == False - - -@responses.activate -def test_add_theme_to_room(meetings): - stub( - responses.PATCH, - 'https://api-eu.vonage.com/v1/meetings/rooms/33791484-231c-421b-8349-96e1a44e27d2', - fixture_path='meetings/long_term_room_with_theme.json', - ) - - meeting = meetings.add_theme_to_room( - room_id='33791484-231c-421b-8349-96e1a44e27d2', - theme_id='90a21428-b74a-4221-adc3-783935d654db', - ) - - assert meeting['id'] == '33791484-231c-421b-8349-96e1a44e27d2' - assert meeting['theme_id'] == '90a21428-b74a-4221-adc3-783935d654db' - - -@responses.activate -def test_update_room_error_no_room_specified(meetings): - stub( - responses.PATCH, - 'https://api-eu.vonage.com/v1/meetings/rooms/b3142c46-d1c1-4405-baa6-85683827ed69', - fixture_path='meetings/update_room_type_error.json', - status_code=400, - ) - with raises(ClientError) as err: - meetings.update_room(room_id='b3142c46-d1c1-4405-baa6-85683827ed69', params={}) - assert 'BadRequestError' in str(err.value) - - -@responses.activate -def test_update_room_error_no_params_specified(meetings): - stub( - responses.PATCH, - 'https://api-eu.vonage.com/v1/meetings/rooms/33791484-231c-421b-8349-96e1a44e27d2', - fixture_path='meetings/update_room_type_error.json', - status_code=400, - ) - with raises(TypeError) as err: - meetings.update_room(room_id='33791484-231c-421b-8349-96e1a44e27d2') - assert "update_room() missing 1 required positional argument: 'params'" in str(err.value) - - -@responses.activate -def test_get_recording(meetings): - stub( - responses.GET, - 'https://api-eu.vonage.com/v1/meetings/recordings/e5b73c98-c087-4ee5-b61b-0ea08204fc65', - fixture_path='meetings/get_recording.json', - ) - - recording = meetings.get_recording(recording_id='e5b73c98-c087-4ee5-b61b-0ea08204fc65') - assert ( - recording['session_id'] - == '1_MX40NjMzOTg5Mn5-MTY3NDYxNDI4NjY5M35WM0xaVXBSc1lpT3hKWE1XQ2diM1B3cXB-fn4' - ) - assert recording['started_at'] == '2023-01-25T02:38:31.000Z' - assert recording['status'] == 'uploaded' - - -@responses.activate -def test_get_recording_not_found(meetings): - stub( - responses.GET, - 'https://api-eu.vonage.com/v1/meetings/recordings/not-a-real-recording-id', - fixture_path='meetings/get_recording_not_found.json', - status_code=404, - ) - - with raises(ClientError) as err: - meetings.get_recording(recording_id='not-a-real-recording-id') - assert 'Recording not-a-real-recording-id was not found' in str(err.value) - - -@responses.activate -def test_delete_recording(meetings): - stub( - responses.DELETE, - 'https://api-eu.vonage.com/v1/meetings/recordings/e5b73c98-c087-4ee5-b61b-0ea08204fc65', - fixture_path='no_content.json', - status_code=204, - ) - - assert meetings.delete_recording(recording_id='e5b73c98-c087-4ee5-b61b-0ea08204fc65') == None - - -@responses.activate -def test_delete_recording_not_uploaded(meetings, client): - stub( - responses.DELETE, - 'https://api-eu.vonage.com/v1/meetings/recordings/881f0dbe-3d91-4fd6-aeea-0eca4209b512', - fixture_path='meetings/delete_recording_not_found.json', - status_code=404, - ) - - with raises(ClientError) as err: - meetings.delete_recording(recording_id='881f0dbe-3d91-4fd6-aeea-0eca4209b512') - assert 'Could not find recording' in str(err.value) - - -@responses.activate -def test_get_session_recordings(meetings): - stub( - responses.GET, - 'https://api-eu.vonage.com/v1/meetings/sessions/1_MX40NjMzOTg5Mn5-MTY3NDYxNDI4NjY5M35WM0xaVXBSc1lpT3hKWE1XQ2diM1B3cXB-fn4/recordings', - fixture_path='meetings/get_session_recordings.json', - ) - - session = meetings.get_session_recordings( - session_id='1_MX40NjMzOTg5Mn5-MTY3NDYxNDI4NjY5M35WM0xaVXBSc1lpT3hKWE1XQ2diM1B3cXB-fn4' - ) - assert session['_embedded']['recordings'][0]['id'] == 'e5b73c98-c087-4ee5-b61b-0ea08204fc65' - assert session['_embedded']['recordings'][0]['started_at'] == '2023-01-25T02:38:31.000Z' - assert session['_embedded']['recordings'][0]['status'] == 'uploaded' - - -@responses.activate -def test_get_session_recordings_not_found(meetings): - stub( - responses.GET, - 'https://api-eu.vonage.com/v1/meetings/sessions/not-a-real-session-id/recordings', - fixture_path='meetings/get_session_recordings_not_found.json', - status_code=404, - ) - - with raises(ClientError) as err: - meetings.get_session_recordings(session_id='not-a-real-session-id') - assert 'NotFoundError' in str(err.value) - - -@responses.activate -def test_list_dial_in_numbers(meetings): - stub( - responses.GET, - 'https://api-eu.vonage.com/v1/meetings/dial-in-numbers', - fixture_path='meetings/list_dial_in_numbers.json', - ) - - numbers = meetings.list_dial_in_numbers() - assert numbers[0]['number'] == '541139862166' - assert numbers[0]['display_name'] == 'Argentina' - assert numbers[1]['number'] == '442381924626' - assert numbers[1]['locale'] == 'en-GB' - - -@responses.activate -def test_list_themes(meetings): - stub( - responses.GET, - 'https://api-eu.vonage.com/v1/meetings/themes', - fixture_path='meetings/list_themes.json', - ) - - themes = meetings.list_themes() - assert themes[0]['theme_id'] == '1fc39568-bc50-464f-82dc-01e13bed0908' - assert themes[0]['main_color'] == '#FF0000' - assert themes[0]['brand_text'] == 'My Other Company' - assert themes[1]['theme_id'] == '90a21428-b74a-4221-adc3-783935d654db' - assert themes[1]['main_color'] == '#12f64e' - assert themes[1]['brand_text'] == 'My Company' - - -@responses.activate -def test_list_themes_no_themes(meetings): - stub( - responses.GET, - 'https://api-eu.vonage.com/v1/meetings/themes', - fixture_path='meetings/empty_themes.json', - ) - - assert meetings.list_themes() == {} - - -@responses.activate -def test_create_theme(meetings): - stub( - responses.POST, - "https://api-eu.vonage.com/v1/meetings/themes", - fixture_path='meetings/theme.json', - ) - - params = { - 'theme_name': 'my_theme', - 'main_color': '#12f64e', - 'brand_text': 'My Company', - 'short_company_url': 'my-company', - } - - theme = meetings.create_theme(params) - assert theme['theme_id'] == '90a21428-b74a-4221-adc3-783935d654db' - assert theme['main_color'] == '#12f64e' - assert theme['brand_text'] == 'My Company' - assert theme['domain'] == 'VCP' - - -def test_create_theme_missing_required_params(meetings): - with raises(MeetingsError) as err: - meetings.create_theme({}) - assert str(err.value) == 'Values for "main_color" and "brand_text" must be specified' - - -@responses.activate -def test_create_theme_name_already_in_use(meetings): - stub( - responses.POST, - "https://api-eu.vonage.com/v1/meetings/themes", - fixture_path='meetings/theme_name_in_use.json', - status_code=409, - ) - - params = { - 'theme_name': 'my_theme', - 'main_color': '#12f64e', - 'brand_text': 'My Company', - } - - with raises(ClientError) as err: - meetings.create_theme(params) - assert 'ConflictError' in str(err.value) - - -@responses.activate -def test_get_theme(meetings): - stub( - responses.GET, - "https://api-eu.vonage.com/v1/meetings/themes/90a21428-b74a-4221-adc3-783935d654db", - fixture_path='meetings/theme.json', - ) - - theme = meetings.get_theme('90a21428-b74a-4221-adc3-783935d654db') - assert theme['main_color'] == '#12f64e' - assert theme['brand_text'] == 'My Company' - - -@responses.activate -def test_get_theme_not_found(meetings): - stub( - responses.GET, - "https://api-eu.vonage.com/v1/meetings/themes/90a21428-b74a-4221-adc3-783935d654dc", - fixture_path='meetings/theme_not_found.json', - status_code=404, - ) - - with raises(ClientError) as err: - meetings.get_theme('90a21428-b74a-4221-adc3-783935d654dc') - assert 'NotFoundError' in str(err.value) - - -@responses.activate -def test_delete_theme(meetings): - stub( - responses.DELETE, - "https://api-eu.vonage.com/v1/meetings/themes/90a21428-b74a-4221-adc3-783935d654db", - fixture_path='no_content.json', - status_code=204, - ) - - theme = meetings.delete_theme('90a21428-b74a-4221-adc3-783935d654db') - assert theme == None - - -@responses.activate -def test_delete_theme_not_found(meetings): - stub( - responses.DELETE, - "https://api-eu.vonage.com/v1/meetings/themes/90a21428-b74a-4221-adc3-783935d654dc", - fixture_path='meetings/theme_not_found.json', - status_code=404, - ) - - with raises(ClientError) as err: - meetings.delete_theme('90a21428-b74a-4221-adc3-783935d654dc') - assert 'NotFoundError' in str(err.value) - - -@responses.activate -def test_delete_theme_in_use(meetings): - stub( - responses.DELETE, - "https://api-eu.vonage.com/v1/meetings/themes/90a21428-b74a-4221-adc3-783935d654db", - fixture_path='meetings/delete_theme_in_use.json', - status_code=400, - ) - - with raises(ClientError) as err: - meetings.delete_theme('90a21428-b74a-4221-adc3-783935d654db') - assert 'Theme 90a21428-b74a-4221-adc3-783935d654db is used by 1 room' in str(err.value) - - -@responses.activate -def test_update_theme(meetings): - stub( - responses.PATCH, - "https://api-eu.vonage.com/v1/meetings/themes/90a21428-b74a-4221-adc3-783935d654db", - fixture_path='meetings/updated_theme.json', - ) - - params = { - 'update_details': { - 'theme_name': 'updated_theme', - 'main_color': '#FF0000', - 'brand_text': 'My Updated Company Name', - 'short_company_url': 'updated_company_url', - } - } - - theme = meetings.update_theme('90a21428-b74a-4221-adc3-783935d654db', params) - assert theme['theme_id'] == '90a21428-b74a-4221-adc3-783935d654db' - assert theme['main_color'] == '#FF0000' - assert theme['brand_text'] == 'My Updated Company Name' - assert theme['short_company_url'] == 'updated_company_url' - - -@responses.activate -def test_update_theme_no_keys(meetings): - stub( - responses.PATCH, - "https://api-eu.vonage.com/v1/meetings/themes/90a21428-b74a-4221-adc3-783935d654db", - fixture_path='meetings/update_no_keys.json', - status_code=400, - ) - - with raises(ClientError) as err: - meetings.update_theme('90a21428-b74a-4221-adc3-783935d654db', {'update_details': {}}) - assert '"update_details" must have at least 1 key' in str(err.value) - - -@responses.activate -def test_update_theme_not_found(meetings): - stub( - responses.PATCH, - "https://api-eu.vonage.com/v1/meetings/themes/90a21428-b74a-4221-adc3-783935d654dc", - fixture_path='meetings/theme_not_found.json', - status_code=404, - ) - - with raises(ClientError) as err: - meetings.update_theme( - '90a21428-b74a-4221-adc3-783935d654dc', - {'update_details': {'theme_name': 'my_new_name'}}, - ) - assert 'NotFoundError' in str(err.value) - - -@responses.activate -def test_update_theme_name_already_exists(meetings): - stub( - responses.PATCH, - 'https://api-eu.vonage.com/v1/meetings/themes/90a21428-b74a-4221-adc3-783935d654db', - fixture_path='meetings/update_theme_already_exists.json', - status_code=409, - ) - - with raises(ClientError) as err: - meetings.update_theme( - '90a21428-b74a-4221-adc3-783935d654db', - {'update_details': {'theme_name': 'my_other_theme'}}, - ) - assert 'theme_name already exists in application' in str(err.value) - - -@responses.activate -def test_list_rooms_with_options(meetings): - stub( - responses.GET, - 'https://api-eu.vonage.com/v1/meetings/themes/90a21428-b74a-4221-adc3-783935d654db/rooms', - fixture_path='meetings/list_rooms_with_theme_id.json', - ) - - rooms = meetings.list_rooms_with_theme_id( - '90a21428-b74a-4221-adc3-783935d654db', - page_size=5, - start_id=0, - end_id=99999999, - ) - assert rooms['_embedded'][0]['id'] == '33791484-231c-421b-8349-96e1a44e27d2' - assert rooms['_embedded'][0]['display_name'] == 'test_long_term_room' - assert rooms['_embedded'][0]['theme_id'] == '90a21428-b74a-4221-adc3-783935d654db' - assert rooms['page_size'] == 5 - assert ( - rooms['_links']['self']['href'] - == 'api-eu.vonage.com/meetings/rooms?page_size=20&start_id=2009870' - ) - - -@responses.activate -def test_list_rooms_with_theme_id_not_found(meetings): - stub( - responses.GET, - 'https://api-eu.vonage.com/v1/meetings/themes/90a21428-b74a-4221-adc3-783935d654dc/rooms', - fixture_path='meetings/list_rooms_theme_id_not_found.json', - status_code=404, - ) - - with raises(ClientError) as err: - meetings.list_rooms_with_theme_id( - '90a21428-b74a-4221-adc3-783935d654dc', start_id=0, end_id=99999999 - ) - assert ( - 'Failed to get rooms because theme id 90a21428-b74a-4221-adc3-783935d654dc not found' - in str(err.value) - ) - - -@responses.activate -def test_update_application_theme(meetings): - stub( - responses.PATCH, - 'https://api-eu.vonage.com/v1/meetings/applications', - fixture_path='meetings/update_application_theme.json', - ) - - response = meetings.update_application_theme(theme_id='90a21428-b74a-4221-adc3-783935d654db') - assert response['application_id'] == 'my-application-id' - assert response['account_id'] == 'my-account-id' - assert response['default_theme_id'] == '90a21428-b74a-4221-adc3-783935d654db' - - -@responses.activate -def test_update_application_theme_bad_request(meetings): - stub( - responses.PATCH, - 'https://api-eu.vonage.com/v1/meetings/applications', - fixture_path='meetings/update_application_theme_id_not_found.json', - status_code=400, - ) - - with raises(ClientError) as err: - meetings.update_application_theme(theme_id='not-a-real-theme-id') - assert 'Failed to update application because theme id not-a-real-theme-id not found' in str( - err.value - ) - - -@responses.activate -def test_upload_logo_to_theme(meetings): - stub( - responses.GET, - 'https://api-eu.vonage.com/v1/meetings/themes/logos-upload-urls', - fixture_path='meetings/list_logo_upload_urls.json', - ) - stub( - responses.POST, - 'https://s3.amazonaws.com/roomservice-whitelabel-logos-prod', - fixture_path='no_content.json', - status_code=204, - ) - stub_bytes( - responses.PUT, - 'https://api-eu.vonage.com/v1/meetings/themes/90a21428-b74a-4221-adc3-783935d654db/finalizeLogos', - body=b'OK', - ) - - response = meetings.upload_logo_to_theme( - theme_id='90a21428-b74a-4221-adc3-783935d654db', - path_to_image='tests/data/meetings/transparent_logo.png', - logo_type='white', - ) - assert response == 'Logo upload to theme: 90a21428-b74a-4221-adc3-783935d654db was successful.' - - -@responses.activate -def test_get_logo_upload_url(meetings): - stub( - responses.GET, - 'https://api-eu.vonage.com/v1/meetings/themes/logos-upload-urls', - fixture_path='meetings/list_logo_upload_urls.json', - ) - - url_w = meetings._get_logo_upload_url('white') - assert url_w['url'] == 'https://s3.amazonaws.com/roomservice-whitelabel-logos-prod' - assert url_w['fields']['X-Amz-Credential'] == 'some-credential' - assert ( - url_w['fields']['key'] - == 'auto-expiring-temp/logos/white/d92b31ae-fbf1-4709-a729-c0fa75368c25' - ) - assert url_w['fields']['logoType'] == 'white' - url_c = meetings._get_logo_upload_url('colored') - assert ( - url_c['fields']['key'] - == 'auto-expiring-temp/logos/colored/c4e00bac-781b-4bf0-bd5f-b9ff2cbc1b6c' - ) - assert url_c['fields']['logoType'] == 'colored' - url_f = meetings._get_logo_upload_url('favicon') - assert ( - url_f['fields']['key'] - == 'auto-expiring-temp/logos/favicon/d7a81477-38f7-460c-b51f-1462b8426df5' - ) - assert url_f['fields']['logoType'] == 'favicon' - - with raises(MeetingsError) as err: - meetings._get_logo_upload_url('not-a-valid-option') - assert str(err.value) == 'Cannot find the upload URL for the specified logo type.' - - -@responses.activate -def test_upload_to_aws(meetings): - stub( - responses.POST, - 'https://s3.amazonaws.com/roomservice-whitelabel-logos-prod', - fixture_path='no_content.json', - status_code=204, - ) - - with open('tests/data/meetings/list_logo_upload_urls.json') as file: - urls = json.load(file) - params = urls[0] - meetings._upload_to_aws(params, 'tests/data/meetings/transparent_logo.png') - - -@responses.activate -def test_upload_to_aws_error(meetings): - stub( - responses.POST, - 'https://s3.amazonaws.com/not-a-valid-url', - status_code=403, - fixture_path='meetings/upload_to_aws_error.xml', - ) - - with open('tests/data/meetings/list_logo_upload_urls.json') as file: - urls = json.load(file) - - params = urls[0] - params['url'] = 'https://s3.amazonaws.com/not-a-valid-url' - with raises(MeetingsError) as err: - meetings._upload_to_aws(params, 'tests/data/meetings/transparent_logo.png') - assert ( - str(err.value) - == 'Logo upload process failed. b\'\\\\nSignatureDoesNotMatchThe request signature we calculated does not match the signature you provided. Check your key and signing method.ASIA5NAYMMB6M7A2QEARb2f311449e26692a174ab2c7ca2afab24bd19c509cc611a4cef7cb2c5bb2ea9a5ZS7MSFN46X89NXAf+HV7uSpeawLv5lFvN+QiYP6swbiTMd/XaJeVGC+/pqKHlwlgKZ6vg+qBjV/ufb1e5WS/bxBM/Y=\'' - ) - - -@responses.activate -def test_add_logo_to_theme(meetings): - stub_bytes( - responses.PUT, - 'https://api-eu.vonage.com/v1/meetings/themes/90a21428-b74a-4221-adc3-783935d654db/finalizeLogos', - body=b'OK', - ) - - response = meetings._add_logo_to_theme( - theme_id='90a21428-b74a-4221-adc3-783935d654db', - key='auto-expiring-temp/logos/white/d92b31ae-fbf1-4709-a729-c0fa75368c25', - ) - assert response == 'OK' - - -@responses.activate -def test_add_logo_to_theme_key_error(meetings): - stub( - responses.PUT, - 'https://api-eu.vonage.com/v1/meetings/themes/90a21428-b74a-4221-adc3-783935d654dc/finalizeLogos', - fixture_path='meetings/logo_key_error.json', - status_code=400, - ) - - with raises(ClientError) as err: - meetings._add_logo_to_theme( - theme_id='90a21428-b74a-4221-adc3-783935d654dc', - key='an-invalid-key', - ) - assert 'could not finalize logos' in str(err.value) - - -@responses.activate -def test_add_logo_to_theme_not_found_error(meetings): - stub( - responses.PUT, - 'https://api-eu.vonage.com/v1/meetings/themes/90a21428-b74a-4221-adc3-783935d654dc/finalizeLogos', - fixture_path='meetings/theme_not_found.json', - status_code=404, - ) - - with raises(ClientError) as err: - meetings._add_logo_to_theme( - theme_id='90a21428-b74a-4221-adc3-783935d654dc', - key='auto-expiring-temp/logos/white/d92b31ae-fbf1-4709-a729-c0fa75368c25', - ) - assert 'NotFoundError' in str(err.value) diff --git a/tests/test_ncco_builder/ncco_samples/ncco_action_samples.py b/tests/test_ncco_builder/ncco_samples/ncco_action_samples.py deleted file mode 100644 index c3e790cd..00000000 --- a/tests/test_ncco_builder/ncco_samples/ncco_action_samples.py +++ /dev/null @@ -1,47 +0,0 @@ -record_full = '{"action": "record", "format": "wav", "split": "conversation", "channels": 4, "endOnSilence": 5, "endOnKey": "*", "timeOut": 100, "beepStart": true, "eventUrl": ["http://example.com"], "eventMethod": "PUT"}' - -record_url_as_str = '{"action": "record", "eventUrl": ["http://example.com/events"]}' - -record_add_split = '{"action": "record", "split": "conversation", "channels": 4}' - -conversation_basic = '{"action": "conversation", "name": "my_conversation"}' - -conversation_full = '{"action": "conversation", "name": "my_conversation", "musicOnHoldUrl": ["http://example.com/music.mp3"], "startOnEnter": true, "endOnExit": true, "record": true, "canSpeak": ["asdf", "qwer"], "canHear": ["asdf"]}' - -conversation_mute_option = '{"action": "conversation", "name": "my_conversation", "mute": true}' - -connect_phone = '{"action": "connect", "endpoint": [{"type": "phone", "number": "447000000000", "dtmfAnswer": "1p2p3p#**903#", "onAnswer": {"url": "https://example.com/answer", "ringbackTone": "http://example.com/ringbackTone.wav"}}]}' - -connect_app = '{"action": "connect", "endpoint": [{"type": "app", "user": "test_user"}]}' - -connect_websocket = '{"action": "connect", "endpoint": [{"type": "websocket", "uri": "ws://example.com/socket", "contentType": "audio/l16;rate=8000", "headers": {"language": "en-GB"}}]}' - -connect_sip = '{"action": "connect", "endpoint": [{"type": "sip", "uri": "sip:rebekka@sip.mcrussell.com", "headers": {"location": "New York City", "occupation": "developer"}}]}' - -connect_vbc = '{"action": "connect", "endpoint": [{"type": "vbc", "extension": "111"}]}' - -connect_full = '{"action": "connect", "endpoint": [{"type": "phone", "number": "447000000000"}], "from": "447400000000", "randomFromNumber": false, "eventType": "synchronous", "timeout": 15, "limit": 1000, "machineDetection": "hangup", "eventUrl": ["http://example.com"], "eventMethod": "PUT", "ringbackTone": "http://example.com"}' - -connect_advancedMachineDetection = '{"action": "connect", "endpoint": [{"type": "phone", "number": "447000000000"}], "from": "447400000000", "advancedMachineDetection": {"behavior": "continue", "mode": "detect"}, "eventUrl": ["http://example.com"]}' - -talk_basic = '{"action": "talk", "text": "hello"}' - -talk_full = '{"action": "talk", "text": "hello", "bargeIn": true, "loop": 3, "level": 0.5, "language": "en-GB", "style": 1, "premium": true}' - -stream_basic = '{"action": "stream", "streamUrl": ["https://example.com/stream/music.mp3"]}' - -stream_full = '{"action": "stream", "streamUrl": ["https://example.com/stream/music.mp3"], "level": 0.1, "bargeIn": true, "loop": 10}' - -input_basic_dtmf = '{"action": "input", "type": ["dtmf"]}' - -input_basic_dtmf_speech = '{"action": "input", "type": ["dtmf", "speech"]}' - -input_dtmf_and_speech_full = '{"action": "input", "type": ["dtmf", "speech"], "dtmf": {"timeOut": 5, "maxDigits": 12, "submitOnHash": true}, "speech": {"uuid": "my-uuid", "endOnSilence": 2.5, "language": "en-GB", "context": ["sales", "billing"], "startTimeout": 20, "maxDuration": 30, "saveAudio": true}, "eventUrl": ["http://example.com/speech"], "eventMethod": "PUT"}' - -notify_basic = ( - '{"action": "notify", "payload": {"message": "hello"}, "eventUrl": ["http://example.com"]}' -) - -notify_full = '{"action": "notify", "payload": {"message": "hello"}, "eventUrl": ["http://example.com"], "eventMethod": "POST"}' - -two_notify_ncco = '[{"action": "notify", "payload": {"message": "hello"}, "eventUrl": ["http://example.com"]}, {"action": "notify", "payload": {"message": "world"}, "eventUrl": ["http://example.com"], "eventMethod": "PUT"}]' diff --git a/tests/test_ncco_builder/ncco_samples/ncco_builder_samples.py b/tests/test_ncco_builder/ncco_samples/ncco_builder_samples.py deleted file mode 100644 index 5d90599e..00000000 --- a/tests/test_ncco_builder/ncco_samples/ncco_builder_samples.py +++ /dev/null @@ -1,131 +0,0 @@ -from vonage import Ncco, ConnectEndpoints, InputTypes - -record = Ncco.Record(eventUrl='http://example.com/events') - -conversation = Ncco.Conversation(name='my_conversation') - -connect = Ncco.Connect( - endpoint=ConnectEndpoints.PhoneEndpoint(number='447000000000'), - from_='447400000000', - randomFromNumber=False, - eventType='synchronous', - timeout=15, - limit=1000, - machineDetection='hangup', - eventUrl='http://example.com', - eventMethod='PUT', - ringbackTone='http://example.com', -) - -connect_advancedMachineDetection = Ncco.Connect( - endpoint=ConnectEndpoints.PhoneEndpoint(number='447000000000'), - advancedMachineDetection={'behavior': 'continue', 'mode': 'detect'}, -) - - -talk_minimal = Ncco.Talk(text='hello') - -talk = Ncco.Talk( - text='hello', bargeIn=True, loop=3, level=0.5, language='en-GB', style=1, premium=True -) - -stream = Ncco.Stream( - streamUrl='https://example.com/stream/music.mp3', level=0.1, bargeIn=True, loop=10 -) - -input = Ncco.Input( - type=['dtmf', 'speech'], - dtmf=InputTypes.Dtmf(timeOut=5, maxDigits=12, submitOnHash=True), - speech=InputTypes.Speech( - uuid='my-uuid', - endOnSilence=2.5, - language='en-GB', - context=['sales', 'billing'], - startTimeout=20, - maxDuration=30, - saveAudio=True, - ), - eventUrl='http://example.com/speech', - eventMethod='put', -) - -notify = Ncco.Notify( - payload={"message": "world"}, eventUrl=["http://example.com"], eventMethod='PUT' -) - -basic_ncco = [{"action": "talk", "text": "hello"}] - -two_part_ncco = [ - { - 'action': 'record', - 'eventUrl': ['http://example.com/events'], - }, - {'action': 'talk', 'text': 'hello'}, -] - -three_part_advancedMachineDetection_ncco = [ - {'action': 'record', 'eventUrl': ['http://example.com/events']}, - { - 'action': 'connect', - 'endpoint': [{'type': 'phone', 'number': '447000000000'}], - 'advancedMachineDetection': {'behavior': 'continue', 'mode': 'detect'}, - }, - {'action': 'talk', 'text': 'hello'}, -] - -insane_ncco = [ - {'action': 'record', 'eventUrl': ['http://example.com/events']}, - {'action': 'conversation', 'name': 'my_conversation'}, - { - 'action': 'connect', - 'endpoint': [{'number': '447000000000', 'type': 'phone'}], - 'eventMethod': 'PUT', - 'eventType': 'synchronous', - 'eventUrl': ['http://example.com'], - 'from': '447400000000', - 'limit': 1000, - 'machineDetection': 'hangup', - 'randomFromNumber': False, - 'ringbackTone': 'http://example.com', - 'timeout': 15, - }, - { - 'action': 'talk', - 'bargeIn': True, - 'language': 'en-GB', - 'level': 0.5, - 'loop': 3, - 'premium': True, - 'style': 1, - 'text': 'hello', - }, - { - 'action': 'stream', - 'bargeIn': True, - 'level': 0.1, - 'loop': 10, - 'streamUrl': ['https://example.com/stream/music.mp3'], - }, - { - 'action': 'input', - 'dtmf': {'maxDigits': 12, 'submitOnHash': True, 'timeOut': 5}, - 'eventMethod': 'PUT', - 'eventUrl': ['http://example.com/speech'], - 'speech': { - 'context': ['sales', 'billing'], - 'endOnSilence': 2.5, - 'language': 'en-GB', - 'maxDuration': 30, - 'saveAudio': True, - 'startTimeout': 20, - 'uuid': 'my-uuid', - }, - 'type': ['dtmf', 'speech'], - }, - { - 'action': 'notify', - 'eventMethod': 'PUT', - 'eventUrl': ['http://example.com'], - 'payload': {'message': 'world'}, - }, -] diff --git a/tests/test_ncco_builder/test_connect_endpoints.py b/tests/test_ncco_builder/test_connect_endpoints.py deleted file mode 100644 index 519b8207..00000000 --- a/tests/test_ncco_builder/test_connect_endpoints.py +++ /dev/null @@ -1,55 +0,0 @@ -from vonage import ConnectEndpoints, Ncco -import ncco_samples.ncco_action_samples as nas - -import json -import pytest -from pydantic import ValidationError - - -def _action_as_dict(action: Ncco.Action): - return action.model_dump(exclude_none=True) - - -def test_connect_all_endpoints_from_model(): - phone = ConnectEndpoints.PhoneEndpoint( - number='447000000000', - dtmfAnswer='1p2p3p#**903#', - onAnswer={ - "url": "https://example.com/answer", - "ringbackTone": "http://example.com/ringbackTone.wav", - }, - ) - connect_phone = Ncco.Connect(endpoint=phone) - assert json.dumps(_action_as_dict(connect_phone)) == nas.connect_phone - - app = ConnectEndpoints.AppEndpoint(user='test_user') - connect_app = Ncco.Connect(endpoint=app) - assert json.dumps(_action_as_dict(connect_app)) == nas.connect_app - - websocket = ConnectEndpoints.WebsocketEndpoint( - uri='ws://example.com/socket', - contentType='audio/l16;rate=8000', - headers={"language": "en-GB"}, - ) - connect_websocket = Ncco.Connect(endpoint=websocket) - assert json.dumps(_action_as_dict(connect_websocket)) == nas.connect_websocket - - sip = ConnectEndpoints.SipEndpoint( - uri='sip:rebekka@sip.mcrussell.com', - headers={"location": "New York City", "occupation": "developer"}, - ) - connect_sip = Ncco.Connect(endpoint=sip) - assert json.dumps(_action_as_dict(connect_sip)) == nas.connect_sip - - vbc = ConnectEndpoints.VbcEndpoint(extension='111') - connect_vbc = Ncco.Connect(endpoint=vbc) - assert json.dumps(_action_as_dict(connect_vbc)) == nas.connect_vbc - - -def test_connect_endpoints_errors(): - with pytest.raises(ValueError) as err: - ConnectEndpoints.create_endpoint_model_from_dict({'type': 'carrier_pigeon'}) - assert ( - str(err.value) - == 'Invalid "type" specified for endpoint object. Cannot create a ConnectEndpoints.Endpoint model.' - ) diff --git a/tests/test_ncco_builder/test_input_types.py b/tests/test_ncco_builder/test_input_types.py deleted file mode 100644 index 592e0518..00000000 --- a/tests/test_ncco_builder/test_input_types.py +++ /dev/null @@ -1,47 +0,0 @@ -from vonage import InputTypes - - -def test_create_dtmf_model(): - dtmf = InputTypes.Dtmf(timeOut=5, maxDigits=2, submitOnHash=True) - assert type(dtmf) == InputTypes.Dtmf - assert dtmf.model_dump() == {'maxDigits': 2, 'submitOnHash': True, 'timeOut': 5} - - -def test_create_dtmf_model_from_dict(): - dtmf_dict = {'timeOut': 3, 'maxDigits': 4, 'submitOnHash': True} - dtmf_model = InputTypes.create_dtmf_model(dtmf_dict) - assert type(dtmf_model) == InputTypes.Dtmf - assert dtmf_model.model_dump() == {'maxDigits': 4, 'submitOnHash': True, 'timeOut': 3} - - -def test_create_speech_model(): - speech = InputTypes.Speech( - uuid='my-uuid', - endOnSilence=2.5, - language='en-GB', - context=['sales', 'billing'], - startTimeout=20, - maxDuration=30, - saveAudio=True, - ) - assert type(speech) == InputTypes.Speech - assert speech.model_dump() == { - 'uuid': 'my-uuid', - 'endOnSilence': 2.5, - 'language': 'en-GB', - 'context': ['sales', 'billing'], - 'startTimeout': 20, - 'maxDuration': 30, - 'saveAudio': True, - } - - -def test_create_speech_model_from_dict(): - speech_dict = {'uuid': 'my-uuid', 'endOnSilence': 2.5, 'maxDuration': 30} - speech_model = InputTypes.create_speech_model(speech_dict) - assert type(speech_model) == InputTypes.Speech - assert speech_model.model_dump(exclude_none=True) == { - 'uuid': 'my-uuid', - 'endOnSilence': 2.5, - 'maxDuration': 30, - } diff --git a/tests/test_ncco_builder/test_ncco_actions.py b/tests/test_ncco_builder/test_ncco_actions.py deleted file mode 100644 index 9d9cf6b1..00000000 --- a/tests/test_ncco_builder/test_ncco_actions.py +++ /dev/null @@ -1,260 +0,0 @@ -from vonage import Ncco, ConnectEndpoints, InputTypes -import ncco_samples.ncco_action_samples as nas - -import json -import pytest -from pydantic import ValidationError - - -def _action_as_dict(action: Ncco.Action): - return action.model_dump(by_alias=True, exclude_none=True) - - -def test_record_full(): - record = Ncco.Record( - format='wav', - split='conversation', - channels=4, - endOnSilence=5, - endOnKey='*', - timeOut=100, - beepStart=True, - eventUrl=['http://example.com'], - eventMethod='PUT', - ) - assert type(record) == Ncco.Record - assert json.dumps(_action_as_dict(record)) == nas.record_full - - -def test_record_url_passed_as_str(): - record = Ncco.Record(eventUrl='http://example.com/events') - assert json.dumps(_action_as_dict(record)) == nas.record_url_as_str - - -def test_record_channels_adds_split_parameter(): - record = Ncco.Record(channels=4) - assert json.dumps(_action_as_dict(record)) == nas.record_add_split - - -def test_record_model_errors(): - with pytest.raises(ValidationError): - Ncco.Record(format='mp4') - with pytest.raises(ValidationError): - Ncco.Record(endOnKey='asdf') - - -def test_conversation_basic(): - conversation = Ncco.Conversation(name='my_conversation') - assert type(conversation) == Ncco.Conversation - assert json.dumps(_action_as_dict(conversation)) == nas.conversation_basic - - -def test_conversation_full(): - conversation = Ncco.Conversation( - name='my_conversation', - musicOnHoldUrl='http://example.com/music.mp3', - startOnEnter=True, - endOnExit=True, - record=True, - canSpeak=['asdf', 'qwer'], - canHear=['asdf'], - ) - assert json.dumps(_action_as_dict(conversation)) == nas.conversation_full - - -def test_conversation_field_type_error(): - with pytest.raises(ValidationError): - Ncco.Conversation(name='my_conversation', startOnEnter='asdf') - - -def test_conversation_mute(): - conversation = Ncco.Conversation(name='my_conversation', mute=True) - assert json.dumps(_action_as_dict(conversation)) == nas.conversation_mute_option - - -def test_conversation_incompatible_options_error(): - with pytest.raises(ValidationError) as err: - Ncco.Conversation(name='my_conversation', canSpeak=['asdf', 'qwer'], mute=True) - str(err.value) == 'Cannot use mute option if canSpeak option is specified.+' - - -def test_connect_phone_endpoint_from_dict(): - connect = Ncco.Connect( - endpoint={ - "type": "phone", - "number": "447000000000", - "dtmfAnswer": "1p2p3p#**903#", - "onAnswer": { - "url": "https://example.com/answer", - "ringbackTone": "http://example.com/ringbackTone.wav", - }, - } - ) - assert type(connect) is Ncco.Connect - assert json.dumps(_action_as_dict(connect)) == nas.connect_phone - - -def test_connect_phone_endpoint_from_list(): - connect = Ncco.Connect( - endpoint=[ - { - "type": "phone", - "number": "447000000000", - "dtmfAnswer": "1p2p3p#**903#", - "onAnswer": { - "url": "https://example.com/answer", - "ringbackTone": "http://example.com/ringbackTone.wav", - }, - } - ] - ) - assert json.dumps(_action_as_dict(connect)) == nas.connect_phone - - -def test_connect_options(): - endpoint = ConnectEndpoints.PhoneEndpoint(number='447000000000') - connect = Ncco.Connect( - endpoint=endpoint, - from_='447400000000', - randomFromNumber=False, - eventType='synchronous', - timeout=15, - limit=1000, - machineDetection='hangup', - eventUrl='http://example.com', - eventMethod='PUT', - ringbackTone='http://example.com', - ) - assert json.dumps(_action_as_dict(connect)) == nas.connect_full - - -def test_connect_advanced_machine_detection(): - advancedMachineDetectionParams = {'behavior': 'continue', 'mode': 'detect'} - endpoint = ConnectEndpoints.PhoneEndpoint(number='447000000000') - connect = Ncco.Connect( - endpoint=endpoint, - from_='447400000000', - advancedMachineDetection=advancedMachineDetectionParams, - eventUrl='http://example.com', - ) - assert json.dumps(_action_as_dict(connect)) == nas.connect_advancedMachineDetection - - -def test_connect_random_from_number_error(): - endpoint = ConnectEndpoints.PhoneEndpoint(number='447000000000') - with pytest.raises(ValueError) as err: - Ncco.Connect(endpoint=endpoint, from_='447400000000', randomFromNumber=True) - - assert ( - 'Cannot set a "from" ("from_") field and also the "randomFromNumber" = True option' - in str(err.value) - ) - - -def test_connect_validation_errors(): - endpoint = ConnectEndpoints.PhoneEndpoint(number='447000000000') - with pytest.raises(ValidationError): - Ncco.Connect(endpoint=endpoint, from_=1234) - with pytest.raises(ValidationError): - Ncco.Connect(endpoint=endpoint, eventType='asynchronous') - with pytest.raises(ValidationError): - Ncco.Connect(endpoint=endpoint, limit=7201) - with pytest.raises(ValidationError): - Ncco.Connect(endpoint=endpoint, machineDetection='do_nothing') - with pytest.raises(ValidationError): - Ncco.Connect(endpoint=endpoint, advancedMachineDetection={'behavior': 'do_nothing'}) - with pytest.raises(ValidationError): - Ncco.Connect(endpoint=endpoint, advancedMachineDetection={'mode': 'detect_nothing'}) - - -def test_talk_basic(): - talk = Ncco.Talk(text='hello') - assert type(talk) == Ncco.Talk - assert json.dumps(_action_as_dict(talk)) == nas.talk_basic - - -def test_talk_optional_params(): - talk = Ncco.Talk( - text='hello', bargeIn=True, loop=3, level=0.5, language='en-GB', style=1, premium=True - ) - assert json.dumps(_action_as_dict(talk)) == nas.talk_full - - -def test_talk_validation_error(): - with pytest.raises(ValidationError): - Ncco.Talk(text='hello', bargeIn='go ahead') - - -def test_stream_basic(): - stream = Ncco.Stream(streamUrl='https://example.com/stream/music.mp3') - assert type(stream) == Ncco.Stream - assert json.dumps(_action_as_dict(stream)) == nas.stream_basic - - -def test_stream_full(): - stream = Ncco.Stream( - streamUrl='https://example.com/stream/music.mp3', level=0.1, bargeIn=True, loop=10 - ) - assert json.dumps(_action_as_dict(stream)) == nas.stream_full - - -def test_input_basic(): - input = Ncco.Input(type='dtmf') - assert type(input) == Ncco.Input - assert json.dumps(_action_as_dict(input)) == nas.input_basic_dtmf - - -def test_input_basic_list(): - input = Ncco.Input(type=['dtmf', 'speech']) - assert json.dumps(_action_as_dict(input)) == nas.input_basic_dtmf_speech - - -def test_input_dtmf_and_speech_options(): - dtmf = InputTypes.Dtmf(timeOut=5, maxDigits=12, submitOnHash=True) - speech = InputTypes.Speech( - uuid='my-uuid', - endOnSilence=2.5, - language='en-GB', - context=['sales', 'billing'], - startTimeout=20, - maxDuration=30, - saveAudio=True, - ) - input = Ncco.Input( - type=['dtmf', 'speech'], - dtmf=dtmf, - speech=speech, - eventUrl='http://example.com/speech', - eventMethod='put', - ) - assert json.dumps(_action_as_dict(input)) == nas.input_dtmf_and_speech_full - - -def test_input_validation_error(): - with pytest.raises(ValidationError): - Ncco.Input(type='invalid_type') - - -def test_notify_basic(): - notify = Ncco.Notify(payload={'message': 'hello'}, eventUrl=['http://example.com']) - assert type(notify) == Ncco.Notify - assert json.dumps(_action_as_dict(notify)) == nas.notify_basic - - -def test_notify_basic_str_in_event_url(): - notify = Ncco.Notify(payload={'message': 'hello'}, eventUrl='http://example.com') - assert type(notify) == Ncco.Notify - assert json.dumps(_action_as_dict(notify)) == nas.notify_basic - - -def test_notify_full(): - notify = Ncco.Notify( - payload={'message': 'hello'}, eventUrl=['http://example.com'], eventMethod='POST' - ) - assert type(notify) == Ncco.Notify - assert json.dumps(_action_as_dict(notify)) == nas.notify_full - - -def test_notify_validation_error(): - with pytest.raises(ValidationError): - Ncco.Notify(payload={'message', 'hello'}, eventUrl=['http://example.com']) diff --git a/tests/test_ncco_builder/test_ncco_builder.py b/tests/test_ncco_builder/test_ncco_builder.py deleted file mode 100644 index 6434c761..00000000 --- a/tests/test_ncco_builder/test_ncco_builder.py +++ /dev/null @@ -1,38 +0,0 @@ -import json - -from vonage import Ncco -import ncco_samples.ncco_builder_samples as nbs - - -def test_build_basic_ncco(): - ncco = Ncco.build_ncco(nbs.talk_minimal) - assert ncco == nbs.basic_ncco - - -def test_build_ncco_from_args(): - ncco = Ncco.build_ncco(nbs.record, nbs.talk_minimal) - assert ncco == nbs.two_part_ncco - assert ( - json.dumps(ncco) - == '[{"action": "record", "eventUrl": ["http://example.com/events"]}, {"action": "talk", "text": "hello"}]' - ) - - -def test_build_ncco_from_list(): - action_list = [nbs.record, nbs.connect_advancedMachineDetection, nbs.talk_minimal] - ncco = Ncco.build_ncco(actions=action_list) - assert ncco == nbs.three_part_advancedMachineDetection_ncco - - -def test_build_insane_ncco(): - action_list = [ - nbs.record, - nbs.conversation, - nbs.connect, - nbs.talk, - nbs.stream, - nbs.input, - nbs.notify, - ] - ncco = Ncco.build_ncco(actions=action_list) - assert ncco == nbs.insane_ncco diff --git a/tests/test_number_insight.py b/tests/test_number_insight.py deleted file mode 100644 index 6efab76f..00000000 --- a/tests/test_number_insight.py +++ /dev/null @@ -1,140 +0,0 @@ -from util import * -from vonage.errors import CallbackRequiredError, NumberInsightError - - -@responses.activate -def test_get_basic_number_insight(number_insight, dummy_data): - stub( - responses.GET, - "https://api.nexmo.com/ni/basic/json", - fixture_path='number_insight/basic_get.json', - ) - - response = number_insight.get_basic_number_insight(number='447700900000') - assert isinstance(response, dict) - assert response['status_message'] == 'Success' - assert request_user_agent() == dummy_data.user_agent - assert "number=447700900000" in request_query() - - -@responses.activate -def test_get_basic_number_insight_error(number_insight): - stub( - responses.GET, - "https://api.nexmo.com/ni/basic/json", - fixture_path='number_insight/get_error.json', - ) - - with pytest.raises(NumberInsightError) as err: - number_insight.get_basic_number_insight(number='1234') - assert ( - str(err.value) - == 'Number Insight API method failed with status: 3 and error: Invalid request :: Not valid number format detected [ 1234 ]' - ) - - -@responses.activate -def test_get_standard_number_insight(number_insight, dummy_data): - stub( - responses.GET, - "https://api.nexmo.com/ni/standard/json", - fixture_path='number_insight/standard_get.json', - ) - - response = number_insight.get_standard_number_insight(number="447700900000") - assert isinstance(response, dict) - assert response['status_message'] == 'Success' - assert request_user_agent() == dummy_data.user_agent - assert "number=447700900000" in request_query() - - -@responses.activate -def test_get_standard_number_insight_error(number_insight): - stub( - responses.GET, - "https://api.nexmo.com/ni/standard/json", - fixture_path='number_insight/get_error.json', - ) - - with pytest.raises(NumberInsightError) as err: - number_insight.get_standard_number_insight(number='1234') - assert ( - str(err.value) - == 'Number Insight API method failed with status: 3 and error: Invalid request :: Not valid number format detected [ 1234 ]' - ) - - -@responses.activate -def test_get_advanced_number_insight(number_insight, dummy_data): - stub( - responses.GET, - "https://api.nexmo.com/ni/advanced/json", - fixture_path='number_insight/advanced_get.json', - ) - - response = number_insight.get_advanced_number_insight(number="447700900000") - assert isinstance(response, dict) - assert response['status_message'] == 'Success' - assert request_user_agent() == dummy_data.user_agent - assert "number=447700900000" in request_query() - - -@responses.activate -def test_get_advanced_number_insight_error(number_insight): - stub( - responses.GET, - "https://api.nexmo.com/ni/advanced/json", - fixture_path='number_insight/get_error.json', - ) - - with pytest.raises(NumberInsightError) as err: - number_insight.get_advanced_number_insight(number='1234') - assert ( - str(err.value) - == 'Number Insight API method failed with status: 3 and error: Invalid request :: Not valid number format detected [ 1234 ]' - ) - - -@responses.activate -def test_get_async_advanced_number_insight(number_insight, dummy_data): - stub( - responses.GET, - "https://api.nexmo.com/ni/advanced/async/json", - fixture_path='number_insight/advanced_get.json', - ) - - params = {"number": "447525856424", "callback": "https://example.com"} - - response = number_insight.get_async_advanced_number_insight(params) - assert isinstance(response, dict) - assert response['status_message'] == 'Success' - assert request_user_agent() == dummy_data.user_agent - assert "number=447525856424" in request_query() - assert "callback=https%3A%2F%2Fexample.com" in request_query() - - -@responses.activate -def test_get_async_advanced_number_insight_error(number_insight): - stub( - responses.GET, - "https://api.nexmo.com/ni/advanced/async/json", - fixture_path='number_insight/get_async_error.json', - ) - - with pytest.raises(NumberInsightError) as err: - number_insight.get_async_advanced_number_insight( - number='1234', callback='https://example.com' - ) - assert ( - str(err.value) - == 'Number Insight API method failed with status: 3 and error: Invalid request :: Not valid number format detected [ 1234 ]' - ) - - -def test_callback_required_error_async_advanced_number_insight(number_insight, dummy_data): - stub(responses.GET, "https://api.nexmo.com/ni/advanced/async/json") - - params = {"number": "447525856424", "callback": ""} - - with pytest.raises(CallbackRequiredError): - number_insight.get_async_advanced_number_insight(params) diff --git a/tests/test_number_management.py b/tests/test_number_management.py deleted file mode 100644 index dcaeccf9..00000000 --- a/tests/test_number_management.py +++ /dev/null @@ -1,59 +0,0 @@ -from util import * - - -@responses.activate -def test_get_account_numbers(numbers, dummy_data): - stub(responses.GET, "https://rest.nexmo.com/account/numbers") - - assert isinstance(numbers.get_account_numbers(size=25), dict) - assert request_user_agent() == dummy_data.user_agent - assert request_params()["size"] == ["25"] - - -@responses.activate -def test_get_available_numbers(numbers, dummy_data): - stub(responses.GET, "https://rest.nexmo.com/number/search") - - assert isinstance(numbers.get_available_numbers("CA", size=25), dict) - assert request_user_agent() == dummy_data.user_agent - assert "country=CA" in request_query() - assert "size=25" in request_query() - - -@responses.activate -def test_buy_number(numbers, dummy_data): - stub(responses.POST, "https://rest.nexmo.com/number/buy") - - params = {"country": "US", "msisdn": "number"} - - assert isinstance(numbers.buy_number(params), dict) - assert request_user_agent() == dummy_data.user_agent - print(request_body()) - print(request_params()) - assert "country=US" in request_body() - assert "msisdn=number" in request_body() - - -@responses.activate -def test_cancel_number(numbers, dummy_data): - stub(responses.POST, "https://rest.nexmo.com/number/cancel") - - params = {"country": "US", "msisdn": "number"} - - assert isinstance(numbers.cancel_number(params), dict) - assert request_user_agent() == dummy_data.user_agent - assert "country=US" in request_body() - assert "msisdn=number" in request_body() - - -@responses.activate -def test_update_number(numbers, dummy_data): - stub(responses.POST, "https://rest.nexmo.com/number/update") - - params = {"country": "US", "msisdn": "number", "moHttpUrl": "callback"} - - assert isinstance(numbers.update_number(params), dict) - assert request_user_agent() == dummy_data.user_agent - assert "country=US" in request_body() - assert "msisdn=number" in request_body() - assert "moHttpUrl=callback" in request_body() diff --git a/tests/test_proactive_connect.py b/tests/test_proactive_connect.py deleted file mode 100644 index 55920859..00000000 --- a/tests/test_proactive_connect.py +++ /dev/null @@ -1,454 +0,0 @@ -from vonage.errors import ProactiveConnectError, ClientError -from util import * - -import responses -from pytest import raises -import csv - - -@responses.activate -def test_list_all_lists(proc, dummy_data): - stub( - responses.GET, - 'https://api-eu.vonage.com/v0.1/bulk/lists', - fixture_path='proactive_connect/list_lists.json', - ) - - lists = proc.list_all_lists() - assert request_user_agent() == dummy_data.user_agent - assert lists['total_items'] == 2 - assert lists['_embedded']['lists'][0]['name'] == 'Recipients for demo' - assert lists['_embedded']['lists'][0]['id'] == 'af8a84b6-c712-4252-ac8d-6e28ac9317ce' - assert lists['_embedded']['lists'][1]['name'] == 'Salesforce contacts' - assert lists['_embedded']['lists'][1]['datasource']['type'] == 'salesforce' - - -@responses.activate -def test_list_all_lists_options(proc): - stub( - responses.GET, - 'https://api-eu.vonage.com/v0.1/bulk/lists', - fixture_path='proactive_connect/list_lists.json', - ) - - lists = proc.list_all_lists(page=1, page_size=5) - assert lists['total_items'] == 2 - assert lists['_embedded']['lists'][0]['name'] == 'Recipients for demo' - assert lists['_embedded']['lists'][0]['id'] == 'af8a84b6-c712-4252-ac8d-6e28ac9317ce' - assert lists['_embedded']['lists'][1]['name'] == 'Salesforce contacts' - - -def test_pagination_errors(proc): - with raises(ProactiveConnectError) as err: - proc.list_all_lists(page=-1) - assert str(err.value) == '"page" must be an int > 0.' - - with raises(ProactiveConnectError) as err: - proc.list_all_lists(page_size=-1) - assert str(err.value) == '"page_size" must be an int > 0.' - - -@responses.activate -def test_create_list_basic(proc): - stub( - responses.POST, - 'https://api-eu.vonage.com/v0.1/bulk/lists', - fixture_path='proactive_connect/create_list_basic.json', - status_code=201, - ) - - list = proc.create_list({'name': 'my_list'}) - assert list['id'] == '6994fd17-7691-4463-be16-172ab1430d97' - assert list['name'] == 'my_list' - - -@responses.activate -def test_create_list_manual(proc): - stub( - responses.POST, - 'https://api-eu.vonage.com/v0.1/bulk/lists', - fixture_path='proactive_connect/create_list_manual.json', - status_code=201, - ) - - params = { - "name": "my name", - "description": "my description", - "tags": ["vip", "sport"], - "attributes": [{"name": "phone_number", "alias": "phone"}], - "datasource": {"type": "manual"}, - } - - list = proc.create_list(params) - assert list['id'] == '9508e7b8-fe99-4fdf-b022-65d7e461db2d' - assert list['name'] == 'my_list' - assert list['description'] == 'my description' - assert list['tags'] == ['vip', 'sport'] - assert list['attributes'][0]['name'] == 'phone_number' - - -@responses.activate -def test_create_list_salesforce(proc): - stub( - responses.POST, - 'https://api-eu.vonage.com/v0.1/bulk/lists', - fixture_path='proactive_connect/create_list_salesforce.json', - status_code=201, - ) - - params = { - "name": "my name", - "description": "my description", - "tags": ["vip", "sport"], - "attributes": [{"name": "phone_number", "alias": "phone"}], - "datasource": { - "type": "salesforce", - "integration_id": "salesforce_credentials", - "soql": "select Id, LastName, FirstName, Phone, Email FROM Contact", - }, - } - - list = proc.create_list(params) - assert list['id'] == '246d17c4-79e6-4a25-8b4e-b777a83f6c30' - assert list['name'] == 'my_salesforce_list' - assert list['description'] == 'my salesforce description' - assert list['datasource']['type'] == 'salesforce' - assert list['datasource']['integration_id'] == 'salesforce_credentials' - assert list['datasource']['soql'] == 'select Id, LastName, FirstName, Phone, Email FROM Contact' - - -def test_create_list_errors(proc): - params = { - "name": "my name", - "datasource": { - "type": "salesforce", - "integration_id": 1234, - "soql": "select Id, LastName, FirstName, Phone, Email FROM Contact", - }, - } - - with raises(ProactiveConnectError) as err: - proc.create_list({}) - assert str(err.value) == 'You must supply a name for the new list.' - - with raises(ProactiveConnectError) as err: - proc.create_list(params) - assert str(err.value) == 'You must supply values for "integration_id" and "soql" as strings.' - - with raises(ProactiveConnectError) as err: - params['datasource'].pop('integration_id') - proc.create_list(params) - assert ( - str(err.value) - == 'You must supply a value for "integration_id" and "soql" when creating a list with Salesforce.' - ) - - -@responses.activate -def test_create_list_invalid_name_error(proc): - stub( - responses.POST, - 'https://api-eu.vonage.com/v0.1/bulk/lists', - fixture_path='proactive_connect/create_list_400.json', - status_code=400, - ) - - with raises(ClientError) as err: - proc.create_list({'name': 1234}) - assert ( - 'name must be longer than or equal to 1 and shorter than or equal to 255 characters' - in str(err.value) - ) - - -@responses.activate -def test_get_list(proc): - list_id = '9508e7b8-fe99-4fdf-b022-65d7e461db2d' - stub( - responses.GET, - f'https://api-eu.vonage.com/v0.1/bulk/lists/{list_id}', - fixture_path='proactive_connect/get_list.json', - ) - - list = proc.get_list(list_id) - assert list['id'] == '9508e7b8-fe99-4fdf-b022-65d7e461db2d' - assert list['name'] == 'my_list' - assert list['tags'] == ['vip', 'sport'] - - -@responses.activate -def test_get_list_404(proc): - list_id = 'a508e7b8-fe99-4fdf-b022-65d7e461db2d' - stub( - responses.GET, - f'https://api-eu.vonage.com/v0.1/bulk/lists/{list_id}', - fixture_path='proactive_connect/not_found.json', - status_code=404, - ) - - with raises(ClientError) as err: - proc.get_list(list_id) - assert 'The requested resource does not exist' in str(err.value) - - -@responses.activate -def test_update_list(proc): - list_id = '9508e7b8-fe99-4fdf-b022-65d7e461db2d' - stub( - responses.PUT, - f'https://api-eu.vonage.com/v0.1/bulk/lists/{list_id}', - fixture_path='proactive_connect/update_list.json', - ) - - params = {'name': 'my_list', 'tags': ['vip', 'sport', 'football']} - list = proc.update_list(list_id, params) - assert list['id'] == '9508e7b8-fe99-4fdf-b022-65d7e461db2d' - assert list['tags'] == ['vip', 'sport', 'football'] - assert list['description'] == 'my updated description' - assert list['updated_at'] == '2023-04-28T21:39:17.825Z' - - -@responses.activate -def test_update_list_salesforce(proc): - list_id = '246d17c4-79e6-4a25-8b4e-b777a83f6c30' - stub( - responses.PUT, - f'https://api-eu.vonage.com/v0.1/bulk/lists/{list_id}', - fixture_path='proactive_connect/update_list_salesforce.json', - ) - - params = {'name': 'my_list', 'tags': ['music']} - list = proc.update_list(list_id, params) - assert list['id'] == list_id - assert list['tags'] == ['music'] - assert list['updated_at'] == '2023-04-28T22:23:37.054Z' - - -def test_update_list_name_error(proc): - with raises(ProactiveConnectError) as err: - proc.update_list( - '9508e7b8-fe99-4fdf-b022-65d7e461db2d', {'description': 'my new description'} - ) - assert str(err.value) == 'You must supply a name for the new list.' - - -@responses.activate -def test_delete_list(proc): - list_id = '9508e7b8-fe99-4fdf-b022-65d7e461db2d' - stub( - responses.DELETE, - f'https://api-eu.vonage.com/v0.1/bulk/lists/{list_id}', - fixture_path='no_content.json', - status_code=204, - ) - - assert proc.delete_list(list_id) == None - - -@responses.activate -def test_clear_list(proc): - list_id = '9508e7b8-fe99-4fdf-b022-65d7e461db2d' - stub( - responses.POST, - f'https://api-eu.vonage.com/v0.1/bulk/lists/{list_id}/clear', - fixture_path='no_content.json', - status_code=202, - ) - - assert proc.clear_list(list_id) == None - - -@responses.activate -def test_sync_list_from_datasource(proc): - list_id = '246d17c4-79e6-4a25-8b4e-b777a83f6c30' - stub( - responses.POST, - f'https://api-eu.vonage.com/v0.1/bulk/lists/{list_id}/fetch', - fixture_path='no_content.json', - status_code=202, - ) - - assert proc.sync_list_from_datasource(list_id) == None - - -@responses.activate -def test_sync_list_manual_datasource_error(proc): - list_id = '9508e7b8-fe99-4fdf-b022-65d7e461db2d' - stub( - responses.POST, - f'https://api-eu.vonage.com/v0.1/bulk/lists/{list_id}/fetch', - fixture_path='proactive_connect/fetch_list_400.json', - status_code=400, - ) - - with raises(ClientError) as err: - proc.sync_list_from_datasource(list_id) == None - assert 'Cannot Fetch a manual list' in str(err.value) - - -@responses.activate -def test_list_all_items(proc): - list_id = '9508e7b8-fe99-4fdf-b022-65d7e461db2d' - stub( - responses.GET, - f'https://api-eu.vonage.com/v0.1/bulk/lists/{list_id}/items', - fixture_path='proactive_connect/list_all_items.json', - ) - - items = proc.list_all_items(list_id, page=1, page_size=10) - assert items['total_items'] == 2 - assert items['_embedded']['items'][0]['id'] == '04c7498c-bae9-40f9-bdcb-c4eabb0418fe' - assert items['_embedded']['items'][1]['id'] == 'd91c39ed-7c34-4803-a139-34bb4b7c6d53' - - -@responses.activate -def test_create_item(proc): - list_id = '246d17c4-79e6-4a25-8b4e-b777a83f6c30' - stub( - responses.POST, - f'https://api-eu.vonage.com/v0.1/bulk/lists/{list_id}/items', - fixture_path='proactive_connect/item.json', - status_code=201, - ) - - data = {'firstName': 'John', 'lastName': 'Doe', 'phone': '123456789101'} - item = proc.create_item(list_id, data) - - assert item['id'] == 'd91c39ed-7c34-4803-a139-34bb4b7c6d53' - assert item['data']['phone'] == '123456789101' - - -@responses.activate -def test_create_item_error_invalid_data(proc): - list_id = '246d17c4-79e6-4a25-8b4e-b777a83f6c30' - - stub( - responses.POST, - f'https://api-eu.vonage.com/v0.1/bulk/lists/{list_id}/items', - fixture_path='proactive_connect/item_400.json', - status_code=400, - ) - - with raises(ClientError) as err: - proc.create_item(list_id, {'data': 1234}) - assert 'data must be an object' in str(err.value) - - -@responses.activate -def test_download_list_items(proc): - list_id = '246d17c4-79e6-4a25-8b4e-b777a83f6c30' - stub( - responses.GET, - f'https://api-eu.vonage.com/v0.1/bulk/lists/{list_id}/items/download', - fixture_path='proactive_connect/list_items.csv', - ) - - proc.download_list_items( - list_id, os.path.join(os.path.dirname(__file__), 'data/proactive_connect/list_items.csv') - ) - items = _read_csv_file( - os.path.join(os.path.dirname(__file__), 'data/proactive_connect/list_items.csv') - ) - assert items[0]['favourite_number'] == '0' - assert items[1]['least_favourite_number'] == '0' - - -@responses.activate -def test_get_item(proc): - list_id = '246d17c4-79e6-4a25-8b4e-b777a83f6c30' - item_id = 'd91c39ed-7c34-4803-a139-34bb4b7c6d53' - stub( - responses.GET, - f'https://api-eu.vonage.com/v0.1/bulk/lists/{list_id}/items/{item_id}', - fixture_path='proactive_connect/item.json', - ) - - item = proc.get_item(list_id, item_id) - assert item['id'] == 'd91c39ed-7c34-4803-a139-34bb4b7c6d53' - assert item['data']['phone'] == '123456789101' - - -@responses.activate -def test_update_item(proc): - list_id = '246d17c4-79e6-4a25-8b4e-b777a83f6c30' - item_id = 'd91c39ed-7c34-4803-a139-34bb4b7c6d53' - data = {'first_name': 'John', 'last_name': 'Doe', 'phone': '447007000000'} - stub( - responses.PUT, - f'https://api-eu.vonage.com/v0.1/bulk/lists/{list_id}/items/{item_id}', - fixture_path='proactive_connect/update_item.json', - ) - - updated_item = proc.update_item(list_id, item_id, data) - - assert updated_item['id'] == item_id - assert updated_item['data'] == data - assert updated_item['updated_at'] == '2023-05-03T19:50:33.207Z' - - -@responses.activate -def test_update_item_error_invalid_data(proc): - list_id = '246d17c4-79e6-4a25-8b4e-b777a83f6c30' - item_id = 'd91c39ed-7c34-4803-a139-34bb4b7c6d53' - data = 'asdf' - stub( - responses.PUT, - f'https://api-eu.vonage.com/v0.1/bulk/lists/{list_id}/items/{item_id}', - fixture_path='proactive_connect/item_400.json', - status_code=400, - ) - - with raises(ClientError) as err: - proc.update_item(list_id, item_id, data) - assert 'data must be an object' in str(err.value) - - -@responses.activate -def test_delete_item(proc): - list_id = '246d17c4-79e6-4a25-8b4e-b777a83f6c30' - item_id = 'd91c39ed-7c34-4803-a139-34bb4b7c6d53' - stub( - responses.DELETE, - f'https://api-eu.vonage.com/v0.1/bulk/lists/{list_id}/items/{item_id}', - fixture_path='no_content.json', - status_code=204, - ) - - response = proc.delete_item(list_id, item_id) - assert response is None - - -@responses.activate -def test_upload_list_items_from_csv(proc): - list_id = '246d17c4-79e6-4a25-8b4e-b777a83f6c30' - file_path = os.path.join(os.path.dirname(__file__), 'data/proactive_connect/csv_to_upload.csv') - stub( - responses.POST, - f'https://api-eu.vonage.com/v0.1/bulk/lists/{list_id}/items/import', - fixture_path='proactive_connect/upload_from_csv.json', - ) - - response = proc.upload_list_items(list_id, file_path) - assert response['inserted'] == 3 - - -@responses.activate -def test_list_events(proc): - stub( - responses.GET, - 'https://api-eu.vonage.com/v0.1/bulk/events', - fixture_path='proactive_connect/list_events.json', - ) - - lists = proc.list_events() - assert lists['total_items'] == 1 - assert lists['_embedded']['events'][0]['occurred_at'] == '2022-08-07T13:18:21.970Z' - assert lists['_embedded']['events'][0]['type'] == 'action-call-succeeded' - assert lists['_embedded']['events'][0]['run_id'] == '7d0d4e5f-6453-4c63-87cf-f95b04377324' - - -def _read_csv_file(path): - with open(os.path.join(os.path.dirname(__file__), path)) as csv_file: - reader = csv.DictReader(csv_file) - dict_list = [row for row in reader] - return dict_list diff --git a/tests/test_rest_calls.py b/tests/test_rest_calls.py deleted file mode 100644 index 96acf051..00000000 --- a/tests/test_rest_calls.py +++ /dev/null @@ -1,218 +0,0 @@ -from util import * -from vonage.errors import AuthenticationError, ClientError, ServerError - -import json - - -@responses.activate -def test_get_with_query_params_auth(client, dummy_data): - stub(responses.GET, "https://api.nexmo.com/v1/applications") - host = "api.nexmo.com" - request_uri = "/v1/applications" - params = {"aaa": "xxx", "bbb": "yyy"} - response = client.get( - host, - request_uri, - params=params, - auth_type='params', - sent_data_type='query', - ) - assert isinstance(response, dict) - assert request_user_agent() == dummy_data.user_agent - assert "aaa=xxx" in request_query() - assert "bbb=yyy" in request_query() - - -@responses.activate -def test_get_with_header_auth(client, dummy_data): - stub(responses.GET, "https://api.nexmo.com/v1/applications") - host = "api.nexmo.com" - request_uri = "/v1/applications" - params = {"aaa": "xxx", "bbb": "yyy"} - response = client.get( - host, - request_uri, - params=params, - auth_type='header', - sent_data_type='query', - ) - assert isinstance(response, dict) - assert request_user_agent() == dummy_data.user_agent - assert "aaa=xxx" in request_query() - assert "bbb=yyy" in request_query() - assert_basic_auth() - - -@responses.activate -def test_post_with_query_params_auth(client, dummy_data): - stub(responses.POST, "https://api.nexmo.com/v1/applications") - host = "api.nexmo.com" - request_uri = "/v1/applications" - params = {"aaa": "xxx", "bbb": "yyy"} - response = client.post( - host, - request_uri, - params, - auth_type='params', - sent_data_type='data', - ) - assert isinstance(response, dict) - assert request_user_agent() == dummy_data.user_agent - assert "aaa=xxx" in request_body() - assert "bbb=yyy" in request_body() - - -@responses.activate -def test_post_with_header_auth(client, dummy_data): - stub(responses.POST, "https://api.nexmo.com/v1/applications") - host = "api.nexmo.com" - request_uri = "/v1/applications" - params = {"aaa": "xxx", "bbb": "yyy"} - response = client.post( - host, - request_uri, - params, - auth_type='header', - sent_data_type='data', - ) - assert isinstance(response, dict) - assert request_user_agent() == dummy_data.user_agent - assert "aaa=xxx" in request_body() - assert "bbb=yyy" in request_body() - assert_basic_auth() - - -@responses.activate -def test_put_with_header_auth(client, dummy_data): - stub(responses.PUT, "https://api.nexmo.com/v1/applications") - host = "api.nexmo.com" - request_uri = "/v1/applications" - params = {"aaa": "xxx", "bbb": "yyy"} - response = client.put( - host, - request_uri, - params=params, - auth_type='header', - ) - assert_basic_auth() - assert isinstance(response, dict) - assert request_user_agent() == dummy_data.user_agent - assert b"aaa" in request_body() - assert b"xxx" in request_body() - assert b"bbb" in request_body() - assert b"yyy" in request_body() - - -@responses.activate -def test_delete_with_header_auth(client, dummy_data): - stub(responses.DELETE, "https://api.nexmo.com/v1/applications") - host = "api.nexmo.com" - request_uri = "/v1/applications" - response = client.delete(host, request_uri, auth_type='header') - assert isinstance(response, dict) - assert request_user_agent() == dummy_data.user_agent - assert_basic_auth() - - -@responses.activate -def test_patch(client, dummy_data): - stub(responses.PATCH, f"https://api.nexmo.com/v2/project", fixture_path="rest_calls/patch.json") - host = "api.nexmo.com" - request_uri = "/v2/project" - params = {"test_param_1": "test1", "test_param_2": "test2"} - response = client.patch(host, request_uri, params=params, auth_type='jwt') - assert isinstance(response, dict) - assert response['patch'] == 'test_case' - assert response['successful'] == True - assert request_headers()['Content-Type'] == 'application/json' - assert re.search(b'^Bearer ', request_headers()['Authorization']) is not None - assert request_user_agent() == dummy_data.user_agent - assert b"test_param_1" in request_body() - assert b"test1" in request_body() - assert b"test_param_2" in request_body() - assert b"test2" in request_body() - - -@responses.activate -def test_patch_no_content(client, dummy_data): - stub( - responses.PATCH, - f"https://api.nexmo.com/v2/project", - status_code=204, - fixture_path='no_content.json', - ) - host = "api.nexmo.com" - request_uri = "/v2/project" - params = {"test_param_1": "test1", "test_param_2": "test2"} - client.patch(host, request_uri, params=params, auth_type='jwt') - assert request_headers()['Content-Type'] == 'application/json' - assert re.search(b'^Bearer ', request_headers()['Authorization']) is not None - assert request_user_agent() == dummy_data.user_agent - assert b"test_param_1" in request_body() - assert b"test1" in request_body() - assert b"test_param_2" in request_body() - assert b"test2" in request_body() - - -@responses.activate -def test_get_with_jwt_auth(client, dummy_data): - stub(responses.GET, "https://api.nexmo.com/v1/calls") - host = "api.nexmo.com" - request_uri = "/v1/calls" - response = client.get(host, request_uri, auth_type='jwt') - assert isinstance(response, dict) - assert request_user_agent() == dummy_data.user_agent - - -@responses.activate -def test_authentication_error(client): - responses.add( - responses.DELETE, - "https://api.nexmo.com/v2/applications/xx-xx-xx-xx", - status=401, - ) - with pytest.raises(AuthenticationError): - client.application.delete_application("xx-xx-xx-xx") - - -@responses.activate -def test_client_error_json_body(client): - responses.add( - responses.DELETE, - "https://api.nexmo.com/v2/applications/xx-xx-xx-xx", - status=430, - body=json.dumps( - { - "type": "nope_error", - "title": "Nope", - "detail": "You really shouldn't have done that", - } - ), - ) - with pytest.raises(ClientError) as err: - client.application.delete_application("xx-xx-xx-xx") - assert "You really shouldn't have done that" in str(err.value) - - -@responses.activate -def test_client_error_non_json_body(client): - responses.add( - responses.DELETE, - 'https://api.nexmo.com/v2/applications/xx-xx-xx-xx', - status=430, - body='this: isnot_json', - ) - with pytest.raises(ClientError) as err: - client.application.delete_application('xx-xx-xx-xx') - assert '430 response from api.nexmo.com' in str(err.value) - - -@responses.activate -def test_server_error(client): - responses.add( - responses.DELETE, - "https://api.nexmo.com/v2/applications/xx-xx-xx-xx", - status=500, - ) - with pytest.raises(ServerError): - client.application.delete_application("xx-xx-xx-xx") diff --git a/tests/test_sms.py b/tests/test_sms.py deleted file mode 100644 index c7363353..00000000 --- a/tests/test_sms.py +++ /dev/null @@ -1,115 +0,0 @@ -import vonage -from util import * -from vonage.errors import SmsError, PartialFailureError - - -@responses.activate -def test_send_message(sms, dummy_data): - stub(responses.POST, "https://rest.nexmo.com/sms/json", fixture_path='sms/send_message.json') - - params = {"from": "Python", "to": "447525856424", "text": "Hey!"} - - assert isinstance(sms.send_message(params), dict) - assert request_user_agent() == dummy_data.user_agent - assert "from=Python" in request_body() - assert "to=447525856424" in request_body() - assert "text=Hey%21" in request_body() - - -@responses.activate -def test_send_message_200_error(sms, dummy_data): - stub( - responses.POST, - "https://rest.nexmo.com/sms/json", - fixture_path='sms/send_message_200_error.json', - ) - - params = {"from": "Python", "text": "Hey!"} - - with pytest.raises(SmsError) as err: - assert isinstance(sms.send_message(params), dict) - assert ( - str(err.value) == 'Sms.send_message method failed with error code 2: Missing to param' - ) - - assert request_user_agent() == dummy_data.user_agent - assert "from=Python" in request_body() - assert "text=Hey%21" in request_body() - - -@responses.activate -def test_send_long_message(sms, dummy_data): - stub( - responses.POST, "https://rest.nexmo.com/sms/json", fixture_path='sms/send_long_message.json' - ) - - with open('tests/data/sms/long_message.txt', 'r') as reader: - long_message = reader.read() - - params = {"from": "Python", "to": "447525856424", "text": long_message} - response_data = sms.send_message(params) - - assert isinstance(response_data, dict) - assert response_data['message-count'] == '2' - assert request_user_agent() == dummy_data.user_agent - assert "from=Python" in request_body() - assert "to=447525856424" in request_body() - assert ( - f"text={long_message.replace(' ', '+').replace(',', '%2C')}" in request_body() - ) # Check for encoding - - -@responses.activate -def test_send_long_message_partial_error(sms, dummy_data): - stub( - responses.POST, - "https://rest.nexmo.com/sms/json", - fixture_path='sms/send_long_message_partial_error.json', - ) - - with open('tests/data/sms/long_message.txt', 'r') as reader: - long_message = reader.read() - - params = {"from": "Python", "to": "447525856424", "text": long_message} - - with pytest.raises(PartialFailureError) as err: - assert isinstance(sms.send_message(params), dict) - assert ( - str(err.value) - == 'Sms.send_message method partially failed. Not all of the message sent successfully.' - ) - - -@responses.activate -def test_authentication_error(sms): - responses.add(responses.POST, "https://rest.nexmo.com/sms/json", status=401) - - with pytest.raises(vonage.AuthenticationError): - sms.send_message({}) - - -@responses.activate -def test_client_error(sms): - responses.add(responses.POST, "https://rest.nexmo.com/sms/json", status=400) - - with pytest.raises(vonage.ClientError) as excinfo: - sms.send_message({}) - excinfo.match(r"400 response from rest.nexmo.com") - - -@responses.activate -def test_server_error(sms): - responses.add(responses.POST, "https://rest.nexmo.com/sms/json", status=500) - - with pytest.raises(vonage.ServerError) as excinfo: - sms.send_message({}) - excinfo.match(r"500 response from rest.nexmo.com") - - -@responses.activate -def test_submit_sms_conversion(sms): - responses.add(responses.POST, "https://api.nexmo.com/conversions/sms", status=200, body=b"OK") - - sms.submit_sms_conversion("a-message-id") - assert "message-id=a-message-id" in request_body() - assert "timestamp" in request_body() diff --git a/tests/test_subaccounts.py b/tests/test_subaccounts.py deleted file mode 100644 index b0196f0a..00000000 --- a/tests/test_subaccounts.py +++ /dev/null @@ -1,383 +0,0 @@ -from vonage import Client, ClientError, SubaccountsError, AuthenticationError -from util import stub - -from pytest import raises -import responses - -api_key = '1234asdf' -api_secret = 'qwerasdfzxcv' -client = Client(key=api_key, secret=api_secret) -subaccount_key = 'asdfzxcv' - - -@responses.activate -def test_list_subaccounts(): - stub( - responses.GET, - f'https://api.nexmo.com/accounts/{api_key}/subaccounts', - fixture_path='subaccounts/list_subaccounts.json', - ) - subaccounts = client.subaccounts.list_subaccounts() - assert subaccounts['total_balance'] == 9.9999 - assert subaccounts['_embedded']['primary_account']['api_key'] == api_key - assert subaccounts['_embedded']['primary_account']['balance'] == 9.9999 - assert subaccounts['_embedded']['subaccounts'][0]['api_key'] == 'qwerasdf' - assert subaccounts['_embedded']['subaccounts'][0]['name'] == 'test_subaccount' - - -@responses.activate -def test_list_subaccounts_error_authentication(): - stub( - responses.GET, - f'https://api.nexmo.com/accounts/{api_key}/subaccounts', - fixture_path='subaccounts/invalid_credentials.json', - status_code=401, - ) - with raises(AuthenticationError) as err: - client.subaccounts.list_subaccounts() - assert str(err.value) == 'Authentication failed.' - - -@responses.activate -def test_list_subaccounts_error_forbidden(): - stub( - responses.GET, - f'https://api.nexmo.com/accounts/{api_key}/subaccounts', - fixture_path='subaccounts/forbidden.json', - status_code=403, - ) - with raises(ClientError) as err: - client.subaccounts.list_subaccounts() - assert 'Account 1234adsf is not provisioned to access Subaccount Provisioning API' in str( - err.value - ) - - -@responses.activate -def test_list_subaccounts_error_not_found(): - stub( - responses.GET, - f'https://api.nexmo.com/accounts/{api_key}/subaccounts', - fixture_path='subaccounts/not_found.json', - status_code=404, - ) - with raises(ClientError) as err: - client.subaccounts.list_subaccounts() - assert "API key '1234asdf' does not exist, or you do not have access" in str(err.value) - - -@responses.activate -def test_create_subaccount(): - stub( - responses.POST, - f'https://api.nexmo.com/accounts/{api_key}/subaccounts', - fixture_path='subaccounts/subaccount.json', - ) - subaccount = client.subaccounts.create_subaccount( - name='my subaccount', secret='Password123', use_primary_account_balance=True - ) - assert subaccount['api_key'] == 'asdfzxcv' - assert subaccount['secret'] == 'Password123' - assert subaccount['primary_account_api_key'] == api_key - assert subaccount['use_primary_account_balance'] == True - - -def test_create_subaccount_error_non_boolean(): - with raises(SubaccountsError) as err: - client.subaccounts.create_subaccount( - 'failed subaccount', use_primary_account_balance='yes please' - ) - assert ( - str(err.value) - == 'If providing a value, it needs to be a boolean. You provided: "yes please"' - ) - - -@responses.activate -def test_get_subaccount(): - stub( - responses.GET, - f'https://api.nexmo.com/accounts/{api_key}/subaccounts/{subaccount_key}', - fixture_path='subaccounts/subaccount.json', - ) - subaccount = client.subaccounts.get_subaccount(subaccount_key) - assert subaccount['api_key'] == 'asdfzxcv' - assert subaccount['secret'] == 'Password123' - assert subaccount['primary_account_api_key'] == api_key - assert subaccount['use_primary_account_balance'] == True - - -@responses.activate -def test_modify_subaccount(): - stub( - responses.PATCH, - f'https://api.nexmo.com/accounts/{api_key}/subaccounts/{subaccount_key}', - fixture_path='subaccounts/modified_subaccount.json', - ) - subaccount = client.subaccounts.modify_subaccount( - subaccount_key, - suspended=True, - use_primary_account_balance=False, - name='my modified subaccount', - ) - assert subaccount['api_key'] == 'asdfzxcv' - assert subaccount['name'] == 'my modified subaccount' - assert subaccount['suspended'] == True - assert subaccount['primary_account_api_key'] == api_key - assert subaccount['use_primary_account_balance'] == False - - -@responses.activate -def test_modify_subaccount_error_authentication(): - stub( - responses.PATCH, - f'https://api.nexmo.com/accounts/{api_key}/subaccounts/{subaccount_key}', - fixture_path='subaccounts/invalid_credentials.json', - status_code=401, - ) - with raises(AuthenticationError) as err: - client.subaccounts.modify_subaccount(subaccount_key, suspended=True) - assert str(err.value) == 'Authentication failed.' - - -@responses.activate -def test_modify_subaccount_validation_error(): - stub( - responses.PATCH, - f'https://api.nexmo.com/accounts/{api_key}/subaccounts/{subaccount_key}', - fixture_path='subaccounts/validation_error.json', - status_code=422, - ) - with raises(ClientError) as err: - client.subaccounts.modify_subaccount(subaccount_key, use_primary_account_balance=True) - assert 'Bad Request' in str(err.value) - - -@responses.activate -def test_list_credit_transfers(): - stub( - responses.GET, - f'https://api.nexmo.com/accounts/{api_key}/credit-transfers', - fixture_path='subaccounts/list_credit_transfers.json', - ) - transfers = client.subaccounts.list_credit_transfers( - start_date='2022-03-29T14:16:56Z', - end_date='2023-06-12T17:20:01Z', - subaccount='asdfzxcv', - ) - assert transfers['_embedded']['credit_transfers'][0]['from'] == '1234asdf' - assert transfers['_embedded']['credit_transfers'][0]['reference'] == 'test credit transfer' - assert transfers['_embedded']['credit_transfers'][1]['to'] == 'asdfzxcv' - assert transfers['_embedded']['credit_transfers'][1]['created_at'] == '2023-06-12T17:20:01.000Z' - - -@responses.activate -def test_list_credit_transfers_validation_error(): - stub( - responses.GET, - f'https://api.nexmo.com/accounts/{api_key}/credit-transfers', - fixture_path='subaccounts/transfer_validation_error.json', - status_code=422, - ) - with raises(ClientError) as err: - client.subaccounts.list_credit_transfers(start_date='invalid-date-format') - assert 'Bad Request' in str(err.value) - - -@responses.activate -def test_transfer_credit(): - stub( - responses.POST, - f'https://api.nexmo.com/accounts/{api_key}/credit-transfers', - fixture_path='subaccounts/credit_transfer.json', - ) - transfer = client.subaccounts.transfer_credit( - from_='1234asdf', to='asdfzxcv', amount=0.50, reference='test credit transfer' - ) - assert transfer['from'] == '1234asdf' - assert transfer['to'] == 'asdfzxcv' - assert transfer['amount'] == 0.5 - assert transfer['reference'] == 'test credit transfer' - - -@responses.activate -def test_transfer_credit_invalid_transfer(): - stub( - responses.POST, - f'https://api.nexmo.com/accounts/{api_key}/credit-transfers', - fixture_path='subaccounts/invalid_transfer.json', - status_code=403, - ) - with raises(ClientError) as err: - client.subaccounts.transfer_credit(from_='asdfzxcv', to='qwerasdf', amount=1) - assert 'Invalid Transfer' in str(err.value) - - -@responses.activate -def test_transfer_credit_insufficient_credit(): - stub( - responses.POST, - f'https://api.nexmo.com/accounts/{api_key}/credit-transfers', - fixture_path='subaccounts/insufficient_credit.json', - status_code=403, - ) - with raises(ClientError) as err: - client.subaccounts.transfer_credit(from_='asdfzxcv', to='qwerasdf', amount=1) - assert 'Insufficient Credit' in str(err.value) - - -@responses.activate -def test_transfer_credit_validation_error(): - stub( - responses.POST, - f'https://api.nexmo.com/accounts/{api_key}/credit-transfers', - fixture_path='subaccounts/must_be_number.json', - status_code=422, - ) - with raises(ClientError) as err: - client.subaccounts.transfer_credit(from_='1234asdf', to='asdfzxcv', amount='0.50') - assert 'Bad Request' in str(err.value) - - -@responses.activate -def test_list_balance_transfers(): - stub( - responses.GET, - f'https://api.nexmo.com/accounts/{api_key}/balance-transfers', - fixture_path='subaccounts/list_balance_transfers.json', - ) - transfers = client.subaccounts.list_balance_transfers( - start_date='2022-03-29T14:16:56Z', - end_date='2023-06-12T17:20:01Z', - subaccount='asdfzxcv', - ) - assert transfers['_embedded']['balance_transfers'][0]['from'] == '1234asdf' - assert transfers['_embedded']['balance_transfers'][0]['reference'] == 'test transfer' - assert transfers['_embedded']['balance_transfers'][1]['to'] == 'asdfzxcv' - assert ( - transfers['_embedded']['balance_transfers'][1]['created_at'] == '2023-06-12T17:20:01.000Z' - ) - - -@responses.activate -def test_list_balance_transfers_validation_error(): - stub( - responses.GET, - f'https://api.nexmo.com/accounts/{api_key}/balance-transfers', - fixture_path='subaccounts/transfer_validation_error.json', - status_code=422, - ) - with raises(ClientError) as err: - client.subaccounts.list_balance_transfers(start_date='invalid-date-format') - assert 'Bad Request' in str(err.value) - - -@responses.activate -def test_transfer_balance(): - stub( - responses.POST, - f'https://api.nexmo.com/accounts/{api_key}/balance-transfers', - fixture_path='subaccounts/balance_transfer.json', - ) - transfer = client.subaccounts.transfer_balance( - from_='1234asdf', to='asdfzxcv', amount=0.50, reference='test balance transfer' - ) - assert transfer['from'] == '1234asdf' - assert transfer['to'] == 'asdfzxcv' - assert transfer['amount'] == 0.5 - assert transfer['reference'] == 'test balance transfer' - - -@responses.activate -def test_transfer_balance_invalid_transfer(): - stub( - responses.POST, - f'https://api.nexmo.com/accounts/{api_key}/balance-transfers', - fixture_path='subaccounts/invalid_transfer.json', - status_code=403, - ) - with raises(ClientError) as err: - client.subaccounts.transfer_balance(from_='asdfzxcv', to='qwerasdf', amount=1) - assert 'Invalid Transfer' in str(err.value) - - -@responses.activate -def test_transfer_balance_validation_error(): - stub( - responses.POST, - f'https://api.nexmo.com/accounts/{api_key}/balance-transfers', - fixture_path='subaccounts/must_be_number.json', - status_code=422, - ) - with raises(ClientError) as err: - client.subaccounts.transfer_balance(from_='1234asdf', to='asdfzxcv', amount='0.50') - assert 'Bad Request' in str(err.value) - - -@responses.activate -def test_transfer_number(): - stub( - responses.POST, - f'https://api.nexmo.com/accounts/{api_key}/transfer-number', - fixture_path='subaccounts/transfer_number.json', - ) - transfer = client.subaccounts.transfer_number( - from_='1234asdf', to='asdfzxcv', number='12345678901', country='US' - ) - assert transfer['from'] == '1234asdf' - assert transfer['to'] == 'asdfzxcv' - assert transfer['number'] == '12345678901' - assert transfer['country'] == 'US' - assert transfer['masterAccountId'] == '1234asdf' - - -@responses.activate -def test_transfer_number_invalid_transfer(): - stub( - responses.POST, - f'https://api.nexmo.com/accounts/{api_key}/transfer-number', - fixture_path='subaccounts/invalid_number_transfer.json', - status_code=403, - ) - with raises(ClientError) as err: - client.subaccounts.transfer_number( - from_='1234asdf', to='asdfzxcv', number='12345678901', country='US' - ) - assert ( - 'Could not transfer number 12345678901 from account 1234asdf to asdfzxcv - ShortCode is not owned by from account' - in str(err.value) - ) - - -@responses.activate -def test_transfer_number_error_number_not_found(): - stub( - responses.POST, - f'https://api.nexmo.com/accounts/{api_key}/transfer-number', - fixture_path='subaccounts/number_not_found.json', - status_code=404, - ) - - with raises(ClientError) as err: - client.subaccounts.transfer_number( - from_='1234asdf', to='asdfzxcv', number='12345678901', country='US' - ) - assert ( - 'Could not transfer number 12345678901 from account 1234asdf to asdfzxcv - ShortCode not found' - in str(err.value) - ) - - -@responses.activate -def test_transfer_number_validation_error(): - stub( - responses.POST, - f'https://api.nexmo.com/accounts/{api_key}/transfer-number', - fixture_path='subaccounts/same_from_and_to_accounts.json', - status_code=422, - ) - with raises(ClientError) as err: - client.subaccounts.transfer_number( - from_='asdfzxcv', to='asdfzxcv', number='12345678901', country='US' - ) - assert 'Bad Request' in str(err.value) diff --git a/tests/test_verify.py b/tests/test_verify.py deleted file mode 100644 index 13a9192c..00000000 --- a/tests/test_verify.py +++ /dev/null @@ -1,280 +0,0 @@ -from util import * -from vonage.errors import VerifyError, BlockedNumberError - - -@responses.activate -def test_start_verification(verify, dummy_data): - stub( - responses.POST, - "https://api.nexmo.com/verify/json", - fixture_path="verify/start_verification.json", - ) - - params = {"number": "447525856424", "brand": "MyApp"} - - response = verify.start_verification(params) - assert isinstance(response, dict) - assert request_user_agent() == dummy_data.user_agent - assert "number=447525856424" in request_body() - assert "brand=MyApp" in request_body() - assert response['status'] == '0' - - -@responses.activate -def test_start_verification_error(verify): - stub( - responses.POST, - "https://api.nexmo.com/verify/json", - fixture_path="verify/start_verification_error.json", - ) - - params = {"number": "447525856424", "brand": "MyApp"} - - with pytest.raises(VerifyError) as err: - assert isinstance(verify.start_verification(params), dict) - assert ( - str(err.value) - == 'Verify API method failed with error code 2: Your request is incomplete and missing the mandatory parameter `number`' - ) - - -@responses.activate -def test_check_verification(verify, dummy_data): - stub( - responses.POST, - "https://api.nexmo.com/verify/check/json", - fixture_path="verify/check_verification.json", - ) - - assert isinstance(verify.check("8g88g88eg8g8gg9g90", code="123445"), dict) - assert request_user_agent() == dummy_data.user_agent - assert "code=123445" in request_body() - assert "request_id=8g88g88eg8g8gg9g90" in request_body() - - -@responses.activate -def test_check_verification_error(verify): - stub( - responses.POST, - "https://api.nexmo.com/verify/check/json", - fixture_path="verify/check_verification_error.json", - ) - - with pytest.raises(VerifyError) as err: - assert isinstance(verify.check("8g88g88eg8g8gg9g90", code="123445"), dict) - assert ( - str(err.value) - == 'Verify.start_verification method failed with error code 16: The code inserted does not match the expected value' - ) - - -@responses.activate -def test_search_for_verification(verify, dummy_data): - stub( - responses.GET, - "https://api.nexmo.com/verify/search/json", - fixture_path="verify/search_verification.json", - ) - - response = verify.search('xxx') - assert isinstance(response, dict) - assert response['status'] == 'IN PROGRESS' - assert request_user_agent() == dummy_data.user_agent - assert "request_id=xxx" in request_query() - - -@responses.activate -def test_search_for_verification_multiple(verify, dummy_data): - stub( - responses.GET, - "https://api.nexmo.com/verify/search/json", - fixture_path="verify/search_verification.json", - ) - - response = verify.search(request=['xxx', 'yyy']) - assert isinstance(response, dict) - assert response['status'] == 'IN PROGRESS' - assert request_user_agent() == dummy_data.user_agent - assert "request_ids=xxx&request_ids=yyy" in request_query() - - -@responses.activate -def test_search_for_verification_200_error(verify): - stub( - responses.GET, - "https://api.nexmo.com/verify/search/json", - fixture_path="verify/search_verification_200_error.json", - ) - - with pytest.raises(VerifyError) as err: - verify.search('xxx') - assert ( - str(err.value) - == 'Verify API method failed with status: IN PROGRESS and error: No response found' - ) - - -@responses.activate -def test_search_for_verification_error_no_id_provided(verify): - stub(responses.GET, "https://api.nexmo.com/verify/search/json") - - with pytest.raises(VerifyError) as err: - verify.search() - assert str(err.value) == 'At least one request ID must be provided.' - - -@responses.activate -def test_cancel_verification(verify, dummy_data): - stub( - responses.POST, - "https://api.nexmo.com/verify/control/json", - fixture_path='verify/cancel_verification.json', - ) - - response = verify.cancel('asdf') - assert isinstance(response, dict) - assert response['command'] == 'cancel' - assert request_user_agent() == dummy_data.user_agent - assert "cmd=cancel" in request_body() - assert "request_id=asdf" in request_body() - - -@responses.activate -def test_cancel_verification_error(verify): - stub( - responses.POST, - "https://api.nexmo.com/verify/control/json", - fixture_path="verify/control_verification_error.json", - ) - - with pytest.raises(VerifyError) as err: - verify.cancel("asdf") - assert ( - str(err.value) - == "Verify API method failed with status: 6 and error: The requestId 'asdf' does not exist or its no longer active." - ) - - -@responses.activate -def test_trigger_next_verification_event(verify, dummy_data): - stub( - responses.POST, - "https://api.nexmo.com/verify/control/json", - fixture_path='verify/trigger_next_event.json', - ) - - response = verify.trigger_next_event("asdf") - assert isinstance(response, dict) - assert response['command'] == 'trigger_next_event' - assert request_user_agent() == dummy_data.user_agent - assert "cmd=trigger_next_event" in request_body() - assert "request_id=asdf" in request_body() - - -@responses.activate -def test_trigger_next_verification_event_error(verify): - stub( - responses.POST, - "https://api.nexmo.com/verify/control/json", - fixture_path='verify/control_verification_error.json', - ) - - with pytest.raises(VerifyError) as err: - verify.trigger_next_event("asdf") - assert ( - str(err.value) - == "Verify API method failed with status: 6 and error: The requestId 'asdf' does not exist or its no longer active." - ) - - -@responses.activate -def test_start_verification_blacklisted_error_with_network_and_request_id(client, dummy_data): - stub( - responses.POST, - "https://api.nexmo.com/verify/json", - fixture_path="verify/blocked_with_network_and_request_id.json", - ) - - params = {"number": "447525856424", "brand": "MyApp"} - error_msg = "Error code 7: The number you are trying to verify is blocked for verification." - - with pytest.raises(BlockedNumberError, match=error_msg): - response = client.verify.start_verification(params) - assert request_user_agent() == dummy_data.user_agent - assert "number=447525856424" in request_body() - assert "brand=MyApp" in request_body() - assert response["status"] == "7" - assert response["network"] == "25503" - assert response["request_id"] == "12345678" - assert ( - response["error_text"] - == "The number you are trying to verify is blacklisted for verification" - ) - - -@responses.activate -def test_start_psd2_verification(verify, dummy_data): - stub( - responses.POST, - "https://api.nexmo.com/verify/psd2/json", - fixture_path='verify/start_verification.json', - ) - - params = {"number": "447525856424", "brand": "MyApp"} - - assert isinstance(verify.psd2(params), dict) - assert request_user_agent() == dummy_data.user_agent - assert "number=447525856424" in request_body() - assert "brand=MyApp" in request_body() - - -@responses.activate -def test_start_psd2_verification_error(verify): - stub( - responses.POST, - "https://api.nexmo.com/verify/psd2/json", - fixture_path='verify/start_verification_error.json', - ) - params = {"brand": "MyApp"} - - with pytest.raises(VerifyError) as err: - verify.psd2(params) - assert ( - str(err.value) - == 'Verify API method failed with status: 2 and error: Your request is incomplete and missing the mandatory parameter `number`' - ) - - -@responses.activate -def test_start_verification_blacklisted_error_with_network_and_request_id(client): - stub( - responses.POST, - "https://api.nexmo.com/verify/json", - fixture_path="verify/blocked_with_network_and_request_id.json", - ) - - params = {"number": "447525856424", "brand": "MyApp"} - with pytest.raises(BlockedNumberError) as err: - client.verify.start_verification(params) - assert ( - str(err.value) - == 'Error code 7: The number you are trying to verify is blocked for verification.' - ) - - -@responses.activate -def test_start_psd2_verification_blacklisted_error_with_network_and_request_id(client): - stub( - responses.POST, - "https://api.nexmo.com/verify/psd2/json", - fixture_path="verify/blocked_with_network_and_request_id.json", - ) - - params = {"number": "447525856424", "brand": "MyApp"} - - with pytest.raises(BlockedNumberError) as err: - client.verify.psd2(params) - assert ( - str(err.value) - == 'Error code 7: The number you are trying to verify is blocked for verification.' - ) diff --git a/tests/test_verify2.py b/tests/test_verify2.py deleted file mode 100644 index 11f78ce6..00000000 --- a/tests/test_verify2.py +++ /dev/null @@ -1,608 +0,0 @@ -from vonage import Client, Verify2 -from util import * -from vonage.errors import ClientError, Verify2Error - -from pydantic import ValidationError -from pytest import raises -import responses - -verify2 = Verify2(Client()) - - -@responses.activate -def test_new_request_sms_basic(dummy_data): - stub( - responses.POST, - "https://api.nexmo.com/v2/verify", - fixture_path="verify2/create_request.json", - status_code=202, - ) - - params = { - "brand": "ACME, Inc", - "workflow": [{"channel": "sms", "to": "447700900000"}], - } - verify_request = verify2.new_request(params) - - assert request_user_agent() == dummy_data.user_agent - assert verify_request["request_id"] == "c11236f4-00bf-4b89-84ba-88b25df97315" - - -@responses.activate -def test_new_request_sms_full(): - stub( - responses.POST, - "https://api.nexmo.com/v2/verify", - fixture_path="verify2/create_request.json", - status_code=202, - ) - - params = { - "locale": "en-gb", - "channel_timeout": 120, - "client_ref": "my client ref", - "code_length": 10, - "fraud_check": False, - "brand": "ACME, Inc", - "workflow": [ - {"channel": "sms", "to": "447700900000", "app_hash": "asdfghjklqw"} - ], - } - verify_request = verify2.new_request(params) - - assert verify_request["request_id"] == "c11236f4-00bf-4b89-84ba-88b25df97315" - - -@responses.activate -def test_new_request_sms_custom_code(dummy_data): - stub( - responses.POST, - "https://api.nexmo.com/v2/verify", - fixture_path="verify2/create_request.json", - status_code=202, - ) - - params = { - "brand": "ACME, Inc", - "code": "asdfghjk", - "workflow": [{"channel": "sms", "to": "447700900000"}], - } - verify_request = verify2.new_request(params) - - assert request_user_agent() == dummy_data.user_agent - assert verify_request["request_id"] == "c11236f4-00bf-4b89-84ba-88b25df97315" - - -@responses.activate -def test_new_request_error_fraud_check_invalid_account(dummy_data): - stub( - responses.POST, - "https://api.nexmo.com/v2/verify", - fixture_path="verify2/fraud_check_invalid_account.json", - status_code=403, - ) - - params = { - "brand": "ACME, Inc", - "fraud_check": False, - "workflow": [{"channel": "sms", "to": "447700900000"}], - } - - with raises(ClientError) as err: - verify2.new_request(params) - assert "Your account does not have permission to perform this action." in str( - err.value - ) - - -def test_new_request_sms_custom_code_length_error(): - params = { - "code_length": 4, - "brand": "ACME, Inc", - "code": "a", - "workflow": [{"channel": "sms", "to": "447700900000"}], - } - - with raises(ValidationError) as err: - verify2.new_request(params) - assert "String should have at least 4 characters" in str(err.value) - - -def test_new_request_sms_custom_code_character_error(): - params = { - "code_length": 4, - "brand": "ACME, Inc", - "code": "?!@%", - "workflow": [{"channel": "sms", "to": "447700900000"}], - } - - with raises(ValidationError) as err: - verify2.new_request(params) - assert "String should match pattern" in str(err.value) - - -def test_new_request_invalid_channel_error(): - params = { - "code_length": 4, - "brand": "ACME, Inc", - "workflow": [{"channel": "carrier_pigeon", "to": "447700900000"}], - } - - with raises(Verify2Error) as err: - verify2.new_request(params) - assert ( - str(err.value) - == "You must specify a valid verify channel inside the \"workflow\" object, one of: \"['sms', 'whatsapp', 'whatsapp_interactive', 'voice', 'email', 'silent_auth']\"" - ) - - -def test_new_request_code_length_error(): - params = { - "code_length": 1000, - "brand": "ACME, Inc", - "workflow": [{"channel": "sms", "to": "447700900000"}], - } - - with raises(ValidationError) as err: - verify2.new_request(params) - assert "Input should be less than or equal to 10" in str(err.value) - - -def test_new_request_to_error(): - params = { - "brand": "ACME, Inc", - "workflow": [{"channel": "sms", "to": "123"}], - } - - with raises(Verify2Error) as err: - verify2.new_request(params) - assert 'You must specify a valid "to" value for channel "sms"' in str(err.value) - - -def test_new_request_sms_app_hash_error(): - params = { - "brand": "ACME, Inc", - "workflow": [{"channel": "sms", "to": "447700900000", "app_hash": "00"}], - } - - with raises(Verify2Error) as err: - verify2.new_request(params) - assert 'Invalid "app_hash" specified.' in str(err.value) - - -def test_new_request_whatsapp_app_hash_error(): - params = { - "brand": "ACME, Inc", - "workflow": [ - {"channel": "whatsapp", "to": "447700900000", "app_hash": "asdfqwerzxc"} - ], - } - - with raises(Verify2Error) as err: - verify2.new_request(params) - assert ( - str(err.value) - == 'Cannot specify a value for "app_hash" unless using SMS for authentication.' - ) - - -@responses.activate -def test_new_request_whatsapp(): - stub( - responses.POST, - "https://api.nexmo.com/v2/verify", - fixture_path="verify2/create_request.json", - status_code=202, - ) - - params = { - "brand": "ACME, Inc", - "workflow": [{"channel": "whatsapp", "to": "447700900000"}], - } - verify_request = verify2.new_request(params) - - assert verify_request["request_id"] == "c11236f4-00bf-4b89-84ba-88b25df97315" - - -@responses.activate -def test_new_request_whatsapp_custom_code(): - stub( - responses.POST, - "https://api.nexmo.com/v2/verify", - fixture_path="verify2/create_request.json", - status_code=202, - ) - - params = { - "brand": "ACME, Inc", - "code": "asdfghjk", - "workflow": [{"channel": "whatsapp", "to": "447700900000"}], - } - verify_request = verify2.new_request(params) - - assert verify_request["request_id"] == "c11236f4-00bf-4b89-84ba-88b25df97315" - - -@responses.activate -def test_new_request_whatsapp_from_field(): - stub( - responses.POST, - "https://api.nexmo.com/v2/verify", - fixture_path="verify2/create_request.json", - status_code=202, - ) - - params = { - "brand": "ACME, Inc", - "workflow": [ - {"channel": "whatsapp", "to": "447700900000", "from": "447000000000"} - ], - } - verify_request = verify2.new_request(params) - - assert verify_request["request_id"] == "c11236f4-00bf-4b89-84ba-88b25df97315" - - -@responses.activate -def test_new_request_whatsapp_invalid_sender_error(): - stub( - responses.POST, - "https://api.nexmo.com/v2/verify", - fixture_path="verify2/invalid_sender.json", - status_code=422, - ) - - params = { - "brand": "ACME, Inc", - "workflow": [ - {"channel": "whatsapp", "to": "447700900000", "from": "asdfghjkl"} - ], - } - with pytest.raises(Verify2Error) as err: - verify2.new_request(params) - assert str(err.value) == 'You must specify a valid "from" value if included.' - - -@responses.activate -def test_new_request_whatsapp_sender_unregistered_error(): - stub( - responses.POST, - "https://api.nexmo.com/v2/verify", - fixture_path="verify2/invalid_sender.json", - status_code=422, - ) - - params = { - "brand": "ACME, Inc", - "workflow": [ - {"channel": "whatsapp", "to": "447700900000", "from": "447999999999"} - ], - } - with pytest.raises(ClientError) as err: - verify2.new_request(params) - assert "Invalid sender" in str(err.value) - - -@responses.activate -def test_new_request_whatsapp_interactive(): - stub( - responses.POST, - "https://api.nexmo.com/v2/verify", - fixture_path="verify2/create_request.json", - status_code=202, - ) - - params = { - "brand": "ACME, Inc", - "workflow": [{"channel": "whatsapp_interactive", "to": "447700900000"}], - } - verify_request = verify2.new_request(params) - - assert verify_request["request_id"] == "c11236f4-00bf-4b89-84ba-88b25df97315" - - -@responses.activate -def test_new_request_voice(): - stub( - responses.POST, - "https://api.nexmo.com/v2/verify", - fixture_path="verify2/create_request.json", - status_code=202, - ) - - params = { - "brand": "ACME, Inc", - "workflow": [{"channel": "voice", "to": "447700900000"}], - } - verify_request = verify2.new_request(params) - - assert verify_request["request_id"] == "c11236f4-00bf-4b89-84ba-88b25df97315" - - -@responses.activate -def test_new_request_voice_custom_code(): - stub( - responses.POST, - "https://api.nexmo.com/v2/verify", - fixture_path="verify2/create_request.json", - status_code=202, - ) - - params = { - "brand": "ACME, Inc", - "code": "asdfhjkl", - "workflow": [{"channel": "voice", "to": "447700900000"}], - } - verify_request = verify2.new_request(params) - - assert verify_request["request_id"] == "c11236f4-00bf-4b89-84ba-88b25df97315" - - -@responses.activate -def test_new_request_email(): - stub( - responses.POST, - "https://api.nexmo.com/v2/verify", - fixture_path="verify2/create_request.json", - status_code=202, - ) - - params = { - "brand": "ACME, Inc", - "workflow": [{"channel": "email", "to": "recipient@example.com"}], - } - verify_request = verify2.new_request(params) - - assert verify_request["request_id"] == "c11236f4-00bf-4b89-84ba-88b25df97315" - - -@responses.activate -def test_new_request_email_additional_fields(): - stub( - responses.POST, - "https://api.nexmo.com/v2/verify", - fixture_path="verify2/create_request.json", - status_code=202, - ) - - params = { - "locale": "en-gb", - "channel_timeout": 120, - "client_ref": "my client ref", - "code_length": 8, - "brand": "ACME, Inc", - "code": "asdfhjkl", - "workflow": [ - { - "channel": "email", - "to": "recipient@example.com", - "from": "sender@example.com", - } - ], - } - verify_request = verify2.new_request(params) - - assert verify_request["request_id"] == "c11236f4-00bf-4b89-84ba-88b25df97315" - - -@responses.activate -def test_new_request_email_error(): - stub( - responses.POST, - "https://api.nexmo.com/v2/verify", - fixture_path="verify2/invalid_email.json", - status_code=422, - ) - - params = { - "brand": "ACME, Inc", - "workflow": [{"channel": "email", "to": "not-an-email-address"}], - } - with pytest.raises(ClientError) as err: - verify2.new_request(params) - assert "Invalid params" in str(err.value) - - -@responses.activate -def test_new_request_silent_auth(): - stub( - responses.POST, - "https://api.nexmo.com/v2/verify", - fixture_path="verify2/create_request_silent_auth.json", - status_code=202, - ) - - params = { - "brand": "ACME, Inc", - "workflow": [{"channel": "silent_auth", "to": "447700900000"}], - } - verify_request = verify2.new_request(params) - - assert verify_request["request_id"] == "b3a2f4bd-7bda-4e5e-978a-81514702d2ce" - assert ( - verify_request["check_url"] - == "https://api-eu-3.vonage.com/v2/verify/b3a2f4bd-7bda-4e5e-978a-81514702d2ce/silent-auth/redirect" - ) - - -@responses.activate -def test_new_request_error_conflict(): - stub( - responses.POST, - "https://api.nexmo.com/v2/verify", - fixture_path="verify2/error_conflict.json", - status_code=409, - ) - params = { - "brand": "ACME, Inc", - "workflow": [{"channel": "sms", "to": "447700900000"}], - } - - with raises(ClientError) as err: - verify2.new_request(params) - assert "Concurrent verifications to the same number are not allowed." in str( - err.value - ) - - -@responses.activate -def test_new_request_rate_limit(): - stub( - responses.POST, - "https://api.nexmo.com/v2/verify", - fixture_path="verify2/rate_limit.json", - status_code=429, - ) - params = { - "brand": "ACME, Inc", - "workflow": [{"channel": "sms", "to": "447700900000"}], - } - - with raises(ClientError) as err: - verify2.new_request(params) - assert "Rate Limit Hit" in str(err.value) - - -@responses.activate -def test_check_code(): - stub( - responses.POST, - "https://api.nexmo.com/v2/verify/c11236f4-00bf-4b89-84ba-88b25df97315", - fixture_path="verify2/check_code.json", - ) - - response = verify2.check_code("c11236f4-00bf-4b89-84ba-88b25df97315", "1234") - assert response["request_id"] == "e043d872-459b-4750-a20c-d33f91d6959f" - assert response["status"] == "completed" - - -@responses.activate -def test_check_code_invalid_code(): - stub( - responses.POST, - "https://api.nexmo.com/v2/verify/c11236f4-00bf-4b89-84ba-88b25df97315", - fixture_path="verify2/invalid_code.json", - status_code=400, - ) - - with pytest.raises(ClientError) as err: - verify2.check_code("c11236f4-00bf-4b89-84ba-88b25df97315", "5678") - - assert "Invalid Code" in str(err.value) - - -@responses.activate -def test_check_code_already_verified(): - stub( - responses.POST, - "https://api.nexmo.com/v2/verify/c11236f4-00bf-4b89-84ba-88b25df97315", - fixture_path="verify2/already_verified.json", - status_code=404, - ) - - with pytest.raises(ClientError) as err: - verify2.check_code("c11236f4-00bf-4b89-84ba-88b25df97315", "5678") - - assert "Not Found" in str(err.value) - - -@responses.activate -def test_check_code_workflow_not_supported(): - stub( - responses.POST, - "https://api.nexmo.com/v2/verify/c11236f4-00bf-4b89-84ba-88b25df97315", - fixture_path="verify2/code_not_supported.json", - status_code=409, - ) - - with pytest.raises(ClientError) as err: - verify2.check_code("c11236f4-00bf-4b89-84ba-88b25df97315", "5678") - - assert "The current Verify workflow step does not support a code." in str(err.value) - - -@responses.activate -def test_check_code_too_many_invalid_code_attempts(): - stub( - responses.POST, - "https://api.nexmo.com/v2/verify/c11236f4-00bf-4b89-84ba-88b25df97315", - fixture_path="verify2/too_many_code_attempts.json", - status_code=410, - ) - - with pytest.raises(ClientError) as err: - verify2.check_code("c11236f4-00bf-4b89-84ba-88b25df97315", "5678") - - assert "Invalid Code" in str(err.value) - - -@responses.activate -def test_check_code_rate_limit(): - stub( - responses.POST, - "https://api.nexmo.com/v2/verify/c11236f4-00bf-4b89-84ba-88b25df97315", - fixture_path="verify2/rate_limit.json", - status_code=429, - ) - - with raises(ClientError) as err: - verify2.check_code("c11236f4-00bf-4b89-84ba-88b25df97315", "5678") - assert "Rate Limit Hit" in str(err.value) - - -@responses.activate -def test_cancel_verification(): - stub( - responses.DELETE, - "https://api.nexmo.com/v2/verify/c11236f4-00bf-4b89-84ba-88b25df97315", - fixture_path="no_content.json", - status_code=204, - ) - - assert verify2.cancel_verification("c11236f4-00bf-4b89-84ba-88b25df97315") == None - - -@responses.activate -def test_cancel_verification_error_not_found(): - stub( - responses.DELETE, - "https://api.nexmo.com/v2/verify/c11236f4-00bf-4b89-84ba-88b25df97315", - fixture_path="verify2/request_not_found.json", - status_code=404, - ) - - with raises(ClientError) as err: - verify2.cancel_verification("c11236f4-00bf-4b89-84ba-88b25df97315") - assert "Not Found" in str(err.value) - - -@responses.activate -def test_new_request_multiple_workflows(): - stub( - responses.POST, - "https://api.nexmo.com/v2/verify", - fixture_path="verify2/create_request.json", - status_code=202, - ) - - params = { - "brand": "ACME, Inc", - "workflow": [ - {"channel": "whatsapp_interactive", "to": "447700900000"}, - {"channel": "sms", "to": "4477009999999"}, - ], - } - verify_request = verify2.new_request(params) - - assert verify_request["request_id"] == "c11236f4-00bf-4b89-84ba-88b25df97315" - - -def test_remove_unnecessary_fraud_check(): - params = { - "brand": "ACME, Inc", - "workflow": [{"channel": "sms", "to": "447700900000"}], - "fraud_check": True, - } - verify2._remove_unnecessary_fraud_check(params) - - assert "fraud_check" not in params diff --git a/tests/test_video.py b/tests/test_video.py deleted file mode 100644 index e710994c..00000000 --- a/tests/test_video.py +++ /dev/null @@ -1,679 +0,0 @@ -from util import * -from vonage import Client -from vonage.errors import ( - ClientError, - InvalidRoleError, - TokenExpiryError, - InvalidOptionsError, - SipError, - InvalidInputError, -) - -import jwt -from time import time - - -session_id = 'my_session_id' -stream_id = 'my_stream_id' -connection_id = '1234-5678' -archive_id = '1234-abcd' -broadcast_id = '1748b7070a81464c9759c46ad10d3734' - - -@responses.activate -def test_create_default_session(client: Client, dummy_data): - stub( - responses.POST, - "https://video.api.vonage.com/session/create", - fixture_path="video/create_session.json", - ) - - session_info = client.video.create_session() - assert isinstance(session_info, dict) - assert request_user_agent() == dummy_data.user_agent - assert session_info['session_id'] == session_id - assert session_info['archive_mode'] == 'manual' - assert session_info['media_mode'] == 'routed' - assert session_info['location'] == None - - -@responses.activate -def test_create_session_custom_archive_mode_and_location(client: Client): - stub( - responses.POST, - "https://video.api.vonage.com/session/create", - fixture_path="video/create_session.json", - ) - - session_options = {'archive_mode': 'always', 'location': '192.0.1.1', 'media_mode': 'routed'} - session_info = client.video.create_session(session_options) - assert isinstance(session_info, dict) - assert session_info['session_id'] == session_id - assert session_info['archive_mode'] == 'always' - assert session_info['media_mode'] == 'routed' - assert session_info['location'] == '192.0.1.1' - - -@responses.activate -def test_create_session_custom_media_mode(client: Client): - stub( - responses.POST, - "https://video.api.vonage.com/session/create", - fixture_path="video/create_session.json", - ) - - session_options = {'media_mode': 'relayed'} - session_info = client.video.create_session(session_options) - assert isinstance(session_info, dict) - assert session_info['session_id'] == session_id - assert session_info['archive_mode'] == 'manual' - assert session_info['media_mode'] == 'relayed' - assert session_info['location'] == None - - -def test_create_session_invalid_archive_mode(client: Client): - session_options = {'archive_mode': 'invalid_option'} - with pytest.raises(InvalidOptionsError) as excinfo: - client.video.create_session(session_options) - assert 'Invalid archive_mode value. Must be one of ' in str(excinfo.value) - - -def test_create_session_invalid_media_mode(client: Client): - session_options = {'media_mode': 'invalid_option'} - with pytest.raises(InvalidOptionsError) as excinfo: - client.video.create_session(session_options) - assert 'Invalid media_mode value. Must be one of ' in str(excinfo.value) - - -def test_create_session_invalid_mode_combination(client: Client): - session_options = {'archive_mode': 'always', 'media_mode': 'relayed'} - with pytest.raises(InvalidOptionsError) as excinfo: - client.video.create_session(session_options) - assert ( - str(excinfo.value) - == 'Invalid combination: cannot specify "archive_mode": "always" and "media_mode": "relayed".' - ) - - -def test_generate_client_token_all_defaults(client: Client): - token = client.video.generate_client_token(session_id) - decoded_token = jwt.decode(token, algorithms='RS256', options={'verify_signature': False}) - assert decoded_token['application_id'] == 'nexmo-application-id' - assert decoded_token['scope'] == 'session.connect' - assert decoded_token['session_id'] == 'my_session_id' - assert decoded_token['role'] == 'publisher' - assert decoded_token['initial_layout_class_list'] == '' - - -def test_generate_client_token_custom_options(client: Client): - now = int(time()) - token_options = { - 'role': 'moderator', - 'data': 'some token data', - 'initialLayoutClassList': ['1234', '5678', '9123'], - 'expireTime': now + 60, - 'jti': 1234, - 'iat': now, - 'subject': 'test_subject', - 'acl': ['1', '2', '3'], - } - - token = client.video.generate_client_token(session_id, token_options) - decoded_token = jwt.decode(token, algorithms='RS256', options={'verify_signature': False}) - assert decoded_token['application_id'] == 'nexmo-application-id' - assert decoded_token['scope'] == 'session.connect' - assert decoded_token['session_id'] == 'my_session_id' - assert decoded_token['role'] == 'moderator' - assert decoded_token['initial_layout_class_list'] == ['1234', '5678', '9123'] - assert decoded_token['data'] == 'some token data' - assert decoded_token['jti'] == 1234 - assert decoded_token['subject'] == 'test_subject' - assert decoded_token['acl'] == ['1', '2', '3'] - - -def test_check_client_token_headers(client: Client): - token = client.video.generate_client_token(session_id) - headers = jwt.get_unverified_header(token) - assert headers['alg'] == 'RS256' - assert headers['typ'] == 'JWT' - - -def test_generate_client_token_invalid_role(client: Client): - with pytest.raises(InvalidRoleError): - client.video.generate_client_token(session_id, {'role': 'observer'}) - - -def test_generate_client_token_invalid_expire_time(client: Client): - now = int(time()) - with pytest.raises(TokenExpiryError): - client.video.generate_client_token(session_id, {'expireTime': now + 3600 * 24 * 30 + 1}) - - -@responses.activate -def test_get_stream(client: Client): - stub( - responses.GET, - f"https://video.api.vonage.com/v2/project/{client.application_id}/session/{session_id}/stream/{stream_id}", - fixture_path="video/get_stream.json", - ) - - stream = client.video.get_stream(session_id, stream_id) - assert isinstance(stream, dict) - assert stream['videoType'] == 'camera' - - -@responses.activate -def test_list_streams( - client: Client, -): - stub( - responses.GET, - f"https://video.api.vonage.com/v2/project/{client.application_id}/session/{session_id}/stream", - fixture_path="video/list_streams.json", - ) - - stream_list = client.video.list_streams(session_id) - assert isinstance(stream_list, dict) - assert stream_list['items'][0]['videoType'] == 'camera' - - -@responses.activate -def test_change_stream_layout(client: Client): - stub( - responses.PUT, - f"https://video.api.vonage.com/v2/project/{client.application_id}/session/{session_id}/stream", - ) - - items = [{'id': 'stream-1234', 'layoutClassList': ["full"]}] - - assert isinstance(client.video.set_stream_layout(session_id, items), dict) - assert request_content_type() == "application/json" - - -@responses.activate -def test_send_signal_to_all_participants(client: Client): - stub( - responses.POST, - f"https://video.api.vonage.com/v2/project/{client.application_id}/session/{session_id}/signal", - ) - - assert isinstance( - client.video.send_signal(session_id, type='chat', data='hello from a test case'), dict - ) - assert request_content_type() == "application/json" - - -@responses.activate -def test_send_signal_to_single_participant(client: Client): - stub( - responses.POST, - f"https://video.api.vonage.com/v2/project/{client.application_id}/session/{session_id}/connection/{connection_id}/signal", - ) - - assert isinstance( - client.video.send_signal( - session_id, type='chat', data='hello from a test case', connection_id=connection_id - ), - dict, - ) - assert request_content_type() == "application/json" - - -@responses.activate -def test_disconnect_client(client: Client): - stub( - responses.DELETE, - f"https://video.api.vonage.com/v2/project/{client.application_id}/session/{session_id}/connection/{connection_id}", - ) - - assert isinstance(client.video.disconnect_client(session_id, connection_id=connection_id), dict) - - -@responses.activate -def test_mute_specific_stream(client: Client): - stub( - responses.POST, - f"https://video.api.vonage.com/v2/project/{client.application_id}/session/{session_id}/stream/{stream_id}/mute", - fixture_path="video/mute_specific_stream.json", - ) - - response = client.video.mute_stream(session_id, stream_id) - assert isinstance(response, dict) - assert response['createdAt'] == 1414642898000 - - -@responses.activate -def test_mute_all_streams(client: Client): - stub( - responses.POST, - f"https://video.api.vonage.com/v2/project/{client.application_id}/session/{session_id}/mute", - fixture_path="video/mute_multiple_streams.json", - ) - - response = client.video.mute_all_streams(session_id) - assert isinstance(response, dict) - assert response['createdAt'] == 1414642898000 - - -@responses.activate -def test_mute_all_streams_except_excluded_list(client: Client): - stub( - responses.POST, - f"https://video.api.vonage.com/v2/project/{client.application_id}/session/{session_id}/mute", - fixture_path="video/mute_multiple_streams.json", - ) - - response = client.video.mute_all_streams( - session_id, excluded_stream_ids=['excluded_stream_id_1', 'excluded_stream_id_2'] - ) - assert isinstance(response, dict) - assert response['createdAt'] == 1414642898000 - - -@responses.activate -def test_disable_mute_all_streams(client: Client): - stub( - responses.POST, - f"https://video.api.vonage.com/v2/project/{client.application_id}/session/{session_id}/mute", - fixture_path="video/disable_mute_multiple_streams.json", - ) - - response = client.video.disable_mute_all_streams( - session_id, excluded_stream_ids=['excluded_stream_id_1', 'excluded_stream_id_2'] - ) - assert isinstance(response, dict) - assert ( - request_body() - == b'{"active": false, "excludedStreamIds": ["excluded_stream_id_1", "excluded_stream_id_2"]}' - ) - assert response['createdAt'] == 1414642898000 - - -@responses.activate -def test_list_archives_with_filters_applied(client: Client): - stub( - responses.GET, - f"https://video.api.vonage.com/v2/project/{client.application_id}/archive", - fixture_path="video/list_archives.json", - ) - - response = client.video.list_archives(offset=0, count=1, session_id=session_id) - assert isinstance(response, dict) - assert response['items'][0]['createdAt'] == 1384221730000 - assert response['items'][0]['streams'][0]['streamId'] == 'abc123' - - -@responses.activate -def test_create_new_archive(client: Client): - stub( - responses.POST, - f"https://video.api.vonage.com/v2/project/{client.application_id}/archive", - fixture_path="video/create_archive.json", - ) - - response = client.video.create_archive( - session_id=session_id, name='my_new_archive', outputMode='individual' - ) - assert isinstance(response, dict) - assert response['name'] == 'my_new_archive' - assert response['createdAt'] == 1384221730555 - - -@responses.activate -def test_get_archive(client: Client): - stub( - responses.GET, - f"https://video.api.vonage.com/v2/project/{client.application_id}/archive/{archive_id}", - fixture_path="video/get_archive.json", - ) - - response = client.video.get_archive(archive_id=archive_id) - assert isinstance(response, dict) - assert response['duration'] == 5049 - assert response['size'] == 247748791 - assert response['streams'] == [] - - -@responses.activate -def test_delete_archive(client: Client): - stub( - responses.GET, - f"https://video.api.vonage.com/v2/project/{client.application_id}/archive/{archive_id}", - status_code=204, - fixture_path='no_content.json', - ) - - assert client.video.delete_archive(archive_id=archive_id) == None - - -@responses.activate -def test_add_stream_to_archive(client: Client): - stub( - responses.PATCH, - f"https://video.api.vonage.com/v2/project/{client.application_id}/archive/{archive_id}/streams", - status_code=204, - fixture_path='no_content.json', - ) - - assert ( - client.video.add_stream_to_archive( - archive_id=archive_id, stream_id='1234', has_audio=True, has_video=True - ) - == None - ) - - -@responses.activate -def test_remove_stream_from_archive(client: Client): - stub( - responses.PATCH, - f"https://video.api.vonage.com/v2/project/{client.application_id}/archive/{archive_id}/streams", - status_code=204, - fixture_path='no_content.json', - ) - - assert client.video.remove_stream_from_archive(archive_id=archive_id, stream_id='1234') == None - - -@responses.activate -def test_stop_archive(client: Client): - stub( - responses.POST, - f"https://video.api.vonage.com/v2/project/{client.application_id}/archive/{archive_id}/stop", - fixture_path="video/stop_archive.json", - ) - - response = client.video.stop_archive(archive_id=archive_id) - assert response['name'] == 'my_new_archive' - assert response['createdAt'] == 1384221730555 - assert response['status'] == 'stopped' - - -@responses.activate -def test_change_archive_layout(client: Client): - stub( - responses.PUT, - f"https://video.api.vonage.com/v2/project/{client.application_id}/archive/{archive_id}/layout", - ) - - params = {'type': 'bestFit', 'screenshareType': 'horizontalPresentation'} - - assert isinstance(client.video.change_archive_layout(archive_id, params), dict) - assert request_content_type() == "application/json" - - -@responses.activate -def test_create_sip_call(client): - stub( - responses.POST, - f'https://video.api.vonage.com/v2/project/{client.application_id}/dial', - fixture_path='video/create_sip_call.json', - ) - - sip = {'uri': 'sip:user@sip.partner.com;transport=tls'} - - sip_call = client.video.create_sip_call(session_id, 'my_token', sip) - assert sip_call['id'] == 'b0a5a8c7-dc38-459f-a48d-a7f2008da853' - assert sip_call['connectionId'] == 'e9f8c166-6c67-440d-994a-04fb6dfed007' - assert sip_call['streamId'] == '482bce73-f882-40fd-8ca5-cb74ff416036' - - -@responses.activate -def test_create_sip_call_not_found_error(client): - stub( - responses.POST, - f'https://video.api.vonage.com/v2/project/{client.application_id}/dial', - status_code=404, - ) - sip = {'uri': 'sip:user@sip.partner.com;transport=tls'} - with pytest.raises(ClientError): - client.video.create_sip_call('an-invalid-session-id', 'my_token', sip) - - -def test_create_sip_call_no_uri_error(client): - sip = {} - with pytest.raises(SipError) as err: - client.video.create_sip_call(session_id, 'my_token', sip) - - assert str(err.value) == 'You must specify a uri when creating a SIP call.' - - -@responses.activate -def test_play_dtmf(client): - stub( - responses.POST, - f'https://video.api.vonage.com/v2/project/{client.application_id}/session/{session_id}/play-dtmf', - fixture_path='video/null.json', - ) - - assert client.video.play_dtmf(session_id, '1234') == None - - -@responses.activate -def test_play_dtmf_specific_connection(client): - stub( - responses.POST, - f'https://video.api.vonage.com/v2/project/{client.application_id}/session/{session_id}/connection/my-connection-id/play-dtmf', - fixture_path='video/null.json', - ) - - assert client.video.play_dtmf(session_id, '1234', connection_id='my-connection-id') == None - - -@responses.activate -def test_play_dtmf_invalid_session_id_error(client): - stub( - responses.POST, - f'https://video.api.vonage.com/v2/project/{client.application_id}/session/{session_id}/play-dtmf', - fixture_path='video/play_dtmf_invalid_error.json', - status_code=400, - ) - - with pytest.raises(ClientError) as err: - client.video.play_dtmf(session_id, '1234') - assert 'One of the properties digits or sessionId is invalid.' in str(err.value) - - -def test_play_dtmf_invalid_input_error(client): - with pytest.raises(InvalidInputError) as err: - client.video.play_dtmf(session_id, '!@£$%^&()asdfghjkl;') - - assert str(err.value) == 'Only digits 0-9, *, #, and "p" are allowed.' - - -@responses.activate -def test_list_broadcasts(client): - stub( - responses.GET, - f'https://video.api.vonage.com/v2/project/{client.application_id}/broadcast', - fixture_path='video/list_broadcasts.json', - ) - - broadcasts = client.video.list_broadcasts() - assert broadcasts['count'] == '1' - assert broadcasts['items'][0]['id'] == '1748b7070a81464c9759c46ad10d3734' - assert broadcasts['items'][0]['applicationId'] == 'abc123' - - -@responses.activate -def test_list_broadcasts_options(client): - stub( - responses.GET, - f'https://video.api.vonage.com/v2/project/{client.application_id}/broadcast', - fixture_path='video/list_broadcasts.json', - ) - - broadcasts = client.video.list_broadcasts( - count=1, session_id='2_MX4xMDBfjE0Mzc2NzY1NDgwMTJ-TjMzfn4' - ) - assert broadcasts['count'] == '1' - assert broadcasts['items'][0]['sessionId'] == '2_MX4xMDBfjE0Mzc2NzY1NDgwMTJ-TjMzfn4' - assert broadcasts['items'][0]['id'] == '1748b7070a81464c9759c46ad10d3734' - assert broadcasts['items'][0]['applicationId'] == 'abc123' - - -@responses.activate -def test_list_broadcasts_invalid_options_errors(client): - stub( - responses.GET, - f'https://video.api.vonage.com/v2/project/{client.application_id}/broadcast', - fixture_path='video/list_broadcasts.json', - ) - - with pytest.raises(InvalidOptionsError) as err: - client.video.list_broadcasts(offset=-2, session_id='2_MX4xMDBfjE0Mzc2NzY1NDgwMTJ-TjMzfn4') - assert str(err.value) == 'Offset must be an int >= 0.' - - with pytest.raises(InvalidOptionsError) as err: - client.video.list_broadcasts(count=9999, session_id='2_MX4xMDBfjE0Mzc2NzY1NDgwMTJ-TjMzfn4') - assert str(err.value) == 'Count must be an int between 0 and 1000.' - - with pytest.raises(InvalidOptionsError) as err: - client.video.list_broadcasts(offset='10', session_id='2_MX4xMDBfjE0Mzc2NzY1NDgwMTJ-TjMzfn4') - assert str(err.value) == 'Offset must be an int >= 0.' - - -@responses.activate -def test_start_broadcast_required_params(client): - stub( - responses.POST, - f'https://video.api.vonage.com/v2/project/{client.application_id}/broadcast', - fixture_path='video/broadcast.json', - ) - - params = { - "sessionId": "2_MX40NTMyODc3Mn5-fg", - "outputs": { - "rtmp": [ - { - "id": "foo", - "serverUrl": "rtmps://myfooserver/myfooapp", - "streamName": "myfoostream", - } - ] - }, - } - - broadcast = client.video.start_broadcast(params) - assert broadcast['id'] == '1748b7070a81464c9759c46ad10d3734' - assert broadcast['createdAt'] == 1437676551000 - assert broadcast['maxBitrate'] == 2000000 - assert broadcast['broadcastUrls']['rtmp'][0]['id'] == 'abc123' - - -@responses.activate -def test_start_broadcast_all_params(client): - stub( - responses.POST, - f'https://video.api.vonage.com/v2/project/{client.application_id}/broadcast', - fixture_path='video/broadcast.json', - ) - - params = { - "sessionId": "2_MX40NTMyODc3Mn5-fg", - "layout": { - "type": "custom", - "stylesheet": "the layout stylesheet (only used with type == custom)", - "screenshareType": "horizontalPresentation", - }, - "maxDuration": 5400, - "outputs": { - "rtmp": [ - { - "id": "foo", - "serverUrl": "rtmps://myfooserver/myfooapp", - "streamName": "myfoostream", - } - ] - }, - "resolution": "1920x1080", - "streamMode": "manual", - "multiBroadcastTag": "foo", - } - - broadcast = client.video.start_broadcast(params) - assert broadcast['id'] == '1748b7070a81464c9759c46ad10d3734' - assert broadcast['createdAt'] == 1437676551000 - assert broadcast['maxBitrate'] == 2000000 - assert broadcast['broadcastUrls']['rtmp'][0]['id'] == 'abc123' - - -@responses.activate -def test_get_broadcast(client): - stub( - responses.GET, - f'https://video.api.vonage.com/v2/project/{client.application_id}/broadcast/{broadcast_id}', - fixture_path='video/broadcast.json', - ) - - broadcast = client.video.get_broadcast(broadcast_id) - assert broadcast['id'] == '1748b7070a81464c9759c46ad10d3734' - assert broadcast['sessionId'] == '2_MX4xMDBfjE0Mzc2NzY1NDgwMTJ-TjMzfn4' - assert broadcast['updatedAt'] == 1437676551000 - assert broadcast['resolution'] == '640x480' - - -@responses.activate -def test_stop_broadcast(client): - stub( - responses.POST, - f'https://video.api.vonage.com/v2/project/{client.application_id}/broadcast/{broadcast_id}', - fixture_path='video/broadcast.json', - ) - - broadcast = client.video.stop_broadcast(broadcast_id) - assert broadcast['id'] == '1748b7070a81464c9759c46ad10d3734' - assert broadcast['sessionId'] == '2_MX4xMDBfjE0Mzc2NzY1NDgwMTJ-TjMzfn4' - assert broadcast['updatedAt'] == 1437676551000 - assert broadcast['resolution'] == '640x480' - - -@responses.activate -def test_change_broadcast_layout(client): - stub( - responses.PUT, - f'https://video.api.vonage.com/v2/project/{client.application_id}/broadcast/{broadcast_id}/layout', - fixture_path='video/null.json', - ) - - params = { - "type": "bestFit", - "stylesheet": "stream.instructor {position: absolute; width: 100%; height:50%;}", - "screenshareType": "pip", - } - - assert client.video.change_broadcast_layout(broadcast_id, params) == None - - -@responses.activate -def test_add_stream_to_broadcast(client: Client, dummy_data): - stub( - responses.PATCH, - f"https://video.api.vonage.com/v2/project/{client.application_id}/broadcast/{broadcast_id}/streams", - status_code=204, - fixture_path='no_content.json', - ) - - assert ( - client.video.add_stream_to_broadcast( - broadcast_id=broadcast_id, stream_id='1234', has_audio=True, has_video=True - ) - == None - ) - assert request_user_agent() == dummy_data.user_agent - - -@responses.activate -def test_remove_stream_from_broadcast(client: Client, dummy_data): - stub( - responses.PATCH, - f"https://video.api.vonage.com/v2/project/{client.application_id}/broadcast/{broadcast_id}/streams", - status_code=204, - fixture_path='no_content.json', - ) - - assert ( - client.video.remove_stream_from_broadcast(broadcast_id=broadcast_id, stream_id='1234') - == None - ) - assert request_user_agent() == dummy_data.user_agent diff --git a/tests/test_voice.py b/tests/test_voice.py deleted file mode 100644 index d2d165f8..00000000 --- a/tests/test_voice.py +++ /dev/null @@ -1,227 +0,0 @@ -import os.path -import time -import jwt -from unittest.mock import patch - -from vonage import Client, Voice, Ncco -from util import * - - -@responses.activate -def test_create_call(voice, dummy_data): - stub(responses.POST, "https://api.nexmo.com/v1/calls") - - params = { - "to": [{"type": "phone", "number": "14843331234"}], - "from": {"type": "phone", "number": "14843335555"}, - "answer_url": ["https://example.com/answer"], - } - - assert isinstance(voice.create_call(params), dict) - assert request_user_agent() == dummy_data.user_agent - assert request_content_type() == "application/json" - - -@responses.activate -def test_params_with_random_number(voice, dummy_data): - stub(responses.POST, "https://api.nexmo.com/v1/calls") - - params = { - "to": [{"type": "phone", "number": "14843331234"}], - "random_from_number": True, - "answer_url": ["https://example.com/answer"], - } - - assert isinstance(voice.create_call(params), dict) - assert request_user_agent() == dummy_data.user_agent - assert request_content_type() == "application/json" - - -@responses.activate -def test_create_call_with_ncco_builder(voice, dummy_data): - stub(responses.POST, "https://api.nexmo.com/v1/calls") - - talk = Ncco.Talk( - text="Hello from Vonage!", - bargeIn=True, - loop=3, - level=0.5, - language="en-GB", - style=1, - premium=True, - ) - ncco = Ncco.build_ncco(talk) - voice.create_call( - { - "to": [{"type": "phone", "number": "447449815316"}], - "from": {"type": "phone", "number": "447418370240"}, - "ncco": ncco, - } - ) - assert ( - request_body() - == b'{"to": [{"type": "phone", "number": "447449815316"}], "from": {"type": "phone", "number": "447418370240"}, "ncco": [{"action": "talk", "text": "Hello from Vonage!", "bargeIn": true, "loop": 3, "level": 0.5, "language": "en-GB", "style": 1, "premium": true}]}' - ) - assert request_user_agent() == dummy_data.user_agent - assert request_content_type() == "application/json" - - -@responses.activate -def test_get_calls(voice, dummy_data): - stub(responses.GET, "https://api.nexmo.com/v1/calls") - - assert isinstance(voice.get_calls(), dict) - assert request_user_agent() == dummy_data.user_agent - assert_re(r"\ABearer ", request_authorization()) - - -@responses.activate -def test_get_call(voice, dummy_data): - stub(responses.GET, "https://api.nexmo.com/v1/calls/xx-xx-xx-xx") - - assert isinstance(voice.get_call("xx-xx-xx-xx"), dict) - assert request_user_agent() == dummy_data.user_agent - assert_re(r"\ABearer ", request_authorization()) - - -@responses.activate -def test_update_call(voice, dummy_data): - stub(responses.PUT, "https://api.nexmo.com/v1/calls/xx-xx-xx-xx") - - assert isinstance(voice.update_call("xx-xx-xx-xx", action="hangup"), dict) - assert request_user_agent() == dummy_data.user_agent - assert request_content_type() == "application/json" - assert request_body() == b'{"action": "hangup"}' - - -@responses.activate -def test_send_audio(voice, dummy_data): - stub(responses.PUT, "https://api.nexmo.com/v1/calls/xx-xx-xx-xx/stream") - - assert isinstance( - voice.send_audio("xx-xx-xx-xx", stream_url="http://example.com/audio.mp3"), - dict, - ) - assert request_user_agent() == dummy_data.user_agent - assert request_content_type() == "application/json" - assert request_body() == b'{"stream_url": "http://example.com/audio.mp3"}' - - -@responses.activate -def test_stop_audio(voice, dummy_data): - stub(responses.DELETE, "https://api.nexmo.com/v1/calls/xx-xx-xx-xx/stream") - - assert isinstance(voice.stop_audio("xx-xx-xx-xx"), dict) - assert request_user_agent() == dummy_data.user_agent - - -@responses.activate -def test_send_speech(voice, dummy_data): - stub(responses.PUT, "https://api.nexmo.com/v1/calls/xx-xx-xx-xx/talk") - - assert isinstance(voice.send_speech("xx-xx-xx-xx", text="Hello"), dict) - assert request_user_agent() == dummy_data.user_agent - assert request_content_type() == "application/json" - assert request_body() == b'{"text": "Hello"}' - - -@responses.activate -def test_stop_speech(voice, dummy_data): - stub(responses.DELETE, "https://api.nexmo.com/v1/calls/xx-xx-xx-xx/talk") - - assert isinstance(voice.stop_speech("xx-xx-xx-xx"), dict) - assert request_user_agent() == dummy_data.user_agent - - -@responses.activate -def test_send_dtmf(voice, dummy_data): - stub(responses.PUT, "https://api.nexmo.com/v1/calls/xx-xx-xx-xx/dtmf") - - assert isinstance(voice.send_dtmf("xx-xx-xx-xx", digits="1234"), dict) - assert request_user_agent() == dummy_data.user_agent - assert request_content_type() == "application/json" - assert request_body() == b'{"digits": "1234"}' - - -@responses.activate -def test_user_provided_authorization(dummy_data): - stub(responses.GET, "https://api.nexmo.com/v1/calls/xx-xx-xx-xx") - - application_id = "different-application-id" - client = Client(application_id=application_id, private_key=dummy_data.private_key) - - nbf = int(time.time()) - exp = nbf + 3600 - - client.auth(nbf=nbf, exp=exp) - client.voice.get_call("xx-xx-xx-xx") - - token = request_authorization().split()[1] - - token = jwt.decode(token, dummy_data.public_key, algorithms="RS256") - print(token) - assert token["application_id"] == application_id - assert token["nbf"] == nbf - assert token["exp"] == exp - - -@responses.activate -def test_authorization_with_private_key_path(dummy_data): - stub(responses.GET, "https://api.nexmo.com/v1/calls/xx-xx-xx-xx") - - private_key = os.path.join(os.path.dirname(__file__), "data/private_key.txt") - - client = Client( - key=dummy_data.api_key, - secret=dummy_data.api_secret, - application_id=dummy_data.application_id, - private_key=private_key, - ) - voice = Voice(client) - voice.get_call("xx-xx-xx-xx") - - token = jwt.decode( - request_authorization().split()[1], dummy_data.public_key, algorithms="RS256" - ) - assert token["application_id"] == dummy_data.application_id - - -@responses.activate -def test_authorization_with_private_key_object(voice, dummy_data): - stub(responses.GET, "https://api.nexmo.com/v1/calls/xx-xx-xx-xx") - - voice.get_call("xx-xx-xx-xx") - - token = jwt.decode( - request_authorization().split()[1], dummy_data.public_key, algorithms="RS256" - ) - assert token["application_id"] == dummy_data.application_id - - -@responses.activate -def test_get_recording(voice, dummy_data): - stub_bytes( - responses.GET, - "https://api.nexmo.com/v1/files/d6e47a2e-3414-11e8-8c2c-2f8b643ed957", - body=b"THISISANMP3", - ) - - assert isinstance( - voice.get_recording( - "https://api.nexmo.com/v1/files/d6e47a2e-3414-11e8-8c2c-2f8b643ed957" - ), - str, - ) - assert request_user_agent() == dummy_data.user_agent - - -def test_verify_jwt_signature(voice: Voice): - with patch("vonage.Voice.verify_signature") as mocked_verify_signature: - mocked_verify_signature.return_value = True - assert voice.verify_signature("valid_token", "valid_signature") - - -def test_verify_jwt_invalid_signature(voice: Voice): - with patch("vonage.Voice.verify_signature") as mocked_verify_signature: - mocked_verify_signature.return_value = False - assert voice.verify_signature("token", "invalid_signature") is False