diff --git a/.pytool/Plugin/RustHostUnitTestPlugin/RustHostUnitTestPlugin.py b/.pytool/Plugin/RustHostUnitTestPlugin/RustHostUnitTestPlugin.py index 5357308d91e..bd62c2fd66c 100644 --- a/.pytool/Plugin/RustHostUnitTestPlugin/RustHostUnitTestPlugin.py +++ b/.pytool/Plugin/RustHostUnitTestPlugin/RustHostUnitTestPlugin.py @@ -26,9 +26,9 @@ def RunBuildPlugin(self, packagename, Edk2pathObj, pkgconfig, environment, PLM, # Build list of packages that are in the EDK2 package we are running CI on pp = Path(Edk2pathObj.GetAbsolutePathOnThisSystemFromEdk2RelativePath(packagename)) - package_name_list = [pkg.name for pkg in filter(lambda pkg: Path(pkg.path).is_relative_to(pp), rust_ws.members)] - package_path_list = [pkg.path for pkg in filter(lambda pkg: Path(pkg.path).is_relative_to(pp), rust_ws.members)] - logging.debug(f"Rust Packages to test: {' '.join(package_name_list)}") + crate_name_list = [pkg.name for pkg in filter(lambda pkg: Path(pkg.path).is_relative_to(pp), rust_ws.members)] + crate_path_list = [pkg.path for pkg in filter(lambda pkg: Path(pkg.path).is_relative_to(pp), rust_ws.members)] + logging.debug(f"Rust Crates to test: {' '.join(crate_name_list)}") # Build a list of paths to ignore when computing results. This includes: # 1. Any tests folder in a rust package @@ -36,12 +36,19 @@ def RunBuildPlugin(self, packagename, Edk2pathObj, pkgconfig, environment, PLM, # 3. Everything in an EDK2 package not being tested. ignore_list = [Path("**", "tests", "*")] ignore_list.extend([Path(s, "**", "*") for s in repo_details(ws)["Submodules"]]) - ignore_list.extend(list(set([pkg.path for pkg in rust_ws.members]) - set(package_path_list))) + ignored_local_crates = list(set(crate.path for crate in rust_ws.members) - set(crate_path_list)) + ignore_list.extend([Path(crate, "**", "*").relative_to(ws) for crate in ignored_local_crates]) ignore_list = [str(i) for i in ignore_list] logging.debug(f"Paths to ignore when computing coverage: {' '.join(ignore_list)}") # Run tests and evaluate results - results = rust_ws.coverage(package_name_list, ignore_list = ignore_list, report_type = "xml") + try: + results = rust_ws.coverage(crate_name_list, ignore_list = ignore_list, report_type = "xml") + except RuntimeError as e: + logging.warning(str(e)) + tc.LogStdError(str(e)) + tc.SetFailed(str(e), "CHECK_FAILED") + return 1 # Evaluate unit test results failed = 0 @@ -49,7 +56,9 @@ def RunBuildPlugin(self, packagename, Edk2pathObj, pkgconfig, environment, PLM, tc.LogStdOut(f'{test} ... PASS') for test in results["fail"]: - tc.LogStdError(f'{test} ... FAIL') + e = f'{test} ... FAIL' + logging.warning(e) + tc.LogStdError(e) failed += 1 # If we failed a unit test, we have no coverage data to evaluate @@ -61,7 +70,11 @@ def RunBuildPlugin(self, packagename, Edk2pathObj, pkgconfig, environment, PLM, coverage = {} for file, cov in results["coverage"].items(): try: - package = next(pkg.name for pkg in rust_ws.members if Path(ws,file).is_relative_to(pkg.path)) + package = next( + crate.name + for crate in rust_ws.members + if Path(ws, file).is_relative_to(crate.path) + ) except StopIteration: continue covered, total = cov.split("/") @@ -80,7 +93,9 @@ def RunBuildPlugin(self, packagename, Edk2pathObj, pkgconfig, environment, PLM, if calc_cov >= required_cov: tc.LogStdOut(f'coverage::{pkg}: {calc_cov} greater than {required_cov} ... PASS') else: - tc.LogStdError(f'coverage::{pkg}: {calc_cov} less than {required_cov} ... FAIL') + e = f'coverage::{pkg}: {calc_cov}% less than {required_cov}% ... FAIL' + logging.warning(e) + tc.LogStdError(e) failed += 1 # Move coverage.xml to Build Directory diff --git a/.pytool/Plugin/RustPackageHelper/RustPackageHelper.py b/.pytool/Plugin/RustPackageHelper/RustPackageHelper.py index 0b7af0c2cd5..0dfbc25bf58 100644 --- a/.pytool/Plugin/RustPackageHelper/RustPackageHelper.py +++ b/.pytool/Plugin/RustPackageHelper/RustPackageHelper.py @@ -68,14 +68,14 @@ def coverage(self, pkg_list = None, ignore_list = None, report_type: str = "html command = "cargo" params = "make" if ignore_list: - params += f' -e COV_FLAGS="--out {report_type} --exclude-files {",".join(ignore_list)}"' + params += f' -e COV_FLAGS="--out {report_type} --exclude-files {" --exclude-files ".join(ignore_list)}"' else: params += f' -e COV_FLAGS="--out {report_type}"' params += f" coverage {','.join(pkg_list)}" # Run the command output = io.StringIO() - RunCmd(command, params, workingdir=self.path, outstream=output) + return_value = RunCmd(command, params, workingdir=self.path, outstream=output) output.seek(0) lines = output.readlines() @@ -88,7 +88,7 @@ def coverage(self, pkg_list = None, ignore_list = None, report_type: str = "html # Determine passed and failed tests for line in lines: line = line.strip().strip("\n") - + if line.startswith("test result:"): continue @@ -99,7 +99,11 @@ def coverage(self, pkg_list = None, ignore_list = None, report_type: str = "html else: result["fail"].append(line.replace(" ... FAILED", "")) continue - + + # Command failed, but we didn't parse any failed tests + if return_value != 0 and len(result["fail"]) == 0: + raise RuntimeError("Failed to compile tests or run command.") + if len(result["fail"]) > 0: return result