VirtualBox

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

Last change on this file since 97487 was 97487, checked in by vboxsync, 2 years ago

ValKit/tdUnitTest1.py: Some nits and tiny cleanups.

  • Property svn:eol-style set to LF
  • Property svn:executable set to *
  • Property svn:keywords set to Author Date Id Revision
File size: 53.2 KB
Line 
1#!/usr/bin/env python
2# -*- coding: utf-8 -*-
3# $Id: tdUnitTest1.py 97487 2022-11-09 20:39:53Z 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: 97487 $"
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 'testcase/tstClipboardMockHGCM': '', # Ditto.
136 'tstClipboardQt': '', # Is interactive and needs Qt, needed for Qt clipboard bugfixing.
137 'testcase/tstClipboardQt': '', # In case it moves here.
138 'testcase/tstFileLock': '',
139 'testcase/tstDisasm-2': '', # without parameters it will disassembler 1GB starting from 0
140 'testcase/tstFileAppendWin-1': '',
141 'testcase/tstDir': '', # useless without parameters
142 'testcase/tstDir-2': '', # useless without parameters
143 'testcase/tstGlobalConfig': '',
144 'testcase/tstHostHardwareLinux': '', # must be killed with CTRL-C
145 'testcase/tstHttp': '', # Talks to outside servers.
146 'testcase/tstRTHttp': '', # parameters required
147 'testcase/tstLdr-2': '', # parameters required
148 'testcase/tstLdr-3': '', # parameters required
149 'testcase/tstLdr': '', # parameters required
150 'testcase/tstLdrLoad': '', # parameters required
151 'testcase/tstMove': '', # parameters required
152 'testcase/tstRTR0Timer': '', # loads 'tstRTR0Timer.r0'
153 'testcase/tstRTR0ThreadDriver': '', # loads 'tstRTR0Thread.r0'
154 'testcase/tstRunTestcases': '', # that's a script like this one
155 'testcase/tstRTReqPool': '', # fails sometimes, testcase buggy
156 'testcase/tstRTS3': '', # parameters required
157 'testcase/tstSDL': '', # graphics test
158 'testcase/tstSupLoadModule': '', # Needs parameters and vboxdrv access. Covered elsewhere.
159 'testcase/tstSeamlessX11': '', # graphics test
160 'testcase/tstTime-3': '', # parameters required
161 'testcase/tstVBoxControl': '', # works only inside a guest
162 'testcase/tstVDCopy': '', # parameters required
163 'testcase/tstVDFill': '', # parameters required
164 'tstAnimate': '', # parameters required
165 'testcase/tstAPI': '', # user interaction required
166 'tstCollector': '', # takes forever
167 'testcase/tstHeadless': '', # parameters required
168 'tstHeadless': '', # parameters required
169 'tstMicroRC': '', # required by tstMicro
170 'tstVBoxDbg': '', # interactive test
171 'testcase/tstTestServMgr': '', # some strange xpcom18a4 test, does not work
172 'tstTestServMgr': '', # some strange xpcom18a4 test, does not work
173 'tstPDMAsyncCompletion': '', # parameters required
174 'testcase/tstXptDump': '', # parameters required
175 'tstXptDump': '', # parameters required
176 'testcase/tstnsIFileEnumerator': '', # some strange xpcom18a4 test, does not work
177 'tstnsIFileEnumerator': '', # some strange xpcom18a4 test, does not work
178 'testcase/tstSimpleTypeLib': '', # parameters required
179 'tstSimpleTypeLib': '', # parameters required
180 'testcase/tstTestAtoms': '', # additional test file (words.txt) required
181 'tstTestAtoms': '', # additional test file (words.txt) required
182 'testcase/tstXptLink': '', # parameters required
183 'tstXptLink': '', # parameters required
184 'tstXPCOMCGlue': '', # user interaction required
185 'testcase/tstXPCOMCGlue': '', # user interaction required
186 'testcase/tstCAPIGlue': '', # user interaction required
187 'testcase/tstTestCallTemplates': '', # some strange xpcom18a4 test, segfaults
188 'tstTestCallTemplates': '', # some strange xpcom18a4 test, segfaults
189 'testcase/tstRTFilesystem': '', # parameters required
190 'testcase/tstRTDvm': '', # parameters required
191 'tstSSLCertDownloads': '', # Obsolete.
192 # later
193 'testcase/tstIntNetR0': '', # RTSPINLOCK_FLAGS_INTERRUPT_SAFE == RTSPINLOCK_FLAGS_INTERRUPT_UNSAFE
194 # slow stuff
195 'testcase/tstAvl': '', # SLOW!
196 'testcase/tstRTAvl': '', # SLOW! (new name)
197 'testcase/tstVD': '', # 8GB fixed-sized vmdk
198 # failed or hang
199 'testcase/tstCryptoPkcs7Verify': '', # hang
200 'tstOVF': '', # hang (only ancient version, now in new place)
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 #
262 # When --only-whitelist is specified, this is the only list being checked for.
263 kdTestCasesWhiteList = {
264 'testcase/tstFile': '',
265 'testcase/tstFileLock': '',
266 'testcase/tstClipboardMockHGCM': '', # Requires X on Linux OSes. Execute on remote targets only (guests).
267 'testcase/tstRTLocalIpc': '',
268 'testcase/tstRTPathQueryInfo': '',
269 'testcase/tstRTPipe': '',
270 'testcase/tstRTProcCreateEx': '',
271 'testcase/tstRTProcCreatePrf': '',
272 'testcase/tstRTProcIsRunningByName': '',
273 'testcase/tstRTProcQueryUsername': '',
274 'testcase/tstRTProcWait': '',
275 'testcase/tstTime-2': '',
276 'testcase/tstTime-3': '',
277 'testcase/tstTime-4': '',
278 'testcase/tstTimer': '',
279 'testcase/tstThread-1': '',
280 'testcase/tstUtf8': ''
281 };
282
283 # Test dependency list -- libraries.
284 # Needed in order to execute testcases on remote targets which don't have a VBox installation present.
285 kdTestCaseDepsLibs = [
286 "VBoxRT"
287 ];
288
289 ## The exclude list.
290 # @note Stripped extensions!
291 kasHardened = [
292 "testcase/tstIntNet-1",
293 "testcase/tstR0ThreadPreemptionDriver", # VBox 4.3
294 "testcase/tstRTR0ThreadPreemptionDriver",
295 "testcase/tstRTR0MemUserKernelDriver",
296 "testcase/tstRTR0SemMutexDriver",
297 "testcase/tstRTR0TimerDriver",
298 "testcase/tstRTR0ThreadDriver",
299 'testcase/tstRTR0DbgKrnlInfoDriver',
300 "tstInt",
301 "tstPDMQueue", # Comment in testcase says its driverless, but it needs driver access.
302 "tstVMM",
303 "tstVMMFork",
304 "tstVMREQ",
305 'testcase/tstCFGM',
306 'testcase/tstContiguous',
307 'testcase/tstGetPagingMode',
308 'testcase/tstGIP-2',
309 'testcase/tstInit',
310 'testcase/tstLow',
311 'testcase/tstMMHyperHeap',
312 'testcase/tstPage',
313 'testcase/tstPin',
314 'testcase/tstRTTime', 'testcase/tstTime', # GIP test case.
315 'testcase/tstRTTime-2', 'testcase/tstTime-2', # GIP test case.
316 'testcase/tstRTTime-4', 'testcase/tstTime-4', # GIP test case.
317 'testcase/tstSSM',
318 'testcase/tstSupSem-Zombie',
319 ]
320
321 ## Argument lists
322 kdArguments = {
323 'testcase/tstbntest': [ '-out', os.devnull, ], # Very noisy.
324 };
325
326
327 ## Status code translations.
328 ## @{
329 kdExitCodeNames = {
330 0: 'RTEXITCODE_SUCCESS',
331 1: 'RTEXITCODE_FAILURE',
332 2: 'RTEXITCODE_SYNTAX',
333 3: 'RTEXITCODE_INIT',
334 4: 'RTEXITCODE_SKIPPED',
335 };
336 kdExitCodeNamesWin = {
337 -1073741515: 'STATUS_DLL_NOT_FOUND',
338 -1073741512: 'STATUS_ORDINAL_NOT_FOUND',
339 -1073741511: 'STATUS_ENTRYPOINT_NOT_FOUND',
340 -1073741502: 'STATUS_DLL_INIT_FAILED',
341 -1073741500: 'STATUS_UNHANDLED_EXCEPTION',
342 -1073741499: 'STATUS_APP_INIT_FAILURE',
343 -1073741819: 'STATUS_ACCESS_VIOLATION',
344 -1073741571: 'STATUS_STACK_OVERFLOW',
345 };
346 ## @}
347
348 def __init__(self):
349 """
350 Reinitialize child class instance.
351 """
352 vbox.TestDriver.__init__(self);
353
354 # We need to set a default test VM set here -- otherwise the test
355 # driver base class won't let us use the "--test-vms" switch.
356 #
357 # See the "--local" switch in self.parseOption().
358 self.oTestVmSet = self.oTestVmManager.getSmokeVmSet('nat');
359
360 # Selected NIC attachment.
361 self.sNicAttachment = '';
362
363 # Session handling stuff.
364 # Only needed for remote tests executed by TxS.
365 self.oSession = None;
366 self.oTxsSession = None;
367
368 self.sVBoxInstallRoot = None;
369
370 ## Testing mode being used:
371 # "local": Execute unit tests locally (same host, default).
372 # "remote-copy": Copies unit tests from host to the remote, then executing it.
373 # "remote-exec": Executes unit tests right on the remote from a given source.
374 self.sMode = 'local';
375
376 self.cSkipped = 0;
377 self.cPassed = 0;
378 self.cFailed = 0;
379
380 # The source directory where our unit tests live.
381 # This most likely is our out/ or some staging directory and
382 # also acts the source for copying over the testcases to a remote target.
383 self.sUnitTestsPathSrc = None;
384
385 # Array of environment variables with NAME=VAL entries
386 # to be applied for testcases.
387 #
388 # This is also needed for testcases which are being executed remotely.
389 self.asEnv = [];
390
391 # The destination directory our unit tests live when being
392 # copied over to a remote target (via TxS).
393 self.sUnitTestsPathDst = None;
394
395 # Will be determined before executing the actual unit tests.
396 self.sExeSuff = '';
397
398 self.aiVBoxVer = (4, 3, 0, 0);
399
400 # For testing testcase logic.
401 self.fDryRun = False;
402 self.fOnlyWhiteList = False;
403
404 @staticmethod
405 def _sanitizePath(sPath):
406 """
407 Does a little bit of sanitizing a given path by removing quoting, if any.
408
409 This is needed because handed-in paths via command line arguments can contain variables like "${CDROM}"
410 which might need to get processed by TXS on the guest side first.
411
412 Returns the sanitized path.
413 """
414 if sPath is None: # Keep uninitialized strings as-is.
415 return None;
416 return sPath.strip('\"').strip('\'');
417
418 def _detectPaths(self):
419 """
420 Internal worker for actionVerify and actionExecute that detects paths.
421
422 This sets sVBoxInstallRoot and sUnitTestsPathBase and returns True/False.
423 """
424
425 reporter.log2('Detecting paths ...');
426
427 #
428 # Do some sanity checking first.
429 #
430 if self.sMode == 'remote-exec' and not self.sUnitTestsPathSrc: # There is no way we can figure this out automatically.
431 reporter.error('Unit tests source must be specified explicitly for selected mode!');
432 return False;
433
434 #
435 # We need a VBox install (/ build) to test.
436 #
437 if False is True: ## @todo r=andy WTF?
438 if not self.importVBoxApi():
439 reporter.error('Unabled to import the VBox Python API.');
440 return False;
441 else:
442 self._detectBuild();
443 if self.oBuild is None:
444 reporter.error('Unabled to detect the VBox build.');
445 return False;
446
447 #
448 # Where are the files installed?
449 # Solaris requires special handling because of it's multi arch subdirs.
450 #
451 if not self.sVBoxInstallRoot:
452 self.sVBoxInstallRoot = self.oBuild.sInstallPath;
453 if not self.oBuild.isDevBuild() and utils.getHostOs() == 'solaris':
454 sArchDir = utils.getHostArch();
455 if sArchDir == 'x86': sArchDir = 'i386';
456 self.sVBoxInstallRoot = os.path.join(self.sVBoxInstallRoot, sArchDir);
457
458 ## @todo r=andy Make sure the install root really exists and is accessible.
459
460 # Add the installation root to the PATH on windows so we can get DLLs from it.
461 if utils.getHostOs() == 'win':
462 sPathName = 'PATH';
463 if not sPathName in os.environ:
464 sPathName = 'Path';
465 sPath = os.environ.get(sPathName, '.');
466 if sPath and sPath[-1] != ';':
467 sPath += ';';
468 os.environ[sPathName] = sPath + self.sVBoxInstallRoot + ';';
469 else:
470 reporter.log2('VBox installation root already set to "%s"' % (self.sVBoxInstallRoot));
471
472 self.sVBoxInstallRoot = self._sanitizePath(self.sVBoxInstallRoot);
473
474 #
475 # The unittests are generally not installed, so look for them.
476 #
477 if not self.sUnitTestsPathSrc:
478 sBinOrDist = 'dist' if utils.getHostOs() in [ 'darwin', ] else 'bin';
479 asCandidates = [
480 self.oBuild.sInstallPath,
481 os.path.join(self.sScratchPath, utils.getHostOsDotArch(), self.oBuild.sType, sBinOrDist),
482 os.path.join(self.sScratchPath, utils.getHostOsDotArch(), 'release', sBinOrDist),
483 os.path.join(self.sScratchPath, utils.getHostOsDotArch(), 'debug', sBinOrDist),
484 os.path.join(self.sScratchPath, utils.getHostOsDotArch(), 'strict', sBinOrDist),
485 os.path.join(self.sScratchPath, utils.getHostOsDotArch(), 'dbgopt', sBinOrDist),
486 os.path.join(self.sScratchPath, utils.getHostOsDotArch(), 'profile', sBinOrDist),
487 os.path.join(self.sScratchPath, sBinOrDist + '.' + utils.getHostArch()),
488 os.path.join(self.sScratchPath, sBinOrDist, utils.getHostArch()),
489 os.path.join(self.sScratchPath, sBinOrDist),
490 ];
491 if utils.getHostOs() == 'darwin':
492 for i in range(1, len(asCandidates)):
493 asCandidates[i] = os.path.join(asCandidates[i], 'VirtualBox.app', 'Contents', 'MacOS');
494
495 for sCandidat in asCandidates:
496 if os.path.exists(os.path.join(sCandidat, 'testcase', 'tstVMStructSize' + self.sExeSuff)):
497 self.sUnitTestsPathSrc = sCandidat;
498 break;
499
500 if not self.sUnitTestsPathSrc:
501 reporter.error('Unable to find unit test source dir. Candidates: %s' % (asCandidates,));
502 return False;
503 else:
504 reporter.log2('Unit test source dir already set to "%s"' % (self.sUnitTestsPathSrc));
505
506 self.sUnitTestsPathSrc = self._sanitizePath(self.sUnitTestsPathSrc);
507
508 return True;
509
510 #
511 # Overridden methods.
512 #
513
514 def showUsage(self):
515 """
516 Shows the testdriver usage.
517 """
518 fRc = vbox.TestDriver.showUsage(self);
519 reporter.log('');
520 reporter.log('Unit Test #1 options:');
521 reporter.log(' --dryrun');
522 reporter.log(' Performs a dryrun (no tests being executed).');
523 reporter.log(' --mode <local|remote-copy|remote-exec>');
524 reporter.log(' Specifies the test execution mode:');
525 reporter.log(' local: Locally on the same machine.');
526 reporter.log(' remote-copy: On remote (guest) by copying them from the local source.');
527 reporter.log(' remote-exec: On remote (guest) directly (needs unit test source).');
528 reporter.log(' --only-whitelist');
529 reporter.log(' Only processes the white list.');
530 reporter.log(' --quick');
531 reporter.log(' Very selective testing.');
532 reporter.log(' --unittest-source <dir>');
533 reporter.log(' Sets the unit test source to <dir>.');
534 reporter.log(' Also used for remote execution.');
535 reporter.log(' --vbox-install-root <dir>');
536 reporter.log(' Sets the VBox install root to <dir>.');
537 reporter.log(' Also used for remote execution.');
538 return fRc;
539
540 def parseOption(self, asArgs, iArg):
541 """
542 Parses the testdriver arguments from the command line.
543 """
544 if asArgs[iArg] == '--dryrun':
545 self.fDryRun = True;
546 elif asArgs[iArg] == '--mode':
547 iArg += 1;
548 if iArg >= len(asArgs):
549 raise base.InvalidOption('Option "%s" needs a value' % (asArgs[iArg - 1]));
550 if asArgs[iArg] in ('local', 'remote-copy', '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.isRemoteMode():
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.isRemoteMode(): # 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 # Misc.
634 #
635 def isRemoteMode(self):
636 """ Predicate method for checking if in any remote mode. """
637 return self.sMode.startswith('remote');
638
639 #
640 # Test execution helpers.
641 #
642
643 def _testRunUnitTests(self, oTestVm):
644 """
645 Main function to execute all unit tests.
646 """
647
648 # Determine executable suffix based on selected execution mode.
649 if self.isRemoteMode(): # Run on a test VM (guest).
650 if oTestVm.isWindows():
651 self.sExeSuff = '.exe';
652 else:
653 self.sExeSuff = '';
654 else:
655 self.sExeSuff = '.exe' if utils.getHostOs() in [ 'win', 'dos', 'os2' ] else '';
656
657 self._testRunUnitTestsSet(oTestVm, r'^tst*', 'testcase');
658 self._testRunUnitTestsSet(oTestVm, r'^tst*', '.');
659
660 fRc = self.cFailed == 0;
661
662 reporter.log('');
663 if self.fDryRun:
664 reporter.log('*********************************************************');
665 reporter.log('DRY RUN - DRY RUN - DRY RUN - DRY RUN - DRY RUN - DRY RUN');
666 reporter.log('*********************************************************');
667 reporter.log('*********************************************************');
668 reporter.log(' Target: %s' % (oTestVm.sVmName if oTestVm else 'local',));
669 reporter.log(' Mode: %s' % (self.sMode,));
670 reporter.log('Unit tests source: %s %s'
671 % (self.sUnitTestsPathSrc, '(on remote)' if self.sMode == 'remote-exec' else '',));
672 reporter.log('VBox install root: %s %s'
673 % (self.sVBoxInstallRoot, '(on remote)' if self.sMode == 'remote-exec' else '',));
674 reporter.log('*********************************************************');
675 reporter.log('*** PASSED: %d' % (self.cPassed,));
676 reporter.log('*** FAILED: %d' % (self.cFailed,));
677 reporter.log('*** SKIPPED: %d' % (self.cSkipped,));
678 reporter.log('*** TOTAL: %d' % (self.cPassed + self.cFailed + self.cSkipped,));
679
680 return fRc;
681
682
683 def testOneVmConfig(self, oVM, oTestVm):
684 """
685 Runs the specified VM thru test #1.
686 """
687
688 # Simple test.
689 self.logVmInfo(oVM);
690
691 if not self.fDryRun:
692 # Try waiting for a bit longer (5 minutes) until the CD is available to avoid running into timeouts.
693 self.oSession, self.oTxsSession = self.startVmAndConnectToTxsViaTcp(oTestVm.sVmName,
694 fCdWait = not self.fDryRun,
695 cMsCdWait = 5 * 60 * 1000);
696 if self.oSession is None:
697 return False;
698
699 self.addTask(self.oTxsSession);
700
701 # Determine the unit tests destination path.
702 self.sUnitTestsPathDst = oTestVm.pathJoin(self.getGuestTempDir(oTestVm), 'testUnitTests');
703
704 # Run the unit tests.
705 self._testRunUnitTests(oTestVm);
706
707 # Cleanup.
708 if self.oSession is not None:
709 self.removeTask(self.oTxsSession);
710 self.terminateVmBySession(self.oSession);
711 return True;
712
713 #
714 # Test execution helpers.
715 #
716
717 def _figureVersion(self):
718 """ Tries to figure which VBox version this is, setting self.aiVBoxVer. """
719 try:
720 sVer = utils.processOutputChecked(['VBoxManage', '--version'])
721
722 sVer = sVer.strip();
723 sVer = re.sub(r'_BETA.*r', '.', sVer);
724 sVer = re.sub(r'_ALPHA.*r', '.', sVer);
725 sVer = re.sub(r'_RC.*r', '.', sVer);
726 sVer = re.sub('_SPB', '', sVer)
727 sVer = sVer.replace('r', '.');
728
729 self.aiVBoxVer = [int(sComp) for sComp in sVer.split('.')];
730
731 reporter.log('VBox version: %s' % (self.aiVBoxVer,));
732 except:
733 reporter.logXcpt();
734 return False;
735 return True;
736
737 def _compareVersion(self, aiVer):
738 """
739 Compares the give version string with the vbox version string,
740 returning a result similar to C strcmp(). aiVer is on the right side.
741 """
742 cComponents = min(len(self.aiVBoxVer), len(aiVer));
743 for i in range(cComponents):
744 if self.aiVBoxVer[i] < aiVer[i]:
745 return -1;
746 if self.aiVBoxVer[i] > aiVer[i]:
747 return 1;
748 return len(self.aiVBoxVer) - len(aiVer);
749
750 def _isExcluded(self, sTest, dExclList):
751 """ Checks if the testcase is excluded or not. """
752 if sTest in dExclList:
753 sFullExpr = dExclList[sTest].replace(' ', '').strip();
754 if sFullExpr == '':
755 return True;
756
757 # Consider each exclusion expression. These are generally ranges,
758 # either open ended or closed: "<4.3.51r12345", ">=4.3.0 && <=4.3.4".
759 asExprs = sFullExpr.split(';');
760 for sExpr in asExprs:
761
762 # Split it on the and operator and process each sub expression.
763 fResult = True;
764 for sSubExpr in sExpr.split('&&'):
765 # Split out the comparison operator and the version value.
766 if sSubExpr.startswith('<=') or sSubExpr.startswith('>='):
767 sOp = sSubExpr[:2];
768 sValue = sSubExpr[2:];
769 elif sSubExpr.startswith('<') or sSubExpr.startswith('>') or sSubExpr.startswith('='):
770 sOp = sSubExpr[:1];
771 sValue = sSubExpr[1:];
772 else:
773 sOp = sValue = '';
774
775 # Convert the version value, making sure we've got a valid one.
776 try: aiValue = [int(sComp) for sComp in sValue.replace('r', '.').split('.')];
777 except: aiValue = ();
778 if not aiValue or len(aiValue) > 4:
779 reporter.error('Invalid exclusion expression for %s: "%s" [%s]' % (sTest, sSubExpr, dExclList[sTest]));
780 return True;
781
782 # Do the compare.
783 iCmp = self._compareVersion(aiValue);
784 if sOp == '>=' and iCmp < 0:
785 fResult = False;
786 elif sOp == '>' and iCmp <= 0:
787 fResult = False;
788 elif sOp == '<' and iCmp >= 0:
789 fResult = False;
790 elif sOp == '>=' and iCmp < 0:
791 fResult = False;
792 reporter.log2('iCmp=%s; %s %s %s -> %s' % (iCmp, self.aiVBoxVer, sOp, aiValue, fResult));
793
794 # Did the expression match?
795 if fResult:
796 return True;
797
798 return False;
799
800 def _sudoExecuteSync(self, asArgs):
801 """
802 Executes a sudo child process synchronously.
803 Returns True if the process executed successfully and returned 0,
804 otherwise False is returned.
805 """
806 reporter.log2('Executing [sudo]: %s' % (asArgs, ));
807 if self.isRemoteMode():
808 iRc = -1; ## @todo Not used remotely yet.
809 else:
810 try:
811 iRc = utils.sudoProcessCall(asArgs, shell = False, close_fds = False);
812 except:
813 reporter.errorXcpt();
814 return False;
815 reporter.log('Exit code [sudo]: %s (%s)' % (iRc, asArgs));
816 return iRc == 0;
817
818
819 def _logExpandString(self, sString, cVerbosity = 2):
820 """
821 Expands a given string by asking TxS on the guest side and logs it.
822 Uses log level 2 by default.
823
824 No-op if no TxS involved.
825 """
826 if reporter.getVerbosity() < cVerbosity or self.oTxsSession is None:
827 return;
828 sStringExp = self.oTxsSession.syncExpandString(sString);
829 if not sStringExp:
830 return;
831 reporter.log2('_logExpandString: "%s" -> "%s"' % (sString, sStringExp));
832
833 def _wrapPathExists(self, sPath):
834 """
835 Creates the directory specified sPath (including parents).
836 """
837 reporter.log2('_wrapPathExists: %s' % (sPath,));
838 if self.fDryRun:
839 return True;
840 fRc = False;
841 if self.isRemoteMode():
842 self._logExpandString(sPath);
843 fRc = self.oTxsSession.syncIsDir(sPath, fIgnoreErrors = True);
844 if not fRc:
845 fRc = self.oTxsSession.syncIsFile(sPath, fIgnoreErrors = True);
846 else:
847 fRc = os.path.exists(sPath);
848 return fRc;
849
850 def _wrapMkDir(self, sPath):
851 """
852 Creates the directory specified sPath (including parents).
853 """
854 reporter.log2('_wrapMkDir: %s' % (sPath,));
855 if self.fDryRun:
856 return True;
857 fRc = True;
858 if self.isRemoteMode():
859 fRc = self.oTxsSession.syncMkDirPath(sPath, fMode = 0o755);
860 else:
861 if utils.getHostOs() in [ 'win', 'os2' ]:
862 os.makedirs(sPath, 0o755);
863 else:
864 fRc = self._sudoExecuteSync(['/bin/mkdir', '-p', '-m', '0755', sPath]);
865 if not fRc:
866 reporter.log('Failed to create dir "%s".' % (sPath,));
867 return fRc;
868
869 def _wrapCopyFile(self, sSrc, sDst, iMode):
870 """
871 Copies a file.
872 """
873 reporter.log2('_wrapCopyFile: %s -> %s (mode: %o)' % (sSrc, sDst, iMode,));
874 if self.fDryRun:
875 return True;
876 fRc = True;
877 if self.isRemoteMode():
878 self._logExpandString(sSrc);
879 self._logExpandString(sDst);
880 if self.sMode == 'remote-exec':
881 self.oTxsSession.syncCopyFile(sSrc, sDst, iMode);
882 else:
883 fRc = self.oTxsSession.syncUploadFile(sSrc, sDst);
884 if fRc:
885 fRc = self.oTxsSession.syncChMod(sDst, iMode);
886 else:
887 if utils.getHostOs() in [ 'win', 'os2' ]:
888 utils.copyFileSimple(sSrc, sDst);
889 os.chmod(sDst, iMode);
890 else:
891 fRc = self._sudoExecuteSync(['/bin/cp', sSrc, sDst]);
892 if fRc:
893 fRc = self._sudoExecuteSync(['/bin/chmod', '%o' % (iMode,), sDst]);
894 if fRc is not True:
895 raise Exception('Failed to chmod "%s".' % (sDst,));
896 if not fRc:
897 reporter.log('Failed to copy "%s" to "%s".' % (sSrc, sDst,));
898 return fRc;
899
900 def _wrapDeleteFile(self, sPath):
901 """
902 Deletes a file.
903 """
904 reporter.log2('_wrapDeleteFile: %s' % (sPath,));
905 if self.fDryRun:
906 return True;
907 fRc = True;
908 if self.isRemoteMode():
909 if self.oTxsSession.syncIsFile(sPath):
910 fRc = self.oTxsSession.syncRmFile(sPath, fIgnoreErrors = True);
911 else:
912 if os.path.exists(sPath):
913 if utils.getHostOs() in [ 'win', 'os2' ]:
914 os.remove(sPath);
915 else:
916 fRc = self._sudoExecuteSync(['/bin/rm', sPath]);
917 if not fRc:
918 reporter.log('Failed to remove "%s".' % (sPath,));
919 return fRc;
920
921 def _wrapRemoveDir(self, sPath):
922 """
923 Removes a directory.
924 """
925 reporter.log2('_wrapRemoveDir: %s' % (sPath,));
926 if self.fDryRun:
927 return True;
928 fRc = True;
929 if self.isRemoteMode():
930 if self.oTxsSession.syncIsDir(sPath):
931 fRc = self.oTxsSession.syncRmDir(sPath, fIgnoreErrors = True);
932 else:
933 if os.path.exists(sPath):
934 if utils.getHostOs() in [ 'win', 'os2' ]:
935 os.rmdir(sPath);
936 else:
937 fRc = self._sudoExecuteSync(['/bin/rmdir', sPath]);
938 if not fRc:
939 reporter.log('Failed to remove "%s".' % (sPath,));
940 return fRc;
941
942 def _envSet(self, sName, sValue):
943 if self.isRemoteMode():
944 # For remote execution we cache the environment block and pass it
945 # right when the process execution happens.
946 self.asEnv.append([ sName, sValue ]);
947 else:
948 os.environ[sName] = sValue;
949 return True;
950
951 def _executeTestCase(self, oTestVm, sName, sFullPath, sTestCaseSubDir, oDevNull): # pylint: disable=too-many-locals,too-many-statements
952 """
953 Executes a test case.
954 """
955
956 fSkipped = False;
957
958 #
959 # If hardening is enabled, some test cases and their dependencies
960 # needs to be copied to and execute from the source
961 # directory in order to work. They also have to be executed as
962 # root, i.e. via sudo.
963 #
964 fHardened = sName in self.kasHardened and self.sUnitTestsPathSrc != self.sVBoxInstallRoot;
965 fCopyToRemote = self.isRemoteMode();
966 fCopyDeps = self.isRemoteMode();
967 asFilesToRemove = []; # Stuff to clean up.
968 asDirsToRemove = []; # Ditto.
969
970 if fHardened or fCopyToRemote:
971 if fCopyToRemote:
972 sDstDir = os.path.join(self.sUnitTestsPathDst, sTestCaseSubDir);
973 else:
974 sDstDir = os.path.join(self.sVBoxInstallRoot, sTestCaseSubDir);
975 if not self._wrapPathExists(sDstDir):
976 self._wrapMkDir(sDstDir);
977 asDirsToRemove.append(sDstDir);
978
979 sSrc = sFullPath + self.sExeSuff;
980 # If the testcase source does not exist for whatever reason, just mark it as skipped
981 # instead of reporting an error.
982 if not self._wrapPathExists(sSrc):
983 self.cSkipped += 1;
984 fSkipped = True;
985 return fSkipped;
986
987 sDst = os.path.join(sDstDir, os.path.basename(sFullPath) + self.sExeSuff);
988 fModeExe = 0;
989 fModeDeps = 0;
990 if not oTestVm or (oTestVm and not oTestVm.isWindows()): ## @todo NT4 does not like the chmod. Investigate this!
991 fModeExe = 0o755;
992 fModeDeps = 0o644;
993 self._wrapCopyFile(sSrc, sDst, fModeExe);
994 asFilesToRemove.append(sDst);
995
996 # Copy required dependencies to destination.
997 if fCopyDeps:
998 for sLib in self.kdTestCaseDepsLibs:
999 for sSuff in [ '.dll', '.so', '.dylib' ]:
1000 assert self.sVBoxInstallRoot is not None;
1001 sSrc = os.path.join(self.sVBoxInstallRoot, sLib + sSuff);
1002 if self._wrapPathExists(sSrc):
1003 sDst = os.path.join(sDstDir, os.path.basename(sSrc));
1004 self._wrapCopyFile(sSrc, sDst, fModeDeps);
1005 asFilesToRemove.append(sDst);
1006
1007 # Copy any associated .dll/.so/.dylib.
1008 for sSuff in [ '.dll', '.so', '.dylib' ]:
1009 sSrc = os.path.splitext(sFullPath)[0] + sSuff;
1010 if os.path.exists(sSrc):
1011 sDst = os.path.join(sDstDir, os.path.basename(sSrc));
1012 self._wrapCopyFile(sSrc, sDst, fModeDeps);
1013 asFilesToRemove.append(sDst);
1014
1015 # Copy any associated .r0, .rc and .gc modules.
1016 offDriver = sFullPath.rfind('Driver')
1017 if offDriver > 0:
1018 for sSuff in [ '.r0', 'RC.rc', 'RC.gc' ]:
1019 sSrc = sFullPath[:offDriver] + sSuff;
1020 if os.path.exists(sSrc):
1021 sDst = os.path.join(sDstDir, os.path.basename(sSrc));
1022 self._wrapCopyFile(sSrc, sDst, fModeDeps);
1023 asFilesToRemove.append(sDst);
1024
1025 sFullPath = os.path.join(sDstDir, os.path.basename(sFullPath));
1026
1027 #
1028 # Set up arguments and environment.
1029 #
1030 asArgs = [sFullPath + self.sExeSuff,]
1031 if sName in self.kdArguments:
1032 asArgs.extend(self.kdArguments[sName]);
1033
1034 sXmlFile = os.path.join(self.sUnitTestsPathDst, 'result.xml');
1035
1036 self._envSet('IPRT_TEST_OMIT_TOP_TEST', '1');
1037 self._envSet('IPRT_TEST_FILE', sXmlFile);
1038
1039 if self._wrapPathExists(sXmlFile):
1040 try: os.unlink(sXmlFile);
1041 except: self._wrapDeleteFile(sXmlFile);
1042
1043 #
1044 # Execute the test case.
1045 #
1046 # Windows is confusing output. Trying a few things to get rid of this.
1047 # First, flush both stderr and stdout before running the child. Second,
1048 # assign the child stderr to stdout. If this doesn't help, we'll have
1049 # to capture the child output.
1050 #
1051 reporter.log('*** Executing %s%s...' % (asArgs, ' [hardened]' if fHardened else ''));
1052 try: sys.stdout.flush();
1053 except: pass;
1054 try: sys.stderr.flush();
1055 except: pass;
1056
1057 iRc = 0;
1058
1059 if not self.fDryRun:
1060 if fCopyToRemote:
1061 fRc = self.txsRunTest(self.oTxsSession, sName, cMsTimeout = 30 * 60 * 1000, sExecName = asArgs[0],
1062 asArgs = asArgs, asAddEnv = self.asEnv, fCheckSessionStatus = True);
1063 if fRc:
1064 iRc = 0;
1065 else:
1066 (_, sOpcode, abPayload) = self.oTxsSession.getLastReply();
1067 if sOpcode.startswith('PROC NOK '): # Extract process rc.
1068 iRc = abPayload[0]; # ASSUMES 8-bit rc for now.
1069 if iRc == 0: # Might happen if the testcase misses some dependencies. Set it to -42 then.
1070 iRc = -42;
1071 else:
1072 iRc = -1; ## @todo
1073 else:
1074 oChild = None;
1075 try:
1076 if fHardened:
1077 oChild = utils.sudoProcessPopen(asArgs, stdin = oDevNull, stdout = sys.stdout, stderr = sys.stdout);
1078 else:
1079 oChild = utils.processPopenSafe(asArgs, stdin = oDevNull, stdout = sys.stdout, stderr = sys.stdout);
1080 except:
1081 if sName in [ 'tstAsmStructsRC', # 32-bit, may fail to start on 64-bit linux. Just ignore.
1082 ]:
1083 reporter.logXcpt();
1084 fSkipped = True;
1085 else:
1086 reporter.errorXcpt();
1087 iRc = 1023;
1088 oChild = None;
1089
1090 if oChild is not None:
1091 self.pidFileAdd(oChild.pid, sName, fSudo = fHardened);
1092 iRc = oChild.wait();
1093 self.pidFileRemove(oChild.pid);
1094 #
1095 # Clean up
1096 #
1097 for sPath in asFilesToRemove:
1098 self._wrapDeleteFile(sPath);
1099 for sPath in asDirsToRemove:
1100 self._wrapRemoveDir(sPath);
1101
1102 #
1103 # Report.
1104 #
1105 if os.path.exists(sXmlFile):
1106 reporter.addSubXmlFile(sXmlFile);
1107 if fHardened:
1108 self._wrapDeleteFile(sXmlFile);
1109 else:
1110 os.unlink(sXmlFile);
1111
1112 if iRc == 0:
1113 reporter.log('*** %s: exit code %d' % (sFullPath, iRc));
1114 self.cPassed += 1;
1115
1116 elif iRc == 4: # RTEXITCODE_SKIPPED
1117 reporter.log('*** %s: exit code %d (RTEXITCODE_SKIPPED)' % (sFullPath, iRc));
1118 fSkipped = True;
1119 self.cSkipped += 1;
1120
1121 elif fSkipped:
1122 reporter.log('*** %s: exit code %d (Skipped)' % (sFullPath, iRc));
1123 self.cSkipped += 1;
1124
1125 else:
1126 sName = self.kdExitCodeNames.get(iRc, '');
1127 if iRc in self.kdExitCodeNamesWin and utils.getHostOs() == 'win':
1128 sName = self.kdExitCodeNamesWin[iRc];
1129 if sName != '':
1130 sName = ' (%s)' % (sName);
1131
1132 if iRc != 1:
1133 reporter.testFailure('Exit status: %d%s' % (iRc, sName));
1134 reporter.log( '!*! %s: exit code %d%s' % (sFullPath, iRc, sName));
1135 else:
1136 reporter.error('!*! %s: exit code %d%s' % (sFullPath, iRc, sName));
1137 self.cFailed += 1;
1138
1139 return fSkipped;
1140
1141 def _testRunUnitTestsSet(self, oTestVm, sTestCasePattern, sTestCaseSubDir):
1142 """
1143 Run subset of the unit tests set.
1144 """
1145
1146 # Open /dev/null for use as stdin further down.
1147 try:
1148 oDevNull = open(os.path.devnull, 'w+'); # pylint: disable=consider-using-with
1149 except:
1150 oDevNull = None;
1151
1152 # Determin the host OS specific exclusion lists.
1153 dTestCasesBuggyForHostOs = self.kdTestCasesBuggyPerOs.get(utils.getHostOs(), []);
1154 dTestCasesBuggyForHostOs.update(self.kdTestCasesBuggyPerOs.get(utils.getHostOsDotArch(), []));
1155
1156 ## @todo Add filtering for more specific OSes (like OL server, doesn't have X installed) by adding a separate
1157 # black list + using utils.getHostOsVersion().
1158
1159 #
1160 # Process the file list and run everything looking like a testcase.
1161 #
1162 if not self.fOnlyWhiteList:
1163 if self.sMode in ('local', 'remote-copy'):
1164 asFiles = sorted(os.listdir(os.path.join(self.sUnitTestsPathSrc, sTestCaseSubDir)));
1165 else: # 'remote-exec'
1166 ## @todo Implement remote file enumeration / directory listing.
1167 reporter.error('Sorry, no remote file enumeration implemented yet!\nUse --only-whitelist instead.');
1168 return;
1169 else:
1170 # Transform our dict into a list, where the keys are the list elements.
1171 asFiles = list(self.kdTestCasesWhiteList.keys());
1172 # Make sure to only keep the list item's base name so that the iteration down below works
1173 # with our white list without any additional modification.
1174 asFiles = [os.path.basename(s) for s in asFiles];
1175
1176 for sFilename in asFiles:
1177 # Separate base and suffix and morph the base into something we
1178 # can use for reporting and array lookups.
1179 sBaseName = os.path.basename(sFilename);
1180 sName, sSuffix = os.path.splitext(sBaseName);
1181 if sTestCaseSubDir != '.':
1182 sName = sTestCaseSubDir + '/' + sName;
1183
1184 reporter.log2('sTestCasePattern=%s, sBaseName=%s, sName=%s, sSuffix=%s, sFileName=%s'
1185 % (sTestCasePattern, sBaseName, sName, sSuffix, sFilename,));
1186
1187 # Process white list first, if set.
1188 if self.fOnlyWhiteList and not self._isExcluded(sName, self.kdTestCasesWhiteList):
1189 # (No testStart/Done or accounting here!)
1190 reporter.log('%s: SKIPPED (not in white list)' % (sName,));
1191 continue;
1192
1193 # Basic exclusion.
1194 if not re.match(sTestCasePattern, sBaseName) or sSuffix in self.kasSuffixBlackList:
1195 reporter.log2('"%s" is not a test case.' % (sName,));
1196 continue;
1197
1198 # When not only processing the white list, do some more checking first.
1199 if not self.fOnlyWhiteList:
1200 # Check if the testcase is black listed or buggy before executing it.
1201 if self._isExcluded(sName, self.kdTestCasesBlackList):
1202 # (No testStart/Done or accounting here!)
1203 reporter.log('%s: SKIPPED (blacklisted)' % (sName,));
1204 continue;
1205
1206 if self._isExcluded(sName, self.kdTestCasesBuggy):
1207 reporter.testStart(sName);
1208 reporter.log('%s: Skipping, buggy in general.' % (sName,));
1209 reporter.testDone(fSkipped = True);
1210 self.cSkipped += 1;
1211 continue;
1212
1213 if self._isExcluded(sName, dTestCasesBuggyForHostOs):
1214 reporter.testStart(sName);
1215 reporter.log('%s: Skipping, buggy on %s.' % (sName, utils.getHostOs(),));
1216 reporter.testDone(fSkipped = True);
1217 self.cSkipped += 1;
1218 continue;
1219 else:
1220 # Passed the white list check already above.
1221 pass;
1222
1223 sFullPath = os.path.normpath(os.path.join(self.sUnitTestsPathSrc, os.path.join(sTestCaseSubDir, sFilename)));
1224 reporter.testStart(sName);
1225 try:
1226 fSkipped = self._executeTestCase(oTestVm, sName, sFullPath, sTestCaseSubDir, oDevNull);
1227 except:
1228 reporter.errorXcpt('!*!');
1229 self.cFailed += 1;
1230 fSkipped = False;
1231 reporter.testDone(fSkipped);
1232
1233
1234if __name__ == '__main__':
1235 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