VirtualBox

source: vbox/trunk/src/VBox/ValidationKit/tests/usb/tdUsb1.py@ 60548

Last change on this file since 60548 was 60522, checked in by vboxsync, 9 years ago

ValidationKit/usb: Fixes, basic compliance testing works finally

  • Property svn:eol-style set to LF
  • Property svn:executable set to *
  • Property svn:keywords set to Author Date Id Revision
File size: 21.0 KB
Line 
1#!/usr/bin/env python
2# -*- coding: utf-8 -*-
3# $Id: tdUsb1.py 60522 2016-04-15 14:34:35Z vboxsync $
4
5"""
6VirtualBox Validation Kit - USB testcase and benchmark.
7"""
8
9__copyright__ = \
10"""
11Copyright (C) 2014-2016 Oracle Corporation
12
13This file is part of VirtualBox Open Source Edition (OSE), as
14available from http://www.virtualbox.org. This file is free software;
15you can redistribute it and/or modify it under the terms of the GNU
16General Public License (GPL) as published by the Free Software
17Foundation, in version 2 as it comes in the "COPYING" file of the
18VirtualBox OSE distribution. VirtualBox OSE is distributed in the
19hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
20
21The contents of this file may alternatively be used under the terms
22of the Common Development and Distribution License Version 1.0
23(CDDL) only, as it comes in the "COPYING.CDDL" file of the
24VirtualBox OSE distribution, in which case the provisions of the
25CDDL are applicable instead of those of the GPL.
26
27You may elect to license modified versions of this file under the
28terms and conditions of either the GPL or the CDDL or both.
29"""
30__version__ = "$Revision: 60522 $"
31
32
33# Standard Python imports.
34import os;
35import sys;
36import socket;
37
38# Only the main script needs to modify the path.
39try: __file__
40except: __file__ = sys.argv[0];
41g_ksValidationKitDir = os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__))));
42sys.path.append(g_ksValidationKitDir);
43
44# Validation Kit imports.
45from testdriver import reporter;
46from testdriver import base;
47from testdriver import vbox;
48from testdriver import vboxcon;
49
50# USB gadget control import
51import usbgadget2;
52
53class tdUsbBenchmark(vbox.TestDriver): # pylint: disable=R0902
54 """
55 USB benchmark.
56 """
57
58 # The available test devices
59 #
60 # The first key is the hostname of the host the test is running on.
61 # It contains a new dictionary with the attached gadgets based on the
62 # USB speed we want to test (Low, Full, High, Super).
63 # The parameters consist of the hostname of the gadget in the network
64 # and the hardware type.
65 kdGadgetParams = {
66 'adaris': {
67 'Low': ('usbtest.de.oracle.com', None),
68 'Full': ('usbtest.de.oracle.com', None),
69 'High': ('usbtest.de.oracle.com', None),
70 'Super': ('usbtest.de.oracle.com', None)
71 },
72 };
73
74 # Mappings of USB controllers to supported USB device speeds.
75 kdUsbSpeedMappings = {
76 'OHCI': ['Low', 'Full'],
77 'EHCI': ['High'],
78 'XHCI': ['Low', 'Full', 'High', 'Super']
79 };
80
81 def __init__(self):
82 vbox.TestDriver.__init__(self);
83 self.asRsrcs = None;
84 self.asTestVMsDef = ['tst-arch'];
85 self.asTestVMs = self.asTestVMsDef;
86 self.asSkipVMs = [];
87 self.asVirtModesDef = ['hwvirt', 'hwvirt-np', 'raw'];
88 self.asVirtModes = self.asVirtModesDef;
89 self.acCpusDef = [1, 2,];
90 self.acCpus = self.acCpusDef;
91 self.asUsbCtrlsDef = ['OHCI', 'EHCI', 'XHCI'];
92 self.asUsbCtrls = self.asUsbCtrlsDef;
93 self.asUsbSpeedDef = ['Low', 'Full', 'High', 'Super'];
94 self.asUsbSpeed = self.asUsbSpeedDef;
95 self.asUsbTestsDef = ['Compliance', 'Reattach'];
96 self.asUsbTests = self.asUsbTestsDef;
97 self.cUsbReattachCyclesDef = 100;
98 self.cUsbReattachCycles = self.cUsbReattachCyclesDef;
99 self.sHostname = socket.gethostname().lower();
100 self.sGadgetHostnameDef = 'usbtest.de.oracle.com';
101 self.uGadgetPortDef = None;
102
103 #
104 # Overridden methods.
105 #
106 def showUsage(self):
107 rc = vbox.TestDriver.showUsage(self);
108 reporter.log('');
109 reporter.log('tdUsb1 Options:');
110 reporter.log(' --virt-modes <m1[:m2[:]]');
111 reporter.log(' Default: %s' % (':'.join(self.asVirtModesDef)));
112 reporter.log(' --cpu-counts <c1[:c2[:]]');
113 reporter.log(' Default: %s' % (':'.join(str(c) for c in self.acCpusDef)));
114 reporter.log(' --test-vms <vm1[:vm2[:...]]>');
115 reporter.log(' Test the specified VMs in the given order. Use this to change');
116 reporter.log(' the execution order or limit the choice of VMs');
117 reporter.log(' Default: %s (all)' % (':'.join(self.asTestVMsDef)));
118 reporter.log(' --skip-vms <vm1[:vm2[:...]]>');
119 reporter.log(' Skip the specified VMs when testing.');
120 reporter.log(' --usb-ctrls <u1[:u2[:]]');
121 reporter.log(' Default: %s' % (':'.join(str(c) for c in self.asUsbCtrlsDef)));
122 reporter.log(' --usb-speed <s1[:s2[:]]');
123 reporter.log(' Default: %s' % (':'.join(str(c) for c in self.asUsbSpeedDef)));
124 reporter.log(' --usb-tests <s1[:s2[:]]');
125 reporter.log(' Default: %s' % (':'.join(str(c) for c in self.asUsbTestsDef)));
126 reporter.log(' --usb-reattach-cycles <cycles>');
127 reporter.log(' Default: %s' % (self.cUsbReattachCyclesDef));
128 reporter.log(' --hostname: <hostname>');
129 reporter.log(' Default: %s' % (self.sHostname));
130 reporter.log(' --default-gadget-host <hostname>');
131 reporter.log(' Default: %s' % (self.sGadgetHostnameDef));
132 reporter.log(' --default-gadget-port <port>');
133 reporter.log(' Default: %s' % (6042));
134 return rc;
135
136 def parseOption(self, asArgs, iArg): # pylint: disable=R0912,R0915
137 if asArgs[iArg] == '--virt-modes':
138 iArg += 1;
139 if iArg >= len(asArgs): raise base.InvalidOption('The "--virt-modes" takes a colon separated list of modes');
140 self.asVirtModes = asArgs[iArg].split(':');
141 for s in self.asVirtModes:
142 if s not in self.asVirtModesDef:
143 raise base.InvalidOption('The "--virt-modes" value "%s" is not valid; valid values are: %s' \
144 % (s, ' '.join(self.asVirtModesDef)));
145 elif asArgs[iArg] == '--cpu-counts':
146 iArg += 1;
147 if iArg >= len(asArgs): raise base.InvalidOption('The "--cpu-counts" takes a colon separated list of cpu counts');
148 self.acCpus = [];
149 for s in asArgs[iArg].split(':'):
150 try: c = int(s);
151 except: raise base.InvalidOption('The "--cpu-counts" value "%s" is not an integer' % (s,));
152 if c <= 0: raise base.InvalidOption('The "--cpu-counts" value "%s" is zero or negative' % (s,));
153 self.acCpus.append(c);
154 elif asArgs[iArg] == '--test-vms':
155 iArg += 1;
156 if iArg >= len(asArgs): raise base.InvalidOption('The "--test-vms" takes colon separated list');
157 self.asTestVMs = asArgs[iArg].split(':');
158 for s in self.asTestVMs:
159 if s not in self.asTestVMsDef:
160 raise base.InvalidOption('The "--test-vms" value "%s" is not valid; valid values are: %s' \
161 % (s, ' '.join(self.asTestVMsDef)));
162 elif asArgs[iArg] == '--skip-vms':
163 iArg += 1;
164 if iArg >= len(asArgs): raise base.InvalidOption('The "--skip-vms" takes colon separated list');
165 self.asSkipVMs = asArgs[iArg].split(':');
166 for s in self.asSkipVMs:
167 if s not in self.asTestVMsDef:
168 reporter.log('warning: The "--test-vms" value "%s" does not specify any of our test VMs.' % (s));
169 elif asArgs[iArg] == '--usb-ctrls':
170 iArg += 1;
171 if iArg >= len(asArgs): raise base.InvalidOption('The "--usb-ctrls" takes a colon separated list of USB controllers');
172 self.asUsbCtrls = asArgs[iArg].split(':');
173 for s in self.asUsbCtrls:
174 if s not in self.asUsbCtrlsDef:
175 reporter.log('warning: The "--usb-ctrls" value "%s" is not a valid USB controller.' % (s));
176 elif asArgs[iArg] == '--usb-speed':
177 iArg += 1;
178 if iArg >= len(asArgs): raise base.InvalidOption('The "--usb-speed" takes a colon separated list of USB speeds');
179 self.asUsbSpeed = asArgs[iArg].split(':');
180 for s in self.asUsbSpeed:
181 if s not in self.asUsbSpeedDef:
182 reporter.log('warning: The "--usb-speed" value "%s" is not a valid USB speed.' % (s));
183 elif asArgs[iArg] == '--usb-tests':
184 iArg += 1;
185 if iArg >= len(asArgs): raise base.InvalidOption('The "--usb-tests" takes a colon separated list of USB tests');
186 self.asUsbTests = asArgs[iArg].split(':');
187 for s in self.asUsbTests:
188 if s not in self.asUsbTestsDef:
189 reporter.log('warning: The "--usb-tests" value "%s" is not a valid USB test.' % (s));
190 elif asArgs[iArg] == '--usb-reattach-cycles':
191 iArg += 1;
192 if iArg >= len(asArgs): raise base.InvalidOption('The "--usb-reattach-cycles" takes cycle count');
193 try: self.cUsbReattachCycles = int(asArgs[iArg]);
194 except: raise base.InvalidOption('The "--usb-reattach-cycles" value "%s" is not an integer' \
195 % (asArgs[iArg],));
196 if self.cUsbReattachCycles <= 0:
197 raise base.InvalidOption('The "--usb-reattach-cycles" value "%s" is zero or negative.' \
198 % (self.cUsbReattachCycles,));
199 elif asArgs[iArg] == '--hostname':
200 iArg += 1;
201 if iArg >= len(asArgs): raise base.InvalidOption('The "--hostname" takes a hostname');
202 self.sHostname = asArgs[iArg];
203 elif asArgs[iArg] == '--default-gadget-host':
204 iArg += 1;
205 if iArg >= len(asArgs): raise base.InvalidOption('The "--default-gadget-host" takes a hostname');
206 self.sGadgetHostnameDef = asArgs[iArg];
207 elif asArgs[iArg] == '--default-gadget-port':
208 iArg += 1;
209 if iArg >= len(asArgs): raise base.InvalidOption('The "--default-gadget-port" takes port number');
210 try: self.uGadgetPortDef = int(asArgs[iArg]);
211 except: raise base.InvalidOption('The "--default-gadget-port" value "%s" is not an integer' \
212 % (asArgs[iArg],));
213 if self.uGadgetPortDef <= 0:
214 raise base.InvalidOption('The "--default-gadget-port" value "%s" is zero or negative.' \
215 % (self.uGadgetPortDef,));
216 else:
217 return vbox.TestDriver.parseOption(self, asArgs, iArg);
218 return iArg + 1;
219
220 def completeOptions(self):
221 # Remove skipped VMs from the test list.
222 for sVM in self.asSkipVMs:
223 try: self.asTestVMs.remove(sVM);
224 except: pass;
225
226 return vbox.TestDriver.completeOptions(self);
227
228 def getResourceSet(self):
229 # Construct the resource list the first time it's queried.
230 if self.asRsrcs is None:
231 self.asRsrcs = [];
232
233 if 'tst-arch' in self.asTestVMs:
234 self.asRsrcs.append('4.2/usb/tst-arch.vdi');
235
236 return self.asRsrcs;
237
238 def actionConfig(self):
239
240 # Some stupid trickery to guess the location of the iso. ## fixme - testsuite unzip ++
241 sVBoxValidationKit_iso = os.path.abspath(os.path.join(os.path.dirname(__file__), '../../VBoxValidationKit.iso'));
242 if not os.path.isfile(sVBoxValidationKit_iso):
243 sVBoxValidationKit_iso = os.path.abspath(os.path.join(os.path.dirname(__file__), '../../VBoxTestSuite.iso'));
244 if not os.path.isfile(sVBoxValidationKit_iso):
245 sVBoxValidationKit_iso = '/mnt/ramdisk/vbox/svn/trunk/validationkit/VBoxValidationKit.iso';
246 if not os.path.isfile(sVBoxValidationKit_iso):
247 sVBoxValidationKit_iso = '/mnt/ramdisk/vbox/svn/trunk/testsuite/VBoxTestSuite.iso';
248 if not os.path.isfile(sVBoxValidationKit_iso):
249 sCur = os.getcwd();
250 for i in range(0, 10):
251 sVBoxValidationKit_iso = os.path.join(sCur, 'validationkit/VBoxValidationKit.iso');
252 if os.path.isfile(sVBoxValidationKit_iso):
253 break;
254 sVBoxValidationKit_iso = os.path.join(sCur, 'testsuite/VBoxTestSuite.iso');
255 if os.path.isfile(sVBoxValidationKit_iso):
256 break;
257 sCur = os.path.abspath(os.path.join(sCur, '..'));
258 if i is None: pass; # shut up pychecker/pylint.
259 if not os.path.isfile(sVBoxValidationKit_iso):
260 sVBoxValidationKit_iso = '/home/bird/validationkit/VBoxValidationKit.iso';
261 if not os.path.isfile(sVBoxValidationKit_iso):
262 sVBoxValidationKit_iso = '/home/bird/testsuite/VBoxTestSuite.iso';
263
264 # Make sure vboxapi has been imported so we can use the constants.
265 if not self.importVBoxApi():
266 return False;
267
268 #
269 # Configure the VMs we're going to use.
270 #
271
272 # Linux VMs
273 if 'tst-arch' in self.asTestVMs:
274 oVM = self.createTestVM('tst-arch', 1, '4.2/usb/tst-arch.vdi', sKind = 'ArchLinux_64', fIoApic = True, \
275 eNic0AttachType = vboxcon.NetworkAttachmentType_NAT, \
276 sDvdImage = sVBoxValidationKit_iso);
277 if oVM is None:
278 return False;
279
280 return True;
281
282 def actionExecute(self):
283 """
284 Execute the testcase.
285 """
286 fRc = self.testUsb();
287 return fRc;
288
289 def getGadgetParams(self, sHostname, sSpeed):
290 """
291 Returns the gadget hostname and port from the
292 given hostname the test is running on and device speed we want to test.
293 """
294 kdGadgetsConfigured = self.kdGadgetParams.get(sHostname);
295 if kdGadgetsConfigured is not None:
296 return kdGadgetsConfigured.get(sSpeed);
297
298 return (self.sGadgetHostnameDef, self.uGadgetPortDef);
299
300 #
301 # Test execution helpers.
302 #
303 def testUsbCompliance(self, oSession, oTxsSession, sUsbCtrl, sSpeed):
304 """
305 Test VirtualBoxs USB stack in a VM.
306 """
307 # Get configured USB test devices from hostname we are running on
308 sGadgetHost, uGadgetPort = self.getGadgetParams(self.sHostname, sSpeed);
309
310 oUsbGadget = usbgadget2.UsbGadget();
311 reporter.log('Connecting to UTS: ' + sGadgetHost);
312 fRc = oUsbGadget.connectTo(30 * 1000, sGadgetHost, uPort = uGadgetPort);
313 if fRc is True:
314 reporter.log('Connect succeeded');
315 self.oVBox.host.addUSBDeviceSource('USBIP', sGadgetHost, sGadgetHost + (':%s' % oUsbGadget.getUsbIpPort()), [], []);
316
317 # Create device filter
318 fRc = oSession.addUsbDeviceFilter('Compliance device', '0525', 'a4a0');
319 if fRc is True:
320 fRc = oUsbGadget.impersonate(usbgadget2.g_ksGadgetImpersonationTest);
321 if fRc is True:
322
323 # Wait a moment to let the USB device appear
324 self.sleep(10);
325
326 tupCmdLine = ('UsbTest', );
327 # Exclude a few tests which hang and cause a timeout, need investigation.
328 if sUsbCtrl is 'XHCI':
329 tupCmdLine = tupCmdLine + ('--exclude', '10', '--exclude', '24');
330
331 fRc = self.txsRunTest(oTxsSession, 'UsbTest', 3600 * 1000, \
332 '${CDROM}/${OS/ARCH}/UsbTest${EXESUFF}', tupCmdLine);
333 if not fRc:
334 reporter.testFailure('Running USB test utility failed');
335
336 else:
337 reporter.testFailure('Failed to impersonate test device');
338
339 oUsbGadget.disconnectFrom();
340 else:
341 reporter.testFailure('Failed to create USB device filter');
342
343 self.oVBox.host.removeUSBDeviceSource(sGadgetHost);
344 else:
345 reporter.testFailure('Failed to connect to USB gadget');
346
347 return fRc;
348
349 def testUsbReattach(self, oSession, oTxsSession, sUsbCtrl, sSpeed): # pylint: disable=W0613
350 """
351 Tests that rapid connect/disconnect cycles work.
352 """
353 # Get configured USB test devices from hostname we are running on
354 sGadgetHost, _ = self.getGadgetParams(self.sHostname, sSpeed);
355
356 oUsbGadget = usbgadget2.UsbGadget();
357 reporter.log('Connecting to UTS: ' + sGadgetHost);
358 fRc = oUsbGadget.connectTo(30 * 1000, sGadgetHost);
359 if fRc is True:
360 reporter.log('Connect succeeded');
361 self.oVBox.host.addUSBDeviceSource('USBIP', sGadgetHost, sGadgetHost + ':' + oUsbGadget.getUsbIpPort(), [], []);
362
363 # Create device filter
364 fRc = oSession.addUsbDeviceFilter('Compliance device', '0525', 'a4a0');
365 if fRc is True:
366 fRc = oUsbGadget.impersonate(usbgadget2.g_ksGadgetImpersonationTest);
367 if fRc is True:
368
369 self.sleep(1);
370
371 # Do a rapid disconnect reconnect cycle. Wait a second before disconnecting
372 # again or it will happen so fast that the VM can't attach the new device.
373 # @todo: Get rid of the constant wait and use an event to get notified when
374 # the device was attached.
375 for iCycle in xrange (0, self.cUsbReattachCycles):
376 fRc = oUsbGadget.disconnectUsb();
377 fRc = fRc and oUsbGadget.connectUsb();
378 if not fRc:
379 reporter.testFailure('Reattach cycle %s failed on the gadget device' % (iCycle));
380 break;
381 self.sleep(1);
382
383 else:
384 reporter.testFailure('Failed to impersonate test device');
385
386 oUsbGadget.disconnectFrom();
387 else:
388 reporter.testFailure('Failed to connect to USB gadget');
389 else:
390 reporter.testFailure('Failed to create USB device filter');
391
392 return fRc;
393
394 def testUsbOneCfg(self, sVmName, sUsbCtrl, sSpeed, sUsbTest):
395 """
396 Runs the specified VM thru one specified test.
397
398 Returns a success indicator on the general test execution. This is not
399 the actual test result.
400 """
401 oVM = self.getVmByName(sVmName);
402
403 # Reconfigure the VM
404 fRc = True;
405 oSession = self.openSession(oVM);
406 if oSession is not None:
407 fRc = fRc and oSession.enableVirtEx(True);
408 fRc = fRc and oSession.enableNestedPaging(True);
409
410 # Make sure controllers are disabled initially.
411 fRc = fRc and oSession.enableUsbOhci(False);
412 fRc = fRc and oSession.enableUsbEhci(False);
413 fRc = fRc and oSession.enableUsbXhci(False);
414
415 if sUsbCtrl == 'OHCI':
416 fRc = fRc and oSession.enableUsbOhci(True);
417 elif sUsbCtrl == 'EHCI':
418 fRc = fRc and oSession.enableUsbEhci(True);
419 elif sUsbCtrl == 'XHCI':
420 fRc = fRc and oSession.enableUsbXhci(True);
421 fRc = fRc and oSession.saveSettings();
422 fRc = oSession.close() and fRc and True; # pychecker hack.
423 oSession = None;
424 else:
425 fRc = False;
426
427 # Start up.
428 if fRc is True:
429 self.logVmInfo(oVM);
430 oSession, oTxsSession = self.startVmAndConnectToTxsViaTcp(sVmName, fCdWait = False, fNatForwardingForTxs = False);
431 if oSession is not None:
432 self.addTask(oSession);
433
434 # Fudge factor - Allow the guest to finish starting up.
435 self.sleep(5);
436
437 if sUsbTest == 'Compliance':
438 fRc = self.testUsbCompliance(oSession, oTxsSession, sUsbCtrl, sSpeed);
439 elif sUsbTest == 'Reattach':
440 fRc = self.testUsbReattach(oSession, oTxsSession, sUsbCtrl, sSpeed);
441
442 # cleanup.
443 self.removeTask(oTxsSession);
444 self.terminateVmBySession(oSession)
445 else:
446 fRc = False;
447 return fRc;
448
449 def testUsbForOneVM(self, sVmName):
450 """
451 Runs one VM thru the various configurations.
452 """
453 reporter.testStart(sVmName);
454 for sUsbCtrl in self.asUsbCtrls:
455 reporter.testStart(sUsbCtrl)
456 for sUsbSpeed in self.asUsbSpeed:
457 asSupportedSpeeds = self.kdUsbSpeedMappings.get(sUsbCtrl);
458 if sUsbSpeed in asSupportedSpeeds:
459 reporter.testStart(sUsbSpeed)
460 for sUsbTest in self.asUsbTests:
461 reporter.testStart(sUsbTest)
462 fRc = self.testUsbOneCfg(sVmName, sUsbCtrl, sUsbSpeed, sUsbTest);
463 reporter.testDone();
464 reporter.testDone();
465 reporter.testDone();
466 reporter.testDone();
467 return fRc;
468
469 def testUsb(self):
470 """
471 Executes USB test.
472 """
473
474 reporter.log("Running on host: " + self.sHostname);
475
476 # Loop thru the test VMs.
477 for sVM in self.asTestVMs:
478 # run test on the VM.
479 fRc = self.testUsbForOneVM(sVM);
480
481 return fRc;
482
483
484
485if __name__ == '__main__':
486 sys.exit(tdUsbBenchmark().main(sys.argv));
487
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