Skip to content

Commit

Permalink
Fix SDK bug. Add UT for CallingServer Client apis.
Browse files Browse the repository at this point in the history
  • Loading branch information
zihzhan-msft committed Sep 9, 2021
1 parent a8131d5 commit d15dbca
Show file tree
Hide file tree
Showing 13 changed files with 499 additions and 24 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,8 @@

from ._shared.utils import (get_authentication_policy, get_current_utc_time,
parse_connection_str)
from ._converters import JoinCallRequestConverter

from ._version import SDK_MONIKER


Expand Down Expand Up @@ -160,7 +162,7 @@ def create_call_connection(
callback_uri=options.callback_uri,
requested_media_types=options.requested_media_types,
requested_call_events=options.requested_call_events,
alternate_caller_id=None if options.alternate_Caller_Id == None else PhoneNumberIdentifierModel(value=options.alternate_Caller_Id.properties['value']),
alternate_caller_id=None if options.alternate_Caller_Id == None else PhoneNumberIdentifierModel(value=options.alternate_Caller_Id),
subject=options.subject,
**kwargs
)
Expand All @@ -177,7 +179,7 @@ def join_call(
self,
server_call_id, # type: str
source, # type: CommunicationIdentifier
options, # type: JoinCallOptions
call_options, # type: JoinCallOptions
**kwargs # type: Any
): # type: (...) -> CallConnection
"""Join the call using server call id.
Expand All @@ -197,13 +199,14 @@ def join_call(
if not source:
raise ValueError("source can not be None")

if not options:
raise ValueError("options can not be None")
if not call_options:
raise ValueError("call_options can not be None")

join_call_request = JoinCallRequestConverter.convert(serialize_identifier(source), call_options)

join_call_response = self._server_call_client.join_call(
server_call_id=server_call_id,
source=source,
call_options=options,
call_request=join_call_request,
**kwargs
)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,11 @@

from .._models import JoinCallOptions, PlayAudioOptions
from .._shared.models import CommunicationIdentifier
from .._generated.models import JoinCallRequest, PlayAudioRequest
from .._generated.models import JoinCallRequest, PlayAudioRequest, CommunicationIdentifierModel

class JoinCallRequestConverter(object):
@classmethod
def convert(self, source: CommunicationIdentifier, join_call_options: JoinCallOptions):
def convert(self, source: CommunicationIdentifierModel, join_call_options: JoinCallOptions):
if not source:
raise ValueError("source can not be None")
if not join_call_options:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,24 +40,37 @@ def __init__(
if not requested_call_events:
raise ValueError("requestedCallEvents can not be None or empty")

self.callback_uri = callback_uri
self.requested_media_types = requested_media_types
self.requested_call_events = requested_call_events
self.subject = None
self.__callback_uri = callback_uri
self.__requested_media_types = requested_media_types
self.__requested_call_events = requested_call_events
self.__alternate_Caller_Id = None
self.__subject = None

@property
def callback_uri(self):
return self.__callback_uri

@property
def requested_media_types(self):
return self.__requested_media_types

@property
def requested_call_events(self):
return self.__requested_call_events

@property
def alternate_Caller_Id(self):
return self._alternate_Caller_Id
return self.__alternate_Caller_Id
@alternate_Caller_Id.setter
def alternate_Caller_Id(self, value: PhoneNumberIdentifier):
self._alternate_Caller_Id = value
def alternate_Caller_Id(self, alternate_Caller_Id: PhoneNumberIdentifier):
self.__alternate_Caller_Id = alternate_Caller_Id

@property
def subject(self):
return self._subject
return self.__subject
@subject.setter
def subject(self, value: str):
self._subject = value
def subject(self, subject: str):
self.__subject = subject

class JoinCallOptions(object):

Expand All @@ -84,9 +97,21 @@ def __init__(
if not requested_call_events:
raise ValueError("requestedCallEvents can not be None or empty")

self._callback_uri = callback_uri
self._requested_media_types = requested_media_types
self._requested_call_events = requested_call_events
self.__callback_uri = callback_uri
self.__requested_media_types = requested_media_types
self.__requested_call_events = requested_call_events

@property
def callback_uri(self):
return self.__callback_uri

@property
def requested_media_types(self):
return self.__requested_media_types

@property
def requested_call_events(self):
return self.__requested_call_events

@property
def subject(self):
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -161,7 +161,7 @@ async def create_call_connection(
callback_uri=options.callback_uri,
requested_media_types=options.requested_media_types,
requested_call_events=options.requested_call_events,
alternate_caller_id=None if options.alternate_Caller_Id == None else PhoneNumberIdentifierModel(value=options.alternate_Caller_Id.properties['value']),
alternate_caller_id=None if options.alternate_Caller_Id == None else PhoneNumberIdentifierModel(value=options.alternate_Caller_Id),
subject=options.subject,
**kwargs
)
Expand Down Expand Up @@ -200,11 +200,10 @@ async def join_call(
if not call_options:
raise ValueError("call_options can not be None")

join_call_request = JoinCallRequestConverter.convert(source, call_options)
join_call_request = JoinCallRequestConverter.convert(serialize_identifier(source), call_options)

join_call_response = await self._server_call_client.join_call(
server_call_id=server_call_id,
source=source,
call_request=join_call_request,
**kwargs
)
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
# -------------------------------------------------------------------------
# Copyright (c) Microsoft Corporation. All rights reserved.
# Licensed under the MIT License. See License.txt in the project root for
# license information.
# --------------------------------------------------------------------------

RESOURCE_SOURCE = "8:acs:resource_source"
RESOURCE_TARGET = "8:acs:resource_target"
Phone_Number = "+14255550123"
CALL_ID = "cad9df7b-f3ac-4c53-96f7-c76e7437b3c1"
CALLBACK_URI = "callBackUri"
CONNECTION_STRING = "endpoint=https://REDACTED.communication.azure.com/;accesskey=eyJhbG=="
FAKE_ENDPOINT = "https://endpoint"
FAKE_TOKEN = "Fake Token"
CALL_SUBJECT = "testsubject"
CreateOrJoinCallPayload={
"callLegId": CALL_ID,
"callConnectionId": CALL_ID,
}
ErrorPayload={"msg": "some error"}

ClientType_ConnectionString = "use connectionString"
ClientType_ManagedIdentity = "use managedIdentity"

SEVERCALL_ID = "b3ba87f4-9daf-4d0b-b95a-53d955a40577"
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
# -------------------------------------------------------------------------
# Copyright (c) Microsoft Corporation. All rights reserved.
# Licensed under the MIT License. See License.txt in the project root for
# license information.
# --------------------------------------------------------------------------
import json
import unittest

import _test_constants
from azure.core.credentials import AccessToken
from azure.communication.callingserver.aio import CallingServerClient as CallingServerClientAsync
from azure.communication.callingserver import CallingServerClient

try:
from unittest.mock import Mock, patch
except ImportError: # python < 3.3
from mock import Mock, patch # type: ignore

class FakeTokenCredential(object):
def __init__(self):
self.token = AccessToken(_test_constants.FAKE_TOKEN, 0)
def get_token(self, *args):
return self.token

class FakeTokenCredential_Async(object):
def __init__(self):
self.token = AccessToken(_test_constants.FAKE_TOKEN, 0)
async def get_token(self, *args):
return self.token

def create_mock_call_connection(status_code, payload, is_async=False):
calling_server_client = create_mock_calling_server_client(status_code, payload, is_async)
return calling_server_client.get_call_connection(_test_constants.CALL_ID)

def create_mock_calling_server_client(status_code, payload, is_async=False, use_managed_identity=False):
async def async_mock_send(*_, **__):
return _mock_response(status_code=status_code, json_payload=payload)

def mock_send(*_, **__):
return _mock_response(status_code=status_code, json_payload=payload)

if is_async:
return create_calling_server_client_async(async_mock_send, use_managed_identity)
return create_calling_server_client(mock_send, use_managed_identity)

def create_calling_server_client_async(mock_transport=None, use_managed_identity=False):
if mock_transport is None:
return (
CallingServerClientAsync.from_connection_string(_test_constants.CONNECTION_STRING)
if use_managed_identity
else CallingServerClientAsync(_test_constants.FAKE_ENDPOINT, FakeTokenCredential_Async())
)

return (
CallingServerClientAsync.from_connection_string(_test_constants.CONNECTION_STRING, transport=Mock(send=mock_transport))
if use_managed_identity
else CallingServerClientAsync(_test_constants.FAKE_ENDPOINT, FakeTokenCredential_Async(), transport=Mock(send=mock_transport))
)

def create_calling_server_client(mock_transport=None, use_managed_identity=False):
if mock_transport is None:
return (
CallingServerClient.from_connection_string(_test_constants.CONNECTION_STRING)
if use_managed_identity
else CallingServerClient(_test_constants.FAKE_ENDPOINT, FakeTokenCredential())
)
return (
CallingServerClient.from_connection_string(_test_constants.CONNECTION_STRING, transport=Mock(send=mock_transport))
if use_managed_identity
else CallingServerClient(_test_constants.FAKE_ENDPOINT, FakeTokenCredential(), transport=Mock(send=mock_transport))
)

def _mock_response(status_code=200, headers=None, json_payload=None):
response = Mock(status_code=status_code, headers=headers or {})
if json_payload is not None:
response.text = lambda encoding=None: json.dumps(json_payload)
response.headers["content-type"] = "application/json"
response.content_type = "application/json"
else:
response.text = lambda encoding=None: ""
response.headers["content-type"] = "text/plain"
response.content_type = "text/plain"
return response
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
# -------------------------------------------------------------------------
# Copyright (c) Microsoft Corporation. All rights reserved.
# Licensed under the MIT License. See License.txt in the project root for
# license information.
# --------------------------------------------------------------------------
import sys

# Ignore collection of async tests for Python 2
collect_ignore_glob = []
if sys.version_info < (3, 5):
collect_ignore_glob.append("*_async.py")
Empty file.
Empty file.
Loading

0 comments on commit d15dbca

Please sign in to comment.