ExportResults.py 26 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607
  1. import xlsxwriter
  2. import logging
  3. import json
  4. import baangt.base.GlobalConstants as GC
  5. from baangt.base.Timing.Timing import Timing
  6. import sys
  7. from baangt.base.Utils import utils
  8. from pathlib import Path
  9. from typing import Optional
  10. from xlsxwriter.worksheet import (
  11. Worksheet, cell_number_tuple, cell_string_tuple)
  12. from sqlalchemy import create_engine
  13. from sqlalchemy.orm import sessionmaker
  14. from baangt.base.DataBaseORM import DATABASE_URL, TestrunLog, TestCaseLog, ExtraField
  15. from datetime import datetime
  16. import time
  17. from baangt import plugin_manager
  18. import re
  19. import csv
  20. from dateutil.parser import parse
  21. logger = logging.getLogger("pyC")
  22. class ExportResults:
  23. def __init__(self, **kwargs):
  24. self.testList = []
  25. self.testRunInstance = kwargs.get(GC.KWARGS_TESTRUNINSTANCE)
  26. self.networkInfo = kwargs.get('networkInfo')
  27. self.testCasesEndDateTimes_1D = kwargs.get('testCasesEndDateTimes_1D')
  28. self.testCasesEndDateTimes_2D = kwargs.get('testCasesEndDateTimes_2D')
  29. self.testRunName = self.testRunInstance.testRunName
  30. self.dataRecords = self.testRunInstance.dataRecords
  31. try:
  32. self.exportFormat = kwargs.get(GC.KWARGS_TESTRUNATTRIBUTES).get(GC.EXPORT_FORMAT)[GC.EXPORT_FORMAT]
  33. except KeyError:
  34. self.exportFormat = GC.EXP_XLSX
  35. self.fileName = self.__getOutputFileName()
  36. logger.info("Export-Sheet for results: " + self.fileName)
  37. if self.exportFormat == GC.EXP_XLSX:
  38. self.fieldListExport = kwargs.get(GC.KWARGS_TESTRUNATTRIBUTES).get(GC.EXPORT_FORMAT)["Fieldlist"]
  39. self.workbook = xlsxwriter.Workbook(self.fileName)
  40. self.summarySheet = self.workbook.add_worksheet("Summary")
  41. self.worksheet = self.workbook.add_worksheet("Output")
  42. self.timingSheet = self.workbook.add_worksheet("Timing")
  43. self.cellFormatGreen = self.workbook.add_format()
  44. self.cellFormatGreen.set_bg_color('green')
  45. self.cellFormatRed = self.workbook.add_format()
  46. self.cellFormatRed.set_bg_color('red')
  47. self.cellFormatBold = self.workbook.add_format()
  48. self.cellFormatBold.set_bold(bold=True)
  49. self.summaryRow = 0
  50. self.__setHeaderDetailSheetExcel()
  51. self.makeSummaryExcel()
  52. self.exportResultExcel()
  53. self.exportTiming = ExportTiming(self.dataRecords,
  54. self.timingSheet)
  55. if self.networkInfo:
  56. self.networkSheet = self.workbook.add_worksheet("Network")
  57. self.exportNetWork = ExportNetWork(self.networkInfo,
  58. self.testCasesEndDateTimes_1D,
  59. self.testCasesEndDateTimes_2D,
  60. self.workbook,
  61. self.networkSheet)
  62. self.closeExcel()
  63. elif self.exportFormat == GC.EXP_CSV:
  64. self.export2CSV()
  65. self.exportToDataBase()
  66. # -- API support --
  67. def getSummary(self):
  68. # records status
  69. summary = {'Testrecords': len(self.dataRecords)}
  70. summary['Successful'] = len([x for x in self.dataRecords.values()
  71. if x[GC.TESTCASESTATUS] == GC.TESTCASESTATUS_SUCCESS])
  72. summary['Paused'] = len([x for x in self.dataRecords.values()
  73. if x[GC.TESTCASESTATUS] == GC.TESTCASESTATUS_WAITING])
  74. summary['Error'] = len([x for x in self.dataRecords.values()
  75. if x[GC.TESTCASESTATUS] == GC.TESTCASESTATUS_ERROR])
  76. # logfile
  77. summary['Logfile'] = logger.handlers[1].baseFilename
  78. # timing
  79. timing:Timing = self.testRunInstance.timing
  80. summary['Starttime'], summary['Endtime'], summary['Duration'] = timing.returnTimeSegment(GC.TIMING_TESTRUN)
  81. summary['Globals'] = {key: value for key, value in self.testRunInstance.globalSettings.items()}
  82. return summary
  83. # -- END of API support --
  84. def export2CSV(self):
  85. """
  86. Writes CSV-File of datarecords
  87. """
  88. f = open(self.fileName, 'w')
  89. writer = csv.DictWriter(f, self.dataRecords[0].keys())
  90. writer.writeheader()
  91. for i in range(0, len(self.dataRecords)-1):
  92. writer.writerow(self.dataRecords[i])
  93. f.close()
  94. def exportToDataBase(self):
  95. engine = create_engine(f'sqlite:///{DATABASE_URL}')
  96. # create a Session
  97. Session = sessionmaker(bind=engine)
  98. session = Session()
  99. # get timings
  100. timing: Timing = self.testRunInstance.timing
  101. start, end, duration = timing.returnTimeSegment(GC.TIMING_TESTRUN)
  102. # get status
  103. success = 0
  104. error = 0
  105. waiting = 0
  106. for value in self.dataRecords.values():
  107. if value[GC.TESTCASESTATUS] == GC.TESTCASESTATUS_SUCCESS:
  108. success += 1
  109. elif value[GC.TESTCASESTATUS] == GC.TESTCASESTATUS_ERROR:
  110. error += 1
  111. if value[GC.TESTCASESTATUS] == GC.TESTCASESTATUS_WAITING:
  112. waiting += 1
  113. # get globals
  114. globalString = '{'
  115. for key, value in self.testRunInstance.globalSettings.items():
  116. if len(globalString) > 1:
  117. globalString += ', '
  118. globalString += f'{key}: {value}'
  119. globalString += '}'
  120. # get documents
  121. datafiles = self.fileName
  122. '''
  123. # create testrun object
  124. log = TestrunLog(
  125. testrunName = self.testRunName,
  126. logfileName = logger.handlers[1].baseFilename,
  127. startTime = datetime.strptime(start, "%H:%M:%S"),
  128. endTime = datetime.strptime(end, "%H:%M:%S"),
  129. statusOk = success,
  130. statusFailed = error,
  131. statusPaused = waiting,
  132. globalVars = globalString,
  133. dataFile = datafiles,
  134. )
  135. # write to DataBase
  136. session.add(log)
  137. session.commit()
  138. # create testcase objects
  139. for testcase in self.dataRecords.values():
  140. caseLog = TestCaseLog(testrun=log)
  141. for key, value in testcase.items():
  142. # check for known fields
  143. if key == 'Toasts':
  144. caseLog.toasts = value
  145. elif key == 'TCErrorLog':
  146. caseLog.tcErrorLog = value
  147. elif key == 'VIGOGF#':
  148. caseLog.vigogf = value
  149. elif key == 'SAP Polizzennr':
  150. caseLog.sapPolizzennr = value
  151. elif key == 'Prämie':
  152. caseLog.pramie = value
  153. elif key == 'PolNR Host':
  154. caseLog.polNrHost = value
  155. elif key == 'TestCaseStatus':
  156. caseLog.testCaseStatus = value
  157. elif key == 'Duration':
  158. caseLog.duration = value
  159. elif key == 'Screenshots':
  160. caseLog.screenshots = value
  161. elif key == 'timelog':
  162. caseLog.timelog = value
  163. elif key == 'exportFilesBasePath':
  164. caseLog.exportFilesBasePath = value
  165. elif key == 'TC.Lines':
  166. caseLog.tcLines = value
  167. elif key == 'TC.dontCloseBrowser':
  168. caseLog.tcDontCloseBrowser = value
  169. elif key == 'TC.BrowserAttributes':
  170. caseLog.tcBrowserAttributes = value
  171. elif key == 'TC.slowExecution':
  172. caseLog.tsSlowExecution = value
  173. elif key == 'TC.NetworkInfo':
  174. caseLog.tcNetworkInfo = value
  175. elif key == 'TX.DEBUG':
  176. caseLog.txDebug = value
  177. elif key == 'ScreenshotPath':
  178. caseLog.screenshotPath = value
  179. elif key == 'ExportPath':
  180. caseLog.exportPath = value
  181. elif key == 'ImportPath':
  182. caseLog.importPath = value
  183. elif key == 'RootPath':
  184. caseLog.rootPath = value
  185. else:
  186. # add extra field
  187. extraField = ExtraField(name=key, value=value)
  188. session.add(extraField)
  189. session.commit()
  190. caseLog.extraFields.append(extraField)
  191. # save to db
  192. session.add(caseLog)
  193. session.commit()
  194. '''
  195. def exportResultExcel(self, **kwargs):
  196. self._exportData()
  197. def makeSummaryExcel(self):
  198. self.summarySheet.write(0,0, f"Testreport for {self.testRunName}", self.cellFormatBold)
  199. self.summarySheet.set_column(0, last_col=0, width=15)
  200. # get testrunname my
  201. self.testList.append(self.testRunName)
  202. # Testrecords
  203. self.__writeSummaryCell("Testrecords", len(self.dataRecords), row=2, format=self.cellFormatBold)
  204. value = len([x for x in self.dataRecords.values()
  205. if x[GC.TESTCASESTATUS] == GC.TESTCASESTATUS_SUCCESS])
  206. self.testList.append(value) # Ok my
  207. if not value:
  208. value = ""
  209. self.__writeSummaryCell("Successful", value, format=self.cellFormatGreen)
  210. self.testList.append(value) # paused my
  211. self.__writeSummaryCell("Paused", len([x for x in self.dataRecords.values()
  212. if x[GC.TESTCASESTATUS] == GC.TESTCASESTATUS_WAITING]))
  213. value = len([x for x in self.dataRecords.values()
  214. if x[GC.TESTCASESTATUS] == GC.TESTCASESTATUS_ERROR])
  215. self.testList.append(value) # error my
  216. if not value:
  217. value = ""
  218. self.__writeSummaryCell("Error", value, format=self.cellFormatRed)
  219. # Logfile
  220. self.__writeSummaryCell("Logfile", logger.handlers[1].baseFilename, row=7)
  221. # get logfilename for database my
  222. self.testList.append(logger.handlers[1].baseFilename)
  223. # Timing
  224. timing:Timing = self.testRunInstance.timing
  225. start, end, duration = timing.returnTimeSegment(GC.TIMING_TESTRUN)
  226. self.__writeSummaryCell("Starttime", start, row=9)
  227. # get start end during time my
  228. self.testList.append(start)
  229. self.testList.append(end)
  230. self.__writeSummaryCell("Endtime", end)
  231. self.__writeSummaryCell("Duration", duration, format=self.cellFormatBold )
  232. self.__writeSummaryCell("Avg. Dur", "")
  233. # Globals:
  234. self.__writeSummaryCell("Global settings for this testrun", "", format=self.cellFormatBold, row=14)
  235. for key, value in self.testRunInstance.globalSettings.items():
  236. self.__writeSummaryCell(key, str(value))
  237. # get global data my
  238. self.testList.append(str(value))
  239. # Testcase and Testsequence setting
  240. self.__writeSummaryCell("TestSequence settings follow:", "", row=16+len(self.testRunInstance.globalSettings),
  241. format=self.cellFormatBold)
  242. lSequence = self.testRunInstance.testRunUtils.getSequenceByNumber(testRunName=self.testRunName, sequence="1")
  243. if lSequence:
  244. for key, value in lSequence[1].items():
  245. if isinstance(value, list) or isinstance(value, dict):
  246. continue
  247. self.__writeSummaryCell(key, str(value))
  248. def __writeSummaryCell(self, lineHeader, lineText, row=None, format=None):
  249. if not row:
  250. self.summaryRow += 1
  251. else:
  252. self.summaryRow = row
  253. if not lineText:
  254. # If we have no lineText we want to apply format to the Header
  255. self.summarySheet.write(self.summaryRow, 0, lineHeader, format)
  256. else:
  257. self.summarySheet.write(self.summaryRow, 0, lineHeader)
  258. self.summarySheet.write(self.summaryRow, 1, lineText, format)
  259. def __getOutputFileName(self):
  260. if self.testRunInstance.globalSettings[GC.PATH_ROOT]:
  261. basePath = Path(self.testRunInstance.globalSettings[GC.PATH_ROOT])
  262. elif "/" not in self.testRunInstance.globalSettings[GC.DATABASE_EXPORTFILENAMEANDPATH][0:1]:
  263. basePath = Path(sys.modules['__main__'].__file__).parent
  264. else:
  265. basePath = ""
  266. l_file: Path = Path(basePath).joinpath(self.testRunInstance.globalSettings[GC.DATABASE_EXPORTFILENAMEANDPATH])
  267. if "~" in str(l_file.absolute()):
  268. l_file = l_file.expanduser()
  269. if not Path(l_file).is_dir():
  270. logger.info(f"Create directory {l_file}")
  271. Path(l_file).mkdir(parents=True, exist_ok=True)
  272. if self.exportFormat == GC.EXP_XLSX:
  273. lExtension = '.xlsx'
  274. elif self.exportFormat == GC.EXP_CSV:
  275. lExtension = '.csv'
  276. else:
  277. logger.critical(f"wrong export file format: {self.exportFormat}, using 'xlsx' instead")
  278. lExtension = '.xlsx'
  279. l_file = l_file.joinpath("baangt_" + self.testRunName + "_" + utils.datetime_return() + lExtension)
  280. logger.debug(f"Filename for export: {str(l_file)}")
  281. return str(l_file)
  282. def __setHeaderDetailSheetExcel(self):
  283. i = 0
  284. self.__extendFieldList() # Add fields with name "RESULT_*" to output fields.
  285. for column in self.fieldListExport:
  286. self.worksheet.write(0, i, column)
  287. i += 1
  288. self.worksheet.write(0, len(self.fieldListExport), "JSON")
  289. def __extendFieldList(self):
  290. """
  291. Fields, that start with "RESULT_" shall always be exported.
  292. @return:
  293. """
  294. try:
  295. for key in self.dataRecords[0].keys():
  296. if "RESULT_" in key:
  297. if not key in self.fieldListExport:
  298. self.fieldListExport.append(key)
  299. except Exception as e:
  300. logger.critical(f'looks like we have no data in records: {self.dataRecords}, len of dataRecords: {len(self.dataRecords)}')
  301. def _exportData(self):
  302. for key, value in self.dataRecords.items():
  303. for (n, column) in enumerate(self.fieldListExport):
  304. self.__writeCell(key+1, n, value, column)
  305. # Also write everything as JSON-String into the last column
  306. self.worksheet.write(key+1, len(self.fieldListExport), json.dumps(value))
  307. # Create autofilter
  308. self.worksheet.autofilter(0,0,len(self.dataRecords.items()),len(self.fieldListExport)-1)
  309. # Make cells wide enough
  310. for n in range(0,len(self.fieldListExport)):
  311. ExcelSheetHelperFunctions.set_column_autowidth(self.worksheet, n)
  312. def __writeCell(self, line, cellNumber, testRecordDict, fieldName, strip=False):
  313. if fieldName in testRecordDict.keys() and testRecordDict[fieldName]:
  314. if '\n' in testRecordDict[fieldName][0:5] or strip:
  315. testRecordDict[fieldName] = testRecordDict[fieldName].strip()
  316. if isinstance(testRecordDict[fieldName], dict) or isinstance(testRecordDict[fieldName], list):
  317. self.worksheet.write(line, cellNumber, testRecordDict[fieldName].strip())
  318. else:
  319. if fieldName == GC.TESTCASESTATUS:
  320. if testRecordDict[GC.TESTCASESTATUS] == GC.TESTCASESTATUS_SUCCESS:
  321. self.worksheet.write(line, cellNumber, testRecordDict[fieldName], self.cellFormatGreen)
  322. elif testRecordDict[GC.TESTCASESTATUS] == GC.TESTCASESTATUS_ERROR:
  323. self.worksheet.write(line, cellNumber, testRecordDict[fieldName], self.cellFormatRed)
  324. else:
  325. self.worksheet.write(line, cellNumber, testRecordDict[fieldName])
  326. def closeExcel(self):
  327. self.workbook.close()
  328. # Next line doesn't work on MAC. Returns "not authorized"
  329. # subprocess.Popen([self.filename], shell=True)
  330. class ExcelSheetHelperFunctions:
  331. def __init__(self):
  332. pass
  333. @staticmethod
  334. def set_column_autowidth(worksheet: Worksheet, column: int):
  335. """
  336. Set the width automatically on a column in the `Worksheet`.
  337. !!! Make sure you run this function AFTER having all cells filled in
  338. the worksheet!
  339. """
  340. maxwidth = ExcelSheetHelperFunctions.get_column_width(worksheet=worksheet, column=column)
  341. if maxwidth is None:
  342. return
  343. elif maxwidth > 45:
  344. maxwidth = 45
  345. worksheet.set_column(first_col=column, last_col=column, width=maxwidth)
  346. @staticmethod
  347. def get_column_width(worksheet: Worksheet, column: int) -> Optional[int]:
  348. """Get the max column width in a `Worksheet` column."""
  349. strings = getattr(worksheet, '_ts_all_strings', None)
  350. if strings is None:
  351. strings = worksheet._ts_all_strings = sorted(
  352. worksheet.str_table.string_table,
  353. key=worksheet.str_table.string_table.__getitem__)
  354. lengths = set()
  355. for row_id, colums_dict in worksheet.table.items(): # type: int, dict
  356. data = colums_dict.get(column)
  357. if not data:
  358. continue
  359. if type(data) is cell_string_tuple:
  360. iter_length = len(strings[data.string])
  361. if not iter_length:
  362. continue
  363. lengths.add(iter_length)
  364. continue
  365. if type(data) is cell_number_tuple:
  366. iter_length = len(str(data.number))
  367. if not iter_length:
  368. continue
  369. lengths.add(iter_length)
  370. if not lengths:
  371. return None
  372. return max(lengths)
  373. class ExportNetWork:
  374. headers = ['BrowserName', 'TestCaseNum', 'Status', 'Method', 'URL', 'ContentType', 'ContentSize', 'Headers',
  375. 'Params', 'Response', 'startDateTime', 'Duration/ms']
  376. def __init__(self, networkInfo: dict, testCasesEndDateTimes_1D: list,
  377. testCasesEndDateTimes_2D: list, workbook: xlsxwriter.Workbook, sheet: xlsxwriter.worksheet):
  378. self.networkInfo = networkInfo
  379. self.testCasesEndDateTimes_1D = testCasesEndDateTimes_1D
  380. self.testCasesEndDateTimes_2D = testCasesEndDateTimes_2D
  381. self.workbook = workbook
  382. self.sheet = sheet
  383. header_style = self.get_header_style()
  384. self.write_header(style=header_style)
  385. self.set_column_align()
  386. self.write_content()
  387. self.set_column_width()
  388. def set_column_align(self):
  389. right_align_indexes = list()
  390. right_align_indexes.append(ExportNetWork.headers.index('ContentSize'))
  391. right_align_indexes.append(ExportNetWork.headers.index('Duration/ms'))
  392. right_align_style = self.get_column_style(alignment='right')
  393. left_align_style = self.get_column_style(alignment='left')
  394. [self.sheet.set_column(i, i, cell_format=right_align_style) if i in right_align_indexes else
  395. self.sheet.set_column(i, i, cell_format=left_align_style) for i in range(len(ExportNetWork.headers))]
  396. def set_column_width(self):
  397. [ExcelSheetHelperFunctions.set_column_autowidth(self.sheet, i) for i in range(len(ExportNetWork.headers))]
  398. def get_header_style(self):
  399. header_style = self.workbook.add_format()
  400. header_style.set_bg_color("#00CCFF")
  401. header_style.set_color("#FFFFFF")
  402. header_style.set_bold()
  403. header_style.set_border()
  404. return header_style
  405. def get_column_style(self, alignment=None):
  406. column_style = self.workbook.add_format()
  407. column_style.set_color("black")
  408. column_style.set_align('right') if alignment == 'right'\
  409. else column_style.set_align('left') if alignment == 'left' else None
  410. column_style.set_border()
  411. return column_style
  412. def write_header(self, style=None):
  413. for index, value in enumerate(ExportNetWork.headers):
  414. self.sheet.write(0, index, value, style)
  415. def _get_test_case_num(self, start_date_time, browser_name):
  416. d_t = parse(start_date_time)
  417. d_t = d_t.replace(tzinfo=None)
  418. if self.testCasesEndDateTimes_1D:
  419. for index, dt_end in enumerate(self.testCasesEndDateTimes_1D):
  420. if d_t < dt_end:
  421. return index + 1
  422. elif self.testCasesEndDateTimes_2D:
  423. browser_num = re.findall(r"\d+\.?\d*", str(browser_name))[-1] \
  424. if re.findall(r"\d+\.?\d*", str(browser_name)) else 0
  425. dt_list_index = int(browser_num) if int(browser_num) > 0 else 0
  426. for i, tcAndDtEnd in enumerate(self.testCasesEndDateTimes_2D[dt_list_index]):
  427. if d_t < tcAndDtEnd[1]:
  428. return tcAndDtEnd[0] + 1
  429. return 'unknown'
  430. def write_content(self):
  431. if not self.networkInfo:
  432. return
  433. partition_index = 0
  434. for info in self.networkInfo:
  435. for index, entry in enumerate(info['log']['entries']):
  436. browser_name = entry['pageref']
  437. status = entry['response']['status']
  438. method = entry['request']['method']
  439. url = entry['request']['url']
  440. content_type = entry['response']['content']['mimeType']
  441. content_size = entry['response']['content']['size']
  442. headers = entry['response']['headers']
  443. params = entry['request']['queryString']
  444. response = entry['response']['content']['text'] if 'text' in entry['response']['content'] else ''
  445. start_date_time = entry['startedDateTime']
  446. duration = entry['time']
  447. test_case_num = self._get_test_case_num(start_date_time, browser_name)
  448. data_list = [browser_name, test_case_num, status, method, url, content_type, content_size,
  449. headers, params, response, start_date_time, duration]
  450. [self.sheet.write(index + partition_index + 1, i, str(data_list[i]) or 'null')
  451. for i in range(len(data_list))]
  452. partition_index += len(info['log']['entries'])
  453. class ExportTiming:
  454. def __init__(self, testdataRecords:dict, sheet:xlsxwriter.worksheet):
  455. self.testdataRecords = testdataRecords
  456. self.sheet:xlsxwriter.worksheet = sheet
  457. self.sections = {}
  458. self.findAllTimingSections()
  459. self.writeHeader()
  460. self.writeLines()
  461. # Autowidth
  462. for n in range(0,len(self.sections)+1):
  463. ExcelSheetHelperFunctions.set_column_autowidth(self.sheet, n)
  464. def writeHeader(self):
  465. self.wc(0,0,"Testcase#")
  466. for index, key in enumerate(self.sections.keys(), start=1):
  467. self.wc(0, index, key)
  468. def writeLines(self):
  469. for tcNumber, (key, line) in enumerate(self.testdataRecords.items(),start=1):
  470. self.wc(tcNumber, 0, tcNumber)
  471. lSections = self.interpretTimeLog(line[GC.TIMELOG])
  472. for section, timingValue in lSections.items():
  473. # find, in which column this section should be written:
  474. for column, key in enumerate(self.sections.keys(),1):
  475. if key == section:
  476. self.wc(tcNumber, column,
  477. timingValue[GC.TIMING_DURATION])
  478. continue
  479. @staticmethod
  480. def shortenTimingValue(timingValue):
  481. # TimingValue is seconds in Float. 2 decimals is enough:
  482. timingValue = int(float(timingValue) * 100)
  483. return timingValue/100
  484. def writeCell(self, row, col, content, format=None):
  485. self.sheet.write(row, col, content, format)
  486. wc = writeCell
  487. def findAllTimingSections(self):
  488. """
  489. We try to have an ordered list of Timing Sequences. As each Testcase might have different sections we'll have
  490. to make guesses
  491. @return:
  492. """
  493. lSections = {}
  494. for key, line in self.testdataRecords.items():
  495. lTiming:dict = ExportTiming.interpretTimeLog(line[GC.TIMELOG])
  496. for key in lTiming.keys():
  497. if lSections.get(key):
  498. continue
  499. else:
  500. lSections[key] = None
  501. self.sections = lSections
  502. @staticmethod
  503. def interpretTimeLog(lTimeLog):
  504. """Example Time Log:
  505. Complete Testrun: Start: 1579553837.241974 - no end recorded
  506. TestCaseSequenceMaster: Start: 1579553837.243414 - no end recorded
  507. CustTestCaseMaster: Start: 1579553838.97329 - no end recorded
  508. Browser Start: , since last call: 2.3161418437957764
  509. Empfehlungen: , since last call: 6.440968036651611, ZIDs:[175aeac023237a73], TS:2020-01-20 21:57:46.525577
  510. Annahme_RABAZ: , since last call: 2.002716064453125e-05, ZIDs:[6be7d0a44e59acf6], TS:2020-01-20 21:58:37.203583
  511. Antrag drucken: , since last call: 9.075241088867188, ZIDs:[6be7d0a44e59acf6, b27c3875ddcbb4fa], TS:2020-01-20 21:58:38.040137
  512. Warten auf Senden an Bestand Button: , since last call: 1.3927149772644043
  513. Senden an Bestand: , since last call: 9.60469913482666, ZIDs:[66b12fa4869cf8a0, ad1f3d47c4694e26], TS:2020-01-20 21:58:49.472288
  514. where the first part before ":" is the section, "since last call:" is the duration, TS: is the timestamp
  515. Update 29.3.2020: Format changed to "since last call: 00:xx:xx,", rest looks identical.
  516. """
  517. lExport = {}
  518. lLines = lTimeLog.split("\n")
  519. for line in lLines:
  520. parts = line.split(",")
  521. if len(parts) < 2:
  522. continue
  523. if "Start:" in line:
  524. # Format <sequence>: <Start>: <time.loctime>
  525. continue
  526. else:
  527. lSection = parts[0].replace(":","").strip()
  528. lDuration = parts[1].split("since last call: ")[1]
  529. lExport[lSection] = {GC.TIMING_DURATION: lDuration}
  530. return lExport