mirror of
https://github.com/chipsec/chipsec
synced 2026-06-08 13:31:00 +00:00
c377a72e28
* merge * Add Debian packaging * cleanup * Removed incorrect info into Copyright. * One more: removed incorrect info in Copyright.
419 lines
15 KiB
Python
419 lines
15 KiB
Python
#!/usr/bin/python
|
|
#CHIPSEC: Platform Security Assessment Framework
|
|
#Copyright (c) 2010-2015, Intel Corporation
|
|
#
|
|
#This program is free software; you can redistribute it and/or
|
|
#modify it under the terms of the GNU General Public License
|
|
#as published by the Free Software Foundation; Version 2.
|
|
#
|
|
#This program is distributed in the hope that it will be useful,
|
|
#but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
#MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
#GNU General Public License for more details.
|
|
#
|
|
#You should have received a copy of the GNU General Public License
|
|
#along with this program; if not, write to the Free Software
|
|
#Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
|
#
|
|
#Contact information:
|
|
#chipsec@intel.com
|
|
#
|
|
|
|
|
|
|
|
import time
|
|
import sys
|
|
import traceback
|
|
import os
|
|
from os.path import basename
|
|
|
|
import xml.etree.ElementTree as ET
|
|
import platform
|
|
import xml.dom.minidom
|
|
|
|
|
|
class xmlAux:
|
|
"""Used to represent the variables to handle the xml output."""
|
|
def __init__(self):
|
|
"""The Constructor."""
|
|
self.test_cases = []
|
|
self.useXML = False
|
|
self.testCase = None
|
|
self.class_name = None
|
|
self.xmlFile = None
|
|
self.xmlStdout = ""
|
|
self.xmlStderr = None
|
|
self.properties = []
|
|
|
|
def add_test_suite_property(self, name, value):
|
|
"""Adds a <property> child node to the <testsuite>."""
|
|
if name is not None and value is not None:
|
|
self.properties.append( ts_property( str(name).strip(), str(value).strip() ) )
|
|
|
|
def set_xml_file(self, name):
|
|
"""Sets the filename used for the XML output."""
|
|
if name != None:
|
|
self.useXML = True
|
|
self.xmlFile = name
|
|
|
|
def append_stdout(self,msg):
|
|
self.xmlStdout += str(msg) + "\n"
|
|
|
|
def _check_testCase_exist(self):
|
|
if self.testCase is None:
|
|
if self.class_name is None:
|
|
self.testCase = xmlTestCase( "test name", "class.name" )
|
|
else:
|
|
self.testCase = xmlTestCase( self.class_name, self.class_name )
|
|
|
|
def _end_test(self):
|
|
try:
|
|
self.testCase.set_time()
|
|
self.testCase.add_stdout_info( self.xmlStdout )
|
|
self.test_cases.append( self.testCase )
|
|
self.testCase = None
|
|
except:
|
|
print "Unexpected error:", sys.exc_info() [0]
|
|
raise
|
|
|
|
def passed_check(self):
|
|
"""Used when you want to mark a testcase as PASS and add it to the testsuite."""
|
|
if self.useXML == True:
|
|
self._check_testCase_exist()
|
|
self._end_test()
|
|
|
|
def failed_check(self, text):
|
|
"""Used when you want to mark a testcase as FAILURE and add it to the testsuite."""
|
|
if self.useXML == True:
|
|
self._check_testCase_exist()
|
|
self.testCase.add_failure_info( text, None )
|
|
self._end_test()
|
|
|
|
def error_check(self, text):
|
|
"""Used when you want to mark a testcase as ERROR and add it to the testsuite."""
|
|
if self.useXML == True:
|
|
self._check_testCase_exist()
|
|
self.testCase.add_error_info( text, None )
|
|
self._end_test()
|
|
|
|
def skipped_check(self, text):
|
|
"""Used when you want to mark a testcase as SKIPPED and add it to the testsuite."""
|
|
if self.useXML == True:
|
|
self._check_testCase_exist()
|
|
self.testCase.add_skipped_info( text, None )
|
|
self._end_test()
|
|
|
|
def start_test(self, test_name):
|
|
"""Starts the test/testcase."""
|
|
self.xmlStdout = ""
|
|
if self.useXML == True:
|
|
self.testCase = xmlTestCase( test_name, self.class_name )
|
|
|
|
def start_module( self, module_name ):
|
|
"""Logs the start point of a Test, this is used for XML output.
|
|
If XML file was not specified, it will just display a banner for the test name.
|
|
"""
|
|
if self.useXML == True:
|
|
self.class_name = module_name
|
|
if self.testCase is not None:
|
|
#If there's a test that did not send a status, so mark it as passed.
|
|
self.passed_check( )
|
|
self.xmlStdout = ""
|
|
|
|
def end_module( self, module_name ):
|
|
if self.useXML == True:
|
|
self.class_name = ""
|
|
if self.testCase is not None:
|
|
#If there's a test that did not send a status, so mark it as passed.
|
|
self.passed_check( )
|
|
self.xmlStdout = ""
|
|
|
|
def saveXML( self ):
|
|
"""Saves the XML info to a file in a JUnit style."""
|
|
if not self.useXML or self.xmlFile is None: return False
|
|
filename = self.xmlFile.replace("'", "")
|
|
ts = xmlTestSuite( basename( os.path.splitext(filename)[0] ) )
|
|
ts.test_cases = self.test_cases
|
|
if self.properties is not None and len( self.properties ) > 0: ts.properties = self.properties
|
|
ts.to_file( filename )
|
|
print "[CHIPSEC] Saving output to XML file: %s" % str( os.path.abspath( filename ) )
|
|
return True
|
|
|
|
class testCaseType:
|
|
"""Used to represent the types of TestCase that can be assigned (FAILURE, ERROR, SKIPPED, PASS)"""
|
|
FAILURE = 1
|
|
ERROR = 2
|
|
SKIPPED = 3
|
|
PASS = 4
|
|
|
|
class xmlTestCase():
|
|
"""Represents a JUnit test case with a result and possibly some stdout or stderr"""
|
|
|
|
def __init__(self, name, classname, pTime=None, stdout=None, stderr=None, tcType=None, message=None, output=None):
|
|
"""The Constructor"""
|
|
self.name = name
|
|
self.time = None
|
|
self.startTime = time.time()
|
|
self.endTime = None
|
|
if pTime is not None:
|
|
self.time = pTime
|
|
self.stdout = stdout
|
|
self.stderr = stderr
|
|
self.classname = classname
|
|
self.tcType = tcType
|
|
self.tcMessage = message
|
|
self.tcOutput = output
|
|
#Just to be compatible with junit_xml
|
|
self.error_message = ""
|
|
self.error_output = ""
|
|
self.failure_message = ""
|
|
self.failure_output = ""
|
|
self.skipped_message = ""
|
|
self.skipped_output = ""
|
|
|
|
if tcType == testCaseType.ERROR:
|
|
self.error_message = message
|
|
self.error_output = output
|
|
elif tcType == testCaseType.FAILURE:
|
|
self.failure_message = message
|
|
self.failure_output = output
|
|
elif tcType == testCaseType.SKIPPED:
|
|
self.skipped_message = message
|
|
self.skipped_output = output
|
|
else:
|
|
#Then it should be PASSED.
|
|
self.tcType = testCaseType.PASS
|
|
|
|
def is_skipped(self):
|
|
"""Returns True if the testCase is of Type Skipped, if not returns False"""
|
|
if self.tcType == testCaseType.SKIPPED:
|
|
return True
|
|
else:
|
|
False
|
|
|
|
def is_error(self):
|
|
"""Returns True if the testCase is of Type Error, if not returns False"""
|
|
if self.tcType == testCaseType.ERROR:
|
|
return True
|
|
else:
|
|
False
|
|
|
|
def is_failure(self):
|
|
"""Returns True if the testCase is of Type Failure, if not returns False"""
|
|
if self.tcType == testCaseType.FAILURE:
|
|
return True
|
|
else:
|
|
False
|
|
|
|
def is_pass(self):
|
|
"""Returns True if the testCase is of Type Pass, if not returns False."""
|
|
if self.tcType not in [testCaseType.ERROR, testCaseType.FAILURE, testCaseType.SKIPPED] or self.tcType == testCaseType.PASS:
|
|
return True
|
|
else:
|
|
False
|
|
|
|
def add_failure_info(self, message=None, output=None):
|
|
"""Sets the values for the corresponding Type Failure."""
|
|
self.tcType = testCaseType.FAILURE
|
|
self.tcMessage = message
|
|
self.tcOutput = output
|
|
#To be compatible with junit_xml
|
|
self.failure_message = message
|
|
self.failure_output = output
|
|
|
|
def add_error_info(self, message=None, output=None):
|
|
"""Sets the values for the corresponding Type Error."""
|
|
self.tcType = testCaseType.ERROR
|
|
self.tcMessage = message
|
|
self.tcOutput = output
|
|
#To be compatible with junit_xml
|
|
self.error_message = message
|
|
self.error_output = output
|
|
|
|
def add_skipped_info(self, message=None, output=None):
|
|
"""Sets the values for the corresponding Type Skipped."""
|
|
self.tcType = testCaseType.SKIPPED
|
|
self.tcMessage = message
|
|
self.tcOutput = output
|
|
#To be compatible with junit_xml
|
|
self.skipped_message = message
|
|
self.skipped_output = output
|
|
|
|
def add_stdout_info(self, text):
|
|
"""Adds the text that is going to be part of the stdout for the TestCase."""
|
|
if self.stdout is not None:
|
|
self.stdout += str(text)
|
|
else:
|
|
self.stdout = str(text)
|
|
|
|
def add_stderr_info(self, text):
|
|
"""Adds the text that is going to be part of the stderr for the TestCase."""
|
|
if self.stderr is not None:
|
|
self.stderr += str(text)
|
|
else:
|
|
self.stderr = str(text)
|
|
|
|
def set_time(self, pTime=None):
|
|
"""Sets the time"""
|
|
if pTime is not None:
|
|
self.time = pTime
|
|
else:
|
|
self.endTime = time.time()
|
|
self.time = self.endTime - self.startTime
|
|
|
|
|
|
class xmlTestSuite(object):
|
|
"""Suite of test cases, it's the father node for TestCase."""
|
|
|
|
def __init__(self, name, test_cases=None, hostname=None, ts_id=None, package=None, timestamp=None, properties=None):
|
|
"""The Constructor."""
|
|
self.name = name
|
|
if not test_cases:
|
|
test_cases = []
|
|
self.test_cases = test_cases
|
|
self.hostname = hostname
|
|
self.ts_id = ts_id
|
|
self.package = package
|
|
self.timestamp = timestamp
|
|
self.properties = properties
|
|
|
|
def to_xml_string(self):
|
|
"""Returns the string representation of the JUnit XML document."""
|
|
try:
|
|
iter( self.test_cases )
|
|
except TypeError:
|
|
raise Exception('test_suite has no test cases')
|
|
|
|
strXML = TestSuite.to_xml_string( TestSuite(self.name, self.test_cases,
|
|
self.hostname, self.ts_id, self.package,
|
|
self.timestamp, self.properties)
|
|
)
|
|
return strXML
|
|
|
|
def to_file(self, file_name):
|
|
"""Writes the JUnit XML document to a file.
|
|
In case of any error, it will print the exception information.
|
|
"""
|
|
with open( file_name, 'wb') as f :
|
|
#f.write( '<?xml-stylesheet type="text/xsl" href="junit.xsl"?>' )
|
|
f.write( self.to_xml_string() )
|
|
|
|
|
|
class ts_property(object):
|
|
"""Class to represent a TestSuite property."""
|
|
def __init__(self, name, value):
|
|
"""The constructor."""
|
|
self.name = name
|
|
self.value = value
|
|
|
|
|
|
class TestSuite(object):
|
|
"""Suite of test cases"""
|
|
|
|
def __init__(self, name, test_cases, hostname, ts_id, package, timestamp, properties):
|
|
self.name = name
|
|
if not test_cases:
|
|
test_cases = []
|
|
try:
|
|
iter( test_cases )
|
|
except:
|
|
pass
|
|
self.test_cases = test_cases
|
|
self.hostname = hostname
|
|
self.ts_id = ts_id
|
|
self.package = package
|
|
self.timestamp = timestamp
|
|
if not properties:
|
|
self.properties = []
|
|
else:
|
|
self.properties = properties
|
|
|
|
|
|
def build_xml(self):
|
|
"""Builds the XML elements."""
|
|
ts_attributes = dict()
|
|
if self.name:
|
|
ts_attributes["name"] = str( self.name )
|
|
else:
|
|
ts_attributes["name"] = "name"
|
|
if self.hostname:
|
|
ts_attributes["hostname"] = str( self.hostname )
|
|
if self.ts_id:
|
|
ts_attributes["id"] = str( self.ts_id )
|
|
if self.package:
|
|
ts_attributes["package"] = str( self.package )
|
|
if self.timestamp:
|
|
ts_attributes["timestamp"] = str( self.timestamp )
|
|
|
|
ts_attributes['failures'] = str( len( [tc for tc in self.test_cases if tc.is_failure()] ) )
|
|
ts_attributes['errors'] = str( len( [tc for tc in self.test_cases if tc.is_error()] ) )
|
|
ts_attributes['skipped'] = str( len( [tc for tc in self.test_cases if tc.is_skipped()] ) )
|
|
#ts_attributes["time"] = str( sum( [tc.time for tc in self.test_cases if tc.time] ) )
|
|
ts_attributes["time"] = "%.5f" % sum( [tc.time for tc in self.test_cases if tc.time] )
|
|
ts_attributes["tests"] = str( len( self.test_cases ) )
|
|
|
|
xml_element = ET.Element( "testsuite", ts_attributes )
|
|
|
|
if len(self.properties) > 0:
|
|
ps_element = ET.SubElement( xml_element, "properties" )
|
|
temp = dict()
|
|
for p in self.properties:
|
|
temp["name"] = p.name
|
|
temp["value"] = p.value
|
|
py_element = ET.SubElement( ps_element, "property", temp )
|
|
|
|
for tc in self.test_cases:
|
|
tc_attributes = dict()
|
|
tc_attributes['name'] = str( tc.name )
|
|
if tc.time:
|
|
tc_attributes['time'] = "%.5f" % tc.time
|
|
if tc.classname:
|
|
tc_attributes['classname'] = str( tc.classname )
|
|
|
|
tc_element = ET.SubElement( xml_element, "testcase", tc_attributes )
|
|
|
|
#For the is_pass() case, just log a 'pass' tag.
|
|
if tc.is_pass():
|
|
pass_element = ET.SubElement( tc_element, "pass", {'type':'pass'} )
|
|
elif tc.is_failure():
|
|
failure_element = ET.SubElement( tc_element, "failure", {'type': 'failure'} )
|
|
if tc.failure_message:
|
|
failure_element.set( 'message', tc.failure_message )
|
|
if tc.failure_output:
|
|
failure_element.text = tc.failure_output
|
|
elif tc.is_error():
|
|
error_element = ET.SubElement( tc_element, "error", {'type': 'error'} )
|
|
if tc.error_message:
|
|
error_element.set( 'message', tc.error_message )
|
|
if tc.error_output:
|
|
error_element.text = tc.error_output
|
|
elif tc.is_skipped():
|
|
skipped_element = ET.SubElement( tc_element, "skipped", {'type': 'skipped'} )
|
|
if tc.skipped_message:
|
|
skipped_element.set( 'message', tc.skipped_message )
|
|
if tc.skipped_output:
|
|
skipped_element.text = tc.skipped_output
|
|
|
|
#system-out and system-err are common for all, so here we go.
|
|
if tc.stdout:
|
|
stdout_element = ET.SubElement( tc_element, "system-out" )
|
|
stdout_element.text = tc.stdout
|
|
if tc.stderr:
|
|
stderr_element = ET.SubElement( tc_element, "system-err" )
|
|
stderr_element.text = tc.stderr
|
|
|
|
return xml_element
|
|
|
|
|
|
def to_xml_string(self):
|
|
"""Returns a string representation of the XML Tree for the TestSuite."""
|
|
xml_element = ET.Element("testsuites")
|
|
xml_element2 = self.build_xml()
|
|
xml_element.append( xml_element2 )
|
|
xml_string = ET.tostring( xml_element, None, None )
|
|
|
|
if platform.system().lower() in ["windows", "linux"]:
|
|
xml_string = xml.dom.minidom.parseString(xml_string).toprettyxml()
|
|
|
|
return xml_string
|