VirtualBox

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

Last change on this file since 78351 was 76553, checked in by vboxsync, 6 years ago

scm --update-copyright-year

  • Property svn:eol-style set to LF
  • Property svn:executable set to *
  • Property svn:keywords set to Author Date Id Revision
File size: 32.4 KB
Line 
1#!/usr/bin/env python
2# -*- coding: utf-8 -*-
3# $Id: tdUnitTest1.py 76553 2019-01-01 01:45:53Z vboxsync $
4
5"""
6VirtualBox Validation Kit - Unit Tests.
7"""
8
9__copyright__ = \
10"""
11Copyright (C) 2010-2019 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: 76553 $"
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/tstOVF': '', # Creates mess when fails, needs to be run in a separate test.
184 'testcase/tstRTLockValidator': '', # Lock validation is not enabled for critical sections
185 'testcase/tstGuestControlSvc': '', # failed: line 288: testHost(&svcTable): expected VINF_SUCCESS, got VERR_NOT_FOUND
186 'testcase/tstRTMemEf': '', # failed w/o error message
187 'testcase/tstSupSem': '', # failed: SRE Timeout Accuracy (ms) : FAILED (1 errors)
188 'testcase/tstCryptoPkcs7Sign': '',# failed: 29330:error:02001002:lib(2):func(1):reason(2):NA:0:fopen('server.pem': '','r')
189 'testcase/tstCompressionBenchmark': '', # failed: error: RTZipBlockCompress failed
190 # for 'RTZipBlock/LZJB' (#4): VERR_NOT_SUPPORTED
191 'tstPDMAsyncCompletionStress': '', # VERR_INVALID_PARAMETER (cbSize = 0)
192 'tstMicro': '', # doesn't work on solaris, fix later if we care.
193 'tstVMM-HwAccm': '', # failed: Only checked AMD-V on linux
194 'tstVMM-HM': '', # failed: Only checked AMD-V on linux
195 'tstVMMFork': '', # failed: xtracker 6171
196 'tstTestFactory': '', # some strange xpcom18a4 test, does not work
197 'testcase/tstRTSemXRoads': '', # sporadically failed: Traffic - 8 threads per direction, 10 sec : FAILED (8 errors)
198 'tstVBoxAPILinux': '', # creates VirtualBox directories for root user because of sudo (should be in vbox)
199 'testcase/tstVMStructDTrace': '', # This is a D-script generator.
200 'tstVMStructRC': '', # This is a C-code generator.
201 'tstDeviceStructSizeRC': '', # This is a C-code generator.
202 'testcase/tstTSC': '', # Doesn't test anything and might fail with HT or/and too many cores.
203 'testcase/tstOpenUSBDev': '', # Not a useful testcase.
204 'testcase/tstX86-1': '', # Really more guest side.
205 'testcase/tstX86-FpuSaveRestore': '', # Experiments, could be useful for the guest not the host.
206 'tstAsmStructsRC': '', # Testcase run during build time (fails to find libstdc++.so.6 on some
207 # Solaris testboxes).
208 };
209
210 # Suffix exclude list.
211 kasSuffixBlackList = [
212 '.r0',
213 '.gc',
214 '.debug',
215 '.rel',
216 '.sys',
217 '.ko',
218 '.o',
219 '.obj',
220 '.lib',
221 '.a',
222 '.so',
223 '.dll',
224 '.dylib',
225 '.tmp',
226 '.log',
227 '.py',
228 '.pyc',
229 '.pyo',
230 '.pdb',
231 '.dSYM',
232 '.sym',
233 ];
234
235 ## The exclude list.
236 # @note Stripped extensions!
237 kasHardened = [
238 "testcase/tstIntNet-1",
239 "testcase/tstR0ThreadPreemptionDriver", # VBox 4.3
240 "testcase/tstRTR0ThreadPreemptionDriver",
241 "testcase/tstRTR0MemUserKernelDriver",
242 "testcase/tstRTR0SemMutexDriver",
243 "testcase/tstRTR0TimerDriver",
244 "testcase/tstRTR0ThreadDriver",
245 'testcase/tstRTR0DbgKrnlInfoDriver',
246 "tstInt",
247 "tstVMM",
248 "tstVMMFork",
249 "tstVMREQ",
250 'testcase/tstCFGM',
251 'testcase/tstContiguous',
252 'testcase/tstGetPagingMode',
253 'testcase/tstGIP-2',
254 'testcase/tstInit',
255 'testcase/tstLow',
256 'testcase/tstMMHyperHeap',
257 'testcase/tstPage',
258 'testcase/tstPin',
259 'testcase/tstRTTime', 'testcase/tstTime', # GIP test case.
260 'testcase/tstSSM',
261 'testcase/tstSupSem-Zombie',
262 ]
263
264 ## Argument lists
265 kdArguments = {
266 'testcase/tstbntest': [ '-out', os.devnull, ], # Very noisy.
267 };
268
269
270 ## Status code translations.
271 ## @{
272 kdExitCodeNames = {
273 0: 'RTEXITCODE_SUCCESS',
274 1: 'RTEXITCODE_FAILURE',
275 2: 'RTEXITCODE_SYNTAX',
276 3: 'RTEXITCODE_INIT',
277 4: 'RTEXITCODE_SKIPPED',
278 };
279 kdExitCodeNamesWin = {
280 -1073741515: 'STATUS_DLL_NOT_FOUND',
281 -1073741512: 'STATUS_ORDINAL_NOT_FOUND',
282 -1073741511: 'STATUS_ENTRYPOINT_NOT_FOUND',
283 -1073741502: 'STATUS_DLL_INIT_FAILED',
284 -1073741500: 'STATUS_UNHANDLED_EXCEPTION',
285 -1073741499: 'STATUS_APP_INIT_FAILURE',
286 -1073741819: 'STATUS_ACCESS_VIOLATION',
287 -1073741571: 'STATUS_STACK_OVERFLOW',
288 };
289 ## @}
290
291 def __init__(self):
292 """
293 Reinitialize child class instance.
294 """
295 vbox.TestDriver.__init__(self)
296 self.oTestVmSet = None;
297
298 self.sVBoxInstallRoot = None
299
300 self.cSkipped = 0
301 self.cPassed = 0
302 self.cFailed = 0
303
304 self.sUnitTestsPathBase = None
305 self.sExeSuff = '.exe' if utils.getHostOs() in [ 'win', 'dos', 'os2' ] else '';
306
307 self.aiVBoxVer = (4, 3, 0, 0);
308
309 # For testing testcase logic.
310 self.fDryRun = False;
311
312
313 def _detectPaths(self):
314 """
315 Internal worker for actionVerify and actionExecute that detects paths.
316
317 This sets sVBoxInstallRoot and sUnitTestsPathBase and returns True/False.
318 """
319
320 #
321 # We need a VBox install (/ build) to test.
322 #
323 if False is True:
324 if not self.importVBoxApi():
325 reporter.error('Unabled to import the VBox Python API.')
326 return False
327 else:
328 self._detectBuild();
329 if self.oBuild is None:
330 reporter.error('Unabled to detect the VBox build.');
331 return False;
332
333 #
334 # Where are the files installed?
335 # Solaris requires special handling because of it's multi arch subdirs.
336 #
337 self.sVBoxInstallRoot = self.oBuild.sInstallPath
338 if not self.oBuild.isDevBuild() and utils.getHostOs() == 'solaris':
339 sArchDir = utils.getHostArch();
340 if sArchDir == 'x86': sArchDir = 'i386';
341 self.sVBoxInstallRoot = os.path.join(self.sVBoxInstallRoot, sArchDir);
342
343 # Add the installation root to the PATH on windows so we can get DLLs from it.
344 if utils.getHostOs() == 'win':
345 sPathName = 'PATH';
346 if not sPathName in os.environ:
347 sPathName = 'Path';
348 sPath = os.environ.get(sPathName, '.');
349 if sPath and sPath[-1] != ';':
350 sPath += ';';
351 os.environ[sPathName] = sPath + self.sVBoxInstallRoot + ';';
352
353 #
354 # The unittests are generally not installed, so look for them.
355 #
356 sBinOrDist = 'dist' if utils.getHostOs() in [ 'darwin', ] else 'bin';
357 asCandidates = [
358 self.oBuild.sInstallPath,
359 os.path.join(self.sScratchPath, utils.getHostOsDotArch(), self.oBuild.sType, sBinOrDist),
360 os.path.join(self.sScratchPath, utils.getHostOsDotArch(), 'release', sBinOrDist),
361 os.path.join(self.sScratchPath, utils.getHostOsDotArch(), 'debug', sBinOrDist),
362 os.path.join(self.sScratchPath, utils.getHostOsDotArch(), 'strict', sBinOrDist),
363 os.path.join(self.sScratchPath, utils.getHostOsDotArch(), 'dbgopt', sBinOrDist),
364 os.path.join(self.sScratchPath, utils.getHostOsDotArch(), 'profile', sBinOrDist),
365 os.path.join(self.sScratchPath, sBinOrDist + '.' + utils.getHostArch()),
366 os.path.join(self.sScratchPath, sBinOrDist, utils.getHostArch()),
367 os.path.join(self.sScratchPath, sBinOrDist),
368 ];
369 if utils.getHostOs() == 'darwin':
370 for i in range(1, len(asCandidates)):
371 asCandidates[i] = os.path.join(asCandidates[i], 'VirtualBox.app', 'Contents', 'MacOS');
372
373 for sCandidat in asCandidates:
374 if os.path.exists(os.path.join(sCandidat, 'testcase', 'tstVMStructSize' + self.sExeSuff)):
375 self.sUnitTestsPathBase = sCandidat;
376 return True;
377
378 reporter.error('Unable to find unit test dir. Candidates: %s' % (asCandidates,))
379 return False;
380
381 #
382 # Overridden methods.
383 #
384
385 def actionVerify(self):
386 return self._detectPaths();
387
388 def actionExecute(self):
389
390 if self.sUnitTestsPathBase is None and self._detectPaths():
391 return False;
392
393 self._figureVersion();
394 self._makeEnvironmentChanges();
395
396 self.testRunUnitTestsSet(r'^tst*', 'testcase')
397 self.testRunUnitTestsSet(r'^tst*', '.')
398
399 reporter.log('')
400 reporter.log('********************')
401 reporter.log('*** PASSED: %d' % self.cPassed)
402 reporter.log('*** FAILED: %d' % self.cFailed)
403 reporter.log('*** SKIPPED: %d' % self.cSkipped)
404 reporter.log('*** TOTAL: %d' % (self.cPassed + self.cFailed + self.cSkipped))
405
406 return self.cFailed == 0
407
408 #
409 # Test execution helpers.
410 #
411
412 def _figureVersion(self):
413 """ Tries to figure which VBox version this is, setting self.aiVBoxVer. """
414 try:
415 sVer = utils.processOutputChecked(['VBoxManage', '--version'])
416
417 sVer = sVer.strip();
418 sVer = re.sub(r'_BETA.*r', '.', sVer);
419 sVer = re.sub(r'_ALPHA.*r', '.', sVer);
420 sVer = re.sub(r'_RC.*r', '.', sVer);
421 sVer = sVer.replace('r', '.');
422
423 self.aiVBoxVer = [int(sComp) for sComp in sVer.split('.')];
424
425 reporter.log('VBox version: %s' % (self.aiVBoxVer,));
426 except:
427 reporter.logXcpt();
428 return False;
429 return True;
430
431 def _compareVersion(self, aiVer):
432 """
433 Compares the give version string with the vbox version string,
434 returning a result similar to C strcmp(). aiVer is on the right side.
435 """
436 cComponents = min(len(self.aiVBoxVer), len(aiVer));
437 for i in range(cComponents):
438 if self.aiVBoxVer[i] < aiVer[i]:
439 return -1;
440 if self.aiVBoxVer[i] > aiVer[i]:
441 return 1;
442 return len(self.aiVBoxVer) - len(aiVer);
443
444 def _isExcluded(self, sTest, dExclList):
445 """ Checks if the testcase is excluded or not. """
446 if sTest in dExclList:
447 sFullExpr = dExclList[sTest].replace(' ', '').strip();
448 if sFullExpr == '':
449 return True;
450
451 # Consider each exclusion expression. These are generally ranges,
452 # either open ended or closed: "<4.3.51r12345", ">=4.3.0 && <=4.3.4".
453 asExprs = sFullExpr.split(';');
454 for sExpr in asExprs:
455
456 # Split it on the and operator and process each sub expression.
457 fResult = True;
458 for sSubExpr in sExpr.split('&&'):
459 # Split out the comparison operator and the version value.
460 if sSubExpr.startswith('<=') or sSubExpr.startswith('>='):
461 sOp = sSubExpr[:2];
462 sValue = sSubExpr[2:];
463 elif sSubExpr.startswith('<') or sSubExpr.startswith('>') or sSubExpr.startswith('='):
464 sOp = sSubExpr[:1];
465 sValue = sSubExpr[1:];
466 else:
467 sOp = sValue = '';
468
469 # Convert the version value, making sure we've got a valid one.
470 try: aiValue = [int(sComp) for sComp in sValue.replace('r', '.').split('.')];
471 except: aiValue = ();
472 if not aiValue or len(aiValue) > 4:
473 reporter.error('Invalid exclusion expression for %s: "%s" [%s]' % (sTest, sSubExpr, dExclList[sTest]));
474 return True;
475
476 # Do the compare.
477 iCmp = self._compareVersion(aiValue);
478 if sOp == '>=' and iCmp < 0:
479 fResult = False;
480 elif sOp == '>' and iCmp <= 0:
481 fResult = False;
482 elif sOp == '<' and iCmp >= 0:
483 fResult = False;
484 elif sOp == '>=' and iCmp < 0:
485 fResult = False;
486 reporter.log2('iCmp=%s; %s %s %s -> %s' % (iCmp, self.aiVBoxVer, sOp, aiValue, fResult));
487
488 # Did the expression match?
489 if fResult:
490 return True;
491
492 return False;
493
494 def _sudoExecuteSync(self, asArgs):
495 """
496 Executes a sudo child process synchronously.
497 Returns True if the process executed successfully and returned 0,
498 otherwise False is returned.
499 """
500 reporter.log('Executing [sudo]: %s' % (asArgs, ));
501 try:
502 iRc = utils.sudoProcessCall(asArgs, shell = False, close_fds = False);
503 except:
504 reporter.errorXcpt();
505 return False;
506 reporter.log('Exit code [sudo]: %s (%s)' % (iRc, asArgs));
507 return iRc is 0;
508
509 def _hardenedMkDir(self, sPath):
510 """
511 Creates the directory specified sPath (including parents).
512 """
513 reporter.log('_hardenedMkDir: %s' % (sPath,));
514 if utils.getHostOs() in [ 'win', 'os2' ]:
515 os.makedirs(sPath, 0o755);
516 else:
517 fRc = self._sudoExecuteSync(['/bin/mkdir', '-p', '-m', '0755', sPath]);
518 if fRc is not True:
519 raise Exception('Failed to create dir "%s".' % (sPath,));
520 return True;
521
522 def _hardenedCopyFile(self, sSrc, sDst, iMode):
523 """
524 Copies a file.
525 """
526 reporter.log('_hardenedCopyFile: %s -> %s (mode: %o)' % (sSrc, sDst, iMode,));
527 if utils.getHostOs() in [ 'win', 'os2' ]:
528 utils.copyFileSimple(sSrc, sDst);
529 os.chmod(sDst, iMode);
530 else:
531 fRc = self._sudoExecuteSync(['/bin/cp', sSrc, sDst]);
532 if fRc is not True:
533 raise Exception('Failed to copy "%s" to "%s".' % (sSrc, sDst,));
534 fRc = self._sudoExecuteSync(['/bin/chmod', '%o' % (iMode,), sDst]);
535 if fRc is not True:
536 raise Exception('Failed to chmod "%s".' % (sDst,));
537 return True;
538
539 def _hardenedDeleteFile(self, sPath):
540 """
541 Deletes a file.
542 """
543 reporter.log('_hardenedDeleteFile: %s' % (sPath,));
544 if os.path.exists(sPath):
545 if utils.getHostOs() in [ 'win', 'os2' ]:
546 os.remove(sPath);
547 else:
548 fRc = self._sudoExecuteSync(['/bin/rm', sPath]);
549 if fRc is not True:
550 raise Exception('Failed to remove "%s".' % (sPath,));
551 return True;
552
553 def _hardenedRemoveDir(self, sPath):
554 """
555 Removes a directory.
556 """
557 reporter.log('_hardenedRemoveDir: %s' % (sPath,));
558 if os.path.exists(sPath):
559 if utils.getHostOs() in [ 'win', 'os2' ]:
560 os.rmdir(sPath);
561 else:
562 fRc = self._sudoExecuteSync(['/bin/rmdir', sPath]);
563 if fRc is not True:
564 raise Exception('Failed to remove "%s".' % (sPath,));
565 return True;
566
567 def _executeTestCase(self, sName, sFullPath, sTestCaseSubDir, oDevNull): # pylint: disable=R0914
568 """
569 Executes a test case.
570 """
571
572 fSkipped = False;
573
574 #
575 # If hardening is enabled, some test cases and their dependencies
576 # needs to be copied to and execute from the sVBoxInstallRoot
577 # directory in order to work. They also have to be executed as
578 # root, i.e. via sudo.
579 #
580 fHardened = False;
581 asFilesToRemove = []; # Stuff to clean up.
582 asDirsToRemove = []; # Ditto.
583 if sName in self.kasHardened \
584 and self.sUnitTestsPathBase != self.sVBoxInstallRoot:
585
586 sDstDir = os.path.join(self.sVBoxInstallRoot, sTestCaseSubDir);
587 if not os.path.exists(sDstDir):
588 self._hardenedMkDir(sDstDir);
589 asDirsToRemove.append(sDstDir);
590
591 sDst = os.path.join(sDstDir, os.path.basename(sFullPath));
592 self._hardenedCopyFile(sFullPath, sDst, 0o755);
593 asFilesToRemove.append(sDst);
594
595 # Copy any associated .dll/.so/.dylib.
596 for sSuff in [ '.dll', '.so', '.dylib' ]:
597 sSrc = os.path.splitext(sFullPath)[0] + sSuff;
598 if os.path.exists(sSrc):
599 sDst = os.path.join(sDstDir, os.path.basename(sSrc));
600 self._hardenedCopyFile(sSrc, sDst, 0o644);
601 asFilesToRemove.append(sDst);
602
603 # Copy any associated .r0, .rc and .gc modules.
604 offDriver = sFullPath.rfind('Driver')
605 if offDriver > 0:
606 for sSuff in [ '.r0', 'RC.rc', 'RC.gc' ]:
607 sSrc = sFullPath[:offDriver] + sSuff;
608 if os.path.exists(sSrc):
609 sDst = os.path.join(sDstDir, os.path.basename(sSrc));
610 self._hardenedCopyFile(sSrc, sDst, 0o644);
611 asFilesToRemove.append(sDst);
612
613 sFullPath = os.path.join(sDstDir, os.path.basename(sFullPath));
614 fHardened = True;
615
616 #
617 # Set up arguments and environment.
618 #
619 asArgs = [sFullPath,]
620 if sName in self.kdArguments:
621 asArgs.extend(self.kdArguments[sName]);
622
623 os.environ['IPRT_TEST_OMIT_TOP_TEST'] = '1';
624 os.environ['IPRT_TEST_FILE'] = sXmlFile = os.path.join(self.sScratchPath, 'result.xml');
625 if os.path.exists(sXmlFile):
626 try: os.unlink(sXmlFile);
627 except: self._hardenedDeleteFile(sXmlFile);
628
629 #
630 # Execute the test case.
631 #
632 # Windows is confusing output. Trying a few things to get rid of this.
633 # First, flush both stderr and stdout before running the child. Second,
634 # assign the child stderr to stdout. If this doesn't help, we'll have
635 # to capture the child output.
636 #
637 reporter.log('*** Executing %s%s...' % (asArgs, ' [hardened]' if fHardened else ''));
638 try: sys.stdout.flush();
639 except: pass;
640 try: sys.stderr.flush();
641 except: pass;
642 if not self.fDryRun:
643 try:
644 if fHardened:
645 oChild = utils.sudoProcessPopen(asArgs, stdin = oDevNull, stdout = sys.stdout, stderr = sys.stdout);
646 else:
647 oChild = utils.processPopenSafe(asArgs, stdin = oDevNull, stdout = sys.stdout, stderr = sys.stdout);
648 except:
649 if sName in [ 'tstAsmStructsRC', # 32-bit, may fail to start on 64-bit linux. Just ignore.
650 ]:
651 reporter.logXcpt();
652 fSkipped = True;
653 else:
654 reporter.errorXcpt();
655 iRc = 1023;
656 oChild = None;
657
658 if oChild is not None:
659 self.pidFileAdd(oChild.pid, sName, fSudo = fHardened);
660 iRc = oChild.wait();
661 self.pidFileRemove(oChild.pid);
662 else:
663 iRc = 0;
664
665 #
666 # Clean up
667 #
668 for sPath in asFilesToRemove:
669 self._hardenedDeleteFile(sPath);
670 for sPath in asDirsToRemove:
671 self._hardenedRemoveDir(sPath);
672
673 #
674 # Report.
675 #
676 if os.path.exists(sXmlFile):
677 reporter.addSubXmlFile(sXmlFile);
678 if fHardened:
679 self._hardenedDeleteFile(sXmlFile);
680 else:
681 os.unlink(sXmlFile);
682
683 if iRc == 0:
684 reporter.log('*** %s: exit code %d' % (sFullPath, iRc));
685 self.cPassed += 1
686
687 elif iRc == 4: # RTEXITCODE_SKIPPED
688 reporter.log('*** %s: exit code %d (RTEXITCODE_SKIPPED)' % (sFullPath, iRc));
689 fSkipped = True;
690 self.cSkipped += 1;
691
692 elif fSkipped:
693 reporter.log('*** %s: exit code %d (Skipped)' % (sFullPath, iRc));
694 self.cSkipped += 1;
695
696 else:
697 sName = self.kdExitCodeNames.get(iRc, '');
698 if iRc in self.kdExitCodeNamesWin and utils.getHostOs() == 'win':
699 sName = self.kdExitCodeNamesWin[iRc];
700 if sName != '':
701 sName = ' (%s)' % (sName);
702
703 if iRc != 1:
704 reporter.testFailure('Exit status: %d%s' % (iRc, sName));
705 reporter.log( '!*! %s: exit code %d%s' % (sFullPath, iRc, sName));
706 else:
707 reporter.error('!*! %s: exit code %d%s' % (sFullPath, iRc, sName));
708 self.cFailed += 1
709
710 return fSkipped;
711
712 def testRunUnitTestsSet(self, sTestCasePattern, sTestCaseSubDir):
713 """
714 Run subset of the unit tests set.
715 """
716
717 # Open /dev/null for use as stdin further down.
718 try:
719 oDevNull = open(os.path.devnull, 'w+');
720 except:
721 oDevNull = None;
722
723 # Determin the host OS specific exclusion lists.
724 dTestCasesBuggyForHostOs = self.kdTestCasesBuggyPerOs.get(utils.getHostOs(), []);
725 dTestCasesBuggyForHostOs.update(self.kdTestCasesBuggyPerOs.get(utils.getHostOsDotArch(), []));
726
727 #
728 # Process the file list and run everything looking like a testcase.
729 #
730 for sFilename in sorted(os.listdir(os.path.join(self.sUnitTestsPathBase, sTestCaseSubDir))):
731 # Separate base and suffix and morph the base into something we
732 # can use for reporting and array lookups.
733 sName, sSuffix = os.path.splitext(sFilename);
734 if sTestCaseSubDir != '.':
735 sName = sTestCaseSubDir + '/' + sName;
736
737 # Basic exclusion.
738 if not re.match(sTestCasePattern, sFilename) \
739 or sSuffix in self.kasSuffixBlackList:
740 reporter.log('"%s" is not a test case.' % (sFilename,))
741 continue
742
743 # Check if the testcase is black listed or buggy before executing it.
744 if self._isExcluded(sName, self.kdTestCasesBlackList):
745 # (No testStart/Done or accounting here!)
746 reporter.log('%s: SKIPPED (blacklisted)' % (sName,));
747
748 elif self._isExcluded(sName, self.kdTestCasesBuggy):
749 reporter.testStart(sName);
750 reporter.log('%s: Skipping, buggy in general.' % (sName,));
751 reporter.testDone(fSkipped = True);
752 self.cSkipped += 1;
753
754 elif self._isExcluded(sName, dTestCasesBuggyForHostOs):
755 reporter.testStart(sName);
756 reporter.log('%s: Skipping, buggy on %s.' % (sName, utils.getHostOs(),));
757 reporter.testDone(fSkipped = True);
758 self.cSkipped += 1;
759
760 else:
761 sFullPath = os.path.normpath(os.path.join(self.sUnitTestsPathBase, os.path.join(sTestCaseSubDir, sFilename)));
762 reporter.testStart(sName);
763 try:
764 fSkipped = self._executeTestCase(sName, sFullPath, sTestCaseSubDir, oDevNull);
765 except:
766 reporter.errorXcpt('!*!');
767 self.cFailed += 1;
768 fSkipped = False;
769 reporter.testDone(fSkipped);
770
771
772
773if __name__ == '__main__':
774 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