onboarding/tests/test_onboarding_concurrency.py

87 lines
3.1 KiB
Python
Raw Permalink Normal View History

2024-05-03 12:58:20 +03:00
# -*- coding: utf-8 -*-
# Part of Odoo. See LICENSE file for full copyright and licensing details.
import threading
from concurrent.futures import ThreadPoolExecutor
from psycopg2 import IntegrityError
import odoo
from odoo.tests.common import get_db_name, tagged, BaseCase
from odoo.tools import mute_logger
@tagged('-standard', '-at_install', 'post_install', 'database_breaking')
class TestOnboardingConcurrency(BaseCase):
@classmethod
def setUpClass(cls):
super().setUpClass()
cls.registry = odoo.registry(get_db_name())
cls.addClassCleanup(cls.cleanUpClass)
with cls.registry.cursor() as cr:
env = odoo.api.Environment(cr, odoo.SUPERUSER_ID, {})
cls.onboarding_id = env['onboarding.onboarding'].create([
{
'name': 'Test Onboarding Concurrent',
'is_per_company': False,
'route_name': 'onboarding_concurrent'
}
]).id
@classmethod
def cleanUpClass(cls):
with cls.registry.cursor() as cr:
env = odoo.api.Environment(cr, odoo.SUPERUSER_ID, {})
env['onboarding.onboarding'].browse(cls.onboarding_id).unlink()
env['onboarding.progress'].search([
('onboarding_id', '=', cls.onboarding_id)
]).unlink()
@mute_logger('odoo.sql_db')
def test_concurrent_create_progress(self):
barrier = threading.Barrier(2)
def run():
raised_unique_violation = False
with self.registry.cursor() as cr:
env = odoo.api.Environment(cr, odoo.SUPERUSER_ID, {})
onboarding = env['onboarding.onboarding'].search([
('id', '=', self.onboarding_id)
])
# There is no progress record
self.assertFalse(env['onboarding.progress'].search([
('onboarding_id', '=', self.onboarding_id)
]))
barrier.wait(timeout=2)
try:
onboarding._create_progress()
except IntegrityError as e:
if e.pgcode == "23505": # UniqueViolation
raised_unique_violation = True
return raised_unique_violation
with ThreadPoolExecutor(max_workers=2) as executor:
future_1 = executor.submit(run)
future_2 = executor.submit(run)
raised_1 = future_1.result(timeout=3)
raised_2 = future_2.result(timeout=3)
with self.registry.cursor() as cr:
env = odoo.api.Environment(cr, odoo.SUPERUSER_ID, {})
self.assertEqual(
len(env['onboarding.progress'].search([('onboarding_id', '=', self.onboarding_id)])),
1,
"Exactly one thread should have been able to create a record."
)
self.assertEqual(
raised_1 + raised_2,
1,
"Exactly one thread should have raised a UniqueViolation error even though "
"there was no progress record at the start of its transaction."
)