VirtualBox

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

Last change on this file since 99509 was 99509, checked in by vboxsync, 22 months ago

Validation Kit/unit tests: Also disabled tstRTTime for darwin.arm64 for now.

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