예제 #1
0
def test_no_celery() -> None:

    with pytest.raises(ServiceUnavailable):
        connector.get_instance()

    log.warning("Skipping {} tests: service not available", CONNECTOR)
    return None
예제 #2
0
def test_no_celerybeat() -> None:

    obj = connector.get_instance()
    assert obj is not None

    with pytest.raises(AttributeError,
                       match=r"Unsupported celery-beat scheduler: None"):
        # get_periodic_task with unknown CELERYBEAT_SCHEDULER
        obj.get_periodic_task("does_not_exist")

    with pytest.raises(AttributeError,
                       match=r"Unsupported celery-beat scheduler: None"):
        # delete_periodic_task with unknown CELERYBEAT_SCHEDULER
        obj.delete_periodic_task("does_not_exist")

    with pytest.raises(AttributeError,
                       match=r"Unsupported celery-beat scheduler: None"):
        # create_periodic_task with unknown CELERYBEAT_SCHEDULER
        obj.create_periodic_task(name="task1",
                                 task="task.does.not.exists",
                                 every="60")

    with pytest.raises(AttributeError,
                       match=r"Unsupported celery-beat scheduler: None"):
        # create_crontab_task with unknown CELERYBEAT_SCHEDULER
        obj.create_crontab_task(name="task2",
                                task="task.does.not.exists",
                                minute="0",
                                hour="1")
예제 #3
0
    def send_task(app: Flask, task_name: str, *args: Any,
                  **kwargs: Any) -> Any:

        c = celery.get_instance()
        c.app = app

        # Celery type hints are wrong!?
        # Mypy complains about: error: "Callable[[], Any]" has no attribute "get"
        # But .tasks is a TaskRegistry and it is child of dict...
        # so that .get is totally legit!
        task = c.celery_app.tasks.get(task_name)

        if not task:
            raise AttributeError("Task not found")

        with execute_from_code_dir():
            return task(*args, **kwargs)
예제 #4
0
graph = neo4j.get_instance()

datasets_to_analise = graph.Dataset.nodes.filter(
    status="UPLOAD COMPLETED").all()

# get all the dataset uuid
datasets_uuid = [x.uuid for x in datasets_to_analise]

chunks_limit = Env.get_int("CHUNKS_LIMIT", 16)

for chunk in [
        datasets_uuid[i:i + chunks_limit]
        for i in range(0, len(datasets_uuid), chunks_limit)
]:
    log.info("Sending pipeline for datasets: {}", chunk)
    # pass the chunk to the celery task
    c = celery.get_instance()
    task = c.celery_app.send_task(
        "launch_pipeline",
        args=(chunk, ),
        countdown=1,
    )
    log.info("{} datasets sent to task {}", len(chunk), task)
    # mark the related datasets as "QUEUED"
    for d in chunk:
        dataset = graph.Dataset.nodes.get_or_none(uuid=d)
        dataset.status = "QUEUED"
        dataset.save()

log.info("Init pipeline cron completed\n")
예제 #5
0
def test_celery(app: Flask, faker: Faker) -> None:

    if not Connector.check_availability(CONNECTOR):

        try:
            obj = connector.get_instance()
            pytest.fail("No exception raised")  # pragma: no cover
        except ServiceUnavailable:
            pass

        log.warning("Skipping {} tests: service not available", CONNECTOR)
        return None

    log.info("Executing {} tests", CONNECTOR)

    obj = connector.get_instance()
    assert obj is not None

    task = obj.celery_app.send_task("test_task")

    assert task is not None
    assert task.id is not None

    if obj.variables.get("backend") == "RABBIT":
        log.warning(
            "Due to limitations on RABBIT backend task results will not be tested"
        )
    else:
        try:
            r = task.get(timeout=10)
            assert r is not None
            # This is the task output, as defined in task_template.py.j2
            assert r == "Task executed!"
            assert task.status == "SUCCESS"
            assert task.result == "Task executed!"
        except celery.exceptions.TimeoutError:  # pragma: no cover
            pytest.fail(
                f"Task timeout, result={task.result}, status={task.status}")

    if CeleryExt.CELERYBEAT_SCHEDULER is None:

        try:
            obj.get_periodic_task("does_not_exist")
            pytest.fail("get_periodic_task with unknown CELERYBEAT_SCHEDULER"
                        )  # pragma: no cover
        except AttributeError as e:
            assert str(e) == "Unsupported celery-beat scheduler: None"
        except BaseException:  # pragma: no cover
            pytest.fail("Unexpected exception raised")

        try:
            obj.delete_periodic_task("does_not_exist")
            pytest.fail(
                "delete_periodic_task with unknown CELERYBEAT_SCHEDULER"
            )  # pragma: no cover
        except AttributeError as e:
            assert str(e) == "Unsupported celery-beat scheduler: None"
        except BaseException:  # pragma: no cover
            pytest.fail("Unexpected exception raised")

        try:
            obj.create_periodic_task(name="task1",
                                     task="task.does.not.exists",
                                     every="60")
            pytest.fail(
                "create_periodic_task with unknown CELERYBEAT_SCHEDULER"
            )  # pragma: no cover
        except AttributeError as e:
            assert str(e) == "Unsupported celery-beat scheduler: None"
        except BaseException:  # pragma: no cover
            pytest.fail("Unexpected exception raised")

        try:
            obj.create_crontab_task(name="task2",
                                    task="task.does.not.exists",
                                    minute="0",
                                    hour="1")
            pytest.fail("create_crontab_task with unknown CELERYBEAT_SCHEDULER"
                        )  # pragma: no cover
        except AttributeError as e:
            assert str(e) == "Unsupported celery-beat scheduler: None"
        except BaseException:  # pragma: no cover
            pytest.fail("Unexpected exception raised")

    else:
        assert obj.get_periodic_task("does_not_exist") is None
        assert not obj.delete_periodic_task("does_not_exist")

        obj.create_periodic_task(name="task1",
                                 task="task.does.not.exists",
                                 every="60")

        assert obj.delete_periodic_task("task1")
        assert not obj.delete_periodic_task("task1")

        obj.create_periodic_task(
            name="task1_bis",
            task="task.does.not.exists",
            every="60",
            period="seconds",
            args=["a", "b", "c"],
            kwargs={
                "a": 1,
                "b": 2,
                "c": 3
            },
        )

        assert obj.delete_periodic_task("task1_bis")
        assert not obj.delete_periodic_task("task1_bis")

        # cron at 01:00
        obj.create_crontab_task(name="task2",
                                task="task.does.not.exists",
                                minute="0",
                                hour="1")

        assert obj.delete_periodic_task("task2")
        assert not obj.delete_periodic_task("task2")

        obj.create_crontab_task(
            name="task2_bis",
            task="task.does.not.exists",
            minute="0",
            hour="1",
            day_of_week="*",
            day_of_month="*",
            month_of_year="*",
            args=["a", "b", "c"],
            kwargs={
                "a": 1,
                "b": 2,
                "c": 3
            },
        )

        assert obj.delete_periodic_task("task2_bis")
        assert not obj.delete_periodic_task("task2_bis")

        if CeleryExt.CELERYBEAT_SCHEDULER == "REDIS":

            obj.create_periodic_task(
                name="task3",
                task="task.does.not.exists",
                every=60,
            )
            assert obj.delete_periodic_task("task3")

            obj.create_periodic_task(name="task4",
                                     task="task.does.not.exists",
                                     every=60,
                                     period="seconds")
            assert obj.delete_periodic_task("task4")

            obj.create_periodic_task(name="task5",
                                     task="task.does.not.exists",
                                     every=60,
                                     period="minutes")
            assert obj.delete_periodic_task("task5")

            obj.create_periodic_task(name="task6",
                                     task="task.does.not.exists",
                                     every=60,
                                     period="hours")
            assert obj.delete_periodic_task("task6")

            obj.create_periodic_task(name="task7",
                                     task="task.does.not.exists",
                                     every=60,
                                     period="days")
            assert obj.delete_periodic_task("task7")

            try:
                obj.create_periodic_task(
                    name="task8",
                    task="task.does.not.exists",
                    every="60",
                    period="years",  # type: ignore
                )
            except BadRequest as e:
                assert str(e) == "Invalid timedelta period: years"

            obj.create_periodic_task(
                name="task9",
                task="task.does.not.exists",
                every=timedelta(seconds=60),
            )
            assert obj.delete_periodic_task("task9")

            try:
                obj.create_periodic_task(
                    name="task10",
                    task="task.does.not.exists",
                    every=["60"],  # type: ignore
                )
            except AttributeError as e:
                assert str(
                    e) == "Invalid input parameter every = ['60'] (type list)"

            try:
                obj.create_periodic_task(
                    name="task11",
                    task="task.does.not.exists",
                    every="invalid",
                )
            except AttributeError as e:
                assert str(
                    e) == "Invalid input parameter every = invalid (type str)"

        else:
            obj.create_periodic_task(name="task3",
                                     task="task.does.not.exists",
                                     every="60",
                                     period="minutes")
            assert obj.delete_periodic_task("task3")

    obj.disconnect()

    # a second disconnect should not raise any error
    obj.disconnect()

    # Create new connector with short expiration time
    obj = connector.get_instance(expiration=2, verification=1)
    obj_id = id(obj)

    # Connector is expected to be still valid
    obj = connector.get_instance(expiration=2, verification=1)
    assert id(obj) == obj_id

    time.sleep(1)

    # The connection should have been checked and should be still valid
    obj = connector.get_instance(expiration=2, verification=1)
    assert id(obj) == obj_id

    time.sleep(1)

    # Connection should have been expired and a new connector been created
    obj = connector.get_instance(expiration=2, verification=1)
    assert id(obj) != obj_id

    assert obj.is_connected()
    obj.disconnect()
    assert not obj.is_connected()

    # ... close connection again ... nothing should happens
    obj.disconnect()

    with connector.get_instance() as obj:
        assert obj is not None

    app = create_app(mode=ServerModes.WORKER)
    assert app is not None
    from restapi.utilities.logs import LOGS_FILE

    assert os.environ["HOSTNAME"] == "backend-server"
    assert LOGS_FILE == "backend-server"

    # this decorator is expected to be used in celery context, i.e. the self reference
    # should contains a request, injected by celery. Let's mock this by injecting an
    # artificial self
    @send_errors_by_email
    def this_function_raises_exceptions(self):
        raise AttributeError("Just an exception")

    class FakeRequest:
        def __init__(self, task_id, task, args):
            self.id = task_id
            self.task = task
            self.args = args

    class FakeSelf:
        def __init__(self, task_id, task, args):
            self.request = FakeRequest(task_id, task, args)

    task_id = faker.pystr()
    task_name = faker.pystr()
    task_args = [faker.pystr()]

    this_function_raises_exceptions(FakeSelf(task_id, task_name, task_args))

    mail = BaseTests.read_mock_email()
    assert mail.get("body") is not None

    assert f"Celery task {task_id} failed" in mail.get("body")
    assert f"Name: {task_name}" in mail.get("body")
    assert f"Arguments: {str(task_args)}" in mail.get("body")
    assert "Error: Traceback (most recent call last):" in mail.get("body")
    assert 'raise AttributeError("Just an exception")' in mail.get("body")
예제 #6
0
def test_celery(app: Flask, faker: Faker) -> None:

    log.info("Executing {} tests", CONNECTOR)

    obj = connector.get_instance()
    assert obj is not None

    task = obj.celery_app.send_task("test_task", args=("myinput", ))

    assert task is not None
    assert task.id is not None

    # Mocked task
    task_output = BaseTests.send_task(app, "test_task", "myinput")

    # As defined in task template
    assert task_output == "Task executed!"

    # wrong is a special value included in tasks template
    with pytest.raises(Ignore):
        BaseTests.send_task(app, "test_task", "wrong")

    project_title = get_project_configuration("project.title",
                                              default="YourProject")

    mail = BaseTests.read_mock_email()

    body = mail.get("body")
    headers = mail.get("headers")
    assert body is not None
    assert headers is not None
    assert f"Subject: {project_title}: Task test_task failed" in headers
    assert "this email is to notify you that a Celery task failed!" in body
    # fixed-id is a mocked value set in TESTING mode by @task in Celery connector
    assert "Task ID: fixed-id" in body
    assert "Task name: test_task" in body
    assert "Arguments: ('wrong',)" in body
    assert "Error Stack" in body
    assert "Traceback (most recent call last):" in body

    exc = (
        "AttributeError: "
        "You can raise exceptions to stop the task execution in case of errors"
    )
    assert exc in body

    # celery.exceptions.Ignore exceptions are ignored

    BaseTests.delete_mock_email()
    # ignore is a special value included in tasks template
    with pytest.raises(Ignore):
        BaseTests.send_task(app, "test_task", "ignore")
    # the errors decorator re-raise the Ignore exception, without any further action
    # No email is sent in case of Ignore exceptions
    with pytest.raises(FileNotFoundError):
        mail = BaseTests.read_mock_email()

    # retry is a special value included in tasks template
    with pytest.raises(CeleryRetryTask):
        BaseTests.send_task(app, "test_task", "retry")

    mail = BaseTests.read_mock_email()

    body = mail.get("body")
    headers = mail.get("headers")
    assert body is not None
    assert headers is not None
    assert f"Subject: {project_title}: Task test_task failed (failure #1)" in headers
    assert "this email is to notify you that a Celery task failed!" in body
    # fixed-id is a mocked value set in TESTING mode by @task in Celery connector
    assert "Task ID: fixed-id" in body
    assert "Task name: test_task" in body
    assert "Arguments: ('retry',)" in body
    assert "Error Stack" in body
    assert "Traceback (most recent call last):" in body

    exc = "CeleryRetryTask: Force the retry of this task"
    assert exc in body

    # retry2 is a special value included in tasks template
    # Can't easily import the custom exception defined in the task...
    # a generic exception is enough here
    with pytest.raises(Exception):
        BaseTests.send_task(app, "test_task", "retry2")

    mail = BaseTests.read_mock_email()

    body = mail.get("body")
    headers = mail.get("headers")
    assert body is not None
    assert headers is not None
    assert f"Subject: {project_title}: Task test_task failed (failure #1)" in headers
    assert "this email is to notify you that a Celery task failed!" in body
    # fixed-id is a mocked value set in TESTING mode by @task in Celery connector
    assert "Task ID: fixed-id" in body
    assert "Task name: test_task" in body
    assert "Arguments: ('retry2',)" in body
    assert "Error Stack" in body
    assert "Traceback (most recent call last):" in body

    exc = "MyException: Force the retry of this task by using a custom exception"
    assert exc in body

    with pytest.raises(AttributeError, match=r"Task not found"):
        BaseTests.send_task(app, "does-not-exist")

    if obj.variables.get("backend_service") == "RABBIT":
        log.warning(
            "Due to limitations on RABBIT backend task results will not be tested"
        )
    else:
        try:
            r = task.get(timeout=10)
            assert r is not None
            # This is the task output, as defined in task_template.py.j2
            assert r == "Task executed!"
            assert task.status == "SUCCESS"
            assert task.result == "Task executed!"
        except celery.exceptions.TimeoutError:  # pragma: no cover
            pytest.fail(
                f"Task timeout, result={task.result}, status={task.status}")

    obj.disconnect()

    # a second disconnect should not raise any error
    obj.disconnect()

    # Create new connector with short expiration time
    obj = connector.get_instance(expiration=2, verification=1)
    obj_id = id(obj)

    # Connector is expected to be still valid
    obj = connector.get_instance(expiration=2, verification=1)
    assert id(obj) == obj_id

    time.sleep(1)

    # The connection should have been checked and should be still valid
    obj = connector.get_instance(expiration=2, verification=1)
    assert id(obj) == obj_id

    time.sleep(1)

    # Connection should have been expired and a new connector been created
    obj = connector.get_instance(expiration=2, verification=1)
    assert id(obj) != obj_id

    assert obj.is_connected()
    obj.disconnect()
    assert not obj.is_connected()

    # ... close connection again ... nothing should happen
    obj.disconnect()

    with connector.get_instance() as obj:
        assert obj is not None

    app = create_app(mode=ServerModes.WORKER)
    assert app is not None
예제 #7
0
def test_celerybeat() -> None:

    obj = connector.get_instance()
    assert obj is not None

    assert obj.get_periodic_task("does_not_exist") is None
    assert not obj.delete_periodic_task("does_not_exist")

    obj.create_periodic_task(name="task1",
                             task="task.does.not.exists",
                             every="60")

    assert obj.delete_periodic_task("task1")
    assert not obj.delete_periodic_task("task1")

    obj.create_periodic_task(
        name="task1_bis",
        task="task.does.not.exists",
        every="60",
        period="seconds",
        args=["a", "b", "c"],
        kwargs={
            "a": 1,
            "b": 2,
            "c": 3
        },
    )

    assert obj.delete_periodic_task("task1_bis")
    assert not obj.delete_periodic_task("task1_bis")

    # cron at 01:00
    obj.create_crontab_task(name="task2",
                            task="task.does.not.exists",
                            minute="0",
                            hour="1")

    assert obj.delete_periodic_task("task2")
    assert not obj.delete_periodic_task("task2")

    obj.create_crontab_task(
        name="task2_bis",
        task="task.does.not.exists",
        minute="0",
        hour="1",
        day_of_week="*",
        day_of_month="*",
        month_of_year="*",
        args=["a", "b", "c"],
        kwargs={
            "a": 1,
            "b": 2,
            "c": 3
        },
    )

    assert obj.delete_periodic_task("task2_bis")
    assert not obj.delete_periodic_task("task2_bis")

    if CeleryExt.CELERYBEAT_SCHEDULER == "REDIS":

        obj.create_periodic_task(
            name="task3",
            task="task.does.not.exists",
            every=60,
        )
        assert obj.delete_periodic_task("task3")

        obj.create_periodic_task(name="task4",
                                 task="task.does.not.exists",
                                 every=60,
                                 period="seconds")
        assert obj.delete_periodic_task("task4")

        obj.create_periodic_task(name="task5",
                                 task="task.does.not.exists",
                                 every=60,
                                 period="minutes")
        assert obj.delete_periodic_task("task5")

        obj.create_periodic_task(name="task6",
                                 task="task.does.not.exists",
                                 every=60,
                                 period="hours")
        assert obj.delete_periodic_task("task6")

        obj.create_periodic_task(name="task7",
                                 task="task.does.not.exists",
                                 every=60,
                                 period="days")
        assert obj.delete_periodic_task("task7")

        with pytest.raises(BadRequest,
                           match=r"Invalid timedelta period: years"):
            obj.create_periodic_task(
                name="task8",
                task="task.does.not.exists",
                every="60",
                period="years",  # type: ignore
            )

        obj.create_periodic_task(
            name="task9",
            task="task.does.not.exists",
            every=timedelta(seconds=60),
        )
        assert obj.delete_periodic_task("task9")

        with pytest.raises(
                AttributeError,
                match=r"Invalid input parameter every = \['60'\] \(type list\)",
        ):
            obj.create_periodic_task(
                name="task10",
                task="task.does.not.exists",
                every=["60"],  # type: ignore
            )

        with pytest.raises(
                AttributeError,
                match=r"Invalid input parameter every = invalid \(type str\)",
        ):
            obj.create_periodic_task(
                name="task11",
                task="task.does.not.exists",
                every="invalid",
            )