VirtualBox

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

Last change on this file since 53503 was 53503, checked in by vboxsync, 10 years ago

more debugging

  • 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 53503 2014-12-10 20:52:25Z vboxsync $
3# pylint: disable=C0302
4
5"""
6Testdriver reporter module.
7"""
8
9__copyright__ = \
10"""
11Copyright (C) 2010-2014 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: 53503 $"
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 self._writeOutput('%s: RemoteReporter: host="%s"' % (self._oParsedTmUrl.hostname));
547
548 if sys.version_info[0] >= 3 \
549 or (sys.version_info[0] == 2 and sys.version_info[1] >= 6):
550 if self._oParsedTmUrl.scheme == 'https': # pylint: disable=E1101
551 self._fnTmConnect = lambda: httplib.HTTPSConnection(self._oParsedTmUrl.hostname,
552 timeout = self.kcSecTestManagerRequestTimeout);
553 else:
554 self._fnTmConnect = lambda: httplib.HTTPConnection( self._oParsedTmUrl.hostname,
555 timeout = self.kcSecTestManagerRequestTimeout);
556 else:
557 if self._oParsedTmUrl.scheme == 'https': # pylint: disable=E1101
558 self._fnTmConnect = lambda: httplib.HTTPSConnection(self._oParsedTmUrl.hostname);
559 else:
560 self._fnTmConnect = lambda: httplib.HTTPConnection( self._oParsedTmUrl.hostname);
561 self._dHttpHeader = \
562 {
563 'Content-Type': 'application/x-www-form-urlencoded; charset=utf-8',
564 'User-Agent': 'TestDriverReporter/%s.0 (%s, %s)' % (__version__, utils.getHostOs(), utils.getHostArch(),),
565 'Accept': 'text/plain,application/x-www-form-urlencoded',
566 'Accept-Encoding': 'identity',
567 'Cache-Control': 'max-age=0',
568 #'Connection': 'keep-alive',
569 };
570
571 dParams = {
572 constants.tbreq.ALL_PARAM_TESTBOX_UUID: self.sTestBoxUuid,
573 constants.tbreq.ALL_PARAM_TESTBOX_ID: self.idTestBox,
574 constants.tbreq.RESULT_PARAM_TEST_SET_ID: self.idTestSet,
575 };
576 self._sTmServerPath = '/%s/testboxdisp.py?%s' \
577 % ( self._oParsedTmUrl.path.strip('/'), # pylint: disable=E1101
578 urllib.urlencode(dParams), );
579
580 def __del__(self):
581 """Flush pending log messages?"""
582 if len(self._asXml) > 0:
583 self._xmlDoFlush(self._asXml, fRetry = True, fDtor = True);
584
585 def _writeOutput(self, sText):
586 """ Does the actual writing and flushing. """
587 print >> self.oOutput, sText.encode('ascii', 'replace');
588 if self.fFlushEachLine: self.oOutput.flush();
589 return None;
590
591 #
592 # Talking to TM.
593 #
594
595 def _processTmStatusResponse(self, oConn, sOperation, fClose = True):
596 """
597 Processes HTTP reponse from the test manager.
598 Returns True, False or None. None should be retried, the others not.
599 May raise exception on HTTP issue (retry ok).
600 """
601 import httplib;
602 from common import constants;
603
604 # Read the response and (optionally) close the connection.
605 oResponse = oConn.getresponse();
606 try:
607 sRspBody = oResponse.read();
608 except httplib.IncompleteRead, oXcpt:
609 self._writeOutput('%s: %s: Warning: httplib.IncompleteRead: %s [expected %s, got %s]'
610 % (utils.getTimePrefix(), sOperation, oXcpt, oXcpt.expected, len(oXcpt.partial),));
611 sRspBody = oXcpt.partial;
612 if fClose is True:
613 try: oConn.close();
614 except: pass;
615
616 # Check the content type.
617 sContentType = oResponse.getheader('Content-Type');
618 if sContentType is not None and sContentType == 'application/x-www-form-urlencoded; charset=utf-8':
619
620 # Parse the body and check the RESULT parameter.
621 dResponse = self._fnUrlParseQs(sRspBody, strict_parsing = True);
622 sResult = dResponse.get(constants.tbresp.ALL_PARAM_RESULT, None);
623 if isinstance(sResult, list):
624 sResult = sResult[0] if len(sResult) == 1 else '%d results' % (len(sResult),);
625
626 if sResult is not None:
627 if sResult == constants.tbresp.STATUS_ACK:
628 return True;
629 if sResult == constants.tbresp.STATUS_NACK:
630 self._writeOutput('%s: %s: Failed (%s). (dResponse=%s)'
631 % (utils.getTimePrefix(), sOperation, sResult, dResponse,));
632 return False;
633
634 self._writeOutput('%s: %s: Failed - dResponse=%s' % (utils.getTimePrefix(), sOperation, dResponse,));
635 else:
636 self._writeOutput('%s: %s: Unexpected Content-Type: %s' % (utils.getTimePrefix(), sOperation, sContentType,));
637 self._writeOutput('%s: %s: Body: %s' % (utils.getTimePrefix(), sOperation, sRspBody,));
638 return None;
639
640 def _doUploadFile(self, oSrcFile, sSrcFilename, sDescription, sKind, sMime):
641 """ Uploads the given file to the test manager. """
642
643 # Prepare header and url.
644 dHeader = dict(self._dHttpHeader);
645 dHeader['Content-Type'] = 'application/octet-stream';
646 self._writeOutput('%s: _doUploadFile: sHeader=%s' % (utils.getTimePrefix(), dHeader,));
647 oSrcFile.seek(0, 2);
648 self._writeOutput('%s: _doUploadFile: size=%d' % (utils.getTimePrefix(), oSrcFile.tell(),));
649 oSrcFile.seek(0);
650
651 from common import constants;
652 sUrl = self._sTmServerPath + '&' \
653 + self._fnUrlEncode({ constants.tbreq.UPLOAD_PARAM_NAME: os.path.basename(sSrcFilename),
654 constants.tbreq.UPLOAD_PARAM_DESC: sDescription,
655 constants.tbreq.UPLOAD_PARAM_KIND: sKind,
656 constants.tbreq.UPLOAD_PARAM_MIME: sMime,
657 constants.tbreq.ALL_PARAM_ACTION: constants.tbreq.UPLOAD,
658 });
659
660 self._writeOutput('%s: _doUploadFile: url="%s"' % (utils.getTimePrefix(), sUrl));
661
662 # Retry loop.
663 secStart = utils.timestampSecond();
664 while True:
665 try:
666 oConn = self._fnTmConnect();
667 oConn.request('POST', sUrl, oSrcFile.read(), dHeader);
668 fRc = self._processTmStatusResponse(oConn, '_doUploadFile', fClose = True);
669 oConn.close();
670 if fRc is not None:
671 return fRc;
672 except:
673 logXcpt('warning: exception during UPLOAD request');
674
675 if utils.timestampSecond() - secStart >= self.kcSecTestManagerRetryTimeout:
676 self._writeOutput('%s: _doUploadFile: Timed out.' % (utils.getTimePrefix(),));
677 break;
678 try: oSrcFile.seek(0);
679 except:
680 logXcpt();
681 break;
682 self._writeOutput('%s: _doUploadFile: Retrying...' % (utils.getTimePrefix(), ));
683 time.sleep(2);
684
685 return False;
686
687 def _xmlDoFlush(self, asXml, fRetry = False, fDtor = False):
688 """
689 The code that does the actual talking to the server.
690 Used by both xmlFlush and __del__.
691 """
692 secStart = utils.timestampSecond();
693 while True:
694 fRc = None;
695 try:
696 # Post.
697 from common import constants;
698 sPostBody = self._fnUrlEncode({constants.tbreq.XML_RESULT_PARAM_BODY: '\n'.join(asXml),});
699 oConn = self._fnTmConnect();
700 oConn.request('POST',
701 self._sTmServerPath + ('&%s=%s' % (constants.tbreq.ALL_PARAM_ACTION, constants.tbreq.XML_RESULTS)),
702 sPostBody,
703 self._dHttpHeader);
704
705 fRc = self._processTmStatusResponse(oConn, '_xmlDoFlush', fClose = True);
706 if fRc is True:
707 if self.fDebugXml:
708 self._writeOutput('_xmlDoFlush:\n%s' % ('\n'.join(asXml),));
709 return (None, False);
710 if fRc is False:
711 self._writeOutput('_xmlDoFlush: Failed - we should abort the test, really.');
712 return (None, True);
713 except Exception, oXcpt:
714 if not fDtor:
715 logXcpt('warning: exception during XML_RESULTS request');
716 else:
717 self._writeOutput('warning: exception during XML_RESULTS request: %s' % (oXcpt,));
718
719 if fRetry is not True \
720 or utils.timestampSecond() - secStart >= self.kcSecTestManagerRetryTimeout:
721 break;
722 time.sleep(2);
723
724 return (asXml, False);
725
726
727 #
728 # Overridden methods.
729 #
730
731 def isLocal(self):
732 return False;
733
734 def log(self, iLevel, sText, sCaller, sTsPrf):
735 if iLevel <= self.iVerbose:
736 if self.iDebug > 0:
737 sLogText = '%s %30s: %s' % (sTsPrf, sCaller, sText);
738 else:
739 sLogText = '%s %s: %s' % (sTsPrf, self.sName, sText);
740 self._writeOutput(sLogText);
741 return 0;
742
743 def addLogFile(self, oSrcFile, sSrcFilename, sAltName, sDescription, sKind, sCaller, sTsPrf):
744 fRc = True;
745 if sKind in [ 'text', 'log', ] or sKind.startswith('log/'):
746 self.log(0, '*** Uploading "%s" - KIND: "%s" - DESC: "%s" ***'
747 % (sSrcFilename, sKind, sDescription), sCaller, sTsPrf);
748 g_oLock.release();
749 self._doUploadFile(oSrcFile, sAltName, sDescription, sKind, 'text/plain');
750 g_oLock.acquire();
751 elif sKind.startswith('screenshot/'):
752 self.log(0, '*** Uploading "%s" - KIND: "%s" - DESC: "%s" ***'
753 % (sSrcFilename, sKind, sDescription), sCaller, sTsPrf);
754 g_oLock.release();
755 self._doUploadFile(oSrcFile, sAltName, sDescription, sKind, 'image/png');
756 g_oLock.acquire();
757 else:
758 self.log(0, '*** UNKNOWN FILE "%s" - KIND "%s" - DESC "%s" ***'
759 % (sSrcFilename, sKind, sDescription), sCaller, sTsPrf);
760 return fRc;
761
762 def xmlFlush(self, fRetry = False, fForce = False):
763 """
764 Flushes the XML back log. Called with the lock held, may leave it
765 while communicating with the server.
766 """
767 if not self._fXmlFlushing:
768 asXml = self._asXml;
769 self._asXml = [];
770 if len(asXml) > 0 or fForce is True:
771 self._fXmlFlushing = True;
772
773 g_oLock.release();
774 (asXml, fIncErrors) = self._xmlDoFlush(asXml, fRetry = fRetry);
775 g_oLock.acquire();
776
777 if fIncErrors:
778 self.testIncErrors();
779
780 self._fXmlFlushing = False;
781 if asXml is None:
782 self._secTsXmlFlush = utils.timestampSecond();
783 else:
784 self._asXml = asXml + self._asXml;
785 return True;
786
787 self._secTsXmlFlush = utils.timestampSecond();
788 return False;
789
790 def _xmlFlushIfNecessary(self):
791 """Flushes the XML back log if necessary."""
792 tsNow = utils.timestampSecond();
793 cSecs = tsNow - self._secTsXmlFlush;
794 cSecsLast = tsNow - self._secTsXmlLast;
795 self._secTsXmlLast = tsNow;
796
797 # Absolute flush thresholds.
798 if cSecs >= self.kcSecXmlFlushMax:
799 return self.xmlFlush();
800 if len(self._asXml) >= self.kcLinesXmlFlush:
801 return self.xmlFlush();
802
803 # Flush if idle long enough.
804 if cSecs >= self.kcSecXmlFlushMin \
805 and cSecsLast >= self.kcSecXmlFlushIdle:
806 return self.xmlFlush();
807
808 return False;
809
810 def _xmlWrite(self, asText, fIndent = True):
811 """XML output function for the reporter."""
812 self._asXml += asText;
813 self._xmlFlushIfNecessary();
814 _ = fIndent; # No pretty printing, thank you.
815 return None;
816
817 def subXmlStart(self, oFileWrapper):
818 oFileWrapper.sXmlBuffer = '';
819 return None;
820
821 def subXmlWrite(self, oFileWrapper, sRawXml, sCaller):
822 oFileWrapper.sXmlBuffer += sRawXml;
823 _ = sCaller;
824 return None;
825
826 def subXmlEnd(self, oFileWrapper):
827 sRawXml = oFileWrapper.sXmlBuffer;
828 ## @todo should validate the document here and maybe auto terminate things. Adding some hints to have the server do
829 # this instead.
830 g_oLock.acquire();
831 self._asXml += [ '<PushHint testdepth="%d"/>' % (len(self.atTests),),
832 sRawXml,
833 '<PopHint testdepth="%d"/>' % (len(self.atTests),),];
834 self._xmlFlushIfNecessary();
835 g_oLock.release();
836 return None;
837
838
839#
840# Helpers
841#
842
843def logXcptWorker(iLevel, fIncErrors, sPrefix="", sText=None, cFrames=1):
844 """
845 Log an exception, optionally with a preceeding message and more than one
846 call frame.
847 """
848 g_oLock.acquire();
849 if fIncErrors:
850 g_oReporter.testIncErrors();
851
852 ## @todo skip all this if iLevel is too high!
853
854 # Try get exception info.
855 sTsPrf = utils.getTimePrefix();
856 try:
857 oType, oValue, oTraceback = sys.exc_info();
858 except:
859 oType = oValue = oTraceback = None;
860 if oType is not None:
861
862 # Try format the info
863 try:
864 rc = 0;
865 sCaller = utils.getCallerName(oTraceback.tb_frame);
866 if sText is not None:
867 rc = g_oReporter.log(iLevel, "%s%s" % (sPrefix, sText), sCaller, sTsPrf);
868 asInfo = [];
869 try:
870 asInfo = asInfo + traceback.format_exception_only(oType, oValue);
871 if cFrames is not None and cFrames <= 1:
872 asInfo = asInfo + traceback.format_tb(oTraceback, 1);
873 else:
874 asInfo.append('Traceback:')
875 asInfo = asInfo + traceback.format_tb(oTraceback, cFrames);
876 asInfo.append('Stack:')
877 asInfo = asInfo + traceback.format_stack(oTraceback.tb_frame.f_back, cFrames);
878 except:
879 g_oReporter.log(0, 'internal-error: Hit exception #2! %s' % (traceback.format_exc()), sCaller, sTsPrf);
880
881 if len(asInfo) > 0:
882 # Do the logging.
883 for sItem in asInfo:
884 asLines = sItem.splitlines();
885 for sLine in asLines:
886 rc = g_oReporter.log(iLevel, '%s%s' % (sPrefix, sLine), sCaller, sTsPrf);
887
888 else:
889 g_oReporter.log(iLevel, 'No exception info...', sCaller, sTsPrf);
890 rc = -3;
891 except:
892 g_oReporter.log(0, 'internal-error: Hit exception! %s' % (traceback.format_exc()), None, sTsPrf);
893 rc = -2;
894 else:
895 g_oReporter.log(0, 'internal-error: No exception! %s'
896 % (utils.getCallerName(iFrame=3)), utils.getCallerName(iFrame=3), sTsPrf);
897 rc = -1;
898
899 g_oLock.release();
900 return rc;
901
902#
903# The public Classes
904#
905class FileWrapper(object):
906 """ File like class for TXS EXEC and similar. """
907 def __init__(self, sPrefix):
908 self.sPrefix = sPrefix;
909
910 def read(self, cb):
911 """file.read"""
912 _ = cb;
913 return "";
914
915 def write(self, sText):
916 """file.write"""
917 if isinstance(sText, array.array):
918 try:
919 sText = sText.tostring();
920 except:
921 pass;
922 g_oLock.acquire();
923 try:
924 sTsPrf = utils.getTimePrefix();
925 sCaller = utils.getCallerName();
926 asLines = sText.splitlines();
927 for sLine in asLines:
928 g_oReporter.log(0, '%s: %s' % (self.sPrefix, sLine), sCaller, sTsPrf);
929 except:
930 traceback.print_exc();
931 g_oLock.release();
932 return None;
933
934class FileWrapperTestPipe(object):
935 """ File like class for the test pipe (TXS EXEC and similar). """
936 def __init__(self):
937 self.sPrefix = '';
938 self.fStarted = False;
939 self.fClosed = False;
940
941 def __del__(self):
942 self.close();
943
944 def close(self):
945 """ file.close """
946 if self.fStarted is True and self.fClosed is False:
947 self.fClosed = True;
948 try: g_oReporter.subXmlEnd(self);
949 except:
950 try: traceback.print_exc();
951 except: pass;
952 return True;
953
954 def read(self, cb = None):
955 """file.read"""
956 _ = cb;
957 return "";
958
959 def write(self, sText):
960 """file.write"""
961 # lazy start.
962 if self.fStarted is not True:
963 try:
964 g_oReporter.subXmlStart(self);
965 except:
966 traceback.print_exc();
967 self.fStarted = True;
968
969 if isinstance(sText, array.array):
970 try:
971 sText = sText.tostring();
972 except:
973 pass;
974 try:
975 g_oReporter.subXmlWrite(self, sText, utils.getCallerName());
976 except:
977 traceback.print_exc();
978 return None;
979
980
981#
982# The public APIs.
983#
984
985def log(sText):
986 """Writes the specfied text to the log."""
987 g_oLock.acquire();
988 try:
989 rc = g_oReporter.log(1, sText, utils.getCallerName(), utils.getTimePrefix());
990 except:
991 rc = -1;
992 g_oLock.release();
993 return rc;
994
995def logXcpt(sText=None, cFrames=1):
996 """
997 Log an exception, optionally with a preceeding message and more than one
998 call frame.
999 """
1000 return logXcptWorker(1, False, "", sText, cFrames);
1001
1002def log2(sText):
1003 """Log level 2: Writes the specfied text to the log."""
1004 g_oLock.acquire();
1005 try:
1006 rc = g_oReporter.log(2, sText, utils.getCallerName(), utils.getTimePrefix());
1007 except:
1008 rc = -1;
1009 g_oLock.release();
1010 return rc;
1011
1012def log2Xcpt(sText=None, cFrames=1):
1013 """
1014 Log level 2: Log an exception, optionally with a preceeding message and
1015 more than one call frame.
1016 """
1017 return logXcptWorker(2, False, "", sText, cFrames);
1018
1019def maybeErr(fIsError, sText):
1020 """ Maybe error or maybe normal log entry. """
1021 if fIsError is True:
1022 return error(sText);
1023 return log(sText);
1024
1025def maybeErrXcpt(fIsError, sText=None, cFrames=1):
1026 """ Maybe error or maybe normal log exception entry. """
1027 if fIsError is True:
1028 return errorXcpt(sText, cFrames);
1029 return logXcpt(sText, cFrames);
1030
1031def maybeLog(fIsNotError, sText):
1032 """ Maybe error or maybe normal log entry. """
1033 if fIsNotError is not True:
1034 return error(sText);
1035 return log(sText);
1036
1037def maybeLogXcpt(fIsNotError, sText=None, cFrames=1):
1038 """ Maybe error or maybe normal log exception entry. """
1039 if fIsNotError is not True:
1040 return errorXcpt(sText, cFrames);
1041 return logXcpt(sText, cFrames);
1042
1043def error(sText):
1044 """
1045 Writes the specfied error message to the log.
1046
1047 This will add an error to the current test.
1048
1049 Always returns False for the convenience of methods returning boolean
1050 success indicators.
1051 """
1052 g_oLock.acquire();
1053 g_oReporter.testIncErrors();
1054 try:
1055 g_oReporter.log(0, 'error: %s' % (sText), utils.getCallerName(), utils.getTimePrefix());
1056 except:
1057 pass;
1058 g_oLock.release();
1059 return False;
1060
1061def errorXcpt(sText=None, cFrames=1):
1062 """
1063 Log an error caused by an exception. If sText is given, it will preceed
1064 the exception information. cFrames can be used to display more stack.
1065
1066 This will add an error to the current test.
1067
1068 Always returns False for the convenience of methods returning boolean
1069 success indicators.
1070 """
1071 logXcptWorker(0, True, "error: ", sText, cFrames);
1072 return False;
1073
1074def errorTimeout(sText):
1075 """
1076 Flags the current test as having timed out and writes the specified message to the log.
1077
1078 This will add an error to the current test.
1079
1080 Always returns False for the convenience of methods returning boolean
1081 success indicators.
1082 """
1083 g_oLock.acquire();
1084 g_oReporter.testSetTimedOut();
1085 try:
1086 g_oReporter.log(0, 'timeout-error: %s' % (sText), utils.getCallerName(), utils.getTimePrefix());
1087 except:
1088 pass;
1089 g_oLock.release();
1090 return False;
1091
1092def fatal(sText):
1093 """
1094 Writes a fatal error to the log.
1095
1096 This will add an error to the current test.
1097
1098 Always returns False for the convenience of methods returning boolean
1099 success indicators.
1100 """
1101 g_oLock.acquire();
1102 g_oReporter.testIncErrors();
1103 try:
1104 g_oReporter.log(0, 'fatal error: %s' % (sText), utils.getCallerName(), utils.getTimePrefix());
1105 except:
1106 pass
1107 g_oLock.release();
1108 return False;
1109
1110def fatalXcpt(sText=None, cFrames=1):
1111 """
1112 Log a fatal error caused by an exception. If sText is given, it will
1113 preceed the exception information. cFrames can be used to display more
1114 stack.
1115
1116 This will add an error to the current test.
1117
1118 Always returns False for the convenience of methods returning boolean
1119 success indicators.
1120 """
1121 logXcptWorker(1, True, "fatal error: ", sText, cFrames);
1122 return False;
1123
1124def addLogFile(sFilename, sKind, sDescription = '', sAltName = None):
1125 """
1126 Adds the specified log file to the report if the file exists.
1127
1128 The sDescription is a free form description of the log file.
1129
1130 The sKind parameter is for adding some machine parsable hint what kind of
1131 log file this really is.
1132
1133 Returns True on success, False on failure (no ENOENT errors are logged).
1134 """
1135 sTsPrf = utils.getTimePrefix();
1136 sCaller = utils.getCallerName();
1137 fRc = False;
1138 if sAltName is None:
1139 sAltName = sFilename;
1140
1141 try:
1142 oSrcFile = utils.openNoInherit(sFilename, 'rb');
1143 except IOError, oXcpt:
1144 if oXcpt.errno != errno.ENOENT:
1145 logXcpt('addLogFile(%s,%s,%s)' % (sFilename, sDescription, sKind));
1146 else:
1147 logXcpt('addLogFile(%s,%s,%s) IOError' % (sFilename, sDescription, sKind));
1148 except:
1149 logXcpt('addLogFile(%s,%s,%s)' % (sFilename, sDescription, sKind));
1150 else:
1151 g_oLock.acquire();
1152 fRc = g_oReporter.addLogFile(oSrcFile, sFilename, sAltName, sDescription, sKind, sCaller, sTsPrf);
1153 g_oLock.release();
1154 oSrcFile.close();
1155 return fRc;
1156
1157def isLocal():
1158 """Is this a local reporter?"""
1159 return g_oReporter.isLocal()
1160
1161def incVerbosity():
1162 """Increases the verbosity level."""
1163 return g_oReporter.incVerbosity()
1164
1165def incDebug():
1166 """Increases the debug level."""
1167 return g_oReporter.incDebug()
1168
1169def getErrorCount():
1170 """
1171 Get the current error count for the entire test run.
1172 """
1173 g_oLock.acquire();
1174 cErrors = g_oReporter.cErrors;
1175 g_oLock.release();
1176 return cErrors;
1177
1178
1179#
1180# Test reporting, a bit similar to RTTestI*.
1181#
1182
1183def testStart(sName):
1184 """
1185 Starts a new test (pushes it).
1186 """
1187 g_oLock.acquire();
1188 rc = g_oReporter.testStart(sName, utils.getCallerName());
1189 g_oLock.release();
1190 return rc;
1191
1192def testValue(sName, sValue, sUnit):
1193 """
1194 Reports a benchmark value or something simiarlly useful.
1195 """
1196 g_oLock.acquire();
1197 rc = g_oReporter.testValue(sName, str(sValue), sUnit, utils.getCallerName());
1198 g_oLock.release();
1199 return rc;
1200
1201def testFailure(sDetails):
1202 """
1203 Reports a failure.
1204 We count these calls and testDone will use them to report PASSED or FAILED.
1205
1206 Returns False so that a return False line can be saved.
1207 """
1208 g_oLock.acquire();
1209 g_oReporter.testFailure(sDetails, utils.getCallerName());
1210 g_oLock.release();
1211 return False;
1212
1213def testFailureXcpt(sDetails = ''):
1214 """
1215 Reports a failure with exception.
1216 We count these calls and testDone will use them to report PASSED or FAILED.
1217
1218 Returns False so that a return False line can be saved.
1219 """
1220 # Extract exception info.
1221 try:
1222 oType, oValue, oTraceback = sys.exc_info();
1223 except:
1224 oType = oValue, oTraceback = None;
1225 if oType is not None:
1226 sCaller = utils.getCallerName(oTraceback.tb_frame);
1227 sXcpt = ' '.join(traceback.format_exception_only(oType, oValue));
1228 else:
1229 sCaller = utils.getCallerName();
1230 sXcpt = 'No exception at %s' % (sCaller,);
1231
1232 # Use testFailure to do the work.
1233 g_oLock.acquire();
1234 if sDetails == '':
1235 g_oReporter.testFailure('Exception: %s' % (sXcpt,), sCaller);
1236 else:
1237 g_oReporter.testFailure('%s: %s' % (sDetails, sXcpt), sCaller);
1238 g_oLock.release();
1239 return False;
1240
1241def testDone(fSkipped = False):
1242 """
1243 Completes the current test (pops it), logging PASSED / FAILURE.
1244
1245 Returns a tuple with the name of the test and its error count.
1246 """
1247 g_oLock.acquire();
1248 rc = g_oReporter.testDone(fSkipped, utils.getCallerName());
1249 g_oLock.release();
1250 return rc;
1251
1252def testErrorCount():
1253 """
1254 Gets the error count of the current test.
1255
1256 Returns the number of errors.
1257 """
1258 g_oLock.acquire();
1259 cErrors = g_oReporter.testErrorCount();
1260 g_oLock.release();
1261 return cErrors;
1262
1263def testCleanup():
1264 """
1265 Closes all open tests with a generic error condition.
1266
1267 Returns True if no open tests, False if something had to be closed with failure.
1268 """
1269 g_oLock.acquire();
1270 fRc = g_oReporter.testCleanup(utils.getCallerName());
1271 g_oReporter.xmlFlush(fRetry = False, fForce = True);
1272 g_oLock.release();
1273 return fRc;
1274
1275
1276#
1277# Sub XML stuff.
1278#
1279
1280def addSubXmlFile(sFilename):
1281 """
1282 Adds a sub-xml result file to the party.
1283 """
1284 fRc = False;
1285 try:
1286 oSrcFile = utils.openNoInherit(sFilename, 'r');
1287 except IOError, oXcpt:
1288 if oXcpt.errno != errno.ENOENT:
1289 logXcpt('addSubXmlFile(%s)' % (sFilename,));
1290 except:
1291 logXcpt('addSubXmlFile(%s)' % (sFilename,));
1292 else:
1293 try:
1294 oWrapper = FileWrapperTestPipe()
1295 oWrapper.write(oSrcFile.read());
1296 oWrapper.close();
1297 except:
1298 logXcpt('addSubXmlFile(%s)' % (sFilename,));
1299 oSrcFile.close();
1300
1301 return fRc;
1302
1303
1304#
1305# Other useful debugging tools.
1306#
1307
1308def logAllStacks(cFrames = None):
1309 """
1310 Logs the stacks of all python threads.
1311 """
1312 sTsPrf = utils.getTimePrefix();
1313 sCaller = utils.getCallerName();
1314 g_oLock.acquire();
1315
1316 cThread = 0;
1317 for idThread, oStack in sys._current_frames().items(): # >=2.5, a bit ugly - pylint: disable=W0212
1318 try:
1319 if cThread > 0:
1320 g_oReporter.log(1, '', sCaller, sTsPrf);
1321 g_oReporter.log(1, 'Thread %s (%#x)' % (idThread, idThread), sCaller, sTsPrf);
1322 try:
1323 asInfo = traceback.format_stack(oStack, cFrames);
1324 except:
1325 g_oReporter.log(1, ' Stack formatting failed w/ exception', sCaller, sTsPrf);
1326 else:
1327 for sInfo in asInfo:
1328 asLines = sInfo.splitlines();
1329 for sLine in asLines:
1330 g_oReporter.log(1, sLine, sCaller, sTsPrf);
1331 except:
1332 pass;
1333 cThread += 1;
1334
1335 g_oLock.release();
1336 return None;
1337
1338def checkTestManagerConnection():
1339 """
1340 Checks the connection to the test manager.
1341
1342 Returns True if the connection is fine, False if not, None if not remote
1343 reporter.
1344
1345 Note! This as the sideeffect of flushing XML.
1346 """
1347 g_oLock.acquire();
1348 fRc = g_oReporter.xmlFlush(fRetry = False, fForce = True);
1349 g_oLock.release();
1350 return fRc;
1351
1352def flushall():
1353 """
1354 Flushes all output streams, both standard and logger related.
1355 """
1356 try: sys.stdout.flush();
1357 except: pass;
1358 try: sys.stderr.flush();
1359 except: pass;
1360
1361 # Note! Current no logger specific streams to flush.
1362
1363 return True;
1364
1365
1366#
1367# Module initialization.
1368#
1369
1370def _InitReporterModule():
1371 """
1372 Instantiate the test reporter.
1373 """
1374 global g_oReporter, g_sReporterName
1375
1376 g_sReporterName = os.getenv("TESTBOX_REPORTER", "local");
1377 if g_sReporterName == "local":
1378 g_oReporter = LocalReporter();
1379 elif g_sReporterName == "remote":
1380 g_oReporter = RemoteReporter();
1381 else:
1382 print >> sys.stderr, os.path.basename(__file__) + ": Unknown TESTBOX_REPORTER value: '" + g_sReporterName + "'";
1383 raise Exception("Unknown TESTBOX_REPORTER value '" + g_sReporterName + "'");
1384
1385if __name__ != "checker": # pychecker avoidance.
1386 _InitReporterModule();
1387
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