Skip to content

Commit c3d24f3

Browse files
committed
[IMP] runbot: add test for build concurency
1 parent f4effee commit c3d24f3

File tree

3 files changed

+101
-1
lines changed

3 files changed

+101
-1
lines changed

runbot_populate/demo/runbot_demo.xml

Lines changed: 45 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,10 @@
5555
<field name="repo_id" ref="repo_runbot"/>
5656
</record>
5757

58+
<record id="version_16" model="runbot.version">
59+
<field name="name">16.0</field>
60+
</record>
61+
5862
<!-- BUNDLES -->
5963
<record id="bundle_16_1" model="runbot.bundle">
6064
<field name="name">saas-16.1</field>
@@ -146,14 +150,54 @@
146150
<field name="ci_context"/>
147151
</record>
148152

149-
150153
<record id="runbot_build_config_linting" model="runbot.build.config">
151154
<field name="name">Linting</field>
152155
</record>
153156
<record id="runbot_build_config_security" model="runbot.build.config">
154157
<field name="name">Security</field>
155158
</record>
156159

160+
<record id="runbot_build_config_split" model="runbot.build.config">
161+
<field name="name">Split</field>
162+
</record>
163+
164+
<record id="runbot_build_config_post_install" model="runbot.build.config">
165+
<field name="name">Post install</field>
166+
</record>
167+
168+
<record id="main_host" model="runbot.host">
169+
<field name="name">main host</field>
170+
</record>
171+
172+
<record id="build_base_params" model="runbot.build.params">
173+
<field name="config_id" ref="runbot_build_config_split"/>
174+
<field name="version_id" ref="version_16"/>
175+
<field name="project_id" ref="project_runbot"/>
176+
</record>
177+
178+
<record id="build_base" model="runbot.build">
179+
<field name="params_id" ref="build_base_params"/>
180+
<field name="host">main host</field>
181+
</record>
182+
183+
<record id="build_child_params" model="runbot.build.params">
184+
<field name="config_id" ref="runbot_build_config_post_install"/>
185+
<field name="version_id" ref="version_16"/>
186+
<field name="project_id" ref="project_runbot"/>
187+
</record>
188+
189+
<record id="build_child1" model="runbot.build">
190+
<field name="params_id" ref="build_child_params"/>
191+
<field name="parent_id" ref="build_base"/>
192+
<field name="host">main host</field>
193+
</record>
194+
195+
<record id="build_child2" model="runbot.build">
196+
<field name="params_id" ref="build_child_params"/>
197+
<field name="parent_id" ref="build_base"/>
198+
<field name="host">main host</field>
199+
</record>
200+
157201
<function model="runbot.runbot" name="_create_demo_data">
158202
</function>
159203

runbot_populate/tests/__init__.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
from . import test_concurrency
Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
from odoo import api, SUPERUSER_ID
2+
from odoo.tests import TransactionCase
3+
from unittest.mock import patch
4+
5+
6+
class TestConcurrency(TransactionCase):
7+
def test_local_status_update(self):
8+
"""
9+
This test ensures that a parent build global state will eventually be updated
10+
even if updated concurrenctly in 2 different transactions, without transaction error
11+
"""
12+
with self.registry.cursor() as cr0:
13+
env0 = api.Environment(cr0, SUPERUSER_ID, {})
14+
host = env0.ref('runbot_populate.main_host')
15+
host._process_messages() # ensure queue is empty
16+
parent_build = env0.ref('runbot_populate.build_base')
17+
build_child1 = env0.ref('runbot_populate.build_child1')
18+
build_child2 = env0.ref('runbot_populate.build_child2')
19+
parent_build.local_state = 'done'
20+
self.assertEqual(host.host_message_ids.mapped('message'), [])
21+
build_child1.local_state = 'testing'
22+
build_child2.local_state = 'testing'
23+
self.assertEqual(host.host_message_ids.mapped('message'), ['global_updated', 'global_updated'])
24+
self.assertEqual(host.host_message_ids.build_id, parent_build)
25+
host._process_messages()
26+
self.assertEqual(parent_build.global_state, 'waiting')
27+
env0.cr.commit() # youplahé
28+
29+
with self.registry.cursor() as cr1:
30+
env1 = api.Environment(cr1, SUPERUSER_ID, {})
31+
with self.registry.cursor() as cr2:
32+
env2 = api.Environment(cr2, SUPERUSER_ID, {})
33+
build_child_cr1 = env1['runbot.build'].browse(build_child1.id)
34+
build_child_cr2 = env2['runbot.build'].browse(build_child2.id)
35+
self.assertEqual(build_child_cr1.parent_id.global_state, 'waiting')
36+
self.assertEqual(build_child_cr1.parent_id.children_ids.mapped('local_state'), ['testing', 'testing'])
37+
self.assertEqual(build_child_cr2.parent_id.global_state, 'waiting')
38+
self.assertEqual(build_child_cr2.parent_id.children_ids.mapped('local_state'), ['testing', 'testing'])
39+
build_child_cr1.local_state = 'done'
40+
build_child_cr2.local_state = 'done'
41+
# from the point of view of each transaction, the other one local_state didn't changed
42+
self.assertEqual(build_child_cr1.parent_id.children_ids.mapped('local_state'), ['testing', 'done'])
43+
self.assertEqual(build_child_cr2.parent_id.global_state, 'waiting')
44+
self.assertEqual(build_child_cr2.parent_id.children_ids.mapped('local_state'), ['done', 'testing'])
45+
env1.cr.commit()
46+
env2.cr.commit()
47+
env0.cr.commit() # not usefull just to ensure we have efefct of other transactions
48+
env0.cache.invalidate()
49+
self.assertEqual(parent_build.children_ids.mapped('local_state'), ['done', 'done'])
50+
self.assertEqual(parent_build.children_ids.mapped('global_state'), ['done', 'done'])
51+
self.assertEqual(host.host_message_ids.mapped('message'), ['global_updated', 'global_updated'])
52+
self.assertEqual(host.host_message_ids.build_id, parent_build)
53+
# at this point, this assertion is true, but not expected : self.assertEqual(parent_build.global_state, 'waiting')
54+
host._process_messages()
55+
self.assertEqual(parent_build.global_state, 'done')

0 commit comments

Comments
 (0)