VirtualBox

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

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

Audio/Validation Kit: Don't skip testing if host audio is not available, as VBox then should fall back to the NULL audio backend, which also is worth having as a test case. ​bugref:10008

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