From 8533f37e3abac949b8e0ba0fa9e818d2e5b37b66 Mon Sep 17 00:00:00 2001 From: Victor Pincay Date: Mon, 31 Aug 2026 23:33:35 +0200 Subject: [PATCH 1/2] [MIG] queue_job_batch, test_queue_job_batch: Migration to 19.0 - Manifest: drop the installable flag the migration bot injected inside the assets dict, bump both modules to 19.0.1.0.0 and make them installable. - Security: res.groups.category_id no longer exists in 19.0. Point the batch user group at queue_job.privilege_queue_job, the res.groups.privilege record created when queue_job was migrated. - Search view: 19.0 drops the wrapper; the groupby filters are now flat, after a separator. - queue.job.batch: Store.add() calls _to_store(store, fields) with two positional arguments in 19.0. Declare the serialized fields in _to_store_defaults() and let Store read them, as the core models do. - res.users: store globals are added with add_global_values(); Store.add() expects a recordset, not a mapping. - Webclient controller: _process_request_for_internal_user is a classmethod taking (store, name, params) in 19.0, and the systray payload is requested by name instead of through a keyword flag. - Store patch: initMessagingParams no longer exists. Request the counter from initialize() with fetchStoreData(), which also replaces fetchData() in the systray menu. --- .pre-commit-config.yaml | 2 - queue_job_batch/README.rst | 20 +++++--- queue_job_batch/__manifest__.py | 7 ++- queue_job_batch/controllers/webclient.py | 16 +++---- queue_job_batch/models/queue_job_batch.py | 15 ++---- queue_job_batch/models/res_users.py | 13 +++--- queue_job_batch/readme/CONTRIBUTORS.md | 3 ++ queue_job_batch/security/security.xml | 2 +- queue_job_batch/static/description/index.html | 46 +++++++++++-------- queue_job_batch/static/src/Store.esm.js | 16 ++++--- .../src/components/QueueJobBatchMenu.esm.js | 2 +- .../views/queue_job_batch_views.xml | 23 +++++----- test_queue_job_batch/README.rst | 20 +++++--- test_queue_job_batch/__manifest__.py | 4 +- test_queue_job_batch/readme/CONTRIBUTORS.md | 3 ++ .../static/description/index.html | 34 +++++++++----- 16 files changed, 129 insertions(+), 97 deletions(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 4cefd00cac..db790853cc 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -2,11 +2,9 @@ exclude: | (?x) # NOT INSTALLABLE ADDONS ^base_import_async/| - ^queue_job_batch/| ^queue_job_cron/| ^queue_job_cron_jobrunner/| ^queue_job_subscribe/| - ^test_queue_job_batch/| # END NOT INSTALLABLE ADDONS # Files and folders generated by bots, to avoid loops ^setup/|/static/description/index\.html$| diff --git a/queue_job_batch/README.rst b/queue_job_batch/README.rst index d0b9d22c38..029c9bad14 100644 --- a/queue_job_batch/README.rst +++ b/queue_job_batch/README.rst @@ -1,3 +1,7 @@ +.. image:: https://odoo-community.org/readme-banner-image + :target: https://odoo-community.org/get-involved?utm_source=readme + :alt: Odoo Community Association + =============== Job Queue Batch =============== @@ -13,17 +17,17 @@ Job Queue Batch .. |badge1| image:: https://img.shields.io/badge/maturity-Beta-yellow.png :target: https://odoo-community.org/page/development-status :alt: Beta -.. |badge2| image:: https://img.shields.io/badge/licence-AGPL--3-blue.png +.. |badge2| image:: https://img.shields.io/badge/license-AGPL--3-blue.png :target: http://www.gnu.org/licenses/agpl-3.0-standalone.html :alt: License: AGPL-3 .. |badge3| image:: https://img.shields.io/badge/github-OCA%2Fqueue-lightgray.png?logo=github - :target: https://github.com/OCA/queue/tree/18.0/queue_job_batch + :target: https://github.com/OCA/queue/tree/19.0/queue_job_batch :alt: OCA/queue .. |badge4| image:: https://img.shields.io/badge/weblate-Translate%20me-F47D42.png - :target: https://translation.odoo-community.org/projects/queue-18-0/queue-18-0-queue_job_batch + :target: https://translation.odoo-community.org/projects/queue-19-0/queue-19-0-queue_job_batch :alt: Translate me on Weblate .. |badge5| image:: https://img.shields.io/badge/runboat-Try%20me-875A7B.png - :target: https://runboat.odoo-community.org/builds?repo=OCA/queue&target_branch=18.0 + :target: https://runboat.odoo-community.org/builds?repo=OCA/queue&target_branch=19.0 :alt: Try me on Runboat |badge1| |badge2| |badge3| |badge4| |badge5| @@ -82,7 +86,7 @@ Bug Tracker Bugs are tracked on `GitHub Issues `_. In case of trouble, please check there if your issue has already been reported. If you spotted it first, help us to smash it by providing a detailed and welcomed -`feedback `_. +`feedback `_. Do not contact contributors directly about support or help with technical issues. @@ -113,6 +117,10 @@ Contributors - Maksym Yankin - Iván Todorovich +- `NextPro `__: + + - Victor Pincay + Other credits ------------- @@ -132,6 +140,6 @@ OCA, or the Odoo Community Association, is a nonprofit organization whose mission is to support the collaborative development of Odoo features and promote its widespread use. -This module is part of the `OCA/queue `_ project on GitHub. +This module is part of the `OCA/queue `_ project on GitHub. You are welcome to contribute. To learn how please visit https://odoo-community.org/page/Contribute. diff --git a/queue_job_batch/__manifest__.py b/queue_job_batch/__manifest__.py index 12dc679b8f..f8a64d20ef 100644 --- a/queue_job_batch/__manifest__.py +++ b/queue_job_batch/__manifest__.py @@ -4,7 +4,7 @@ { "name": "Job Queue Batch", - "version": "18.0.1.0.0", + "version": "19.0.1.0.0", "author": "Creu Blanca,Odoo Community Association (OCA)", "website": "https://github.com/OCA/queue", "license": "AGPL-3", @@ -29,7 +29,6 @@ "queue_job_batch/static/src/**/*.xml", "queue_job_batch/static/src/**/*.scss", ], - 'installable': False, -}, - 'installable': False, + }, + "installable": True, } diff --git a/queue_job_batch/controllers/webclient.py b/queue_job_batch/controllers/webclient.py index 8967932795..1ef7ebfe72 100644 --- a/queue_job_batch/controllers/webclient.py +++ b/queue_job_batch/controllers/webclient.py @@ -4,20 +4,20 @@ from odoo.http import request from odoo.addons.mail.controllers.webclient import WebclientController +from odoo.addons.mail.tools.discuss import Store class WebClient(WebclientController): - def _process_request_for_internal_user(self, store, **kwargs): - res = super()._process_request_for_internal_user(store, **kwargs) - if kwargs.get("systray_get_queue_job_batches"): + @classmethod + def _process_request_for_internal_user(self, store: Store, name, params): + res = super()._process_request_for_internal_user(store, name, params) + if name == "systray_get_queue_job_batches": # sudo: bus.bus: reading non-sensitive last id bus_last_id = request.env["bus.bus"].sudo()._bus_last_id() batches = request.env.user._get_queue_job_batches() store.add(batches) - store.add( - { - "queueJobBatchCounter": len(batches), - "queueJobBatchCounterBusId": bus_last_id, - } + store.add_global_values( + queueJobBatchCounter=len(batches), + queueJobBatchCounterBusId=bus_last_id, ) return res diff --git a/queue_job_batch/models/queue_job_batch.py b/queue_job_batch/models/queue_job_batch.py index 998f7a5ac2..f908638b1d 100644 --- a/queue_job_batch/models/queue_job_batch.py +++ b/queue_job_batch/models/queue_job_batch.py @@ -4,8 +4,6 @@ from odoo import api, fields, models -from odoo.addons.mail.tools.discuss import Store - class QueueJobBatch(models.Model): _name = "queue.job.batch" @@ -109,9 +107,8 @@ def _compute_job_count(self): rec.completeness = rec.finished_job_count / max(1, rec.job_count) rec.failed_percentage = rec.failed_job_count / max(1, rec.job_count) - @api.model - def _to_store_fnames(self): - return ( + def _to_store_defaults(self, target): + return [ "name", "state", "job_count", @@ -119,10 +116,4 @@ def _to_store_fnames(self): "failed_job_count", "completeness", "failed_percentage", - ) - - def _to_store(self, store: Store): - fnames = self._to_store_fnames() - for rec in self: - data = rec.read(fnames)[0] - store.add(rec, data) + ] diff --git a/queue_job_batch/models/res_users.py b/queue_job_batch/models/res_users.py index de53d2b31f..ca7549cb43 100644 --- a/queue_job_batch/models/res_users.py +++ b/queue_job_batch/models/res_users.py @@ -1,21 +1,20 @@ # Copyright 2025 Camptocamp SA (https://www.camptocamp.com). # License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). -from odoo import models +from odoo import api, models class Users(models.Model): _name = "res.users" _inherit = ["res.users"] + @api.model def _init_store_data(self, store): res = super()._init_store_data(store) - store.add( - { - "hasQueueJobBatchUserGroup": self.env.user.has_group( - "queue_job_batch.group_queue_job_batch_user" - ), - } + store.add_global_values( + hasQueueJobBatchUserGroup=self.env.user.has_group( + "queue_job_batch.group_queue_job_batch_user" + ), ) return res diff --git a/queue_job_batch/readme/CONTRIBUTORS.md b/queue_job_batch/readme/CONTRIBUTORS.md index 6b13c0aa12..24cdcd27ed 100644 --- a/queue_job_batch/readme/CONTRIBUTORS.md +++ b/queue_job_batch/readme/CONTRIBUTORS.md @@ -10,3 +10,6 @@ - [Camptocamp](https://camptocamp.com): - Maksym Yankin \<\> - Iván Todorovich \<\> + +- [NextPro](https://www.nextpro.pe): + - Victor Pincay \<\> diff --git a/queue_job_batch/security/security.xml b/queue_job_batch/security/security.xml index 9443708ae0..b6d104442f 100644 --- a/queue_job_batch/security/security.xml +++ b/queue_job_batch/security/security.xml @@ -3,7 +3,7 @@ Job Queue Batch User - + -Job Queue Batch +README.rst -
-

Job Queue Batch

+
+ + +Odoo Community Association + +
+

Job Queue Batch

-

Beta License: AGPL-3 OCA/queue Translate me on Weblate Try me on Runboat

+

Beta License: AGPL-3 OCA/queue Translate me on Weblate Try me on Runboat

This addon adds an a grouper for queue jobs.

It allows to show your jobs in a batched form in order to know better the results.

Example:

-from odoo import models, fields, api
+from odoo import models, fields, api
 
 
-class MyModel(models.Model):
+class MyModel(models.Model):
     _name = 'my.model'
 
-    def my_method(self, a, k=None):
+    def my_method(self, a, k=None):
         _logger.info('executed with a: %s and k: %s', a, k)
 
 
-class MyOtherModel(models.Model):
+class MyOtherModel(models.Model):
     _name = 'my.other.model'
 
     @api.multi
-    def button_do_stuff(self):
+    def button_do_stuff(self):
         batch = self.env['queue.job.batch'].get_new_batch('Group')
         model = self.env['my.model'].with_context(job_batch=batch)
         for i in range(1, 100):
@@ -415,29 +420,29 @@ 

Job Queue Batch

-

Usage

+

Usage

You can manage your batch jobs from the Systray. A new button will be shown with your currently executing job batches and the recently finished job groups.

-

Bug Tracker

+

Bug Tracker

Bugs are tracked on GitHub Issues. In case of trouble, please check there if your issue has already been reported. If you spotted it first, help us to smash it by providing a detailed and welcomed -feedback.

+feedback.

Do not contact contributors directly about support or help with technical issues.

-

Credits

+

Credits

-

Authors

+

Authors

  • Creu Blanca
-

Contributors

+

Contributors

-

Other credits

+

Other credits

The migration of this module from 12.0 to 14.0 was financially supported by Camptocamp

-

Maintainers

+

Maintainers

This module is maintained by the OCA.

Odoo Community Association @@ -470,10 +479,11 @@

Maintainers

OCA, or the Odoo Community Association, is a nonprofit organization whose mission is to support the collaborative development of Odoo features and promote its widespread use.

-

This module is part of the OCA/queue project on GitHub.

+

This module is part of the OCA/queue project on GitHub.

You are welcome to contribute. To learn how please visit https://odoo-community.org/page/Contribute.

+
diff --git a/queue_job_batch/static/src/Store.esm.js b/queue_job_batch/static/src/Store.esm.js index 619d7090b0..f99ce2aa4e 100644 --- a/queue_job_batch/static/src/Store.esm.js +++ b/queue_job_batch/static/src/Store.esm.js @@ -12,11 +12,15 @@ patch(Store.prototype, { queueJobBatchCounterBusId: 0, queueJobBatchCounter: 0, - /** @override */ - get initMessagingParams() { - return { - ...super.initMessagingParams, - systray_get_queue_job_batches: true, - }; + /** + * @override + * The counter has to be known before the systray menu is opened, so it is + * requested along with the rest of the initial store data. + */ + async initialize() { + await Promise.all([ + this.fetchStoreData("systray_get_queue_job_batches"), + super.initialize(...arguments), + ]); }, }); diff --git a/queue_job_batch/static/src/components/QueueJobBatchMenu.esm.js b/queue_job_batch/static/src/components/QueueJobBatchMenu.esm.js index a8addd461b..b84b338b63 100644 --- a/queue_job_batch/static/src/components/QueueJobBatchMenu.esm.js +++ b/queue_job_batch/static/src/components/QueueJobBatchMenu.esm.js @@ -32,7 +32,7 @@ export class QueueJobBatchMenu extends Component { } onBeforeOpen() { - this.store.fetchData({systray_get_queue_job_batches: true}); + this.store.fetchStoreData("systray_get_queue_job_batches"); } getGroupInfo(batch) { diff --git a/queue_job_batch/views/queue_job_batch_views.xml b/queue_job_batch/views/queue_job_batch_views.xml index 34bdc1fee3..2212ce63fa 100644 --- a/queue_job_batch/views/queue_job_batch_views.xml +++ b/queue_job_batch/views/queue_job_batch_views.xml @@ -96,18 +96,17 @@ string="Finished" domain="[('state', '=', 'finished')]" /> - - - - + + +
diff --git a/test_queue_job_batch/README.rst b/test_queue_job_batch/README.rst index 6c2f32a04b..8a78bf830f 100644 --- a/test_queue_job_batch/README.rst +++ b/test_queue_job_batch/README.rst @@ -1,3 +1,7 @@ +.. image:: https://odoo-community.org/readme-banner-image + :target: https://odoo-community.org/get-involved?utm_source=readme + :alt: Odoo Community Association + ==================== Test Job Queue Batch ==================== @@ -13,17 +17,17 @@ Test Job Queue Batch .. |badge1| image:: https://img.shields.io/badge/maturity-Beta-yellow.png :target: https://odoo-community.org/page/development-status :alt: Beta -.. |badge2| image:: https://img.shields.io/badge/licence-AGPL--3-blue.png +.. |badge2| image:: https://img.shields.io/badge/license-AGPL--3-blue.png :target: http://www.gnu.org/licenses/agpl-3.0-standalone.html :alt: License: AGPL-3 .. |badge3| image:: https://img.shields.io/badge/github-OCA%2Fqueue-lightgray.png?logo=github - :target: https://github.com/OCA/queue/tree/18.0/test_queue_job_batch + :target: https://github.com/OCA/queue/tree/19.0/test_queue_job_batch :alt: OCA/queue .. |badge4| image:: https://img.shields.io/badge/weblate-Translate%20me-F47D42.png - :target: https://translation.odoo-community.org/projects/queue-18-0/queue-18-0-test_queue_job_batch + :target: https://translation.odoo-community.org/projects/queue-19-0/queue-19-0-test_queue_job_batch :alt: Translate me on Weblate .. |badge5| image:: https://img.shields.io/badge/runboat-Try%20me-875A7B.png - :target: https://runboat.odoo-community.org/builds?repo=OCA/queue&target_branch=18.0 + :target: https://runboat.odoo-community.org/builds?repo=OCA/queue&target_branch=19.0 :alt: Try me on Runboat |badge1| |badge2| |badge3| |badge4| |badge5| @@ -41,7 +45,7 @@ Bug Tracker Bugs are tracked on `GitHub Issues `_. In case of trouble, please check there if your issue has already been reported. If you spotted it first, help us to smash it by providing a detailed and welcomed -`feedback `_. +`feedback `_. Do not contact contributors directly about support or help with technical issues. @@ -64,6 +68,10 @@ Contributors - Hoang Diep +- `NextPro `__: + + - Victor Pincay + Other credits ------------- @@ -83,6 +91,6 @@ OCA, or the Odoo Community Association, is a nonprofit organization whose mission is to support the collaborative development of Odoo features and promote its widespread use. -This module is part of the `OCA/queue `_ project on GitHub. +This module is part of the `OCA/queue `_ project on GitHub. You are welcome to contribute. To learn how please visit https://odoo-community.org/page/Contribute. diff --git a/test_queue_job_batch/__manifest__.py b/test_queue_job_batch/__manifest__.py index e0d6eb85ab..381664e6cd 100644 --- a/test_queue_job_batch/__manifest__.py +++ b/test_queue_job_batch/__manifest__.py @@ -3,7 +3,7 @@ { "name": "Test Job Queue Batch", - "version": "18.0.1.0.0", + "version": "19.0.1.0.0", "author": "Creu Blanca,Odoo Community Association (OCA)", "website": "https://github.com/OCA/queue", "license": "AGPL-3", @@ -12,5 +12,5 @@ "queue_job_batch", "test_queue_job", ], - 'installable': False, + "installable": True, } diff --git a/test_queue_job_batch/readme/CONTRIBUTORS.md b/test_queue_job_batch/readme/CONTRIBUTORS.md index aa6ae84916..0f46e4a6fa 100644 --- a/test_queue_job_batch/readme/CONTRIBUTORS.md +++ b/test_queue_job_batch/readme/CONTRIBUTORS.md @@ -4,3 +4,6 @@ - [Trobz](https://trobz.com): - Hoang Diep \<\> + +- [NextPro](https://www.nextpro.pe): + - Victor Pincay \<\> diff --git a/test_queue_job_batch/static/description/index.html b/test_queue_job_batch/static/description/index.html index 6bdb598296..5250a8ff0c 100644 --- a/test_queue_job_batch/static/description/index.html +++ b/test_queue_job_batch/static/description/index.html @@ -3,7 +3,7 @@ -Test Job Queue Batch +README.rst -
-

Test Job Queue Batch

+
+ + +Odoo Community Association + +
+

Test Job Queue Batch

-

Beta License: AGPL-3 OCA/queue Translate me on Weblate Try me on Runboat

+

Beta License: AGPL-3 OCA/queue Translate me on Weblate Try me on Runboat

This addon is used to test the queue job batch functionality

Table of contents

@@ -385,23 +390,23 @@

Test Job Queue Batch

-

Bug Tracker

+

Bug Tracker

Bugs are tracked on GitHub Issues. In case of trouble, please check there if your issue has already been reported. If you spotted it first, help us to smash it by providing a detailed and welcomed -feedback.

+feedback.

Do not contact contributors directly about support or help with technical issues.

-

Credits

+

Credits

-

Authors

+

Authors

  • Creu Blanca
-

Contributors

+

Contributors

+
  • NextPro: +
  • -

    Other credits

    +

    Other credits

    The migration of this module from 12.0 to 14.0 was financially supported by Camptocamp

    -

    Maintainers

    +

    Maintainers

    This module is maintained by the OCA.

    Odoo Community Association @@ -425,10 +434,11 @@

    Maintainers

    OCA, or the Odoo Community Association, is a nonprofit organization whose mission is to support the collaborative development of Odoo features and promote its widespread use.

    -

    This module is part of the OCA/queue project on GitHub.

    +

    This module is part of the OCA/queue project on GitHub.

    You are welcome to contribute. To learn how please visit https://odoo-community.org/page/Contribute.

    +
    From 5390a7e8ffc1c88a480af0cae717764e68741bc6 Mon Sep 17 00:00:00 2001 From: Victor Pincay Date: Tue, 1 Sep 2026 05:22:05 +0200 Subject: [PATCH 2/2] [IMP] test_queue_job_batch: cover the store and systray surfaces The 19.0 migration changed three Python surfaces that had no test at all: the store payload of the batch, the group flag published by `res.users`, and the systray request in the webclient controller. - `_to_store_defaults` replaced a hand-written read of the progress fields. Dropping one of them leaves the client without the value and the progress bar renders empty with no error, so the list itself is the contract. - `_init_store_data` publishes `hasQueueJobBatchUserGroup`, which is what makes the systray appear at all. Covered on both sides of the group. - The controller now dispatches **by name** instead of by a keyword flag. The added guard asserts that an unrelated request does *not* receive the batch counter: that is the failure mode the new signature introduces, and a test that only checked the payload would not notice the controller answering everything. Each test was verified by mutation: removing a field from `_to_store_defaults`, pinning the group flag to False, widening the controller guard to every request, and dropping `store.add(batches)` each turn exactly one test red. --- test_queue_job_batch/tests/__init__.py | 1 + .../tests/test_store_surfaces.py | 136 ++++++++++++++++++ 2 files changed, 137 insertions(+) create mode 100644 test_queue_job_batch/tests/test_store_surfaces.py diff --git a/test_queue_job_batch/tests/__init__.py b/test_queue_job_batch/tests/__init__.py index 39cec46423..da6b194f40 100644 --- a/test_queue_job_batch/tests/__init__.py +++ b/test_queue_job_batch/tests/__init__.py @@ -1 +1,2 @@ from . import test_queue_job_batch +from . import test_store_surfaces diff --git a/test_queue_job_batch/tests/test_store_surfaces.py b/test_queue_job_batch/tests/test_store_surfaces.py new file mode 100644 index 0000000000..231b5338c1 --- /dev/null +++ b/test_queue_job_batch/tests/test_store_surfaces.py @@ -0,0 +1,136 @@ +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html) + +from odoo.tests.common import HttpCase, TransactionCase, new_test_user, tagged + +from odoo.addons.mail.tools.discuss import Store + + +class TestBatchStoreData(TransactionCase): + """The store payload the web client relies on to draw the systray.""" + + @classmethod + def setUpClass(cls): + super().setUpClass() + cls.batch = cls.env["queue.job.batch"].get_new_batch("TEST STORE") + + def test_the_batch_is_stored_with_its_progress_fields(self): + """`_to_store_defaults` decides what the systray can draw. + + The migration replaced a hand-written read of these fields by + `_to_store_defaults`. Dropping one of them leaves the client without the + value and the progress bar silently renders empty, so the contract is + the list itself. + """ + result = Store().add(self.batch).get_result() + self.assertIn("queue.job.batch", result) + stored = result["queue.job.batch"][0] + self.assertEqual(stored["id"], self.batch.id) + for field in ( + "name", + "state", + "job_count", + "finished_job_count", + "failed_job_count", + "completeness", + "failed_percentage", + ): + self.assertIn( + field, + stored, + f"'{field}' is not in the store payload: the client cannot draw " + f"what it is not given", + ) + self.assertEqual(stored["name"], "TEST STORE") + self.assertEqual(stored["state"], self.batch.state) + + def test_a_user_in_the_group_is_told_so(self): + """`hasQueueJobBatchUserGroup` is what makes the systray appear at all.""" + user = new_test_user( + self.env, + login="batch_user", + groups="base.group_user,queue_job_batch.group_queue_job_batch_user", + ) + store = Store() + self.env["res.users"].with_user(user)._init_store_data(store) + self.assertTrue( + store.get_result()["Store"]["hasQueueJobBatchUserGroup"], + "a member of the group was not told so: the systray never shows up", + ) + + def test_a_user_outside_the_group_is_told_so(self): + """The negative side: without it the flag would be useless.""" + user = new_test_user(self.env, login="plain_user", groups="base.group_user") + store = Store() + self.env["res.users"].with_user(user)._init_store_data(store) + self.assertFalse( + store.get_result()["Store"]["hasQueueJobBatchUserGroup"], + "a user outside the group was told otherwise", + ) + + +@tagged("-at_install", "post_install") +class TestBatchSystrayRequest(HttpCase): + """The systray request over /mail/data. + + In 19.0 the request is dispatched **by name** instead of by a keyword flag, + so a test that only checked the payload would not notice the controller + answering every request. + """ + + @classmethod + def setUpClass(cls): + super().setUpClass() + cls.user = new_test_user( + cls.env, + login="systray_user", + password="systray_user", + groups="base.group_user,queue_job_batch.group_queue_job_batch_user", + ) + cls.batch = ( + cls.env["queue.job.batch"].with_user(cls.user).get_new_batch("TEST SYSTRAY") + ) + + def test_the_systray_request_returns_the_unread_batches(self): + self.authenticate("systray_user", "systray_user") + data = self.make_jsonrpc_request( + "/mail/data", {"fetch_params": ["systray_get_queue_job_batches"]} + ) + self.assertEqual( + data["Store"]["queueJobBatchCounter"], + 1, + "the counter does not match the unread batches of the user", + ) + self.assertIn( + "queueJobBatchCounterBusId", + data["Store"], + "without the bus id the client cannot tell a stale counter from a " + "fresh one", + ) + # Guarded before indexing: a bare KeyError here says nothing to whoever + # reads the red. + self.assertIn( + "queue.job.batch", + data, + "the batch itself was not sent, only its count: the systray has a " + "number it cannot open", + ) + self.assertEqual( + [batch["id"] for batch in data["queue.job.batch"]], + [self.batch.id], + ) + + def test_another_request_does_not_get_the_batch_counter(self): + """Guard against answering every request instead of its own. + + This is the shape of the 19.0 change: dispatch by `name`. If the guard + goes, the counter rides along on unrelated requests. + """ + self.authenticate("systray_user", "systray_user") + data = self.make_jsonrpc_request( + "/mail/data", {"fetch_params": ["systray_get_activities"]} + ) + self.assertNotIn( + "queueJobBatchCounter", + data.get("Store", {}), + "the batch counter answered a request that did not ask for it", + )