Пример #1
0
 def test_prep_processing_pipeline_direction_unknown_raises_exception(
         self, three_level_app_chain):
     with pytest.raises(ValidationError):
         with connection_manager() as conn:
             pipeline = BasePipeline(connection_name=conn.name,
                                     installed_apps=three_level_app_chain)
             pipeline._setup_message_handling("inbound")
Пример #2
0
    async def test_stop_allows_only_one_stop_process_to_run_concurrently(
            self, three_level_app_chain):
        with connection_manager() as conn:
            pipeline = BasePipeline(connection_name=conn.name,
                                    installed_apps=three_level_app_chain)

            # Mock all of the apps that have been configured for this pipeline.
            for key, app in pipeline._installed_apps.items():
                app_mock = MagicMock(app.__class__)
                app_mock.stop = get_mock_async()

                pipeline._installed_apps[key] = app_mock

            asyncio.create_task(pipeline.stop())
            asyncio.create_task(pipeline.stop())
            asyncio.create_task(pipeline.stop())
            await pipeline.stop()

            for app in pipeline.apps.values():
                assert app.stop.called
                assert app.stop.call_count == 1

            # Wait for separate tasks to complete
            tasks = asyncio.all_tasks()
            await asyncio.wait(tasks, timeout=0.1)
Пример #3
0
    async def test_start_starts_apps_in_reverse_order(self,
                                                      three_level_app_chain):
        with connection_manager() as conn:
            pipeline = BasePipeline(connection_name=conn.name,
                                    installed_apps=three_level_app_chain)

            mock_parent = MagicMock()

            # Mock all of the apps that have been configured for this pipeline.
            for key, app in pipeline._installed_apps.items():
                app_mock = MagicMock(app.__class__)
                app_mock.name = app.name

                setattr(mock_parent, app.name, app_mock)

                pipeline._installed_apps[key] = app_mock

            pipeline.stopped_event.set(
            )  # Stop pipeline immediately after start has been executed
            await pipeline.start()

            for app in pipeline.apps.values():
                assert app.start.called
                assert app.start.call_count == 1

            call_order = [
                call[0].rstrip(".start")
                for call in mock_parent.method_calls[-len(pipeline.apps):]
            ]
            assert call_order == list(reversed(pipeline.apps.keys()))

            await pipeline.stop()
Пример #4
0
    async def test_stop_stops_apps_in_top_down_order(self,
                                                     three_level_app_chain):
        with connection_manager() as conn:
            pipeline = BasePipeline(connection_name=conn.name,
                                    installed_apps=three_level_app_chain)

            mock_parent = MagicMock()

            # Mock all of the apps that have been configured for this pipeline.
            for key, app in pipeline._installed_apps.items():
                app_mock = MagicMock(app.__class__)
                app_mock.name = app.name

                setattr(mock_parent, app.name, app_mock)

                pipeline._installed_apps[key] = app_mock

            await pipeline.stop()

            for app in pipeline.apps.values():
                assert app.stop.called
                assert app.stop.call_count == 1

            call_order = [
                call[0].rstrip("stop").rstrip(".")
                for call in mock_parent.method_calls[-len(pipeline.apps):]
            ]
            assert call_order == list(pipeline.apps.keys())
Пример #5
0
    async def test_send_stop(self, three_level_stop_app_chain):
        with connection_manager() as conn:
            pipeline = BasePipeline(connection_name=conn.name,
                                    installed_apps=three_level_stop_app_chain)

            # Simulate all apps active
            pipeline._active_apps = OrderedDict(pipeline.apps.items())

            message = await pipeline.send(admin.TestRequestMessage("Test"))
            assert message.TestReqID == "Test s3"
Пример #6
0
    def test_prep_processing_pipeline_inbound_order(self,
                                                    three_level_app_chain):
        with connection_manager() as conn:
            pipeline = BasePipeline(connection_name=conn.name,
                                    installed_apps=three_level_app_chain)

            func, app_chain = pipeline._setup_message_handling(
                pipeline.INBOUND_PROCESSING)
            assert func == "on_receive"
            assert next(app_chain).name == "below"
            assert next(app_chain).name == "middle"
            assert next(app_chain).name == "top"
Пример #7
0
def get_wsgi_application(*args, session_name=None):
    gunicorn_logger = logging.getLogger("gunicorn.error")
    app.logger.handlers = gunicorn_logger.handlers
    app.logger.setLevel(gunicorn_logger.level)

    settings.logger = app.logger

    if session_name is None:
        session_name = settings.default_session_name

    app.fix_pipeline = BasePipeline(connection_name=session_name)

    if RESTfulServiceApp.name not in app.fix_pipeline.apps.keys():
        app.logger.warning(
            f"'{RESTfulServiceApp.name}' was not found in the pipeline. It might be unnecessary to run "
            f"WTFIX with a Flask server (unless any of your custom apps also need to serve HTTP requests). "
            f"You should probably use 'run_client.py' instead if you want to use WTFIX as a standalone application."
        )

    atexit.register(
        app.fix_pipeline.stop
    )  # Stop the pipeline when the server is shut down
    app.fix_pipeline.start()

    return app
Пример #8
0
    async def test_send_stop(self, three_level_stop_app_chain):
        with connection_manager() as conn:
            pipeline = BasePipeline(connection_name=conn.name,
                                    installed_apps=three_level_stop_app_chain)

            message = await pipeline.send(admin.TestRequestMessage("Test"))
            assert message.TestReqID == "Test s3"
Пример #9
0
 def test_load_apps_falls_back_to_settings(self):
     with connection_manager() as conn:
         pipeline = BasePipeline(connection_name=conn.name)
         assert len(pipeline.apps) == len(pipeline.settings.PIPELINE_APPS)
         assert all(f"{app.__class__.__module__}.{app.__class__.__name__}"
                    in pipeline.settings.PIPELINE_APPS
                    for app in pipeline.apps.values())
Пример #10
0
    def test_pre_processing_pipeline_outbound_order(self,
                                                    three_level_app_chain):
        with connection_manager() as conn:
            pipeline = BasePipeline(connection_name=conn.name,
                                    installed_apps=three_level_app_chain)

            # Simulate all apps active
            pipeline._active_apps = OrderedDict(pipeline.apps.items())

            func, app_chain = pipeline._setup_message_handling(
                pipeline.OUTBOUND_PROCESSING)

            assert func == "on_send"
            assert next(app_chain).name == "top"
            assert next(app_chain).name == "middle"
            assert next(app_chain).name == "below"
Пример #11
0
async def main():
    logging.basicConfig(
        level=settings.LOGGING_LEVEL,
        format="%(asctime)s - %(threadName)s - %(module)s - %(levelname)s - %(message)s",
    )

    args = parser.parse_args()
    exit_code = os.EX_OK

    with connection_manager(args.connection) as conn:
        fix_pipeline = BasePipeline(
            connection_name=conn.name, new_session=args.new_session
        )

        try:
            # Graceful shutdown on termination signals.
            # See: https://docs.python.org/3.7/library/asyncio-eventloop.html#set-signal-handlers-for-sigint-and-sigterm
            loop = asyncio.get_running_loop()
            for sig_name in {"SIGINT", "SIGTERM"}:
                loop.add_signal_handler(
                    getattr(signal, sig_name),
                    lambda: asyncio.create_task(
                        graceful_shutdown(fix_pipeline, sig_name=sig_name)
                    ),
                )

            await fix_pipeline.start()

        except ImproperlyConfigured as e:
            # User needs to fix config issue before restart is attempted. Set os.EX_OK so that system process
            # monitors like Supervisor do not attempt a restart immediately.
            await graceful_shutdown(fix_pipeline, error=e)

        except KeyboardInterrupt:
            logger.info("Received keyboard interrupt! Initiating shutdown...")
            await graceful_shutdown(fix_pipeline)

        except Exception as e:
            await graceful_shutdown(fix_pipeline, error=e)
            exit_code = os.EX_UNAVAILABLE  # Abnormal termination

        finally:
            # Report tasks that are still running after shutdown.
            tasks = [
                task
                for task in asyncio.all_tasks()
                if task is not asyncio.current_task() and not task.cancelled()
            ]

            if tasks:
                task_output = "\n".join(str(task) for task in tasks)
                logger.warning(
                    f"There are still {len(tasks)} tasks running that have not been cancelled! Cancelling them now...\n"
                    f"{task_output}."
                )

                for task in tasks:
                    task.cancel()

            sys.exit(exit_code)
Пример #12
0
    async def test_stop_cancels_all_tasks_on_stop_timeout(
            self, three_level_app_chain):
        with pytest.raises(futures.CancelledError):
            with connection_manager() as conn:
                pipeline = BasePipeline(connection_name=conn.name,
                                        installed_apps=three_level_app_chain)

                settings.STOP_TIMEOUT = 0.1
                # Mock all of the apps that have been configured for this pipeline.
                for key, app in pipeline._installed_apps.items():
                    app_mock = MagicMock(app.__class__)
                    app_mock.stop = get_slow_mock_async(settings.STOP_TIMEOUT +
                                                        0.1)

                    pipeline._installed_apps[key] = app_mock

                await pipeline.stop()
Пример #13
0
    async def test_stop_no_op_if_already_stopped(self, three_level_app_chain):
        with connection_manager() as conn:
            pipeline = BasePipeline(connection_name=conn.name,
                                    installed_apps=three_level_app_chain)

            # Mock all of the apps that have been configured for this pipeline.
            for key, app in pipeline._installed_apps.items():
                app_mock = MagicMock(app.__class__)

                pipeline._installed_apps[key] = app_mock

            await pipeline.stop()
            await pipeline.stop()

            for app in pipeline.apps.values():
                assert app.stop.called
                assert app.stop.call_count == 1
Пример #14
0
    def test_load_apps_raises_exception_if_no_apps_installed(self):
        with pytest.raises(ImproperlyConfigured):
            with connection_manager() as conn:
                orig_apps = settings.CONNECTIONS[conn.name]["PIPELINE_APPS"]

                settings.CONNECTIONS[conn.name]["PIPELINE_APPS"] = []
                _ = BasePipeline(connection_name=conn.name)

                settings.CONNECTIONS[conn.name]["PIPELINE_APPS"] = orig_apps
Пример #15
0
async def main():
    logging.basicConfig(
        level=settings.LOGGING_LEVEL,
        format=
        "%(asctime)s - %(threadName)s - %(module)s - %(levelname)s - %(message)s",
    )

    args = parser.parse_args()

    with connection_manager(args.connection) as conn:
        fix_pipeline = BasePipeline(connection_name=conn.name,
                                    new_session=args.new_session)

        try:
            # Graceful shutdown on termination signals.
            # See: https://docs.python.org/3.7/library/asyncio-eventloop.html#set-signal-handlers-for-sigint-and-sigterm
            loop = asyncio.get_running_loop()
            for sig_name in {"SIGINT", "SIGTERM"}:
                loop.add_signal_handler(
                    getattr(signal, sig_name),
                    lambda: asyncio.ensure_future(
                        graceful_shutdown(sig_name, fix_pipeline)),
                )

            await fix_pipeline.start()

        except asyncio.TimeoutError as e:
            logger.error(e)
            sys.exit(os.EX_UNAVAILABLE)

        except KeyboardInterrupt:
            logger.info("Received keyboard interrupt! Initiating shutdown...")
            sys.exit(os.EX_OK)

        except futures.CancelledError as e:
            logger.error(f"Cancelled: connection terminated abnormally! ({e})")
            sys.exit(os.EX_UNAVAILABLE)

        except ImproperlyConfigured as e:
            logger.error(e)
            sys.exit(
                os.EX_OK
            )  # User needs to fix config issue before restart is attempted

        except Exception as e:
            logger.exception(e)
            sys.exit(os.EX_UNAVAILABLE)

        finally:
            try:
                await fix_pipeline.stop()
            except futures.CancelledError as e:
                logger.error(
                    f"Cancelled: connection terminated abnormally! ({e})")
                sys.exit(os.EX_UNAVAILABLE)
Пример #16
0
    async def test_start_raises_exception_on_initialize_timeout(
            self, three_level_app_chain):
        with pytest.raises(asyncio.TimeoutError):
            with connection_manager() as conn:
                pipeline = BasePipeline(connection_name=conn.name,
                                        installed_apps=three_level_app_chain)

                settings.INIT_TIMEOUT = 0.1
                # Mock all of the apps that have been configured for this pipeline.
                for key, app in pipeline._installed_apps.items():
                    app_mock = MagicMock(app.__class__)
                    app_mock.initialize = get_slow_mock_async(
                        settings.INIT_TIMEOUT + 0.1)
                    app_mock.stop = get_mock_async()

                    pipeline._installed_apps[key] = app_mock

                await pipeline.start()

            await pipeline.stop()
Пример #17
0
    async def test_initialize_initializes_each_app_exactly_once(
            self, three_level_app_chain):
        with connection_manager() as conn:
            pipeline = BasePipeline(connection_name=conn.name,
                                    installed_apps=three_level_app_chain)

            # Mock all of the apps that have been configured for this pipeline.
            for key, app in pipeline._installed_apps.items():
                app_mock = MagicMock(app.__class__)
                app_mock.name = app.name

                pipeline._installed_apps[key] = app_mock

            await pipeline.initialize()

            for app in pipeline.apps.values():
                assert app.initialize.called
                assert app.initialize.call_count == 1

            await pipeline.stop()
Пример #18
0
    async def test_start_raises_exception_on_initialize_timeout(
            self, three_level_app_chain, create_mock_coro):

        mock_, _ = create_mock_coro(
            runtime=settings.INIT_TIMEOUT + 0.1,
            to_patch="wtfix.apps.base.BaseApp.initialize",
        )

        with pytest.raises(asyncio.exceptions.TimeoutError):
            with connection_manager() as conn:
                pipeline = BasePipeline(connection_name=conn.name,
                                        installed_apps=three_level_app_chain)

                settings.INIT_TIMEOUT = 0.1
                await pipeline.start()

            await pipeline.stop()

            assert mock_.call_count == 1
Пример #19
0
    def test_load_apps_installs_apps_in_pipeline(self, three_level_app_chain):
        with connection_manager() as conn:
            pipeline = BasePipeline(connection_name=conn.name,
                                    installed_apps=three_level_app_chain)

        assert len(pipeline.apps) == 3