VirtualBox

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

最後變更 在這個檔案從95481是 95042,由 vboxsync 提交於 3 年 前

Validation Kit/unit tests: Check if oTestvm is not None when running unit tests locally and not in a test VM. bugref:10195

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

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