From aaade72ee99e074bd0c128aa4b40f1678b0940b2 Mon Sep 17 00:00:00 2001 From: Xavier-Do Date: Fri, 17 Mar 2023 11:08:01 +0100 Subject: [PATCH] [IMP] runbot: add test for build concurency --- runbot_populate/demo/runbot_demo.xml | 46 ++++++++++++++++++- runbot_populate/tests/__init__.py | 1 + runbot_populate/tests/test_concurrency.py | 55 +++++++++++++++++++++++ 3 files changed, 101 insertions(+), 1 deletion(-) create mode 100644 runbot_populate/tests/__init__.py create mode 100644 runbot_populate/tests/test_concurrency.py diff --git a/runbot_populate/demo/runbot_demo.xml b/runbot_populate/demo/runbot_demo.xml index da55fc03..203213cb 100644 --- a/runbot_populate/demo/runbot_demo.xml +++ b/runbot_populate/demo/runbot_demo.xml @@ -55,6 +55,10 @@ + + 16.0 + + saas-16.1 @@ -146,7 +150,6 @@ - Linting @@ -154,6 +157,47 @@ Security + + Split + + + + Post install + + + + main host + + + + + + + + + + + main host + + + + + + + + + + + + main host + + + + + + main host + + diff --git a/runbot_populate/tests/__init__.py b/runbot_populate/tests/__init__.py new file mode 100644 index 00000000..173715a4 --- /dev/null +++ b/runbot_populate/tests/__init__.py @@ -0,0 +1 @@ +from . import test_concurrency diff --git a/runbot_populate/tests/test_concurrency.py b/runbot_populate/tests/test_concurrency.py new file mode 100644 index 00000000..b5b1f7ab --- /dev/null +++ b/runbot_populate/tests/test_concurrency.py @@ -0,0 +1,55 @@ +from odoo import api, SUPERUSER_ID +from odoo.tests import TransactionCase +from unittest.mock import patch + + +class TestConcurrency(TransactionCase): + def test_local_status_update(self): + """ + This test ensures that a parent build global state will eventually be updated + even if updated concurrenctly in 2 different transactions, without transaction error + """ + with self.registry.cursor() as cr0: + env0 = api.Environment(cr0, SUPERUSER_ID, {}) + host = env0.ref('runbot_populate.main_host') + host._process_messages() # ensure queue is empty + parent_build = env0.ref('runbot_populate.build_base') + build_child1 = env0.ref('runbot_populate.build_child1') + build_child2 = env0.ref('runbot_populate.build_child2') + parent_build.local_state = 'done' + self.assertEqual(host.host_message_ids.mapped('message'), []) + build_child1.local_state = 'testing' + build_child2.local_state = 'testing' + self.assertEqual(host.host_message_ids.mapped('message'), ['global_updated', 'global_updated']) + self.assertEqual(host.host_message_ids.build_id, parent_build) + host._process_messages() + self.assertEqual(parent_build.global_state, 'waiting') + env0.cr.commit() # youplahé + + with self.registry.cursor() as cr1: + env1 = api.Environment(cr1, SUPERUSER_ID, {}) + with self.registry.cursor() as cr2: + env2 = api.Environment(cr2, SUPERUSER_ID, {}) + build_child_cr1 = env1['runbot.build'].browse(build_child1.id) + build_child_cr2 = env2['runbot.build'].browse(build_child2.id) + self.assertEqual(build_child_cr1.parent_id.global_state, 'waiting') + self.assertEqual(build_child_cr1.parent_id.children_ids.mapped('local_state'), ['testing', 'testing']) + self.assertEqual(build_child_cr2.parent_id.global_state, 'waiting') + self.assertEqual(build_child_cr2.parent_id.children_ids.mapped('local_state'), ['testing', 'testing']) + build_child_cr1.local_state = 'done' + build_child_cr2.local_state = 'done' + # from the point of view of each transaction, the other one local_state didn't changed + self.assertEqual(build_child_cr1.parent_id.children_ids.mapped('local_state'), ['testing', 'done']) + self.assertEqual(build_child_cr2.parent_id.global_state, 'waiting') + self.assertEqual(build_child_cr2.parent_id.children_ids.mapped('local_state'), ['done', 'testing']) + env1.cr.commit() + env2.cr.commit() + env0.cr.commit() # not usefull just to ensure we have efefct of other transactions + env0.cache.invalidate() + self.assertEqual(parent_build.children_ids.mapped('local_state'), ['done', 'done']) + self.assertEqual(parent_build.children_ids.mapped('global_state'), ['done', 'done']) + self.assertEqual(host.host_message_ids.mapped('message'), ['global_updated', 'global_updated']) + self.assertEqual(host.host_message_ids.build_id, parent_build) + # at this point, this assertion is true, but not expected : self.assertEqual(parent_build.global_state, 'waiting') + host._process_messages() + self.assertEqual(parent_build.global_state, 'done')