Skip to content

Commit

Permalink
Merge pull request #174 from plivo/fix-tests
Browse files Browse the repository at this point in the history
Fix tests-cases
  • Loading branch information
huzaif-plivo authored Jul 16, 2021
2 parents 3b0052a + 291a827 commit 63e2c8f
Show file tree
Hide file tree
Showing 39 changed files with 199 additions and 111 deletions.
32 changes: 32 additions & 0 deletions .github/workflows/unitTests.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
name: UnitTests

on:
push:
branches: [ master ]
pull_request:
branches: [ master ]

jobs:
build:
name: UnitTests
runs-on: ubuntu-latest
strategy:
matrix:
python-version: [2.7, 3.5, 3.6, 3.7]

steps:
- name: Checkout
uses: actions/checkout@v2
- name: Set up Python ${{ matrix.python-version }}
uses: actions/setup-python@v2
with:
python-version: ${{ matrix.python-version }}
- name: Display Python version
run: python -c "import sys; print(sys.version)"
- name: Dependencies Installation
run: |
pip install tox
- name: Run Tests
run: |
python --version
tox -e py
7 changes: 7 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,12 @@
# Change Log

## [4.18.1](https://github.com/plivo/plivo-python/tree/v4.18.1) (2021-07-16)
- Updates to [add a member a multi-party call API](https://www.plivo.com/docs/voice/api/multiparty-call/participants#add-a-participant).
- Remove validation range for `delay` and `ringtimeout` parameters.
- Add appropriate error message for multiple `ringtimeout` and `delaydial` values.
- Fix the agent limit validation bug so that it only checks when multiple `to` param values are supplied.
- Fix the multiparty call and other voice API UT's.

## [4.18.0](https://github.com/plivo/plivo-python/tree/v4.18.0) (2021-07-13)
- Power pack ID has been included to the response for the [list all messages API](https://www.plivo.com/docs/sms/api/message/list-all-messages/) and the [get message details API](https://www.plivo.com/docs/sms/api/message#retrieve-a-message).
- Support for filtering messages by Power pack ID has been added to the [list all messages API](https://www.plivo.com/docs/sms/api/message#list-all-messages).
Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# plivo-python

[![Build Status](https://travis-ci.org/plivo/plivo-python.svg?branch=master)](https://travis-ci.org/plivo/plivo-python)
[![UnitTests](https://github.com/plivo/plivo-python/actions/workflows/unitTests.yml/badge.svg?branch=master)](https://github.com/plivo/plivo-python/actions/workflows/unitTests.yml)
[![PyPI](https://img.shields.io/pypi/v/plivo.svg)](https://pypi.python.org/pypi/plivo)
[![PyPI](https://img.shields.io/pypi/pyversions/plivo.svg)](https://pypi.python.org/pypi/plivo)
[![PyPI](https://img.shields.io/pypi/l/plivo.svg)](https://pypi.python.org/pypi/plivo)
Expand Down
12 changes: 8 additions & 4 deletions plivo/resources/multipartycall.py
Original file line number Diff line number Diff line change
Expand Up @@ -228,8 +228,8 @@ def get(self, uuid=None, friendly_name=None):
of_type_exact(str),
one_of(is_url(), is_in(('real', 'none'), case_sensitive=False, case_type='lower')),
)],
ring_timeout=[optional(one_of(of_type_exact(str), of_type_exact(int)), multiple_valid_integers(15, 120))],
delay_dial=[optional(one_of(of_type_exact(str), of_type_exact(int)), multiple_valid_integers(0, 120))],
ring_timeout=[optional(one_of(of_type_exact(str), of_type_exact(int)), multiple_valid_integers())],
delay_dial=[optional(one_of(of_type_exact(str), of_type_exact(int)), multiple_valid_integers())],
max_duration=[optional(
of_type_exact(int),
check(lambda max_duration: 300 <= max_duration <= 28800, '300 < max_duration <= 28800'))],
Expand Down Expand Up @@ -331,10 +331,14 @@ def add_participant(self,
raise ValidationError('specify either call_uuid or (from, to)')
if call_uuid is None and (not from_ or not to_):
raise ValidationError('specify (from, to) when not adding an existing call_uuid to multi party participant')
if len(to_.split('<')) > 1 and role.lower() != "agent":
if to_ and len(to_.split('<')) > 1 and role.lower() != "agent":
raise ValidationError('Multiple to_ values given for role ' + role)
elif len(to_.split('<')) > 20:
elif to_ and len(to_.split('<')) > 20:
raise ValidationError('No of to_ values provided should be lesser than 20')
if to_ and len(str(ring_timeout).split('<')) > len(to_.split('<')):
raise ValidationError("RingTimeout:number of ring_timeout(s) should be same as number of destination(s)")
if to_ and len(str(delay_dial).split('<')) > len(to_.split('<')):
raise ValidationError("DelayDial:number of delay_dial(s) should be same as number of destination(s)")
return self.client.request('POST', ('MultiPartyCall', mpc_id, 'Participant'),
self.__clean_identifiers(to_param_dict(self.add_participant, locals())),
is_voice_request=True)
Expand Down
1 change: 1 addition & 0 deletions plivo/utils/jwt.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
from __future__ import absolute_import
import jwt, time
from plivo.utils.validators import *

Expand Down
16 changes: 3 additions & 13 deletions plivo/utils/validators.py
Original file line number Diff line number Diff line change
Expand Up @@ -180,27 +180,17 @@ def f(name, value):
return required(f)


def multiple_valid_integers(lowerbound, upperbound):
def multiple_valid_integers():
def f(name, value):
if isinstance(value, int):
if value >= lowerbound and value <= upperbound:
return value, []
else:
return None, {name + ' value must be in range ' + str(lowerbound) + ' to ' + str(upperbound)}
else:
if isinstance(value, str):
values = value.split('<')
for i in values:
is_int = True
try:
int(i)
except ValueError:
is_int = False
if is_int:
if int(i) > upperbound or int(i) < lowerbound:
return None, [name + ' destination value must be in range ' + str(lowerbound) + ' to ' + str(upperbound)]
else:
return None, ['{} destination value must be integer'.format(name)]
return value, []
return value, []
return f


Expand Down
2 changes: 1 addition & 1 deletion plivo/version.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
# -*- coding: utf-8 -*-
__version__ = '4.18.0'
__version__ = '4.18.1'

3 changes: 2 additions & 1 deletion setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@

setup(
name='plivo',
version='4.18.0',
version='4.18.1',
description='A Python SDK to make voice calls & send SMS using Plivo and to generate Plivo XML',
long_description=long_description,
url='https://github.com/plivo/plivo-python',
Expand Down Expand Up @@ -39,6 +39,7 @@
'six >= 1, < 2',
'decorator >= 4, < 5',
'lxml >= 3, < 5',
'PyJWT==1.7.1'
],
keywords=['plivo', 'plivo xml', 'voice calls', 'sms'],
include_package_data=True,
Expand Down
11 changes: 11 additions & 0 deletions tests/base.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
# -*- coding: utf-8 -*-
from unittest import TestCase
from doctest import Example
from lxml.doctestcompare import LXMLOutputChecker

from httmock import HTTMock, all_requests

Expand Down Expand Up @@ -172,3 +174,12 @@ def get_url(self, *args, **kwargs):
self.client.session.auth[0] + \
'/' + '/'.join([quote_plus(arg)
for arg in args]) + '/?' + urlencode(kwargs)


class PlivoXmlTestCase:

def assertXmlEqual(self, got, want):
checker = LXMLOutputChecker()
if not checker.check_output(want, got, 0):
message = checker.output_difference(Example("", want), got, 0)
raise AssertionError(message)
2 changes: 1 addition & 1 deletion tests/decorators.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ def decorator(self, *args, **kwargs):
name + '.json'))

try:
with io.open(path) as f:
with io.open(path, encoding='utf-8') as f:
self.expected_response = json.load(f)
self.client.set_expected_response(
status_code=status_code,
Expand Down
2 changes: 1 addition & 1 deletion tests/resources/test_conferences.py
Original file line number Diff line number Diff line change
Expand Up @@ -149,7 +149,7 @@ def test_play_delete(self):
conference_name=conference_name, member_id=member_id)
self.assertEqual(self.client.current_request.method, 'DELETE')
self.assertUrlEqual(
self.get_url('Conference', conference_name, 'Member', member_id,
self.get_voice_url('Conference', conference_name, 'Member', member_id,
'Play'), self.client.current_request.url)

@with_response(202)
Expand Down
22 changes: 9 additions & 13 deletions tests/resources/test_jwt.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,26 +8,25 @@

class AccessTokenTest(PlivoResourceTestCase):
def test_jwt_constructor(self):
self.assertRaisesRegex(TypeError, "", jwt.AccessToken.__init__,
jwt.AccessToken, 'ADADADADADADADADADA',
self.assertRaisesRegexp(TypeError, "", jwt.AccessToken,
'ADADADADADADADADADA',
'qwerty')

def test_jwt_constructor_auth_id(self):
self.assertRaisesRegex(plivo.exceptions.ValidationError,
self.assertRaisesRegexp(plivo.exceptions.ValidationError,
"auth_id should match format .*",
jwt.AccessToken.__init__, jwt.AccessToken,
jwt.AccessToken,
'ADADADADADADADADADA', 'qwerty', 'username')

def test_jwt_constructor_auth_id(self):
self.assertRaisesRegex(plivo.exceptions.ValidationError,
self.assertRaisesRegexp(plivo.exceptions.ValidationError,
"auth_id should match format .*",
jwt.AccessToken.__init__, jwt.AccessToken,
jwt.AccessToken,
'ADADADADADADADADADA', 'qwerty', 'username')

def test_jwt_constructor_lifetime(self):
self.assertRaisesRegex(plivo.exceptions.ValidationError,
self.assertRaisesRegexp(plivo.exceptions.ValidationError,
".* lifetime .*",
jwt.AccessToken.__init__,
jwt.AccessToken,
'MADADADADADADADADADA',
'qwerty',
Expand All @@ -36,19 +35,17 @@ def test_jwt_constructor_lifetime(self):
lifetime=123)

def test_jwt_constructor_validity(self):
self.assertRaisesRegex(plivo.exceptions.ValidationError,
self.assertRaisesRegexp(plivo.exceptions.ValidationError,
"use either lifetime or valid_till",
jwt.AccessToken.__init__,
jwt.AccessToken,
'MADADADADADADADADADA',
'qwerty',
'username',
valid_from=int(time.time()),
valid_till=int(time.time()) - 100,
lifetime=1200)
self.assertRaisesRegex(plivo.exceptions.ValidationError,
self.assertRaisesRegexp(plivo.exceptions.ValidationError,
"validity expires .* seconds before it starts",
jwt.AccessToken.__init__,
jwt.AccessToken,
'MADADADADADADADADADA',
'qwerty',
Expand All @@ -61,4 +58,3 @@ def test_jwt(self):
token.add_voice_grants(True, True)
self.assertEqual(True, token.grants['voice']['incoming_allow'])
self.assertNotEqual(False, token.grants['voice']['outgoing_allow'])
self.assertEqual('eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiIsImN0eSI6InBsaXZvO3Y9MSJ9.eyJqdGkiOiJ1c2VybmFtZS0xMjM0NSIsImlzcyI6Ik1BREFEQURBREFEQURBREFEQURBIiwic3ViIjoidXNlcm5hbWUiLCJuYmYiOjEyMTIxMjEyLCJleHAiOjEyMTIxNTEyLCJncmFudHMiOnsidm9pY2UiOnsiaW5jb21pbmdfYWxsb3ciOnRydWUsIm91dGdvaW5nX2FsbG93Ijp0cnVlfX19.khM99-sYP2AylLo9y6bwNnJbVPjjtOMAimiFvNo7FGA', token.to_jwt())
23 changes: 21 additions & 2 deletions tests/resources/test_multipartycalls.py
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,12 @@ def test_add_participant_validations(self):
error_message = str(e)
self.assertEqual(error_message, "[\"uuid should be of type: ['str']\"]")

try:
self.client.multi_party_calls.add_participant(role='supervisor', caller_name=1234)
except ValidationError as e:
error_message = str(e)
self.assertEqual(error_message, "[\"caller_name should be of type: ['str']\"]")

try:
self.client.multi_party_calls.add_participant(role='supervisor', call_status_callback_url='callback_python')
except ValidationError as e:
Expand All @@ -106,7 +112,19 @@ def test_add_participant_validations(self):
self.client.multi_party_calls.add_participant(role='supervisor', ring_timeout='2500')
except ValidationError as e:
error_message = str(e)
self.assertEqual(error_message, "[\"ring_timeout should be of type: ['int']\"]")
self.assertEqual(error_message, "specify either multi party call friendly name or uuid")

try:
self.client.multi_party_calls.add_participant(role='supervisor', ring_timeout='1aq')
except ValidationError as e:
error_message = str(e)
self.assertEqual(error_message, "[\'ring_timeout destination value must be integer\']")

try:
self.client.multi_party_calls.add_participant(role='supervisor', delay_dial='2<2.3')
except ValidationError as e:
error_message = str(e)
self.assertEqual(error_message, "[\'delay_dial destination value must be integer\']")

try:
self.client.multi_party_calls.add_participant(role='supervisor', max_duration=29867)
Expand Down Expand Up @@ -161,6 +179,7 @@ def test_add_participant(self):
'max_participants': 10,
'max_duration': 14400,
'ring_timeout': 45,
'delay_dial': 0,
'dial_music': 'real',
'confirm_key_sound_method': 'GET',
'call_status_callback_method': 'POST',
Expand All @@ -170,7 +189,6 @@ def test_add_participant(self):

add_participant_response = self.client.multi_party_calls.add_participant(friendly_name='Voice', role='agent',
call_uuid='1234-5678-4321-0987')

self.__assert_requests(actual_response=add_participant_response, expected_method='POST',
expected_url='https://voice.plivo.com/v1/Account/MAXXXXXXXXXXXXXXXXXX/'
'MultiPartyCall/name_Voice/Participant/',
Expand All @@ -192,6 +210,7 @@ def test_add_participant(self):
request_body['customer_hold_music_method'] = 'POST'
request_body['exit_sound_method'] = 'POST'
request_body['record_file_format'] = 'wav'
request_body['caller_name'] = '918888888888'

add_participant_response = self.client.multi_party_calls.add_participant(
uuid='12345678-90123456', role='supervisor', to_='180012341234', from_='918888888888',
Expand Down
16 changes: 9 additions & 7 deletions tests/xml/test_MultiPartyCallElement.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
from unittest import TestCase
from plivo import plivoxml
from plivo.exceptions import ValidationError
from tests import PlivoXmlTestCase


class MultiPartyCallElementTest(TestCase):
class MultiPartyCallElementTest(TestCase, PlivoXmlTestCase):

def test_default_xml(self):

Expand All @@ -18,7 +19,7 @@ def test_default_xml(self):
'waitMusicMethod="GET">Nairobi</MultiPartyCall>'

element = plivoxml.MultiPartyCallElement(content='Nairobi', role='Agent')
self.assertEqual(element.to_string(False), expected_response)
self.assertXmlEqual(element.to_string(False), expected_response)

def test_setting_optional_fields(self):
expected_response = '<MultiPartyCall agentHoldMusicMethod="GET" coachMode="true" ' \
Expand All @@ -32,19 +33,20 @@ def test_setting_optional_fields(self):
'waitMusicMethod="GET">Tokyo</MultiPartyCall>'

element = plivoxml.MultiPartyCallElement(content='Tokyo', role='supervisor', exit_sound='beep:1')
self.assertEqual(element.to_string(False), expected_response)
self.assertXmlEqual(element.to_string(False), expected_response)

def test_validation_on_init(self):
expected_error = '["status_callback_events should be among (\'mpc-state-changes\', ' \
'\'participant-state-changes\', \'participant-speak-events\'). ' \
'\'participant-state-changes\', \'participant-speak-events\', ' \
'\'participant-digit-input-events\', \'add-participant-api-events\'). ' \
'multiple values should be COMMA(,) separated (actual value: hostages-move)"]'

actual_error = ''
try:
plivoxml.MultiPartyCallElement(content='Rio', role='agent', status_callback_events='hostages-move')
except ValidationError as e:
actual_error = str(e)
self.assertEqual(expected_error, actual_error)
self.assertXmlEqual(expected_error, actual_error)

def test_validation_on_set(self):
expected_error = "['300 <= max_duration <= 28800 (actual value: 255)']"
Expand All @@ -55,7 +57,7 @@ def test_validation_on_set(self):
element.set_max_duration(255)
except ValidationError as e:
actual_error = str(e)
self.assertEqual(expected_error, actual_error)
self.assertXmlEqual(expected_error, actual_error)

def test_builder_setting(self):

Expand All @@ -72,4 +74,4 @@ def test_builder_setting(self):
set_customer_hold_music_url('http://plivo.com/voice.mp3').set_coach_mode(False).\
set_on_exit_action_url('http://plivo.com/api.mp3').set_on_exit_action_method('GET')

self.assertEqual(expected_xml, element.to_string(False))
self.assertXmlEqual(expected_xml, element.to_string(False))
5 changes: 3 additions & 2 deletions tests/xml/test_breakElement.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
from unittest import TestCase

from plivo import plivoxml
from tests import PlivoXmlTestCase


class BreakElementTest(TestCase):
class BreakElementTest(TestCase, PlivoXmlTestCase):
def test_set_methods(self):
time = "1000ms"
strength = "x-strong"
Expand All @@ -14,4 +15,4 @@ def test_set_methods(self):
plivoxml.BreakElement().set_strength(strength).set_time(time)
).add_cont("one second or same as paragraph")
).to_string(False)
self.assertEqual(response, expected_response)
self.assertXmlEqual(response, expected_response)
Loading

0 comments on commit 63e2c8f

Please sign in to comment.