VirtualBox

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

Last change on this file since 87267 was 86615, checked in by vboxsync, 4 years ago

ValKit/tdUnitTest1.py: tstTime-2 and tstTime-4 must be run as root as they require supdrv/GIP access to do anything useful. Asserts and dies in asan & strict builds. bugref:9841

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