The Gaudi Framework  v33r2 (a6f0ec87)
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 2107 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 2134 of file GaudiTest.py.

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

Member Function Documentation

◆ Summarize()

def GaudiTest.XMLResultStream.Summarize (   self)

Definition at line 2395 of file GaudiTest.py.

2395  def Summarize(self):
2396 
2397  # Set the final end date time
2398  self._EndTestTime.text = str(self._endTime)
2399  self._EndDateTime.text = time.strftime("%b %d %H:%M %Z",
2400  time.localtime(self._endTime))
2401 
2402  # Compute the total duration
2403  if self._endTime and self._startTime:
2404  delta = self._endTime - self._startTime
2405  else:
2406  delta = 0
2407  self._ElapsedMinutes.text = str(delta / 60)
2408 
2409  # Write into the file
2410  # ,True) in python 2.7 to add the xml header
2411  self._tree.write(self._xmlFile, "utf-8")

◆ WriteAnnotation()

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

Definition at line 2234 of file GaudiTest.py.

2234  def WriteAnnotation(self, key, value):
2235  if key == "qmtest.run.start_time":
2236  if self._site.get("qmtest.run.start_time") is not None:
2237  return None
2238  self._site.set(str(key), str(value))
2239 
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 2240 of file GaudiTest.py.

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

Member Data Documentation

◆ _ElapsedMinutes

GaudiTest.XMLResultStream._ElapsedMinutes
private

Definition at line 2215 of file GaudiTest.py.

◆ _EndDateTime

GaudiTest.XMLResultStream._EndDateTime
private

Definition at line 2211 of file GaudiTest.py.

◆ _EndTestTime

GaudiTest.XMLResultStream._EndTestTime
private

Definition at line 2213 of file GaudiTest.py.

◆ _endTime

GaudiTest.XMLResultStream._endTime
private

Definition at line 2146 of file GaudiTest.py.

◆ _site

GaudiTest.XMLResultStream._site
private

Definition at line 2170 of file GaudiTest.py.

◆ _StartDateTime

GaudiTest.XMLResultStream._StartDateTime
private

Definition at line 2204 of file GaudiTest.py.

◆ _StartTestTime

GaudiTest.XMLResultStream._StartTestTime
private

Definition at line 2206 of file GaudiTest.py.

◆ _startTime

GaudiTest.XMLResultStream._startTime
private

Definition at line 2145 of file GaudiTest.py.

◆ _Testing

GaudiTest.XMLResultStream._Testing
private

Definition at line 2201 of file GaudiTest.py.

◆ _TestList

GaudiTest.XMLResultStream._TestList
private

Definition at line 2208 of file GaudiTest.py.

◆ _tree

GaudiTest.XMLResultStream._tree
private

Definition at line 2154 of file GaudiTest.py.

◆ _xmlFile

GaudiTest.XMLResultStream._xmlFile
private

Definition at line 2142 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 2116 of file GaudiTest.py.


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