VirtualBox

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

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

Shared Clipboard/testcases: Skip running tstClipboardQt on testboxes; is interactive and needs Qt. Cleaned up Makefile a bit.

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