VirtualBox

source: vbox/trunk/src/VBox/ValidationKit/tests/storage/tdStorageStress1.py@ 103914

Last change on this file since 103914 was 101035, checked in by vboxsync, 15 months ago

Initial commit (based draft v2 / on patch v5) for implementing platform architecture support for x86 and ARM. bugref:10384

  • Property svn:eol-style set to LF
  • Property svn:executable set to *
  • Property svn:keywords set to Author Date Id Revision
File size: 23.1 KB
Line 
1#!/usr/bin/env python
2# -*- coding: utf-8 -*-
3
4"""
5Storage testcase using xfstests.
6"""
7
8__copyright__ = \
9"""
10Copyright (C) 2012-2023 Oracle and/or its affiliates.
11
12This file is part of VirtualBox base platform packages, as
13available from https://www.virtualbox.org.
14
15This program is free software; you can redistribute it and/or
16modify it under the terms of the GNU General Public License
17as published by the Free Software Foundation, in version 3 of the
18License.
19
20This program is distributed in the hope that it will be useful, but
21WITHOUT ANY WARRANTY; without even the implied warranty of
22MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
23General Public License for more details.
24
25You should have received a copy of the GNU General Public License
26along with this program; if not, see <https://www.gnu.org/licenses>.
27
28The contents of this file may alternatively be used under the terms
29of the Common Development and Distribution License Version 1.0
30(CDDL), a copy of it is provided in the "COPYING.CDDL" file included
31in the VirtualBox distribution, in which case the provisions of the
32CDDL are applicable instead of those of the GPL.
33
34You may elect to license modified versions of this file under the
35terms and conditions of either the GPL or the CDDL or both.
36
37SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0
38"""
39__version__ = "$Id: tdStorageStress1.py 101035 2023-09-07 08:59:15Z vboxsync $"
40
41
42# Standard Python imports.
43import os;
44import sys;
45
46# Only the main script needs to modify the path.
47try: __file__ # pylint: disable=used-before-assignment
48except: __file__ = sys.argv[0];
49g_ksValidationKitDir = os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__))));
50sys.path.append(g_ksValidationKitDir);
51
52# Validation Kit imports.
53from testdriver import reporter;
54from testdriver import base;
55from testdriver import vbox;
56from testdriver import vboxcon;
57
58
59class tdStorageStress(vbox.TestDriver): # pylint: disable=too-many-instance-attributes
60 """
61 Storage testcase.
62 """
63
64 def __init__(self):
65 vbox.TestDriver.__init__(self);
66 self.asRsrcs = None;
67 self.oGuestToGuestVM = None;
68 self.oGuestToGuestSess = None;
69 self.oGuestToGuestTxs = None;
70 self.asTestVMsDef = ['tst-debian'];
71 self.asTestVMs = self.asTestVMsDef;
72 self.asSkipVMs = [];
73 self.asVirtModesDef = ['hwvirt', 'hwvirt-np', 'raw',]
74 self.asVirtModes = self.asVirtModesDef
75 self.acCpusDef = [1, 2,]
76 self.acCpus = self.acCpusDef;
77 self.asStorageCtrlsDef = ['AHCI', 'IDE', 'LsiLogicSAS', 'LsiLogic', 'BusLogic'];
78 self.asStorageCtrls = self.asStorageCtrlsDef;
79 self.asDiskFormatsDef = ['VDI', 'VMDK', 'VHD', 'QED', 'Parallels', 'QCOW'];
80 self.asDiskFormats = self.asDiskFormatsDef;
81 self.asTestsDef = ['xfstests'];
82 self.asTests = self.asTestsDef;
83 self.asGuestFs = ['xfs', 'ext4', 'btrfs'];
84 self.asGuestFsDef = self.asGuestFs;
85 self.asIscsiTargetsDef = ['aurora|iqn.2011-03.home.aurora:aurora.storagebench|1'];
86 self.asIscsiTargets = self.asIscsiTargetsDef;
87 self.asDirsDef = ['/run/media/alexander/OWCSSD/alexander', \
88 '/run/media/alexander/CrucialSSD/alexander', \
89 '/run/media/alexander/HardDisk/alexander', \
90 '/home/alexander'];
91 self.asDirs = self.asDirsDef;
92
93 #
94 # Overridden methods.
95 #
96 def showUsage(self):
97 rc = vbox.TestDriver.showUsage(self);
98 reporter.log('');
99 reporter.log('tdStorageBenchmark1 Options:');
100 reporter.log(' --virt-modes <m1[:m2[:]]');
101 reporter.log(' Default: %s' % (':'.join(self.asVirtModesDef)));
102 reporter.log(' --cpu-counts <c1[:c2[:]]');
103 reporter.log(' Default: %s' % (':'.join(str(c) for c in self.acCpusDef)));
104 reporter.log(' --storage-ctrls <type1[:type2[:...]]>');
105 reporter.log(' Default: %s' % (':'.join(self.asStorageCtrls)));
106 reporter.log(' --disk-formats <type1[:type2[:...]]>');
107 reporter.log(' Default: %s' % (':'.join(self.asDiskFormats)));
108 reporter.log(' --disk-dirs <path1[:path2[:...]]>');
109 reporter.log(' Default: %s' % (':'.join(self.asDirs)));
110 reporter.log(' --iscsi-targets <target1[:target2[:...]]>');
111 reporter.log(' Default: %s' % (':'.join(self.asIscsiTargets)));
112 reporter.log(' --tests <test1[:test2[:...]]>');
113 reporter.log(' Default: %s' % (':'.join(self.asTests)));
114 reporter.log(' --guest-fs <fs1[:fs2[:...]]>');
115 reporter.log(' Default: %s' % (':'.join(self.asGuestFs)));
116 reporter.log(' --test-vms <vm1[:vm2[:...]]>');
117 reporter.log(' Test the specified VMs in the given order. Use this to change');
118 reporter.log(' the execution order or limit the choice of VMs');
119 reporter.log(' Default: %s (all)' % (':'.join(self.asTestVMsDef)));
120 reporter.log(' --skip-vms <vm1[:vm2[:...]]>');
121 reporter.log(' Skip the specified VMs when testing.');
122 return rc;
123
124 def parseOption(self, asArgs, iArg): # pylint: disable=too-many-branches,too-many-statements
125 if asArgs[iArg] == '--virt-modes':
126 iArg += 1;
127 if iArg >= len(asArgs): raise base.InvalidOption('The "--virt-modes" takes a colon separated list of modes');
128 self.asVirtModes = asArgs[iArg].split(':');
129 for s in self.asVirtModes:
130 if s not in self.asVirtModesDef:
131 raise base.InvalidOption('The "--virt-modes" value "%s" is not valid; valid values are: %s' \
132 % (s, ' '.join(self.asVirtModesDef)));
133 elif asArgs[iArg] == '--cpu-counts':
134 iArg += 1;
135 if iArg >= len(asArgs): raise base.InvalidOption('The "--cpu-counts" takes a colon separated list of cpu counts');
136 self.acCpus = [];
137 for s in asArgs[iArg].split(':'):
138 try: c = int(s);
139 except: raise base.InvalidOption('The "--cpu-counts" value "%s" is not an integer' % (s,));
140 if c <= 0: raise base.InvalidOption('The "--cpu-counts" value "%s" is zero or negative' % (s,));
141 self.acCpus.append(c);
142 elif asArgs[iArg] == '--storage-ctrls':
143 iArg += 1;
144 if iArg >= len(asArgs):
145 raise base.InvalidOption('The "--storage-ctrls" takes a colon separated list of Storage controller types');
146 self.asStorageCtrls = asArgs[iArg].split(':');
147 elif asArgs[iArg] == '--disk-formats':
148 iArg += 1;
149 if iArg >= len(asArgs): raise base.InvalidOption('The "--disk-formats" takes a colon separated list of disk formats');
150 self.asDiskFormats = asArgs[iArg].split(':');
151 elif asArgs[iArg] == '--disk-dirs':
152 iArg += 1;
153 if iArg >= len(asArgs): raise base.InvalidOption('The "--disk-dirs" takes a colon separated list of directories');
154 self.asDirs = asArgs[iArg].split(':');
155 elif asArgs[iArg] == '--iscsi-targets':
156 iArg += 1;
157 if iArg >= len(asArgs):
158 raise base.InvalidOption('The "--iscsi-targets" takes a colon separated list of iscsi targets');
159 self.asIscsiTargets = asArgs[iArg].split(':');
160 elif asArgs[iArg] == '--tests':
161 iArg += 1;
162 if iArg >= len(asArgs): raise base.InvalidOption('The "--tests" takes a colon separated list of disk formats');
163 self.asTests = asArgs[iArg].split(':');
164 elif asArgs[iArg] == '--guest-fs':
165 iArg += 1;
166 if iArg >= len(asArgs):
167 raise base.InvalidOption('The "--guest-fs" takes a colon separated list of filesystem identifiers');
168 self.asGuestFs = asArgs[iArg].split(':');
169 elif asArgs[iArg] == '--test-vms':
170 iArg += 1;
171 if iArg >= len(asArgs): raise base.InvalidOption('The "--test-vms" takes colon separated list');
172 self.asTestVMs = asArgs[iArg].split(':');
173 for s in self.asTestVMs:
174 if s not in self.asTestVMsDef:
175 raise base.InvalidOption('The "--test-vms" value "%s" is not valid; valid values are: %s' \
176 % (s, ' '.join(self.asTestVMsDef)));
177 elif asArgs[iArg] == '--skip-vms':
178 iArg += 1;
179 if iArg >= len(asArgs): raise base.InvalidOption('The "--skip-vms" takes colon separated list');
180 self.asSkipVMs = asArgs[iArg].split(':');
181 for s in self.asSkipVMs:
182 if s not in self.asTestVMsDef:
183 reporter.log('warning: The "--test-vms" value "%s" does not specify any of our test VMs.' % (s));
184 else:
185 return vbox.TestDriver.parseOption(self, asArgs, iArg);
186 return iArg + 1;
187
188 def completeOptions(self):
189 # Remove skipped VMs from the test list.
190 for sVM in self.asSkipVMs:
191 try: self.asTestVMs.remove(sVM);
192 except: pass;
193
194 return vbox.TestDriver.completeOptions(self);
195
196 def getResourceSet(self):
197 # Construct the resource list the first time it's queried.
198 if self.asRsrcs is None:
199 self.asRsrcs = [];
200 if 'tst-debian' in self.asTestVMs:
201 self.asRsrcs.append('4.2/storage/debian.vdi');
202
203 return self.asRsrcs;
204
205 def actionConfig(self):
206 # Some stupid trickery to guess the location of the iso. ## fixme - testsuite unzip ++
207 sVBoxValidationKit_iso = os.path.abspath(os.path.join(os.path.dirname(__file__),
208 '../../VBoxValidationKitStorIo.iso'));
209 if not os.path.isfile(sVBoxValidationKit_iso):
210 sVBoxValidationKit_iso = os.path.abspath(os.path.join(os.path.dirname(__file__),
211 '../../VBoxValidationKitStorIo.iso'));
212 if not os.path.isfile(sVBoxValidationKit_iso):
213 sVBoxValidationKit_iso = '/mnt/ramdisk/vbox/svn/trunk/validationkit/VBoxValidationKitStorIo.iso';
214 if not os.path.isfile(sVBoxValidationKit_iso):
215 sVBoxValidationKit_iso = '/mnt/ramdisk/vbox/svn/trunk/testsuite/VBoxTestSuiteStorIo.iso';
216 if not os.path.isfile(sVBoxValidationKit_iso):
217 sCur = os.getcwd();
218 for i in range(0, 10):
219 sVBoxValidationKit_iso = os.path.join(sCur, 'validationkit/VBoxValidationKitStorIo.iso');
220 if os.path.isfile(sVBoxValidationKit_iso):
221 break;
222 sVBoxValidationKit_iso = os.path.join(sCur, 'testsuite/VBoxTestSuiteStorIo.iso');
223 if os.path.isfile(sVBoxValidationKit_iso):
224 break;
225 sCur = os.path.abspath(os.path.join(sCur, '..'));
226 if i is None: pass; # shut up pychecker/pylint.
227 if not os.path.isfile(sVBoxValidationKit_iso):
228 sVBoxValidationKit_iso = '/mnt/VirtualBox/VBoxValidationKitStorIo.iso';
229 if not os.path.isfile(sVBoxValidationKit_iso):
230 sVBoxValidationKit_iso = '/mnt/VirtualBox/VBoxTestSuiteStorIo.iso';
231
232
233
234 # Make sure vboxapi has been imported so we can use the constants.
235 if not self.importVBoxApi():
236 return False;
237
238 #
239 # Configure the VMs we're going to use.
240 #
241
242 # Linux VMs
243 if 'tst-debian' in self.asTestVMs:
244 oVM = self.createTestVM('tst-debian', 1, '4.2/storage/debian.vdi', sKind = 'Debian_64', fIoApic = True, \
245 eNic0AttachType = vboxcon.NetworkAttachmentType_NAT, \
246 eNic0Type = vboxcon.NetworkAdapterType_Am79C973, \
247 sDvdImage = sVBoxValidationKit_iso);
248 if oVM is None:
249 return False;
250
251 return True;
252
253 def actionExecute(self):
254 """
255 Execute the testcase.
256 """
257 fRc = self.test1();
258 return fRc;
259
260
261 #
262 # Test execution helpers.
263 #
264
265 def test1RunTestProgs(self, oSession, oTxsSession, fRc, sTestName, sGuestFs):
266 """
267 Runs all the test programs on the test machine.
268 """
269 _ = oSession;
270
271 reporter.testStart(sTestName);
272
273 sMkfsCmd = 'mkfs.' + sGuestFs;
274
275 # Prepare test disks, just create filesystem without partition
276 reporter.testStart('Preparation');
277 fRc = fRc and self.txsRunTest(oTxsSession, 'Create FS 1', 60000, \
278 '/sbin/' + sMkfsCmd,
279 (sMkfsCmd, '/dev/sdb'));
280
281 fRc = fRc and self.txsRunTest(oTxsSession, 'Create FS 2', 60000, \
282 '/sbin/' + sMkfsCmd,
283 (sMkfsCmd, '/dev/sdc'));
284
285 # Create test and scratch directory
286 fRc = fRc and self.txsRunTest(oTxsSession, 'Create /mnt/test', 10000, \
287 '/bin/mkdir',
288 ('mkdir', '/mnt/test'));
289
290 fRc = fRc and self.txsRunTest(oTxsSession, 'Create /mnt/scratch', 10000, \
291 '/bin/mkdir',
292 ('mkdir', '/mnt/scratch'));
293
294 # Mount test and scratch directory.
295 fRc = fRc and self.txsRunTest(oTxsSession, 'Mount /mnt/test', 10000, \
296 '/bin/mount',
297 ('mount', '/dev/sdb','/mnt/test'));
298
299 fRc = fRc and self.txsRunTest(oTxsSession, 'Mount /mnt/scratch', 10000, \
300 '/bin/mount',
301 ('mount', '/dev/sdc','/mnt/scratch'));
302
303 fRc = fRc and self.txsRunTest(oTxsSession, 'Copying xfstests', 10000, \
304 '/bin/cp',
305 ('cp', '-r','${CDROM}/${OS.ARCH}/xfstests', '/tmp'));
306
307 reporter.testDone();
308
309 # Run xfstests (this sh + cd crap is required because the cwd for the script must be in the root
310 # of the xfstests directory...)
311 reporter.testStart('xfstests');
312 if fRc and 'xfstests' in self.asTests:
313 fRc = self.txsRunTest(oTxsSession, 'xfstests', 3600000,
314 '/bin/sh',
315 ('sh', '-c', '(cd /tmp/xfstests && ./check -g auto)'),
316 ('TEST_DIR=/mnt/test', 'TEST_DEV=/dev/sdb', 'SCRATCH_MNT=/mnt/scratch', 'SCRATCH_DEV=/dev/sdc',
317 'FSTYP=' + sGuestFs));
318 reporter.testDone();
319 else:
320 reporter.testDone(fSkipped = True);
321
322 reporter.testDone(not fRc);
323 return fRc;
324
325 # pylint: disable=too-many-arguments
326
327 def test1OneCfg(self, sVmName, eStorageController, sDiskFormat, sDiskPath1, sDiskPath2, \
328 sGuestFs, cCpus, fHwVirt, fNestedPaging):
329 """
330 Runs the specified VM thru test #1.
331
332 Returns a success indicator on the general test execution. This is not
333 the actual test result.
334 """
335 oVM = self.getVmByName(sVmName);
336
337 # Reconfigure the VM
338 fRc = True;
339 oSession = self.openSession(oVM);
340 if oSession is not None:
341 # Attach HD
342 fRc = oSession.ensureControllerAttached(self.controllerTypeToName(eStorageController));
343 fRc = fRc and oSession.setStorageControllerType(eStorageController, self.controllerTypeToName(eStorageController));
344
345 if sDiskFormat == "iSCSI":
346 listNames = [];
347 listValues = [];
348 listValues = sDiskPath1.split('|');
349 listNames.append('TargetAddress');
350 listNames.append('TargetName');
351 listNames.append('LUN');
352
353 if self.fpApiVer >= 5.0:
354 oHd = oSession.oVBox.createMedium(sDiskFormat, sDiskPath1, vboxcon.AccessMode_ReadWrite, \
355 vboxcon.DeviceType_HardDisk);
356 else:
357 oHd = oSession.oVBox.createHardDisk(sDiskFormat, sDiskPath1);
358 oHd.type = vboxcon.MediumType_Normal;
359 oHd.setProperties(listNames, listValues);
360
361 # Attach it.
362 if fRc is True:
363 try:
364 if oSession.fpApiVer >= 4.0:
365 oSession.o.machine.attachDevice(self.controllerTypeToName(eStorageController),
366 1, 0, vboxcon.DeviceType_HardDisk, oHd);
367 else:
368 oSession.o.machine.attachDevice(self.controllerTypeToName(eStorageController),
369 1, 0, vboxcon.DeviceType_HardDisk, oHd.id);
370 except:
371 reporter.errorXcpt('attachDevice("%s",%s,%s,HardDisk,"%s") failed on "%s"' \
372 % (self.controllerTypeToName(eStorageController), 1, 0, oHd.id, oSession.sName) );
373 fRc = False;
374 else:
375 reporter.log('attached "%s" to %s' % (sDiskPath1, oSession.sName));
376 else:
377 fRc = fRc and oSession.createAndAttachHd(sDiskPath1, sDiskFormat, self.controllerTypeToName(eStorageController),
378 cb = 10*1024*1024*1024, iPort = 1, fImmutable = False);
379 fRc = fRc and oSession.createAndAttachHd(sDiskPath2, sDiskFormat, self.controllerTypeToName(eStorageController),
380 cb = 10*1024*1024*1024, iPort = 2, fImmutable = False);
381 fRc = fRc and oSession.enableVirtExX86(fHwVirt);
382 fRc = fRc and oSession.enableNestedPagingX86(fNestedPaging);
383 fRc = fRc and oSession.setCpuCount(cCpus);
384 fRc = fRc and oSession.saveSettings();
385 fRc = oSession.close() and fRc and True; # pychecker hack.
386 oSession = None;
387 else:
388 fRc = False;
389
390 # Start up.
391 if fRc is True:
392 self.logVmInfo(oVM);
393 oSession, oTxsSession = self.startVmAndConnectToTxsViaTcp(sVmName, fCdWait = False, fNatForwardingForTxs = True);
394 if oSession is not None:
395 self.addTask(oTxsSession);
396
397 # Fudge factor - Allow the guest to finish starting up.
398 self.sleep(5);
399
400 fRc = self.test1RunTestProgs(oSession, oTxsSession, fRc, 'stress testing', sGuestFs);
401
402 # cleanup.
403 self.removeTask(oTxsSession);
404 self.terminateVmBySession(oSession)
405
406 # Remove disk
407 oSession = self.openSession(oVM);
408 if oSession is not None:
409 try:
410 oSession.o.machine.detachDevice(self.controllerTypeToName(eStorageController), 1, 0);
411 oSession.o.machine.detachDevice(self.controllerTypeToName(eStorageController), 2, 0);
412
413 # Remove storage controller if it is not an IDE controller.
414 if eStorageController not in (vboxcon.StorageControllerType_PIIX3, vboxcon.StorageControllerType_PIIX4,):
415 oSession.o.machine.removeStorageController(self.controllerTypeToName(eStorageController));
416
417 oSession.saveSettings();
418 oSession.oVBox.deleteHdByLocation(sDiskPath1);
419 oSession.oVBox.deleteHdByLocation(sDiskPath2);
420 oSession.saveSettings();
421 oSession.close();
422 oSession = None;
423 except:
424 reporter.errorXcpt('failed to detach/delete disks %s and %s from storage controller' % \
425 (sDiskPath1, sDiskPath2));
426 else:
427 fRc = False;
428 else:
429 fRc = False;
430 return fRc;
431
432 def test1OneVM(self, sVmName):
433 """
434 Runs one VM thru the various configurations.
435 """
436 reporter.testStart(sVmName);
437 fRc = True;
438 for sStorageCtrl in self.asStorageCtrls:
439 reporter.testStart(sStorageCtrl);
440
441 if sStorageCtrl == 'AHCI':
442 eStorageCtrl = vboxcon.StorageControllerType_IntelAhci;
443 elif sStorageCtrl == 'IDE':
444 eStorageCtrl = vboxcon.StorageControllerType_PIIX4;
445 elif sStorageCtrl == 'LsiLogicSAS':
446 eStorageCtrl = vboxcon.StorageControllerType_LsiLogicSas;
447 elif sStorageCtrl == 'LsiLogic':
448 eStorageCtrl = vboxcon.StorageControllerType_LsiLogic;
449 elif sStorageCtrl == 'BusLogic':
450 eStorageCtrl = vboxcon.StorageControllerType_BusLogic;
451 else:
452 eStorageCtrl = None;
453
454 for sDiskFormat in self.asDiskFormats:
455 reporter.testStart('%s' % (sDiskFormat,));
456
457 asPaths = self.asDirs;
458
459 for sDir in asPaths:
460 reporter.testStart('%s' % (sDir,));
461
462 sPathDisk1 = sDir + "/disk1.disk";
463 sPathDisk2 = sDir + "/disk2.disk";
464
465 for sGuestFs in self.asGuestFs:
466 reporter.testStart('%s' % (sGuestFs,));
467
468 for cCpus in self.acCpus:
469 if cCpus == 1: reporter.testStart('1 cpu');
470 else: reporter.testStart('%u cpus' % (cCpus,));
471
472 for sVirtMode in self.asVirtModes:
473 if sVirtMode == 'raw' and cCpus > 1:
474 continue;
475 hsVirtModeDesc = {};
476 hsVirtModeDesc['raw'] = 'Raw-mode';
477 hsVirtModeDesc['hwvirt'] = 'HwVirt';
478 hsVirtModeDesc['hwvirt-np'] = 'NestedPaging';
479 reporter.testStart(hsVirtModeDesc[sVirtMode]);
480
481 fHwVirt = sVirtMode != 'raw';
482 fNestedPaging = sVirtMode == 'hwvirt-np';
483 fRc = self.test1OneCfg(sVmName, eStorageCtrl, sDiskFormat, sPathDisk1, sPathDisk2, \
484 sGuestFs, cCpus, fHwVirt, fNestedPaging) and fRc and True;
485 reporter.testDone();
486 reporter.testDone();
487 reporter.testDone();
488 reporter.testDone();
489 reporter.testDone();
490 reporter.testDone();
491 reporter.testDone();
492 return fRc;
493
494 def test1(self):
495 """
496 Executes test #1.
497 """
498
499 # Loop thru the test VMs.
500 for sVM in self.asTestVMs:
501 # run test on the VM.
502 if not self.test1OneVM(sVM):
503 fRc = False;
504 else:
505 fRc = True;
506
507 return fRc;
508
509
510
511if __name__ == '__main__':
512 sys.exit(tdStorageStress().main(sys.argv));
513
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