VirtualBox

source: vbox/trunk/src/VBox/ValidationKit/testdriver/reporter.py@ 60851

Last change on this file since 60851 was 60851, checked in by vboxsync, 9 years ago

ValidationKit: Make sure we close all files when Session.taskExec() returns. Fixes submitting data form the test pipe to the testmanager

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 46.3 KB
Line 
1# -*- coding: utf-8 -*-
2# $Id: reporter.py 60851 2016-05-05 17:11:08Z vboxsync $
3# pylint: disable=C0302
4
5"""
6Testdriver reporter module.
7"""
8
9__copyright__ = \
10"""
11Copyright (C) 2010-2015 Oracle Corporation
12
13This file is part of VirtualBox Open Source Edition (OSE), as
14available from http://www.virtualbox.org. This file is free software;
15you can redistribute it and/or modify it under the terms of the GNU
16General Public License (GPL) as published by the Free Software
17Foundation, in version 2 as it comes in the "COPYING" file of the
18VirtualBox OSE distribution. VirtualBox OSE is distributed in the
19hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
20
21The contents of this file may alternatively be used under the terms
22of the Common Development and Distribution License Version 1.0
23(CDDL) only, as it comes in the "COPYING.CDDL" file of the
24VirtualBox OSE distribution, in which case the provisions of the
25CDDL are applicable instead of those of the GPL.
26
27You may elect to license modified versions of this file under the
28terms and conditions of either the GPL or the CDDL or both.
29"""
30__version__ = "$Revision: 60851 $"
31
32
33# Standard Python imports.
34import array
35import datetime
36import errno
37import os
38import os.path
39import sys
40import time
41import threading
42import traceback
43
44# Validation Kit imports.
45from common import utils;
46
47## test reporter instance
48g_oReporter = None;
49g_sReporterName = None;
50g_oLock = threading.Lock();
51
52
53
54class PythonLoggingStream(object):
55 """
56 Python logging => testdriver/reporter.py stream.
57 """
58
59 def write(self, sText):
60 """Writes python log message to our stream."""
61 if g_oReporter != None:
62 sText = sText.rstrip("\r\n");
63 #g_oReporter.log(0, 'python: %s' % (sText), utils.getCallerName(), utils.getTimePrefix());
64 return True;
65
66 def flush(self):
67 """Flushes the stream."""
68 return True;
69
70
71class ReporterBase(object):
72 """
73 Base class for the reporters.
74 """
75
76 def __init__(self):
77 self.iVerbose = 1;
78 self.iDebug = 0;
79 self.cErrors = 0;
80 self.fTimedOut = False; # Once set, it trickles all the way up.
81 self.atTests = [];
82 self.sName = os.path.splitext(os.path.basename(sys.argv[0]))[0];
83
84 # Hook into the python logging.
85 import logging;
86 logging.basicConfig(stream = PythonLoggingStream(),
87 level = logging.DEBUG,
88 format = '%(name)-12s %(levelname)-8s %(message)s');
89 #
90 # Introspection and configuration.
91 #
92
93 def isLocal(self):
94 """Is this a local reporter?"""
95 return False;
96
97 def incVerbosity(self):
98 """Increases the verbosity level."""
99 self.iVerbose += 1;
100
101 def incDebug(self):
102 """Increases the debug level."""
103 self.iDebug += 1;
104
105 #
106 # Generic logging.
107 #
108
109 def log(self, iLevel, sText, sCaller, sTsPrf):
110 """
111 Writes the specfied text to the log if iLevel is less or requal
112 to iVerbose.
113 """
114 _ = iLevel; _ = sText; _ = sCaller; _ = sTsPrf;
115 return 0;
116
117 #
118 # XML output from the reporter.
119 #
120
121 def _xmlEscAttr(self, sValue):
122 """Escapes an XML attribute value."""
123 sValue = sValue.replace('&', '&');
124 sValue = sValue.replace('<', '&lt;');
125 sValue = sValue.replace('>', '&gt;');
126 #sValue = sValue.replace('\'', '&apos;');
127 sValue = sValue.replace('"', '&quot;');
128 sValue = sValue.replace('\n', '&#xA');
129 sValue = sValue.replace('\r', '&#xD');
130 return sValue;
131
132 def _xmlWrite(self, asText, fIndent = True):
133 """XML output function for the reporter."""
134 _ = asText; _ = fIndent;
135 return None;
136
137 def xmlFlush(self, fRetry = False, fForce = False):
138 """Flushes XML output if buffered."""
139 _ = fRetry; _ = fForce;
140 return None;
141
142 #
143 # XML output from child.
144 #
145
146 def subXmlStart(self, oFileWrapper):
147 """Called by the file wrapper when the first bytes are written to the test pipe."""
148 _ = oFileWrapper;
149 return None;
150
151 def subXmlWrite(self, oFileWrapper, sRawXml, sCaller):
152 """Called by the file wrapper write method for test pipes."""
153 return self.log(0, 'raw xml%s: %s' % (oFileWrapper.sPrefix, sRawXml), sCaller, utils.getTimePrefix());
154
155 def subXmlEnd(self, oFileWrapper):
156 """Called by the file wrapper __del__ method for test pipes."""
157 _ = oFileWrapper;
158 return None;
159
160 #
161 # File output.
162 #
163
164 def addLogFile(self, oSrcFile, sSrcFilename, sAltName, sDescription, sKind, sCaller, sTsPrf):
165 """
166 Adds the file to the report.
167 Returns True on success, False on failure.
168 """
169 _ = oSrcFile; _ = sSrcFilename; _ = sAltName; _ = sDescription; _ = sKind; _ = sCaller; _ = sTsPrf;
170 return True;
171
172 #
173 # Test reporting
174 #
175
176 def _testGetFullName(self):
177 """
178 Mangles the test names in atTest into a single name to make it easier
179 to spot where we are.
180 """
181 sName = '';
182 for t in self.atTests:
183 if sName != '':
184 sName += ', ';
185 sName += t[0];
186 return sName;
187
188 def testIncErrors(self):
189 """Increates the error count."""
190 self.cErrors += 1;
191 return self.cErrors;
192
193 def testSetTimedOut(self):
194 """Sets time out indicator for the current test and increases the error counter."""
195 self.fTimedOut = True;
196 self.cErrors += 1;
197 return None;
198
199 def testStart(self, sName, sCaller):
200 """ Starts a new test, may be nested. """
201 (sTsPrf, sTsIso) = utils.getTimePrefixAndIsoTimestamp();
202 self._xmlWrite([ '<Test timestamp="%s" name="%s">' % (sTsIso, self._xmlEscAttr(sName),), ]);
203 self.atTests.append((sName, self.cErrors, self.fTimedOut));
204 self.fTimedOut = False;
205 return self.log(1, ' %-50s: TESTING' % (self._testGetFullName()), sCaller, sTsPrf);
206
207 def testValue(self, sName, sValue, sUnit, sCaller):
208 """ Reports a benchmark value or something simiarlly useful. """
209 (sTsPrf, sTsIso) = utils.getTimePrefixAndIsoTimestamp();
210 self._xmlWrite([ '<Value timestamp="%s" name="%s" unit="%s" value="%s"/>'
211 % (sTsIso, self._xmlEscAttr(sName), self._xmlEscAttr(sUnit), self._xmlEscAttr(sValue)), ]);
212 return self.log(0, '** %-48s: %12s %s' % (sName, sValue, sUnit), sCaller, sTsPrf);
213
214 def testFailure(self, sDetails, sCaller):
215 """ Reports a failure. """
216 (sTsPrf, sTsIso) = utils.getTimePrefixAndIsoTimestamp();
217 self.cErrors = self.cErrors + 1;
218 self._xmlWrite([ '<FailureDetails timestamp="%s" text="%s"/>' % (sTsIso, self._xmlEscAttr(sDetails),), ]);
219 return self.log(0, sDetails, sCaller, sTsPrf);
220
221 def testDone(self, fSkipped, sCaller):
222 """
223 Marks the current test as DONE, pops it and maks the next test on the
224 stack current.
225 Returns (name, errors).
226 """
227 (sTsPrf, sTsIso) = utils.getTimePrefixAndIsoTimestamp();
228 sFullName = self._testGetFullName();
229
230 # safe pop
231 if len(self.atTests) <= 0:
232 self.log(0, 'testDone on empty test stack!', sCaller, sTsPrf);
233 return ('internal error', 0);
234 fTimedOut = self.fTimedOut;
235 sName, cErrorsStart, self.fTimedOut = self.atTests.pop();
236
237 # log + xml.
238 cErrors = self.cErrors - cErrorsStart;
239 if cErrors == 0:
240 if fSkipped is not True:
241 self._xmlWrite([ ' <Passed timestamp="%s"/>' % (sTsIso,), '</Test>' ],);
242 self.log(1, '** %-50s: PASSED' % (sFullName,), sCaller, sTsPrf);
243 else:
244 self._xmlWrite([ ' <Skipped timestamp="%s"/>' % (sTsIso,), '</Test>' ]);
245 self.log(1, '** %-50s: SKIPPED' % (sFullName,), sCaller, sTsPrf);
246 elif fTimedOut:
247 self._xmlWrite([ ' <TimedOut timestamp="%s" errors="%d"/>' % (sTsIso, cErrors), '</Test>' ]);
248 self.log(0, '** %-50s: TIMED-OUT - %d errors' % (sFullName, cErrors), sCaller, sTsPrf);
249 else:
250 self._xmlWrite([ ' <Failed timestamp="%s" errors="%d"/>' % (sTsIso, cErrors), '</Test>' ]);
251 self.log(0, '** %-50s: FAILED - %d errors' % (sFullName, cErrors), sCaller, sTsPrf);
252
253 # Flush buffers when reaching the last test.
254 if len(self.atTests) == 0:
255 self.xmlFlush(fRetry = True);
256
257 return (sName, cErrors);
258
259 def testErrorCount(self):
260 """
261 Returns the number of errors accumulated by the current test.
262 """
263 cTests = len(self.atTests);
264 if cTests <= 0:
265 return self.cErrors;
266 return self.cErrors - self.atTests[cTests - 1][1];
267
268 def testCleanup(self, sCaller):
269 """
270 Closes all open test as failed.
271 Returns True if no open tests, False if there were open tests.
272 """
273 if len(self.atTests) == 0:
274 return True;
275 for _ in range(len(self.atTests)):
276 self.testFailure('Test not closed by test drver', sCaller)
277 self.testDone(False, sCaller);
278 return False;
279
280
281
282class LocalReporter(ReporterBase):
283 """
284 Local reporter instance.
285 """
286
287 def __init__(self):
288 ReporterBase.__init__(self);
289 self.oLogFile = None;
290 self.oXmlFile = None;
291 self.fXmlOk = True;
292 self.iSubXml = 0;
293 self.iOtherFile = 0;
294 self.fnGetIsoTimestamp = utils.getIsoTimestamp; # Hack to get a timestamp in __del__.
295 self.oStdErr = sys.stderr; # Hack for __del__ output.
296
297 #
298 # Figure the main log directory.
299 #
300 try:
301 import user;
302 self.sDefLogDir = os.path.abspath(os.path.join(user.home, "VBoxTestLogs"));
303 except:
304 self.sDefLogDir = os.path.abspath("VBoxTestLogs");
305 try:
306 sLogDir = os.path.abspath(os.environ.get('TESTBOX_REPORTER_LOG_DIR', self.sDefLogDir));
307 if not os.path.isdir(sLogDir):
308 os.makedirs(sLogDir, 0750);
309 except:
310 sLogDir = self.sDefLogDir;
311 if not os.path.isdir(sLogDir):
312 os.makedirs(sLogDir, 0750);
313
314 #
315 # Make a subdirectory for this test run.
316 #
317 sTs = datetime.datetime.utcnow().strftime('%Y-%m-%dT%H-%M-%S.log');
318 self.sLogDir = sLogDir = os.path.join(sLogDir, '%s-%s' % (sTs, self.sName));
319 try:
320 os.makedirs(self.sLogDir, 0750);
321 except:
322 self.sLogDir = '%s-%s' % (self.sLogDir, os.getpid());
323 os.makedirs(self.sLogDir, 0750);
324
325 #
326 # Open the log file and write a header.
327 #
328 sLogName = os.path.join(self.sLogDir, 'testsuite.log');
329 sTsIso = utils.getIsoTimestamp();
330 self.oLogFile = utils.openNoInherit(sLogName, "w");
331 self.oLogFile.write(('Created log file at %s.\nRunning: %s' % (sTsIso, sys.argv)).encode('utf-8'));
332
333 #
334 # Open the xml log file and write the mandatory introduction.
335 #
336 # Note! This is done here and not in the base class because the remote
337 # logger doesn't really need this. It doesn't need the outer
338 # test wrapper either.
339 #
340 sXmlName = os.path.join(self.sLogDir, 'testsuite.xml');
341 self.oXmlFile = utils.openNoInherit(sXmlName, "w");
342 self._xmlWrite([ '<?xml version="1.0" encoding="UTF-8" ?>',
343 '<Test timestamp="%s" name="%s">' % (sTsIso, self._xmlEscAttr(self.sName),), ],
344 fIndent = False);
345
346 def __del__(self):
347 """Ends and completes the log files."""
348 try: sTsIso = self.fnGetIsoTimestamp();
349 except Exception, oXcpt:
350 sTsIso = str(oXcpt);
351
352 if self.oLogFile is not None:
353 try:
354 self.oLogFile.write(('\nThe End %s\n' % (sTsIso,)).encode('utf-8'));
355 self.oLogFile.close();
356 except: pass;
357 self.oLogFile = None;
358
359 if self.oXmlFile is not None:
360 self._closeXml(sTsIso);
361 self.oXmlFile = None;
362
363 def _closeXml(self, sTsIso):
364 """Closes the XML file."""
365 if self.oXmlFile is not None:
366 # pop the test stack
367 while len(self.atTests) > 0:
368 sName, cErrorsStart, self.fTimedOut = self.atTests.pop();
369 self._xmlWrite([ '<End timestamp="%s" errors="%d"/>' % (sTsIso, self.cErrors - cErrorsStart,),
370 '</%s>' % (sName,), ]);
371
372 # The outer one is not on the stack.
373 self._xmlWrite([ ' <End timestamp="%s"/>' % (sTsIso,),
374 '</Test>', ], fIndent = False);
375 try:
376 self.oXmlFile.close();
377 self.oXmlFile = None;
378 except:
379 pass;
380
381 def _xmlWrite(self, asText, fIndent = True):
382 """Writes to the XML file."""
383 for sText in asText:
384 if fIndent:
385 sIndent = ''.ljust((len(self.atTests) + 1) * 2);
386 sText = sIndent + sText;
387 sText += '\n';
388
389 try:
390 self.oXmlFile.write(sText.encode('utf-8'));
391 except:
392 if self.fXmlOk:
393 traceback.print_exc();
394 self.fXmlOk = False;
395 return False;
396 return True;
397
398 #
399 # Overridden methods.
400 #
401
402 def isLocal(self):
403 """Is this a local reporter?"""
404 return True;
405
406 def log(self, iLevel, sText, sCaller, sTsPrf):
407 if iLevel <= self.iVerbose:
408 # format it.
409 if self.iDebug > 0:
410 sLogText = '%s %30s: %s' % (sTsPrf, sCaller, sText);
411 else:
412 sLogText = '%s %s' % (sTsPrf, sText);
413
414 # output it.
415 sAscii = sLogText.encode('ascii', 'replace');
416 if self.iDebug == 0:
417 print >> self.oStdErr, '%s: %s' % (self.sName, sAscii)
418 else:
419 print >> self.oStdErr, '%s' % (sAscii)
420 sLogText += '\n';
421 try:
422 self.oLogFile.write(sLogText.encode('utf-8'));
423 except:
424 pass;
425 return 0;
426
427 def addLogFile(self, oSrcFile, sSrcFilename, sAltName, sDescription, sKind, sCaller, sTsPrf):
428 # Figure the destination filename.
429 iOtherFile = self.iOtherFile;
430 self.iOtherFile += 1;
431 sDstFilename = os.path.join(self.sLogDir, 'other-%d-%s.log' \
432 % (iOtherFile, os.path.splitext(os.path.basename(sSrcFilename))[0]));
433 self.log(0, '** Other log file: %s - %s (%s)' % (sDstFilename, sDescription, sSrcFilename), sCaller, sTsPrf);
434
435 # Open the destination file and copy over the data.
436 fRc = True;
437 try:
438 oDstFile = utils.openNoInherit(sDstFilename, 'w');
439 except Exception, oXcpt:
440 self.log(0, 'error opening %s: %s' % (sDstFilename, oXcpt), sCaller, sTsPrf);
441 else:
442 while True:
443 try:
444 abBuf = oSrcFile.read(65536);
445 except Exception, oXcpt:
446 fRc = False;
447 self.log(0, 'error reading %s: %s' % (sSrcFilename, oXcpt), sCaller, sTsPrf);
448 else:
449 try:
450 oDstFile.write(abBuf);
451 except Exception, oXcpt:
452 fRc = False;
453 self.log(0, 'error writing %s: %s' % (sDstFilename, oXcpt), sCaller, sTsPrf);
454 else:
455 if len(abBuf) > 0:
456 continue;
457 break;
458 oDstFile.close();
459
460 # Leave a mark in the XML log.
461 self._xmlWrite(['<LogFile timestamp="%s" filename="%s" source="%s" kind="%s" ok="%s">%s</LogFile>\n'
462 % (utils.getIsoTimestamp(), self._xmlEscAttr(os.path.basename(sDstFilename)), self._xmlEscAttr(sSrcFilename), \
463 self._xmlEscAttr(sKind), fRc, self._xmlEscAttr(sDescription))] );
464 _ = sAltName;
465 return fRc;
466
467 def subXmlStart(self, oFileWrapper):
468 # Open a new file and just include it from the main XML.
469 iSubXml = self.iSubXml;
470 self.iSubXml += 1;
471 sSubXmlName = os.path.join(self.sLogDir, 'sub-%d.xml' % (iSubXml,));
472 try:
473 oFileWrapper.oSubXmlFile = utils.openNoInherit(sSubXmlName, "w");
474 except:
475 errorXcpt('open(%s)' % oFileWrapper.oSubXmlName);
476 oFileWrapper.oSubXmlFile = None;
477 else:
478 self._xmlWrite(['<Include timestamp="%s" filename="%s"/>\n'
479 % (utils.getIsoTimestamp(), self._xmlEscAttr(os.path.basename(sSubXmlName)))]);
480 return None;
481
482 def subXmlWrite(self, oFileWrapper, sRawXml, sCaller):
483 if oFileWrapper.oSubXmlFile is not None:
484 try:
485 oFileWrapper.oSubXmlFile.write(sRawXml);
486 except:
487 pass;
488 if sCaller is None: pass; # pychecker - NOREF
489 return None;
490
491 def subXmlEnd(self, oFileWrapper):
492 if oFileWrapper.oSubXmlFile is not None:
493 try:
494 oFileWrapper.oSubXmlFile.close();
495 oFileWrapper.oSubXmlFile = None;
496 except:
497 pass;
498 return None;
499
500
501
502class RemoteReporter(ReporterBase):
503 """
504 Reporter that talks to the test manager server.
505 """
506
507
508 ## The XML sync min time (seconds).
509 kcSecXmlFlushMin = 30;
510 ## The XML sync max time (seconds).
511 kcSecXmlFlushMax = 120;
512 ## The XML sync idle time before flushing (seconds).
513 kcSecXmlFlushIdle = 5;
514 ## The XML sync line count threshold.
515 kcLinesXmlFlush = 512;
516
517 ## The retry timeout.
518 kcSecTestManagerRetryTimeout = 120;
519 ## The request timeout.
520 kcSecTestManagerRequestTimeout = 30;
521
522
523 def __init__(self):
524 ReporterBase.__init__(self);
525 self.sTestManagerUrl = os.environ.get('TESTBOX_MANAGER_URL');
526 self.sTestBoxUuid = os.environ.get('TESTBOX_UUID');
527 self.idTestBox = int(os.environ.get('TESTBOX_ID'));
528 self.idTestSet = int(os.environ.get('TESTBOX_TEST_SET_ID'));
529 self._asXml = [];
530 self._secTsXmlFlush = utils.timestampSecond();
531 self._secTsXmlLast = self._secTsXmlFlush;
532 self._fXmlFlushing = False;
533 self.oOutput = sys.stdout; # Hack for __del__ output.
534 self.fFlushEachLine = True;
535 self.fDebugXml = 'TESTDRIVER_REPORTER_DEBUG_XML' in os.environ;
536
537 # Prepare the TM connecting.
538 import urlparse;
539 import httplib;
540 import urllib;
541 from common import constants;
542
543 self._fnUrlEncode = urllib.urlencode;
544 self._fnUrlParseQs = urlparse.parse_qs;
545 self._oParsedTmUrl = urlparse.urlparse(self.sTestManagerUrl);
546
547 if sys.version_info[0] >= 3 \
548 or (sys.version_info[0] == 2 and sys.version_info[1] >= 6):
549 if self._oParsedTmUrl.scheme == 'https': # pylint: disable=E1101
550 self._fnTmConnect = lambda: httplib.HTTPSConnection(self._oParsedTmUrl.hostname,
551 timeout = self.kcSecTestManagerRequestTimeout);
552 else:
553 self._fnTmConnect = lambda: httplib.HTTPConnection( self._oParsedTmUrl.hostname,
554 timeout = self.kcSecTestManagerRequestTimeout);
555 else:
556 if self._oParsedTmUrl.scheme == 'https': # pylint: disable=E1101
557 self._fnTmConnect = lambda: httplib.HTTPSConnection(self._oParsedTmUrl.hostname);
558 else:
559 self._fnTmConnect = lambda: httplib.HTTPConnection( self._oParsedTmUrl.hostname);
560 self._dHttpHeader = \
561 {
562 'Content-Type': 'application/x-www-form-urlencoded; charset=utf-8',
563 'User-Agent': 'TestDriverReporter/%s.0 (%s, %s)' % (__version__, utils.getHostOs(), utils.getHostArch(),),
564 'Accept': 'text/plain,application/x-www-form-urlencoded',
565 'Accept-Encoding': 'identity',
566 'Cache-Control': 'max-age=0',
567 #'Connection': 'keep-alive',
568 };
569
570 dParams = {
571 constants.tbreq.ALL_PARAM_TESTBOX_UUID: self.sTestBoxUuid,
572 constants.tbreq.ALL_PARAM_TESTBOX_ID: self.idTestBox,
573 constants.tbreq.RESULT_PARAM_TEST_SET_ID: self.idTestSet,
574 };
575 self._sTmServerPath = '/%s/testboxdisp.py?%s' \
576 % ( self._oParsedTmUrl.path.strip('/'), # pylint: disable=E1101
577 urllib.urlencode(dParams), );
578
579 def __del__(self):
580 """Flush pending log messages?"""
581 if len(self._asXml) > 0:
582 self._xmlDoFlush(self._asXml, fRetry = True, fDtor = True);
583
584 def _writeOutput(self, sText):
585 """ Does the actual writing and flushing. """
586 print >> self.oOutput, sText.encode('ascii', 'replace');
587 if self.fFlushEachLine: self.oOutput.flush();
588 return None;
589
590 #
591 # Talking to TM.
592 #
593
594 def _processTmStatusResponse(self, oConn, sOperation, fClose = True):
595 """
596 Processes HTTP reponse from the test manager.
597 Returns True, False or None. None should be retried, the others not.
598 May raise exception on HTTP issue (retry ok).
599 """
600 import httplib;
601 from common import constants;
602
603 # Read the response and (optionally) close the connection.
604 oResponse = oConn.getresponse();
605 try:
606 sRspBody = oResponse.read();
607 except httplib.IncompleteRead, oXcpt:
608 self._writeOutput('%s: %s: Warning: httplib.IncompleteRead: %s [expected %s, got %s]'
609 % (utils.getTimePrefix(), sOperation, oXcpt, oXcpt.expected, len(oXcpt.partial),));
610 sRspBody = oXcpt.partial;
611 if fClose is True:
612 try: oConn.close();
613 except: pass;
614
615 # Check the content type.
616 sContentType = oResponse.getheader('Content-Type');
617 if sContentType is not None and sContentType == 'application/x-www-form-urlencoded; charset=utf-8':
618
619 # Parse the body and check the RESULT parameter.
620 dResponse = self._fnUrlParseQs(sRspBody, strict_parsing = True);
621 sResult = dResponse.get(constants.tbresp.ALL_PARAM_RESULT, None);
622 if isinstance(sResult, list):
623 sResult = sResult[0] if len(sResult) == 1 else '%d results' % (len(sResult),);
624
625 if sResult is not None:
626 if sResult == constants.tbresp.STATUS_ACK:
627 return True;
628 if sResult == constants.tbresp.STATUS_NACK:
629 self._writeOutput('%s: %s: Failed (%s). (dResponse=%s)'
630 % (utils.getTimePrefix(), sOperation, sResult, dResponse,));
631 return False;
632
633 self._writeOutput('%s: %s: Failed - dResponse=%s' % (utils.getTimePrefix(), sOperation, dResponse,));
634 else:
635 self._writeOutput('%s: %s: Unexpected Content-Type: %s' % (utils.getTimePrefix(), sOperation, sContentType,));
636 self._writeOutput('%s: %s: Body: %s' % (utils.getTimePrefix(), sOperation, sRspBody,));
637 return None;
638
639 def _doUploadFile(self, oSrcFile, sSrcFilename, sDescription, sKind, sMime):
640 """ Uploads the given file to the test manager. """
641
642 # Prepare header and url.
643 dHeader = dict(self._dHttpHeader);
644 dHeader['Content-Type'] = 'application/octet-stream';
645 self._writeOutput('%s: _doUploadFile: sHeader=%s' % (utils.getTimePrefix(), dHeader,));
646 oSrcFile.seek(0, 2);
647 self._writeOutput('%s: _doUploadFile: size=%d' % (utils.getTimePrefix(), oSrcFile.tell(),));
648 oSrcFile.seek(0);
649
650 from common import constants;
651 sUrl = self._sTmServerPath + '&' \
652 + self._fnUrlEncode({ constants.tbreq.UPLOAD_PARAM_NAME: os.path.basename(sSrcFilename),
653 constants.tbreq.UPLOAD_PARAM_DESC: sDescription,
654 constants.tbreq.UPLOAD_PARAM_KIND: sKind,
655 constants.tbreq.UPLOAD_PARAM_MIME: sMime,
656 constants.tbreq.ALL_PARAM_ACTION: constants.tbreq.UPLOAD,
657 });
658
659 # Retry loop.
660 secStart = utils.timestampSecond();
661 while True:
662 try:
663 oConn = self._fnTmConnect();
664 oConn.request('POST', sUrl, oSrcFile.read(), dHeader);
665 fRc = self._processTmStatusResponse(oConn, '_doUploadFile', fClose = True);
666 oConn.close();
667 if fRc is not None:
668 return fRc;
669 except:
670 logXcpt('warning: exception during UPLOAD request');
671
672 if utils.timestampSecond() - secStart >= self.kcSecTestManagerRetryTimeout:
673 self._writeOutput('%s: _doUploadFile: Timed out.' % (utils.getTimePrefix(),));
674 break;
675 try: oSrcFile.seek(0);
676 except:
677 logXcpt();
678 break;
679 self._writeOutput('%s: _doUploadFile: Retrying...' % (utils.getTimePrefix(), ));
680 time.sleep(2);
681
682 return False;
683
684 def _xmlDoFlush(self, asXml, fRetry = False, fDtor = False):
685 """
686 The code that does the actual talking to the server.
687 Used by both xmlFlush and __del__.
688 """
689 secStart = utils.timestampSecond();
690 while True:
691 fRc = None;
692 try:
693 # Post.
694 from common import constants;
695 sPostBody = self._fnUrlEncode({constants.tbreq.XML_RESULT_PARAM_BODY: '\n'.join(asXml),});
696 oConn = self._fnTmConnect();
697 oConn.request('POST',
698 self._sTmServerPath + ('&%s=%s' % (constants.tbreq.ALL_PARAM_ACTION, constants.tbreq.XML_RESULTS)),
699 sPostBody,
700 self._dHttpHeader);
701
702 fRc = self._processTmStatusResponse(oConn, '_xmlDoFlush', fClose = True);
703 if fRc is True:
704 if self.fDebugXml:
705 self._writeOutput('_xmlDoFlush:\n%s' % ('\n'.join(asXml),));
706 return (None, False);
707 if fRc is False:
708 self._writeOutput('_xmlDoFlush: Failed - we should abort the test, really.');
709 return (None, True);
710 except Exception, oXcpt:
711 if not fDtor:
712 logXcpt('warning: exception during XML_RESULTS request');
713 else:
714 self._writeOutput('warning: exception during XML_RESULTS request: %s' % (oXcpt,));
715
716 if fRetry is not True \
717 or utils.timestampSecond() - secStart >= self.kcSecTestManagerRetryTimeout:
718 break;
719 time.sleep(2);
720
721 return (asXml, False);
722
723
724 #
725 # Overridden methods.
726 #
727
728 def isLocal(self):
729 return False;
730
731 def log(self, iLevel, sText, sCaller, sTsPrf):
732 if iLevel <= self.iVerbose:
733 if self.iDebug > 0:
734 sLogText = '%s %30s: %s' % (sTsPrf, sCaller, sText);
735 else:
736 sLogText = '%s %s: %s' % (sTsPrf, self.sName, sText);
737 self._writeOutput(sLogText);
738 return 0;
739
740 def addLogFile(self, oSrcFile, sSrcFilename, sAltName, sDescription, sKind, sCaller, sTsPrf):
741 fRc = True;
742 if sKind in [ 'text', 'log', ] or sKind.startswith('log/'):
743 self.log(0, '*** Uploading "%s" - KIND: "%s" - DESC: "%s" ***'
744 % (sSrcFilename, sKind, sDescription), sCaller, sTsPrf);
745 g_oLock.release();
746 self._doUploadFile(oSrcFile, sAltName, sDescription, sKind, 'text/plain');
747 g_oLock.acquire();
748 elif sKind.startswith('screenshot/'):
749 self.log(0, '*** Uploading "%s" - KIND: "%s" - DESC: "%s" ***'
750 % (sSrcFilename, sKind, sDescription), sCaller, sTsPrf);
751 g_oLock.release();
752 self._doUploadFile(oSrcFile, sAltName, sDescription, sKind, 'image/png');
753 g_oLock.acquire();
754 else:
755 self.log(0, '*** UNKNOWN FILE "%s" - KIND "%s" - DESC "%s" ***'
756 % (sSrcFilename, sKind, sDescription), sCaller, sTsPrf);
757 return fRc;
758
759 def xmlFlush(self, fRetry = False, fForce = False):
760 """
761 Flushes the XML back log. Called with the lock held, may leave it
762 while communicating with the server.
763 """
764 if not self._fXmlFlushing:
765 asXml = self._asXml;
766 self._asXml = [];
767 if len(asXml) > 0 or fForce is True:
768 self._fXmlFlushing = True;
769
770 g_oLock.release();
771 (asXml, fIncErrors) = self._xmlDoFlush(asXml, fRetry = fRetry);
772 g_oLock.acquire();
773
774 if fIncErrors:
775 self.testIncErrors();
776
777 self._fXmlFlushing = False;
778 if asXml is None:
779 self._secTsXmlFlush = utils.timestampSecond();
780 else:
781 self._asXml = asXml + self._asXml;
782 return True;
783
784 self._secTsXmlFlush = utils.timestampSecond();
785 return False;
786
787 def _xmlFlushIfNecessary(self):
788 """Flushes the XML back log if necessary."""
789 tsNow = utils.timestampSecond();
790 cSecs = tsNow - self._secTsXmlFlush;
791 cSecsLast = tsNow - self._secTsXmlLast;
792 self._secTsXmlLast = tsNow;
793
794 # Absolute flush thresholds.
795 if cSecs >= self.kcSecXmlFlushMax:
796 return self.xmlFlush();
797 if len(self._asXml) >= self.kcLinesXmlFlush:
798 return self.xmlFlush();
799
800 # Flush if idle long enough.
801 if cSecs >= self.kcSecXmlFlushMin \
802 and cSecsLast >= self.kcSecXmlFlushIdle:
803 return self.xmlFlush();
804
805 return False;
806
807 def _xmlWrite(self, asText, fIndent = True):
808 """XML output function for the reporter."""
809 self._asXml += asText;
810 self._xmlFlushIfNecessary();
811 _ = fIndent; # No pretty printing, thank you.
812 return None;
813
814 def subXmlStart(self, oFileWrapper):
815 oFileWrapper.sXmlBuffer = '';
816 return None;
817
818 def subXmlWrite(self, oFileWrapper, sRawXml, sCaller):
819 oFileWrapper.sXmlBuffer += sRawXml;
820 _ = sCaller;
821 return None;
822
823 def subXmlEnd(self, oFileWrapper):
824 sRawXml = oFileWrapper.sXmlBuffer;
825 ## @todo should validate the document here and maybe auto terminate things. Adding some hints to have the server do
826 # this instead.
827 g_oLock.acquire();
828 self._asXml += [ '<PushHint testdepth="%d"/>' % (len(self.atTests),),
829 sRawXml,
830 '<PopHint testdepth="%d"/>' % (len(self.atTests),),];
831 self._xmlFlushIfNecessary();
832 g_oLock.release();
833 return None;
834
835
836#
837# Helpers
838#
839
840def logXcptWorker(iLevel, fIncErrors, sPrefix="", sText=None, cFrames=1):
841 """
842 Log an exception, optionally with a preceeding message and more than one
843 call frame.
844 """
845 g_oLock.acquire();
846 if fIncErrors:
847 g_oReporter.testIncErrors();
848
849 ## @todo skip all this if iLevel is too high!
850
851 # Try get exception info.
852 sTsPrf = utils.getTimePrefix();
853 try:
854 oType, oValue, oTraceback = sys.exc_info();
855 except:
856 oType = oValue = oTraceback = None;
857 if oType is not None:
858
859 # Try format the info
860 try:
861 rc = 0;
862 sCaller = utils.getCallerName(oTraceback.tb_frame);
863 if sText is not None:
864 rc = g_oReporter.log(iLevel, "%s%s" % (sPrefix, sText), sCaller, sTsPrf);
865 asInfo = [];
866 try:
867 asInfo = asInfo + traceback.format_exception_only(oType, oValue);
868 if cFrames is not None and cFrames <= 1:
869 asInfo = asInfo + traceback.format_tb(oTraceback, 1);
870 else:
871 asInfo.append('Traceback:')
872 asInfo = asInfo + traceback.format_tb(oTraceback, cFrames);
873 asInfo.append('Stack:')
874 asInfo = asInfo + traceback.format_stack(oTraceback.tb_frame.f_back, cFrames);
875 except:
876 g_oReporter.log(0, '** internal-error: Hit exception #2! %s' % (traceback.format_exc()), sCaller, sTsPrf);
877
878 if len(asInfo) > 0:
879 # Do the logging.
880 for sItem in asInfo:
881 asLines = sItem.splitlines();
882 for sLine in asLines:
883 rc = g_oReporter.log(iLevel, '%s%s' % (sPrefix, sLine), sCaller, sTsPrf);
884
885 else:
886 g_oReporter.log(iLevel, 'No exception info...', sCaller, sTsPrf);
887 rc = -3;
888 except:
889 g_oReporter.log(0, '** internal-error: Hit exception! %s' % (traceback.format_exc()), None, sTsPrf);
890 rc = -2;
891 else:
892 g_oReporter.log(0, '** internal-error: No exception! %s'
893 % (utils.getCallerName(iFrame=3)), utils.getCallerName(iFrame=3), sTsPrf);
894 rc = -1;
895
896 g_oLock.release();
897 return rc;
898
899#
900# The public Classes
901#
902class FileWrapper(object):
903 """ File like class for TXS EXEC and similar. """
904 def __init__(self, sPrefix):
905 self.sPrefix = sPrefix;
906
907 def __del__(self):
908 self.close();
909
910 def close(self):
911 """ file.close """
912 # Nothing to be done.
913 return;
914
915 def read(self, cb):
916 """file.read"""
917 _ = cb;
918 return "";
919
920 def write(self, sText):
921 """file.write"""
922 if isinstance(sText, array.array):
923 try:
924 sText = sText.tostring();
925 except:
926 pass;
927 g_oLock.acquire();
928 try:
929 sTsPrf = utils.getTimePrefix();
930 sCaller = utils.getCallerName();
931 asLines = sText.splitlines();
932 for sLine in asLines:
933 g_oReporter.log(0, '%s: %s' % (self.sPrefix, sLine), sCaller, sTsPrf);
934 except:
935 traceback.print_exc();
936 g_oLock.release();
937 return None;
938
939class FileWrapperTestPipe(object):
940 """ File like class for the test pipe (TXS EXEC and similar). """
941 def __init__(self):
942 self.sPrefix = '';
943 self.fStarted = False;
944 self.fClosed = False;
945
946 def __del__(self):
947 self.close();
948
949 def close(self):
950 """ file.close """
951 if self.fStarted is True and self.fClosed is False:
952 self.fClosed = True;
953 try: g_oReporter.subXmlEnd(self);
954 except:
955 try: traceback.print_exc();
956 except: pass;
957 return True;
958
959 def read(self, cb = None):
960 """file.read"""
961 _ = cb;
962 return "";
963
964 def write(self, sText):
965 """file.write"""
966 # lazy start.
967 if self.fStarted is not True:
968 try:
969 g_oReporter.subXmlStart(self);
970 except:
971 traceback.print_exc();
972 self.fStarted = True;
973
974 if isinstance(sText, array.array):
975 try:
976 sText = sText.tostring();
977 except:
978 pass;
979 try:
980 g_oReporter.subXmlWrite(self, sText, utils.getCallerName());
981 except:
982 traceback.print_exc();
983 return None;
984
985
986#
987# The public APIs.
988#
989
990def log(sText):
991 """Writes the specfied text to the log."""
992 g_oLock.acquire();
993 try:
994 rc = g_oReporter.log(1, sText, utils.getCallerName(), utils.getTimePrefix());
995 except:
996 rc = -1;
997 g_oLock.release();
998 return rc;
999
1000def logXcpt(sText=None, cFrames=1):
1001 """
1002 Log an exception, optionally with a preceeding message and more than one
1003 call frame.
1004 """
1005 return logXcptWorker(1, False, "", sText, cFrames);
1006
1007def log2(sText):
1008 """Log level 2: Writes the specfied text to the log."""
1009 g_oLock.acquire();
1010 try:
1011 rc = g_oReporter.log(2, sText, utils.getCallerName(), utils.getTimePrefix());
1012 except:
1013 rc = -1;
1014 g_oLock.release();
1015 return rc;
1016
1017def log2Xcpt(sText=None, cFrames=1):
1018 """
1019 Log level 2: Log an exception, optionally with a preceeding message and
1020 more than one call frame.
1021 """
1022 return logXcptWorker(2, False, "", sText, cFrames);
1023
1024def maybeErr(fIsError, sText):
1025 """ Maybe error or maybe normal log entry. """
1026 if fIsError is True:
1027 return error(sText);
1028 return log(sText);
1029
1030def maybeErrXcpt(fIsError, sText=None, cFrames=1):
1031 """ Maybe error or maybe normal log exception entry. """
1032 if fIsError is True:
1033 return errorXcpt(sText, cFrames);
1034 return logXcpt(sText, cFrames);
1035
1036def maybeLog(fIsNotError, sText):
1037 """ Maybe error or maybe normal log entry. """
1038 if fIsNotError is not True:
1039 return error(sText);
1040 return log(sText);
1041
1042def maybeLogXcpt(fIsNotError, sText=None, cFrames=1):
1043 """ Maybe error or maybe normal log exception entry. """
1044 if fIsNotError is not True:
1045 return errorXcpt(sText, cFrames);
1046 return logXcpt(sText, cFrames);
1047
1048def error(sText):
1049 """
1050 Writes the specfied error message to the log.
1051
1052 This will add an error to the current test.
1053
1054 Always returns False for the convenience of methods returning boolean
1055 success indicators.
1056 """
1057 g_oLock.acquire();
1058 g_oReporter.testIncErrors();
1059 try:
1060 g_oReporter.log(0, '** error: %s' % (sText), utils.getCallerName(), utils.getTimePrefix());
1061 except:
1062 pass;
1063 g_oLock.release();
1064 return False;
1065
1066def errorXcpt(sText=None, cFrames=1):
1067 """
1068 Log an error caused by an exception. If sText is given, it will preceed
1069 the exception information. cFrames can be used to display more stack.
1070
1071 This will add an error to the current test.
1072
1073 Always returns False for the convenience of methods returning boolean
1074 success indicators.
1075 """
1076 logXcptWorker(0, True, '** error: ', sText, cFrames);
1077 return False;
1078
1079def errorTimeout(sText):
1080 """
1081 Flags the current test as having timed out and writes the specified message to the log.
1082
1083 This will add an error to the current test.
1084
1085 Always returns False for the convenience of methods returning boolean
1086 success indicators.
1087 """
1088 g_oLock.acquire();
1089 g_oReporter.testSetTimedOut();
1090 try:
1091 g_oReporter.log(0, '** timeout-error: %s' % (sText), utils.getCallerName(), utils.getTimePrefix());
1092 except:
1093 pass;
1094 g_oLock.release();
1095 return False;
1096
1097def fatal(sText):
1098 """
1099 Writes a fatal error to the log.
1100
1101 This will add an error to the current test.
1102
1103 Always returns False for the convenience of methods returning boolean
1104 success indicators.
1105 """
1106 g_oLock.acquire();
1107 g_oReporter.testIncErrors();
1108 try:
1109 g_oReporter.log(0, '** fatal error: %s' % (sText), utils.getCallerName(), utils.getTimePrefix());
1110 except:
1111 pass
1112 g_oLock.release();
1113 return False;
1114
1115def fatalXcpt(sText=None, cFrames=1):
1116 """
1117 Log a fatal error caused by an exception. If sText is given, it will
1118 preceed the exception information. cFrames can be used to display more
1119 stack.
1120
1121 This will add an error to the current test.
1122
1123 Always returns False for the convenience of methods returning boolean
1124 success indicators.
1125 """
1126 logXcptWorker(0, True, "** fatal error: ", sText, cFrames);
1127 return False;
1128
1129def addLogFile(sFilename, sKind, sDescription = '', sAltName = None):
1130 """
1131 Adds the specified log file to the report if the file exists.
1132
1133 The sDescription is a free form description of the log file.
1134
1135 The sKind parameter is for adding some machine parsable hint what kind of
1136 log file this really is.
1137
1138 Returns True on success, False on failure (no ENOENT errors are logged).
1139 """
1140 sTsPrf = utils.getTimePrefix();
1141 sCaller = utils.getCallerName();
1142 fRc = False;
1143 if sAltName is None:
1144 sAltName = sFilename;
1145
1146 try:
1147 oSrcFile = utils.openNoInherit(sFilename, 'rb');
1148 except IOError, oXcpt:
1149 if oXcpt.errno != errno.ENOENT:
1150 logXcpt('addLogFile(%s,%s,%s)' % (sFilename, sDescription, sKind));
1151 else:
1152 logXcpt('addLogFile(%s,%s,%s) IOError' % (sFilename, sDescription, sKind));
1153 except:
1154 logXcpt('addLogFile(%s,%s,%s)' % (sFilename, sDescription, sKind));
1155 else:
1156 g_oLock.acquire();
1157 fRc = g_oReporter.addLogFile(oSrcFile, sFilename, sAltName, sDescription, sKind, sCaller, sTsPrf);
1158 g_oLock.release();
1159 oSrcFile.close();
1160 return fRc;
1161
1162def isLocal():
1163 """Is this a local reporter?"""
1164 return g_oReporter.isLocal()
1165
1166def incVerbosity():
1167 """Increases the verbosity level."""
1168 return g_oReporter.incVerbosity()
1169
1170def incDebug():
1171 """Increases the debug level."""
1172 return g_oReporter.incDebug()
1173
1174def getErrorCount():
1175 """
1176 Get the current error count for the entire test run.
1177 """
1178 g_oLock.acquire();
1179 cErrors = g_oReporter.cErrors;
1180 g_oLock.release();
1181 return cErrors;
1182
1183
1184#
1185# Test reporting, a bit similar to RTTestI*.
1186#
1187
1188def testStart(sName):
1189 """
1190 Starts a new test (pushes it).
1191 """
1192 g_oLock.acquire();
1193 rc = g_oReporter.testStart(sName, utils.getCallerName());
1194 g_oLock.release();
1195 return rc;
1196
1197def testValue(sName, sValue, sUnit):
1198 """
1199 Reports a benchmark value or something simiarlly useful.
1200 """
1201 g_oLock.acquire();
1202 rc = g_oReporter.testValue(sName, str(sValue), sUnit, utils.getCallerName());
1203 g_oLock.release();
1204 return rc;
1205
1206def testFailure(sDetails):
1207 """
1208 Reports a failure.
1209 We count these calls and testDone will use them to report PASSED or FAILED.
1210
1211 Returns False so that a return False line can be saved.
1212 """
1213 g_oLock.acquire();
1214 g_oReporter.testFailure(sDetails, utils.getCallerName());
1215 g_oLock.release();
1216 return False;
1217
1218def testFailureXcpt(sDetails = ''):
1219 """
1220 Reports a failure with exception.
1221 We count these calls and testDone will use them to report PASSED or FAILED.
1222
1223 Returns False so that a return False line can be saved.
1224 """
1225 # Extract exception info.
1226 try:
1227 oType, oValue, oTraceback = sys.exc_info();
1228 except:
1229 oType = oValue, oTraceback = None;
1230 if oType is not None:
1231 sCaller = utils.getCallerName(oTraceback.tb_frame);
1232 sXcpt = ' '.join(traceback.format_exception_only(oType, oValue));
1233 else:
1234 sCaller = utils.getCallerName();
1235 sXcpt = 'No exception at %s' % (sCaller,);
1236
1237 # Use testFailure to do the work.
1238 g_oLock.acquire();
1239 if sDetails == '':
1240 g_oReporter.testFailure('Exception: %s' % (sXcpt,), sCaller);
1241 else:
1242 g_oReporter.testFailure('%s: %s' % (sDetails, sXcpt), sCaller);
1243 g_oLock.release();
1244 return False;
1245
1246def testDone(fSkipped = False):
1247 """
1248 Completes the current test (pops it), logging PASSED / FAILURE.
1249
1250 Returns a tuple with the name of the test and its error count.
1251 """
1252 g_oLock.acquire();
1253 rc = g_oReporter.testDone(fSkipped, utils.getCallerName());
1254 g_oLock.release();
1255 return rc;
1256
1257def testErrorCount():
1258 """
1259 Gets the error count of the current test.
1260
1261 Returns the number of errors.
1262 """
1263 g_oLock.acquire();
1264 cErrors = g_oReporter.testErrorCount();
1265 g_oLock.release();
1266 return cErrors;
1267
1268def testCleanup():
1269 """
1270 Closes all open tests with a generic error condition.
1271
1272 Returns True if no open tests, False if something had to be closed with failure.
1273 """
1274 g_oLock.acquire();
1275 fRc = g_oReporter.testCleanup(utils.getCallerName());
1276 g_oReporter.xmlFlush(fRetry = False, fForce = True);
1277 g_oLock.release();
1278 return fRc;
1279
1280
1281#
1282# Sub XML stuff.
1283#
1284
1285def addSubXmlFile(sFilename):
1286 """
1287 Adds a sub-xml result file to the party.
1288 """
1289 fRc = False;
1290 try:
1291 oSrcFile = utils.openNoInherit(sFilename, 'r');
1292 except IOError, oXcpt:
1293 if oXcpt.errno != errno.ENOENT:
1294 logXcpt('addSubXmlFile(%s)' % (sFilename,));
1295 except:
1296 logXcpt('addSubXmlFile(%s)' % (sFilename,));
1297 else:
1298 try:
1299 oWrapper = FileWrapperTestPipe()
1300 oWrapper.write(oSrcFile.read());
1301 oWrapper.close();
1302 except:
1303 logXcpt('addSubXmlFile(%s)' % (sFilename,));
1304 oSrcFile.close();
1305
1306 return fRc;
1307
1308
1309#
1310# Other useful debugging tools.
1311#
1312
1313def logAllStacks(cFrames = None):
1314 """
1315 Logs the stacks of all python threads.
1316 """
1317 sTsPrf = utils.getTimePrefix();
1318 sCaller = utils.getCallerName();
1319 g_oLock.acquire();
1320
1321 cThread = 0;
1322 for idThread, oStack in sys._current_frames().items(): # >=2.5, a bit ugly - pylint: disable=W0212
1323 try:
1324 if cThread > 0:
1325 g_oReporter.log(1, '', sCaller, sTsPrf);
1326 g_oReporter.log(1, 'Thread %s (%#x)' % (idThread, idThread), sCaller, sTsPrf);
1327 try:
1328 asInfo = traceback.format_stack(oStack, cFrames);
1329 except:
1330 g_oReporter.log(1, ' Stack formatting failed w/ exception', sCaller, sTsPrf);
1331 else:
1332 for sInfo in asInfo:
1333 asLines = sInfo.splitlines();
1334 for sLine in asLines:
1335 g_oReporter.log(1, sLine, sCaller, sTsPrf);
1336 except:
1337 pass;
1338 cThread += 1;
1339
1340 g_oLock.release();
1341 return None;
1342
1343def checkTestManagerConnection():
1344 """
1345 Checks the connection to the test manager.
1346
1347 Returns True if the connection is fine, False if not, None if not remote
1348 reporter.
1349
1350 Note! This as the sideeffect of flushing XML.
1351 """
1352 g_oLock.acquire();
1353 fRc = g_oReporter.xmlFlush(fRetry = False, fForce = True);
1354 g_oLock.release();
1355 return fRc;
1356
1357def flushall():
1358 """
1359 Flushes all output streams, both standard and logger related.
1360 """
1361 try: sys.stdout.flush();
1362 except: pass;
1363 try: sys.stderr.flush();
1364 except: pass;
1365
1366 # Note! Current no logger specific streams to flush.
1367
1368 return True;
1369
1370
1371#
1372# Module initialization.
1373#
1374
1375def _InitReporterModule():
1376 """
1377 Instantiate the test reporter.
1378 """
1379 global g_oReporter, g_sReporterName
1380
1381 g_sReporterName = os.getenv("TESTBOX_REPORTER", "local");
1382 if g_sReporterName == "local":
1383 g_oReporter = LocalReporter();
1384 elif g_sReporterName == "remote":
1385 g_oReporter = RemoteReporter();
1386 else:
1387 print >> sys.stderr, os.path.basename(__file__) + ": Unknown TESTBOX_REPORTER value: '" + g_sReporterName + "'";
1388 raise Exception("Unknown TESTBOX_REPORTER value '" + g_sReporterName + "'");
1389
1390if __name__ != "checker": # pychecker avoidance.
1391 _InitReporterModule();
1392
Note: See TracBrowser for help on using the repository browser.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette