Skip to content

Commit 5807899

Browse files
authored
Merge pull request #1395 from microsoft/axsuarez/skillDialogDeleteConversationId
skill dialog delete conversation id
2 parents 9629963 + ccbec99 commit 5807899

File tree

2 files changed

+69
-4
lines changed

2 files changed

+69
-4
lines changed

libraries/botbuilder-dialogs/botbuilder/dialogs/skills/skill_dialog.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -249,6 +249,11 @@ async def _send_to_skill(
249249
if from_skill_activity.type == ActivityTypes.end_of_conversation:
250250
# Capture the EndOfConversation activity if it was sent from skill
251251
eoc_activity = from_skill_activity
252+
253+
# The conversation has ended, so cleanup the conversation id
254+
await self.dialog_options.conversation_id_factory.delete_conversation_reference(
255+
skill_conversation_id
256+
)
252257
elif await self._intercept_oauth_cards(
253258
context, from_skill_activity, self.dialog_options.connection_name
254259
):

libraries/botbuilder-dialogs/tests/test_skill_dialog.py

Lines changed: 64 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
# Licensed under the MIT License.
33
import uuid
44
from http import HTTPStatus
5-
from typing import Callable, Union
5+
from typing import Callable, Union, List
66
from unittest.mock import Mock
77

88
import aiounittest
@@ -46,13 +46,15 @@
4646
class SimpleConversationIdFactory(ConversationIdFactoryBase):
4747
def __init__(self):
4848
self.conversation_refs = {}
49+
self.create_count = 0
4950

5051
async def create_skill_conversation_id(
5152
self,
5253
options_or_conversation_reference: Union[
5354
SkillConversationIdFactoryOptions, ConversationReference
5455
],
5556
) -> str:
57+
self.create_count += 1
5658
key = (
5759
options_or_conversation_reference.activity.conversation.id
5860
+ options_or_conversation_reference.activity.service_url
@@ -72,7 +74,8 @@ async def get_conversation_reference(
7274
return self.conversation_refs[skill_conversation_id]
7375

7476
async def delete_conversation_reference(self, skill_conversation_id: str):
75-
raise NotImplementedError()
77+
self.conversation_refs.pop(skill_conversation_id, None)
78+
return
7679

7780

7881
class SkillDialogTests(aiounittest.AsyncTestCase):
@@ -506,6 +509,57 @@ async def post_return():
506509
self.assertIsNotNone(final_activity)
507510
self.assertEqual(len(final_activity.attachments), 1)
508511

512+
async def test_end_of_conversation_from_expect_replies_calls_delete_conversation_reference(
513+
self,
514+
):
515+
activity_sent: Activity = None
516+
517+
# Callback to capture the parameters sent to the skill
518+
async def capture_action(
519+
from_bot_id: str, # pylint: disable=unused-argument
520+
to_bot_id: str, # pylint: disable=unused-argument
521+
to_uri: str, # pylint: disable=unused-argument
522+
service_url: str, # pylint: disable=unused-argument
523+
conversation_id: str, # pylint: disable=unused-argument
524+
activity: Activity,
525+
):
526+
# Capture values sent to the skill so we can assert the right parameters were used.
527+
nonlocal activity_sent
528+
activity_sent = activity
529+
530+
eoc = Activity.create_end_of_conversation_activity()
531+
expected_replies = list([eoc])
532+
533+
# Create a mock skill client to intercept calls and capture what is sent.
534+
mock_skill_client = self._create_mock_skill_client(
535+
capture_action, expected_replies=expected_replies
536+
)
537+
538+
# Use Memory for conversation state
539+
conversation_state = ConversationState(MemoryStorage())
540+
dialog_options = self.create_skill_dialog_options(
541+
conversation_state, mock_skill_client
542+
)
543+
544+
# Create the SkillDialogInstance and the activity to send.
545+
sut = SkillDialog(dialog_options, dialog_id="dialog")
546+
activity_to_send = Activity.create_message_activity()
547+
activity_to_send.delivery_mode = DeliveryModes.expect_replies
548+
activity_to_send.text = str(uuid.uuid4())
549+
client = DialogTestClient(
550+
"test",
551+
sut,
552+
BeginSkillDialogOptions(activity_to_send),
553+
conversation_state=conversation_state,
554+
)
555+
556+
# Send something to the dialog to start it
557+
await client.send_activity("hello")
558+
559+
simple_id_factory: SimpleConversationIdFactory = dialog_options.conversation_id_factory
560+
self.assertEqual(0, len(simple_id_factory.conversation_refs))
561+
self.assertEqual(1, simple_id_factory.create_count)
562+
509563
@staticmethod
510564
def create_skill_dialog_options(
511565
conversation_state: ConversationState,
@@ -547,9 +601,15 @@ def create_oauth_card_attachment_activity(uri: str) -> Activity:
547601
return attachment_activity
548602

549603
def _create_mock_skill_client(
550-
self, callback: Callable, return_status: Union[Callable, int] = 200
604+
self,
605+
callback: Callable,
606+
return_status: Union[Callable, int] = 200,
607+
expected_replies: List[Activity] = None,
551608
) -> BotFrameworkClient:
552609
mock_client = Mock()
610+
activity_list = ExpectedReplies(
611+
activities=expected_replies or [MessageFactory.text("dummy activity")]
612+
)
553613

554614
async def mock_post_activity(
555615
from_bot_id: str,
@@ -572,7 +632,7 @@ async def mock_post_activity(
572632

573633
if isinstance(return_status, Callable):
574634
return await return_status()
575-
return InvokeResponse(status=return_status)
635+
return InvokeResponse(status=return_status, body=activity_list)
576636

577637
mock_client.post_activity.side_effect = mock_post_activity
578638

0 commit comments

Comments
 (0)