Files
odoo_source/addons/bus/tests/test_websocket_controller.py
T
tsm-odoo be1ea4d3c8 [FIX] bus: handle session expired in peek notifications
In order to know whether or not the websocket session is up to date,
the session is saved when opening a websocket connection. Then, for
each incoming/outgoing message, we check if the session still exists
on the file system. When it does not exist anymore, the websocket
connection is refreshed. This ensures the session is always up to date.

Odoo sh proxies the websocket connection and needs a way to tell
when a websocket session is expired. This commit adds the same
check that is done for each incoming websocket message in the
websocket peek route in order to raise a `SessionExpiredException`
when the session is outdated.

This will allow odoo sh to catch this error and to refresh their
websocket connection accordingly.

closes odoo/odoo#100416

Signed-off-by: Julien Castiaux <juc@odoo.com>
2022-09-20 16:29:26 +02:00

93 lines
3.4 KiB
Python

# Part of Odoo. See LICENSE file for full copyright and licensing details.
import json
from odoo.tests import common
class TestWebsocketController(common.HttpCase):
def _make_rpc(self, route, params, headers=None):
data = json.dumps({
'id': 0,
'jsonrpc': '2.0',
'method': 'call',
'params': params,
}).encode()
headers = headers or {}
headers['Content-Type'] = 'application/json'
return self.url_open(route, data, headers=headers)
def test_websocket_peek(self):
response = json.loads(
self._make_rpc('/websocket/peek_notifications', {
'channels': [],
'last': 0,
'is_first_poll': True,
}).content.decode()
)
# Response containing channels/notifications is retrieved and is
# conform to excpectations.
result = response.get('result')
self.assertIsNotNone(result)
channels = result.get('channels')
self.assertIsNotNone(channels)
self.assertIsInstance(channels, list)
notifications = result.get('notifications')
self.assertIsNotNone(notifications)
self.assertIsInstance(notifications, list)
response = json.loads(
self._make_rpc('/websocket/peek_notifications', {
'channels': [],
'last': 0,
'is_first_poll': False,
}).content.decode()
)
# Reponse is received as long as the session is valid.
self.assertIn('result', response)
def test_websocket_peek_session_expired_login(self):
session = self.authenticate(None, None)
# first rpc should be fine
self._make_rpc('/websocket/peek_notifications', {
'channels': [],
'last': 0,
'is_first_poll': True,
})
self.authenticate('admin', 'admin')
# rpc with outdated session should lead to error.
headers = {'Cookie': f'session_id={session.sid};'}
response = json.loads(
self._make_rpc('/websocket/peek_notifications', {
'channels': [],
'last': 0,
'is_first_poll': False,
}, headers=headers).content.decode()
)
error = response.get('error')
self.assertIsNotNone(error, 'Sending a poll with an outdated session should lead to error')
self.assertEqual('odoo.http.SessionExpiredException', error['data']['name'])
def test_websocket_peek_session_expired_logout(self):
session = self.authenticate('demo', 'demo')
# first rpc should be fine
self._make_rpc('/websocket/peek_notifications', {
'channels': [],
'last': 0,
'is_first_poll': True,
})
self.url_open('/web/session/logout')
# rpc with outdated session should lead to error.
headers = {'Cookie': f'session_id={session.sid};'}
response = json.loads(
self._make_rpc('/websocket/peek_notifications', {
'channels': [],
'last': 0,
'is_first_poll': False,
}, headers=headers).content.decode()
)
error = response.get('error')
self.assertIsNotNone(error, 'Sending a poll with an outdated session should lead to error')
self.assertEqual('odoo.http.SessionExpiredException', error['data']['name'])