VirtualBox

source: vbox/trunk/src/VBox/ValidationKit/tests/unittests/tdUnitTest1.py@ 61353

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

tdUnitTest1.py: We should set VBOX_USER_HOME too.

  • Property svn:eol-style set to LF
  • Property svn:executable set to *
  • Property svn:keywords set to Author Date Id Revision
File size: 31.0 KB
Line 
1#!/usr/bin/env python
2# -*- coding: utf-8 -*-
3# $Id: tdUnitTest1.py 61353 2016-06-01 00:59:11Z vboxsync $
4
5"""
6VirtualBox Validation Kit - Unit Tests.
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: 61353 $"
31
32
33# Standard Python imports.
34import os
35import sys
36import re
37import subprocess
38import shutil
39
40
41# Only the main script needs to modify the path.
42try: __file__
43except: __file__ = sys.argv[0];
44g_ksValidationKitDir = os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
45sys.path.append(g_ksValidationKitDir)
46
47# Validation Kit imports.
48from common import utils;
49from testdriver import vbox
50from testdriver import reporter
51
52
53class tdUnitTest1(vbox.TestDriver):
54 """
55 Unit Tests.
56 """
57
58 ## The temporary exclude list.
59 ## @note This shall be empty before we release 4.3!
60 kdTestCasesBuggyPerOs = {
61 'darwin': {
62 'testcase/tstX86-1': '', # 'FSTP M32R, ST0' fails; no idea why.
63 },
64 'linux': {
65 'testcase/tstRTFileAio': '', # See xTracker #8035.
66 },
67 'solaris': {
68 'testcase/tstIntNet-1': '', # Fails opening rge0, probably a generic issue figuring which nic to use.
69 'testcase/tstIprtList': '', # Crashes in the multithreaded test, I think.
70 'testcase/tstRTCritSect': '', # Fairness/whatever issue here.
71 'testcase/tstRTR0MemUserKernelDriver': '', # Failes when kernel to kernel buffers.
72 'testcase/tstRTSemRW': '', # line 338: RTSemRWReleaseRead(hSemRW): got VERR_ACCESS_DENIED
73 'testcase/tstRTStrAlloc': '', # VERR_NO_STR_MEMORY!
74 'testcase/tstRTFileGetSize-1': '', # VERR_DEV_IO_ERROR on /dev/null!
75 },
76 'win': {
77 'testcase/tstFile': '', # ??
78 'testcase/tstIntNet-1': '', # possibly same issue as solaris.
79 'testcase/tstMouseImpl': '', # STATUS_ACCESS_VIOLATION
80 'testcase/tstRTR0ThreadPreemptionDriver': '', # ??
81 'testcase/tstRTPath': '<4.3.51r89894',
82 'testcase/tstRTPipe': '', # ??
83 'testcase/tstRTR0MemUserKernelDriver': '', # ??
84 'testcase/tstRTR0SemMutexDriver': '', # ??
85 'testcase/tstRTStrAlloc': '', # ??
86 'testcase/tstRTStrFormat': '', # ??
87 'testcase/tstRTSystemQueryOsInfo': '', # ??
88 'testcase/tstRTTemp': '', # ??
89 'testcase/tstRTTime': '', # ??
90 'testcase/tstTime-2': '', # Total time differs too much! ... delta=-10859859
91 'testcase/tstUtf8': '', # ??
92 'testcase/tstVMMR0CallHost-2': '', # STATUS_STACK_OVERFLOW
93 'testcase/tstX86-1': '', # Fails on win.x86.
94 'tscpasswd': '', # ??
95 'tstVMREQ': '', # ?? Same as darwin.x86?
96 },
97 'win.x86': {
98 'testcase/tstRTR0TimerDriver': '', # See xTracker #8041.
99 }
100 };
101
102 kdTestCasesBuggy = {
103 'testcase/tstGuestPropSvc': '', # GET_NOTIFICATION fails on testboxlin5.de.oracle.com and others.
104 'testcase/tstRTProcCreateEx': '', # Seen failing on wei01-b6ka-9.de.oracle.com.
105 'testcase/tstTimer': '', # Sometimes fails on linux, not important atm.
106 'testcase/tstGIP-2': '', # 2015-09-10: Fails regularly. E.g. TestSetID 2744205 (testboxsh2),
107 # 2743961 (wei01-b6kc-6). The responsible engineer should reenable
108 # it once it has been fixed.
109 };
110
111 ## The permanent exclude list.
112 # @note Stripped extensions!
113 kdTestCasesBlackList = {
114 'testcase/tstClipboardX11Smoke': '',
115 'testcase/tstFileLock': '',
116 'testcase/tstDisasm-2': '', # without parameters it will disassembler 1GB starting from 0
117 'testcase/tstFileAppendWin-1': '',
118 'testcase/tstDir': '', # useless without parameters
119 'testcase/tstDir-2': '', # useless without parameters
120 'testcase/tstGlobalConfig': '',
121 'testcase/tstHostHardwareLinux': '', # must be killed with CTRL-C
122 'testcase/tstHttp': '', # Talks to outside servers.
123 'testcase/tstRTHttp': '', # parameters required
124 'testcase/tstLdr-2': '', # parameters required
125 'testcase/tstLdr-3': '', # parameters required
126 'testcase/tstLdr': '', # parameters required
127 'testcase/tstLdrLoad': '', # parameters required
128 'testcase/tstMove': '', # parameters required
129 'testcase/tstRTR0Timer': '', # loads 'tstRTR0Timer.r0'
130 'testcase/tstRTR0ThreadDriver': '', # loads 'tstRTR0Thread.r0'
131 'testcase/tstRunTestcases': '', # that's a script like this one
132 'testcase/tstRTReqPool': '', # fails sometimes, testcase buggy
133 'testcase/tstRTS3': '', # parameters required
134 'testcase/tstSDL': '', # graphics test
135 'testcase/tstSupLoadModule': '', # Needs parameters and vboxdrv access. Covered elsewhere.
136 'testcase/tstSeamlessX11': '', # graphics test
137 'testcase/tstTime-3': '', # parameters required
138 'testcase/tstVBoxControl': '', # works only inside a guest
139 'testcase/tstVDCopy': '', # parameters required
140 'tstAnimate': '', # parameters required
141 'testcase/tstAPI': '', # user interaction required
142 'tstCollector': '', # takes forever
143 'testcase/tstHeadless': '', # parameters required
144 'tstHeadless': '', # parameters required
145 'tstMicroRC': '', # required by tstMicro
146 'tstVBoxDbg': '', # interactive test
147 'testcase/tstTestServMgr': '', # some strange xpcom18a4 test, does not work
148 'tstTestServMgr': '', # some strange xpcom18a4 test, does not work
149 'tstPDMAsyncCompletion': '', # parameters required
150 'testcase/tstXptDump': '', # parameters required
151 'tstXptDump': '', # parameters required
152 'testcase/tstnsIFileEnumerator': '', # some strange xpcom18a4 test, does not work
153 'tstnsIFileEnumerator': '', # some strange xpcom18a4 test, does not work
154 'testcase/tstSimpleTypeLib': '', # parameters required
155 'tstSimpleTypeLib': '', # parameters required
156 'testcase/tstTestAtoms': '', # additional test file (words.txt) required
157 'tstTestAtoms': '', # additional test file (words.txt) required
158 'testcase/tstXptLink': '', # parameters required
159 'tstXptLink': '', # parameters required
160 'tstXPCOMCGlue': '', # user interaction required
161 'testcase/tstXPCOMCGlue': '', # user interaction required
162 'testcase/tstCAPIGlue': '', # user interaction required
163 'testcase/tstTestCallTemplates': '', # some strange xpcom18a4 test, segfaults
164 'tstTestCallTemplates': '', # some strange xpcom18a4 test, segfaults
165 'testcase/tstRTFilesystem': '', # parameters required
166 'testcase/tstRTDvm': '', # parameters required
167 # later
168 'testcase/tstIntNetR0': '', # RTSPINLOCK_FLAGS_INTERRUPT_SAFE == RTSPINLOCK_FLAGS_INTERRUPT_UNSAFE
169 # slow stuff
170 'testcase/tstAvl': '', # SLOW!
171 'testcase/tstRTAvl': '', # SLOW! (new name)
172 'testcase/tstVD': '', # 8GB fixed-sized vmdk
173 # failed or hang
174 'testcase/tstCryptoPkcs7Verify': '', # hang
175 'tstOVF': '', # hang (only ancient version, now in new place)
176 'testcase/tstRTLockValidator': '', # Lock validation is not enabled for critical sections
177 'testcase/tstGuestControlSvc': '', # failed: line 288: testHost(&svcTable): expected VINF_SUCCESS, got VERR_NOT_FOUND
178 'testcase/tstRTMemEf': '', # failed w/o error message
179 'testcase/tstSupSem': '', # failed: SRE Timeout Accuracy (ms) : FAILED (1 errors)
180 'testcase/tstCryptoPkcs7Sign': '',# failed: 29330:error:02001002:lib(2):func(1):reason(2):NA:0:fopen('server.pem': '','r')
181 'testcase/tstCompressionBenchmark': '', # failed: error: RTZipBlockCompress failed
182 # for 'RTZipBlock/LZJB' (#4): VERR_NOT_SUPPORTED
183 'testcase/tstLdr-4': '', # failed: Failed to get bits for '/home/vbox/test/tmp/bin/testcase/tstLdrObjR0.r0'/0,
184 # rc=VERR_SYMBOL_VALUE_TOO_BIG. aborting test
185 'tstPDMAsyncCompletionStress': '', # VERR_INVALID_PARAMETER (cbSize = 0)
186 'tstMicro': '', # doesn't work on solaris, fix later if we care.
187 'tstVMM-HwAccm': '', # failed: Only checked AMD-V on linux
188 'tstVMM-HM': '', # failed: Only checked AMD-V on linux
189 'tstVMMFork': '', # failed: xtracker 6171
190 'tstTestFactory': '', # some strange xpcom18a4 test, does not work
191 'testcase/tstRTSemXRoads': '', # sporadically failed: Traffic - 8 threads per direction, 10 sec : FAILED (8 errors)
192 'tstVBoxAPILinux': '', # creates VirtualBox directories for root user because of sudo (should be in vbox)
193 'testcase/tstVMStructDTrace': '', # This is a D-script generator.
194 'tstVMStructRC': '', # This is a C-code generator.
195 'tstDeviceStructSizeRC': '', # This is a C-code generator.
196 'testcase/tstTSC': '', # Doesn't test anything and might fail with HT or/and too many cores.
197 'testcase/tstOpenUSBDev': '', # Not a useful testcase.
198 };
199
200 # Suffix exclude list.
201 kasSuffixBlackList = [
202 '.r0',
203 '.gc',
204 '.debug',
205 '.rel',
206 '.sys',
207 '.ko',
208 '.o',
209 '.obj',
210 '.lib',
211 '.a',
212 '.so',
213 '.dll',
214 '.dylib',
215 '.tmp',
216 '.log',
217 '.py',
218 '.pyc',
219 '.pyo',
220 '.pdb',
221 '.dSYM',
222 '.sym',
223 ];
224
225 ## The exclude list.
226 # @note Stripped extensions!
227 kasHardened = [
228 "testcase/tstIntNet-1",
229 "testcase/tstR0ThreadPreemptionDriver", # VBox 4.3
230 "testcase/tstRTR0ThreadPreemptionDriver",
231 "testcase/tstRTR0MemUserKernelDriver",
232 "testcase/tstRTR0SemMutexDriver",
233 "testcase/tstRTR0TimerDriver",
234 "testcase/tstRTR0ThreadDriver",
235 'testcase/tstRTR0DbgKrnlInfoDriver',
236 "tstInt",
237 "tstVMM",
238 "tstVMMFork",
239 "tstVMREQ",
240 'testcase/tstCFGM',
241 'testcase/tstContiguous',
242 'testcase/tstGetPagingMode',
243 'testcase/tstGIP-2',
244 'testcase/tstInit',
245 'testcase/tstLow',
246 'testcase/tstMMHyperHeap',
247 'testcase/tstPage',
248 'testcase/tstPin',
249 'testcase/tstRTTime', 'testcase/tstTime', # GIP test case.
250 'testcase/tstSSM',
251 'testcase/tstSupSem-Zombie',
252 ]
253
254 ## Argument lists
255 kdArguments = {
256 'testcase/tstbntest': [ '-out', os.devnull, ], # Very noisy.
257 };
258
259
260 ## Status code translations.
261 ## @{
262 kdExitCodeNames = {
263 0: 'RTEXITCODE_SUCCESS',
264 1: 'RTEXITCODE_FAILURE',
265 2: 'RTEXITCODE_SYNTAX',
266 3: 'RTEXITCODE_INIT',
267 4: 'RTEXITCODE_SKIPPED',
268 };
269 kdExitCodeNamesWin = {
270 -1073741515: 'STATUS_DLL_NOT_FOUND',
271 -1073741512: 'STATUS_ORDINAL_NOT_FOUND',
272 -1073741511: 'STATUS_ENTRYPOINT_NOT_FOUND',
273 -1073741502: 'STATUS_DLL_INIT_FAILED',
274 -1073741500: 'STATUS_UNHANDLED_EXCEPTION',
275 -1073741499: 'STATUS_APP_INIT_FAILURE',
276 -1073741819: 'STATUS_ACCESS_VIOLATION',
277 -1073741571: 'STATUS_STACK_OVERFLOW',
278 };
279 ## @}
280
281 def __init__(self):
282 """
283 Reinitialize child class instance.
284 """
285 vbox.TestDriver.__init__(self)
286 self.oTestVmSet = None;
287
288 self.sVBoxInstallRoot = None
289
290 self.cSkipped = 0
291 self.cPassed = 0
292 self.cFailed = 0
293
294 self.sUnitTestsPathBase = None
295 self.sExeSuff = '.exe' if utils.getHostOs() in [ 'win', 'dos', 'os2' ] else '';
296
297 self.aiVBoxVer = (4, 3, 0, 0);
298
299 # For testing testcase logic.
300 self.fDryRun = False;
301
302
303 def _detectPaths(self):
304 """
305 Internal worker for actionVerify and actionExecute that detects paths.
306
307 This sets sVBoxInstallRoot and sUnitTestsPathBase and returns True/False.
308 """
309
310 #
311 # We need a VBox install (/ build) to test.
312 #
313 if False:
314 if not self.importVBoxApi():
315 reporter.error('Unabled to import the VBox Python API.')
316 return False
317 else:
318 self._detectBuild();
319 if self.oBuild is None:
320 reporter.error('Unabled to detect the VBox build.');
321 return False;
322
323 #
324 # Where are the files installed?
325 # Solaris requires special handling because of it's multi arch subdirs.
326 #
327 self.sVBoxInstallRoot = self.oBuild.sInstallPath
328 if not self.oBuild.isDevBuild() and utils.getHostOs() == 'solaris':
329 sArchDir = utils.getHostArch();
330 if sArchDir == 'x86': sArchDir = 'i386';
331 self.sVBoxInstallRoot = os.path.join(self.sVBoxInstallRoot, sArchDir);
332
333 # Add the installation root to the PATH on windows so we can get DLLs from it.
334 if utils.getHostOs() == 'win':
335 sPathName = 'PATH';
336 if not sPathName in os.environ:
337 sPathName = 'Path';
338 sPath = os.environ.get(sPathName, '.');
339 if len(sPath) > 0 and sPath[-1] != ';':
340 sPath += ';';
341 os.environ[sPathName] = sPath + self.sVBoxInstallRoot + ';';
342
343 #
344 # The unittests are generally not installed, so look for them.
345 #
346 sBinOrDist = 'dist' if utils.getHostOs() in [ 'darwin', ] else 'bin';
347 asCandidates = [
348 self.oBuild.sInstallPath,
349 os.path.join(self.sScratchPath, sBinOrDist + '.' + utils.getHostArch()),
350 os.path.join(self.sScratchPath, sBinOrDist, utils.getHostArch()),
351 os.path.join(self.sScratchPath, sBinOrDist),
352 ];
353 if utils.getHostOs() == 'darwin':
354 for i in range(1, len(asCandidates)):
355 asCandidates[i] = os.path.join(asCandidates[i], 'VirtualBox.app', 'Contents', 'MacOS');
356
357 for sCandidat in asCandidates:
358 if os.path.exists(os.path.join(sCandidat, 'testcase', 'tstVMStructSize' + self.sExeSuff)):
359 self.sUnitTestsPathBase = sCandidat;
360 return True;
361
362 reporter.error('Unable to find unit test dir. Candidates: %s' % (asCandidates,))
363 return False;
364
365 #
366 # Overridden methods.
367 #
368
369 def actionVerify(self):
370 return self._detectPaths();
371
372 def actionExecute(self):
373
374 if self.sUnitTestsPathBase is None and self._detectPaths():
375 return False;
376
377 self._figureVersion();
378 self._makeEnvironmentChanges();
379
380 self.testRunUnitTestsSet(r'^tst*', 'testcase')
381 self.testRunUnitTestsSet(r'^tst*', '.')
382
383 reporter.log('')
384 reporter.log('********************')
385 reporter.log('*** PASSED: %d' % self.cPassed)
386 reporter.log('*** FAILED: %d' % self.cFailed)
387 reporter.log('*** SKIPPED: %d' % self.cSkipped)
388 reporter.log('*** TOTAL: %d' % (self.cPassed + self.cFailed + self.cSkipped))
389
390 return self.cFailed == 0
391
392 #
393 # Test execution helpers.
394 #
395
396 def _figureVersion(self):
397 """ Tries to figure which VBox version this is, setting self.aiVBoxVer. """
398 try:
399 sVer = utils.processOutputChecked(['VBoxManage', '--version'])
400
401 sVer = sVer.strip();
402 sVer = re.sub(r'_BETA.*r', '.', sVer);
403 sVer = re.sub(r'_ALPHA.*r', '.', sVer);
404 sVer = re.sub(r'_RC.*r', '.', sVer);
405 sVer = sVer.replace('r', '.');
406
407 self.aiVBoxVer = [int(sComp) for sComp in sVer.split('.')];
408
409 reporter.log('VBox version: %s' % (self.aiVBoxVer,));
410 except:
411 reporter.logXcpt();
412 return False;
413 return True;
414
415 def _compareVersion(self, aiVer):
416 """
417 Compares the give version string with the vbox version string,
418 returning a result similar to C strcmp(). aiVer is on the right side.
419 """
420 cComponents = min(len(self.aiVBoxVer), len(aiVer));
421 for i in range(cComponents):
422 if self.aiVBoxVer[i] < aiVer[i]:
423 return -1;
424 if self.aiVBoxVer[i] > aiVer[i]:
425 return 1;
426 return len(self.aiVBoxVer) - len(aiVer);
427
428 def _isExcluded(self, sTest, dExclList):
429 """ Checks if the testcase is excluded or not. """
430 if sTest in dExclList:
431 sFullExpr = dExclList[sTest].replace(' ', '').strip();
432 if sFullExpr == '':
433 return True;
434
435 # Consider each exclusion expression. These are generally ranges,
436 # either open ended or closed: "<4.3.51r12345", ">=4.3.0 && <=4.3.4".
437 asExprs = sFullExpr.split(';');
438 for sExpr in asExprs:
439
440 # Split it on the and operator and process each sub expression.
441 fResult = True;
442 for sSubExpr in sExpr.split('&&'):
443 # Split out the comparison operator and the version value.
444 if sSubExpr.startswith('<=') or sSubExpr.startswith('>='):
445 sOp = sSubExpr[:2];
446 sValue = sSubExpr[2:];
447 elif sSubExpr.startswith('<') or sSubExpr.startswith('>') or sSubExpr.startswith('='):
448 sOp = sSubExpr[:1];
449 sValue = sSubExpr[1:];
450 else:
451 sOp = sValue = '';
452
453 # Convert the version value, making sure we've got a valid one.
454 try: aiValue = [int(sComp) for sComp in sValue.replace('r', '.').split('.')];
455 except: aiValue = ();
456 if len(aiValue) == 0 or len(aiValue) > 4:
457 reporter.error('Invalid exclusion expression for %s: "%s" [%s]' % (sTest, sSubExpr, dExclList[sTest]));
458 return True;
459
460 # Do the compare.
461 iCmp = self._compareVersion(aiValue);
462 if sOp == '>=' and iCmp < 0:
463 fResult = False;
464 elif sOp == '>' and iCmp <= 0:
465 fResult = False;
466 elif sOp == '<' and iCmp >= 0:
467 fResult = False;
468 elif sOp == '>=' and iCmp < 0:
469 fResult = False;
470 reporter.log2('iCmp=%s; %s %s %s -> %s' % (iCmp, self.aiVBoxVer, sOp, aiValue, fResult));
471
472 # Did the expression match?
473 if fResult:
474 return True;
475
476 return False;
477
478 def _sudoExecuteSync(self, asArgs):
479 """
480 Executes a sudo child process synchronously.
481 Returns True if the process executed successfully and returned 0,
482 otherwise False is returned.
483 """
484 reporter.log('Executing [sudo]: %s' % (asArgs, ));
485 try:
486 iRc = utils.sudoProcessCall(asArgs, shell = False, close_fds = False);
487 except:
488 reporter.errorXcpt();
489 return False;
490 reporter.log('Exit code [sudo]: %s (%s)' % (iRc, asArgs));
491 return iRc is 0;
492
493 def _hardenedMkDir(self, sPath):
494 """
495 Creates the directory specified sPath (including parents).
496 """
497 reporter.log('_hardenedMkDir: %s' % (sPath,));
498 if utils.getHostOs() in [ 'win', 'os2' ]:
499 os.makedirs(sPath, 0755);
500 else:
501 fRc = self._sudoExecuteSync(['/bin/mkdir', '-p', '-m', '0755', sPath]);
502 if fRc is not True:
503 raise Exception('Failed to create dir "%s".' % (sPath,));
504 return True;
505
506 def _hardenedCopyFile(self, sSrc, sDst, iMode):
507 """
508 Copies a file.
509 """
510 reporter.log('_hardenedCopyFile: %s -> %s (mode: %o)' % (sSrc, sDst, iMode,));
511 if utils.getHostOs() in [ 'win', 'os2' ]:
512 shutil.copyfile(sSrc, sDst);
513 os.chmod(sDst, iMode);
514 else:
515 fRc = self._sudoExecuteSync(['/bin/cp', sSrc, sDst]);
516 if fRc is not True:
517 raise Exception('Failed to copy "%s" to "%s".' % (sSrc, sDst,));
518 fRc = self._sudoExecuteSync(['/bin/chmod', '%o' % (iMode,), sDst]);
519 if fRc is not True:
520 raise Exception('Failed to chmod "%s".' % (sDst,));
521 return True;
522
523 def _hardenedDeleteFile(self, sPath):
524 """
525 Deletes a file.
526 """
527 reporter.log('_hardenedDeleteFile: %s' % (sPath,));
528 if os.path.exists(sPath):
529 if utils.getHostOs() in [ 'win', 'os2' ]:
530 os.remove(sPath);
531 else:
532 fRc = self._sudoExecuteSync(['/bin/rm', sPath]);
533 if fRc is not True:
534 raise Exception('Failed to remove "%s".' % (sPath,));
535 return True;
536
537 def _hardenedRemoveDir(self, sPath):
538 """
539 Removes a directory.
540 """
541 reporter.log('_hardenedRemoveDir: %s' % (sPath,));
542 if os.path.exists(sPath):
543 if utils.getHostOs() in [ 'win', 'os2' ]:
544 os.rmdir(sPath);
545 else:
546 fRc = self._sudoExecuteSync(['/bin/rmdir', sPath]);
547 if fRc is not True:
548 raise Exception('Failed to remove "%s".' % (sPath,));
549 return True;
550
551 def _executeTestCase(self, sName, sFullPath, sTestCaseSubDir, oDevNull): # pylint: disable=R0914
552 """
553 Executes a test case.
554 """
555
556 fSkipped = False;
557
558 #
559 # If hardening is enabled, some test cases and their dependencies
560 # needs to be copied to and execute from the sVBoxInstallRoot
561 # directory in order to work. They also have to be executed as
562 # root, i.e. via sudo.
563 #
564 fHardened = False;
565 asFilesToRemove = []; # Stuff to clean up.
566 asDirsToRemove = []; # Ditto.
567 if sName in self.kasHardened \
568 and self.sUnitTestsPathBase != self.sVBoxInstallRoot:
569
570 sDstDir = os.path.join(self.sVBoxInstallRoot, sTestCaseSubDir);
571 if not os.path.exists(sDstDir):
572 self._hardenedMkDir(sDstDir);
573 asDirsToRemove.append(sDstDir);
574
575 sDst = os.path.join(sDstDir, os.path.basename(sFullPath));
576 self._hardenedCopyFile(sFullPath, sDst, 0755);
577 asFilesToRemove.append(sDst);
578
579 # Copy any associated .dll/.so/.dylib.
580 for sSuff in [ '.dll', '.so', '.dylib' ]:
581 sSrc = os.path.splitext(sFullPath)[0] + sSuff;
582 if os.path.exists(sSrc):
583 sDst = os.path.join(sDstDir, os.path.basename(sSrc));
584 self._hardenedCopyFile(sSrc, sDst, 0644);
585 asFilesToRemove.append(sDst);
586
587 # Copy any associated .r0, .rc and .gc modules.
588 offDriver = sFullPath.rfind('Driver')
589 if offDriver > 0:
590 for sSuff in [ '.r0', 'RC.rc', 'RC.gc' ]:
591 sSrc = sFullPath[:offDriver] + sSuff;
592 if os.path.exists(sSrc):
593 sDst = os.path.join(sDstDir, os.path.basename(sSrc));
594 self._hardenedCopyFile(sSrc, sDst, 0644);
595 asFilesToRemove.append(sDst);
596
597 sFullPath = os.path.join(sDstDir, os.path.basename(sFullPath));
598 fHardened = True;
599
600 #
601 # Set up arguments and environment.
602 #
603 asArgs = [sFullPath,]
604 if sName in self.kdArguments:
605 asArgs.extend(self.kdArguments[sName]);
606
607 os.environ['IPRT_TEST_OMIT_TOP_TEST'] = '1';
608 os.environ['IPRT_TEST_FILE'] = sXmlFile = os.path.join(self.sScratchPath, 'result.xml');
609 if os.path.exists(sXmlFile):
610 try: os.unlink(sXmlFile);
611 except: self._hardenedDeleteFile(sXmlFile);
612
613 #
614 # Execute the test case.
615 #
616 # Windows is confusing output. Trying a few things to get rid of this.
617 # First, flush both stderr and stdout before running the child. Second,
618 # assign the child stderr to stdout. If this doesn't help, we'll have
619 # to capture the child output.
620 #
621 reporter.log('*** Executing %s%s...' % (asArgs, ' [hardened]' if fHardened else ''));
622 try: sys.stdout.flush();
623 except: pass;
624 try: sys.stderr.flush();
625 except: pass;
626 if not self.fDryRun:
627 try:
628 if fHardened:
629 oChild = utils.sudoProcessPopen(asArgs, stdin = oDevNull, stdout = sys.stdout, stderr = sys.stdout);
630 else:
631 oChild = subprocess.Popen( asArgs, stdin = oDevNull, stdout = sys.stdout, stderr = sys.stdout);
632 except:
633 if sName in [ 'tstAsmStructsRC', # 32-bit, may fail to start on 64-bit linux. Just ignore.
634 ]:
635 reporter.logXcpt();
636 fSkipped = True;
637 else:
638 reporter.errorXcpt();
639 iRc = 1023;
640 oChild = None;
641
642 if oChild is not None:
643 self.pidFileAdd(oChild.pid, fSudo = fHardened);
644 iRc = oChild.wait();
645 self.pidFileRemove(oChild.pid);
646 else:
647 iRc = 0;
648
649 #
650 # Clean up
651 #
652 for sPath in asFilesToRemove:
653 self._hardenedDeleteFile(sPath);
654 for sPath in asDirsToRemove:
655 self._hardenedRemoveDir(sPath);
656
657 #
658 # Report.
659 #
660 if os.path.exists(sXmlFile):
661 reporter.addSubXmlFile(sXmlFile);
662 if fHardened:
663 self._hardenedDeleteFile(sXmlFile);
664 else:
665 os.unlink(sXmlFile);
666
667 if iRc == 0:
668 reporter.log('*** %s: exit code %d' % (sFullPath, iRc));
669 self.cPassed += 1
670
671 elif iRc == 4: # RTEXITCODE_SKIPPED
672 reporter.log('*** %s: exit code %d (RTEXITCODE_SKIPPED)' % (sFullPath, iRc));
673 fSkipped = True;
674 self.cSkipped += 1;
675
676 elif fSkipped:
677 reporter.log('*** %s: exit code %d (Skipped)' % (sFullPath, iRc));
678 self.cSkipped += 1;
679
680 else:
681 sName = self.kdExitCodeNames.get(iRc, '');
682 if iRc in self.kdExitCodeNamesWin and utils.getHostOs() == 'win':
683 sName = self.kdExitCodeNamesWin[iRc];
684 if sName != '':
685 sName = ' (%s)' % (sName);
686
687 if iRc != 1:
688 reporter.testFailure('Exit status: %d%s' % (iRc, sName));
689 reporter.log( '!*! %s: exit code %d%s' % (sFullPath, iRc, sName));
690 else:
691 reporter.error('!*! %s: exit code %d%s' % (sFullPath, iRc, sName));
692 self.cFailed += 1
693
694 return fSkipped;
695
696 def testRunUnitTestsSet(self, sTestCasePattern, sTestCaseSubDir):
697 """
698 Run subset of the unit tests set.
699 """
700
701 # Open /dev/null for use as stdin further down.
702 try:
703 oDevNull = open(os.path.devnull, 'w+');
704 except:
705 oDevNull = None;
706
707 # Determin the host OS specific exclusion lists.
708 dTestCasesBuggyForHostOs = self.kdTestCasesBuggyPerOs.get(utils.getHostOs(), []);
709 dTestCasesBuggyForHostOs.update(self.kdTestCasesBuggyPerOs.get(utils.getHostOsDotArch(), []));
710
711 #
712 # Process the file list and run everything looking like a testcase.
713 #
714 for sFilename in sorted(os.listdir(os.path.join(self.sUnitTestsPathBase, sTestCaseSubDir))):
715 # Separate base and suffix and morph the base into something we
716 # can use for reporting and array lookups.
717 sName, sSuffix = os.path.splitext(sFilename);
718 if sTestCaseSubDir != '.':
719 sName = sTestCaseSubDir + '/' + sName;
720
721 # Basic exclusion.
722 if not re.match(sTestCasePattern, sFilename) \
723 or sSuffix in self.kasSuffixBlackList:
724 reporter.log('"%s" is not a test case.' % (sFilename,))
725 continue
726
727 # Check if the testcase is black listed or buggy before executing it.
728 if self._isExcluded(sName, self.kdTestCasesBlackList):
729 # (No testStart/Done or accounting here!)
730 reporter.log('%s: SKIPPED (blacklisted)' % (sName,));
731
732 elif self._isExcluded(sName, self.kdTestCasesBuggy):
733 reporter.testStart(sName);
734 reporter.log('%s: Skipping, buggy in general.' % (sName,));
735 reporter.testDone(fSkipped = True);
736 self.cSkipped += 1;
737
738 elif self._isExcluded(sName, dTestCasesBuggyForHostOs):
739 reporter.testStart(sName);
740 reporter.log('%s: Skipping, buggy on %s.' % (sName, utils.getHostOs(),));
741 reporter.testDone(fSkipped = True);
742 self.cSkipped += 1;
743
744 else:
745 sFullPath = os.path.normpath(os.path.join(self.sUnitTestsPathBase, os.path.join(sTestCaseSubDir, sFilename)));
746 reporter.testStart(sName);
747 try:
748 fSkipped = self._executeTestCase(sName, sFullPath, sTestCaseSubDir, oDevNull);
749 except:
750 reporter.errorXcpt('!*!');
751 self.cFailed += 1;
752 fSkipped = False;
753 reporter.testDone(fSkipped);
754
755
756
757if __name__ == '__main__':
758 sys.exit(tdUnitTest1().main(sys.argv))
Note: See TracBrowser for help on using the repository browser.

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