def test_should_not_be_able_to_set_responded_to_False(self): context = BotContext(SimpleAdapter(), ACTIVITY) try: context.responded = False except ValueError: pass except Exception as e: raise e
def test_apply_conversation_reference_when_is_incoming_is_True_should_not_prepare_a_reply( self): reference = BotContext.get_conversation_reference(ACTIVITY) reply = BotContext.apply_conversation_reference( Activity(type='message', text='reply'), reference, True) assert reply.recipient == ACTIVITY.recipient assert reply.from_property == ACTIVITY.from_property assert reply.conversation == ACTIVITY.conversation assert reply.service_url == ACTIVITY.service_url assert reply.channel_id == ACTIVITY.channel_id
async def test_should_call_on_update_activity_handler_before_update(self): context = BotContext(SimpleAdapter(), ACTIVITY) called = False async def update_handler(context, activity, next_handler_coroutine): nonlocal called called = True assert activity is not None assert context is not None assert activity.id == '1234' await next_handler_coroutine() context.on_update_activity(update_handler) await context.update_activity(ACTIVITY) assert called is True
async def test_should_call_send_on_activities_handler_before_send(self): context = BotContext(SimpleAdapter(), ACTIVITY) called = False async def send_handler(context, activities, next_handler_coroutine): nonlocal called called = True assert activities is not None assert context is not None assert activities[0].id == '1234' await next_handler_coroutine() context.on_send_activities(send_handler) await context.send_activity(ACTIVITY) assert called is True
def test_should_not_create_context_without_request(self): try: context = BotContext(SimpleAdapter(), None) except TypeError: pass except Exception as e: raise e
async def test_should_call_on_delete_activity_handlers_before_deletion( self): context = BotContext(SimpleAdapter(), ACTIVITY) called = False async def delete_handler(context, reference, next_handler_coroutine): nonlocal called called = True assert reference is not None assert context is not None assert reference.activity_id == '1234' await next_handler_coroutine() context.on_delete_activity(delete_handler) await context.delete_activity(ACTIVITY.id) assert called is True
def test_should_not_create_context_without_adapter(self): try: context = BotContext(None, ACTIVITY) except TypeError: pass except Exception as e: raise e
async def receive_activity(self, activity): """ INTERNAL: called by a `TestFlow` instance to simulate a user sending a message to the bot. This will cause the adapters middleware pipe to be run and it's logic to be called. :param activity: :return: """ if type(activity) == str: activity = Activity(type='message', text=activity) # Initialize request request = copy(self.template) for key, value in vars(activity).items(): if value is not None and key != 'additional_properties': setattr(request, key, value) if not request.type: request.type = ActivityTypes.message if not request.id: self._next_id += 1 request.id = str(self._next_id) # Create context object and run middleware context = BotContext(self, request) return await self.run_middleware(context, self.logic)
def test_get_conversation_reference_should_return_valid_reference(self): reference = BotContext.get_conversation_reference(ACTIVITY) assert reference.activity_id == ACTIVITY.id assert reference.user == ACTIVITY.from_property assert reference.bot == ACTIVITY.recipient assert reference.conversation == ACTIVITY.conversation assert reference.channel_id == ACTIVITY.channel_id assert reference.service_url == ACTIVITY.service_url
async def test_should_call_multiple_on_delete_activity_handlers_in_order( self): context = BotContext(SimpleAdapter(), ACTIVITY) called_first = False called_second = False async def first_delete_handler(context, reference, next_handler_coroutine): nonlocal called_first, called_second assert called_first is False, 'called_first should not be True before first_delete_handler is called.' called_first = True assert called_second is False, 'Second on_delete_activity handler was called before first.' assert reference is not None assert context is not None assert reference.activity_id == '1234' await next_handler_coroutine() async def second_delete_handler(context, reference, next_handler_coroutine): nonlocal called_first, called_second assert called_first assert called_second is False, 'called_second was set to True before second handler was called.' called_second = True assert reference is not None assert context is not None assert reference.activity_id == '1234' await next_handler_coroutine() context.on_delete_activity(first_delete_handler) context.on_delete_activity(second_delete_handler) await context.delete_activity(ACTIVITY.id) assert called_first is True assert called_second is True
async def test_should_reject_with_error_if_from_property_is_missing(self): context = BotContext(self.adapter, MISSING_FROM_PROPERTY) async def next_middleware(): assert False, 'Should not have called next_middleware' try: await self.middleware.on_process_request(context, next_middleware) except AttributeError: pass else: raise AssertionError( 'Should not have completed and not raised AttributeError.')
async def test_should_reject_with_error_if_conversation_is_missing(self): context = BotContext(self.adapter, MISSING_CONVERSATION) async def next_middleware(): assert False, 'should not have called next_middleware' try: await self.middleware.on_process_request(context, next_middleware) except AttributeError: pass except Exception as e: raise e else: raise AssertionError('Should not have completed and not raised AttributeError.')
class TestUserState: storage = MemoryStorage() adapter = TestAdapter() context = BotContext(adapter, RECEIVED_MESSAGE) middleware = UserState(storage) @pytest.mark.asyncio async def test_should_load_and_save_state_from_storage(self): async def next_middleware(): state = await self.middleware.get(self.context) assert isinstance(state, StoreItem), 'State not loaded' state.test = 'foo' await self.middleware.on_process_request(self.context, next_middleware) key = self.middleware.get_storage_key(self.context) assert type(key) == str, 'Key not found' items = await self.storage.read([key]) assert key in items, 'Saved state not found in storage' assert items[key].test == 'foo', 'Missing test value in stored state.' @pytest.mark.asyncio async def test_should_reject_with_error_if_channel_id_is_missing(self): context = BotContext(self.adapter, MISSING_CHANNEL_ID) async def next_middleware(): assert False, 'Should not have called next_middleware' try: await self.middleware.on_process_request(context, next_middleware) except AttributeError: pass else: raise AssertionError( 'Should not have completed and not raised AttributeError.') @pytest.mark.asyncio async def test_should_reject_with_error_if_from_property_is_missing(self): context = BotContext(self.adapter, MISSING_FROM_PROPERTY) async def next_middleware(): assert False, 'Should not have called next_middleware' try: await self.middleware.on_process_request(context, next_middleware) except AttributeError: pass else: raise AssertionError( 'Should not have completed and not raised AttributeError.')
class TestBotState: storage = MemoryStorage() adapter = TestAdapter() context = BotContext(adapter, RECEIVED_MESSAGE) middleware = BotState(storage, key_factory) @pytest.mark.asyncio async def test_should_return_undefined_from_get_if_nothing_cached(self): state = await self.middleware.get(self.context) assert state is None, 'state returned' @pytest.mark.asyncio async def test_should_load_and_save_state_from_storage(self): async def next_middleware(): state = cached_state(self.context, self.middleware.state_key) assert state is not None, 'state not loaded' state.test = 'foo' await self.middleware.on_process_request(self.context, next_middleware) items = await self.storage.read([STORAGE_KEY]) assert STORAGE_KEY in items, 'saved state not found in storage.' assert items[ STORAGE_KEY].test == 'foo', 'Missing test value in stored state.' @pytest.mark.skipif( True, reason= 'skipping while goal of test is investigated, test currently fails') @pytest.mark.asyncio async def test_should_force_read_of_state_from_storage(self): async def next_middleware(): state = cached_state(self.context, self.middleware.state_key) assert state.test == 'foo', 'invalid initial state' del state.test # items will not have the attribute 'test' items = await self.middleware.read(self.context, True) # Similarly, the returned value from cached_state will also not have the attribute 'test' assert cached_state( self.context, self.middleware.state_key).test == 'foo', 'state not reloaded' await self.middleware.on_process_request(self.context, next_middleware) @pytest.mark.asyncio async def test_should_clear_state_storage(self): async def next_middleware(): assert cached_state(self.context, self.middleware.state_key ).test == 'foo', 'invalid initial state' await self.middleware.clear(self.context) cached_state_data = cached_state(self.context, self.middleware.state_key) assert not hasattr(cached_state_data, 'test'), 'state not cleared on context.' await self.middleware.on_process_request(self.context, next_middleware) items = await self.storage.read([STORAGE_KEY]) assert not hasattr(items[STORAGE_KEY], 'test'), 'state not cleared from storage.' @pytest.mark.asyncio async def test_should_force_immediate_write_of_state_to_storage(self): async def next_middleware(): state = cached_state(self.context, self.middleware.state_key) assert not hasattr(state, 'test'), 'invalid initial state' state.test = 'foo' await self.middleware.write(self.context, True) items = await self.storage.read([STORAGE_KEY]) assert items[ STORAGE_KEY].test == 'foo', 'state not immediately flushed.' await self.middleware.on_process_request(self.context, next_middleware) @pytest.mark.asyncio async def test_should_read_from_storage_if_cached_state_missing(self): self.context.services[self.middleware.state_key] = None state = await self.middleware.read(self.context) assert state.test == 'foo', 'state not loaded' @pytest.mark.asyncio async def test_should_read_from_cache(self): state = await self.middleware.read(self.context) assert state.test == 'foo', 'state not loaded' @pytest.mark.asyncio async def test_should_force_write_to_storage_of_an_empty_state_object( self): self.context.services[self.middleware.state_key] = None await self.middleware.write(self.context, True) @pytest.mark.asyncio async def test_should_noop_calls_to_clear_when_nothing_cached(self): self.context.services[self.middleware.state_key] = None await self.middleware.clear(self.context)
class TestConversationState: storage = MemoryStorage() adapter = TestAdapter() context = BotContext(adapter, RECEIVED_MESSAGE) middleware = ConversationState(storage) @pytest.mark.asyncio async def test_should_load_and_save_state_from_storage(self): key = None async def next_middleware(): nonlocal key key = self.middleware.get_storage_key(self.context) state = await self.middleware.get(self.context) assert state is not None, 'State not loaded' assert key is not None, 'Key not found' state.test = 'foo' await self.middleware.on_process_request(self.context, next_middleware) items = await self.storage.read([key]) assert key in items, 'Saved state not found in storage.' assert items[key].test == 'foo', 'Missing test value in stored state.' @pytest.mark.asyncio async def test_should_ignore_any_activities_that_are_not_endOfConversation(self): key = None async def next_middleware(): nonlocal key key = self.middleware.get_storage_key(self.context) state = await self.middleware.get(self.context) assert state.test == 'foo', 'invalid initial state' await self.context.send_activity(Activity(type='message', text='foo')) await self.middleware.on_process_request(self.context, next_middleware) items = await self.storage.read([key]) assert hasattr(items[key], 'test'), 'state cleared and should not have been' @pytest.mark.asyncio async def test_should_reject_with_error_if_channel_id_is_missing(self): context = BotContext(self.adapter, MISSING_CHANNEL_ID) async def next_middleware(): assert False, 'should not have called next_middleware' try: await self.middleware.on_process_request(context, next_middleware) except AttributeError: pass except Exception as e: raise e else: raise AssertionError('Should not have completed and not raised AttributeError.') @pytest.mark.asyncio async def test_should_reject_with_error_if_conversation_is_missing(self): context = BotContext(self.adapter, MISSING_CONVERSATION) async def next_middleware(): assert False, 'should not have called next_middleware' try: await self.middleware.on_process_request(context, next_middleware) except AttributeError: pass except Exception as e: raise e else: raise AssertionError('Should not have completed and not raised AttributeError.')
def test_responded_should_be_automatically_set_to_False(self): context = BotContext(SimpleAdapter(), ACTIVITY) assert context.responded is False
def test_copy_to_should_copy_all_references(self): old_adapter = SimpleAdapter() old_activity = Activity(id='2', type='message', text='test copy') old_context = BotContext(old_adapter, old_activity) old_context.responded = True async def send_activities_handler(context, activities, next_handler): assert context is not None assert activities is not None assert next_handler is not None await next_handler async def delete_activity_handler(context, reference, next_handler): assert context is not None assert reference is not None assert next_handler is not None await next_handler async def update_activity_handler(context, activity, next_handler): assert context is not None assert activity is not None assert next_handler is not None await next_handler old_context.on_send_activities(send_activities_handler) old_context.on_delete_activity(delete_activity_handler) old_context.on_update_activity(update_activity_handler) adapter = SimpleAdapter() new_context = BotContext(adapter, ACTIVITY) assert len(new_context._on_send_activities) == 0 assert len(new_context._on_update_activity) == 0 assert len(new_context._on_delete_activity) == 0 old_context.copy_to(new_context) assert new_context.adapter == old_adapter assert new_context.activity == old_activity assert new_context.responded is True assert len(new_context._on_send_activities) == 1 assert len(new_context._on_update_activity) == 1 assert len(new_context._on_delete_activity) == 1
def test_should_create_context_with_older_context(self): context = BotContext(SimpleAdapter(), ACTIVITY) new_context = BotContext(context)
def test_should_be_able_to_set_responded_to_True(self): context = BotContext(SimpleAdapter(), ACTIVITY) assert context.responded is False context.responded = True assert context.responded
def test_should_create_context_with_request_and_adapter(self): context = BotContext(SimpleAdapter(), ACTIVITY)