VirtualBox

source: vbox/trunk/src/VBox/ValidationKit/tests/audio/tdAudioTest.py@ 92489

Last change on this file since 92489 was 92380, checked in by vboxsync, 3 years ago

Audio/Validation Kit: Disabled the test driver's maximum logging line restrictions per group. This comes in handy when running in a (very) verbose mode, e.g. for debugging. bugref:10008

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 32.4 KB
Line 
1# -*- coding: utf-8 -*-
2# $Id: tdAudioTest.py 92380 2021-11-11 17:56:54Z vboxsync $
3
4"""
5AudioTest test driver which invokes the VKAT (Validation Kit Audio Test)
6binary to perform the actual audio tests.
7
8The generated test set archive on the guest will be downloaded by TXS
9to the host for later audio comparison / verification.
10"""
11
12__copyright__ = \
13"""
14Copyright (C) 2021 Oracle Corporation
15
16This file is part of VirtualBox Open Source Edition (OSE), as
17available from http://www.virtualbox.org. This file is free software;
18you can redistribute it and/or modify it under the terms of the GNU
19General Public License (GPL) as published by the Free Software
20Foundation, in version 2 as it comes in the "COPYING" file of the
21VirtualBox OSE distribution. VirtualBox OSE is distributed in the
22hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
23
24The contents of this file may alternatively be used under the terms
25of the Common Development and Distribution License Version 1.0
26(CDDL) only, as it comes in the "COPYING.CDDL" file of the
27VirtualBox OSE distribution, in which case the provisions of the
28CDDL are applicable instead of those of the GPL.
29
30You may elect to license modified versions of this file under the
31terms and conditions of either the GPL or the CDDL or both.
32"""
33__version__ = "$Revision: 92380 $"
34
35# Standard Python imports.
36from datetime import datetime
37import os
38import sys
39import signal
40import subprocess
41import time
42
43# Only the main script needs to modify the path.
44try: __file__
45except: __file__ = sys.argv[0];
46g_ksValidationKitDir = os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__))));
47sys.path.append(g_ksValidationKitDir);
48
49# Validation Kit imports.
50from testdriver import reporter
51from testdriver import base
52from testdriver import vbox
53from testdriver import vboxcon;
54from testdriver import vboxtestvms
55from common import utils;
56
57# pylint: disable=unnecessary-semicolon
58
59class tdAudioTest(vbox.TestDriver):
60 """
61 Runs various audio tests.
62 """
63 def __init__(self):
64 vbox.TestDriver.__init__(self);
65 self.oTestVmSet = self.oTestVmManager.getSmokeVmSet('nat');
66 self.asGstVkatPaths = [
67 # Debugging stuff (SCP'd over to the guest).
68 '/tmp/vkat',
69 '/tmp/VBoxAudioTest',
70 'C:\\Temp\\vkat',
71 'C:\\Temp\\VBoxAudioTest',
72 # Validation Kit .ISO.
73 '${CDROM}/vboxvalidationkit/${OS/ARCH}/vkat${EXESUFF}',
74 '${CDROM}/${OS/ARCH}/vkat${EXESUFF}',
75 # Test VMs.
76 '/opt/apps/vkat',
77 '/opt/apps/VBoxAudioTest',
78 '/apps/vkat',
79 '/apps/VBoxAudioTest',
80 'C:\\Apps\\vkat${EXESUFF}',
81 'C:\\Apps\\VBoxAudioTest${EXESUFF}',
82 ## @odo VBoxAudioTest on Guest Additions?
83 ];
84 self.asTestsDef = [
85 'guest_tone_playback', 'guest_tone_recording'
86 ];
87 self.asTests = self.asTestsDef;
88
89 # Optional arguments passing to VKAT when doing the actual audio tests.
90 self.asVkatTestArgs = [];
91 # Optional arguments passing to VKAT when verifying audio test sets.
92 self.asVkatVerifyArgs = [];
93
94 # Enable audio debug mode.
95 #
96 # This is needed in order to load and use the Validation Kit audio driver,
97 # which in turn is being used in conjunction with the guest side to record
98 # output (guest is playing back) and injecting input (guest is recording).
99 self.asOptExtraData = [
100 'VBoxInternal2/Audio/Debug/Enabled:true',
101 ];
102
103 # Name of the running VM to use for running the test driver. Optional, and None if not being used.
104 self.sRunningVmName = None;
105
106 # Audio controller type to use.
107 # If set to None, the OS' recommended controller type will be used (defined by Main).
108 self.sAudioControllerType = None;
109
110 def showUsage(self):
111 """
112 Shows the audio test driver-specific command line options.
113 """
114 fRc = vbox.TestDriver.showUsage(self);
115 reporter.log('');
116 reporter.log('tdAudioTest Options:');
117 reporter.log(' --runningvmname <vmname>');
118 reporter.log(' --audio-tests <s1[:s2[:]]>');
119 reporter.log(' Default: %s (all)' % (':'.join(self.asTestsDef)));
120 reporter.log(' --audio-controller-type <HDA|AC97|SB16>');
121 reporter.log(' Default: recommended controller');
122 reporter.log(' --audio-test-count <number>');
123 reporter.log(' Default: 0 (means random)');
124 reporter.log(' --audio-test-tone-duration <ms>');
125 reporter.log(' Default: 0 (means random)');
126 reporter.log(' --audio-verify-max-diff-count <number>');
127 reporter.log(' Default: 0 (strict)');
128 reporter.log(' --audio-verify-max-diff-percent <0-100>');
129 reporter.log(' Default: 0 (strict)');
130 reporter.log(' --audio-verify-max-size-percent <0-100>');
131 reporter.log(' Default: 0 (strict)');
132 return fRc;
133
134 def parseOption(self, asArgs, iArg):
135 """
136 Parses the audio test driver-specific command line options.
137 """
138 if asArgs[iArg] == '--runningvmname':
139 iArg += 1;
140 if iArg >= len(asArgs):
141 raise base.InvalidOption('The "--runningvmname" needs VM name');
142
143 self.sRunningVmName = asArgs[iArg];
144 elif asArgs[iArg] == '--audio-tests':
145 iArg += 1;
146 if asArgs[iArg] == 'all': # Nice for debugging scripts.
147 self.asTests = self.asTestsDef;
148 else:
149 self.asTests = asArgs[iArg].split(':');
150 for s in self.asTests:
151 if s not in self.asTestsDef:
152 raise base.InvalidOption('The "--audio-tests" value "%s" is not valid; valid values are: %s'
153 % (s, ' '.join(self.asTestsDef)));
154 elif asArgs[iArg] == '--audio-controller-type':
155 iArg += 1;
156 if iArg >= len(asArgs):
157 raise base.InvalidOption('Option "%s" needs a value' % (asArgs[iArg - 1]));
158 if asArgs[iArg] == 'HDA' \
159 or asArgs[iArg] == 'AC97' \
160 or asArgs[iArg] == 'SB16':
161 self.sAudioControllerType = asArgs[iArg];
162 else:
163 raise base.InvalidOption('The "--audio-controller-type" value "%s" is not valid' % (asArgs[iArg]));
164 elif asArgs[iArg] == '--audio-test-count' \
165 or asArgs[iArg] == '--audio-test-tone-duration':
166 # Strip the "--audio-test-" prefix and keep the options as defined in VKAT,
167 # e.g. "--audio-test-count" -> "--count". That way we don't
168 # need to do any special argument translation and whatnot.
169 self.asVkatTestArgs.extend(['--' + asArgs[iArg][len('--audio-test-'):]]);
170 iArg += 1;
171 if iArg >= len(asArgs):
172 raise base.InvalidOption('Option "%s" needs a value' % (asArgs[iArg - 1]));
173 self.asVkatTestArgs.extend([asArgs[iArg]]);
174 elif asArgs[iArg] == '--audio-verify-max-diff-count' \
175 or asArgs[iArg] == '--audio-verify-max-diff-percent' \
176 or asArgs[iArg] == '--audio-verify-max-size-percent':
177 # Strip the "--audio-verify-" prefix and keep the options as defined in VKAT,
178 # e.g. "--audio-verify-max-diff-count" -> "--max-diff-count". That way we don't
179 # need to do any special argument translation and whatnot.
180 self.asVkatVerifyArgs.extend(['--' + asArgs[iArg][len('--audio-verify-'):]]);
181 iArg += 1;
182 if iArg >= len(asArgs):
183 raise base.InvalidOption('Option "%s" needs a value' % (asArgs[iArg - 1]));
184 self.asVkatVerifyArgs.extend([asArgs[iArg]]);
185 else:
186 return vbox.TestDriver.parseOption(self, asArgs, iArg);
187 return iArg + 1;
188
189 def actionVerify(self):
190 """
191 Verifies the test driver before running.
192 """
193 if self.sVBoxValidationKitIso is None or not os.path.isfile(self.sVBoxValidationKitIso):
194 reporter.error('Cannot find the VBoxValidationKit.iso! (%s)'
195 'Please unzip a Validation Kit build in the current directory or in some parent one.'
196 % (self.sVBoxValidationKitIso,) );
197 return False;
198 return vbox.TestDriver.actionVerify(self);
199
200 def actionConfig(self):
201 """
202 Configures the test driver before running.
203 """
204 if not self.importVBoxApi(): # So we can use the constant below.
205 return False;
206
207 # Make sure that the Validation Kit .ISO is mounted
208 # to find the VKAT (Validation Kit Audio Test) binary on it.
209 assert self.sVBoxValidationKitIso is not None;
210 return self.oTestVmSet.actionConfig(self, sDvdImage = self.sVBoxValidationKitIso);
211
212 def actionExecute(self):
213 """
214 Executes the test driver.
215 """
216
217 # Disable maximum logging line restrictions per group.
218 # This comes in handy when running this test driver in a (very) verbose mode, e.g. for debugging.
219 os.environ['VBOX_LOG_MAX_PER_GROUP'] = '0';
220 os.environ['VBOX_RELEASE_LOG_MAX_PER_GROUP'] = '0';
221 os.environ['VKAT_RELEASE_LOG_MAX_PER_GROUP'] = '0';
222
223 if self.sRunningVmName is None:
224 return self.oTestVmSet.actionExecute(self, self.testOneVmConfig);
225 return self.actionExecuteOnRunnigVM();
226
227 def actionExecuteOnRunnigVM(self):
228 """
229 Executes the tests in an already configured + running VM.
230 """
231 if not self.importVBoxApi():
232 return False;
233
234 fRc = True;
235
236 oVM = None;
237 oVirtualBox = None;
238
239 oVirtualBox = self.oVBoxMgr.getVirtualBox();
240 try:
241 oVM = oVirtualBox.findMachine(self.sRunningVmName);
242 if oVM.state != self.oVBoxMgr.constants.MachineState_Running:
243 reporter.error("Machine '%s' is not in Running state (state is %d)" % (self.sRunningVmName, oVM.state));
244 fRc = False;
245 except:
246 reporter.errorXcpt("Machine '%s' not found" % (self.sRunningVmName));
247 fRc = False;
248
249 if fRc:
250 oSession = self.openSession(oVM);
251 if oSession:
252 # Tweak this to your likings.
253 oTestVm = vboxtestvms.TestVm('runningvm', sKind = 'WindowsXP'); #sKind = 'WindowsXP' # sKind = 'Ubuntu_64'
254 (fRc, oTxsSession) = self.txsDoConnectViaTcp(oSession, 30 * 1000);
255 if fRc:
256 self.doTest(oTestVm, oSession, oTxsSession);
257 else:
258 reporter.error("Unable to open session for machine '%s'" % (self.sRunningVmName));
259 fRc = False;
260
261 if oVM:
262 del oVM;
263 if oVirtualBox:
264 del oVirtualBox;
265 return fRc;
266
267 def getGstVkatLogFilePath(self, oTestVm):
268 """
269 Returns the log file path of VKAT running on the guest (daemonized).
270 """
271 return oTestVm.pathJoin(self.getGuestTempDir(oTestVm), 'vkat-guest.log');
272
273 def locateGstBinary(self, oSession, oTxsSession, asPaths):
274 """
275 Locates a guest binary on the guest by checking the paths in \a asPaths.
276 """
277 for sCurPath in asPaths:
278 reporter.log2('Checking for \"%s\" ...' % (sCurPath));
279 if self.txsIsFile(oSession, oTxsSession, sCurPath, fIgnoreErrors = True):
280 return (True, sCurPath);
281 reporter.error('Unable to find guest binary in any of these places:\n%s' % ('\n'.join(asPaths),));
282 return (False, "");
283
284 def executeHstLoop(self, sWhat, asArgs, asEnv = None, fAsAdmin = False):
285 """
286 Inner loop which handles the execution of a host binary.
287 """
288 fRc = False;
289
290 asEnvTmp = os.environ.copy();
291 if asEnv:
292 for sEnv in asEnv:
293 sKey, sValue = sEnv.split('=');
294 reporter.log2('Setting env var \"%s\" -> \"%s\"' % (sKey, sValue));
295 os.environ[sKey] = sValue; # Also apply it to the current environment.
296 asEnvTmp[sKey] = sValue;
297
298 try:
299 if fAsAdmin \
300 and utils.getHostOs() != 'win':
301 sStdOut = utils.sudoProcessOutputChecked(asArgs, env = asEnvTmp);
302 if sStdOut:
303 sStdOut = sStdOut.strip();
304 reporter.log("stdout:\n" + sStdOut);
305 else:
306 (iExit, sStdOut, sStdErr) = utils.processOutputUnchecked(asArgs, env = asEnvTmp);
307
308 if sStdOut:
309 sStdOut = sStdOut.strip();
310 reporter.log("stdout:\n" + sStdOut);
311
312 if sStdErr:
313 sStdErr = sStdErr.strip();
314 reporter.log("stderr:\n" + sStdErr);
315
316 if iExit == 0:
317 reporter.log('*** %s: exit code %d' % (sWhat, iExit));
318 fRc = True;
319 else:
320 reporter.log('!*! %s: exit code %d' % (sWhat, iExit));
321
322 except:
323 reporter.logXcpt('Executing "%s" failed!' % (sWhat));
324
325 return fRc;
326
327 def executeHst(self, sWhat, asArgs, asEnv = None, fAsAdmin = False):
328 """
329 Runs a binary (image) with optional admin (root) rights on the host and
330 waits until it terminates.
331
332 Windows currently is not supported yet running stuff as Administrator.
333
334 Returns success status (exit code is 0).
335 """
336 reporter.log('Executing \"%s\" on host (as admin = %s)' % (sWhat, fAsAdmin));
337
338 try: sys.stdout.flush();
339 except: pass;
340 try: sys.stderr.flush();
341 except: pass;
342
343 fRc = self.executeHstLoop(sWhat, asArgs, asEnv, fAsAdmin);
344 if fRc:
345 reporter.log('Executing \"%s\" on host done' % (sWhat,));
346 else:
347 reporter.log('Executing \"%s\" on host failed' % (sWhat,));
348
349 return fRc;
350
351 def killHstProcessByName(self, sProcName):
352 """
353 Kills processes by their name.
354 """
355 reporter.log('Trying to kill processes named "%s"' % (sProcName,));
356 if sys.platform == 'win32':
357 sArgProcName = '\"%s.exe\"' % sProcName;
358 asArgs = [ 'taskkill', '/IM', sArgProcName, '/F' ];
359 self.executeHst('Killing process', asArgs);
360 else: # Note: killall is not available on older Debians (requires psmisc).
361 # Using the BSD syntax here; MacOS also should understand this.
362 procPs = subprocess.Popen(['ps', 'ax'], stdout=subprocess.PIPE);
363 out, err = procPs.communicate();
364 if err:
365 reporter.log('PS stderr:');
366 for sLine in err.decode('utf-8').splitlines():
367 reporter.log(sLine);
368 if out:
369 reporter.log4('PS stdout:');
370 for sLine in out.decode('utf-8').splitlines():
371 reporter.log4(sLine);
372 if sProcName in sLine:
373 pid = int(sLine.split(None, 1)[0]);
374 reporter.log('Killing PID %d' % (pid,));
375 os.kill(pid, signal.SIGKILL); # pylint: disable=no-member
376
377 def killHstVkat(self):
378 """
379 Kills VKAT (VBoxAudioTest) on the host side.
380 """
381 reporter.log('Killing stale/old VKAT processes ...');
382 self.killHstProcessByName("vkat");
383 self.killHstProcessByName("VBoxAudioTest");
384
385 def getWinFirewallArgsDisable(self, sOsType):
386 """
387 Returns the command line arguments for Windows OSes
388 to disable the built-in firewall (if any).
389
390 If not supported, returns an empty array.
391 """
392 if sOsType == 'vista': # pylint: disable=no-else-return
393 # Vista and up.
394 return (['netsh.exe', 'advfirewall', 'set', 'allprofiles', 'state', 'off']);
395 elif sOsType == 'xp': # Older stuff (XP / 2003).
396 return(['netsh.exe', 'firewall', 'set', 'opmode', 'mode=DISABLE']);
397 # Not supported / available.
398 return [];
399
400 def disableGstFirewall(self, oTestVm, oTxsSession):
401 """
402 Disables the firewall on a guest (if any).
403
404 Needs elevated / admin / root privileges.
405
406 Returns success status, not logged.
407 """
408 fRc = False;
409
410 asArgs = [];
411 sOsType = '';
412 if oTestVm.isWindows():
413 if oTestVm.sKind in ['WindowsNT4', 'WindowsNT3x']:
414 sOsType = 'nt3x'; # Not supported, but define it anyway.
415 elif oTestVm.sKind in ('Windows2000', 'WindowsXP', 'Windows2003'):
416 sOsType = 'xp';
417 else:
418 sOsType = 'vista';
419 asArgs = self.getWinFirewallArgsDisable(sOsType);
420 else:
421 sOsType = 'unsupported';
422
423 reporter.log('Disabling firewall on guest (type: %s) ...' % (sOsType,));
424
425 if asArgs:
426 fRc = self.txsRunTest(oTxsSession, 'Disabling guest firewall', 3 * 60 * 1000, \
427 oTestVm.pathJoin(self.getGuestSystemDir(oTestVm), asArgs[0]), asArgs);
428 if not fRc:
429 reporter.error('Disabling firewall on guest returned exit code error %d' % (self.getLastRcFromTxs(oTxsSession)));
430 else:
431 reporter.log('Firewall not available on guest, skipping');
432 fRc = True; # Not available, just skip.
433
434 return fRc;
435
436 def disableHstFirewall(self):
437 """
438 Disables the firewall on the host (if any).
439
440 Needs elevated / admin / root privileges.
441
442 Returns success status, not logged.
443 """
444 fRc = False;
445
446 asArgs = [];
447 sOsType = sys.platform;
448
449 if sOsType == 'win32':
450 reporter.log('Disabling firewall on host (type: %s) ...' % (sOsType));
451
452 ## @todo For now we ASSUME that we don't run (and don't support even) on old(er)
453 # Windows hosts than Vista.
454 asArgs = self.getWinFirewallArgsDisable('vista');
455 if asArgs:
456 fRc = self.executeHst('Disabling host firewall', asArgs, fAsAdmin = True);
457 else:
458 reporter.log('Firewall not available on host, skipping');
459 fRc = True; # Not available, just skip.
460
461 return fRc;
462
463 def getLastRcFromTxs(self, oTxsSession):
464 """
465 Extracts the last exit code reported by TXS from a run before.
466 Assumes that nothing else has been run on the same TXS session in the meantime.
467 """
468 iRc = 0;
469 (_, sOpcode, abPayload) = oTxsSession.getLastReply();
470 if sOpcode.startswith('PROC NOK '): # Extract process rc
471 iRc = abPayload[0]; # ASSUMES 8-bit rc for now.
472 return iRc;
473
474 def startVkatOnGuest(self, oTestVm, oSession, oTxsSession, sTag):
475 """
476 Starts VKAT on the guest (running in background).
477 """
478 sPathTemp = self.getGuestTempDir(oTestVm);
479 sPathAudioOut = oTestVm.pathJoin(sPathTemp, 'vkat-guest-out');
480 sPathAudioTemp = oTestVm.pathJoin(sPathTemp, 'vkat-guest-temp');
481
482 reporter.log('Guest audio test temp path is \"%s\"' % (sPathAudioOut));
483 reporter.log('Guest audio test output path is \"%s\"' % (sPathAudioTemp));
484 reporter.log('Guest audio test tag is \"%s\"' % (sTag));
485
486 fRc, sVkatExe = self.locateGstBinary(oSession, oTxsSession, self.asGstVkatPaths);
487 if fRc:
488 reporter.log('Using VKAT on guest at \"%s\"' % (sVkatExe));
489
490 sCmd = '';
491 asArgs = [];
492
493 asArgsVkat = [ sVkatExe, 'test', '--mode', 'guest', '--probe-backends', \
494 '--tempdir', sPathAudioTemp, '--outdir', sPathAudioOut, \
495 '--tag', sTag ];
496
497 asArgs.extend(asArgsVkat);
498
499 for _ in range(1, reporter.getVerbosity()): # Verbosity always is initialized at 1.
500 asArgs.extend([ '-v' ]);
501
502 # Needed for NATed VMs.
503 asArgs.extend(['--tcp-connect-addr', '10.0.2.2' ]);
504
505 if oTestVm.sKind in 'Oracle_64':
506 #
507 # Some Linux distros have a bug / are configured (?) so that processes started by init system
508 # cannot access the PulseAudio server ("Connection refused"), for example OL 8.1.
509 #
510 # To work around this, we use the (hopefully) configured user "vbox" and run it under its behalf,
511 # as the Test Execution Service (TxS) currently does not implement impersonation yet.
512 #
513 asSU = [ '/bin/su',
514 '/usr/bin/su',
515 '/usr/local/bin/su' ];
516 fRc, sCmd = self.locateGstBinary(oSession, oTxsSession, asSU);
517 if fRc:
518 sCmdArgs = '';
519 for sArg in asArgs:
520 sCmdArgs += sArg + " ";
521 asArgs = [ sCmd, oTestVm.getTestUser(), '-c', sCmdArgs ];
522 else:
523 reporter.log('Unable to find SU on guest, falling back to regular starting ...')
524
525 if not sCmd: # Just start it with the same privileges as TxS.
526 sCmd = sVkatExe;
527
528 reporter.log2('startVkatOnGuest: sCmd=%s' % (sCmd,));
529 reporter.log2('startVkatOnGuest: asArgs=%s' % (asArgs,));
530
531 #
532 # Add own environment stuff.
533 #
534 asEnv = [];
535
536 # Write the log file to some deterministic place so TxS can retrieve it later.
537 sVkatLogFile = 'VKAT_RELEASE_LOG_DEST=file=' + self.getGstVkatLogFilePath(oTestVm);
538 asEnv.extend([ sVkatLogFile ]);
539
540 #
541 # Execute asynchronously on the guest.
542 #
543 fRc = oTxsSession.asyncExec(sCmd, asArgs, asEnv, cMsTimeout = 15 * 60 * 1000, sPrefix = '[VKAT Guest] ');
544 if fRc:
545 self.addTask(oTxsSession);
546
547 if not fRc:
548 reporter.error('VKAT on guest returned exit code error %d' % (self.getLastRcFromTxs(oTxsSession)));
549 else:
550 reporter.error('VKAT on guest not found');
551
552 return fRc;
553
554 def runTests(self, oTestVm, oSession, oTxsSession, sDesc, sTag, asTests):
555 """
556 Runs one or more tests using VKAT on the host, which in turn will
557 communicate with VKAT running on the guest and the Validation Kit
558 audio driver ATS (Audio Testing Service).
559 """
560 _ = oTestVm, oSession, oTxsSession;
561
562 sPathTemp = self.sScratchPath;
563 sPathAudioOut = os.path.join(sPathTemp, 'vkat-host-out-%s' % (sTag));
564 sPathAudioTemp = os.path.join(sPathTemp, 'vkat-host-temp-%s' % (sTag));
565
566 reporter.log('Host audio test temp path is \"%s\"' % (sPathAudioOut));
567 reporter.log('Host audio test output path is \"%s\"' % (sPathAudioTemp));
568 reporter.log('Host audio test tag is \"%s\"' % (sTag));
569
570 reporter.testStart(sDesc);
571
572 sVkatExe = self.getBinTool('vkat');
573
574 reporter.log('Using VKAT on host at: \"%s\"' % (sVkatExe));
575
576 # Build the base command line, exclude all tests by default.
577 asArgs = [ sVkatExe, 'test', '--mode', 'host', '--probe-backends',
578 '--tempdir', sPathAudioTemp, '--outdir', sPathAudioOut, '-a',
579 '--tag', sTag,
580 '--no-audio-ok', # Enables running on hosts which do not have any audio hardware.
581 '--no-verify' ]; # We do the verification separately in the step below.
582
583 for _ in range(1, reporter.getVerbosity()): # Verbosity always is initialized at 1.
584 asArgs.extend([ '-v' ]);
585
586 if self.asVkatTestArgs:
587 asArgs += self.asVkatTestArgs;
588
589 # ... and extend it with wanted tests.
590 asArgs.extend(asTests);
591
592 #
593 # Let VKAT on the host run synchronously.
594 #
595 fRc = self.executeHst("VKAT Host", asArgs);
596
597 reporter.testDone();
598
599 if fRc:
600 #
601 # When running the test(s) above were successful, do the verification step next.
602 # This gives us a bit more fine-grained test results in the test manager.
603 #
604 reporter.testStart('Verifying audio data');
605
606 sNameSetHst = '%s-host.tar.gz' % (sTag);
607 sPathSetHst = os.path.join(sPathAudioOut, sNameSetHst);
608 sNameSetGst = '%s-guest.tar.gz' % (sTag);
609 sPathSetGst = os.path.join(sPathAudioOut, sNameSetGst);
610
611 asArgs = [ sVkatExe, 'verify', sPathSetHst, sPathSetGst ];
612
613 for _ in range(1, reporter.getVerbosity()): # Verbosity always is initialized at 1.
614 asArgs.extend([ '-v' ]);
615
616 if self.asVkatVerifyArgs:
617 asArgs += self.asVkatVerifyArgs;
618
619 fRc = self.executeHst("VKAT Host Verify", asArgs);
620 if fRc:
621 reporter.log("Verification audio data successful");
622 else:
623 #
624 # Add the test sets to the test manager for later (manual) diagnosis.
625 #
626 reporter.addLogFile(sPathSetGst, 'misc/other', 'Guest audio test set');
627 reporter.addLogFile(sPathSetHst, 'misc/other', 'Host audio test set');
628
629 reporter.error("Verification of audio data failed");
630
631 reporter.testDone();
632
633 return fRc;
634
635 def doTest(self, oTestVm, oSession, oTxsSession):
636 """
637 Executes the specified audio tests.
638 """
639
640 # Disable any OS-specific firewalls preventing VKAT / ATS to run.
641 fRc = self.disableHstFirewall();
642 fRc = self.disableGstFirewall(oTestVm, oTxsSession) and fRc;
643
644 if not fRc:
645 return False;
646
647 # First try to kill any old VKAT / VBoxAudioTest processes lurking around on the host.
648 # Might happen because of former (aborted) runs.
649 self.killHstVkat();
650
651 reporter.log("Active tests: %s" % (self.asTests,));
652
653 # Define a tag for the whole run.
654 sTag = oTestVm.sVmName + "_" + datetime.now().strftime("%Y%m%d_%H%M%S");
655
656 fRc = self.startVkatOnGuest(oTestVm, oSession, oTxsSession, sTag);
657 if fRc:
658 #
659 # Execute the tests using VKAT on the guest side (in guest mode).
660 #
661 if "guest_tone_playback" in self.asTests:
662 fRc = self.runTests(oTestVm, oSession, oTxsSession, \
663 'Guest audio playback', sTag + "_test_playback", \
664 asTests = [ '-i0' ]);
665 if "guest_tone_recording" in self.asTests:
666 fRc = fRc and self.runTests(oTestVm, oSession, oTxsSession, \
667 'Guest audio recording', sTag + "_test_recording", \
668 asTests = [ '-i1' ]);
669
670 # Cancel guest VKAT execution task summoned by startVkatOnGuest().
671 oTxsSession.cancelTask();
672
673 #
674 # Retrieve log files for diagnosis.
675 #
676 self.txsDownloadFiles(oSession, oTxsSession,
677 [ ( self.getGstVkatLogFilePath(oTestVm),
678 'vkat-guest-%s.log' % (oTestVm.sVmName,),),
679 ],
680 fIgnoreErrors = True);
681
682 # A bit of diagnosis on error.
683 ## @todo Remove this later when stuff runs stable.
684 if not fRc:
685 reporter.log('Kernel messages:');
686 sCmdDmesg = oTestVm.pathJoin(self.getGuestSystemDir(oTestVm), 'dmesg');
687 oTxsSession.syncExec(sCmdDmesg, (sCmdDmesg), fIgnoreErrors = True);
688 reporter.log('Loaded kernel modules:');
689 sCmdLsMod = oTestVm.pathJoin(self.getGuestSystemAdminDir(oTestVm), 'lsmod');
690 oTxsSession.syncExec(sCmdLsMod, (sCmdLsMod), fIgnoreErrors = True);
691
692 return fRc;
693
694 def testOneVmConfig(self, oVM, oTestVm):
695 """
696 Runs tests using one specific VM config.
697 """
698
699 self.logVmInfo(oVM);
700
701 reporter.testStart("Audio Testing");
702
703 fSkip = False;
704
705 if oTestVm.isWindows() \
706 and oTestVm.sKind in ('WindowsNT4', 'Windows2000'): # Too old for DirectSound and WASAPI backends.
707 reporter.log('Audio testing skipped, not implemented/available for that OS yet.');
708 fSkip = True;
709
710 if not fSkip \
711 and self.fpApiVer < 7.0:
712 reporter.log('Audio testing for non-trunk builds skipped.');
713 fSkip = True;
714
715 if not fSkip:
716 sVkatExe = self.getBinTool('vkat');
717 asArgs = [ sVkatExe, 'enum', '--probe-backends' ];
718 for _ in range(1, reporter.getVerbosity()): # Verbosity always is initialized at 1.
719 asArgs.extend([ '-v' ]);
720 fRc = self.executeHst("VKAT Host Audio Probing", asArgs);
721 if not fRc:
722 # Not fatal, as VBox then should fall back to the NULL audio backend (also worth having as a test case).
723 reporter.log('Warning: Backend probing on host failed, no audio available (pure server installation?)');
724
725 if fSkip:
726 reporter.testDone(fSkipped = True);
727 return True;
728
729 # Reconfigure the VM.
730 oSession = self.openSession(oVM);
731 if oSession is not None:
732
733 cVerbosity = reporter.getVerbosity();
734 if cVerbosity >= 2: # Explicitly set verbosity via extra-data when >= level 2.
735 self.asOptExtraData.extend([ 'VBoxInternal2/Audio/Debug/Level:' + str(cVerbosity) ]);
736
737 # Set extra data.
738 for sExtraData in self.asOptExtraData:
739 sKey, sValue = sExtraData.split(':');
740 reporter.log('Set extradata: %s => %s' % (sKey, sValue));
741 fRc = oSession.setExtraData(sKey, sValue) and fRc;
742
743 # Make sure that the VM's audio adapter is configured the way we need it to.
744 if self.fpApiVer >= 4.0:
745 enmAudioControllerType = None;
746 reporter.log('Configuring audio controller type ...');
747 if self.sAudioControllerType is None:
748 oOsType = oSession.getOsType();
749 enmAudioControllerType = oOsType.recommendedAudioController;
750 else:
751 if self.sAudioControllerType == 'HDA':
752 enmAudioControllerType = vboxcon.AudioControllerType_HDA;
753 elif self.sAudioControllerType == 'AC97':
754 enmAudioControllerType = vboxcon.AudioControllerType_AC97;
755 elif self.sAudioControllerType == 'SB16':
756 enmAudioControllerType = vboxcon.AudioControllerType_SB16;
757 assert enmAudioControllerType is not None;
758
759 # For now we're encforcing to test the HDA emulation only, regardless of
760 # what the recommended audio controller type from above was.
761 ## @todo Make other emulations work as well.
762 fEncforceHDA = True;
763
764 if fEncforceHDA:
765 enmAudioControllerType = vboxcon.AudioControllerType_HDA;
766 reporter.log('Enforcing audio controller type to HDA');
767
768 reporter.log('Setting user-defined audio controller type to %d' % (enmAudioControllerType));
769 oSession.setupAudio(enmAudioControllerType,
770 fEnable = True, fEnableIn = True, fEnableOut = True);
771
772 # Save the settings.
773 fRc = fRc and oSession.saveSettings();
774 fRc = oSession.close() and fRc;
775
776 reporter.testStart('Waiting for TXS');
777 oSession, oTxsSession = self.startVmAndConnectToTxsViaTcp(oTestVm.sVmName,
778 fCdWait = True,
779 cMsTimeout = 3 * 60 * 1000,
780 sFileCdWait = '${OS/ARCH}/vkat${EXESUFF}');
781 reporter.testDone();
782
783 reporter.log('Waiting for any OS startup sounds getting played (to skip those) ...');
784 time.sleep(5);
785
786 if oSession is not None:
787 self.addTask(oTxsSession);
788
789 fRc = self.doTest(oTestVm, oSession, oTxsSession);
790
791 # Cleanup.
792 self.removeTask(oTxsSession);
793 self.terminateVmBySession(oSession);
794
795 reporter.testDone();
796 return fRc;
797
798 def onExit(self, iRc):
799 """
800 Exit handler for this test driver.
801 """
802 return vbox.TestDriver.onExit(self, iRc);
803
804if __name__ == '__main__':
805 sys.exit(tdAudioTest().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