VirtualBox

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

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

Validation Kit/tdUnitTest1.py: Fixed running locally on Windows (hosts) [pylint, grml].

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