VirtualBox

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

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

Audio/Validation Kit: More verbosity level handling for the testdriver + Main side [Python 2.x fixes]. bugref:10008

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