Example #1
0
 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
Example #2
0
    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
Example #3
0
    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
Example #4
0
    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
Example #5
0
 def test_should_not_create_context_without_request(self):
     try:
         context = BotContext(SimpleAdapter(), None)
     except TypeError:
         pass
     except Exception as e:
         raise e
Example #6
0
    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
Example #7
0
 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)
Example #9
0
    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
Example #10
0
    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
Example #11
0
    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.')
Example #12
0
    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.')
Example #13
0
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.')
Example #14
0
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)
Example #15
0
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.')
Example #16
0
 def test_responded_should_be_automatically_set_to_False(self):
     context = BotContext(SimpleAdapter(), ACTIVITY)
     assert context.responded is False
Example #17
0
    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
Example #18
0
 def test_should_create_context_with_older_context(self):
     context = BotContext(SimpleAdapter(), ACTIVITY)
     new_context = BotContext(context)
Example #19
0
 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
Example #20
0
 def test_should_create_context_with_request_and_adapter(self):
     context = BotContext(SimpleAdapter(), ACTIVITY)