Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 5 additions & 4 deletions queue_job/README.rst
Original file line number Diff line number Diff line change
Expand Up @@ -388,13 +388,14 @@ be customized in ``Base._job_prepare_context_before_enqueue_keys``.
When you are developing (ie: connector modules) you might want
to bypass the queue job and run your code immediately.

To do so you can set `TEST_QUEUE_JOB_NO_DELAY=1` in your enviroment.
To do so you can set `QUEUE_JOB_NO_DELAY=1` in your enviroment.

**Bypass jobs in tests**

When writing tests on job-related methods is always tricky to deal with
delayed recordsets. To make your testing life easier
you can set `test_queue_job_no_delay=True` in the context.
delayed recordsets. To make your testing life easier,
or to run a delayed action immediately,
you can set `queue_job__no_delay=True` in the context.

Tip: you can do this at test case level like this

Expand All @@ -405,7 +406,7 @@ Tip: you can do this at test case level like this
super().setUpClass()
cls.env = cls.env(context=dict(
cls.env.context,
test_queue_job_no_delay=True, # no jobs thanks
queue_job__no_delay=True, # no jobs thanks
))

Then all your tests execute the job methods synchronously
Expand Down
12 changes: 2 additions & 10 deletions queue_job/delay.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,11 @@

import itertools
import logging
import os
import uuid
from collections import defaultdict, deque

from .job import Job
from .utils import must_run_without_delay

_logger = logging.getLogger(__name__)

Expand Down Expand Up @@ -217,17 +217,9 @@ def _has_to_execute_directly(self, vertices):
In tests, prefer to use
:func:`odoo.addons.queue_job.tests.common.trap_jobs`.
"""
if os.getenv("TEST_QUEUE_JOB_NO_DELAY"):
_logger.warning(
"`TEST_QUEUE_JOB_NO_DELAY` env var found. NO JOB scheduled."
)
return True
envs = {vertex.recordset.env for vertex in vertices}
for env in envs:
if env.context.get("test_queue_job_no_delay"):
_logger.warning(
"`test_queue_job_no_delay` ctx key found. NO JOB scheduled."
)
if must_run_without_delay(env):
return True
return False

Expand Down
7 changes: 2 additions & 5 deletions queue_job/models/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,12 @@
# License LGPL-3.0 or later (http://www.gnu.org/licenses/lgpl.html)

import functools
import logging

from odoo import api, models

from ..delay import Delayable
from ..job import DelayableRecordset

_logger = logging.getLogger(__name__)
from ..utils import must_run_without_delay


class Base(models.AbstractModel):
Expand Down Expand Up @@ -216,8 +214,7 @@ def auto_delay_wrapper(self, *args, **kwargs):
if (
self.env.context.get("job_uuid")
or not context_delay
or self.env.context.get("_job_force_sync")
or self.env.context.get("test_queue_job_no_delay")
or must_run_without_delay(self.env)
):
# we are in the job execution
return auto_delay_wrapper.origin(self, *args, **kwargs)
Expand Down
14 changes: 7 additions & 7 deletions queue_job/readme/USAGE.rst
Original file line number Diff line number Diff line change
Expand Up @@ -254,13 +254,13 @@ be customized in ``Base._job_prepare_context_before_enqueue_keys``.
When you are developing (ie: connector modules) you might want
to bypass the queue job and run your code immediately.

To do so you can set `TEST_QUEUE_JOB_NO_DELAY=1` in your enviroment.
To do so you can set `QUEUE_JOB__NO_DELAY=1` in your enviroment.

**Bypass jobs in tests**

When writing tests on job-related methods is always tricky to deal with
delayed recordsets. To make your testing life easier
you can set `test_queue_job_no_delay=True` in the context.
you can set `queue_job__no_delay=True` in the context.

Tip: you can do this at test case level like this

Expand All @@ -271,7 +271,7 @@ Tip: you can do this at test case level like this
super().setUpClass()
cls.env = cls.env(context=dict(
cls.env.context,
test_queue_job_no_delay=True, # no jobs thanks
queue_job__no_delay=True, # no jobs thanks
))

Then all your tests execute the job methods synchronously
Expand Down Expand Up @@ -370,15 +370,15 @@ If you prefer, you can still test the whole thing in a single test, by calling
When you are developing (ie: connector modules) you might want
to bypass the queue job and run your code immediately.

To do so you can set ``TEST_QUEUE_JOB_NO_DELAY=1`` in your environment.
To do so you can set ``QUEUE_JOB__NO_DELAY=1`` in your environment.

.. WARNING:: Do not do this in production

**Execute jobs synchronously in tests**

You should use ``trap_jobs``, really, but if for any reason you could not use it,
and still need to have job methods executed synchronously in your tests, you can
do so by setting ``test_queue_job_no_delay=True`` in the context.
do so by setting ``queue_job__no_delay=True`` in the context.

Tip: you can do this at test case level like this

Expand All @@ -389,7 +389,7 @@ Tip: you can do this at test case level like this
super().setUpClass()
cls.env = cls.env(context=dict(
cls.env.context,
test_queue_job_no_delay=True, # no jobs thanks
queue_job__no_delay=True, # no jobs thanks
))

Then all your tests execute the job methods synchronously without delaying any
Expand All @@ -399,7 +399,7 @@ In tests you'll have to mute the logger like:

@mute_logger('odoo.addons.queue_job.models.base')

.. NOTE:: in graphs of jobs, the ``test_queue_job_no_delay`` context key must be in at
.. NOTE:: in graphs of jobs, the ``queue_job__no_delay`` context key must be in at
least one job's env of the graph for the whole graph to be executed synchronously


Expand Down
40 changes: 40 additions & 0 deletions queue_job/utils.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
# Copyright 2023 Camptocamp
# License LGPL-3.0 or later (http://www.gnu.org/licenses/lgpl.html)

import logging
import os

_logger = logging.getLogger(__name__)


def must_run_without_delay(env):
"""Retrun true if jobs have to run immediately.

:param env: `odoo.api.Environment` instance
"""
# TODO: drop in v17
if os.getenv("TEST_QUEUE_JOB_NO_DELAY"):
_logger.warning(
"`TEST_QUEUE_JOB_NO_DELAY` env var found. NO JOB scheduled. "
"Note that this key is deprecated: please use `QUEUE_JOB__NO_DELAY`"
)
return True

if os.getenv("QUEUE_JOB__NO_DELAY"):
_logger.warning("`QUEUE_JOB__NO_DELAY` env var found. NO JOB scheduled.")
return True

# TODO: drop in v17
deprecated_keys = ("_job_force_sync", "test_queue_job_no_delay")
for key in deprecated_keys:
if env.context.get(key):
_logger.warning(
"`%s` ctx key found. NO JOB scheduled. "
"Note that this key is deprecated: please use `queue_job__no_delay`",
key,
)
return True

if env.context.get("queue_job__no_delay"):
_logger.warning("`queue_job__no_delay` ctx key found. NO JOB scheduled.")
return True
16 changes: 8 additions & 8 deletions test_queue_job/tests/test_delay_mocks.py
Original file line number Diff line number Diff line change
Expand Up @@ -133,8 +133,8 @@ def test_mock_with_delay(self):
self.assertEqual(delay_args, (1,))
self.assertDictEqual(delay_kwargs, {"foo": 2})

@mute_logger("odoo.addons.queue_job.models.base")
@mock.patch.dict(os.environ, {"TEST_QUEUE_JOB_NO_DELAY": "1"})
@mute_logger("odoo.addons.queue_job.utils")
@mock.patch.dict(os.environ, {"QUEUE_JOB__NO_DELAY": "1"})
def test_delay_graph_direct_exec_env_var(self):
node = Delayable(self.env["test.queue.job"]).create_ir_logging(
"test_delay_graph_direct_exec 1"
Expand All @@ -157,10 +157,10 @@ def test_delay_graph_direct_exec_env_var(self):
self.assertEqual(logs[0].message, "test_delay_graph_direct_exec 2")
self.assertEqual(logs[1].message, "test_delay_graph_direct_exec 1")

@mute_logger("odoo.addons.queue_job.models.base")
@mute_logger("odoo.addons.queue_job.utils")
def test_delay_graph_direct_exec_context_key(self):
node = Delayable(
self.env["test.queue.job"].with_context(test_queue_job_no_delay=True)
self.env["test.queue.job"].with_context(queue_job__no_delay=True)
).create_ir_logging("test_delay_graph_direct_exec 1")
node2 = Delayable(self.env["test.queue.job"]).create_ir_logging(
"test_delay_graph_direct_exec 2"
Expand All @@ -180,8 +180,8 @@ def test_delay_graph_direct_exec_context_key(self):
self.assertEqual(logs[0].message, "test_delay_graph_direct_exec 2")
self.assertEqual(logs[1].message, "test_delay_graph_direct_exec 1")

@mute_logger("odoo.addons.queue_job.models.base")
@mock.patch.dict(os.environ, {"TEST_QUEUE_JOB_NO_DELAY": "1"})
@mute_logger("odoo.addons.queue_job.utils")
@mock.patch.dict(os.environ, {"QUEUE_JOB__NO_DELAY": "1"})
def test_delay_with_delay_direct_exec_env_var(self):
model = self.env["test.queue.job"]
model.with_delay().create_ir_logging("test_delay_graph_direct_exec 1")
Expand All @@ -196,9 +196,9 @@ def test_delay_with_delay_direct_exec_env_var(self):
self.assertEqual(len(logs), 1)
self.assertEqual(logs[0].message, "test_delay_graph_direct_exec 1")

@mute_logger("odoo.addons.queue_job.models.base")
@mute_logger("odoo.addons.queue_job.utils")
def test_delay_with_delay_direct_exec_context_key(self):
model = self.env["test.queue.job"].with_context(test_queue_job_no_delay=True)
model = self.env["test.queue.job"].with_context(queue_job__no_delay=True)
model.with_delay().create_ir_logging("test_delay_graph_direct_exec 1")
# jobs are executed directly
logs = self.env["ir.logging"].search(
Expand Down