VirtualBox

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

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

scm copyright and license note update

  • Property svn:eol-style set to LF
  • Property svn:executable set to *
  • Property svn:keywords set to Author Date Id Revision
File size: 53.0 KB
Line 
1#!/usr/bin/env python
2# -*- coding: utf-8 -*-
3# $Id: tdUnitTest1.py 96407 2022-08-22 17:43:14Z vboxsync $
4
5"""
6VirtualBox Validation Kit - Unit Tests.
7"""
8
9__copyright__ = \
10"""
11Copyright (C) 2010-2022 Oracle and/or its affiliates.
12
13This file is part of VirtualBox base platform packages, as
14available from https://www.virtualbox.org.
15
16This program is free software; you can redistribute it and/or
17modify it under the terms of the GNU General Public License
18as published by the Free Software Foundation, in version 3 of the
19License.
20
21This program is distributed in the hope that it will be useful, but
22WITHOUT ANY WARRANTY; without even the implied warranty of
23MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
24General Public License for more details.
25
26You should have received a copy of the GNU General Public License
27along with this program; if not, see <https://www.gnu.org/licenses>.
28
29The contents of this file may alternatively be used under the terms
30of the Common Development and Distribution License Version 1.0
31(CDDL), a copy of it is provided in the "COPYING.CDDL" file included
32in the VirtualBox distribution, in which case the provisions of the
33CDDL are applicable instead of those of the GPL.
34
35You may elect to license modified versions of this file under the
36terms and conditions of either the GPL or the CDDL or both.
37
38SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0
39"""
40__version__ = "$Revision: 96407 $"
41
42
43# Standard Python imports.
44import os
45import sys
46import re
47
48
49# Only the main script needs to modify the path.
50try: __file__
51except: __file__ = sys.argv[0];
52g_ksValidationKitDir = os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
53sys.path.append(g_ksValidationKitDir)
54
55# Validation Kit imports.
56from common import utils;
57from testdriver import base;
58from testdriver import reporter;
59from testdriver import vbox;
60from testdriver import vboxcon;
61
62
63class tdUnitTest1(vbox.TestDriver):
64 """
65 Unit Tests.
66 """
67
68 ## The temporary exclude list.
69 ## @note This shall be empty before we release 4.3!
70 kdTestCasesBuggyPerOs = {
71 'darwin': {
72 'testcase/tstX86-1': '', # 'FSTP M32R, ST0' fails; no idea why.
73 },
74 'linux': {
75 'testcase/tstRTFileAio': '', # See xTracker #8035.
76 },
77 'linux.amd64': {
78 'testcase/tstLdr-4': '', # failed: Failed to get bits for '/home/vbox/test/tmp/bin/testcase/tstLdrObjR0.r0'/0,
79 # rc=VERR_SYMBOL_VALUE_TOO_BIG. aborting test
80 },
81 'solaris': {
82 'testcase/tstIntNet-1': '', # Fails opening rge0, probably a generic issue figuring which nic to use.
83 'testcase/tstIprtList': '', # Crashes in the multithreaded test, I think.
84 'testcase/tstRTCritSect': '', # Fairness/whatever issue here.
85 'testcase/tstRTR0MemUserKernelDriver': '', # Failes when kernel to kernel buffers.
86 'testcase/tstRTSemRW': '', # line 338: RTSemRWReleaseRead(hSemRW): got VERR_ACCESS_DENIED
87 'testcase/tstRTStrAlloc': '', # VERR_NO_STR_MEMORY!
88 'testcase/tstRTFileQuerySize-1': '', # VERR_DEV_IO_ERROR on /dev/null!
89 },
90 'solaris.amd64': {
91 'testcase/tstLdr-4': '', # failed: Failed to get bits for '/home/vbox/test/tmp/bin/testcase/tstLdrObjR0.r0'/0,
92 # rc=VERR_SYMBOL_VALUE_TOO_BIG. aborting test
93 },
94 'win': {
95 'testcase/tstFile': '', # ??
96 'testcase/tstIntNet-1': '', # possibly same issue as solaris.
97 'testcase/tstMouseImpl': '', # STATUS_ACCESS_VIOLATION
98 'testcase/tstRTR0ThreadPreemptionDriver': '', # ??
99 'testcase/tstRTPath': '<4.3.51r89894',
100 'testcase/tstRTPipe': '', # ??
101 'testcase/tstRTR0MemUserKernelDriver': '', # ??
102 'testcase/tstRTR0SemMutexDriver': '', # ??
103 'testcase/tstRTStrAlloc': '', # ??
104 'testcase/tstRTStrFormat': '', # ??
105 'testcase/tstRTSystemQueryOsInfo': '', # ??
106 'testcase/tstRTTemp': '', # ??
107 'testcase/tstRTTime': '', # ??
108 'testcase/tstTime-2': '', # Total time differs too much! ... delta=-10859859
109 'testcase/tstTime-4': '', # Needs to be converted to DLL; ditto for tstTime-2.
110 'testcase/tstUtf8': '', # ??
111 'testcase/tstVMMR0CallHost-2': '', # STATUS_STACK_OVERFLOW
112 'testcase/tstX86-1': '', # Fails on win.x86.
113 'tscpasswd': '', # ??
114 'tstVMREQ': '', # ?? Same as darwin.x86?
115 },
116 'win.x86': {
117 'testcase/tstRTR0TimerDriver': '', # See xTracker #8041.
118 }
119 };
120
121 kdTestCasesBuggy = {
122 'testcase/tstGuestPropSvc': '', # GET_NOTIFICATION fails on testboxlin5.de.oracle.com and others.
123 'testcase/tstRTProcCreateEx': '', # Seen failing on wei01-b6ka-9.de.oracle.com.
124 'testcase/tstTimer': '', # Sometimes fails on linux, not important atm.
125 'testcase/tstGIP-2': '', # 2015-09-10: Fails regularly. E.g. TestSetID 2744205 (testboxsh2),
126 # 2743961 (wei01-b6kc-6). The responsible engineer should reenable
127 # it once it has been fixed.
128 };
129
130 ## The permanent exclude list.
131 # @note Stripped of extensions!
132 kdTestCasesBlackList = {
133 'testcase/tstClipboardX11Smoke': '', # (Old naming, deprecated) Needs X, not available on all test boxes.
134 'testcase/tstClipboardGH-X11Smoke': '', # (New name) Ditto.
135 'tstClipboardQt': '', # Is interactive and needs Qt, needed for Qt clipboard bugfixing.
136 'testcase/tstClipboardQt': '', # In case it moves here.
137 'testcase/tstFileLock': '',
138 'testcase/tstDisasm-2': '', # without parameters it will disassembler 1GB starting from 0
139 'testcase/tstFileAppendWin-1': '',
140 'testcase/tstDir': '', # useless without parameters
141 'testcase/tstDir-2': '', # useless without parameters
142 'testcase/tstGlobalConfig': '',
143 'testcase/tstHostHardwareLinux': '', # must be killed with CTRL-C
144 'testcase/tstHttp': '', # Talks to outside servers.
145 'testcase/tstRTHttp': '', # parameters required
146 'testcase/tstLdr-2': '', # parameters required
147 'testcase/tstLdr-3': '', # parameters required
148 'testcase/tstLdr': '', # parameters required
149 'testcase/tstLdrLoad': '', # parameters required
150 'testcase/tstMove': '', # parameters required
151 'testcase/tstRTR0Timer': '', # loads 'tstRTR0Timer.r0'
152 'testcase/tstRTR0ThreadDriver': '', # loads 'tstRTR0Thread.r0'
153 'testcase/tstRunTestcases': '', # that's a script like this one
154 'testcase/tstRTReqPool': '', # fails sometimes, testcase buggy
155 'testcase/tstRTS3': '', # parameters required
156 'testcase/tstSDL': '', # graphics test
157 'testcase/tstSupLoadModule': '', # Needs parameters and vboxdrv access. Covered elsewhere.
158 'testcase/tstSeamlessX11': '', # graphics test
159 'testcase/tstTime-3': '', # parameters required
160 'testcase/tstVBoxControl': '', # works only inside a guest
161 'testcase/tstVDCopy': '', # parameters required
162 'testcase/tstVDFill': '', # parameters required
163 'tstAnimate': '', # parameters required
164 'testcase/tstAPI': '', # user interaction required
165 'tstCollector': '', # takes forever
166 'testcase/tstHeadless': '', # parameters required
167 'tstHeadless': '', # parameters required
168 'tstMicroRC': '', # required by tstMicro
169 'tstVBoxDbg': '', # interactive test
170 'testcase/tstTestServMgr': '', # some strange xpcom18a4 test, does not work
171 'tstTestServMgr': '', # some strange xpcom18a4 test, does not work
172 'tstPDMAsyncCompletion': '', # parameters required
173 'testcase/tstXptDump': '', # parameters required
174 'tstXptDump': '', # parameters required
175 'testcase/tstnsIFileEnumerator': '', # some strange xpcom18a4 test, does not work
176 'tstnsIFileEnumerator': '', # some strange xpcom18a4 test, does not work
177 'testcase/tstSimpleTypeLib': '', # parameters required
178 'tstSimpleTypeLib': '', # parameters required
179 'testcase/tstTestAtoms': '', # additional test file (words.txt) required
180 'tstTestAtoms': '', # additional test file (words.txt) required
181 'testcase/tstXptLink': '', # parameters required
182 'tstXptLink': '', # parameters required
183 'tstXPCOMCGlue': '', # user interaction required
184 'testcase/tstXPCOMCGlue': '', # user interaction required
185 'testcase/tstCAPIGlue': '', # user interaction required
186 'testcase/tstTestCallTemplates': '', # some strange xpcom18a4 test, segfaults
187 'tstTestCallTemplates': '', # some strange xpcom18a4 test, segfaults
188 'testcase/tstRTFilesystem': '', # parameters required
189 'testcase/tstRTDvm': '', # parameters required
190 'tstSSLCertDownloads': '', # Obsolete.
191 # later
192 'testcase/tstIntNetR0': '', # RTSPINLOCK_FLAGS_INTERRUPT_SAFE == RTSPINLOCK_FLAGS_INTERRUPT_UNSAFE
193 # slow stuff
194 'testcase/tstAvl': '', # SLOW!
195 'testcase/tstRTAvl': '', # SLOW! (new name)
196 'testcase/tstVD': '', # 8GB fixed-sized vmdk
197 # failed or hang
198 'testcase/tstCryptoPkcs7Verify': '', # hang
199 'tstOVF': '', # hang (only ancient version, now in new place)
200 'testcase/tstOVF': '', # Creates mess when fails, needs to be run in a separate test.
201 'testcase/tstRTLockValidator': '', # Lock validation is not enabled for critical sections
202 'testcase/tstGuestControlSvc': '', # failed: line 288: testHost(&svcTable):
203 # expected VINF_SUCCESS, got VERR_NOT_FOUND
204 'testcase/tstRTMemEf': '', # failed w/o error message
205 'testcase/tstSupSem': '', # failed: SRE Timeout Accuracy (ms) : FAILED (1 errors)
206 'testcase/tstCryptoPkcs7Sign': '', # failed: 29330:
207 # error:02001002:lib(2):func(1):reason(2):NA:0:fopen('server.pem': '','r')
208 'testcase/tstCompressionBenchmark': '', # failed: error: RTZipBlockCompress failed
209 # for 'RTZipBlock/LZJB' (#4): VERR_NOT_SUPPORTED
210 'tstPDMAsyncCompletionStress': '', # VERR_INVALID_PARAMETER (cbSize = 0)
211 'tstMicro': '', # doesn't work on solaris, fix later if we care.
212 'tstVMM-HwAccm': '', # failed: Only checked AMD-V on linux
213 'tstVMM-HM': '', # failed: Only checked AMD-V on linux
214 'tstVMMFork': '', # failed: xtracker 6171
215 'tstTestFactory': '', # some strange xpcom18a4 test, does not work
216 'testcase/tstRTSemXRoads': '', # sporadically failed: Traffic - 8 threads per direction, 10 sec :
217 # FAILED (8 errors)
218 'tstVBoxAPILinux': '', # creates VirtualBox directories for root user because of sudo
219 # (should be in vbox)
220 'testcase/tstVMStructDTrace': '', # This is a D-script generator.
221 'tstVMStructRC': '', # This is a C-code generator.
222 'tstDeviceStructSizeRC': '', # This is a C-code generator.
223 'testcase/tstTSC': '', # Doesn't test anything and might fail with HT or/and too many cores.
224 'testcase/tstOpenUSBDev': '', # Not a useful testcase.
225 'testcase/tstX86-1': '', # Really more guest side.
226 'testcase/tstX86-FpuSaveRestore': '', # Experiments, could be useful for the guest not the host.
227 'tstAsmStructsRC': '', # Testcase run during build time (fails to find libstdc++.so.6 on some
228 # Solaris testboxes).
229 };
230
231 # Suffix exclude list.
232 kasSuffixBlackList = [
233 '.r0',
234 '.gc',
235 '.debug',
236 '.rel',
237 '.sys',
238 '.ko',
239 '.o',
240 '.obj',
241 '.lib',
242 '.a',
243 '.so',
244 '.dll',
245 '.dylib',
246 '.tmp',
247 '.log',
248 '.py',
249 '.pyc',
250 '.pyo',
251 '.pdb',
252 '.dSYM',
253 '.sym',
254 '.template',
255 '.expected',
256 '.expect',
257 ];
258
259 # White list, which contains tests considered to be safe to execute,
260 # even on remote targets (guests).
261 kdTestCasesWhiteList = {
262 'testcase/tstFile': '',
263 'testcase/tstFileLock': '',
264 'testcase/tstRTLocalIpc': '',
265 'testcase/tstRTPathQueryInfo': '',
266 'testcase/tstRTPipe': '',
267 'testcase/tstRTProcCreateEx': '',
268 'testcase/tstRTProcCreatePrf': '',
269 'testcase/tstRTProcIsRunningByName': '',
270 'testcase/tstRTProcQueryUsername': '',
271 'testcase/tstRTProcWait': '',
272 'testcase/tstTime-2': '',
273 'testcase/tstTime-3': '',
274 'testcase/tstTime-4': '',
275 'testcase/tstTimer': '',
276 'testcase/tstThread-1': '',
277 'testcase/tstUtf8': ''
278 };
279
280 # Test dependency list -- libraries.
281 # Needed in order to execute testcases on remote targets which don't have a VBox installation present.
282 kdTestCaseDepsLibs = [
283 "VBoxRT"
284 ];
285
286 ## The exclude list.
287 # @note Stripped extensions!
288 kasHardened = [
289 "testcase/tstIntNet-1",
290 "testcase/tstR0ThreadPreemptionDriver", # VBox 4.3
291 "testcase/tstRTR0ThreadPreemptionDriver",
292 "testcase/tstRTR0MemUserKernelDriver",
293 "testcase/tstRTR0SemMutexDriver",
294 "testcase/tstRTR0TimerDriver",
295 "testcase/tstRTR0ThreadDriver",
296 'testcase/tstRTR0DbgKrnlInfoDriver',
297 "tstInt",
298 "tstPDMQueue", # Comment in testcase says its driverless, but it needs driver access.
299 "tstVMM",
300 "tstVMMFork",
301 "tstVMREQ",
302 'testcase/tstCFGM',
303 'testcase/tstContiguous',
304 'testcase/tstGetPagingMode',
305 'testcase/tstGIP-2',
306 'testcase/tstInit',
307 'testcase/tstLow',
308 'testcase/tstMMHyperHeap',
309 'testcase/tstPage',
310 'testcase/tstPin',
311 'testcase/tstRTTime', 'testcase/tstTime', # GIP test case.
312 'testcase/tstRTTime-2', 'testcase/tstTime-2', # GIP test case.
313 'testcase/tstRTTime-4', 'testcase/tstTime-4', # GIP test case.
314 'testcase/tstSSM',
315 'testcase/tstSupSem-Zombie',
316 ]
317
318 ## Argument lists
319 kdArguments = {
320 'testcase/tstbntest': [ '-out', os.devnull, ], # Very noisy.
321 };
322
323
324 ## Status code translations.
325 ## @{
326 kdExitCodeNames = {
327 0: 'RTEXITCODE_SUCCESS',
328 1: 'RTEXITCODE_FAILURE',
329 2: 'RTEXITCODE_SYNTAX',
330 3: 'RTEXITCODE_INIT',
331 4: 'RTEXITCODE_SKIPPED',
332 };
333 kdExitCodeNamesWin = {
334 -1073741515: 'STATUS_DLL_NOT_FOUND',
335 -1073741512: 'STATUS_ORDINAL_NOT_FOUND',
336 -1073741511: 'STATUS_ENTRYPOINT_NOT_FOUND',
337 -1073741502: 'STATUS_DLL_INIT_FAILED',
338 -1073741500: 'STATUS_UNHANDLED_EXCEPTION',
339 -1073741499: 'STATUS_APP_INIT_FAILURE',
340 -1073741819: 'STATUS_ACCESS_VIOLATION',
341 -1073741571: 'STATUS_STACK_OVERFLOW',
342 };
343 ## @}
344
345 def __init__(self):
346 """
347 Reinitialize child class instance.
348 """
349 vbox.TestDriver.__init__(self);
350
351 # We need to set a default test VM set here -- otherwise the test
352 # driver base class won't let us use the "--test-vms" switch.
353 #
354 # See the "--local" switch in self.parseOption().
355 self.oTestVmSet = self.oTestVmManager.getSmokeVmSet('nat');
356
357 # Selected NIC attachment.
358 self.sNicAttachment = '';
359
360 # Session handling stuff.
361 # Only needed for remote tests executed by TxS.
362 self.oSession = None;
363 self.oTxsSession = None;
364
365 self.sVBoxInstallRoot = None;
366
367 # Testing mode being used:
368 # "local": Execute unit tests locally (same host, default).
369 # "remote-copy": Copies unit tests from host to the remote, then executing it.
370 # "remote-exec": Executes unit tests right on the remote from a given source.
371 self.sMode = 'local';
372
373 self.cSkipped = 0;
374 self.cPassed = 0;
375 self.cFailed = 0;
376
377 # The source directory where our unit tests live.
378 # This most likely is our out/ or some staging directory and
379 # also acts the source for copying over the testcases to a remote target.
380 self.sUnitTestsPathSrc = None;
381
382 # Array of environment variables with NAME=VAL entries
383 # to be applied for testcases.
384 #
385 # This is also needed for testcases which are being executed remotely.
386 self.asEnv = [];
387
388 # The destination directory our unit tests live when being
389 # copied over to a remote target (via TxS).
390 self.sUnitTestsPathDst = None;
391
392 # Will be determined before executing the actual unit tests.
393 self.sExeSuff = '';
394
395 self.aiVBoxVer = (4, 3, 0, 0);
396
397 # For testing testcase logic.
398 self.fDryRun = False;
399 self.fOnlyWhiteList = False;
400
401 @staticmethod
402 def _sanitizePath(sPath):
403 """
404 Does a little bit of sanitizing a given path by removing quoting, if any.
405
406 This is needed because handed-in paths via command line arguments can contain variables like "${CDROM}"
407 which might need to get processed by TXS on the guest side first.
408
409 Returns the sanitized path.
410 """
411 if sPath is None: # Keep uninitialized strings as-is.
412 return None;
413 return sPath.strip('\"').strip('\'');
414
415 def _detectPaths(self):
416 """
417 Internal worker for actionVerify and actionExecute that detects paths.
418
419 This sets sVBoxInstallRoot and sUnitTestsPathBase and returns True/False.
420 """
421
422 reporter.log2('Detecting paths ...');
423
424 #
425 # Do some sanity checking first.
426 #
427 if self.sMode == 'remote-exec' \
428 and not self.sUnitTestsPathSrc: # There is no way we can figure this out automatically.
429 reporter.error('Unit tests source must be specified explicitly for selected mode!');
430 return False;
431
432 #
433 # We need a VBox install (/ build) to test.
434 #
435 if False is True: ## @todo r=andy WTF?
436 if not self.importVBoxApi():
437 reporter.error('Unabled to import the VBox Python API.');
438 return False;
439 else:
440 self._detectBuild();
441 if self.oBuild is None:
442 reporter.error('Unabled to detect the VBox build.');
443 return False;
444
445 #
446 # Where are the files installed?
447 # Solaris requires special handling because of it's multi arch subdirs.
448 #
449 if not self.sVBoxInstallRoot:
450 self.sVBoxInstallRoot = self.oBuild.sInstallPath;
451 if not self.oBuild.isDevBuild() and utils.getHostOs() == 'solaris':
452 sArchDir = utils.getHostArch();
453 if sArchDir == 'x86': sArchDir = 'i386';
454 self.sVBoxInstallRoot = os.path.join(self.sVBoxInstallRoot, sArchDir);
455
456 ## @todo r=andy Make sure the install root really exists and is accessible.
457
458 # Add the installation root to the PATH on windows so we can get DLLs from it.
459 if utils.getHostOs() == 'win':
460 sPathName = 'PATH';
461 if not sPathName in os.environ:
462 sPathName = 'Path';
463 sPath = os.environ.get(sPathName, '.');
464 if sPath and sPath[-1] != ';':
465 sPath += ';';
466 os.environ[sPathName] = sPath + self.sVBoxInstallRoot + ';';
467 else:
468 reporter.log2('VBox installation root already set to "%s"' % (self.sVBoxInstallRoot));
469
470 self.sVBoxInstallRoot = self._sanitizePath(self.sVBoxInstallRoot);
471
472 #
473 # The unittests are generally not installed, so look for them.
474 #
475 if not self.sUnitTestsPathSrc:
476 sBinOrDist = 'dist' if utils.getHostOs() in [ 'darwin', ] else 'bin';
477 asCandidates = [
478 self.oBuild.sInstallPath,
479 os.path.join(self.sScratchPath, utils.getHostOsDotArch(), self.oBuild.sType, sBinOrDist),
480 os.path.join(self.sScratchPath, utils.getHostOsDotArch(), 'release', sBinOrDist),
481 os.path.join(self.sScratchPath, utils.getHostOsDotArch(), 'debug', sBinOrDist),
482 os.path.join(self.sScratchPath, utils.getHostOsDotArch(), 'strict', sBinOrDist),
483 os.path.join(self.sScratchPath, utils.getHostOsDotArch(), 'dbgopt', sBinOrDist),
484 os.path.join(self.sScratchPath, utils.getHostOsDotArch(), 'profile', sBinOrDist),
485 os.path.join(self.sScratchPath, sBinOrDist + '.' + utils.getHostArch()),
486 os.path.join(self.sScratchPath, sBinOrDist, utils.getHostArch()),
487 os.path.join(self.sScratchPath, sBinOrDist),
488 ];
489 if utils.getHostOs() == 'darwin':
490 for i in range(1, len(asCandidates)):
491 asCandidates[i] = os.path.join(asCandidates[i], 'VirtualBox.app', 'Contents', 'MacOS');
492
493 for sCandidat in asCandidates:
494 if os.path.exists(os.path.join(sCandidat, 'testcase', 'tstVMStructSize' + self.sExeSuff)):
495 self.sUnitTestsPathSrc = sCandidat;
496 break;
497
498 if not self.sUnitTestsPathSrc:
499 reporter.error('Unable to find unit test source dir. Candidates: %s' % (asCandidates,));
500 return False;
501 else:
502 reporter.log2('Unit test source dir already set to "%s"' % (self.sUnitTestsPathSrc));
503
504 self.sUnitTestsPathSrc = self._sanitizePath(self.sUnitTestsPathSrc);
505
506 return True;
507
508 #
509 # Overridden methods.
510 #
511
512 def showUsage(self):
513 """
514 Shows the testdriver usage.
515 """
516 fRc = vbox.TestDriver.showUsage(self);
517 reporter.log('');
518 reporter.log('Unit Test #1 options:');
519 reporter.log(' --dryrun');
520 reporter.log(' Performs a dryrun (no tests being executed).');
521 reporter.log(' --mode <local|remote-copy|remote-exec>');
522 reporter.log(' Specifies the test execution mode:');
523 reporter.log(' local: Locally on the same machine.');
524 reporter.log(' remote-copy: On remote (guest) by copying them from the local source.');
525 reporter.log(' remote-exec: On remote (guest) directly (needs unit test source).');
526 reporter.log(' --only-whitelist');
527 reporter.log(' Only processes the white list.');
528 reporter.log(' --quick');
529 reporter.log(' Very selective testing.');
530 reporter.log(' --unittest-source <dir>');
531 reporter.log(' Sets the unit test source to <dir>.');
532 reporter.log(' Also used for remote execution.');
533 reporter.log(' --vbox-install-root <dir>');
534 reporter.log(' Sets the VBox install root to <dir>.');
535 reporter.log(' Also used for remote execution.');
536 return fRc;
537
538 def parseOption(self, asArgs, iArg):
539 """
540 Parses the testdriver arguments from the command line.
541 """
542 if asArgs[iArg] == '--dryrun':
543 self.fDryRun = True;
544 elif asArgs[iArg] == '--mode':
545 iArg += 1;
546 if iArg >= len(asArgs):
547 raise base.InvalidOption('Option "%s" needs a value' % (asArgs[iArg - 1]));
548 if asArgs[iArg] == 'local' \
549 or asArgs[iArg] == 'remote-copy' \
550 or asArgs[iArg] == 'remote-exec':
551 self.sMode = asArgs[iArg];
552 else:
553 raise base.InvalidOption('Argument "%s" invalid' % (asArgs[iArg]));
554 elif asArgs[iArg] == '--unittest-source':
555 iArg += 1;
556 if iArg >= len(asArgs):
557 raise base.InvalidOption('Option "%s" needs a value' % (asArgs[iArg - 1]));
558 self.sUnitTestsPathSrc = asArgs[iArg];
559 elif asArgs[iArg] == '--only-whitelist':
560 self.fOnlyWhiteList = True;
561 elif asArgs[iArg] == '--quick':
562 self.fOnlyWhiteList = True;
563 elif asArgs[iArg] == '--vbox-install-root':
564 iArg += 1;
565 if iArg >= len(asArgs):
566 raise base.InvalidOption('Option "%s" needs a value' % (asArgs[iArg - 1]));
567 self.sVBoxInstallRoot = asArgs[iArg];
568 else:
569 return vbox.TestDriver.parseOption(self, asArgs, iArg);
570 return iArg + 1;
571
572 def actionVerify(self):
573 if not self._detectPaths():
574 return False;
575
576 if self.oTestVmSet:
577 return vbox.TestDriver.actionVerify(self);
578
579 return True;
580
581 def actionConfig(self):
582 # Make sure vboxapi has been imported so we can use the constants.
583 if not self.importVBoxApi():
584 return False;
585
586 # Do the configuring.
587 if self.sMode.startswith('remote'):
588 if self.sNicAttachment == 'nat': eNic0AttachType = vboxcon.NetworkAttachmentType_NAT;
589 elif self.sNicAttachment == 'bridged': eNic0AttachType = vboxcon.NetworkAttachmentType_Bridged;
590 else: eNic0AttachType = None;
591
592 # Make sure to mount the Validation Kit .ISO so that TxS has the chance
593 # to update itself.
594 #
595 # This is necessary as a lot of our test VMs nowadays have a very old TxS
596 # installed which don't understand commands like uploading files to the guest.
597 # Uploading files is needed for this test driver, however.
598 #
599 ## @todo Get rid of this as soon as we create test VMs in a descriptive (automated) manner.
600 return self.oTestVmSet.actionConfig(self, eNic0AttachType = eNic0AttachType, \
601 sDvdImage = self.sVBoxValidationKitIso);
602
603 return True;
604
605 def actionExecute(self):
606 # Make sure vboxapi has been imported so we can execute the driver without going thru
607 # a former configuring step.
608 if not self.importVBoxApi():
609 return False;
610 if not self._detectPaths():
611 return False;
612 reporter.log2('Unit test source path is "%s"\n' % self.sUnitTestsPathSrc);
613
614 if not self.sUnitTestsPathDst:
615 self.sUnitTestsPathDst = self.sScratchPath;
616 reporter.log2('Unit test destination path is "%s"\n' % self.sUnitTestsPathDst);
617
618 if self.sMode.startswith('remote'): # Run on a test VM (guest).
619 if self.fpApiVer < 7.0: ## @todo Needs Validation Kit .ISO tweaking (including the unit tests) first.
620 reporter.log('Remote unit tests for non-trunk builds skipped.');
621 fRc = True;
622 else:
623 assert self.oTestVmSet is not None;
624 fRc = self.oTestVmSet.actionExecute(self, self.testOneVmConfig);
625 else: # Run locally (host).
626 self._figureVersion();
627 self._makeEnvironmentChanges();
628 fRc = self._testRunUnitTests(None);
629
630 return fRc;
631
632 #
633 # Test execution helpers.
634 #
635
636 def _testRunUnitTests(self, oTestVm):
637 """
638 Main function to execute all unit tests.
639 """
640
641 # Determine executable suffix based on selected execution mode.
642 if self.sMode.startswith('remote'): # Run on a test VM (guest).
643 if oTestVm.isWindows():
644 self.sExeSuff = '.exe';
645 else:
646 self.sExeSuff = '';
647 else:
648 self.sExeSuff = '.exe' if utils.getHostOs() in [ 'win', 'dos', 'os2' ] else '';
649
650 self._testRunUnitTestsSet(oTestVm, r'^tst*', 'testcase');
651 self._testRunUnitTestsSet(oTestVm, r'^tst*', '.');
652
653 fRc = self.cFailed == 0;
654
655 reporter.log('');
656 if self.fDryRun:
657 reporter.log('*********************************************************');
658 reporter.log('DRY RUN - DRY RUN - DRY RUN - DRY RUN - DRY RUN - DRY RUN');
659 reporter.log('*********************************************************');
660 reporter.log('*********************************************************');
661 reporter.log(' Target: %s' % (oTestVm.sVmName if oTestVm else 'local'));
662 reporter.log(' Mode: %s' % (self.sMode));
663 reporter.log('Unit tests source: %s %s' % (self.sUnitTestsPathSrc, \
664 '(on remote)' if self.sMode == 'remote-exec' else ''));
665 reporter.log('VBox install root: %s %s' % (self.sVBoxInstallRoot, \
666 '(on remote)' if self.sMode == 'remote-exec' else ''));
667 reporter.log('*********************************************************');
668 reporter.log('*** PASSED: %d' % self.cPassed);
669 reporter.log('*** FAILED: %d' % self.cFailed);
670 reporter.log('*** SKIPPED: %d' % self.cSkipped);
671 reporter.log('*** TOTAL: %d' % (self.cPassed + self.cFailed + self.cSkipped));
672
673 return fRc;
674
675
676 def testOneVmConfig(self, oVM, oTestVm):
677 """
678 Runs the specified VM thru test #1.
679 """
680
681 # Simple test.
682 self.logVmInfo(oVM);
683
684 if not self.fDryRun:
685 # Try waiting for a bit longer (5 minutes) until the CD is available to avoid running into timeouts.
686 self.oSession, self.oTxsSession = self.startVmAndConnectToTxsViaTcp(oTestVm.sVmName, \
687 fCdWait = not self.fDryRun, \
688 cMsCdWait = 5 * 60 * 1000);
689 if self.oSession is None:
690 return False;
691
692 self.addTask(self.oTxsSession);
693
694 # Determine the unit tests destination path.
695 self.sUnitTestsPathDst = oTestVm.pathJoin(self.getGuestTempDir(oTestVm), 'testUnitTests');
696
697 # Run the unit tests.
698 self._testRunUnitTests(oTestVm);
699
700 # Cleanup.
701 if self.oSession is not None:
702 self.removeTask(self.oTxsSession);
703 self.terminateVmBySession(self.oSession);
704 return True;
705
706 #
707 # Test execution helpers.
708 #
709
710 def _figureVersion(self):
711 """ Tries to figure which VBox version this is, setting self.aiVBoxVer. """
712 try:
713 sVer = utils.processOutputChecked(['VBoxManage', '--version'])
714
715 sVer = sVer.strip();
716 sVer = re.sub(r'_BETA.*r', '.', sVer);
717 sVer = re.sub(r'_ALPHA.*r', '.', sVer);
718 sVer = re.sub(r'_RC.*r', '.', sVer);
719 sVer = re.sub('_SPB', '', sVer)
720 sVer = sVer.replace('r', '.');
721
722 self.aiVBoxVer = [int(sComp) for sComp in sVer.split('.')];
723
724 reporter.log('VBox version: %s' % (self.aiVBoxVer,));
725 except:
726 reporter.logXcpt();
727 return False;
728 return True;
729
730 def _compareVersion(self, aiVer):
731 """
732 Compares the give version string with the vbox version string,
733 returning a result similar to C strcmp(). aiVer is on the right side.
734 """
735 cComponents = min(len(self.aiVBoxVer), len(aiVer));
736 for i in range(cComponents):
737 if self.aiVBoxVer[i] < aiVer[i]:
738 return -1;
739 if self.aiVBoxVer[i] > aiVer[i]:
740 return 1;
741 return len(self.aiVBoxVer) - len(aiVer);
742
743 def _isExcluded(self, sTest, dExclList):
744 """ Checks if the testcase is excluded or not. """
745 if sTest in dExclList:
746 sFullExpr = dExclList[sTest].replace(' ', '').strip();
747 if sFullExpr == '':
748 return True;
749
750 # Consider each exclusion expression. These are generally ranges,
751 # either open ended or closed: "<4.3.51r12345", ">=4.3.0 && <=4.3.4".
752 asExprs = sFullExpr.split(';');
753 for sExpr in asExprs:
754
755 # Split it on the and operator and process each sub expression.
756 fResult = True;
757 for sSubExpr in sExpr.split('&&'):
758 # Split out the comparison operator and the version value.
759 if sSubExpr.startswith('<=') or sSubExpr.startswith('>='):
760 sOp = sSubExpr[:2];
761 sValue = sSubExpr[2:];
762 elif sSubExpr.startswith('<') or sSubExpr.startswith('>') or sSubExpr.startswith('='):
763 sOp = sSubExpr[:1];
764 sValue = sSubExpr[1:];
765 else:
766 sOp = sValue = '';
767
768 # Convert the version value, making sure we've got a valid one.
769 try: aiValue = [int(sComp) for sComp in sValue.replace('r', '.').split('.')];
770 except: aiValue = ();
771 if not aiValue or len(aiValue) > 4:
772 reporter.error('Invalid exclusion expression for %s: "%s" [%s]' % (sTest, sSubExpr, dExclList[sTest]));
773 return True;
774
775 # Do the compare.
776 iCmp = self._compareVersion(aiValue);
777 if sOp == '>=' and iCmp < 0:
778 fResult = False;
779 elif sOp == '>' and iCmp <= 0:
780 fResult = False;
781 elif sOp == '<' and iCmp >= 0:
782 fResult = False;
783 elif sOp == '>=' and iCmp < 0:
784 fResult = False;
785 reporter.log2('iCmp=%s; %s %s %s -> %s' % (iCmp, self.aiVBoxVer, sOp, aiValue, fResult));
786
787 # Did the expression match?
788 if fResult:
789 return True;
790
791 return False;
792
793 def _sudoExecuteSync(self, asArgs):
794 """
795 Executes a sudo child process synchronously.
796 Returns True if the process executed successfully and returned 0,
797 otherwise False is returned.
798 """
799 reporter.log2('Executing [sudo]: %s' % (asArgs, ));
800 if self.sMode.startswith('remote'):
801 iRc = -1; ## @todo Not used remotely yet.
802 else:
803 try:
804 iRc = utils.sudoProcessCall(asArgs, shell = False, close_fds = False);
805 except:
806 reporter.errorXcpt();
807 return False;
808 reporter.log('Exit code [sudo]: %s (%s)' % (iRc, asArgs));
809 return iRc == 0;
810
811
812 def _logExpandString(self, sString, cVerbosity = 2):
813 """
814 Expands a given string by asking TxS on the guest side and logs it.
815 Uses log level 2 by default.
816
817 No-op if no TxS involved.
818 """
819 if reporter.getVerbosity() < cVerbosity \
820 or self.oTxsSession is None:
821 return;
822 sStringExp = self.oTxsSession.syncExpandString(sString);
823 if not sStringExp:
824 return;
825 reporter.log2('_logExpandString: "%s" -> "%s"' % (sString, sStringExp));
826
827 def _wrapPathExists(self, sPath):
828 """
829 Creates the directory specified sPath (including parents).
830 """
831 reporter.log2('_wrapPathExists: %s' % (sPath,));
832 if self.fDryRun:
833 return True;
834 fRc = False;
835 if self.sMode.startswith('remote'):
836 self._logExpandString(sPath);
837 fRc = self.oTxsSession.syncIsDir(sPath, fIgnoreErrors = True);
838 if not fRc:
839 fRc = self.oTxsSession.syncIsFile(sPath, fIgnoreErrors = True);
840 else:
841 fRc = os.path.exists(sPath);
842 return fRc;
843
844 def _wrapMkDir(self, sPath):
845 """
846 Creates the directory specified sPath (including parents).
847 """
848 reporter.log2('_wrapMkDir: %s' % (sPath,));
849 if self.fDryRun:
850 return True;
851 fRc = True;
852 if self.sMode.startswith('remote'):
853 fRc = self.oTxsSession.syncMkDirPath(sPath, fMode = 0o755);
854 else:
855 if utils.getHostOs() in [ 'win', 'os2' ]:
856 os.makedirs(sPath, 0o755);
857 else:
858 fRc = self._sudoExecuteSync(['/bin/mkdir', '-p', '-m', '0755', sPath]);
859 if not fRc:
860 reporter.log('Failed to create dir "%s".' % (sPath,));
861 return fRc;
862
863 def _wrapCopyFile(self, sSrc, sDst, iMode):
864 """
865 Copies a file.
866 """
867 reporter.log2('_wrapCopyFile: %s -> %s (mode: %o)' % (sSrc, sDst, iMode,));
868 if self.fDryRun:
869 return True;
870 fRc = True;
871 if self.sMode.startswith('remote'):
872 self._logExpandString(sSrc);
873 self._logExpandString(sDst);
874 if self.sMode == 'remote-exec':
875 self.oTxsSession.syncCopyFile(sSrc, sDst, iMode);
876 else:
877 fRc = self.oTxsSession.syncUploadFile(sSrc, sDst);
878 if fRc:
879 fRc = self.oTxsSession.syncChMod(sDst, iMode);
880 else:
881 if utils.getHostOs() in [ 'win', 'os2' ]:
882 utils.copyFileSimple(sSrc, sDst);
883 os.chmod(sDst, iMode);
884 else:
885 fRc = self._sudoExecuteSync(['/bin/cp', sSrc, sDst]);
886 if fRc:
887 fRc = self._sudoExecuteSync(['/bin/chmod', '%o' % (iMode,), sDst]);
888 if fRc is not True:
889 raise Exception('Failed to chmod "%s".' % (sDst,));
890 if not fRc:
891 reporter.log('Failed to copy "%s" to "%s".' % (sSrc, sDst,));
892 return fRc;
893
894 def _wrapDeleteFile(self, sPath):
895 """
896 Deletes a file.
897 """
898 reporter.log2('_wrapDeleteFile: %s' % (sPath,));
899 if self.fDryRun:
900 return True;
901 fRc = True;
902 if self.sMode.startswith('remote'):
903 if self.oTxsSession.syncIsFile(sPath):
904 fRc = self.oTxsSession.syncRmFile(sPath, fIgnoreErrors = True);
905 else:
906 if os.path.exists(sPath):
907 if utils.getHostOs() in [ 'win', 'os2' ]:
908 os.remove(sPath);
909 else:
910 fRc = self._sudoExecuteSync(['/bin/rm', sPath]);
911 if not fRc:
912 reporter.log('Failed to remove "%s".' % (sPath,));
913 return fRc;
914
915 def _wrapRemoveDir(self, sPath):
916 """
917 Removes a directory.
918 """
919 reporter.log2('_wrapRemoveDir: %s' % (sPath,));
920 if self.fDryRun:
921 return True;
922 fRc = True;
923 if self.sMode.startswith('remote'):
924 if self.oTxsSession.syncIsDir(sPath):
925 fRc = self.oTxsSession.syncRmDir(sPath, fIgnoreErrors = True);
926 else:
927 if os.path.exists(sPath):
928 if utils.getHostOs() in [ 'win', 'os2' ]:
929 os.rmdir(sPath);
930 else:
931 fRc = self._sudoExecuteSync(['/bin/rmdir', sPath]);
932 if not fRc:
933 reporter.log('Failed to remove "%s".' % (sPath,));
934 return fRc;
935
936 def _envSet(self, sName, sValue):
937 if self.sMode.startswith('remote'):
938 # For remote execution we cache the environment block and pass it
939 # right when the process execution happens.
940 self.asEnv.append([ sName, sValue ]);
941 else:
942 os.environ[sName] = sValue;
943 return True;
944
945 def _executeTestCase(self, oTestVm, sName, sFullPath, sTestCaseSubDir, oDevNull): # pylint: disable=too-many-locals,too-many-statements
946 """
947 Executes a test case.
948 """
949
950 fSkipped = False;
951
952 #
953 # If hardening is enabled, some test cases and their dependencies
954 # needs to be copied to and execute from the source
955 # directory in order to work. They also have to be executed as
956 # root, i.e. via sudo.
957 #
958 fHardened = False;
959 fCopyToRemote = False;
960 fCopyDeps = False;
961 asFilesToRemove = []; # Stuff to clean up.
962 asDirsToRemove = []; # Ditto.
963
964 if sName in self.kasHardened \
965 and self.sUnitTestsPathSrc != self.sVBoxInstallRoot:
966 fHardened = True;
967
968 if self.sMode.startswith('remote'):
969 fCopyToRemote = True;
970 fCopyDeps = True;
971
972 if fHardened \
973 or fCopyToRemote:
974 if fCopyToRemote:
975 sDstDir = os.path.join(self.sUnitTestsPathDst, sTestCaseSubDir);
976 else:
977 sDstDir = os.path.join(self.sVBoxInstallRoot, sTestCaseSubDir);
978 if not self._wrapPathExists(sDstDir):
979 self._wrapMkDir(sDstDir);
980 asDirsToRemove.append(sDstDir);
981
982 sSrc = sFullPath + self.sExeSuff;
983 # If the testcase source does not exist for whatever reason, just mark it as skipped
984 # instead of reporting an error.
985 if not self._wrapPathExists(sSrc):
986 self.cSkipped += 1;
987 fSkipped = True;
988 return fSkipped;
989
990 sDst = os.path.join(sDstDir, os.path.basename(sFullPath) + self.sExeSuff);
991 fModeExe = 0;
992 fModeDeps = 0;
993 if not oTestVm \
994 or (oTestVm and not oTestVm.isWindows()): ## @todo NT4 does not like the chmod. Investigate this!
995 fModeExe = 0o755;
996 fModeDeps = 0o644;
997 self._wrapCopyFile(sSrc, sDst, fModeExe);
998 asFilesToRemove.append(sDst);
999
1000 # Copy required dependencies to destination.
1001 if fCopyDeps:
1002 for sLib in self.kdTestCaseDepsLibs:
1003 for sSuff in [ '.dll', '.so', '.dylib' ]:
1004 assert self.sVBoxInstallRoot is not None;
1005 sSrc = os.path.join(self.sVBoxInstallRoot, sLib + sSuff);
1006 if self._wrapPathExists(sSrc):
1007 sDst = os.path.join(sDstDir, os.path.basename(sSrc));
1008 self._wrapCopyFile(sSrc, sDst, fModeDeps);
1009 asFilesToRemove.append(sDst);
1010
1011 # Copy any associated .dll/.so/.dylib.
1012 for sSuff in [ '.dll', '.so', '.dylib' ]:
1013 sSrc = os.path.splitext(sFullPath)[0] + sSuff;
1014 if os.path.exists(sSrc):
1015 sDst = os.path.join(sDstDir, os.path.basename(sSrc));
1016 self._wrapCopyFile(sSrc, sDst, fModeDeps);
1017 asFilesToRemove.append(sDst);
1018
1019 # Copy any associated .r0, .rc and .gc modules.
1020 offDriver = sFullPath.rfind('Driver')
1021 if offDriver > 0:
1022 for sSuff in [ '.r0', 'RC.rc', 'RC.gc' ]:
1023 sSrc = sFullPath[:offDriver] + sSuff;
1024 if os.path.exists(sSrc):
1025 sDst = os.path.join(sDstDir, os.path.basename(sSrc));
1026 self._wrapCopyFile(sSrc, sDst, fModeDeps);
1027 asFilesToRemove.append(sDst);
1028
1029 sFullPath = os.path.join(sDstDir, os.path.basename(sFullPath));
1030
1031 #
1032 # Set up arguments and environment.
1033 #
1034 asArgs = [sFullPath + self.sExeSuff,]
1035 if sName in self.kdArguments:
1036 asArgs.extend(self.kdArguments[sName]);
1037
1038 sXmlFile = os.path.join(self.sUnitTestsPathDst, 'result.xml');
1039
1040 self._envSet('IPRT_TEST_OMIT_TOP_TEST', '1');
1041 self._envSet('IPRT_TEST_FILE', sXmlFile);
1042
1043 if self._wrapPathExists(sXmlFile):
1044 try: os.unlink(sXmlFile);
1045 except: self._wrapDeleteFile(sXmlFile);
1046
1047 #
1048 # Execute the test case.
1049 #
1050 # Windows is confusing output. Trying a few things to get rid of this.
1051 # First, flush both stderr and stdout before running the child. Second,
1052 # assign the child stderr to stdout. If this doesn't help, we'll have
1053 # to capture the child output.
1054 #
1055 reporter.log('*** Executing %s%s...' % (asArgs, ' [hardened]' if fHardened else ''));
1056 try: sys.stdout.flush();
1057 except: pass;
1058 try: sys.stderr.flush();
1059 except: pass;
1060
1061 iRc = 0;
1062
1063 if not self.fDryRun:
1064 if fCopyToRemote:
1065 fRc = self.txsRunTest(self.oTxsSession, sName, cMsTimeout = 30 * 60 * 1000, sExecName = asArgs[0], \
1066 asArgs = asArgs, asAddEnv = self.asEnv, fCheckSessionStatus = True);
1067 if fRc:
1068 iRc = 0;
1069 else:
1070 (_, sOpcode, abPayload) = self.oTxsSession.getLastReply();
1071 if sOpcode.startswith('PROC NOK '): # Extract process rc.
1072 iRc = abPayload[0]; # ASSUMES 8-bit rc for now.
1073 if iRc == 0: # Might happen if the testcase misses some dependencies. Set it to -42 then.
1074 iRc = -42;
1075 else:
1076 iRc = -1; ## @todo
1077 else:
1078 oChild = None;
1079 try:
1080 if fHardened:
1081 oChild = utils.sudoProcessPopen(asArgs, stdin = oDevNull, stdout = sys.stdout, stderr = sys.stdout);
1082 else:
1083 oChild = utils.processPopenSafe(asArgs, stdin = oDevNull, stdout = sys.stdout, stderr = sys.stdout);
1084 except:
1085 if sName in [ 'tstAsmStructsRC', # 32-bit, may fail to start on 64-bit linux. Just ignore.
1086 ]:
1087 reporter.logXcpt();
1088 fSkipped = True;
1089 else:
1090 reporter.errorXcpt();
1091 iRc = 1023;
1092 oChild = None;
1093
1094 if oChild is not None:
1095 self.pidFileAdd(oChild.pid, sName, fSudo = fHardened);
1096 iRc = oChild.wait();
1097 self.pidFileRemove(oChild.pid);
1098 #
1099 # Clean up
1100 #
1101 for sPath in asFilesToRemove:
1102 self._wrapDeleteFile(sPath);
1103 for sPath in asDirsToRemove:
1104 self._wrapRemoveDir(sPath);
1105
1106 #
1107 # Report.
1108 #
1109 if os.path.exists(sXmlFile):
1110 reporter.addSubXmlFile(sXmlFile);
1111 if fHardened:
1112 self._wrapDeleteFile(sXmlFile);
1113 else:
1114 os.unlink(sXmlFile);
1115
1116 if iRc == 0:
1117 reporter.log('*** %s: exit code %d' % (sFullPath, iRc));
1118 self.cPassed += 1;
1119
1120 elif iRc == 4: # RTEXITCODE_SKIPPED
1121 reporter.log('*** %s: exit code %d (RTEXITCODE_SKIPPED)' % (sFullPath, iRc));
1122 fSkipped = True;
1123 self.cSkipped += 1;
1124
1125 elif fSkipped:
1126 reporter.log('*** %s: exit code %d (Skipped)' % (sFullPath, iRc));
1127 self.cSkipped += 1;
1128
1129 else:
1130 sName = self.kdExitCodeNames.get(iRc, '');
1131 if iRc in self.kdExitCodeNamesWin and utils.getHostOs() == 'win':
1132 sName = self.kdExitCodeNamesWin[iRc];
1133 if sName != '':
1134 sName = ' (%s)' % (sName);
1135
1136 if iRc != 1:
1137 reporter.testFailure('Exit status: %d%s' % (iRc, sName));
1138 reporter.log( '!*! %s: exit code %d%s' % (sFullPath, iRc, sName));
1139 else:
1140 reporter.error('!*! %s: exit code %d%s' % (sFullPath, iRc, sName));
1141 self.cFailed += 1;
1142
1143 return fSkipped;
1144
1145 def _testRunUnitTestsSet(self, oTestVm, sTestCasePattern, sTestCaseSubDir):
1146 """
1147 Run subset of the unit tests set.
1148 """
1149
1150 # Open /dev/null for use as stdin further down.
1151 try:
1152 oDevNull = open(os.path.devnull, 'w+'); # pylint: disable=consider-using-with
1153 except:
1154 oDevNull = None;
1155
1156 # Determin the host OS specific exclusion lists.
1157 dTestCasesBuggyForHostOs = self.kdTestCasesBuggyPerOs.get(utils.getHostOs(), []);
1158 dTestCasesBuggyForHostOs.update(self.kdTestCasesBuggyPerOs.get(utils.getHostOsDotArch(), []));
1159
1160 ## @todo Add filtering for more specific OSes (like OL server, doesn't have X installed) by adding a separate
1161 # black list + using utils.getHostOsVersion().
1162
1163 #
1164 # Process the file list and run everything looking like a testcase.
1165 #
1166 if not self.fOnlyWhiteList:
1167 if self.sMode == 'local' \
1168 or self.sMode == 'remote-copy':
1169 asFiles = sorted(os.listdir(os.path.join(self.sUnitTestsPathSrc, sTestCaseSubDir)));
1170 else: # 'remote-exec'
1171 ## @todo Implement remote file enumeration / directory listing.
1172 reporter.error('Sorry, no remote file enumeration implemented yet!\nUse --only-whitelist instead.');
1173 return;
1174 else:
1175 # Transform our dict into a list, where the keys are the list elements.
1176 asFiles = list(self.kdTestCasesWhiteList.keys());
1177 # Make sure to only keep the list item's base name so that the iteration down below works
1178 # with our white list without any additional modification.
1179 asFiles = [os.path.basename(s) for s in asFiles];
1180
1181 for sFilename in asFiles:
1182 # Separate base and suffix and morph the base into something we
1183 # can use for reporting and array lookups.
1184 sBaseName = os.path.basename(sFilename);
1185 sName, sSuffix = os.path.splitext(sBaseName);
1186 if sTestCaseSubDir != '.':
1187 sName = sTestCaseSubDir + '/' + sName;
1188
1189 reporter.log2('sTestCasePattern=%s, sBaseName=%s, sName=%s, sSuffix=%s, sFileName=%s' \
1190 % (sTestCasePattern, sBaseName, sName, sSuffix, sFilename,));
1191
1192 # Process white list first, if set.
1193 if self.fOnlyWhiteList \
1194 and not self._isExcluded(sName, self.kdTestCasesWhiteList):
1195 reporter.log('%s: SKIPPED (not in white list)' % (sName,));
1196 continue;
1197
1198 # Basic exclusion.
1199 if not re.match(sTestCasePattern, sBaseName) \
1200 or sSuffix in self.kasSuffixBlackList:
1201 reporter.log2('"%s" is not a test case.' % (sName,));
1202 continue;
1203
1204 # Check if the testcase is black listed or buggy before executing it.
1205 if self._isExcluded(sName, self.kdTestCasesBlackList):
1206 # (No testStart/Done or accounting here!)
1207 reporter.log('%s: SKIPPED (blacklisted)' % (sName,));
1208
1209 elif self._isExcluded(sName, self.kdTestCasesBuggy):
1210 reporter.testStart(sName);
1211 reporter.log('%s: Skipping, buggy in general.' % (sName,));
1212 reporter.testDone(fSkipped = True);
1213 self.cSkipped += 1;
1214
1215 elif self._isExcluded(sName, dTestCasesBuggyForHostOs):
1216 reporter.testStart(sName);
1217 reporter.log('%s: Skipping, buggy on %s.' % (sName, utils.getHostOs(),));
1218 reporter.testDone(fSkipped = True);
1219 self.cSkipped += 1;
1220
1221 else:
1222 sFullPath = os.path.normpath(os.path.join(self.sUnitTestsPathSrc, os.path.join(sTestCaseSubDir, sFilename)));
1223 reporter.testStart(sName);
1224 try:
1225 fSkipped = self._executeTestCase(oTestVm, sName, sFullPath, sTestCaseSubDir, oDevNull);
1226 except:
1227 reporter.errorXcpt('!*!');
1228 self.cFailed += 1;
1229 fSkipped = False;
1230 reporter.testDone(fSkipped);
1231
1232
1233
1234if __name__ == '__main__':
1235 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