Skip to content

Commit

Permalink
.pytool/Plugin: Improve Rust support
Browse files Browse the repository at this point in the history
Makes multiple improvements to the RustHostUnitTestPlugin to support
a more reliable experience:

1. The plugin now fails when a test fails to compile or cargo tarpaulin
   fails to run.
2. The plugin now logs the reason for failing as a warning in addition
   to logging the output to the xml file.
3. The plugin now properly filters results to only include results of
   rust crates inside the package being tested.
  • Loading branch information
Javagedes committed Sep 27, 2023
1 parent 76416ab commit 7facd89
Show file tree
Hide file tree
Showing 2 changed files with 31 additions and 12 deletions.
31 changes: 23 additions & 8 deletions .pytool/Plugin/RustHostUnitTestPlugin/RustHostUnitTestPlugin.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,30 +26,39 @@ 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
# 2. Everything in a submodule
# 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
for test in results["pass"]:
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
Expand All @@ -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("/")
Expand All @@ -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
Expand Down
12 changes: 8 additions & 4 deletions .pytool/Plugin/RustPackageHelper/RustPackageHelper.py
Original file line number Diff line number Diff line change
Expand Up @@ -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()

Expand All @@ -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

Expand All @@ -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

Expand Down

0 comments on commit 7facd89

Please sign in to comment.