VirtualBox

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

Last change on this file since 99818 was 99818, checked in by vboxsync, 21 months ago

HostDrivers/Support/testcase/tstPin,
ValidationKit/tests/unittests/tdUnitTest1.py: Addressed several
Solaris-specific unit test failures. tstPin and tstContiguous both
attempt to allocate kernel memory with a contiguous physical backing
below 4GB for running code (RTR0MemObjAllocCont() with fExecutable=true)
but this isn't implemented on Solaris. tstLow attempts to allocate
kernel memory with a physical backing below 4GB for running code
(RTR0MemObjAllocLow() with fExecutable=true) which isn't implemented on
Solaris. tstPDMQueue attempts to run driverless, i.e. without the
support driver (vboxdrv), which isn't supported on Solaris. tstPin
exercises other memory operations so the fix simply #ifdef's out the
RTR0MemObjAllocCont() request for Solaris. For the rest of the tests we
update tdUnitTest1.py to move them to the kdTestCasesBuggyPerOs list to
mark them as known to be not applicable at this time and also to not
count their expected failures as part of the final results tally.

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