VirtualBox

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

Last change on this file since 98564 was 98564, checked in by vboxsync, 2 years ago

ValKit/tdUnitTest1.py: More cleanups and some attempts at making sense of the code in regard to remote-exec and remote-copy. Seems remote-copy isn't working and probably should just be removed. Replaced the _envSet stuff with a local dictionary which is then converted/applied according to the execution method. bugref:10195

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

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