VirtualBox

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

Last change on this file since 103914 was 103475, checked in by vboxsync, 10 months ago

ValidationKit/tdUnitTest1: Exclude tstInt on darwin as it requires the support driver [fix path to the testcase]

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