Пример #1
0
def test_script_execution_service_worker_handles_request_to_list_invalid_id(caplog):
    """
    The ValueError raised when SES.summarise is given an invalid PID should be handled.
    """
    helper = PubSubHelper()

    work_q = MPQueue()
    msg = EventMessage(
        "TEST_SUMMARY",
        "PUBSUB",
        dict(topic=topics.request.procedure.list, kwargs={"request_id": "123"}),
    )
    work_q.put(msg)

    with mock.patch(
        "oet.procedure.application.main.ScriptExecutionService.summarise"
    ) as mock_cls:
        mock_cls.side_effect = ValueError
        _proc_worker_wrapper_helper(
            caplog,
            ScriptExecutionServiceWorker,
            args=(work_q,),
            expect_shutdown_evt=True,
        )

    mock_cls.assert_called_once()

    assert helper.topic_list == [
        topics.request.procedure.list,  # list requested
        topics.procedure.pool.list,  # response published
    ]
    assert helper.messages[1][1] == dict(msg_src="TEST", request_id="123", result=[])
Пример #2
0
def test_script_execution_service_worker_verify_list_method_called(caplog):
    """
    SES.summarise should be called when 'request.procedure.list' message is received
    """
    helper = PubSubHelper()

    work_q = MPQueue()
    msg = EventMessage(
        "TEST_SUMMARY",
        "PUBSUB",
        dict(topic=topics.request.procedure.list, kwargs={"request_id": "123"}),
    )
    work_q.put(msg)
    event = mp.Event()

    with mock.patch(
        "oet.procedure.application.main.ScriptExecutionService.summarise"
    ) as mock_cls:
        mock_cls.side_effect = partial(set_event, event)
        _proc_worker_wrapper_helper(
            caplog,
            ScriptExecutionServiceWorker,
            args=(work_q,),
            expect_shutdown_evt=True,
        )

    assert event.is_set() is True
    mock_cls.assert_called_once()

    assert helper.topic_list == [
        topics.request.procedure.list,  # list requested
        topics.procedure.pool.list,  # response published
    ]
Пример #3
0
def _proc_worker_wrapper_helper(caplog,
                                worker_class,
                                args=None,
                                expect_shutdown_evt=True,
                                alarm_secs=1.0):
    startup_evt = mp.Event()
    shutdown_evt = mp.Event()
    event_q = MPQueue()
    if args is None:
        args = ()

    def alarm_handler(signal_num, current_stack_frame):
        shutdown_evt.set()

    if alarm_secs:
        signal.signal(signal.SIGALRM, alarm_handler)
        signal.setitimer(signal.ITIMER_REAL, alarm_secs)
    caplog.set_level(logging.DEBUG)
    exitcode = proc_worker_wrapper(worker_class, "TEST", startup_evt,
                                   shutdown_evt, event_q, *args)
    assert startup_evt.is_set()
    assert shutdown_evt.is_set() == expect_shutdown_evt
    items = list(event_q.drain())
    assert items
    last_item = items[-1]
    assert last_item.msg_src == "TEST"
    assert last_item.msg_type == "SHUTDOWN"
    assert last_item.msg == "Normal"
    assert exitcode == 0

    return items[:-1]
Пример #4
0
def test_proc_worker_run(caplog):
    class ProcWorkerTest(ProcWorker):
        def init_args(self, args):
            self.args = args

        def main_func(self):
            self.log(logging.INFO, f"MAIN_FUNC: {self.args}")
            self.shutdown_event.set()

    startup_evt = mp.Event()
    shutdown_evt = mp.Event()
    event_q = MPQueue()

    caplog.set_level(logging.INFO)
    pw = ProcWorkerTest("TEST", startup_evt, shutdown_evt, event_q, "ARG1",
                        "ARG2")
    assert not startup_evt.is_set()
    assert not shutdown_evt.is_set()

    pw.run()

    assert startup_evt.is_set()
    assert shutdown_evt.is_set()
    item = event_q.safe_get()
    assert item
    assert item.msg_src == "TEST"
    assert item.msg_type == "SHUTDOWN"
    assert item.msg == "Normal"
    assert f"MAIN_FUNC: ('ARG1', 'ARG2')" in caplog.text
Пример #5
0
def test_queue_put():
    # Create MPQueue of max size 2
    q = MPQueue(2)
    # Putting two items should succeed and return True
    assert q.safe_put("ITEM1")
    assert q.safe_put("ITEM2")
    # But once full, puts should return False
    assert not q.safe_put("ITEM3")

    num_left = q.safe_close()
    assert num_left == 2
Пример #6
0
def test_proc_start_hangs(caplog):
    shutdown_evt = mp.Event()
    event_q = MPQueue()
    log_q = MPQueue()
    caplog.set_level(logging.INFO)
    Proc.STARTUP_WAIT_SECS = 0.2
    try:
        with pytest.raises(RuntimeError):
            Proc("TEST", StartHangWorker, shutdown_evt, event_q, log_q)
    finally:
        Proc.STARTUP_WAIT_SECS = 3.0
Пример #7
0
def test_proc_worker_no_main_func(caplog):
    startup_evt = mp.Event()
    shutdown_evt = mp.Event()
    event_q = MPQueue()

    try:
        caplog.set_level(logging.INFO)
        pw = ProcWorker("TEST", startup_evt, shutdown_evt, event_q)
        with pytest.raises(NotImplementedError):
            pw.main_func()

    finally:
        event_q.safe_close()
Пример #8
0
def test_queue_proc_worker(caplog):
    work_q = MPQueue()
    work_q.put(1)
    work_q.put(2)
    work_q.put(3)
    work_q.put(4)
    work_q.put("END")
    work_q.put(5)

    items = _proc_worker_wrapper_helper(caplog,
                                        QueueProcWorkerTest,
                                        args=(work_q, ),
                                        expect_shutdown_evt=False)
    assert len(items) == 4
    assert items == [f"DONE {idx + 1}" for idx in range(4)]
Пример #9
0
def test_procworker_passes_excess_arguments_to_init_args():
    class ProcWorkerTest(ProcWorker):
        def init_args(self, args):
            (l, ) = args
            l.extend(["ARG1", "ARG2"])

    arglist = []
    ProcWorkerTest("TEST", mp.Event(), mp.Event(), MPQueue(), arglist)
    assert arglist == ["ARG1", "ARG2"]
Пример #10
0
def test_proc_full_stop(caplog):
    shutdown_evt = mp.Event()
    event_q = MPQueue()
    caplog.set_level(logging.INFO)
    proc = Proc("TEST", TimerProcWorkerTest, shutdown_evt, event_q)

    for idx in range(4):
        item = event_q.safe_get(1.0)
        assert item, f"idx: {idx}"
        assert item.startswith(f"TIMER {idx + 1} [")

    item = event_q.safe_get(1.0)
    assert item.msg_src == "TEST"
    assert item.msg_type == "SHUTDOWN"
    assert item.msg == "Normal"

    proc.full_stop(wait_time=0.5)

    assert not proc.proc.is_alive()
Пример #11
0
def test_event_bus_worker_verify_message_publishes_when_message_in_work_queue(caplog):
    """
    Verify that message event is published if the event originates from an
    external source.
    """
    helper = PubSubHelper()

    work_q = MPQueue()
    msg = EventMessage(
        "EXTERNAL COMPONENT",
        "PUBSUB",
        dict(topic=topics.request.procedure.list, kwargs={"request_id": "123"}),
    )
    work_q.put(msg)
    _proc_worker_wrapper_helper(
        caplog, EventBusWorker, args=(work_q,), expect_shutdown_evt=True
    )

    assert topics.request.procedure.list in helper.topic_list
Пример #12
0
def test_main_loop_checks_shutdown_event_after_every_queue_get():
    """
    Loop should regularly check shutdown event,
    """
    mock_ctx = mock.MagicMock()

    event_q = MPQueue()
    mock_ctx.event_queue.safe_get.side_effect = [
        False,
        False,
        EventMessage("TEST", "END", msg="foo"),
    ]

    # loop won't exit as a result of shutdown_event being True
    mock_ctx.shutdown_event.is_set.side_effect = [False, False, False, False, False]

    main_loop(mock_ctx, [])

    assert event_q.safe_close() == 0
    assert mock_ctx.shutdown_event.is_set.call_count == 3
Пример #13
0
def test_event_bus_worker_does_not_publish_messages_from_self(caplog):
    """
    Verify that message event is not published if the event originates from
    an internal source.
    """
    helper = PubSubHelper()

    work_q = MPQueue()
    # TEST is the default component name assigned in
    # _proc_worker_wrapper_helper. This message should be ignored.
    msg = EventMessage(
        "TEST",
        "PUBSUB",
        dict(topic=topics.request.procedure.list, kwargs={"request_id": "123"}),
    )

    work_q.put(msg)
    # But coming from NONTEST, this message should be republished.
    msg = EventMessage(
        "NONTEST",
        "PUBSUB",
        dict(topic=topics.request.procedure.list, kwargs={"request_id": "456"}),
    )
    work_q.put(msg)

    _proc_worker_wrapper_helper(
        caplog, EventBusWorker, args=(work_q,), expect_shutdown_evt=True
    )

    assert len(helper.messages) == 1
    assert helper.messages[0][1] == dict(msg_src="NONTEST", request_id="456")
Пример #14
0
def test_main_loop_ends_on_end_message():
    """
    Main loop should terminate when end messsage is received.
    """
    mock_ctx = mock.MagicMock()

    event_q = MPQueue()
    event_q.put(EventMessage("TEST", "PUBSUB", msg="foo"))
    event_q.put(EventMessage("TEST", "PUBSUB", msg="foo"))
    event_q.put(EventMessage("TEST", "PUBSUB", msg="foo"))
    event_q.put(EventMessage("TEST", "END", msg="foo"))
    mock_ctx.event_queue = event_q

    mock_ctx.shutdown_event.is_set.return_value = False

    main_loop(mock_ctx, [])

    assert event_q.safe_close() == 0
Пример #15
0
def test_flask_worker_starts_flask(caplog):
    """
    Verify that the FlaskWorker starts Flask.
    """
    with mock.patch("flask.Flask") as mock_flask:
        # mock Flask causes connection error in shutdown as shutdown URL is accessed
        with mock.patch("requests.post"):
            _proc_worker_wrapper_helper(
                caplog, FlaskWorker, args=(MPQueue(),), expect_shutdown_evt=True
            )

        mock_app_instance = mock_flask.return_value
        mock_app_instance.run.assert_called_once()
Пример #16
0
def test_proc_worker_exception(caplog):
    class ProcWorkerException(ProcWorker):
        def main_func(self):
            raise NameError("Because this doesn't happen often")

    startup_evt = mp.Event()
    shutdown_evt = mp.Event()
    event_q = MPQueue()

    caplog.set_level(logging.INFO)
    with pytest.raises(SystemExit):
        proc_worker_wrapper(ProcWorkerException, "TEST", startup_evt,
                            shutdown_evt, event_q)
    assert startup_evt.is_set()
    assert not shutdown_evt.is_set()
    item = event_q.safe_get()
    assert item
    assert item.msg_src == "TEST"
    assert item.msg_type == "FATAL"
    assert item.msg == "Because this doesn't happen often"

    assert f"Exception Shutdown" in caplog.text
Пример #17
0
    def messages(self) -> Generator[Message, None, None]:
        """
        A generator of Message objects created from received pubsub events
        """
        q = MPQueue()

        def add_to_q(topic: pub.Topic = pub.AUTO_TOPIC, **kwargs):
            kwargs["topic"] = topic.name
            other = {}
            if "request_id" in kwargs:
                other["id"] = kwargs["request_id"]
                del kwargs["request_id"]

            msg = Message(kwargs, **other)
            q.put(msg)

        pub.subscribe(add_to_q, pub.ALL_TOPICS)

        while True:
            msg = q.safe_get(timeout=0.1)
            if msg is not None:
                yield msg
Пример #18
0
def test_mpqueue_get():
    Q = MPQueue()

    item = Q.safe_get(None)
    assert item is None

    Q.put("ITEM1")
    Q.put("ITEM2")

    assert Q.safe_get(0.02) == "ITEM1"
    assert Q.safe_get(0.02) == "ITEM2"
    assert Q.safe_get(0.02) is None
    assert Q.safe_get(None) is None

    num_left = Q.safe_close()
    assert num_left == 0
Пример #19
0
def test_main_loop_ends_when_shutdown_event_is_set():
    """
    Main loop should terminate when shutdown event is set.
    """
    mock_ctx = mock.MagicMock()

    event_q = MPQueue()
    event_q.put(EventMessage("TEST", "PUBSUB", msg="foo"))
    event_q.put(EventMessage("TEST", "PUBSUB", msg="foo"))
    event_q.put(EventMessage("TEST", "PUBSUB", msg="foo"))
    event_q.put(EventMessage("TEST", "END", msg="foo"))
    mock_ctx.event_queue = event_q

    # one processing loop before shutdown in set, at which point the loop
    # should exit with two messages still in the event queue
    mock_ctx.shutdown_event.is_set.side_effect = [False, False, True]

    main_loop(mock_ctx, [])

    assert event_q.safe_close() == 2
Пример #20
0
def assert_command_request_and_response(
    caplog, mock_method, request_topic, response_topic, cmd
):
    helper = PubSubHelper()

    work_q = MPQueue()
    msg = EventMessage(
        "UNITTEST",
        "PUBSUB",
        dict(topic=request_topic, kwargs={"request_id": "1234", "cmd": cmd}),
    )
    work_q.put(msg)
    event = mp.Event()

    mock_method.side_effect = partial(set_event, event)
    _proc_worker_wrapper_helper(
        caplog, ScriptExecutionServiceWorker, args=(work_q,), expect_shutdown_evt=True
    )

    assert event.is_set()
    mock_method.assert_called_once()
    assert mock_method.call_args[0][0] == cmd

    assert helper.topic_list == [request_topic, response_topic]
Пример #21
0
def test_drain_queue():
    Q = MPQueue()

    items = list(Q.drain())
    assert items == []

    expected = [f"ITEM{idx}" for idx in range(10)]
    for item in expected:
        Q.put(item)

    items = list(Q.drain())
    assert items == expected

    num_left = Q.safe_close()
    assert num_left == 0
Пример #22
0
def test_main_loop_ignores_and_logs_events_of_unknown_types():
    """
    Loop should log events it doesn't know how to handle.
    """
    mock_ctx = mock.MagicMock()

    event_q = MPQueue()
    event_q.put(EventMessage("TEST", "FOO", msg="1"))
    mock_ctx.event_queue = event_q

    # one processing loop before shutdown in set, at which point the loop
    # should exit with three messages still in the event queue
    mock_ctx.shutdown_event.is_set.side_effect = [False, True]

    main_loop(mock_ctx, [])

    event_q.safe_close()
    mock_ctx.log.assert_called_once()
    assert "Unknown Event" in mock_ctx.log.call_args[0][1]
Пример #23
0
def test_procworker_rejects_unexpected_arguments():
    with pytest.raises(ValueError):
        ProcWorker("TEST", mp.Event(), mp.Event(), MPQueue(), MPQueue(),
                   "ARG1", "ARG2")
Пример #24
0
def test_proc_full_stop_need_terminate(caplog):
    shutdown_evt = mp.Event()
    event_q = MPQueue()
    caplog.set_level(logging.INFO)
    proc = Proc("TEST", NeedTerminateWorker, shutdown_evt, event_q)
    proc.full_stop(wait_time=0.1)
Пример #25
0
def test_main_loop_adds_pubsub_messages_to_event_queues():
    """
    PUBSUB messages should be added to event queues.
    """
    mock_ctx = mock.MagicMock()

    event_q = MPQueue()
    event_q.put(EventMessage("TEST", "PUBSUB", msg="1"))
    event_q.put(EventMessage("TEST", "PUBSUB", msg="2"))
    event_q.put(EventMessage("TEST", "PUBSUB", msg="3"))
    event_q.put(EventMessage("TEST", "END", msg="foo"))
    mock_ctx.event_queue = event_q

    # one processing loop before shutdown in set, at which point the loop
    # should exit with three messages still in the event queue
    mock_ctx.shutdown_event.is_set.return_value = False

    q1 = MPQueue()
    q2 = MPQueue()

    main_loop(mock_ctx, [q1, q2])

    assert q1.safe_close() == 3
    assert q2.safe_close() == 3

    event_q.safe_close()