Skip to content
Closed
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
8 changes: 8 additions & 0 deletions queue_job/controllers/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -216,6 +216,14 @@ def _get_failure_values(cls, job, traceback_txt, orig_exception):
def runjob(self, db, job_uuid, **kw):
http.request.session.db = db
env = http.request.env(user=SUPERUSER_ID)
# `IrHttp._auth_method_none()` (this route's auth method) forces
# `transaction.default_env` to an environment with `uid=None`,
# bypassing the truthy-uid guard in `Environment.__new__`. Any
# `env.user` access during a savepoint-triggered flush inside the
# job (e.g. a recompute/constrain calling `has_group`) then raises
# "Expected singleton: res.users()" because `browse(None)` is
# empty. Repair it to the real job-running user.
env.transaction.default_env = env
job = self._acquire_job(env, job_uuid)
if not job:
return ""
Expand Down
34 changes: 33 additions & 1 deletion queue_job/tests/test_run_rob_controller.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl).

from odoo.tests.common import TransactionCase
from odoo.tests.common import HttpCase, TransactionCase

from ..controllers.main import RunJobController
from ..job import Job
from ..models.queue_job import QueueJob


class TestRunJobController(TransactionCase):
Expand All @@ -21,3 +22,34 @@ def test_runjob_success(self):
RunJobController._runjob(self.env, job)
self.assertEqual(job.state, "done")
self.assertEqual(job.db_record().state, "done")


class TestRunJobControllerHttp(HttpCase):
def test_runjob_http_repairs_default_env(self):
"""A job run through the real /queue_job/runjob (auth=none) route
must leave `transaction.default_env` on a valid, real user.

`IrHttp._auth_method_none()` forces `transaction.default_env` to an
environment with `uid=None` before the controller runs. Any
`env.user` access during a savepoint-triggered flush inside the job
(e.g. a recompute/constrain calling `has_group`) then raises
"Expected singleton: res.users()" because `browse(None)` is empty.
"""

def _test_job(self):
with self.env.cr.savepoint():
pass
# Would raise "Expected singleton: res.users()" without the fix.
self.env.transaction.default_env.user.ensure_one()

self.patch(QueueJob, "_test_job", _test_job)
job_ = self.env["queue.job"].with_delay()._test_job()
job_.set_enqueued()
job_.store()
db_job = job_.db_record()
response = self.url_open(
f"/queue_job/runjob?db={self.env.cr.dbname}&job_uuid={db_job.uuid}"
)
self.assertEqual(response.status_code, 200)
db_job.invalidate_recordset()
self.assertEqual(db_job.state, "done", db_job.exc_info)
Loading