]> git.proxmox.com Git - mirror_edk2.git/blob - .pytool/Plugin/HostUnitTestCompilerPlugin/HostUnitTestCompilerPlugin.py
.pytool: Add CI support for host based unit tests with results
[mirror_edk2.git] / .pytool / Plugin / HostUnitTestCompilerPlugin / HostUnitTestCompilerPlugin.py
1 # @file HostUnitTestCompilerPlugin.py
2 ##
3 # Copyright (c) Microsoft Corporation.
4 # SPDX-License-Identifier: BSD-2-Clause-Patent
5 ##
6
7 import logging
8 import os
9 import re
10 from edk2toollib.uefi.edk2.parsers.dsc_parser import DscParser
11 from edk2toolext.environment.plugintypes.ci_build_plugin import ICiBuildPlugin
12 from edk2toolext.environment.uefi_build import UefiBuilder
13 from edk2toolext import edk2_logging
14 from edk2toolext.environment.var_dict import VarDict
15 from edk2toollib.utility_functions import GetHostInfo
16
17
18 class HostUnitTestCompilerPlugin(ICiBuildPlugin):
19 """
20 A CiBuildPlugin that compiles the dsc for host based unit test apps.
21 An IUefiBuildPlugin may be attached to this plugin that will run the
22 unit tests and collect the results after successful compilation.
23
24 Configuration options:
25 "HostUnitTestCompilerPlugin": {
26 "DscPath": "<path to dsc from root of pkg>"
27 }
28 """
29
30 def GetTestName(self, packagename: str, environment: VarDict) -> tuple:
31 """ Provide the testcase name and classname for use in reporting
32 testclassname: a descriptive string for the testcase can include whitespace
33 classname: should be patterned <packagename>.<plugin>.<optionally any unique condition>
34
35 Args:
36 packagename: string containing name of package to build
37 environment: The VarDict for the test to run in
38 Returns:
39 a tuple containing the testcase name and the classname
40 (testcasename, classname)
41 """
42 num,types = self.__GetHostUnitTestArch(environment)
43 types = types.replace(" ", "_")
44
45 return ("Compile and Run Host-Based UnitTests for " + packagename + " on arch " + types,
46 packagename + ".HostUnitTestCompiler." + types)
47
48 def RunsOnTargetList(self):
49 return ["NOOPT"]
50
51 #
52 # Find the intersection of application types that can run on this host
53 # and the TARGET_ARCH being build in this request.
54 #
55 # return tuple with (number of UEFI arch types, space separated string)
56 def __GetHostUnitTestArch(self, environment):
57 requested = environment.GetValue("TARGET_ARCH").split(' ')
58 host = []
59 if GetHostInfo().arch == 'x86':
60 #assume 64bit can handle 64 and 32
61 #assume 32bit can only handle 32
62 ## change once IA32 issues resolved host.append("IA32")
63 if GetHostInfo().bit == '64':
64 host.append("X64")
65 elif GetHostInfo().arch == 'ARM':
66 if GetHostInfo().bit == '64':
67 host.append("AARCH64")
68 elif GetHostInfo().bit == '32':
69 host.append("ARM")
70
71 willrun = set(requested) & set(host)
72 return (len(willrun), " ".join(willrun))
73
74
75 ##
76 # External function of plugin. This function is used to perform the task of the ICiBuildPlugin Plugin
77 #
78 # - package is the edk2 path to package. This means workspace/packagepath relative.
79 # - edk2path object configured with workspace and packages path
80 # - PkgConfig Object (dict) for the pkg
81 # - EnvConfig Object
82 # - Plugin Manager Instance
83 # - Plugin Helper Obj Instance
84 # - Junit Logger
85 # - output_stream the StringIO output stream from this plugin via logging
86 def RunBuildPlugin(self, packagename, Edk2pathObj, pkgconfig, environment, PLM, PLMHelper, tc, output_stream=None):
87 self._env = environment
88 environment.SetValue("CI_BUILD_TYPE", "host_unit_test", "Set in HostUnitTestCompilerPlugin")
89
90 # Parse the config for required DscPath element
91 if "DscPath" not in pkgconfig:
92 tc.SetSkipped()
93 tc.LogStdError("DscPath not found in config file. Nothing to compile for HostBasedUnitTests.")
94 return -1
95
96 AP = Edk2pathObj.GetAbsolutePathOnThisSytemFromEdk2RelativePath(packagename)
97
98 APDSC = os.path.join(AP, pkgconfig["DscPath"].strip())
99 AP_Path = Edk2pathObj.GetEdk2RelativePathFromAbsolutePath(APDSC)
100 if AP is None or AP_Path is None or not os.path.isfile(APDSC):
101 tc.SetSkipped()
102 tc.LogStdError("Package HostBasedUnitTest Dsc not found.")
103 return -1
104
105 logging.info("Building {0}".format(AP_Path))
106 self._env.SetValue("ACTIVE_PLATFORM", AP_Path, "Set in Compiler Plugin")
107 num, RUNNABLE_ARCHITECTURES = self.__GetHostUnitTestArch(environment)
108 if(num == 0):
109 tc.SetSkipped()
110 tc.LogStdError("No host architecture compatibility")
111 return -1
112
113 if not environment.SetValue("TARGET_ARCH",
114 RUNNABLE_ARCHITECTURES,
115 "Update Target Arch based on Host Support"):
116 #use AllowOverride function since this is a controlled attempt to change
117 environment.AllowOverride("TARGET_ARCH")
118 if not environment.SetValue("TARGET_ARCH",
119 RUNNABLE_ARCHITECTURES,
120 "Update Target Arch based on Host Support"):
121 raise RuntimeError("Can't Change TARGET_ARCH as required")
122
123 # Parse DSC to check for SUPPORTED_ARCHITECTURES
124 dp = DscParser()
125 dp.SetBaseAbsPath(Edk2pathObj.WorkspacePath)
126 dp.SetPackagePaths(Edk2pathObj.PackagePathList)
127 dp.ParseFile(AP_Path)
128 if "SUPPORTED_ARCHITECTURES" in dp.LocalVars:
129 SUPPORTED_ARCHITECTURES = dp.LocalVars["SUPPORTED_ARCHITECTURES"].split('|')
130 TARGET_ARCHITECTURES = environment.GetValue("TARGET_ARCH").split(' ')
131
132 # Skip if there is no intersection between SUPPORTED_ARCHITECTURES and TARGET_ARCHITECTURES
133 if len(set(SUPPORTED_ARCHITECTURES) & set(TARGET_ARCHITECTURES)) == 0:
134 tc.SetSkipped()
135 tc.LogStdError("No supported architecutres to build for host unit tests")
136 return -1
137
138 uefiBuilder = UefiBuilder()
139 # do all the steps
140 # WorkSpace, PackagesPath, PInHelper, PInManager
141 ret = uefiBuilder.Go(Edk2pathObj.WorkspacePath, os.pathsep.join(Edk2pathObj.PackagePathList), PLMHelper, PLM)
142 if ret != 0: # failure:
143 tc.SetFailed("Compile failed for {0}".format(packagename), "Compile_FAILED")
144 tc.LogStdError("{0} Compile failed with error code {1} ".format(AP_Path, ret))
145 return 1
146
147 else:
148 tc.SetSuccess()
149 return 0