VirtualBox

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

Last change on this file since 103068 was 102988, checked in by vboxsync, 14 months ago

ValidationKit/tests/tdUnitTest1.py: Skip tstVMMR0CallHost-1 for asan builds as it triggers a false positive

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

© 2025 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette