VirtualBox

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

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

ValKit/tdUnitTest1.py: The lovely tstClipboardQt testcase is in the 'bin' directory not in 'bin/testcase'.

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