VirtualBox

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

Last change on this file since 67787 was 65963, checked in by vboxsync, 8 years ago

ValidationKit/tests: pylint 2.0.0 fixes.

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