From 0062fbe5bc48d674ad890ce97b70bce54fa8c3a6 Mon Sep 17 00:00:00 2001 From: Rene Cannao Date: Wed, 19 Aug 2026 07:07:22 +0000 Subject: [PATCH] build: make MySQLX bridge dependencies deterministic --- .github/workflows/CI-lint-groups-json.yml | 2 + test/tap/groups/test_makefile_dependencies.py | 63 +++++++++++++++++++ test/tap/tests/Makefile | 20 +++--- 3 files changed, 76 insertions(+), 9 deletions(-) create mode 100644 test/tap/groups/test_makefile_dependencies.py diff --git a/.github/workflows/CI-lint-groups-json.yml b/.github/workflows/CI-lint-groups-json.yml index f1fbd81632..3f905dbd36 100644 --- a/.github/workflows/CI-lint-groups-json.yml +++ b/.github/workflows/CI-lint-groups-json.yml @@ -25,6 +25,8 @@ jobs: run: python3 test/tap/groups/lint_groups_json.py - name: Check AI TAP shard split run: python3 test/tap/groups/test_ai_group_shards.py + - name: Check TAP Makefile dependency graph + run: python3 test/tap/groups/test_makefile_dependencies.py - name: Check every TAP source is registered in groups.json run: python3 test/tap/groups/check_groups.py --source - name: Check cluster simulator coverage contract diff --git a/test/tap/groups/test_makefile_dependencies.py b/test/tap/groups/test_makefile_dependencies.py new file mode 100644 index 0000000000..4b4199e6f5 --- /dev/null +++ b/test/tap/groups/test_makefile_dependencies.py @@ -0,0 +1,63 @@ +#!/usr/bin/env python3 +"""Regression contracts for TAP Makefile dependency boundaries.""" + +import subprocess +import unittest +from pathlib import Path + + +ROOT = Path(__file__).resolve().parents[3] +TAP_TESTS_DIR = ROOT / "test/tap/tests" +MYSQLX_BRIDGE_TARGETS = ( + "test_mysqlx_plugin_load-t", + "test_mysqlx_admin_tables-t", +) + + +class MakefileDependencyTest(unittest.TestCase): + def test_mysqlx_bridge_targets_share_one_unit_submake(self): + result = subprocess.run( + [ + "make", + "--no-print-directory", + "-C", + str(TAP_TESTS_DIR), + "-n", + "-j2", + "MAKE=echo", + *MYSQLX_BRIDGE_TARGETS, + ], + cwd=ROOT, + text=True, + capture_output=True, + check=False, + timeout=30, + ) + + self.assertEqual(result.returncode, 0, result.stdout + result.stderr) + + unit_submakes = [ + line.split()[2:] + for line in result.stdout.splitlines() + if line.startswith("-C unit ") + ] + self.assertEqual( + unit_submakes, + [list(MYSQLX_BRIDGE_TARGETS)], + result.stdout, + ) + + symlinks = [ + line + for line in result.stdout.splitlines() + if line.startswith("ln -fs unit/") + ] + self.assertCountEqual( + symlinks, + [f"ln -fs unit/{target} {target}" for target in MYSQLX_BRIDGE_TARGETS], + result.stdout, + ) + + +if __name__ == "__main__": + unittest.main() diff --git a/test/tap/tests/Makefile b/test/tap/tests/Makefile index 77f8865271..0520d1c33a 100644 --- a/test/tap/tests/Makefile +++ b/test/tap/tests/Makefile @@ -293,15 +293,17 @@ test_tokenizer-t: test_tokenizer-t.cpp $(TAP_LDIR)/libtap$(SHLIB_EXT) test_mysql_query_digests_stages-t: test_mysql_query_digests_stages-t.cpp $(TAP_LDIR)/libtap$(SHLIB_EXT) $(CXX) $< $(IDIRS) $(LDIRS) $(OPT) $(MYLIBS) -o $@ -.PHONY: test_mysqlx_plugin_load-t -test_mysqlx_plugin_load-t: - $(MAKE) -C unit test_mysqlx_plugin_load-t - ln -fs unit/test_mysqlx_plugin_load-t $@ - -.PHONY: test_mysqlx_admin_tables-t -test_mysqlx_admin_tables-t: - $(MAKE) -C unit test_mysqlx_admin_tables-t - ln -fs unit/test_mysqlx_admin_tables-t $@ +MYSQLX_BRIDGE_TESTS := test_mysqlx_plugin_load-t test_mysqlx_admin_tables-t + +# Build both bridge tests in one unit submake. Separate recursive makes do not +# share a dependency graph and can otherwise rebuild common objects such as +# unit/obj/test_init.o concurrently. +.PHONY: mysqlx-bridge-tests $(MYSQLX_BRIDGE_TESTS) +mysqlx-bridge-tests: + $(MAKE) -C unit $(MYSQLX_BRIDGE_TESTS) + +$(MYSQLX_BRIDGE_TESTS): mysqlx-bridge-tests + ln -fs unit/$@ $@ # test_mysqlx_listener_smoke-t was retired with the dormant MysqlxWorker # path in 98aee7db2. Listener-lifecycle coverage now lives in