Adam Litke has uploaded a new change for review.
Change subject: tests: Add initial FakeLVM tests and fix errors ......................................................................
tests: Add initial FakeLVM tests and fix errors
The FakeLVM class inside storagefakelib.py is becoming increasingly complex. In order to ensure that FakeLVM is providing correct LVM emulation we need to test its output against what a real LVM environment would present.
This first patch introduces the new test module and adds some tests for createVG and getVG. We test that the VG properties and attributes returned match a real LVM installation. After writing these tests I found and fixed several errors in the existing FakeLVM implementation.
Change-Id: I1650b98f25df1a22ba2a0920b093e78fc2fdee88 Signed-off-by: Adam Litke alitke@redhat.com --- M tests/Makefile.am M tests/storagefakelib.py A tests/storagefakelibTests.py 3 files changed, 161 insertions(+), 16 deletions(-)
git pull ssh://gerrit.ovirt.org:29418/vdsm refs/changes/57/47857/1
diff --git a/tests/Makefile.am b/tests/Makefile.am index 1168862..e8b9d6e 100644 --- a/tests/Makefile.am +++ b/tests/Makefile.am @@ -102,6 +102,7 @@ stompAdapterTests.py \ stompAsyncClientTests.py \ stompTests.py \ + storagefakelibTests.py \ storageMailboxTests.py \ storageMonitorTests.py \ storageServerTests.py \ diff --git a/tests/storagefakelib.py b/tests/storagefakelib.py index 11954d5..a60aaf5 100644 --- a/tests/storagefakelib.py +++ b/tests/storagefakelib.py @@ -26,19 +26,29 @@
class FakeLVM(object): - _PV_SIZE = 10 << 30 # We pretend all PVs contribute 10G of space - + _PV_SIZE = 10 << 30 # We pretend all PVs are 10G in size + _PV_PE_SIZE = 128 << 20 # Found via inspection of real environment + _PV_MDA_COUNT = 2 # The number of PEs used for metadata areas + _PV_UNUSABLE = (_PV_PE_SIZE * # 2 PE for metadata + 1 PE to hold a header + (1 + _PV_MDA_COUNT)) def __init__(self, root): self.root = root os.mkdir(os.path.join(self.root, 'dev')) + self.pvmd = {} self.vgmd = {} self.lvmd = {}
def createVG(self, vgName, devices, initialTag, metadataSize, - extentsize=134217728, force=False): - devices = [_fqpvname(dev) for dev in devices] - size = self._PV_SIZE * len(devices) - extent_count = size / extentsize + extentsize=128, force=False): + # Convert params from MB to bytes to match other fields + metadataSize <<= 20 + extentsize <<= 20 + + for dev in devices: + self._create_pv(dev, vgName, self._PV_SIZE) + pv_name = tuple([_fqpvname(pdev) for pdev in _normalizeargs(devices)]) + extent_count = self._calc_vg_pe_count(vgName) + size = extent_count * self._PV_PE_SIZE
vg_attr = dict(permission='w', resizeable='z', @@ -49,17 +59,17 @@ vg_md = dict(uuid=fake_lvm_uuid(), name=vgName, attr=vg_attr, - size=size, - free=size, - extent_size=extentsize, - extent_count=extent_count, - free_count=extent_count, - tags=[initialTag], - vg_mda_size=metadataSize, - vg_mda_free=metadataSize, + size=str(size), + free=str(size), + extent_size=str(extentsize), + extent_count=str(extent_count), + free_count=str(extent_count), + tags=(initialTag,), + vg_mda_size=str(metadataSize), + vg_mda_free=None, lv_count='0', - pv_count=len(devices), - pv_name=tuple(devices), + pv_count=str(len(devices)), + pv_name=pv_name, writeable=True, partial='OK') self.vgmd[vgName] = vg_md @@ -123,7 +133,31 @@ with open(volpath, "w") as f: f.truncate(int(self.lvmd[vg_name][lv_name]['size']))
+ def _create_pv(self, pv_name, vg_name, size): + # pe_start is difficult to calculate correctly but since it's not + # currently needed by users of FakeLVM, set it to None. + pe_start = None + pe_count = (size - self._PV_UNUSABLE) / self._PV_PE_SIZE + pv_md = dict(uuid=fake_lvm_uuid(), + name='/dev/mapper/%s' % pv_name, + guid=pv_name, + size=str(pe_count * self._PV_PE_SIZE), + vg_name=vg_name, + vg_uuid=None, # This is calculated dynamically + pe_start=pe_start, + pe_count=str(pe_count), + pe_alloc_count='0', + mda_count=str(self._PV_MDA_COUNT), + dev_size=str(self._PV_SIZE)) + self.pvmd[pv_name] = pv_md + + def _calc_vg_pe_count(self, vg_name): + return sum(int(pv["pe_count"]) for pv in self.pvmd.values() + if pv["vg_name"] == vg_name) + + _fqpvname = real_lvm._fqpvname +_normalizeargs = real_lvm._normalizeargs
def fake_lvm_uuid(): diff --git a/tests/storagefakelibTests.py b/tests/storagefakelibTests.py new file mode 100644 index 0000000..8c73a54 --- /dev/null +++ b/tests/storagefakelibTests.py @@ -0,0 +1,110 @@ +# Copyright 2015 Red Hat, Inc. +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +# +# Refer to the README and COPYING files for full details of the license +# + +from contextlib import contextmanager + +from testlib import VdsmTestCase, namedTemporaryDir +from testlib import permutations, expandPermutations +from storagefakelib import FakeLVM + +from storage import blockSD + + +@expandPermutations +class FakeLVMSimpleVGTests(VdsmTestCase): + VG_NAME = '1ffead52-7363-4968-a8c7-3bc34504d452' + DEVICES = ['360014054d75cb132d474c0eae9825766'] + + @contextmanager + def base_config(self): + """ + Create a simple volume group from a single 10G LUN. + + lvm.createVG('1ffead52-7363-4968-a8c7-3bc34504d452', + ['360014054d75cb132d474c0eae9825766'], + blockSD.STORAGE_UNREADY_DOMAIN_TAG, + blockSD.VG_METADATASIZE) + + print lvm.getVG('1ffead52-7363-4968-a8c7-3bc34504d452') + VG(uuid='15hlPF-V3eG-F9Cp-SGtu-4Mq0-28Do-HC806y', + name='1ffead52-7363-4968-a8c7-3bc34504d452', + attr=VG_ATTR(permission='w', resizeable='z', exported='-', + partial='-', allocation='n', clustered='-'), + size='10334765056', free='10334765056', extent_size='134217728', + extent_count='77', free_count='77', + tags=('RHAT_storage_domain_UNREADY',), vg_mda_size='134217728', + vg_mda_free='67107328', lv_count='0', pv_count='1', + pv_name=('/dev/mapper/360014054d75cb132d474c0eae9825766',), + writeable=True, partial='OK') + + print lvm.getPV('360014054d75cb132d474c0eae9825766') + PV(uuid='fIRjbD-usOA-tYgW-b2Uz-oUly-AJ49-bMMjYe', + name='/dev/mapper/360014054d75cb132d474c0eae9825766', + size='10334765056', vg_name='1ffead52-7363-4968-a8c7-3bc34504d452', + vg_uuid='15hlPF-V3eG-F9Cp-SGtu-4Mq0-28Do-HC806y', + pe_start='138412032', pe_count='77', pe_alloc_count='0', + mda_count='2', dev_size='10737418240', + guid='360014054d75cb132d474c0eae9825766') + """ + with namedTemporaryDir() as tmpdir: + lvm = FakeLVM(tmpdir) + lvm.createVG(self.VG_NAME, self.DEVICES, + blockSD.STORAGE_UNREADY_DOMAIN_TAG, + blockSD.VG_METADATASIZE) + yield lvm + + @permutations([ + ['name', VG_NAME], + ['size', '10334765056'], + ['free', '10334765056'], + ['extent_size', '134217728'], + ['extent_count', '77'], + ['free_count', '77'], + ['tags', (blockSD.STORAGE_UNREADY_DOMAIN_TAG,)], + ['vg_mda_size', '134217728'], + ['lv_count', '0'], + ['pv_count', '1'], + ['writeable', True], + ['partial', 'OK'], + ['pv_name', tuple(['/dev/mapper/%s' % d for d in DEVICES])], + ]) + def test_vg_properties(self, var, val): + with self.base_config() as lvm: + vg = lvm.getVG(self.VG_NAME) + self.assertEqual(val, getattr(vg, var)) + + @permutations([ + ['permission', 'w'], + ['resizeable', 'z'], + ['exported', '-'], + ['partial', '-'], + ['allocation', 'n'], + ['clustered', '-'], + ]) + def test_vg_attributes(self, var, val): + with self.base_config() as lvm: + vg = lvm.getVG(self.VG_NAME) + self.assertEqual(val, getattr(vg.attr, var)) + + def test_vg_mda_free(self): + # It is too complex to emulate vg_mda_free and at this point we do not + # rely on this value. For this reason, FakeLVM sets it to None. + with self.base_config() as lvm: + vg = lvm.getVG(self.VG_NAME) + self.assertEqual(None, vg.vg_mda_free)