summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorXavier Morel <xmo@odoo.com>2020-03-06 14:45:21 +0000
committerOlivier Dony <odo@odoo.com>2020-08-14 21:20:47 +0000
commitdccbf425a1742c08564d4f7b223ce27f8746c832 (patch)
tree3a45016eb7a06a00cf41e95f722e0b9c69100a70
parent950d962d95d214bdd1bdd64d8771af96d4d618cf (diff)
[FIX] core: ensure we create a new session for each tour
The browser itself would get mostly cleaned up between tours, but the session object would not get cleaned, and apparently in some cases that could lead to an incoherent session: a tour would add data to the session which the next tour (logging in as a different user) would not (fully) override, leading to a session inconsistency and a Session Expired exception during the tour. Fix by not storing the session on the test object, the session is created during authentication then set on the opener & browser.
-rw-r--r--addons/account/tests/test_portal_attachment.py2
-rw-r--r--addons/test_xlsx_export/tests/test_export.py4
-rw-r--r--addons/website/tests/test_page.py1
-rw-r--r--odoo/tests/common.py55
4 files changed, 36 insertions, 26 deletions
diff --git a/addons/account/tests/test_portal_attachment.py b/addons/account/tests/test_portal_attachment.py
index 02ac0cf04a7..2340fc75f2a 100644
--- a/addons/account/tests/test_portal_attachment.py
+++ b/addons/account/tests/test_portal_attachment.py
@@ -32,6 +32,8 @@ class TestPortalAttachment(AccountTestInvoicingHttpCommon):
def test_01_portal_attachment(self):
"""Test the portal chatter attachment route."""
+ self.authenticate(None, None)
+
# Test public user can't create attachment without token of document
res = self.url_open(
url='%s/portal/attachment/add' % self.base_url,
diff --git a/addons/test_xlsx_export/tests/test_export.py b/addons/test_xlsx_export/tests/test_export.py
index df0f85a5a4c..5ba8c0a0de5 100644
--- a/addons/test_xlsx_export/tests/test_export.py
+++ b/addons/test_xlsx_export/tests/test_export.py
@@ -22,8 +22,8 @@ class XlsxCreatorCase(common.HttpCase):
super().setUp()
self.model = self.env[self.model_name]
- u = mail_new_test_user(self.env, login='fof', password='123456789', groups='base.group_user,base.group_allow_export')
- self.authenticate('fof', '123456789')
+ mail_new_test_user(self.env, login='fof', password='123456789', groups='base.group_user,base.group_allow_export')
+ self.session = self.authenticate('fof', '123456789')
self.worksheet = {} # mock worksheet
diff --git a/addons/website/tests/test_page.py b/addons/website/tests/test_page.py
index eb7a1ba9976..7d7d0928518 100644
--- a/addons/website/tests/test_page.py
+++ b/addons/website/tests/test_page.py
@@ -222,6 +222,7 @@ class WithContext(HttpCase):
specific_page = self.page.copy({'website_id': self.env['website'].get_current_website().id})
specific_page.write({'is_published': False, 'arch': self.page.arch.replace('I am a generic page', 'I am a specific page')})
+ self.authenticate(None, None)
r = self.url_open(specific_page.url)
self.assertEqual(r.status_code, 404, "Restricted users should see a 404 and not the generic one as we unpublished the specific one")
diff --git a/odoo/tests/common.py b/odoo/tests/common.py
index 71418c5cc2f..066bb067148 100644
--- a/odoo/tests/common.py
+++ b/odoo/tests/common.py
@@ -1255,14 +1255,8 @@ class HttpCaseCommon(BaseCase):
if self.registry_test_mode:
self.registry.enter_test_mode(self.cr)
self.addCleanup(self.registry.leave_test_mode)
- # setup a magic session_id that will be rollbacked
- self.session = odoo.http.root.session_store.new()
- self.session_id = self.session.sid
- self.session.db = get_db_name()
- odoo.http.root.session_store.save(self.session)
# setup an url opener helper
self.opener = requests.Session()
- self.opener.cookies['session_id'] = self.session_id
@classmethod
def start_browser(cls):
@@ -1311,31 +1305,44 @@ class HttpCaseCommon(BaseCase):
odoo.http.root.session_store.save(self.session)
def authenticate(self, user, password):
- # stay non-authenticated
- if user is None:
- if self.session:
- odoo.http.root.session_store.delete(self.session)
- self.browser.delete_cookie('session_id', domain=HOST)
- return
-
db = get_db_name()
- uid = self.registry['res.users'].authenticate(db, user, password, {'interactive': False})
- env = api.Environment(self.cr, uid, {})
-
- session = self.session
+ if getattr(self, 'session', None):
+ odoo.http.root.session_store.delete(self.session)
+ self.session = session = odoo.http.root.session_store.new()
session.db = db
- session.uid = uid
- session.login = user
- session.session_token = uid and security.compute_session_token(session, env)
- session.context = dict(env['res.users'].context_get() or {})
- session.context['uid'] = uid
- session._fix_lang(session.context)
+
+ if user: # if authenticated
+ uid = self.registry['res.users'].authenticate(db, user, password, {'interactive': False})
+ env = api.Environment(self.cr, uid, {})
+ session.uid = uid
+ session.login = user
+ session.session_token = uid and security.compute_session_token(session, env)
+ session.context = dict(env['res.users'].context_get() or {})
+ session.context['uid'] = uid
+ session._fix_lang(session.context)
odoo.http.root.session_store.save(session)
+ # Reset the opener: turns out when we set cookies['foo'] we're really
+ # setting a cookie on domain='' path='/'.
+ #
+ # But then our friendly neighborhood server might set a cookie for
+ # domain='localhost' path='/' (with the same value) which is considered
+ # a *different* cookie following ours rather than the same.
+ #
+ # When we update our cookie, it's done in-place, so the server-set
+ # cookie is still present and (as it follows ours and is more precise)
+ # very likely to still be used, therefore our session change is ignored.
+ #
+ # An alternative would be to set the cookie to None (unsetting it
+ # completely) or clear-ing session.cookies.
+ self.opener = requests.Session()
+ self.opener.cookies['session_id'] = session.sid
if self.browser:
self._logger.info('Setting session cookie in browser')
- self.browser.set_cookie('session_id', self.session_id, '/', HOST)
+ self.browser.set_cookie('session_id', session.sid, '/', HOST)
+
+ return session
def browser_js(self, url_path, code, ready='', login=None, timeout=60, **kw):
""" Test js code running in the browser