Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -17,32 +17,19 @@
)


def _get_teams_api_client(context: TurnContext) -> ApiClient:
"""
Get the cached Teams API client from the context.

:param context: The turn context.
:return: The cached Teams API client.
:raises ValueError: If the Teams API client is not found.
"""
api_client = context.services.get(ApiClient)
if isinstance(api_client, ApiClient):
return api_client
raise ValueError("Unable to retrieve Teams API client.")


def _set_teams_api_client(
context: TurnContext, connection_manager: Connections
) -> None:
) -> ApiClient:
"""
Set the Teams API client in the context if it is not already set.

:param context: The turn context.
:param connection_manager: The connection manager.
"""
Comment on lines 23 to 28

if context.services.has(ApiClient):
return
api_client = context.services.get(ApiClient)
if api_client is not None:
return api_client

headers = {
"Accept": "application/json",
Expand Down Expand Up @@ -74,3 +61,4 @@ async def token_factory() -> str:
)

context.services.set(ApiClient, api_client)
return api_client
Original file line number Diff line number Diff line change
Expand Up @@ -57,10 +57,7 @@
_common_get_app_graph_client_for_connection,
)

from ._teams_api_client import (
_get_teams_api_client,
_set_teams_api_client,
)
from ._teams_api_client import _set_teams_api_client
from ._utils import _try_get_channel_data

from .teams_activity import TeamsActivity
Expand Down Expand Up @@ -124,7 +121,6 @@ def _configure_app(self):

async def on_before_turn(context: TurnContext, state: StateT) -> bool:
if context.activity.channel_id == Channels.ms_teams:
_set_teams_api_client(context, self._app.connection_manager)
# caches the deserialized version of ChannelData
context.activity.channel_data = _try_get_channel_data(context.activity)
return True
Expand Down Expand Up @@ -301,7 +297,10 @@ def get_teams_api_client(self, context: TurnContext) -> ApiClient:

:return: The Teams API client.
"""
return _get_teams_api_client(context)
api_client = context.services.get(ApiClient)
if not api_client:
return _set_teams_api_client(context, self._app.connection_manager)
return api_client
Comment on lines +300 to +303

def get_graph_client(
self,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@
_common_get_app_graph_client,
_common_get_app_graph_client_for_connection,
)
from ._teams_api_client import _get_teams_api_client, _set_teams_api_client
from ._teams_api_client import _set_teams_api_client
from .teams_activity import TeamsActivity


Expand Down Expand Up @@ -96,7 +96,10 @@ def activity(self) -> TeamsActivity:
@property
def api_client(self) -> ApiClient:
"""Get the API client for the Teams turn context."""
return _get_teams_api_client(self)
api_client = self._services.get(ApiClient)
if not api_client:
return _set_teams_api_client(self, self._app.connection_manager)
return api_client
Comment on lines +99 to +102

@staticmethod
def _make_targeted_activity(activity: Activity) -> None:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -65,9 +65,7 @@ async def get_token_or_sign_in_resource(
state,
)

mock_user_token_client.get_user_token = mocker.AsyncMock(
side_effect=get_user_token
)
mock_user_token_client.get_user_token = mocker.AsyncMock(side_effect=get_user_token)
mock_user_token_client.sign_out_user = mocker.AsyncMock(side_effect=sign_out_user)
mock_user_token_client.exchange_token = mocker.AsyncMock(side_effect=exchange_token)
mock_user_token_client.get_token_or_sign_in_resource = mocker.AsyncMock(
Expand Down
38 changes: 0 additions & 38 deletions tests/hosting_msteams/test_internal.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,49 +13,11 @@
)

if is_supported_version:
from microsoft_teams.api import ApiClient

from microsoft_agents.hosting.msteams._teams_api_client import (
_get_teams_api_client,
)
from microsoft_agents.hosting.msteams.errors.error_resources import (
TeamsErrorResources,
)


class _FakeServices:
def __init__(self, values=None):
self._values = values or {}

def get(self, key):
return self._values.get(key)


class _FakeContext:
"""Minimal stand-in exposing only the ``services`` accessor reads."""

def __init__(self, services):
self.services = services


class TestGetTeamsApiClient:

def test_returns_cached_api_client(self):
client = ApiClient("https://smba.trafficmanager.net/teams/")
ctx = _FakeContext(_FakeServices({ApiClient: client}))
assert _get_teams_api_client(ctx) is client

def test_raises_when_missing(self):
ctx = _FakeContext(_FakeServices())
with pytest.raises(ValueError, match="Teams API client"):
_get_teams_api_client(ctx)

def test_raises_when_wrong_type(self):
ctx = _FakeContext(_FakeServices({ApiClient: object()}))
with pytest.raises(ValueError, match="Teams API client"):
_get_teams_api_client(ctx)


class TestTeamsErrorResources:

def _error_messages(self):
Expand Down
1 change: 0 additions & 1 deletion tests/hosting_msteams/test_teams_agent_extension.py
Original file line number Diff line number Diff line change
Expand Up @@ -125,7 +125,6 @@ async def test_teams_channel_deserializes_channel_data(self):
assert result is True
assert isinstance(activity.channel_data, ChannelData)
assert activity.channel_data.channel.id == "c1"
assert ctx.services.has(ApiClient)

Comment on lines 125 to 128
@pytest.mark.asyncio
async def test_teams_channel_without_channel_data_sets_none(self):
Expand Down
29 changes: 29 additions & 0 deletions tests/hosting_msteams/test_teams_turn_context.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@

"""Tests for TeamsTurnContext helpers that can be exercised without a live adapter."""

from types import SimpleNamespace

import pytest

from .helpers import is_supported_version
Expand All @@ -17,11 +19,19 @@
Activity,
ActivityTreatmentTypes,
Entity,
ResourceResponse,
)
from microsoft_teams.api import ApiClient

from microsoft_agents.hosting.core import TurnContext
from microsoft_agents.hosting.msteams import TeamsTurnContext


class _StubAdapter:
async def send_activities(self, context, activities):
return [ResourceResponse()] * len(activities)


class TestMakeTargetedActivity:
"""``_make_targeted_activity`` mutates the supplied activity in place (returns
None) by appending a TARGETED activity-treatment entity."""
Expand Down Expand Up @@ -52,3 +62,22 @@ def test_each_call_appends_another_treatment(self):
if getattr(e, "treatment", None) == ActivityTreatmentTypes.TARGETED
]
assert len(treatments) == 2


class TestTeamsApiClient:

def test_api_client_returns_cached_client(self):
activity = Activity(
type="message",
channel_id="msteams",
service_url="https://smba.trafficmanager.net/teams/",
)
context = TurnContext(_StubAdapter(), activity)
client = object.__new__(ApiClient)
context.services.set(ApiClient, client)

teams_context = TeamsTurnContext(
context, SimpleNamespace(connection_manager=object())
)

assert teams_context.api_client is client
Loading