summaryrefslogtreecommitdiff
path: root/test
diff options
context:
space:
mode:
authorLee Duncan <lduncan@suse.com>2020-02-19 15:39:13 -0800
committerLee Duncan <lduncan@suse.com>2020-02-19 15:39:13 -0800
commit8293415f4b0e32348d4ba183b5877d304efc0632 (patch)
tree2ae0b58476ba5455115bb00eaf5c39e60e20f118 /test
parentf66c504430a6c568bf90a5cdf2a64eb995b557de (diff)
downloadopen-iscsi-8293415f4b0e32348d4ba183b5877d304efc0632.tar.gz
First 32 tests working?
At least they are coded.
Diffstat (limited to 'test')
-rw-r--r--test/TODO5
-rw-r--r--test/harness/iscsi.py16
-rw-r--r--test/harness/util.py121
-rwxr-xr-xtest/test-open-iscsi.py76
4 files changed, 148 insertions, 70 deletions
diff --git a/test/TODO b/test/TODO
index ce98f4e..830e7f2 100644
--- a/test/TODO
+++ b/test/TODO
@@ -17,3 +17,8 @@
- discovery, with and without authentication
- session creation, w/ & w/o auth
- etc
+
+* Gather actual regression data!
+ - Since we are testing all of these combinations, why not
+ keep historical data to see if there are any negative
+ trends (i.e. regressions)?
diff --git a/test/harness/iscsi.py b/test/harness/iscsi.py
index 569a66e..a252d7a 100644
--- a/test/harness/iscsi.py
+++ b/test/harness/iscsi.py
@@ -53,11 +53,11 @@ class IscsiData:
print('* MaxRecvDataSegmentLength = %d' % self.max_recv_dlength)
print('* MaxOutstandingR2T = %d' % self.max_r2t)
c = ['iscsiadm', '-m', 'node', '-T', target, '-p', ipnr, '-o', 'update']
- run_cmd(c + ['-n', 'node.session.iscsi.ImmediateData', '-v', self.imm_data_en], quiet_mode=True)
- run_cmd(c + ['-n', 'node.session.iscsi.InitialR2T', '-v', self.initial_r2t_en], quiet_mode=True)
- run_cmd(c + ['-n', 'node.conn[0].iscsi.HeaderDigest', '-v', self.hdrdgst_en], quiet_mode=True)
- run_cmd(c + ['-n', 'node.conn[0].iscsi.DataDigest', '-v', self.datdgst_en], quiet_mode=True)
- run_cmd(c + ['-n', 'node.session.iscsi.FirstBurstLength', '-v', str(self.first_burst)], quiet_mode=True)
- run_cmd(c + ['-n', 'node.session.iscsi.MaxBurstLength', '-v', str(self.max_burst)], quiet_mode=True)
- run_cmd(c + ['-n', 'node.conn[0].iscsi.MaxRecvDataSegmentLength', '-v', str(self.max_recv_dlength)], quiet_mode=True)
- run_cmd(c + ['-n', 'node.session.iscsi.MaxOutstandingR2T', '-v', str(self.max_r2t)], quiet_mode=True)
+ run_cmd(c + ['-n', 'node.session.iscsi.ImmediateData', '-v', self.imm_data_en])
+ run_cmd(c + ['-n', 'node.session.iscsi.InitialR2T', '-v', self.initial_r2t_en])
+ run_cmd(c + ['-n', 'node.conn[0].iscsi.HeaderDigest', '-v', self.hdrdgst_en])
+ run_cmd(c + ['-n', 'node.conn[0].iscsi.DataDigest', '-v', self.datdgst_en])
+ run_cmd(c + ['-n', 'node.session.iscsi.FirstBurstLength', '-v', str(self.first_burst)])
+ run_cmd(c + ['-n', 'node.session.iscsi.MaxBurstLength', '-v', str(self.max_burst)])
+ run_cmd(c + ['-n', 'node.conn[0].iscsi.MaxRecvDataSegmentLength', '-v', str(self.max_recv_dlength)])
+ run_cmd(c + ['-n', 'node.session.iscsi.MaxOutstandingR2T', '-v', str(self.max_r2t)])
diff --git a/test/harness/util.py b/test/harness/util.py
index 3d21480..8c310ed 100644
--- a/test/harness/util.py
+++ b/test/harness/util.py
@@ -6,18 +6,23 @@ import os
import shutil
import sys
import unittest
+import time
+import tempfile
#
# globals
#
class Global:
- _FSTYPE = os.getenv('FSTYPE', 'ext3')
- _MOUNTOPTIONS = os.getenv('MOUNTOPTIONS', '').split(' ') + [' -t ', _FSTYPE]
- _MKFSCMD = [os.getenv('MKFSCMD', 'mkfs.' + _FSTYPE)]
+ FSTYPE = os.getenv('FSTYPE', 'ext3')
+ if os.getenv('MOUNTOPTIONS'):
+ MOUNTOPTIONS = os.getenv('MOUNTOPTIONS').split(' ')
+ else:
+ MOUNTOPTIONS = []
+ MOUNTOPTIONS += ['-t', FSTYPE]
+ MKFSCMD = [os.getenv('MKFSCMD', 'mkfs.' + FSTYPE)]
if os.getenv('MKFSOPTS'):
- _MKFSCMD += os.getenv('MKFSOPTS').split(' ')
- _PARTITIONSUFFIX = '1'
- _BONNIEPARAMS = os.getenv('BONNIEPARAMS', '--r0 -n10:0:0 -s16 -uroot -f -q').split(' ')
+ MKFSCMD += os.getenv('MKFSOPTS').split(' ')
+ BONNIEPARAMS = os.getenv('BONNIEPARAMS', '-r0 -n10:0:0 -s16 -uroot -f -q').split(' ')
verbosity = 1
debug = False
# the target (e.g. "iqn.*")
@@ -51,31 +56,22 @@ def vprint(*args):
print(arg, end='')
print('')
-def notice(*args):
- """
- Print if not in quiet mode
- """
- if Global.verbosity > 0:
- for arg in args:
- print(arg, end='')
- print('')
-
-def run_cmd(cmd, output_save_file=None, quiet_mode=False):
+def run_cmd(cmd, output_save_file=None):
"""
run specified command, waiting for and returning result
"""
- if (Global.verbosity > 1 and not quiet_mode) or Global.debug:
+ if Global.debug:
cmd_str = ' '.join(cmd)
if output_save_file:
cmd_str += ' >& %s' % output_save_file
- vprint(cmd_str)
+ dprint(cmd_str)
pid = os.fork()
if pid < 0:
print("Error: cannot fork!", flie=sys.stderr)
sys.exit(1)
if pid == 0:
# the child
- if output_save_file or quiet_mode:
+ if output_save_file or not Global.debug:
stdout_fileno = sys.stdout.fileno()
stderr_fileno = sys.stderr.fileno()
if output_save_file:
@@ -87,6 +83,7 @@ def run_cmd(cmd, output_save_file=None, quiet_mode=False):
os.dup2(new_stdout, stderr_fileno)
os.execvp(cmd[0], cmd)
# not reached
+ sys.exit(1)
# the parent
wpid, wstat = os.waitpid(pid, 0)
@@ -163,6 +160,7 @@ def verify_needed_commands_exist(cmd_list):
Verify that the commands in the supplied list are in our path
"""
path_list = os.getenv('PATH').split(':')
+ any_cmd_not_found = False
for cmd in cmd_list:
found = False
for a_path in path_list:
@@ -171,7 +169,9 @@ def verify_needed_commands_exist(cmd_list):
break
if not found:
print('Error: %s must be in your PATH' % cmd)
- sys.exit(1)
+ any_cmd_not_found = True
+ if any_cmd_not_found:
+ sys.exit(1)
def run_fio():
@@ -192,26 +192,46 @@ def run_fio():
'16k', '32k', '75536', '128k', '1000000']
# for each block size, do a read test, then a write test
for bs in blocksizes:
- vprint('Running "fio" read test: 2 seconds, 8 threads, bs=%s' % bs)
+ vprint('Running "fio" read test: 8 threads, bs=%s' % bs)
+ # only support direct IO with aligned reads
+ if bs.endswith('k'):
+ direct=1
+ else:
+ direct=0
res = run_cmd(['fio', '--name=read-test', '--readwrite=randread',
'--runtime=2s', '--numjobs=8', '--blocksize=%s' % bs,
- '--direct=1', '--filename=%s' % Global.device], quiet_mode=True)
+ '--direct=%d' % direct, '--filename=%s' % Global.device])
if res != 0:
return (res, 'fio failed')
- vprint('Running "fio" write test: 2 seconds, 8 threads, bs=%s' % bs)
+ vprint('Running "fio" write test: 8 threads, bs=%s' % bs)
res = run_cmd(['fio', '--name=write-test', '--readwrite=randwrite',
'--runtime=2s', '--numjobs=8', '--blocksize=%s' % bs,
- '--direct=1', '--filename=%s' % Global.device], quiet_mode=True)
+ '--direct=%d' % direct, '--filename=%s' % Global.device])
if res != 0:
return (res, 'fio failed')
- vprint('Running "fio" verify test: 2 seconds, 8 threads, bs=%s' % bs)
+ vprint('Running "fio" verify test: 1 thread, bs=%s' % bs)
res = run_cmd(['fio', '--name=verify-test', '--readwrite=randwrite',
'--runtime=2s', '--numjobs=1', '--blocksize=%s' % bs,
- '--direct=1', '--filename=%s' % Global.device,
- '--verify=md5', '--verify_state_save=0'], quiet_mode=True)
+ '--direct=%d' % direct, '--filename=%s' % Global.device,
+ '--verify=md5', '--verify_state_save=0'])
if res != 0:
return (res, 'fio failed')
- return (0, None)
+ return (0, 'Success')
+
+def wait_for_path(path, present=True):
+ """Wait until a path exists or is gone"""
+ dprint("Looking for path=%s, present=%s" % (path, present))
+ for i in range(10):
+ if os.path.exists(path) == present:
+ dprint("Found path!")
+ break
+ time.sleep(1)
+ if os.path.exists(path) != present:
+ dprint("Did NOT find path!")
+ return False
+ dprint("%s: present=%d after %d second(s)" % \
+ (path, present, i))
+ return True
def run_parted():
"""
@@ -224,34 +244,47 @@ def run_parted():
Uses Globals: device, partition
"""
# zero out the label and parition table
- res = run_cmd(['dd', 'if=/dev/zero', 'of=%s' % Global.device, 'bs=4k', 'count=100'],
- quiet_mode=True)
+ res = run_cmd(['dd', 'if=/dev/zero', 'of=%s' % Global.device, 'bs=4k', 'count=100'])
if res != 0:
return (res, '%s: could not zero out label' % Global.device)
# ensure our partition file is not there, to be safe
- if os.path.exists(Global.partition):
+ if not wait_for_path(Global.partition, present=False):
return (1, '%s: Partition already exists?' % Global.partition)
# make a label, then a partition table with one partition
- res = run_cmd(['parted', Global.device, 'mklabel', 'gpt'], quiet_mode=True)
+ vprint('Running "parted" to create a label and partition table')
+ res = run_cmd(['parted', Global.device, 'mklabel', 'gpt'])
if res != 0:
return (res, '%s: Could not create a GPT label' % Global.device)
- res = run_cmd(['parted', '-a', 'none', Global.device, 'mkpart', 'primary', '0', '100%'],
- quiet_mode=True)
+ res = run_cmd(['parted', '-a', 'none', Global.device, 'mkpart', 'primary', '0', '100%'])
if res != 0:
return (res, '%s: Could not create a primary partition' % Global.device)
# wait for the partition to show up
- for i in range(10):
- if os.path.exists(Global.partition):
- break
- os.sleep(1)
- if not os.path.exists(Global.partition):
+ if not wait_for_path(Global.partition):
return (1, '%s: Partition never showed up?' % Global.partition)
- return (0, None)
+ # success
+ return (0, 'Success')
def run_mkfs():
- #return (1, "Not Yet Implemented: mkfs")
- return (0, None)
+ vprint('Running "mkfs" to to create filesystem')
+ res = run_cmd(Global.MKFSCMD + [ Global.partition ] )
+ if res != 0:
+ return (res, '%s: mkfs failed (%d)' % (Global.partition, res))
+ return (0, 'Success')
def run_bonnie():
- #return (1, "Not Yet Implemented: bonnie")
- return (0, None)
+ # make a temp dir and mount the device there
+ with tempfile.TemporaryDirectory() as tmp_dir:
+ vprint('Mounting the filesystem')
+ res = run_cmd(['mount'] + Global.MOUNTOPTIONS + [Global.partition, tmp_dir])
+ if res != 0:
+ return (res, '%s: mount failed (%d)' % (Global.partition, res))
+ # run bonnie++ on the new directory
+ vprint('Running "bonnie++" on the filesystem')
+ res = run_cmd(['bonnie++'] + Global.BONNIEPARAMS + ['-d', tmp_dir])
+ if res != 0:
+ return (res, '%s: umount failed (%d)' % (tmp_dir, res))
+ # unmount the device and remove the temp dir
+ res = run_cmd(['umount', tmp_dir])
+ if res != 0:
+ return (res, '%s: umount failed (%d)' % (tmp_dir, res))
+ return (0, 'Success')
diff --git a/test/test-open-iscsi.py b/test/test-open-iscsi.py
index 8d5bdeb..7c06c59 100755
--- a/test/test-open-iscsi.py
+++ b/test/test-open-iscsi.py
@@ -6,6 +6,7 @@ Unit tests for open-iscsi, using the unittest built-in package
import sys
import unittest
import os
+import time
from harness import util
from harness.util import Global
from harness.iscsi import IscsiData
@@ -18,35 +19,72 @@ class TestRegression(unittest.TestCase):
@classmethod
def setUpClass(cls):
+ util.verify_needed_commands_exist(['parted', 'fio', 'mkfs', 'bonnie++', 'dd', 'iscsiadm'])
util.vprint('*** Starting %s' % cls.__name__)
# XXX validate that target exists?
- cls.first_burst_values = [4096, 8192, 16384, 32768, 65536, 131972]
- cls.max_burst_values = [4096, 8192, 16384, 32768, 65536, 131072]
- cls.max_recv_values = [4096, 8192, 16384, 32768, 65536, 131072]
+ # an array of first burts, max burst, and max recv values, for testing
+ cls.param_values = [[4096, 4096, 4096],
+ [8192, 4096, 4096],
+ [16384, 4096, 4096],
+ [32768, 4096, 4096],
+ [65536, 4096, 4096],
+ [131972, 4096, 4096],
+ [4096, 8192, 4096],
+ [4096, 16384, 4096],
+ [4096, 32768, 4096],
+ [4096, 65536, 4096],
+ [4096, 131072, 4096],
+ [4096, 4096, 8192],
+ [4096, 4096, 16384],
+ [4096, 4096, 32768],
+ [4096, 4096, 65536],
+ [4096, 4096, 131072]]
def setUp(self):
if Global.debug or Global.verbosity > 1:
# this makes debug printing a little more clean
print('', file=sys.stderr)
- res = util.run_cmd(['iscsiadm', '-m', 'node', '-T', Global.target, '-p', Global.ipnr, '--logout'], quiet_mode=True)
+
+ def iscsi_logout(self):
+ res = util.run_cmd(['iscsiadm', '-m', 'node',
+ '-T', Global.target,
+ '-p', Global.ipnr,
+ '--logout'])
if res not in [0, 21]:
self.fail('logout failed')
self.assertFalse(os.path.exists(Global.device), '%s: exists after logout!' % Global.device)
- def test_immediate_data(self):
- """
- Test No Immediate Data but Initial Request to Transmit
- """
- iscsi_data = IscsiData('No', 'Yes', 'None', 'None', 4096, 4096, 4096)
- iscsi_data.update_cfg(Global.target, Global.ipnr)
- res = util.run_cmd(['iscsiadm', '-m', 'node', '-T', Global.target, '-p', Global.ipnr, '--login'], quiet_mode=True)
+ def test_InitialR2T(self):
+ """Test Initial Request to Transmit set, but no Immediate Data"""
+ i = 1
+ for v in self.param_values:
+ with self.subTest('Testing FirstBurst={} MaxBurts={} MaxRecv={}'.format(*v), i=i):
+ self.iscsi_logout()
+ iscsi_data = IscsiData('No', 'Yes', 'None', 'None', v[0], v[1], v[2])
+ iscsi_data.update_cfg(Global.target, Global.ipnr)
+ self.run_the_rest()
+ i += 1
+
+ def test_ImmediateData(self):
+ """Test Initial Request to Transmit set, but no Immediate Data"""
+ i = 1
+ for v in self.param_values:
+ with self.subTest('Testing FirstBurst={} MaxBurts={} MaxRecv={}'.format(*v), i=i):
+ self.iscsi_logout()
+ iscsi_data = IscsiData('Yes', 'No', 'None', 'None', v[0], v[1], v[2])
+ iscsi_data.update_cfg(Global.target, Global.ipnr)
+ self.run_the_rest()
+ i += 1
+
+ def run_the_rest(self):
+ res = util.run_cmd(['iscsiadm', '-m', 'node',
+ '-T', Global.target,
+ '-p', Global.ipnr,
+ '--login'])
self.assertEqual(res, 0, 'cannot login to device')
# wait a few seconds for the device to show up
- for i in range(10):
- if os.path.exists(Global.device):
- break
- os.sleep(1)
- self.assertTrue(os.path.exists(Global.device), '%s: does not exist after login' % Global.device)
+ if not util.wait_for_path(Global.device):
+ self.fail('%s: does not exist after login' % Global.device)
(res, reason) = util.run_fio()
self.assertEqual(res, 0, reason)
(res, reason) = util.run_parted()
@@ -62,11 +100,13 @@ class TestRegression(unittest.TestCase):
iscsi_data = IscsiData()
iscsi_data.update_cfg(Global.target, Global.ipnr)
# log out of iscsi connection
- util.run_cmd(['iscsiadm', '-m', 'node', '-T', Global.target, '-p', Global.ipnr, '--logout'], quiet_mode=True)
+ util.run_cmd(['iscsiadm', '-m', 'node',
+ '-T', Global.target,
+ '-p', Global.ipnr,
+ '--logout'])
if __name__ == '__main__':
- util.verify_needed_commands_exist(['parted', 'fio', 'mkfs', 'bonnie++', 'dd', 'iscsiadm'])
# do our own hackery first, to get access to verbosity, debug, etc,
# as well as add our own command-line options
util.setup_testProgram_overrides()