VirtualBox

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

Last change on this file since 91350 was 91212, checked in by vboxsync, 4 years ago

Audio/VKAT: Implemented support for (optional) VKAT "test" command arguments in the test driver. bugref:10008

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

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