VirtualBox

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

Last change on this file since 107044 was 107014, checked in by vboxsync, 3 months ago

Validation Kit/tdUnitTest1: Also blacklist tstCAPIGlue-x86 (requires interaction), which otherwise will timeout testboxes.

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

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