perf(test-e2e-playwright): order Playwright passes by meta/tests.yml run_after

A role's playwright.run_after names the roles its pass runs after; the new
playwright_order lookup reads it through role_tests (which now renders
Jinja with the queried role as application_id) and orders the round with
a stable topological sort, so only constrained roles move. web-app-docs
runs after every other invokable role: in CI run 41206003651 (Discourse#2)
its pass waited 3126 s for the docs server's Sphinx build while stalwart,
bigbluebutton, jitsi and prometheus (~400 s) queued behind it. Cycles,
self references, unknown roles and non-list values fail loudly.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
kevinveenbirkenbachandClaude Opus 5.5 committed 2026-10-31 21:41:55 +01:00
1 parent 104c140a0b
commit 89063972a6
11 files changed
+361 -8

No files matched your search

@@ -13,6 +13,7 @@ from utils.roles.order import (
build_dependency_graph,
find_cycle,
ordered_roles,
stable_order_after,
topological_sort,
)
@@ -82,5 +83,37 @@ class TestRoleOrder(unittest.TestCase):
ordered_roles(self.temp_dir, "grp")
class TestStableOrderAfter(unittest.TestCase):
NAMES = ("keycloak", "matomo", "docs", "stalwart", "jitsi")
def test_no_constraint_keeps_the_order(self):
self.assertEqual(stable_order_after(list(self.NAMES), {}), list(self.NAMES))
def test_a_name_after_all_others_moves_last_and_nothing_else_moves(self):
others = [name for name in self.NAMES if name != "docs"]
result = stable_order_after(list(self.NAMES), {"docs": others})
self.assertEqual(result, [*others, "docs"])
def test_a_satisfied_constraint_moves_nothing(self):
result = stable_order_after(list(self.NAMES), {"stalwart": ["matomo"]})
self.assertEqual(result, list(self.NAMES))
def test_names_outside_the_list_constrain_nothing(self):
result = stable_order_after(
list(self.NAMES), {"matomo": ["absent"], "docs": ["jitsi", "gone"]}
)
self.assertEqual(result, ["keycloak", "matomo", "stalwart", "jitsi", "docs"])
def test_a_name_listing_itself_raises(self):
with self.assertRaises(RuntimeError):
stable_order_after(list(self.NAMES), {"docs": ["docs"]})
def test_a_cycle_raises_and_names_its_members(self):
with self.assertRaises(RuntimeError) as ctx:
stable_order_after(list(self.NAMES), {"docs": ["jitsi"], "jitsi": ["docs"]})
self.assertIn("docs", str(ctx.exception))
self.assertIn("jitsi", str(ctx.exception))
if __name__ == "__main__":
unittest.main()