VirtualBox

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

最後變更 在這個檔案從99487是 99487,由 vboxsync 提交於 2 年 前

Validation Kit/tdUnitTest1.py: Disabled running tstIntNet-1, tstLow and tstPin on darwin.arm64, as those are not supported (yet).

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

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