Skip to content

Commit db66144

Browse files
committed
Fix Cloud Hypervisor live migration nextest filtering
Run Cloud Hypervisor live migration tests through the CLI path and construct the nextest filter as a shell-safe expression. Preserve the base test filter while excluding the serial-only live migration test from the parallel run.
1 parent 9bc43a1 commit db66144

2 files changed

Lines changed: 95 additions & 7 deletions

File tree

lisa/microsoft/testsuites/cloud_hypervisor/ch_tests.py

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -126,14 +126,17 @@ def verify_cloud_hypervisor_live_migration_tests(
126126
"ch_live_migration_tests_excluded",
127127
)
128128
ch_tests: CloudHypervisorTests = node.tools[CloudHypervisorTests]
129+
# Cloud Hypervisor exposes live migration as integration subtests.
129130
ch_tests.run_tests(
130131
result,
131132
"integration-live-migration",
132133
hypervisor,
133134
log_path,
134135
ref,
135-
include_list,
136-
exclude_list,
136+
only=include_list,
137+
skip=exclude_list,
138+
cli_test_type="integration",
139+
cli_test_filter="live_migration",
137140
)
138141

139142
@TestCaseMetadata(

lisa/microsoft/testsuites/cloud_hypervisor/ch_tests_tool.py

Lines changed: 90 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -144,18 +144,73 @@ def _sanitize_name(self, s: str) -> str:
144144
"""Sanitize names for filenames: keep alphanumeric, dot, dash, underscore."""
145145
return re.sub(r"[^A-Za-z0-9_.-]", "_", s)
146146

147+
@staticmethod
148+
def _escape_nextest_filter_matcher(matcher: str) -> str:
149+
return matcher.replace("\\", "\\\\").replace(")", "\\)")
150+
151+
@staticmethod
152+
def _quote_bash_arg(arg: str) -> str:
153+
escaped = (
154+
arg.replace("\\", "\\\\")
155+
.replace('"', '\\"')
156+
.replace("$", "\\$")
157+
.replace("`", "\\`")
158+
)
159+
return f'"{escaped}"'
160+
161+
def _build_nextest_filterset(
162+
self,
163+
base_filter: str,
164+
only: Optional[List[str]],
165+
skip: Optional[List[str]],
166+
) -> str:
167+
filterset = f"test(~{self._escape_nextest_filter_matcher(base_filter)})"
168+
169+
if only:
170+
included_tests = "|".join(
171+
f"test(={self._escape_nextest_filter_matcher(test_name)})"
172+
for test_name in only
173+
)
174+
filterset = f"({filterset}&({included_tests}))"
175+
176+
if skip:
177+
for skipped_test in skip:
178+
skipped_filter = self._escape_nextest_filter_matcher(skipped_test)
179+
filterset = f"{filterset}-test(={skipped_filter})"
180+
181+
return f"--filterset={filterset}"
182+
147183
def _prepare_subtests(
148184
self,
149185
test_type: str,
150186
hypervisor: str,
151187
only: Optional[List[str]],
152188
skip: Optional[List[str]],
189+
cli_test_type: Optional[str] = None,
190+
only_test_prefixes: Optional[List[str]] = None,
153191
) -> Dict[str, Any]:
154192
"""Prepare subtests and skip arguments."""
155-
subtests = self._list_subtests(hypervisor, test_type)
193+
subtests = self._list_subtests(hypervisor, cli_test_type or test_type)
156194
# Store the ordered list for diagnostic purposes
157195
self._ordered_subtests = subtests.copy()
158196

197+
if only_test_prefixes is not None:
198+
prefixed_subtests = [
199+
subtest
200+
for subtest in subtests
201+
if any(subtest.startswith(prefix) for prefix in only_test_prefixes)
202+
]
203+
if not prefixed_subtests:
204+
fail(
205+
f"No Cloud Hypervisor {test_type} subtests matched prefixes "
206+
f"{only_test_prefixes}. Verify the selected Cloud Hypervisor "
207+
"ref contains those integration tests."
208+
)
209+
if only is None:
210+
only = prefixed_subtests
211+
else:
212+
only = [subtest for subtest in only if subtest in prefixed_subtests]
213+
159214
if only is not None:
160215
if not skip:
161216
skip = []
@@ -409,16 +464,46 @@ def run_tests(
409464
ref: str = "",
410465
only: Optional[List[str]] = None,
411466
skip: Optional[List[str]] = None,
467+
cli_test_type: Optional[str] = None,
468+
only_test_prefixes: Optional[List[str]] = None,
469+
cli_test_filter: Optional[str] = None,
412470
) -> None:
471+
cli_test_type = cli_test_type or test_type
472+
413473
if ref:
414474
self.node.tools[Git].checkout(ref, self.repo_root)
415475

416-
subtests = self._prepare_subtests(test_type, hypervisor, only, skip)
476+
if cli_test_filter:
477+
subtests: Dict[str, Any] = {"subtest_set": set(), "skip_args": ""}
478+
else:
479+
subtests = self._prepare_subtests(
480+
test_type,
481+
hypervisor,
482+
only,
483+
skip,
484+
cli_test_type,
485+
only_test_prefixes,
486+
)
417487
self._configure_environment_if_needed(hypervisor)
418488

419489
# Use enhanced diagnostics for better debugging and monitoring
420490
skip_args = subtests["skip_args"]
421-
cmd_args = f"tests --hypervisor {hypervisor} --{test_type} -- -- {skip_args}"
491+
if cli_test_filter:
492+
nextest_filter = self._build_nextest_filterset(
493+
cli_test_filter,
494+
only,
495+
skip,
496+
)
497+
test_script_args = f"--test-filter {self._quote_bash_arg(nextest_filter)}"
498+
cmd_args = (
499+
f"tests --hypervisor {hypervisor} --{cli_test_type} -- "
500+
f"{test_script_args}"
501+
)
502+
else:
503+
cmd_args = (
504+
f"tests --hypervisor {hypervisor} --{cli_test_type} -- -- "
505+
f"{skip_args}"
506+
)
422507
# normalize name so artifacts are predictable (no spaces/colons/slashes)
423508
safe_test_type = self._sanitize_name(test_type.replace("-", "_"))
424509
test_name = self._sanitize_name(f"ch_{safe_test_type}_{hypervisor}")
@@ -1379,8 +1464,8 @@ def _cache_vmm_version(self) -> None:
13791464
except Exception as e:
13801465
self._log.debug(f"Could not cache VMM version: {e}")
13811466

1382-
def _list_subtests(self, hypervisor: str, test_type: str) -> List[str]:
1383-
cmd_args = f"tests --hypervisor {hypervisor} --{test_type} -- -- --list"
1467+
def _list_subtests(self, hypervisor: str, cli_test_type: str) -> List[str]:
1468+
cmd_args = f"tests --hypervisor {hypervisor} --{cli_test_type} -- -- --list"
13841469
# Use enhanced environment variables for consistency
13851470
enhanced_env_vars = self.env_vars.copy()
13861471
enhanced_env_vars.update(

0 commit comments

Comments
 (0)