The Gaudi Framework  v32r2 (46d42edc)
GaudiTest.XMLResultStream Class Reference
Inheritance diagram for GaudiTest.XMLResultStream:
Collaboration diagram for GaudiTest.XMLResultStream:

Public Member Functions

def __init__ (self, arguments=None, **args)
 
def WriteAnnotation (self, key, value)
 
def WriteResult (self, result)
 
def Summarize (self)
 

Static Public Attributes

list arguments
 

Private Attributes

 _xmlFile
 
 _startTime
 
 _endTime
 
 _tree
 
 _site
 
 _Testing
 
 _StartDateTime
 
 _StartTestTime
 
 _TestList
 
 _EndDateTime
 
 _EndTestTime
 
 _ElapsedMinutes
 

Detailed Description

An 'XMLResultStream' writes its output to a Ctest XML file.

The argument 'dir' is used to select the destination file for the XML
report.
The destination directory may already contain the report from a previous run
(for example of a different package), in which case it will be overrided to
with the new data.

Definition at line 2097 of file GaudiTest.py.

Constructor & Destructor Documentation

◆ __init__()

def GaudiTest.XMLResultStream.__init__ (   self,
  arguments = None,
**  args 
)
Prepare the destination directory.

Creates the destination directory and store in it some preliminary
annotations .

Definition at line 2124 of file GaudiTest.py.

2124  def __init__(self, arguments=None, **args):
2125  """Prepare the destination directory.
2126 
2127  Creates the destination directory and store in it some preliminary
2128  annotations .
2129  """
2130  ResultStream.__init__(self, arguments, **args)
2131 
2132  self._xmlFile = os.path.join(self.dir, self.prefix + 'Test.xml')
2133 
2134  # add some global variable
2135  self._startTime = None
2136  self._endTime = None
2137  # Format the XML file if it not exists
2138  if not os.path.isfile(self._xmlFile):
2139  # check that the container directory exists and create it if not
2140  if not os.path.exists(os.path.dirname(self._xmlFile)):
2141  os.makedirs(os.path.dirname(self._xmlFile))
2142 
2143  newdataset = ET.Element("newdataset")
2144  self._tree = ET.ElementTree(newdataset)
2145  self._tree.write(self._xmlFile)
2146  else:
2147  # Read the xml file
2148  self._tree = ET.parse(self._xmlFile)
2149  newdataset = self._tree.getroot()
2150 
2151  # Find the corresponding site, if do not exist, create it
2152 
2153  #site = newdataset.find('Site[@BuildStamp="'+result["qmtest.start_time"]+'"][@OSPlatform="'+os.getenv("CMTOPT")+'"]')
2154  # I don't know why this syntax doesn't work. Maybe it is because of the python version. Indeed,
2155  # This works well in the python terminal. So I have to make a for:
2156  for site in newdataset.getiterator():
2157  # and site.get("BuildStamp") == result["qmtest.start_time"] and:
2158  if site.get("OSPlatform") == os.uname()[4]:
2159  # Here we can add some variable to define the difference beetween 2 site
2160  self._site = site
2161  break
2162  else:
2163  site = None
2164 
2165  if site is None:
2166  import socket
2167  import multiprocessing
2168  attrib = {
2169  "BuildName": os.getenv("CMTCONFIG"),
2170  "Name": os.uname()[1],
2171  "Generator": "QMTest " + qm.version,
2172  "OSName": os.uname()[0],
2173  "Hostname": socket.gethostname(),
2174  "OSRelease": os.uname()[2],
2175  "OSVersion": os.uname()[3],
2176  "OSPlatform": os.uname()[4],
2177  "Is64Bits": "unknown",
2178  "VendorString": "unknown",
2179  "VendorID": "unknown",
2180  "FamilyID": "unknown",
2181  "ModelID": "unknown",
2182  "ProcessorCacheSize": "unknown",
2183  "NumberOfLogicalCPU": str(multiprocessing.cpu_count()),
2184  "NumberOfPhysicalCPU": "0",
2185  "TotalVirtualMemory": "0",
2186  "TotalPhysicalMemory": "0",
2187  "LogicalProcessorsPerPhysical": "0",
2188  "ProcessorClockFrequency": "0",
2189  }
2190  self._site = ET.SubElement(newdataset, "Site", attrib)
2191  self._Testing = ET.SubElement(self._site, "Testing")
2192 
2193  # Start time elements
2194  self._StartDateTime = ET.SubElement(self._Testing, "StartDateTime")
2195 
2196  self._StartTestTime = ET.SubElement(self._Testing, "StartTestTime")
2197 
2198  self._TestList = ET.SubElement(self._Testing, "TestList")
2199 
2200  # End time elements
2201  self._EndDateTime = ET.SubElement(self._Testing, "EndDateTime")
2202 
2203  self._EndTestTime = ET.SubElement(self._Testing, "EndTestTime")
2204 
2205  self._ElapsedMinutes = ET.SubElement(self._Testing,
2206  "ElapsedMinutes")
2207 
2208  else: # We get the elements
2209  self._Testing = self._site.find("Testing")
2210  self._StartDateTime = self._Testing.find("StartDateTime")
2211  self._StartTestTime = self._Testing.find("StartTestTime")
2212  self._TestList = self._Testing.find("TestList")
2213  self._EndDateTime = self._Testing.find("EndDateTime")
2214  self._EndTestTime = self._Testing.find("EndTestTime")
2215  self._ElapsedMinutes = self._Testing.find("ElapsedMinutes")
2216  """
2217  # Add some non-QMTest attributes
2218  if "CMTCONFIG" in os.environ:
2219  self.WriteAnnotation("cmt.cmtconfig", os.environ["CMTCONFIG"])
2220  import socket
2221  self.WriteAnnotation("hostname", socket.gethostname())
2222  """
2223 

Member Function Documentation

◆ Summarize()

def GaudiTest.XMLResultStream.Summarize (   self)

Definition at line 2385 of file GaudiTest.py.

2385  def Summarize(self):
2386 
2387  # Set the final end date time
2388  self._EndTestTime.text = str(self._endTime)
2389  self._EndDateTime.text = time.strftime("%b %d %H:%M %Z",
2390  time.localtime(self._endTime))
2391 
2392  # Compute the total duration
2393  if self._endTime and self._startTime:
2394  delta = self._endTime - self._startTime
2395  else:
2396  delta = 0
2397  self._ElapsedMinutes.text = str(delta / 60)
2398 
2399  # Write into the file
2400  # ,True) in python 2.7 to add the xml header
2401  self._tree.write(self._xmlFile, "utf-8")

◆ WriteAnnotation()

def GaudiTest.XMLResultStream.WriteAnnotation (   self,
  key,
  value 
)

Definition at line 2224 of file GaudiTest.py.

2224  def WriteAnnotation(self, key, value):
2225  if key == "qmtest.run.start_time":
2226  if self._site.get("qmtest.run.start_time") is not None:
2227  return None
2228  self._site.set(str(key), str(value))
2229 
auto get(const Handle &handle, const Algo &, const EventContext &) -> decltype(details::deref(handle.get()))

◆ WriteResult()

def GaudiTest.XMLResultStream.WriteResult (   self,
  result 
)
Prepare the test result directory in the destination directory storing
into it the result fields.
A summary of the test result is stored both in a file in the test directory
and in the global summary file.

Definition at line 2230 of file GaudiTest.py.

2230  def WriteResult(self, result):
2231  """Prepare the test result directory in the destination directory storing
2232  into it the result fields.
2233  A summary of the test result is stored both in a file in the test directory
2234  and in the global summary file.
2235  """
2236  summary = {}
2237  summary["id"] = result.GetId()
2238  summary["outcome"] = result.GetOutcome()
2239  summary["cause"] = result.GetCause()
2240  summary["fields"] = result.keys()
2241  summary["fields"].sort()
2242 
2243  # Since we miss proper JSON support, I hack a bit
2244  for f in ["id", "outcome", "cause"]:
2245  summary[f] = str(summary[f])
2246  summary["fields"] = map(str, summary["fields"])
2247 
2248  # format
2249  # package_Test.xml
2250 
2251  if "qmtest.start_time" in summary["fields"]:
2252  haveStartDate = True
2253  else:
2254  haveStartDate = False
2255  if "qmtest.end_time" in summary["fields"]:
2256  haveEndDate = True
2257  else:
2258  haveEndDate = False
2259 
2260  # writing the start date time
2261  if haveStartDate:
2262  self._startTime = calendar.timegm(
2263  time.strptime(result["qmtest.start_time"],
2264  "%Y-%m-%dT%H:%M:%SZ"))
2265  if self._StartTestTime.text is None:
2266  self._StartDateTime.text = time.strftime(
2267  "%b %d %H:%M %Z", time.localtime(self._startTime))
2268  self._StartTestTime.text = str(self._startTime)
2269  self._site.set("BuildStamp", result["qmtest.start_time"])
2270 
2271  # Save the end date time in memory
2272  if haveEndDate:
2273  self._endTime = calendar.timegm(
2274  time.strptime(result["qmtest.end_time"], "%Y-%m-%dT%H:%M:%SZ"))
2275 
2276  # add the current test to the test list
2277  tl = ET.Element("Test")
2278  tl.text = summary["id"]
2279  self._TestList.insert(0, tl)
2280 
2281  # Fill the current test
2282  Test = ET.Element("Test")
2283  if summary["outcome"] == "PASS":
2284  Test.set("Status", "passed")
2285  elif summary["outcome"] == "FAIL":
2286  Test.set("Status", "failed")
2287  elif summary["outcome"] == "SKIPPED" or summary[
2288  "outcome"] == "UNTESTED":
2289  Test.set("Status", "skipped")
2290  elif summary["outcome"] == "ERROR":
2291  Test.set("Status", "failed")
2292  Name = ET.SubElement(
2293  Test,
2294  "Name",
2295  )
2296  Name.text = summary["id"]
2297  Results = ET.SubElement(Test, "Results")
2298 
2299  # add the test after the other test
2300  self._Testing.insert(3, Test)
2301 
2302  if haveStartDate and haveEndDate:
2303  # Compute the test duration
2304  delta = self._endTime - self._startTime
2305  testduration = str(delta)
2306  Testduration = ET.SubElement(Results, "NamedMeasurement")
2307  Testduration.set("name", "Execution Time")
2308  Testduration.set("type", "numeric/float")
2309  value = ET.SubElement(Testduration, "Value")
2310  value.text = testduration
2311 
2312  # remove the fields that we store in a different way
2313  for n in ("qmtest.end_time", "qmtest.start_time", "qmtest.cause",
2314  "ExecTest.stdout"):
2315  if n in summary["fields"]:
2316  summary["fields"].remove(n)
2317 
2318  # Here we can add some NamedMeasurment which we know the type
2319  #
2320  if "ExecTest.exit_code" in summary["fields"]:
2321  summary["fields"].remove("ExecTest.exit_code")
2322  ExitCode = ET.SubElement(Results, "NamedMeasurement")
2323  ExitCode.set("name", "exit_code")
2324  ExitCode.set("type", "numeric/integer")
2325  value = ET.SubElement(ExitCode, "Value")
2326  value.text = convert_xml_illegal_chars(
2327  result["ExecTest.exit_code"])
2328 
2329  TestStartTime = ET.SubElement(Results, "NamedMeasurement")
2330  TestStartTime.set("name", "Start_Time")
2331  TestStartTime.set("type", "String")
2332  value = ET.SubElement(TestStartTime, "Value")
2333  if haveStartDate:
2334  value.text = escape_xml_illegal_chars(
2335  time.strftime("%b %d %H:%M %Z %Y",
2336  time.localtime(self._startTime)))
2337  else:
2338  value.text = ""
2339 
2340  TestEndTime = ET.SubElement(Results, "NamedMeasurement")
2341  TestEndTime.set("name", "End_Time")
2342  TestEndTime.set("type", "String")
2343  value = ET.SubElement(TestEndTime, "Value")
2344  if haveStartDate:
2345  value.text = escape_xml_illegal_chars(
2346  time.strftime("%b %d %H:%M %Z %Y",
2347  time.localtime(self._endTime)))
2348  else:
2349  value.text = ""
2350 
2351  if summary["cause"]:
2352  FailureCause = ET.SubElement(Results, "NamedMeasurement")
2353  FailureCause.set("name", "Cause")
2354  FailureCause.set("type", "String")
2355  value = ET.SubElement(FailureCause, "Value")
2356  value.text = escape_xml_illegal_chars(summary["cause"])
2357 
2358  # Fill the result
2359  fields = {}
2360  for field in summary["fields"]:
2361  fields[field] = ET.SubElement(Results, "NamedMeasurement")
2362  fields[field].set("type", "String")
2363  fields[field].set("name", field)
2364  value = ET.SubElement(fields[field], "Value")
2365  # to escape the <pre></pre>
2366  if "<pre>" in result[field][0:6]:
2367  value.text = convert_xml_illegal_chars(result[field][5:-6])
2368  else:
2369  value.text = convert_xml_illegal_chars(result[field])
2370 
2371  if "ExecTest.stdout" in result: # "ExecTest.stdout" in result :
2372  Measurement = ET.SubElement(Results, "Measurement")
2373  value = ET.SubElement(Measurement, "Value")
2374  if "<pre>" in result["ExecTest.stdout"][0:6]:
2375  value.text = convert_xml_illegal_chars(
2376  result["ExecTest.stdout"][5:-6])
2377  else:
2378  value.text = convert_xml_illegal_chars(
2379  result["ExecTest.stdout"])
2380 
2381  # write the file
2382  # ,True) in python 2.7 to add the xml header
2383  self._tree.write(self._xmlFile, "utf-8")
2384 
def escape_xml_illegal_chars(val, replacement='?')
Definition: GaudiTest.py:369
struct GAUDI_API map
Parametrisation class for map-like implementation.
def convert_xml_illegal_chars(val)
Definition: GaudiTest.py:365
constexpr struct ranges::Gaudi::Functional::details::insert_t insert

Member Data Documentation

◆ _ElapsedMinutes

GaudiTest.XMLResultStream._ElapsedMinutes
private

Definition at line 2205 of file GaudiTest.py.

◆ _EndDateTime

GaudiTest.XMLResultStream._EndDateTime
private

Definition at line 2201 of file GaudiTest.py.

◆ _EndTestTime

GaudiTest.XMLResultStream._EndTestTime
private

Definition at line 2203 of file GaudiTest.py.

◆ _endTime

GaudiTest.XMLResultStream._endTime
private

Definition at line 2136 of file GaudiTest.py.

◆ _site

GaudiTest.XMLResultStream._site
private

Definition at line 2160 of file GaudiTest.py.

◆ _StartDateTime

GaudiTest.XMLResultStream._StartDateTime
private

Definition at line 2194 of file GaudiTest.py.

◆ _StartTestTime

GaudiTest.XMLResultStream._StartTestTime
private

Definition at line 2196 of file GaudiTest.py.

◆ _startTime

GaudiTest.XMLResultStream._startTime
private

Definition at line 2135 of file GaudiTest.py.

◆ _Testing

GaudiTest.XMLResultStream._Testing
private

Definition at line 2191 of file GaudiTest.py.

◆ _TestList

GaudiTest.XMLResultStream._TestList
private

Definition at line 2198 of file GaudiTest.py.

◆ _tree

GaudiTest.XMLResultStream._tree
private

Definition at line 2144 of file GaudiTest.py.

◆ _xmlFile

GaudiTest.XMLResultStream._xmlFile
private

Definition at line 2132 of file GaudiTest.py.

◆ arguments

list GaudiTest.XMLResultStream.arguments
static
Initial value:
= [
qm.fields.TextField(
name="dir",
title="Destination Directory",
description=,
verbatim="true",
default_value=""),
qm.fields.TextField(
name="prefix",
title="Output File Prefix",
description=,
verbatim="true",
default_value=""),
]

Definition at line 2106 of file GaudiTest.py.


The documentation for this class was generated from the following file: