VirtualBox

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

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

tdUnitTest1.py: arg

  • 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 57740 2015-09-14 15:00:12Z 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: 57740 $"
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 '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
379 self.testRunUnitTestsSet(r'^tst*', 'testcase')
380 self.testRunUnitTestsSet(r'^tst*', '.')
381
382 reporter.log('')
383 reporter.log('********************')
384 reporter.log('*** PASSED: %d' % self.cPassed)
385 reporter.log('*** FAILED: %d' % self.cFailed)
386 reporter.log('*** SKIPPED: %d' % self.cSkipped)
387 reporter.log('*** TOTAL: %d' % (self.cPassed + self.cFailed + self.cSkipped))
388
389 return self.cFailed == 0
390
391 #
392 # Test execution helpers.
393 #
394
395 def _figureVersion(self):
396 """ Tries to figure which VBox version this is, setting self.aiVBoxVer. """
397 try:
398 sVer = utils.processOutputChecked(['VBoxManage', '--version'])
399
400 sVer = sVer.strip();
401 sVer = re.sub(r'_BETA.*r', '.', sVer);
402 sVer = re.sub(r'_ALPHA.*r', '.', sVer);
403 sVer = re.sub(r'_RC.*r', '.', sVer);
404 sVer = sVer.replace('r', '.');
405
406 self.aiVBoxVer = [int(sComp) for sComp in sVer.split('.')];
407
408 reporter.log('VBox version: %s' % (self.aiVBoxVer,));
409 except:
410 reporter.logXcpt();
411 return False;
412 return True;
413
414 def _compareVersion(self, aiVer):
415 """
416 Compares the give version string with the vbox version string,
417 returning a result similar to C strcmp(). aiVer is on the right side.
418 """
419 cComponents = min(len(self.aiVBoxVer), len(aiVer));
420 for i in range(cComponents):
421 if self.aiVBoxVer[i] < aiVer[i]:
422 return -1;
423 if self.aiVBoxVer[i] > aiVer[i]:
424 return 1;
425 return len(self.aiVBoxVer) - len(aiVer);
426
427 def _isExcluded(self, sTest, dExclList):
428 """ Checks if the testcase is excluded or not. """
429 if sTest in dExclList:
430 sFullExpr = dExclList[sTest].replace(' ', '').strip();
431 if sFullExpr == '':
432 return True;
433
434 # Consider each exclusion expression. These are generally ranges,
435 # either open ended or closed: "<4.3.51r12345", ">=4.3.0 && <=4.3.4".
436 asExprs = sFullExpr.split(';');
437 for sExpr in asExprs:
438
439 # Split it on the and operator and process each sub expression.
440 fResult = True;
441 for sSubExpr in sExpr.split('&&'):
442 # Split out the comparison operator and the version value.
443 if sSubExpr.startswith('<=') or sSubExpr.startswith('>='):
444 sOp = sSubExpr[:2];
445 sValue = sSubExpr[2:];
446 elif sSubExpr.startswith('<') or sSubExpr.startswith('>') or sSubExpr.startswith('='):
447 sOp = sSubExpr[:1];
448 sValue = sSubExpr[1:];
449 else:
450 sOp = sValue = '';
451
452 # Convert the version value, making sure we've got a valid one.
453 try: aiValue = [int(sComp) for sComp in sValue.replace('r', '.').split('.')];
454 except: aiValue = ();
455 if len(aiValue) == 0 or len(aiValue) > 4:
456 reporter.error('Invalid exclusion expression for %s: "%s" [%s]' % (sTest, sSubExpr, dExclList[sTest]));
457 return True;
458
459 # Do the compare.
460 iCmp = self._compareVersion(aiValue);
461 if sOp == '>=' and iCmp < 0:
462 fResult = False;
463 elif sOp == '>' and iCmp <= 0:
464 fResult = False;
465 elif sOp == '<' and iCmp >= 0:
466 fResult = False;
467 elif sOp == '>=' and iCmp < 0:
468 fResult = False;
469 reporter.log2('iCmp=%s; %s %s %s -> %s' % (iCmp, self.aiVBoxVer, sOp, aiValue, fResult));
470
471 # Did the expression match?
472 if fResult:
473 return True;
474
475 return False;
476
477 def _sudoExecuteSync(self, asArgs):
478 """
479 Executes a sudo child process synchronously.
480 Returns True if the process executed successfully and returned 0,
481 otherwise False is returned.
482 """
483 reporter.log('Executing [sudo]: %s' % (asArgs, ));
484 try:
485 iRc = utils.sudoProcessCall(asArgs, shell = False, close_fds = False);
486 except:
487 reporter.errorXcpt();
488 return False;
489 reporter.log('Exit code [sudo]: %s (%s)' % (iRc, asArgs));
490 return iRc is 0;
491
492 def _hardenedMkDir(self, sPath):
493 """
494 Creates the directory specified sPath (including parents).
495 """
496 reporter.log('_hardenedMkDir: %s' % (sPath,));
497 if utils.getHostOs() in [ 'win', 'os2' ]:
498 os.makedirs(sPath, 0755);
499 else:
500 fRc = self._sudoExecuteSync(['/bin/mkdir', '-p', '-m', '0755', sPath]);
501 if fRc is not True:
502 raise Exception('Failed to create dir "%s".' % (sPath,));
503 return True;
504
505 def _hardenedCopyFile(self, sSrc, sDst, iMode):
506 """
507 Copies a file.
508 """
509 reporter.log('_hardenedCopyFile: %s -> %s (mode: %o)' % (sSrc, sDst, iMode,));
510 if utils.getHostOs() in [ 'win', 'os2' ]:
511 shutil.copyfile(sSrc, sDst);
512 os.chmod(sDst, iMode);
513 else:
514 fRc = self._sudoExecuteSync(['/bin/cp', sSrc, sDst]);
515 if fRc is not True:
516 raise Exception('Failed to copy "%s" to "%s".' % (sSrc, sDst,));
517 fRc = self._sudoExecuteSync(['/bin/chmod', '%o' % (iMode,), sDst]);
518 if fRc is not True:
519 raise Exception('Failed to chmod "%s".' % (sDst,));
520 return True;
521
522 def _hardenedDeleteFile(self, sPath):
523 """
524 Deletes a file.
525 """
526 reporter.log('_hardenedDeleteFile: %s' % (sPath,));
527 if os.path.exists(sPath):
528 if utils.getHostOs() in [ 'win', 'os2' ]:
529 os.remove(sPath);
530 else:
531 fRc = self._sudoExecuteSync(['/bin/rm', sPath]);
532 if fRc is not True:
533 raise Exception('Failed to remove "%s".' % (sPath,));
534 return True;
535
536 def _hardenedRemoveDir(self, sPath):
537 """
538 Removes a directory.
539 """
540 reporter.log('_hardenedRemoveDir: %s' % (sPath,));
541 if os.path.exists(sPath):
542 if utils.getHostOs() in [ 'win', 'os2' ]:
543 os.rmdir(sPath);
544 else:
545 fRc = self._sudoExecuteSync(['/bin/rmdir', sPath]);
546 if fRc is not True:
547 raise Exception('Failed to remove "%s".' % (sPath,));
548 return True;
549
550 def _executeTestCase(self, sName, sFullPath, sTestCaseSubDir, oDevNull): # pylint: disable=R0914
551 """
552 Executes a test case.
553 """
554
555 fSkipped = False;
556
557 #
558 # If hardening is enabled, some test cases and their dependencies
559 # needs to be copied to and execute from the sVBoxInstallRoot
560 # directory in order to work. They also have to be executed as
561 # root, i.e. via sudo.
562 #
563 fHardened = False;
564 asFilesToRemove = []; # Stuff to clean up.
565 asDirsToRemove = []; # Ditto.
566 if sName in self.kasHardened \
567 and self.sUnitTestsPathBase != self.sVBoxInstallRoot:
568
569 sDstDir = os.path.join(self.sVBoxInstallRoot, sTestCaseSubDir);
570 if not os.path.exists(sDstDir):
571 self._hardenedMkDir(sDstDir);
572 asDirsToRemove.append(sDstDir);
573
574 sDst = os.path.join(sDstDir, os.path.basename(sFullPath));
575 self._hardenedCopyFile(sFullPath, sDst, 0755);
576 asFilesToRemove.append(sDst);
577
578 # Copy any associated .dll/.so/.dylib.
579 for sSuff in [ '.dll', '.so', '.dylib' ]:
580 sSrc = os.path.splitext(sFullPath)[0] + sSuff;
581 if os.path.exists(sSrc):
582 sDst = os.path.join(sDstDir, os.path.basename(sSrc));
583 self._hardenedCopyFile(sSrc, sDst, 0644);
584 asFilesToRemove.append(sDst);
585
586 # Copy any associated .r0, .rc and .gc modules.
587 offDriver = sFullPath.rfind('Driver')
588 if offDriver > 0:
589 for sSuff in [ '.r0', 'RC.rc', 'RC.gc' ]:
590 sSrc = sFullPath[:offDriver] + sSuff;
591 if os.path.exists(sSrc):
592 sDst = os.path.join(sDstDir, os.path.basename(sSrc));
593 self._hardenedCopyFile(sSrc, sDst, 0644);
594 asFilesToRemove.append(sDst);
595
596 sFullPath = os.path.join(sDstDir, os.path.basename(sFullPath));
597 fHardened = True;
598
599 #
600 # Set up arguments and environment.
601 #
602 asArgs = [sFullPath,]
603 if sName in self.kdArguments:
604 asArgs.extend(self.kdArguments[sName]);
605
606 os.environ['IPRT_TEST_OMIT_TOP_TEST'] = '1';
607 os.environ['IPRT_TEST_FILE'] = sXmlFile = os.path.join(self.sScratchPath, 'result.xml');
608 if os.path.exists(sXmlFile):
609 try: os.unlink(sXmlFile);
610 except: self._hardenedDeleteFile(sXmlFile);
611
612 #
613 # Execute the test case.
614 #
615 # Windows is confusing output. Trying a few things to get rid of this.
616 # First, flush both stderr and stdout before running the child. Second,
617 # assign the child stderr to stdout. If this doesn't help, we'll have
618 # to capture the child output.
619 #
620 reporter.log('*** Executing %s%s...' % (asArgs, ' [hardened]' if fHardened else ''));
621 try: sys.stdout.flush();
622 except: pass;
623 try: sys.stderr.flush();
624 except: pass;
625 if not self.fDryRun:
626 try:
627 if fHardened:
628 oChild = utils.sudoProcessPopen(asArgs, stdin = oDevNull, stdout = sys.stdout, stderr = sys.stdout);
629 else:
630 oChild = subprocess.Popen( asArgs, stdin = oDevNull, stdout = sys.stdout, stderr = sys.stdout);
631 except:
632 if sName in [ 'tstAsmStructsRC', # 32-bit, may fail to start on 64-bit linux. Just ignore.
633 ]:
634 reporter.logXcpt();
635 fSkipped = True;
636 else:
637 reporter.errorXcpt();
638 iRc = 1023;
639 oChild = None;
640
641 if oChild is not None:
642 self.pidFileAdd(oChild.pid, fSudo = fHardened);
643 iRc = oChild.wait();
644 self.pidFileRemove(oChild.pid);
645 else:
646 iRc = 0;
647
648 #
649 # Clean up
650 #
651 for sPath in asFilesToRemove:
652 self._hardenedDeleteFile(sPath);
653 for sPath in asDirsToRemove:
654 self._hardenedRemoveDir(sPath);
655
656 #
657 # Report.
658 #
659 if os.path.exists(sXmlFile):
660 reporter.addSubXmlFile(sXmlFile);
661 if fHardened:
662 self._hardenedDeleteFile(sXmlFile);
663 else:
664 os.unlink(sXmlFile);
665
666 if iRc == 0:
667 reporter.log('*** %s: exit code %d' % (sFullPath, iRc));
668 self.cPassed += 1
669
670 elif iRc == 4: # RTEXITCODE_SKIPPED
671 reporter.log('*** %s: exit code %d (RTEXITCODE_SKIPPED)' % (sFullPath, iRc));
672 fSkipped = True;
673 self.cSkipped += 1;
674
675 elif fSkipped:
676 reporter.log('*** %s: exit code %d (Skipped)' % (sFullPath, iRc));
677 self.cSkipped += 1;
678
679 else:
680 sName = self.kdExitCodeNames.get(iRc, '');
681 if iRc in self.kdExitCodeNamesWin and utils.getHostOs() == 'win':
682 sName = self.kdExitCodeNamesWin[iRc];
683 if sName != '':
684 sName = ' (%s)' % (sName);
685
686 if iRc != 1:
687 reporter.testFailure('Exit status: %d%s' % (iRc, sName));
688 reporter.log( '!*! %s: exit code %d%s' % (sFullPath, iRc, sName));
689 else:
690 reporter.error('!*! %s: exit code %d%s' % (sFullPath, iRc, sName));
691 self.cFailed += 1
692
693 return fSkipped;
694
695 def testRunUnitTestsSet(self, sTestCasePattern, sTestCaseSubDir):
696 """
697 Run subset of the unit tests set.
698 """
699
700 # Open /dev/null for use as stdin further down.
701 try:
702 oDevNull = open(os.path.devnull, 'w+');
703 except:
704 oDevNull = None;
705
706 # Determin the host OS specific exclusion lists.
707 dTestCasesBuggyForHostOs = self.kdTestCasesBuggyPerOs.get(utils.getHostOs(), []);
708 dTestCasesBuggyForHostOs.update(self.kdTestCasesBuggyPerOs.get(utils.getHostOsDotArch(), []));
709
710 #
711 # Process the file list and run everything looking like a testcase.
712 #
713 for sFilename in sorted(os.listdir(os.path.join(self.sUnitTestsPathBase, sTestCaseSubDir))):
714 # Separate base and suffix and morph the base into something we
715 # can use for reporting and array lookups.
716 sName, sSuffix = os.path.splitext(sFilename);
717 if sTestCaseSubDir != '.':
718 sName = sTestCaseSubDir + '/' + sName;
719
720 # Basic exclusion.
721 if not re.match(sTestCasePattern, sFilename) \
722 or sSuffix in self.kasSuffixBlackList:
723 reporter.log('"%s" is not a test case.' % (sFilename,))
724 continue
725
726 # Check if the testcase is black listed or buggy before executing it.
727 if self._isExcluded(sName, self.kdTestCasesBlackList):
728 # (No testStart/Done or accounting here!)
729 reporter.log('%s: SKIPPED (blacklisted)' % (sName,));
730
731 elif self._isExcluded(sName, self.kdTestCasesBuggy):
732 reporter.testStart(sName);
733 reporter.log('%s: Skipping, buggy in general.' % (sName,));
734 reporter.testDone(fSkipped = True);
735 self.cSkipped += 1;
736
737 elif self._isExcluded(sName, dTestCasesBuggyForHostOs):
738 reporter.testStart(sName);
739 reporter.log('%s: Skipping, buggy on %s.' % (sName, utils.getHostOs(),));
740 reporter.testDone(fSkipped = True);
741 self.cSkipped += 1;
742
743 else:
744 sFullPath = os.path.normpath(os.path.join(self.sUnitTestsPathBase, os.path.join(sTestCaseSubDir, sFilename)));
745 reporter.testStart(sName);
746 try:
747 fSkipped = self._executeTestCase(sName, sFullPath, sTestCaseSubDir, oDevNull);
748 except:
749 reporter.errorXcpt('!*!');
750 self.cFailed += 1;
751 fSkipped = False;
752 reporter.testDone(fSkipped);
753
754
755
756if __name__ == '__main__':
757 sys.exit(tdUnitTest1().main(sys.argv))
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