async def test_should_work_as_a_middleware_plugin(self): adapter = TestAdapter() context = TurnContext(adapter, Activity()) foo_state = BotStateMock({"foo": "bar"}) autosave_middleware = AutoSaveStateMiddleware().add(foo_state) await autosave_middleware.on_turn(context, aux_func) assert foo_state.write_called, "save_all_changes() not called."
async def test_should_add_and_call_load_all_on_multiple_plugins(self): adapter = TestAdapter() context = TurnContext(adapter, Activity()) foo_state = BotStateMock({"foo": "bar"}) bar_state = BotStateMock({"bar": "foo"}) bot_state_set = AutoSaveStateMiddleware([foo_state, bar_state]) await bot_state_set.bot_state_set.load_all(context)
async def test_should_pass_force_flag_through_in_load_all_call(self): adapter = TestAdapter() context = TurnContext(adapter, Activity()) foo_state = BotStateMock({"foo": "bar"}) foo_state.assert_force = True autosave_middleware = AutoSaveStateMiddleware().add(foo_state) await autosave_middleware.bot_state_set.load_all(context, True)
def use_state( adapter: BotAdapter, user_state: UserState, conversation_state: ConversationState, auto: bool = True, ) -> BotAdapter: """ Registers user and conversation state objects with the adapter. These objects will be available via the turn context's `turn_state` property. :param adapter: The BotAdapter on which to register the state objects. :param user_state: The UserState object to register. :param conversation_state: The ConversationState object to register. :param auto: True to automatically persist state each turn. :return: The BotAdapter """ if not adapter: raise TypeError("BotAdapter is required") if not user_state: raise TypeError("UserState is required") if not conversation_state: raise TypeError("ConversationState is required") adapter.use(RegisterClassMiddleware(user_state)) adapter.use(RegisterClassMiddleware(conversation_state)) if auto: adapter.use(AutoSaveStateMiddleware([user_state, conversation_state])) return adapter
async def test_should_add_and_call_save_all_changes_on_a_single_plugin( self): adapter = TestAdapter() context = TurnContext(adapter, Activity()) foo_state = BotStateMock({"foo": "bar"}) bot_state_set = AutoSaveStateMiddleware().add(foo_state) await bot_state_set.bot_state_set.save_all_changes(context) assert foo_state.write_called, "write not called for plugin."
async def test_should_add_and_call_save_all_changes_on_multiple_plugins( self): adapter = TestAdapter() context = TurnContext(adapter, Activity()) foo_state = BotStateMock({"foo": "bar"}) bar_state = BotStateMock({"bar": "foo"}) autosave_middleware = AutoSaveStateMiddleware([foo_state, bar_state]) await autosave_middleware.bot_state_set.save_all_changes(context) assert (foo_state.write_called or bar_state.write_called), "write not called for either plugin." assert foo_state.write_called, "write not called for 'foo_state' plugin." assert bar_state.write_called, "write not called for 'bar_state' plugin."
def __init__( self, channel_or_adapter: Union[str, TestAdapter], target_dialog: Dialog, initial_dialog_options: object = None, middlewares: List[Middleware] = None, conversation_state: ConversationState = None, ): """ Create a DialogTestClient to test a dialog without having to create a full-fledged adapter. ```python client = DialogTestClient("test", MY_DIALOG, MY_OPTIONS) reply = await client.send_activity("first message") self.assertEqual(reply.text, "first reply", "reply failed") ``` :param channel_or_adapter: The channel Id or test adapter to be used for the test. For channel Id, use 'emulator' or 'test' if you are uncertain of the channel you are targeting. Otherwise, it is recommended that you use the id for the channel(s) your bot will be using and write a test case for each channel. Or, a test adapter instance can be used. :type channel_or_adapter: Union[str, TestAdapter] :param target_dialog: The dialog to be tested. This will be the root dialog for the test client. :type target_dialog: Dialog :param initial_dialog_options: (Optional) additional argument(s) to pass to the dialog being started. :type initial_dialog_options: object :param middlewares: (Optional) The test adapter to use. If this parameter is not provided, the test client will use a default TestAdapter. :type middlewares: List[Middleware] :param conversation_state: (Optional) A ConversationState instance to use in the test client. :type conversation_state: ConversationState """ self.dialog_turn_result: DialogTurnResult = None self.conversation_state: ConversationState = (ConversationState( MemoryStorage()) if conversation_state is None else conversation_state) dialog_state = self.conversation_state.create_property("DialogState") self._callback = self._get_default_callback(target_dialog, initial_dialog_options, dialog_state) if isinstance(channel_or_adapter, str): conversation_reference = ConversationReference( channel_id=channel_or_adapter) self.test_adapter = TestAdapter(self._callback, conversation_reference) self.test_adapter.use(AutoSaveStateMiddleware().add( self.conversation_state)) else: self.test_adapter = channel_or_adapter self._add_user_middlewares(middlewares)
def use_bot_state(bot_adapter: BotAdapter, *bot_states: BotState, auto: bool = True) -> BotAdapter: """ Registers bot state object into the TurnContext. The botstate will be available via the turn context. :param bot_adapter: The BotAdapter on which to register the state objects. :param bot_states: One or more BotState objects to register. :return: The updated adapter. """ if not bot_states: raise TypeError("At least one BotAdapter is required") for bot_state in bot_states: bot_adapter.use( RegisterClassMiddleware(bot_state, AdapterExtensions.fullname(bot_state))) if auto: bot_adapter.use(AutoSaveStateMiddleware(bot_states)) return bot_adapter
def use_state( adapter: BotAdapter, user_state: UserState, conversation_state: ConversationState, auto: bool = True, ) -> BotAdapter: """ [DEPRECATED] Registers user and conversation state objects with the adapter. These objects will be available via the turn context's `turn_state` property. :param adapter: The BotAdapter on which to register the state objects. :param user_state: The UserState object to register. :param conversation_state: The ConversationState object to register. :param auto: True to automatically persist state each turn. :return: The BotAdapter """ warn( "This method is deprecated in 4.9. You should use the method .use_bot_state() instead.", DeprecationWarning, ) if not adapter: raise TypeError("BotAdapter is required") if not user_state: raise TypeError("UserState is required") if not conversation_state: raise TypeError("ConversationState is required") adapter.use(RegisterClassMiddleware(user_state)) adapter.use(RegisterClassMiddleware(conversation_state)) if auto: adapter.use( AutoSaveStateMiddleware([user_state, conversation_state])) return adapter
async def test_should_add_and_call_load_all_on_single_plugin(self): adapter = TestAdapter() context = TurnContext(adapter, Activity()) foo_state = BotStateMock({"foo": "bar"}) bot_state_set = AutoSaveStateMiddleware().add(foo_state) await bot_state_set.bot_state_set.load_all(context)
async def test_should_not_add_any_bot_state_on_construction_if_none_are_passed_in( self): middleware = AutoSaveStateMiddleware() assert (not middleware.bot_state_set.bot_states ), "should not have added any BotState."
async def create_test_flow( dialog: Dialog, test_case: SkillFlowTestCase = SkillFlowTestCase.root_bot_only, enabled_trace=False, ) -> TestAdapter: conversation_id = "testFlowConversationId" storage = MemoryStorage() conversation_state = ConversationState(storage) user_state = UserState(storage) activity = Activity( channel_id="test", service_url="https://test.com", from_property=ChannelAccount(id="user1", name="User1"), recipient=ChannelAccount(id="bot", name="Bot"), conversation=ConversationAccount(is_group=False, conversation_type=conversation_id, id=conversation_id), ) dialog_manager = DialogManager(dialog) dialog_manager.user_state = user_state dialog_manager.conversation_state = conversation_state async def logic(context: TurnContext): if test_case != SkillFlowTestCase.root_bot_only: # Create a skill ClaimsIdentity and put it in turn_state so isSkillClaim() returns True. claims_identity = ClaimsIdentity({}, False) claims_identity.claims[ "ver"] = "2.0" # AuthenticationConstants.VersionClaim claims_identity.claims["aud"] = ( SimpleComponentDialog.skill_bot_id ) # AuthenticationConstants.AudienceClaim claims_identity.claims["azp"] = ( SimpleComponentDialog.parent_bot_id ) # AuthenticationConstants.AuthorizedParty context.turn_state[ BotAdapter.BOT_IDENTITY_KEY] = claims_identity if test_case == SkillFlowTestCase.root_bot_consuming_skill: # Simulate the SkillConversationReference with a channel OAuthScope stored in turn_state. # This emulates a response coming to a root bot through SkillHandler. context.turn_state[ SkillHandler. SKILL_CONVERSATION_REFERENCE_KEY] = SkillConversationReference( None, AuthenticationConstants. TO_CHANNEL_FROM_BOT_OAUTH_SCOPE) if test_case == SkillFlowTestCase.middle_skill: # Simulate the SkillConversationReference with a parent Bot ID stored in turn_state. # This emulates a response coming to a skill from another skill through SkillHandler. context.turn_state[ SkillHandler. SKILL_CONVERSATION_REFERENCE_KEY] = SkillConversationReference( None, SimpleComponentDialog.parent_bot_id) async def aux( turn_context: TurnContext, # pylint: disable=unused-argument activities: List[Activity], next: Callable, ): for activity in activities: if activity.type == ActivityTypes.end_of_conversation: SimpleComponentDialog.eoc_sent = activity break return await next() # Interceptor to capture the EoC activity if it was sent so we can assert it in the tests. context.on_send_activities(aux) SimpleComponentDialog.dm_turn_result = await dialog_manager.on_turn( context) adapter = TestAdapter(logic, activity, enabled_trace) adapter.use(AutoSaveStateMiddleware([user_state, conversation_state])) return adapter