8000 Testing SkillHttpClient · itsmokha/botbuilder-python@36421bf · GitHub
[go: up one dir, main page]

Skip to content

Navigation Menu

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

Commit 36421bf

Browse files
committed
Testing SkillHttpClient
1 parent 5807899 commit 36421bf

File tree

3 files changed

+208
-2
lines changed

3 files changed

+208
-2
lines changed

libraries/botbuilder-integration-aiohttp/botbuilder/integration/aiohttp/skills/skill_http_client.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,7 @@ async def post_activity_to_skill(
5050
originating_audience = (
5151
GovernmentConstants.TO_CHANNEL_FROM_BOT_OAUTH_SCOPE
5252
if self._channel_provider is not None
53-
and self._channel_provider.IsGovernment()
53+
and self._channel_provider.is_government()
5454
else AuthenticationConstants.TO_CHANNEL_FROM_BOT_OAUTH_SCOPE
5555
)
5656

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
msrest==0.6.10
22
botframework-connector==4.10.0
33
botbuilder-schema==4.10.0
4-
aiohttp==3.6.2
4+
aiohttp==3.6.2
5+
ddt==1.2.1
Lines changed: 205 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,205 @@
1+
# Copyright (c) Microsoft Corporation. All rights reserved.
2+
# Licensed under the MIT License.
3+
4+
from uuid import uuid4
5+
from typing import Awaitable, Callable, Dict, Union
6+
7+
8+
from unittest.mock import Mock
9+
import aiounittest
10+
11+
from botbuilder.core import MessageFactory, InvokeResponse
12+
from botbuilder.core.skills import (
13+
BotFrameworkSkill,
14+
ConversationIdFactoryBase,
15+
SkillConversationIdFactoryOptions,
16+
SkillConversationReference,
17+
)
18+
from botbuilder.integration.aiohttp.skills import SkillHttpClient
19+
from botbuilder.schema import Activity, ConversationAccount, ConversationReference
20+
from botframework.connector.auth import (
21+
AuthenticationConstants,
22+
ChannelProvider,
23+
GovernmentConstants,
24+
)
25+
26+
27+
class SimpleConversationIdFactory(ConversationIdFactoryBase):
28+
def __init__(self, conversation_id: str):
29+
self._conversation_id = conversation_id
30+
self._conversation_refs: Dict[str, SkillConversationReference] = {}
31+
# Public property to capture and assert the options passed to CreateSkillConversationIdAsync.
32+
self.creation_options: SkillConversationIdFactoryOptions = None
33+
34+
async def create_skill_conversation_id(
35+
self,
36+
options_or_conversation_reference: Union[
37+
SkillConversationIdFactoryOptions, ConversationReference
38+
],
39+
) -> str:
40+
self.creation_options = options_or_conversation_reference
41+
42+
key = self._conversation_id
43+
self._conversation_refs[key] = self._conversation_refs.get(
44+
key,
45+
SkillConversationReference(
46+
conversation_reference=options_or_conversation_reference.activity.get_conversation_reference(),
47+
oauth_scope=options_or_conversation_reference.from_bot_oauth_scope,
48+
),
49+
)
50+
return key
51+
52+
async def get_conversation_reference(
53+
self, skill_conversation_id: str
54+
) -> SkillConversationReference:
55+
return self._conversation_refs[skill_conversation_id]
56+
57+
async def delete_conversation_reference(self, skill_conversation_id: str):
58+
raise NotImplementedError()
59+
60+
61+
class TestSkillHttpClientTests(aiounittest.AsyncTestCase):
62+
async def test_post_activity_with_originating_audience(self):
63+
conversation_id = str(uuid4())
64+
conversation_id_factory = SimpleConversationIdFactory(conversation_id)
65+
test_activity = MessageFactory.text("some message")
66+
test_activity.conversation = ConversationAccount()
67+
skill = BotFrameworkSkill(
68+
id="SomeSkill",
69+
app_id="",
70+
skill_endpoint="https://someskill.com/api/messages",
71+
)
72+
73+
async def _mock_post_content(
74+
to_url: str,
75+
token: str, # pylint: disable=unused-argument
76+
activity: Activity,
77+
) -> (int, object):
78+
nonlocal self
79+
self.assertEqual(skill.skill_endpoint, to_url)
80+
# Assert that the activity being sent has what we expect.
81+
self.assertEqual(conversation_id, activity.conversation.id)
82+
self.assertEqual("https://parentbot.com/api/messages", activity.service_url)
83+
84+
# Create mock response.
85+
return 200, None
86+
87+
sut = await self._create_http_client_with_mock_handler(
88+
_mock_post_content, conversation_id_factory
89+
)
90+
91+
result = await sut.post_activity_to_skill(
92+
"",
93+
skill,
94+
"https://parentbot.com/api/messages",
95+
test_activity,
96+
"someOriginatingAudience",
97+
)
98+
99+
# Assert factory options
100+
self.assertEqual("", conversation_id_factory.creation_options.from_bot_id)
101+
self.assertEqual(
102+
"someOriginatingAudience",
103+
conversation_id_factory.creation_options.from_bot_oauth_scope,
104+
)
105+
self.assertEqual(
106+
test_activity, conversation_id_factory.creation_options.activity
107+
)
108+
self.assertEqual(
109+
skill, conversation_id_factory.creation_options.bot_framework_skill
110+
)
111+
112+
# Assert result
113+
self.assertIsInstance(result, InvokeResponse)
114+
self.assertEqual(200, result.status)
115+
116+
async def test_post_activity_using_invoke_response(self):
117+
for is_gov in [True, False]:
118+
with self.subTest(is_government=is_gov):
119+
# pylint: disable=undefined-variable
120+
# pylint: disable=cell-var-from-loop
121+
conversation_id = str(uuid4())
122+
conversation_id_factory = SimpleConversationIdFactory(conversation_id)
123+
test_activity = MessageFactory.text("some message")
124+
test_activity.conversation = ConversationAccount()
125+
expected_oauth_scope = (
126+
AuthenticationConstants.TO_CHANNEL_FROM_BOT_OAUTH_SCOPE
127+
)
128+
mock_channel_provider: ChannelProvider = Mock(spec=ChannelProvider)
129+
130+
def is_government_mock():
131+
nonlocal expected_oauth_scope
132+
if is_government:
133+
expected_oauth_scope = (
134+
GovernmentConstants.TO_CHANNEL_FROM_BOT_OAUTH_SCOPE
135+
)
136+
137+
return is_government
138+
139+
mock_channel_provider.is_government = Mock(
140+
side_effect=is_government_mock
141+
)
142+
143+
skill = BotFrameworkSkill(
144+
id="SomeSkill",
145+
app_id="",
146+
skill_endpoint="https://someskill.com/api/messages",
147+
)
148+
149+
async def _mock_post_content(
150+
to_url: str,
151+
token: str, # pylint: disable=unused-argument
152+
activity: Activity,
153+
) -> (int, object):
154+
nonlocal self
155+
156+
self.assertEqual(skill.skill_endpoint, to_url)
157+
# Assert that the activity being sent has what we expect.
158+
self.assertEqual(conversation_id, activity.conversation.id)
159+
self.assertEqual(
160+
"https://parentbot.com/api/messages", activity.service_url
161+
)
162+
163+
# Create mock response.
164+
return 200, None
165+
166+
sut = await self._create_http_client_with_mock_handler(
167+
_mock_post_content, conversation_id_factory
168+
)
169+
result = await sut.post_activity_to_skill(
170+
"", skill, "https://parentbot.com/api/messages", test_activity
171+
)
172+
173+
# Assert factory options
174+
self.assertEqual(
175+
"", conversation_id_factory.creation_options.from_bot_id
176+
)
177+
self.assertEqual(
178+
expected_oauth_scope,
179+
conversation_id_factory.creation_options.from_bot_oauth_scope,
180+
)
181+
self.assertEqual(
182+
test_activity, conversation_id_factory.creation_options.activity
183+
)
184+
self.assertEqual(
185+
skill, conversation_id_factory.creation_options.bot_framework_skill
186+
)
187+
188+
# Assert result
189+
self.assertIsInstance(result, InvokeResponse)
190+
self.assertEqual(200, result.status)
191+
192+
# Helper to create an HttpClient with a mock message handler that executes function argument to validate the request
193+
# and mock a response.
194+
async def _create_http_client_with_mock_handler(
195+
self,
196+
value_function: Callable[[object], Awaitable[object]],
197+
id_factory: ConversationIdFactoryBase,
198+
channel_provider: ChannelProvider = None,
199+
) -> SkillHttpClient:
200+
# pylint: disable=protected-access
201+
client = SkillHttpClient(Mock(), id_factory, channel_provider)
202+
client._post_content = value_function
203+
await client._session.close()
204+
205+
return client

0 commit comments

Comments
 (0)
0