VirtualBox

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

Last change on this file since 93307 was 93208, checked in by vboxsync, 3 years ago

ValKit/tdUnitTest1: Ignore files with suffixes .template, .expect and .expected. bugref:9781

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