VirtualBox

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

Last change on this file since 83049 was 82968, checked in by vboxsync, 5 years ago

Copyright year updates by scm.

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