Esempio n. 1
0
def _add_unknown_events_tests(cls, module, all_events, handled_events):
    """
    Add tests for properly handling of "unknown events," which are events that aren't
    handled by a particular stage.  These operations should be passed up by any stage into
    the stages that proceed it..
    """

    unknown_events = all_except(all_items=all_events,
                                items_to_exclude=handled_events)

    if not unknown_events:
        return

    @pytest.mark.describe(
        "{} - .handle_pipeline_event() -- unknown and unhandled events".format(
            cls.__name__))
    class LocalTestObject(StageHandlePipelineEventTestBase):
        @pytest.fixture(params=unknown_events)
        def event(self, request):
            return make_mock_op_or_event(request.param)

        @pytest.fixture
        def stage(self):
            return cls()

        @pytest.mark.it("Passes unknown event to previous stage")
        def test_passes_event_to_previous_stage(self, stage, event, mocker):
            mocker.spy(stage, "send_event_up")
            stage.handle_pipeline_event(event)

            assert stage.send_event_up.call_count == 1
            assert stage.send_event_up.call_args == mocker.call(event)

    setattr(module, "Test{}UnknownEvents".format(cls.__name__),
            LocalTestObject)
Esempio n. 2
0
def _add_unknown_ops_tests(cls, module, all_ops, handled_ops):
    """
    Add tests for properly handling of "unknown operations," which are operations that aren't
    handled by a particular stage.  These operations should be passed down by any stage into
    the stages that follow.
    """
    unknown_ops = all_except(all_items=all_ops, items_to_exclude=handled_ops)

    @pytest.mark.describe(
        "{} - .run_op() -- unknown and unhandled operations".format(
            cls.__name__))
    class LocalTestObject(StageRunOpTestBase):
        @pytest.fixture(params=unknown_ops)
        def op(self, request, mocker):
            op = make_mock_op_or_event(request.param)
            op.callback_stack.append(mocker.MagicMock())
            return op

        @pytest.fixture
        def stage(self):
            if cls == PipelineRootStage:
                return cls(None)
            else:
                return cls()

        @pytest.mark.it("Passes unknown operation down to the next stage")
        def test_passes_op_to_next_stage(self, mocker, op, stage):
            mocker.spy(stage, "send_op_down")
            stage.run_op(op)
            assert stage.send_op_down.call_count == 1
            assert stage.send_op_down.call_args == mocker.call(op)

    setattr(module, "Test{}UnknownOps".format(cls.__name__), LocalTestObject)
def add_unknown_ops_tests(cls, module, all_ops, handled_ops):
    """
    Add tests for properly handling of "unknown operations," which are operations that aren't
    handled by a particular stage.  These operations should be passed down by any stage into
    the stages that follow.
    """
    unknown_ops = all_except(all_items=all_ops, items_to_exclude=handled_ops)

    @pytest.mark.describe("{} - .run_op() -- unknown and unhandled operations".format(cls.__name__))
    class LocalTestObject(object):
        @pytest.fixture
        def op(self, op_cls, callback):
            op = make_mock_op_or_event(op_cls)
            op.callback = callback
            op.action = "pend"
            add_mock_method_waiter(op, "callback")
            return op

        @pytest.fixture
        def stage(self, mocker):
            return make_mock_stage(mocker=mocker, stage_to_make=cls)

        @pytest.mark.it("Passes unknown operation to next stage")
        @pytest.mark.parametrize("op_cls", unknown_ops)
        def test_passes_op_to_next_stage(self, op_cls, op, stage):
            stage.run_op(op)
            assert stage.next.run_op.call_count == 1
            assert stage.next.run_op.call_args[0][0] == op

        @pytest.mark.it("Fails unknown operation if there is no next stage")
        @pytest.mark.parametrize("op_cls", unknown_ops)
        def test_passes_op_with_no_next_stage(self, op_cls, op, stage):
            stage.next = None
            stage.run_op(op)
            op.wait_for_callback_to_be_called()
            assert_callback_failed(op=op)

        @pytest.mark.it("Catches Exceptions raised when passing unknown operation to next stage")
        @pytest.mark.parametrize("op_cls", unknown_ops)
        def test_passes_op_to_next_stage_which_throws_exception(self, op_cls, op, stage):
            op.action = "exception"
            stage.run_op(op)
            op.wait_for_callback_to_be_called()
            assert_callback_failed(op=op)

        @pytest.mark.it(
            "Allows BaseExceptions raised when passing unknown operation to next start to propogate"
        )
        @pytest.mark.parametrize("op_cls", unknown_ops)
        def test_passes_op_to_next_stage_which_throws_base_exception(self, op_cls, op, stage):
            op.action = "base_exception"
            with pytest.raises(UnhandledException):
                stage.run_op(op)

    setattr(module, "Test{}UnknownOps".format(cls.__name__), LocalTestObject)
Esempio n. 4
0
def add_unknown_events_tests(cls, module, all_events, handled_events):
    """
    Add tests for properly handling of "unknown events," which are events that aren't
    handled by a particular stage.  These operations should be passed up by any stage into
    the stages that proceed it..
    """

    unknown_events = all_except(all_items=all_events,
                                items_to_exclude=handled_events)

    if not unknown_events:
        return

    @pytest.mark.describe(
        "{} - .handle_pipeline_event() -- unknown and unhandled events".format(
            cls.__name__))
    @pytest.mark.parametrize("event_cls", unknown_events)
    class LocalTestObject(object):
        @pytest.fixture
        def event(self, event_cls):
            return make_mock_op_or_event(event_cls)

        @pytest.fixture
        def stage(self, mocker):
            return make_mock_stage(mocker=mocker, stage_to_make=cls)

        @pytest.fixture
        def previous(self, stage, mocker):
            class PreviousStage(PipelineStage):
                def __init__(self):
                    super(PreviousStage, self).__init__()
                    self.handle_pipeline_event = mocker.MagicMock()

                def _run_op(self, op):
                    pass

            previous = PreviousStage()
            stage.previous = previous
            return previous

        @pytest.mark.it("Passes unknown event to previous stage")
        def test_passes_event_to_previous_stage(self, event_cls, stage, event,
                                                previous):
            stage.handle_pipeline_event(event)
            assert previous.handle_pipeline_event.call_count == 1
            assert previous.handle_pipeline_event.call_args[0][0] == event

        @pytest.mark.it(
            "Calls unhandled exception handler if there is no previous stage")
        def test_passes_event_with_no_previous_stage(self, event_cls, stage,
                                                     event,
                                                     unhandled_error_handler):
            stage.handle_pipeline_event(event)
            assert unhandled_error_handler.call_count == 1

        @pytest.mark.it(
            "Catches Exceptions raised when passing unknown event to previous stage"
        )
        def test_passes_event_to_previous_stage_which_throws_exception(
                self, event_cls, stage, event, previous,
                unhandled_error_handler):
            e = Exception()
            previous.handle_pipeline_event.side_effect = e
            stage.handle_pipeline_event(event)
            assert unhandled_error_handler.call_count == 1
            assert unhandled_error_handler.call_args[0][0] == e

        @pytest.mark.it(
            "Allows BaseExceptions raised when passing unknown operation to next start to propogate"
        )
        def test_passes_event_to_previous_stage_which_throws_base_exception(
                self, event_cls, stage, event, previous,
                unhandled_error_handler):
            e = UnhandledException()
            previous.handle_pipeline_event.side_effect = e
            with pytest.raises(UnhandledException):
                stage.handle_pipeline_event(event)
            assert unhandled_error_handler.call_count == 0

    setattr(module, "Test{}UnknownEvents".format(cls.__name__),
            LocalTestObject)
        stage.next.send_event_up(iot_response)
        assert op.callback.call_count == 0
        assert unhandled_error_handler.call_count == 0


"""
A note on terms in the TimeoutStage tests:
    No-timeout ops are ops that don't need a timeout check
    Yes-timeout ops are ops that do need a timeout check
"""
timeout_intervals = {
    pipeline_ops_mqtt.MQTTSubscribeOperation: 10,
    pipeline_ops_mqtt.MQTTUnsubscribeOperation: 10,
}
yes_timeout_ops = list(timeout_intervals.keys())
no_timeout_ops = all_except(all_common_ops, yes_timeout_ops)

pipeline_stage_test.add_base_pipeline_stage_tests(
    cls=pipeline_stages_base.TimeoutStage,
    module=this_module,
    all_ops=all_common_ops,
    handled_ops=yes_timeout_ops,
    all_events=all_common_events,
    handled_events=[],
    extra_initializer_defaults={"timeout_intervals": timeout_intervals},
)


@pytest.fixture()
def mock_timer(mocker):
    return mocker.patch(
Esempio n. 6
0
def add_unknown_ops_tests(cls, module, all_ops, handled_ops):
    """
    Add tests for properly handling of "unknown operations," which are operations that aren't
    handled by a particular stage.  These operations should be passed down by any stage into
    the stages that follow.
    """
    unknown_ops = all_except(all_items=all_ops, items_to_exclude=handled_ops)

    @pytest.mark.describe(
        "{} - .run_op() -- unknown and unhandled operations".format(
            cls.__name__))
    class LocalTestObject(StageTestBase):
        @pytest.fixture
        def op(self, op_cls, mocker):
            op = make_mock_op_or_event(op_cls)
            op.callback = mocker.MagicMock()
            add_mock_method_waiter(op, "callback")
            return op

        @pytest.fixture
        def stage(self):
            if cls == PipelineRootStage:
                return cls(None)
            else:
                return cls()

        @pytest.mark.it("Passes unknown operation to next stage")
        @pytest.mark.parametrize("op_cls", unknown_ops)
        def test_passes_op_to_next_stage(self, op_cls, op, stage):
            stage.run_op(op)
            assert stage.next.run_op.call_count == 1
            assert stage.next.run_op.call_args[0][0] == op

        @pytest.mark.it("Fails unknown operation if there is no next stage")
        @pytest.mark.parametrize("op_cls", unknown_ops)
        def test_passes_op_with_no_next_stage(self, op_cls, op, stage):
            stage.next = None
            stage.run_op(op)
            op.wait_for_callback_to_be_called()
            assert_callback_failed(op=op)

        @pytest.mark.it(
            "Catches Exceptions raised when passing unknown operation to next stage"
        )
        @pytest.mark.parametrize("op_cls", unknown_ops)
        def test_passes_op_to_next_stage_which_throws_exception(
                self, op_cls, op, stage, next_stage_raises_arbitrary_exception,
                arbitrary_exception):
            stage.run_op(op)
            op.wait_for_callback_to_be_called()
            assert_callback_failed(op=op, error=arbitrary_exception)

        @pytest.mark.it(
            "Allows BaseExceptions raised when passing unknown operation to next start to propogate"
        )
        @pytest.mark.parametrize("op_cls", unknown_ops)
        def test_passes_op_to_next_stage_which_throws_base_exception(
            self,
            op_cls,
            op,
            stage,
            next_stage_raises_arbitrary_base_exception,
            arbitrary_base_exception,
        ):
            with pytest.raises(arbitrary_base_exception.__class__) as e_info:
                stage.run_op(op)
            assert e_info.value is arbitrary_base_exception

    setattr(module, "Test{}UnknownOps".format(cls.__name__), LocalTestObject)
Esempio n. 7
0
def add_unknown_events_tests(cls, module, all_events, handled_events):
    """
    Add tests for properly handling of "unknown events," which are events that aren't
    handled by a particular stage.  These operations should be passed up by any stage into
    the stages that proceed it..
    """

    unknown_events = all_except(all_items=all_events,
                                items_to_exclude=handled_events)

    if not unknown_events:
        return

    @pytest.mark.describe(
        "{} - .handle_pipeline_event() -- unknown and unhandled events".format(
            cls.__name__))
    @pytest.mark.parametrize("event_cls", unknown_events)
    class LocalTestObject(StageTestBase):
        @pytest.fixture
        def event(self, event_cls):
            return make_mock_op_or_event(event_cls)

        @pytest.fixture
        def stage(self):
            return cls()

        @pytest.fixture
        def previous(self, stage, stage_base_configuration):
            return stage.previous

        @pytest.mark.it("Passes unknown event to previous stage")
        def test_passes_event_to_previous_stage(self, event_cls, stage, event,
                                                previous, mocker):
            mocker.spy(previous, "handle_pipeline_event")
            stage.handle_pipeline_event(event)
            assert previous.handle_pipeline_event.call_count == 1
            assert previous.handle_pipeline_event.call_args[0][0] == event

        @pytest.mark.it(
            "Calls unhandled exception handler if there is no previous stage")
        def test_passes_event_with_no_previous_stage(self, event_cls, stage,
                                                     event,
                                                     unhandled_error_handler):
            stage.previous = None
            stage.handle_pipeline_event(event)
            assert unhandled_error_handler.call_count == 1

        @pytest.mark.it(
            "Catches Exceptions raised when passing unknown event to previous stage"
        )
        def test_passes_event_to_previous_stage_which_throws_exception(
            self,
            event_cls,
            stage,
            event,
            previous,
            unhandled_error_handler,
            arbitrary_exception,
            mocker,
        ):
            previous.handle_pipeline_event = mocker.MagicMock(
                side_effect=arbitrary_exception)
            stage.handle_pipeline_event(event)
            assert unhandled_error_handler.call_count == 1
            assert unhandled_error_handler.call_args[0][
                0] == arbitrary_exception

        @pytest.mark.it(
            "Allows BaseExceptions raised when passing unknown operation to next start to propogate"
        )
        def test_passes_event_to_previous_stage_which_throws_base_exception(
            self,
            event_cls,
            stage,
            event,
            previous,
            unhandled_error_handler,
            arbitrary_base_exception,
            mocker,
        ):
            previous.handle_pipeline_event = mocker.MagicMock(
                side_effect=arbitrary_base_exception)
            with pytest.raises(arbitrary_base_exception.__class__) as e_info:
                stage.handle_pipeline_event(event)
            assert unhandled_error_handler.call_count == 0
            assert e_info.value is arbitrary_base_exception

    setattr(module, "Test{}UnknownEvents".format(cls.__name__),
            LocalTestObject)