VirtualBox

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

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

Audio/Validation Kit: Also pass on the verbosity level when doing the host audio enumeration test. ​bugref:10008

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 30.9 KB
Line 
1# -*- coding: utf-8 -*-
2# $Id: tdAudioTest.py 92011 2021-10-22 17:00:34Z 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: 92011 $"
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 if self.sRunningVmName is None:
217 return self.oTestVmSet.actionExecute(self, self.testOneVmConfig);
218 return self.actionExecuteOnRunnigVM();
219
220 def actionExecuteOnRunnigVM(self):
221 """
222 Executes the tests in an already configured + running VM.
223 """
224 if not self.importVBoxApi():
225 return False;
226
227 fRc = True;
228
229 oVM = None;
230 oVirtualBox = None;
231
232 oVirtualBox = self.oVBoxMgr.getVirtualBox();
233 try:
234 oVM = oVirtualBox.findMachine(self.sRunningVmName);
235 if oVM.state != self.oVBoxMgr.constants.MachineState_Running:
236 reporter.error("Machine '%s' is not in Running state (state is %d)" % (self.sRunningVmName, oVM.state));
237 fRc = False;
238 except:
239 reporter.errorXcpt("Machine '%s' not found" % (self.sRunningVmName));
240 fRc = False;
241
242 if fRc:
243 oSession = self.openSession(oVM);
244 if oSession:
245 # Tweak this to your likings.
246 oTestVm = vboxtestvms.TestVm('runningvm', sKind = 'WindowsXP'); #sKind = 'WindowsXP' # sKind = 'Ubuntu_64'
247 (fRc, oTxsSession) = self.txsDoConnectViaTcp(oSession, 30 * 1000);
248 if fRc:
249 self.doTest(oTestVm, oSession, oTxsSession);
250 else:
251 reporter.error("Unable to open session for machine '%s'" % (self.sRunningVmName));
252 fRc = False;
253
254 if oVM:
255 del oVM;
256 if oVirtualBox:
257 del oVirtualBox;
258 return fRc;
259
260 def getGstVkatLogFilePath(self, oTestVm):
261 """
262 Returns the log file path of VKAT running on the guest (daemonized).
263 """
264 return oTestVm.pathJoin(self.getGuestTempDir(oTestVm), 'vkat-guest.log');
265
266 def locateGstBinary(self, oSession, oTxsSession, asPaths):
267 """
268 Locates a guest binary on the guest by checking the paths in \a asPaths.
269 """
270 for sCurPath in asPaths:
271 reporter.log2('Checking for \"%s\" ...' % (sCurPath));
272 if self.txsIsFile(oSession, oTxsSession, sCurPath, fIgnoreErrors = True):
273 return (True, sCurPath);
274 reporter.error('Unable to find guest binary in any of these places:\n%s' % ('\n'.join(asPaths),));
275 return (False, "");
276
277 def executeHstLoop(self, sWhat, asArgs, asEnv = None, fAsAdmin = False):
278 """
279 Inner loop which handles the execution of a host binary.
280 """
281 fRc = False;
282
283 asEnvTmp = os.environ.copy();
284 if asEnv:
285 for sEnv in asEnv:
286 sKey, sValue = sEnv.split('=');
287 reporter.log2('Setting env var \"%s\" -> \"%s\"' % (sKey, sValue));
288 os.environ[sKey] = sValue; # Also apply it to the current environment.
289 asEnvTmp[sKey] = sValue;
290
291 if fAsAdmin \
292 and utils.getHostOs() != 'win':
293 oProcess = utils.sudoProcessPopen(asArgs,
294 env = asEnvTmp,
295 stdout = sys.stdout, stderr = sys.stdout,
296 close_fds = False);
297 else:
298 oProcess = utils.processPopenSafe(asArgs,
299 env = asEnvTmp,
300 stdout = sys.stdout, stderr = sys.stdout);
301 if oProcess:
302 self.pidFileAdd(oProcess.pid, sWhat, fSudo = fAsAdmin);
303 iRc = oProcess.wait();
304 self.pidFileRemove(oProcess.pid);
305
306 if iRc == 0:
307 reporter.log('*** %s: exit code %d' % (sWhat, iRc));
308 fRc = True;
309 else:
310 reporter.log('!*! %s: exit code %d' % (sWhat, iRc));
311
312 return fRc;
313
314 def executeHst(self, sWhat, asArgs, asEnv = None, fAsync = False, fAsAdmin = False):
315 """
316 Runs a binary (image) with optional admin (root) rights on the host and
317 waits until it terminates.
318
319 Windows currently is not supported yet running stuff as Administrator.
320
321 Returns success status (exit code is 0).
322 """
323 reporter.log('Executing \"%s\" on host (as admin = %s, async = %s)' % (sWhat, fAsAdmin, fAsync));
324
325 reporter.testStart(sWhat);
326
327 try: sys.stdout.flush();
328 except: pass;
329 try: sys.stderr.flush();
330 except: pass;
331
332 fRc = self.executeHstLoop(sWhat, asArgs, asEnv);
333 if fRc:
334 reporter.log('Executing \"%s\" on host done' % (sWhat,));
335 else:
336 reporter.log('Executing \"%s\" on host failed' % (sWhat,));
337
338 reporter.testDone();
339
340 return fRc;
341
342 def killHstProcessByName(self, sProcName):
343 """
344 Kills processes by their name.
345 """
346 reporter.log('Trying to kill processes named "%s"' % (sProcName,));
347 if sys.platform == 'win32':
348 sArgProcName = '\"%s.exe\"' % sProcName;
349 asArgs = [ 'taskkill', '/IM', sArgProcName, '/F' ];
350 self.executeHst('Killing process', asArgs);
351 else: # Note: killall is not available on older Debians (requires psmisc).
352 # Using the BSD syntax here; MacOS also should understand this.
353 procPs = subprocess.Popen(['ps', 'ax'], stdout=subprocess.PIPE);
354 out, err = procPs.communicate();
355 if err:
356 reporter.log('PS stderr:');
357 for sLine in err.decode('utf-8').splitlines():
358 reporter.log(sLine);
359 if out:
360 reporter.log4('PS stdout:');
361 for sLine in out.decode('utf-8').splitlines():
362 reporter.log4(sLine);
363 if sProcName in sLine:
364 pid = int(sLine.split(None, 1)[0]);
365 reporter.log('Killing PID %d' % (pid,));
366 os.kill(pid, signal.SIGKILL); # pylint: disable=no-member
367
368 def killHstVkat(self):
369 """
370 Kills VKAT (VBoxAudioTest) on the host side.
371 """
372 reporter.log('Killing stale/old VKAT processes ...');
373 self.killHstProcessByName("vkat");
374 self.killHstProcessByName("VBoxAudioTest");
375
376 def getWinFirewallArgsDisable(self, sOsType):
377 """
378 Returns the command line arguments for Windows OSes
379 to disable the built-in firewall (if any).
380
381 If not supported, returns an empty array.
382 """
383 if sOsType == 'vista': # pylint: disable=no-else-return
384 # Vista and up.
385 return (['netsh.exe', 'advfirewall', 'set', 'allprofiles', 'state', 'off']);
386 elif sOsType == 'xp': # Older stuff (XP / 2003).
387 return(['netsh.exe', 'firewall', 'set', 'opmode', 'mode=DISABLE']);
388 # Not supported / available.
389 return [];
390
391 def disableGstFirewall(self, oTestVm, oTxsSession):
392 """
393 Disables the firewall on a guest (if any).
394
395 Needs elevated / admin / root privileges.
396
397 Returns success status, not logged.
398 """
399 fRc = False;
400
401 asArgs = [];
402 sOsType = '';
403 if oTestVm.isWindows():
404 if oTestVm.sKind in ['WindowsNT4', 'WindowsNT3x']:
405 sOsType = 'nt3x'; # Not supported, but define it anyway.
406 elif oTestVm.sKind in ('Windows2000', 'WindowsXP', 'Windows2003'):
407 sOsType = 'xp';
408 else:
409 sOsType = 'vista';
410 asArgs = self.getWinFirewallArgsDisable(sOsType);
411 else:
412 sOsType = 'unsupported';
413
414 reporter.log('Disabling firewall on guest (type: %s) ...' % (sOsType,));
415
416 if asArgs:
417 fRc = self.txsRunTest(oTxsSession, 'Disabling guest firewall', 3 * 60 * 1000, \
418 oTestVm.pathJoin(self.getGuestSystemDir(oTestVm), asArgs[0]), asArgs);
419 if not fRc:
420 reporter.error('Disabling firewall on guest returned exit code error %d' % (self.getLastRcFromTxs(oTxsSession)));
421 else:
422 reporter.log('Firewall not available on guest, skipping');
423 fRc = True; # Not available, just skip.
424
425 return fRc;
426
427 def disableHstFirewall(self):
428 """
429 Disables the firewall on the host (if any).
430
431 Needs elevated / admin / root privileges.
432
433 Returns success status, not logged.
434 """
435 fRc = False;
436
437 asArgs = [];
438 sOsType = sys.platform;
439
440 if sOsType == 'win32':
441 reporter.log('Disabling firewall on host (type: %s) ...' % (sOsType));
442
443 ## @todo For now we ASSUME that we don't run (and don't support even) on old(er)
444 # Windows hosts than Vista.
445 asArgs = self.getWinFirewallArgsDisable('vista');
446 if asArgs:
447 fRc = self.executeHst('Disabling host firewall', asArgs, fAsAdmin = True);
448 else:
449 reporter.log('Firewall not available on host, skipping');
450 fRc = True; # Not available, just skip.
451
452 return fRc;
453
454 def getLastRcFromTxs(self, oTxsSession):
455 """
456 Extracts the last exit code reported by TXS from a run before.
457 Assumes that nothing else has been run on the same TXS session in the meantime.
458 """
459 iRc = 0;
460 (_, sOpcode, abPayload) = oTxsSession.getLastReply();
461 if sOpcode.startswith('PROC NOK '): # Extract process rc
462 iRc = abPayload[0]; # ASSUMES 8-bit rc for now.
463 return iRc;
464
465 def startVkatOnGuest(self, oTestVm, oSession, oTxsSession, sTag):
466 """
467 Starts VKAT on the guest (running in background).
468 """
469 sPathTemp = self.getGuestTempDir(oTestVm);
470 sPathAudioOut = oTestVm.pathJoin(sPathTemp, 'vkat-guest-out');
471 sPathAudioTemp = oTestVm.pathJoin(sPathTemp, 'vkat-guest-temp');
472
473 reporter.log('Guest audio test temp path is \"%s\"' % (sPathAudioOut));
474 reporter.log('Guest audio test output path is \"%s\"' % (sPathAudioTemp));
475 reporter.log('Guest audio test tag is \"%s\"' % (sTag));
476
477 fRc, sVkatExe = self.locateGstBinary(oSession, oTxsSession, self.asGstVkatPaths);
478 if fRc:
479 reporter.log('Using VKAT on guest at \"%s\"' % (sVkatExe));
480
481 sCmd = '';
482 asArgs = [];
483
484 asArgsVkat = [ sVkatExe, 'test', '--mode', 'guest', '--probe-backends', \
485 '--tempdir', sPathAudioTemp, '--outdir', sPathAudioOut, \
486 '--tag', sTag ];
487
488 asArgs.extend(asArgsVkat);
489
490 for _ in range(1, reporter.getVerbosity()): # Verbosity always is initialized at 1.
491 asArgs.extend([ '-v' ]);
492
493 # Needed for NATed VMs.
494 asArgs.extend(['--tcp-connect-addr', '10.0.2.2' ]);
495
496 if oTestVm.sKind in 'Oracle_64':
497 #
498 # Some Linux distros have a bug / are configured (?) so that processes started by init system
499 # cannot access the PulseAudio server ("Connection refused"), for example OL 8.1.
500 #
501 # To work around this, we use the (hopefully) configured user "vbox" and run it under its behalf,
502 # as the Test Execution Service (TxS) currently does not implement impersonation yet.
503 #
504 asSU = [ '/bin/su',
505 '/usr/bin/su',
506 '/usr/local/bin/su' ];
507 fRc, sCmd = self.locateGstBinary(oSession, oTxsSession, asSU);
508 if fRc:
509 sCmdArgs = '';
510 for sArg in asArgs:
511 sCmdArgs += sArg + " ";
512 asArgs = [ sCmd, oTestVm.getTestUser(), '-c', sCmdArgs ];
513 else:
514 reporter.log('Unable to find SU on guest, falling back to regular starting ...')
515
516 if not sCmd: # Just start it with the same privileges as TxS.
517 sCmd = sVkatExe;
518
519 reporter.log2('startVkatOnGuest: sCmd=%s' % (sCmd,));
520 reporter.log2('startVkatOnGuest: asArgs=%s' % (asArgs,));
521
522 #
523 # Add own environment stuff.
524 #
525 asEnv = [];
526
527 # Write the log file to some deterministic place so TxS can retrieve it later.
528 sVkatLogFile = 'VKAT_RELEASE_LOG_DEST=file=' + self.getGstVkatLogFilePath(oTestVm);
529 asEnv.extend([ sVkatLogFile ]);
530
531 #
532 # Execute asynchronously on the guest.
533 #
534 fRc = oTxsSession.asyncExec(sCmd, asArgs, asEnv, cMsTimeout = 15 * 60 * 1000, sPrefix = '[VKAT Guest] ');
535 if fRc:
536 self.addTask(oTxsSession);
537
538 if not fRc:
539 reporter.error('VKAT on guest returned exit code error %d' % (self.getLastRcFromTxs(oTxsSession)));
540 else:
541 reporter.error('VKAT on guest not found');
542
543 return fRc;
544
545 def runTests(self, oTestVm, oSession, oTxsSession, sDesc, sTag, asTests):
546 """
547 Runs one or more tests using VKAT on the host, which in turn will
548 communicate with VKAT running on the guest and the Validation Kit
549 audio driver ATS (Audio Testing Service).
550 """
551 _ = oTestVm, oSession, oTxsSession;
552
553 sPathTemp = self.sScratchPath;
554 sPathAudioOut = os.path.join(sPathTemp, 'vkat-host-out-%s' % (sTag));
555 sPathAudioTemp = os.path.join(sPathTemp, 'vkat-host-temp-%s' % (sTag));
556
557 reporter.log('Host audio test temp path is \"%s\"' % (sPathAudioOut));
558 reporter.log('Host audio test output path is \"%s\"' % (sPathAudioTemp));
559 reporter.log('Host audio test tag is \"%s\"' % (sTag));
560
561 reporter.testStart(sDesc);
562
563 sVkatExe = self.getBinTool('vkat');
564
565 reporter.log('Using VKAT on host at: \"%s\"' % (sVkatExe));
566
567 # Build the base command line, exclude all tests by default.
568 asArgs = [ sVkatExe, 'test', '--mode', 'host', '--probe-backends', \
569 '--tempdir', sPathAudioTemp, '--outdir', sPathAudioOut, '-a', \
570 '--tag', sTag, \
571 '--no-verify' ]; # We do the verification separately in the step below.
572
573 for _ in range(1, reporter.getVerbosity()): # Verbosity always is initialized at 1.
574 asArgs.extend([ '-v' ]);
575
576 if self.asVkatTestArgs:
577 asArgs += self.asVkatTestArgs;
578
579 # ... and extend it with wanted tests.
580 asArgs.extend(asTests);
581
582 #
583 # Let VKAT on the host run synchronously.
584 #
585 fRc = self.executeHst("VKAT Host", asArgs);
586
587 reporter.testDone();
588
589 if fRc:
590 #
591 # When running the test(s) above were successful, do the verification step next.
592 # This gives us a bit more fine-grained test results in the test manager.
593 #
594 reporter.testStart('Verifying audio data');
595
596 sNameSetHst = '%s-host.tar.gz' % (sTag);
597 sPathSetHst = os.path.join(sPathAudioOut, sNameSetHst);
598 sNameSetGst = '%s-guest.tar.gz' % (sTag);
599 sPathSetGst = os.path.join(sPathAudioOut, sNameSetGst);
600
601 asArgs = [ sVkatExe, 'verify', sPathSetHst, sPathSetGst ];
602
603 for _ in range(1, reporter.getVerbosity()): # Verbosity always is initialized at 1.
604 asArgs.extend([ '-v' ]);
605
606 if self.asVkatVerifyArgs:
607 asArgs += self.asVkatVerifyArgs;
608
609 fRc = self.executeHst("VKAT Host Verify", asArgs);
610 if fRc:
611 reporter.log("Verification audio data successful");
612 else:
613 #
614 # Add the test sets to the test manager for later (manual) diagnosis.
615 #
616 reporter.addLogFile(sPathSetGst, 'misc/other', 'Guest audio test set');
617 reporter.addLogFile(sPathSetHst, 'misc/other', 'Host audio test set');
618
619 reporter.error("Verification of audio data failed");
620
621 reporter.testDone();
622
623 return fRc;
624
625 def doTest(self, oTestVm, oSession, oTxsSession):
626 """
627 Executes the specified audio tests.
628 """
629
630 # Disable any OS-specific firewalls preventing VKAT / ATS to run.
631 fRc = self.disableHstFirewall();
632 fRc = self.disableGstFirewall(oTestVm, oTxsSession) and fRc;
633
634 if not fRc:
635 return False;
636
637 # First try to kill any old VKAT / VBoxAudioTest processes lurking around on the host.
638 # Might happen because of former (aborted) runs.
639 self.killHstVkat();
640
641 reporter.log("Active tests: %s" % (self.asTests,));
642
643 # Define a tag for the whole run.
644 sTag = oTestVm.sVmName + "_" + datetime.now().strftime("%Y%m%d_%H%M%S");
645
646 fRc = self.startVkatOnGuest(oTestVm, oSession, oTxsSession, sTag);
647 if fRc:
648 #
649 # Execute the tests using VKAT on the guest side (in guest mode).
650 #
651 if "guest_tone_playback" in self.asTests:
652 fRc = self.runTests(oTestVm, oSession, oTxsSession, \
653 'Guest audio playback', sTag + "_test_playback", \
654 asTests = [ '-i0' ]);
655 if "guest_tone_recording" in self.asTests:
656 fRc = fRc and self.runTests(oTestVm, oSession, oTxsSession, \
657 'Guest audio recording', sTag + "_test_recording", \
658 asTests = [ '-i1' ]);
659
660 # Cancel guest VKAT execution task summoned by startVkatOnGuest().
661 oTxsSession.cancelTask();
662
663 #
664 # Retrieve log files for diagnosis.
665 #
666 self.txsDownloadFiles(oSession, oTxsSession,
667 [ ( self.getGstVkatLogFilePath(oTestVm),
668 'vkat-guest-%s.log' % (oTestVm.sVmName,),),
669 ],
670 fIgnoreErrors = True);
671
672
673 # Always attach the VM log to the test report, as we want to see what the Validation Kit audio driver does.
674 oSession.addLogsToReport();
675
676 return fRc;
677
678 def testOneVmConfig(self, oVM, oTestVm):
679 """
680 Runs tests using one specific VM config.
681 """
682
683 self.logVmInfo(oVM);
684
685 reporter.testStart("Audio Testing");
686
687 fSkip = False;
688
689 if oTestVm.isWindows() \
690 and oTestVm.sKind in ('WindowsNT4', 'Windows2000'): # Too old for DirectSound and WASAPI backends.
691 reporter.log('Audio testing skipped, not implemented/available for that OS yet.');
692 fSkip = True;
693
694 if not fSkip \
695 and self.fpApiVer < 7.0:
696 reporter.log('Audio testing for non-trunk builds skipped.');
697 fSkip = True;
698
699 if not fSkip:
700 sVkatExe = self.getBinTool('vkat');
701 asArgs = [ sVkatExe, 'enum', '--probe-backends' ];
702 for _ in range(1, reporter.getVerbosity()): # Verbosity always is initialized at 1.
703 asArgs.extend([ '-v' ]);
704 fRc = self.executeHst("VKAT Host Audio Probing", asArgs);
705 if not fRc:
706 # Not fatal, as VBox then should fall back to the NULL audio backend (also worth having as a test case).
707 reporter.log('Warning: Backend probing on host failed, no audio available (pure server installation?)');
708
709 if fSkip:
710 reporter.testDone(fSkipped = True);
711 return True;
712
713 # Reconfigure the VM.
714 oSession = self.openSession(oVM);
715 if oSession is not None:
716 # Set extra data.
717 for sExtraData in self.asOptExtraData:
718 sKey, sValue = sExtraData.split(':');
719 reporter.log('Set extradata: %s => %s' % (sKey, sValue));
720 fRc = oSession.setExtraData(sKey, sValue) and fRc;
721
722 # Make sure that the VM's audio adapter is configured the way we need it to.
723 if self.fpApiVer >= 4.0:
724 enmAudioControllerType = None;
725 reporter.log('Configuring audio controller type ...');
726 if self.sAudioControllerType is None:
727 oOsType = oSession.getOsType();
728 enmAudioControllerType = oOsType.recommendedAudioController;
729 else:
730 if self.sAudioControllerType == 'HDA':
731 enmAudioControllerType = vboxcon.AudioControllerType_HDA;
732 elif self.sAudioControllerType == 'AC97':
733 enmAudioControllerType = vboxcon.AudioControllerType_AC97;
734 elif self.sAudioControllerType == 'SB16':
735 enmAudioControllerType = vboxcon.AudioControllerType_SB16;
736 assert enmAudioControllerType is not None;
737
738 reporter.log('Setting user-defined audio controller type to %d' % (enmAudioControllerType));
739 oSession.setupAudio(enmAudioControllerType,
740 fEnable = True, fEnableIn = True, fEnableOut = True);
741
742 # Save the settings.
743 fRc = fRc and oSession.saveSettings();
744 fRc = oSession.close() and fRc;
745
746 reporter.testStart('Waiting for TXS');
747 oSession, oTxsSession = self.startVmAndConnectToTxsViaTcp(oTestVm.sVmName,
748 fCdWait = True,
749 cMsTimeout = 3 * 60 * 1000,
750 sFileCdWait = '${OS/ARCH}/vkat${EXESUFF}');
751 reporter.testDone();
752
753 reporter.log('Waiting for any OS startup sounds getting played (to skip those) ...');
754 time.sleep(90);
755
756 if oSession is not None:
757 self.addTask(oTxsSession);
758
759 fRc = self.doTest(oTestVm, oSession, oTxsSession);
760
761 # Cleanup.
762 self.removeTask(oTxsSession);
763 self.terminateVmBySession(oSession);
764
765 reporter.testDone();
766 return fRc;
767
768 def onExit(self, iRc):
769 """
770 Exit handler for this test driver.
771 """
772 return vbox.TestDriver.onExit(self, iRc);
773
774if __name__ == '__main__':
775 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