mirror of https://github.com/acidanthera/audk.git
.pytool: Add CI support for host based unit tests with results
https://bugzilla.tianocore.org/show_bug.cgi?id=2505 * Add plugin to build and run host based unit tests * Add plugin that performs a DSC complete check DSC files used to build host based tests * Update DscCompleteCheck plugin to ignore module INFs with a MODULE_TYPE of HOST_APPLICATION and library INFs that only support a module type of HOST_APPLICATION. * Fix issues in XML reports from checkers. Cc: Sean Brogan <sean.brogan@microsoft.com> Cc: Bret Barkelew <Bret.Barkelew@microsoft.com> Cc: Liming Gao <liming.gao@intel.com> Signed-off-by: Michael D Kinney <michael.d.kinney@intel.com> Reviewed-by: Bret Barkelew <Bret.Barkelew@microsoft.com>
This commit is contained in:
parent
bd33a385ee
commit
61364ab927
|
@ -48,7 +48,8 @@ class Settings(CiBuildSettingsManager, UpdateSettingsManager, SetupSettingsManag
|
|||
"FmpDevicePkg",
|
||||
"ShellPkg",
|
||||
"FatPkg",
|
||||
"CryptoPkg"
|
||||
"CryptoPkg",
|
||||
"UnitTestFrameworkPkg"
|
||||
)
|
||||
|
||||
def GetArchitecturesSupported(self):
|
||||
|
@ -117,10 +118,13 @@ class Settings(CiBuildSettingsManager, UpdateSettingsManager, SetupSettingsManag
|
|||
|
||||
def GetActiveScopes(self):
|
||||
''' return tuple containing scopes that should be active for this process '''
|
||||
scopes = ("cibuild","edk2-build")
|
||||
scopes = ("cibuild", "edk2-build", "host-based-test")
|
||||
|
||||
self.ActualToolChainTag = shell_environment.GetBuildVars().GetValue("TOOL_CHAIN_TAG", "")
|
||||
|
||||
if GetHostInfo().os.upper() == "WINDOWS":
|
||||
scopes += ('host-test-win',)
|
||||
|
||||
if GetHostInfo().os.upper() == "LINUX" and self.ActualToolChainTag.upper().startswith("GCC"):
|
||||
if "AARCH64" in self.ActualArchitectures:
|
||||
scopes += ("gcc_aarch64_linux",)
|
||||
|
@ -133,18 +137,21 @@ class Settings(CiBuildSettingsManager, UpdateSettingsManager, SetupSettingsManag
|
|||
''' return iterable containing RequiredSubmodule objects.
|
||||
If no RequiredSubmodules return an empty iterable
|
||||
'''
|
||||
rs=[]
|
||||
rs = []
|
||||
rs.append(RequiredSubmodule(
|
||||
"ArmPkg/Library/ArmSoftFloatLib/berkeley-softfloat-3", False))
|
||||
rs.append(RequiredSubmodule(
|
||||
"CryptoPkg/Library/OpensslLib/openssl", False))
|
||||
rs.append(RequiredSubmodule(
|
||||
"UnitTestFrameworkPkg/Library/CmockaLib/cmocka", False))
|
||||
return rs
|
||||
|
||||
def GetName(self):
|
||||
return "Edk2"
|
||||
|
||||
def GetDependencies(self):
|
||||
return []
|
||||
return [
|
||||
]
|
||||
|
||||
def GetPackagesPath(self):
|
||||
return ()
|
||||
|
@ -155,10 +162,11 @@ class Settings(CiBuildSettingsManager, UpdateSettingsManager, SetupSettingsManag
|
|||
|
||||
def FilterPackagesToTest(self, changedFilesList: list, potentialPackagesList: list) -> list:
|
||||
''' Filter potential packages to test based on changed files. '''
|
||||
build_these_packages=[]
|
||||
possible_packages=potentialPackagesList.copy()
|
||||
build_these_packages = []
|
||||
possible_packages = potentialPackagesList.copy()
|
||||
for f in changedFilesList:
|
||||
nodes=f.split("/") # split each part of path for comparison later
|
||||
# split each part of path for comparison later
|
||||
nodes = f.split("/")
|
||||
|
||||
# python file change in .pytool folder causes building all
|
||||
if f.endswith(".py") and ".pytool" in nodes:
|
||||
|
|
|
@ -100,7 +100,7 @@ class CharEncodingCheck(ICiBuildPlugin):
|
|||
overall_status += 1
|
||||
|
||||
tc.LogStdOut("Tested Encoding on {0} files".format(files_tested))
|
||||
if overall_status is not 0:
|
||||
if overall_status != 0:
|
||||
tc.SetFailed("CharEncoding {0} Failed. Errors {1}".format(packagename, overall_status), "CHAR_ENCODING_CHECK_FAILED")
|
||||
else:
|
||||
tc.SetSuccess()
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
# @file HostUnitTestCompiler_plugin.py
|
||||
# @file CompilerPlugin.py
|
||||
##
|
||||
# Copyright (c) Microsoft Corporation.
|
||||
# SPDX-License-Identifier: BSD-2-Clause-Patent
|
||||
|
@ -42,7 +42,7 @@ class CompilerPlugin(ICiBuildPlugin):
|
|||
return ["DEBUG", "RELEASE"]
|
||||
|
||||
##
|
||||
# External function of plugin. This function is used to perform the task of the MuBuild Plugin
|
||||
# External function of plugin. This function is used to perform the task of the ICiBuildPlugin Plugin
|
||||
#
|
||||
# - package is the edk2 path to package. This means workspace/packagepath relative.
|
||||
# - edk2path object configured with workspace and packages path
|
||||
|
|
|
@ -113,7 +113,7 @@ class DependencyCheck(ICiBuildPlugin):
|
|||
overall_status += 1
|
||||
|
||||
# If XML object exists, add results
|
||||
if overall_status is not 0:
|
||||
if overall_status != 0:
|
||||
tc.SetFailed("Failed with {0} errors".format(overall_status), "DEPENDENCYCHECK_FAILED")
|
||||
else:
|
||||
tc.SetSuccess()
|
||||
|
|
|
@ -54,12 +54,15 @@ class DscCompleteCheck(ICiBuildPlugin):
|
|||
# Parse the config for required DscPath element
|
||||
if "DscPath" not in pkgconfig:
|
||||
tc.SetSkipped()
|
||||
tc.LogStdError("DscPath not found in config file. Nothing to check.")
|
||||
tc.LogStdError(
|
||||
"DscPath not found in config file. Nothing to check.")
|
||||
return -1
|
||||
|
||||
abs_pkg_path = Edk2pathObj.GetAbsolutePathOnThisSytemFromEdk2RelativePath(packagename)
|
||||
abs_pkg_path = Edk2pathObj.GetAbsolutePathOnThisSytemFromEdk2RelativePath(
|
||||
packagename)
|
||||
abs_dsc_path = os.path.join(abs_pkg_path, pkgconfig["DscPath"].strip())
|
||||
wsr_dsc_path = Edk2pathObj.GetEdk2RelativePathFromAbsolutePath(abs_dsc_path)
|
||||
wsr_dsc_path = Edk2pathObj.GetEdk2RelativePathFromAbsolutePath(
|
||||
abs_dsc_path)
|
||||
|
||||
if abs_dsc_path is None or wsr_dsc_path == "" or not os.path.isfile(abs_dsc_path):
|
||||
tc.SetSkipped()
|
||||
|
@ -68,7 +71,8 @@ class DscCompleteCheck(ICiBuildPlugin):
|
|||
|
||||
# Get INF Files
|
||||
INFFiles = self.WalkDirectoryForExtension([".inf"], abs_pkg_path)
|
||||
INFFiles = [Edk2pathObj.GetEdk2RelativePathFromAbsolutePath(x) for x in INFFiles] # make edk2relative path so can compare with DSC
|
||||
INFFiles = [Edk2pathObj.GetEdk2RelativePathFromAbsolutePath(
|
||||
x) for x in INFFiles] # make edk2relative path so can compare with DSC
|
||||
|
||||
# remove ignores
|
||||
|
||||
|
@ -79,8 +83,10 @@ class DscCompleteCheck(ICiBuildPlugin):
|
|||
tc.LogStdOut("Ignoring INF {0}".format(a))
|
||||
INFFiles.remove(a)
|
||||
except:
|
||||
tc.LogStdError("DscCompleteCheck.IgnoreInf -> {0} not found in filesystem. Invalid ignore file".format(a))
|
||||
logging.info("DscCompleteCheck.IgnoreInf -> {0} not found in filesystem. Invalid ignore file".format(a))
|
||||
tc.LogStdError(
|
||||
"DscCompleteCheck.IgnoreInf -> {0} not found in filesystem. Invalid ignore file".format(a))
|
||||
logging.info(
|
||||
"DscCompleteCheck.IgnoreInf -> {0} not found in filesystem. Invalid ignore file".format(a))
|
||||
|
||||
# DSC Parser
|
||||
dp = DscParser()
|
||||
|
@ -99,11 +105,19 @@ class DscCompleteCheck(ICiBuildPlugin):
|
|||
infp.SetPackagePaths(Edk2pathObj.PackagePathList)
|
||||
infp.ParseFile(INF)
|
||||
if("MODULE_TYPE" not in infp.Dict):
|
||||
tc.LogStdOut("Ignoring INF. Missing key for MODULE_TYPE {0}".format(INF))
|
||||
tc.LogStdOut(
|
||||
"Ignoring INF. Missing key for MODULE_TYPE {0}".format(INF))
|
||||
continue
|
||||
|
||||
if(infp.Dict["MODULE_TYPE"] == "HOST_APPLICATION"):
|
||||
tc.LogStdOut("Ignoring INF. Module type is HOST_APPLICATION {0}".format(INF))
|
||||
tc.LogStdOut(
|
||||
"Ignoring INF. Module type is HOST_APPLICATION {0}".format(INF))
|
||||
continue
|
||||
|
||||
if len(infp.SupportedPhases) == 1 and \
|
||||
"HOST_APPLICATION" in infp.SupportedPhases:
|
||||
tc.LogStdOut(
|
||||
"Ignoring Library INF due to only supporting type HOST_APPLICATION {0}".format(INF))
|
||||
continue
|
||||
|
||||
logging.critical(INF + " not in " + wsr_dsc_path)
|
||||
|
@ -111,8 +125,9 @@ class DscCompleteCheck(ICiBuildPlugin):
|
|||
overall_status = overall_status + 1
|
||||
|
||||
# If XML object exists, add result
|
||||
if overall_status is not 0:
|
||||
tc.SetFailed("DscCompleteCheck {0} Failed. Errors {1}".format(wsr_dsc_path, overall_status), "CHECK_FAILED")
|
||||
if overall_status != 0:
|
||||
tc.SetFailed("DscCompleteCheck {0} Failed. Errors {1}".format(
|
||||
wsr_dsc_path, overall_status), "CHECK_FAILED")
|
||||
else:
|
||||
tc.SetSuccess()
|
||||
return overall_status
|
||||
|
|
|
@ -7,6 +7,11 @@ that it would not be built if the package were built). This is critical because
|
|||
much of the CI infrastructure assumes that all modules will be listed in the DSC
|
||||
and compiled.
|
||||
|
||||
This test will ignore INFs in the following cases:
|
||||
|
||||
1. When MODULE_TYPE = HOST_APPLICATION
|
||||
2. When a Library instance **only** supports the HOST_APPLICATION environment
|
||||
|
||||
## Configuration
|
||||
|
||||
The plugin has a few configuration options to support the UEFI codebase.
|
||||
|
@ -14,7 +19,7 @@ The plugin has a few configuration options to support the UEFI codebase.
|
|||
``` yaml
|
||||
"DscCompleteCheck": {
|
||||
"DscPath": "", # Path to dsc from root of package
|
||||
"IgnoreInf": [] # Ignore INF if found in filesystem by not dsc
|
||||
"IgnoreInf": [] # Ignore INF if found in filesystem but not dsc
|
||||
}
|
||||
```
|
||||
|
||||
|
|
|
@ -221,7 +221,7 @@ class GuidCheck(ICiBuildPlugin):
|
|||
|
||||
# add result to test case
|
||||
overall_status = len(Errors)
|
||||
if overall_status is not 0:
|
||||
if overall_status != 0:
|
||||
tc.SetFailed("GuidCheck {0} Failed. Errors {1}".format(
|
||||
packagename, overall_status), "CHECK_FAILED")
|
||||
else:
|
||||
|
|
|
@ -0,0 +1,149 @@
|
|||
# @file HostUnitTestCompilerPlugin.py
|
||||
##
|
||||
# Copyright (c) Microsoft Corporation.
|
||||
# SPDX-License-Identifier: BSD-2-Clause-Patent
|
||||
##
|
||||
|
||||
import logging
|
||||
import os
|
||||
import re
|
||||
from edk2toollib.uefi.edk2.parsers.dsc_parser import DscParser
|
||||
from edk2toolext.environment.plugintypes.ci_build_plugin import ICiBuildPlugin
|
||||
from edk2toolext.environment.uefi_build import UefiBuilder
|
||||
from edk2toolext import edk2_logging
|
||||
from edk2toolext.environment.var_dict import VarDict
|
||||
from edk2toollib.utility_functions import GetHostInfo
|
||||
|
||||
|
||||
class HostUnitTestCompilerPlugin(ICiBuildPlugin):
|
||||
"""
|
||||
A CiBuildPlugin that compiles the dsc for host based unit test apps.
|
||||
An IUefiBuildPlugin may be attached to this plugin that will run the
|
||||
unit tests and collect the results after successful compilation.
|
||||
|
||||
Configuration options:
|
||||
"HostUnitTestCompilerPlugin": {
|
||||
"DscPath": "<path to dsc from root of pkg>"
|
||||
}
|
||||
"""
|
||||
|
||||
def GetTestName(self, packagename: str, environment: VarDict) -> tuple:
|
||||
""" Provide the testcase name and classname for use in reporting
|
||||
testclassname: a descriptive string for the testcase can include whitespace
|
||||
classname: should be patterned <packagename>.<plugin>.<optionally any unique condition>
|
||||
|
||||
Args:
|
||||
packagename: string containing name of package to build
|
||||
environment: The VarDict for the test to run in
|
||||
Returns:
|
||||
a tuple containing the testcase name and the classname
|
||||
(testcasename, classname)
|
||||
"""
|
||||
num,types = self.__GetHostUnitTestArch(environment)
|
||||
types = types.replace(" ", "_")
|
||||
|
||||
return ("Compile and Run Host-Based UnitTests for " + packagename + " on arch " + types,
|
||||
packagename + ".HostUnitTestCompiler." + types)
|
||||
|
||||
def RunsOnTargetList(self):
|
||||
return ["NOOPT"]
|
||||
|
||||
#
|
||||
# Find the intersection of application types that can run on this host
|
||||
# and the TARGET_ARCH being build in this request.
|
||||
#
|
||||
# return tuple with (number of UEFI arch types, space separated string)
|
||||
def __GetHostUnitTestArch(self, environment):
|
||||
requested = environment.GetValue("TARGET_ARCH").split(' ')
|
||||
host = []
|
||||
if GetHostInfo().arch == 'x86':
|
||||
#assume 64bit can handle 64 and 32
|
||||
#assume 32bit can only handle 32
|
||||
## change once IA32 issues resolved host.append("IA32")
|
||||
if GetHostInfo().bit == '64':
|
||||
host.append("X64")
|
||||
elif GetHostInfo().arch == 'ARM':
|
||||
if GetHostInfo().bit == '64':
|
||||
host.append("AARCH64")
|
||||
elif GetHostInfo().bit == '32':
|
||||
host.append("ARM")
|
||||
|
||||
willrun = set(requested) & set(host)
|
||||
return (len(willrun), " ".join(willrun))
|
||||
|
||||
|
||||
##
|
||||
# External function of plugin. This function is used to perform the task of the ICiBuildPlugin Plugin
|
||||
#
|
||||
# - package is the edk2 path to package. This means workspace/packagepath relative.
|
||||
# - edk2path object configured with workspace and packages path
|
||||
# - PkgConfig Object (dict) for the pkg
|
||||
# - EnvConfig Object
|
||||
# - Plugin Manager Instance
|
||||
# - Plugin Helper Obj Instance
|
||||
# - Junit Logger
|
||||
# - output_stream the StringIO output stream from this plugin via logging
|
||||
def RunBuildPlugin(self, packagename, Edk2pathObj, pkgconfig, environment, PLM, PLMHelper, tc, output_stream=None):
|
||||
self._env = environment
|
||||
environment.SetValue("CI_BUILD_TYPE", "host_unit_test", "Set in HostUnitTestCompilerPlugin")
|
||||
|
||||
# Parse the config for required DscPath element
|
||||
if "DscPath" not in pkgconfig:
|
||||
tc.SetSkipped()
|
||||
tc.LogStdError("DscPath not found in config file. Nothing to compile for HostBasedUnitTests.")
|
||||
return -1
|
||||
|
||||
AP = Edk2pathObj.GetAbsolutePathOnThisSytemFromEdk2RelativePath(packagename)
|
||||
|
||||
APDSC = os.path.join(AP, pkgconfig["DscPath"].strip())
|
||||
AP_Path = Edk2pathObj.GetEdk2RelativePathFromAbsolutePath(APDSC)
|
||||
if AP is None or AP_Path is None or not os.path.isfile(APDSC):
|
||||
tc.SetSkipped()
|
||||
tc.LogStdError("Package HostBasedUnitTest Dsc not found.")
|
||||
return -1
|
||||
|
||||
logging.info("Building {0}".format(AP_Path))
|
||||
self._env.SetValue("ACTIVE_PLATFORM", AP_Path, "Set in Compiler Plugin")
|
||||
num, RUNNABLE_ARCHITECTURES = self.__GetHostUnitTestArch(environment)
|
||||
if(num == 0):
|
||||
tc.SetSkipped()
|
||||
tc.LogStdError("No host architecture compatibility")
|
||||
return -1
|
||||
|
||||
if not environment.SetValue("TARGET_ARCH",
|
||||
RUNNABLE_ARCHITECTURES,
|
||||
"Update Target Arch based on Host Support"):
|
||||
#use AllowOverride function since this is a controlled attempt to change
|
||||
environment.AllowOverride("TARGET_ARCH")
|
||||
if not environment.SetValue("TARGET_ARCH",
|
||||
RUNNABLE_ARCHITECTURES,
|
||||
"Update Target Arch based on Host Support"):
|
||||
raise RuntimeError("Can't Change TARGET_ARCH as required")
|
||||
|
||||
# Parse DSC to check for SUPPORTED_ARCHITECTURES
|
||||
dp = DscParser()
|
||||
dp.SetBaseAbsPath(Edk2pathObj.WorkspacePath)
|
||||
dp.SetPackagePaths(Edk2pathObj.PackagePathList)
|
||||
dp.ParseFile(AP_Path)
|
||||
if "SUPPORTED_ARCHITECTURES" in dp.LocalVars:
|
||||
SUPPORTED_ARCHITECTURES = dp.LocalVars["SUPPORTED_ARCHITECTURES"].split('|')
|
||||
TARGET_ARCHITECTURES = environment.GetValue("TARGET_ARCH").split(' ')
|
||||
|
||||
# Skip if there is no intersection between SUPPORTED_ARCHITECTURES and TARGET_ARCHITECTURES
|
||||
if len(set(SUPPORTED_ARCHITECTURES) & set(TARGET_ARCHITECTURES)) == 0:
|
||||
tc.SetSkipped()
|
||||
tc.LogStdError("No supported architecutres to build for host unit tests")
|
||||
return -1
|
||||
|
||||
uefiBuilder = UefiBuilder()
|
||||
# do all the steps
|
||||
# WorkSpace, PackagesPath, PInHelper, PInManager
|
||||
ret = uefiBuilder.Go(Edk2pathObj.WorkspacePath, os.pathsep.join(Edk2pathObj.PackagePathList), PLMHelper, PLM)
|
||||
if ret != 0: # failure:
|
||||
tc.SetFailed("Compile failed for {0}".format(packagename), "Compile_FAILED")
|
||||
tc.LogStdError("{0} Compile failed with error code {1} ".format(AP_Path, ret))
|
||||
return 1
|
||||
|
||||
else:
|
||||
tc.SetSuccess()
|
||||
return 0
|
|
@ -0,0 +1,12 @@
|
|||
##
|
||||
# CiBuildPlugin used to build anything that identifies
|
||||
# as a unit test.
|
||||
#
|
||||
# Copyright (c) Microsoft Corporation.
|
||||
# SPDX-License-Identifier: BSD-2-Clause-Patent
|
||||
##
|
||||
{
|
||||
"scope": "host-based-test",
|
||||
"name": "Host Unit Test Compiler Plugin",
|
||||
"module": "HostUnitTestCompilerPlugin"
|
||||
}
|
|
@ -0,0 +1,24 @@
|
|||
# Host UnitTest Compiler Plugin
|
||||
|
||||
A CiBuildPlugin that compiles the dsc for host based unit test apps.
|
||||
An IUefiBuildPlugin may be attached to this plugin that will run the unit tests and collect the results after successful compilation.
|
||||
|
||||
## Configuration
|
||||
|
||||
The package relative path of the DSC file to build.
|
||||
|
||||
``` yaml
|
||||
"HostUnitTestCompilerPlugin": {
|
||||
"DscPath": "<path to dsc from root of pkg>"
|
||||
}
|
||||
```
|
||||
|
||||
### DscPath
|
||||
|
||||
Package relative path to the DSC file to build.
|
||||
|
||||
## Copyright
|
||||
|
||||
Copyright (c) Microsoft Corporation.
|
||||
SPDX-License-Identifier: BSD-2-Clause-Patent
|
||||
|
|
@ -0,0 +1,140 @@
|
|||
# @file HostUnitTestDscCompleteCheck.py
|
||||
#
|
||||
# This is a copy of DscCompleteCheck with different filtering logic.
|
||||
# It should be discussed if this should be one plugin
|
||||
#
|
||||
# Copyright (c) Microsoft Corporation.
|
||||
# SPDX-License-Identifier: BSD-2-Clause-Patent
|
||||
##
|
||||
import logging
|
||||
import os
|
||||
from edk2toolext.environment.plugintypes.ci_build_plugin import ICiBuildPlugin
|
||||
from edk2toollib.uefi.edk2.parsers.dsc_parser import DscParser
|
||||
from edk2toollib.uefi.edk2.parsers.inf_parser import InfParser
|
||||
from edk2toolext.environment.var_dict import VarDict
|
||||
|
||||
|
||||
class HostUnitTestDscCompleteCheck(ICiBuildPlugin):
|
||||
"""
|
||||
A CiBuildPlugin that scans the package Host Unit Test dsc file and confirms all Host application modules (inf files) are
|
||||
listed in the components sections.
|
||||
|
||||
Configuration options:
|
||||
"HostUnitTestDscCompleteCheck": {
|
||||
"DscPath": "", # Path to Host based unit test DSC file
|
||||
"IgnoreInf": [] # Ignore INF if found in filesystem but not dsc
|
||||
}
|
||||
"""
|
||||
|
||||
def GetTestName(self, packagename: str, environment: VarDict) -> tuple:
|
||||
""" Provide the testcase name and classname for use in reporting
|
||||
|
||||
Args:
|
||||
packagename: string containing name of package to build
|
||||
environment: The VarDict for the test to run in
|
||||
Returns:
|
||||
a tuple containing the testcase name and the classname
|
||||
(testcasename, classname)
|
||||
testclassname: a descriptive string for the testcase can include whitespace
|
||||
classname: should be patterned <packagename>.<plugin>.<optionally any unique condition>
|
||||
"""
|
||||
return ("Check the " + packagename + " Host Unit Test DSC for a being complete", packagename + ".HostUnitTestDscCompleteCheck")
|
||||
|
||||
##
|
||||
# External function of plugin. This function is used to perform the task of the MuBuild Plugin
|
||||
#
|
||||
# - package is the edk2 path to package. This means workspace/packagepath relative.
|
||||
# - edk2path object configured with workspace and packages path
|
||||
# - PkgConfig Object (dict) for the pkg
|
||||
# - VarDict containing the shell environment Build Vars
|
||||
# - Plugin Manager Instance
|
||||
# - Plugin Helper Obj Instance
|
||||
# - Junit Logger
|
||||
# - output_stream the StringIO output stream from this plugin via logging
|
||||
def RunBuildPlugin(self, packagename, Edk2pathObj, pkgconfig, environment, PLM, PLMHelper, tc, output_stream=None):
|
||||
overall_status = 0
|
||||
|
||||
# Parse the config for required DscPath element
|
||||
if "DscPath" not in pkgconfig:
|
||||
tc.SetSkipped()
|
||||
tc.LogStdError(
|
||||
"DscPath not found in config file. Nothing to check.")
|
||||
return -1
|
||||
|
||||
abs_pkg_path = Edk2pathObj.GetAbsolutePathOnThisSytemFromEdk2RelativePath(
|
||||
packagename)
|
||||
abs_dsc_path = os.path.join(abs_pkg_path, pkgconfig["DscPath"].strip())
|
||||
wsr_dsc_path = Edk2pathObj.GetEdk2RelativePathFromAbsolutePath(
|
||||
abs_dsc_path)
|
||||
|
||||
if abs_dsc_path is None or wsr_dsc_path == "" or not os.path.isfile(abs_dsc_path):
|
||||
tc.SetSkipped()
|
||||
tc.LogStdError("Package Host Unit Test Dsc not found")
|
||||
return 0
|
||||
|
||||
# Get INF Files
|
||||
INFFiles = self.WalkDirectoryForExtension([".inf"], abs_pkg_path)
|
||||
INFFiles = [Edk2pathObj.GetEdk2RelativePathFromAbsolutePath(
|
||||
x) for x in INFFiles] # make edk2relative path so can compare with DSC
|
||||
|
||||
# remove ignores
|
||||
|
||||
if "IgnoreInf" in pkgconfig:
|
||||
for a in pkgconfig["IgnoreInf"]:
|
||||
a = a.replace(os.sep, "/")
|
||||
try:
|
||||
tc.LogStdOut("Ignoring INF {0}".format(a))
|
||||
INFFiles.remove(a)
|
||||
except:
|
||||
tc.LogStdError(
|
||||
"HostUnitTestDscCompleteCheck.IgnoreInf -> {0} not found in filesystem. Invalid ignore file".format(a))
|
||||
logging.info(
|
||||
"HostUnitTestDscCompleteCheck.IgnoreInf -> {0} not found in filesystem. Invalid ignore file".format(a))
|
||||
|
||||
# DSC Parser
|
||||
dp = DscParser()
|
||||
dp.SetBaseAbsPath(Edk2pathObj.WorkspacePath)
|
||||
dp.SetPackagePaths(Edk2pathObj.PackagePathList)
|
||||
dp.SetInputVars(environment.GetAllBuildKeyValues())
|
||||
dp.ParseFile(wsr_dsc_path)
|
||||
|
||||
# Check if INF in component section
|
||||
for INF in INFFiles:
|
||||
if not any(INF.strip() in x for x in dp.ThreeMods) and \
|
||||
not any(INF.strip() in x for x in dp.SixMods) and \
|
||||
not any(INF.strip() in x for x in dp.OtherMods):
|
||||
|
||||
infp = InfParser().SetBaseAbsPath(Edk2pathObj.WorkspacePath)
|
||||
infp.SetPackagePaths(Edk2pathObj.PackagePathList)
|
||||
infp.ParseFile(INF)
|
||||
if("MODULE_TYPE" not in infp.Dict):
|
||||
tc.LogStdOut(
|
||||
"Ignoring INF. Missing key for MODULE_TYPE {0}".format(INF))
|
||||
continue
|
||||
|
||||
if(infp.Dict["MODULE_TYPE"] == "HOST_APPLICATION"):
|
||||
# should compile test a library that is declared type HOST_APPLICATION
|
||||
pass
|
||||
|
||||
elif len(infp.SupportedPhases) > 0 and \
|
||||
"HOST_APPLICATION" in infp.SupportedPhases:
|
||||
# should compile test a library that supports HOST_APPLICATION but
|
||||
# require it to be an explicit opt-in
|
||||
pass
|
||||
|
||||
else:
|
||||
tc.LogStdOut(
|
||||
"Ignoring INF. MODULE_TYPE or suppored phases not HOST_APPLICATION {0}".format(INF))
|
||||
continue
|
||||
|
||||
logging.critical(INF + " not in " + wsr_dsc_path)
|
||||
tc.LogStdError("{0} not in {1}".format(INF, wsr_dsc_path))
|
||||
overall_status = overall_status + 1
|
||||
|
||||
# If XML object exists, add result
|
||||
if overall_status != 0:
|
||||
tc.SetFailed("HostUnitTestDscCompleteCheck {0} Failed. Errors {1}".format(
|
||||
wsr_dsc_path, overall_status), "CHECK_FAILED")
|
||||
else:
|
||||
tc.SetSuccess()
|
||||
return overall_status
|
|
@ -0,0 +1,12 @@
|
|||
##
|
||||
# CiBuildPlugin used to confirm all INFs are listed in
|
||||
# the components section of package dsc
|
||||
#
|
||||
# Copyright (c) Microsoft Corporation.
|
||||
# SPDX-License-Identifier: BSD-2-Clause-Patent
|
||||
##
|
||||
{
|
||||
"scope": "host-based-test",
|
||||
"name": "Host Unit Test Dsc Complete Check Test",
|
||||
"module": "HostUnitTestDscCompleteCheck"
|
||||
}
|
|
@ -0,0 +1,32 @@
|
|||
# Host Unit Test Dsc Complete Check Plugin
|
||||
|
||||
This CiBuildPlugin scans all INF files from a package for those related to host
|
||||
based unit tests confirms they are listed in the unit test DSC file for the package.
|
||||
The test considers it an error if any INF meeting the requirements does not appear
|
||||
in the `Components` section of the unit test DSC. This is critical because
|
||||
much of the CI infrastructure assumes that modules will be listed in the DSC
|
||||
and compiled.
|
||||
|
||||
This test will only require INFs in the following cases:
|
||||
|
||||
1. When MODULE_TYPE = HOST_APPLICATION
|
||||
2. When a Library instance supports the HOST_APPLICATION environment
|
||||
|
||||
## Configuration
|
||||
|
||||
The plugin has a few configuration options to support the UEFI codebase.
|
||||
|
||||
``` yaml
|
||||
"HostUnitTestDscCompleteCheck": {
|
||||
"DscPath": "", # Path to Host based unit test DSC file
|
||||
"IgnoreInf": [] # Ignore INF if found in filesystem but not dsc
|
||||
}
|
||||
```
|
||||
|
||||
### DscPath
|
||||
|
||||
Path to DSC to consider platform dsc
|
||||
|
||||
### IgnoreInf
|
||||
|
||||
Ignore error if Inf file is not listed in DSC file
|
|
@ -146,7 +146,7 @@ class LibraryClassCheck(ICiBuildPlugin):
|
|||
|
||||
|
||||
# If XML object exists, add result
|
||||
if overall_status is not 0:
|
||||
if overall_status != 0:
|
||||
tc.SetFailed("LibraryClassCheck {0} Failed. Errors {1}".format(wsr_dec_path, overall_status), "CHECK_FAILED")
|
||||
else:
|
||||
tc.SetSuccess()
|
||||
|
|
Loading…
Reference in New Issue