|
6 | 6 | from unittest import mock |
7 | 7 |
|
8 | 8 | import odoo.tests.common as common |
| 9 | +from odoo.tests.common import mute_logger |
9 | 10 |
|
10 | 11 | from odoo.addons.queue_job import identity_exact |
11 | 12 | from odoo.addons.queue_job.delay import DelayableGraph |
12 | 13 | from odoo.addons.queue_job.exception import ( |
13 | 14 | FailedJobError, |
| 15 | + JobMethodNotFound, |
14 | 16 | NoSuchJobError, |
15 | 17 | RetryableJobError, |
16 | 18 | ) |
@@ -304,6 +306,33 @@ def test_job_unlinked(self): |
304 | 306 | with self.assertRaises(NoSuchJobError): |
305 | 307 | Job.load(self.env, test_job.uuid) |
306 | 308 |
|
| 309 | + def _create_non_existing_method_job(self): |
| 310 | + test_job = Job(self.method) |
| 311 | + test_job.store() |
| 312 | + self.env.cr.execute( |
| 313 | + "UPDATE queue_job SET method_name = %s WHERE uuid = %s", |
| 314 | + ("nonexistent_xyz", test_job.uuid), |
| 315 | + ) |
| 316 | + self.env["queue.job"].invalidate_model() |
| 317 | + return test_job.uuid |
| 318 | + |
| 319 | + def test_load_missing_method(self): |
| 320 | + """Job.load raises JobMethodNotFound when the method is missing.""" |
| 321 | + uuid = self._create_non_existing_method_job() |
| 322 | + with self.assertRaises(JobMethodNotFound): |
| 323 | + Job.load(self.env, uuid) |
| 324 | + |
| 325 | + def test_load_many_skips_missing_method(self): |
| 326 | + """load_many skips a broken job — other jobs still load.""" |
| 327 | + good = Job(self.method) |
| 328 | + good.store() |
| 329 | + bad_uuid = self._create_non_existing_method_job() |
| 330 | + with mute_logger("odoo.addons.queue_job.job"): |
| 331 | + loaded = Job.load_many(self.env, [good.uuid, bad_uuid]) |
| 332 | + loaded_uuids = {j.uuid for j in loaded} |
| 333 | + self.assertIn(good.uuid, loaded_uuids) |
| 334 | + self.assertNotIn(bad_uuid, loaded_uuids) |
| 335 | + |
307 | 336 | def test_unicode(self): |
308 | 337 | test_job = Job( |
309 | 338 | self.method, |
@@ -571,6 +600,16 @@ def test_requeue(self): |
571 | 600 | stored.requeue() |
572 | 601 | self.assertEqual(stored.state, PENDING) |
573 | 602 |
|
| 603 | + def test_change_state_skips_missing_method(self): |
| 604 | + """_change_job_state does not crash when the method is missing.""" |
| 605 | + stored = self._create_job() |
| 606 | + self.env.cr.execute( |
| 607 | + "UPDATE queue_job SET method_name = %s WHERE uuid = %s", |
| 608 | + ("vanished_xyz", stored.uuid), |
| 609 | + ) |
| 610 | + self.env["queue.job"].invalidate_model() |
| 611 | + stored.button_done() |
| 612 | + |
574 | 613 | def test_requeue_wait_dependencies_not_touched(self): |
575 | 614 | job_root = Job(self.env["test.queue.job"].testing_method) |
576 | 615 | job_child = Job(self.env["test.queue.job"].testing_method) |
|
0 commit comments