diff --git a/addons/bus/controllers/websocket.py b/addons/bus/controllers/websocket.py index d870b3da29c..2056b37d74e 100644 --- a/addons/bus/controllers/websocket.py +++ b/addons/bus/controllers/websocket.py @@ -1,7 +1,6 @@ # Part of Odoo. See LICENSE file for full copyright and licensing details. import json -from werkzeug.exceptions import ServiceUnavailable from odoo.http import Controller, request, route, SessionExpiredException from odoo.addons.base.models.assetsbundle import AssetsBundle @@ -16,10 +15,6 @@ class WebsocketController(Controller): Handle the websocket handshake, upgrade the connection if successfull. """ - is_headful_browser = request.httprequest.user_agent and 'Headless' not in request.httprequest.user_agent.string - if request.registry.in_test_mode() and is_headful_browser: - # Prevent browsers from interfering with the unittests - raise ServiceUnavailable() return WebsocketConnectionHandler.open_connection(request) @route('/websocket/health', type='http', auth='none', save_session=False) diff --git a/addons/bus/static/tests/bus_tests.js b/addons/bus/static/tests/bus_tests.js index e0f9ddfd5c9..f393996b4cb 100644 --- a/addons/bus/static/tests/bus_tests.js +++ b/addons/bus/static/tests/bus_tests.js @@ -358,6 +358,7 @@ QUnit.test("Can reconnect after late close event", async (assert) => { QUnit.test("Fallback on simple worker when shared worker failed to initialize", async (assert) => { addBusServicesToRegistry(); + patchWebsocketWorkerWithCleanup(); const originalSharedWorker = browser.SharedWorker; const originalWorker = browser.Worker; patchWithCleanup(browser, { diff --git a/addons/bus/tests/common.py b/addons/bus/tests/common.py index e332c2ec348..7d260983e2d 100644 --- a/addons/bus/tests/common.py +++ b/addons/bus/tests/common.py @@ -12,12 +12,12 @@ except ImportError: websocket = None import odoo.tools -from odoo.tests import HOST, common +from odoo.tests import HOST, HttpCase from ..websocket import CloseCode, Websocket, WebsocketConnectionHandler from ..models.bus import dispatch, hashable, channel_with_db -class WebsocketCase(common.HttpCase): +class WebsocketCase(HttpCase): @classmethod def setUpClass(cls): super().setUpClass() @@ -25,6 +25,8 @@ class WebsocketCase(common.HttpCase): cls._logger.warning("websocket-client module is not installed") raise unittest.SkipTest("websocket-client module is not installed") cls._WEBSOCKET_URL = f"ws://{HOST}:{odoo.tools.config['http_port']}/websocket" + websocket_allowed_patch = patch.object(WebsocketConnectionHandler, "websocket_allowed", return_value=True) + cls.startClassPatcher(websocket_allowed_patch) def setUp(self): super().setUp() diff --git a/addons/bus/tests/test_websocket_caryall.py b/addons/bus/tests/test_websocket_caryall.py index 3e26e661c9d..5c8e70dc7d3 100644 --- a/addons/bus/tests/test_websocket_caryall.py +++ b/addons/bus/tests/test_websocket_caryall.py @@ -183,17 +183,6 @@ class TestWebsocketCaryall(WebsocketCase): self.assertEqual(notifications[0]['message']['type'], 'notif_type') self.assertEqual(notifications[0]['message']['payload'], 'another_message') - def test_opening_websocket_connection_during_tests(self): - # During tests, browsers can't open websocket connections. - headers = ['User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/102.0.0.0 Safari/537.36'] - with self.assertRaises(WebSocketBadStatusException) as error_catcher: - self.websocket_connect(header=headers) - self.assertEqual(error_catcher.exception.status_code, 503) - - # But ChromeHeadless still can. - headers = ['User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) HeadlessChrome/102.0.0.0 Safari/537.36'] - self.websocket_connect() - def test_subscribe_higher_last_notification_id(self): server_last_notification_id = self.env['bus.bus'].sudo().search([], limit=1, order='id desc').id or 0 client_last_notification_id = server_last_notification_id + 1 diff --git a/addons/bus/websocket.py b/addons/bus/websocket.py index 3d4bd77b46c..d44938c1d93 100644 --- a/addons/bus/websocket.py +++ b/addons/bus/websocket.py @@ -19,7 +19,7 @@ from urllib.parse import urlparse from weakref import WeakSet from werkzeug.local import LocalStack -from werkzeug.exceptions import BadRequest, HTTPException +from werkzeug.exceptions import BadRequest, HTTPException, ServiceUnavailable import odoo from odoo import api @@ -821,6 +821,10 @@ class WebsocketConnectionHandler: 'sec-websocket-version', 'upgrade', 'origin', } + @classmethod + def websocket_allowed(cls, request): + return not request.registry.in_test_mode() + @classmethod def open_connection(cls, request): """ @@ -831,6 +835,8 @@ class WebsocketConnectionHandler: versions the client supports and those we support. :raise: BadRequest if the handshake data is incorrect. """ + if not cls.websocket_allowed(request): + raise ServiceUnavailable("Websocket is disabled in test mode") cls._handle_public_configuration(request) try: response = cls._get_handshake_response(request.httprequest.headers)