VirtualBox

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

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

Audio/Validation Kit: Waiting for any OS startup sounds getting played (to skip those). ​bugref:10008

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