Add more funtional tests
This patch adds 4 new functional tests: - Stats proper update after volume creation - Extend volume operation - Volume cloning - Creating a volume from snapshot It also improves the create volume tests to check the size of the newly created volume.
This commit is contained in:
		@@ -132,45 +132,63 @@ the location of our configuration file via environmental variable
 | 
			
		||||
 | 
			
		||||
   $ CL_FTEST_CFG=temp/tests.yaml tox -efunctional
 | 
			
		||||
 | 
			
		||||
   functional develop-inst-nodeps: /home/geguileo/code/cinderlib
 | 
			
		||||
   functional installed: You are using pip version 8.1.2, ...
 | 
			
		||||
   functional runtests: PYTHONHASHSEED='2093635202'
 | 
			
		||||
   functional runtests: commands[0] | unit2 discover -v -s tests/functional
 | 
			
		||||
   test_attach_detach_volume_on_kaminario (tests_basic.BackendFunctBasic) ... ok
 | 
			
		||||
   test_attach_detach_volume_on_lvm (tests_basic.BackendFunctBasic) ... ok
 | 
			
		||||
   test_attach_detach_volume_on_xtremio (tests_basic.BackendFunctBasic) ... ok
 | 
			
		||||
   test_stats_on_kaminario (tests_basic.BackendFunctBasic) ... ok
 | 
			
		||||
   test_stats_on_lvm (tests_basic.BackendFunctBasic) ... ok
 | 
			
		||||
   test_stats_on_xtremio (tests_basic.BackendFunctBasic) ... ok
 | 
			
		||||
   test_create_volume_on_kaminario (tests_basic.BackendFunctBasic) ... ok
 | 
			
		||||
   test_create_volume_on_lvm (tests_basic.BackendFunctBasic) ... ok
 | 
			
		||||
   test_create_volume_on_xtremio (tests_basic.BackendFunctBasic) ... ok
 | 
			
		||||
   test_attach_detach_volume_via_attachment_on_kaminario (tests_basic.BackendFunctBasic) ... ok
 | 
			
		||||
   test_attach_detach_volume_via_attachment_on_lvm (tests_basic.BackendFunctBasic) ... ok
 | 
			
		||||
   test_attach_detach_volume_via_attachment_on_xtremio (tests_basic.BackendFunctBasic) ... ok
 | 
			
		||||
   test_attach_volume_on_kaminario (tests_basic.BackendFunctBasic) ... ok
 | 
			
		||||
   test_attach_volume_on_lvm (tests_basic.BackendFunctBasic) ... ok
 | 
			
		||||
   test_attach_volume_on_xtremio (tests_basic.BackendFunctBasic) ... ok
 | 
			
		||||
   test_clone_on_kaminario (tests_basic.BackendFunctBasic) ... ok
 | 
			
		||||
   test_clone_on_lvm (tests_basic.BackendFunctBasic) ... ok
 | 
			
		||||
   test_clone_on_xtremio (tests_basic.BackendFunctBasic) ... ok
 | 
			
		||||
   test_connect_disconnect_multiple_times_on_kaminario (tests_basic.BackendFunctBasic) ... ok
 | 
			
		||||
   test_connect_disconnect_multiple_times_on_lvm (tests_basic.BackendFunctBasic) ... ok
 | 
			
		||||
   test_connect_disconnect_multiple_times_on_xtremio (tests_basic.BackendFunctBasic) ... ok
 | 
			
		||||
   test_connect_disconnect_multiple_volumes_on_kaminario (tests_basic.BackendFunctBasic) ... ok
 | 
			
		||||
   test_connect_disconnect_multiple_volumes_on_lvm (tests_basic.BackendFunctBasic) ... ok
 | 
			
		||||
   test_connect_disconnect_multiple_volumes_on_xtremio (tests_basic.BackendFunctBasic) ... ok
 | 
			
		||||
   test_connect_disconnect_volume_on_kaminario (tests_basic.BackendFunctBasic) ... ok
 | 
			
		||||
   test_connect_disconnect_volume_on_lvm (tests_basic.BackendFunctBasic) ... ok
 | 
			
		||||
   test_connect_disconnect_volume_on_xtremio (tests_basic.BackendFunctBasic) ... ok
 | 
			
		||||
   test_create_delete_snapshot_on_kaminario (tests_basic.BackendFunctBasic) ... ok
 | 
			
		||||
   test_create_delete_snapshot_on_lvm (tests_basic.BackendFunctBasic) ... ok
 | 
			
		||||
   test_create_delete_snapshot_on_xtremio (tests_basic.BackendFunctBasic) ... ok
 | 
			
		||||
   test_create_delete_volume_on_kaminario (tests_basic.BackendFunctBasic) ... ok
 | 
			
		||||
   test_create_delete_volume_on_lvm (tests_basic.BackendFunctBasic) ... ok
 | 
			
		||||
   test_create_delete_volume_on_xtremio (tests_basic.BackendFunctBasic) ... ok
 | 
			
		||||
   test_create_snapshot_on_kaminario (tests_basic.BackendFunctBasic) ... ok
 | 
			
		||||
   test_create_snapshot_on_lvm (tests_basic.BackendFunctBasic) ... ok
 | 
			
		||||
   test_create_snapshot_on_xtremio (tests_basic.BackendFunctBasic) ... ok
 | 
			
		||||
   test_create_delete_snapshot_on_kaminario (tests_basic.BackendFunctBasic) ... ok
 | 
			
		||||
   test_create_delete_snapshot_on_lvm (tests_basic.BackendFunctBasic) ... ok
 | 
			
		||||
   test_create_delete_snapshot_on_xtremio (tests_basic.BackendFunctBasic) ... ok
 | 
			
		||||
   test_attach_volume_on_kaminario (tests_basic.BackendFunctBasic) ... ok
 | 
			
		||||
   test_attach_volume_on_lvm (tests_basic.BackendFunctBasic) ... ok
 | 
			
		||||
   test_attach_volume_on_xtremio (tests_basic.BackendFunctBasic) ... ok
 | 
			
		||||
   test_attach_detach_volume_via_attachment_on_kaminario (tests_basic.BackendFunctBasic) ... ok
 | 
			
		||||
   test_attach_detach_volume_via_attachment_on_lvm (tests_basic.BackendFunctBasic) ... ok
 | 
			
		||||
   test_attach_detach_volume_via_attachment_on_xtremio (tests_basic.BackendFunctBasic) ... ok
 | 
			
		||||
   test_disk_io_kaminario (tests_basic.BackendFunctBasic) ... ok
 | 
			
		||||
   test_disk_io_lvm (tests_basic.BackendFunctBasic) ... ok
 | 
			
		||||
   test_disk_io_xtremio (tests_basic.BackendFunctBasic) ... ok
 | 
			
		||||
   test_connect_disconnect_volume_on_kaminario (tests_basic.BackendFunctBasic) ... ok
 | 
			
		||||
   test_connect_disconnect_volume_on_lvm (tests_basic.BackendFunctBasic) ... ok
 | 
			
		||||
   test_connect_disconnect_volume_on_xtremio (tests_basic.BackendFunctBasic) ... ok
 | 
			
		||||
   test_connect_disconnect_multiple_volumes_on_kaminario (tests_basic.BackendFunctBasic) ... ok
 | 
			
		||||
   test_connect_disconnect_multiple_volumes_on_lvm (tests_basic.BackendFunctBasic) ... ok
 | 
			
		||||
   test_connect_disconnect_multiple_volumes_on_xtremio (tests_basic.BackendFunctBasic) ... ok
 | 
			
		||||
   test_connect_disconnect_multiple_times_on_kaminario (tests_basic.BackendFunctBasic) ... ok
 | 
			
		||||
   test_connect_disconnect_multiple_times_on_lvm (tests_basic.BackendFunctBasic) ... ok
 | 
			
		||||
   test_connect_disconnect_multiple_times_on_xtremio (tests_basic.BackendFunctBasic) ... ok
 | 
			
		||||
   test_stats_with_cretion_on_kaminario (tests_basic.BackendFunctBasic) ... ok
 | 
			
		||||
   test_stats_with_cretion_on_lvm (tests_basic.BackendFunctBasic) ... ok
 | 
			
		||||
   test_stats_with_cretion_on_xtremio (tests_basic.BackendFunctBasic) ... ok
 | 
			
		||||
   test_create_volume_from_snapshot_on_kaminario (tests_basic.BackendFunctBasic) ... ok
 | 
			
		||||
   test_create_volume_from_snapshot_on_lvm (tests_basic.BackendFunctBasic) ... ok
 | 
			
		||||
   test_create_volume_from_snapshot_on_xtremio (tests_basic.BackendFunctBasic) ... ok
 | 
			
		||||
   test_create_volume_on_kaminario (tests_basic.BackendFunctBasic) ... ok
 | 
			
		||||
   test_create_volume_on_lvm (tests_basic.BackendFunctBasic) ... ok
 | 
			
		||||
   test_create_volume_on_xtremio (tests_basic.BackendFunctBasic) ... ok
 | 
			
		||||
   test_disk_io_on_kaminario (tests_basic.BackendFunctBasic) ... ok
 | 
			
		||||
   test_disk_io_on_lvm (tests_basic.BackendFunctBasic) ... ok
 | 
			
		||||
   test_disk_io_on_xtremio (tests_basic.BackendFunctBasic) ... ok
 | 
			
		||||
   test_extend_on_kaminario (tests_basic.BackendFunctBasic) ... ok
 | 
			
		||||
   test_extend_on_lvm (tests_basic.BackendFunctBasic) ... ok
 | 
			
		||||
   test_extend_on_xtremio (tests_basic.BackendFunctBasic) ... ok
 | 
			
		||||
   test_stats_on_kaminario (tests_basic.BackendFunctBasic) ... ok
 | 
			
		||||
   test_stats_on_lvm (tests_basic.BackendFunctBasic) ... ok
 | 
			
		||||
   test_stats_on_xtremio (tests_basic.BackendFunctBasic) ... ok
 | 
			
		||||
   test_stats_with_creation_on_kaminario (tests_basic.BackendFunctBasic) ... ok
 | 
			
		||||
   test_stats_with_creation_on_lvm (tests_basic.BackendFunctBasic) ... ok
 | 
			
		||||
   test_stats_with_creation_on_xtremio (tests_basic.BackendFunctBasic) ... ok
 | 
			
		||||
 | 
			
		||||
   ----------------------------------------------------------------------
 | 
			
		||||
   Ran 48 tests in x.ys
 | 
			
		||||
 | 
			
		||||
   OK
 | 
			
		||||
 | 
			
		||||
As can be seen each test will have a meaningful name ending in the name of the
 | 
			
		||||
backend we have provided via the `volume_backend_name` key in the YAML file.
 | 
			
		||||
 
 | 
			
		||||
@@ -13,9 +13,11 @@
 | 
			
		||||
#    License for the specific language governing permissions and limitations
 | 
			
		||||
#    under the License.
 | 
			
		||||
 | 
			
		||||
import json
 | 
			
		||||
import functools
 | 
			
		||||
import os
 | 
			
		||||
import subprocess
 | 
			
		||||
import tempfile
 | 
			
		||||
 | 
			
		||||
import unittest2
 | 
			
		||||
import yaml
 | 
			
		||||
@@ -156,3 +158,61 @@ class BaseFunctTestCase(unittest2.TestCase):
 | 
			
		||||
 | 
			
		||||
        self.assertIn(snap, vol.snapshots)
 | 
			
		||||
        return snap
 | 
			
		||||
 | 
			
		||||
    def _get_vol_size(self, vol, do_detach=True):
 | 
			
		||||
        if not vol.local_attach:
 | 
			
		||||
            vol.attach()
 | 
			
		||||
 | 
			
		||||
        try:
 | 
			
		||||
            while True:
 | 
			
		||||
                try:
 | 
			
		||||
                    result = self._root_execute('lsblk', '-o', 'SIZE', '-J',
 | 
			
		||||
                                                '-b', vol.local_attach.path)
 | 
			
		||||
                    data = json.loads(result)
 | 
			
		||||
                    size_bytes = data['blockdevices'][0]['size']
 | 
			
		||||
                    return float(size_bytes) / 1024.0 / 1024.0 / 1024.0
 | 
			
		||||
                # NOTE(geguileo): We can't catch subprocess.CalledProcessError
 | 
			
		||||
                # because somehow we get an instance from a different
 | 
			
		||||
                # subprocess.CalledProcessError class that isn't the same.
 | 
			
		||||
                except Exception as exc:
 | 
			
		||||
                    # If the volume is not yet available
 | 
			
		||||
                    if getattr(exc, 'returncode', 0) != 32:
 | 
			
		||||
                        raise
 | 
			
		||||
        finally:
 | 
			
		||||
            if do_detach:
 | 
			
		||||
                vol.detach()
 | 
			
		||||
 | 
			
		||||
    def _write_data(self, vol, data=None, do_detach=True):
 | 
			
		||||
        if not data:
 | 
			
		||||
            data = '0123456789' * 100
 | 
			
		||||
 | 
			
		||||
        if not vol.local_attach:
 | 
			
		||||
            vol.attach()
 | 
			
		||||
 | 
			
		||||
        # TODO(geguileo: This will not work on Windows, for that we need to
 | 
			
		||||
        # pass delete=False and do the manual deletion ourselves.
 | 
			
		||||
        try:
 | 
			
		||||
            with tempfile.NamedTemporaryFile() as f:
 | 
			
		||||
                f.write(data)
 | 
			
		||||
                f.flush()
 | 
			
		||||
                self._root_execute('dd', 'if=' + f.name,
 | 
			
		||||
                                   of=vol.local_attach.path)
 | 
			
		||||
        finally:
 | 
			
		||||
            if do_detach:
 | 
			
		||||
                vol.detach()
 | 
			
		||||
 | 
			
		||||
        return data
 | 
			
		||||
 | 
			
		||||
    def _read_data(self, vol, length, do_detach=True):
 | 
			
		||||
        if not vol.local_attach:
 | 
			
		||||
            vol.attach()
 | 
			
		||||
        try:
 | 
			
		||||
            stdout = self._root_execute('dd', 'if=' + vol.local_attach.path,
 | 
			
		||||
                                        count=1, ibs=length)
 | 
			
		||||
        finally:
 | 
			
		||||
            if do_detach:
 | 
			
		||||
                vol.detach()
 | 
			
		||||
        return stdout
 | 
			
		||||
 | 
			
		||||
    def _pools_info(self, stats):
 | 
			
		||||
        return stats.get('pools', [stats])
 | 
			
		||||
 
 | 
			
		||||
@@ -14,7 +14,6 @@
 | 
			
		||||
#    under the License.
 | 
			
		||||
 | 
			
		||||
import os
 | 
			
		||||
import tempfile
 | 
			
		||||
 | 
			
		||||
import base_tests
 | 
			
		||||
 | 
			
		||||
@@ -26,13 +25,40 @@ class BackendFunctBasic(base_tests.BaseFunctTestCase):
 | 
			
		||||
        stats = self.backend.stats()
 | 
			
		||||
        self.assertIn('vendor_name', stats)
 | 
			
		||||
        self.assertIn('volume_backend_name', stats)
 | 
			
		||||
        pools_info = stats.get('pools', [stats])
 | 
			
		||||
        pools_info = self._pools_info(stats)
 | 
			
		||||
        for pool_info in pools_info:
 | 
			
		||||
            self.assertIn('free_capacity_gb', pool_info)
 | 
			
		||||
            self.assertIn('total_capacity_gb', pool_info)
 | 
			
		||||
 | 
			
		||||
    def test_stats_with_creation(self):
 | 
			
		||||
        # This test can fail if we are don't have exclusive usage of the
 | 
			
		||||
        # storage pool used in the tests or if the specific driver does not
 | 
			
		||||
        # return the right values in allocated_capacity_gb or
 | 
			
		||||
        # provisioned_capacity_gb.
 | 
			
		||||
        initial_stats = self.backend.stats(refresh=True)
 | 
			
		||||
        vol = self._create_vol(self.backend)
 | 
			
		||||
        new_stats = self.backend.stats(refresh=True)
 | 
			
		||||
 | 
			
		||||
        initial_pools_info = self._pools_info(initial_stats)
 | 
			
		||||
        new_pools_info = self._pools_info(new_stats)
 | 
			
		||||
 | 
			
		||||
        initial_volumes = sum(p.get('total_volumes', 0)
 | 
			
		||||
                              for p in initial_pools_info)
 | 
			
		||||
        new_volumes = sum(p.get('total_volumes', 1) for p in new_pools_info)
 | 
			
		||||
        self.assertEqual(initial_volumes + 1, new_volumes)
 | 
			
		||||
 | 
			
		||||
        initial_size = sum(p.get('allocated_capacity_gb',
 | 
			
		||||
                                 p.get('provisioned_capacity_gb', 0))
 | 
			
		||||
                           for p in initial_pools_info)
 | 
			
		||||
        new_size = sum(p.get('allocated_capacity_gb',
 | 
			
		||||
                             p.get('provisioned_capacity_gb', vol.size))
 | 
			
		||||
                       for p in new_pools_info)
 | 
			
		||||
        self.assertEqual(initial_size + vol.size, new_size)
 | 
			
		||||
 | 
			
		||||
    def test_create_volume(self):
 | 
			
		||||
        self._create_vol(self.backend)
 | 
			
		||||
        vol = self._create_vol(self.backend)
 | 
			
		||||
        vol_size = self._get_vol_size(vol)
 | 
			
		||||
        self.assertEqual(vol.size, vol_size)
 | 
			
		||||
        # We are not testing delete, so leave the deletion to the tearDown
 | 
			
		||||
 | 
			
		||||
    def test_create_delete_volume(self):
 | 
			
		||||
@@ -114,29 +140,61 @@ class BackendFunctBasic(base_tests.BaseFunctTestCase):
 | 
			
		||||
        self.assertNotIn(attach, vol.connections)
 | 
			
		||||
 | 
			
		||||
    def test_disk_io(self):
 | 
			
		||||
        data = '0123456789' * 100
 | 
			
		||||
 | 
			
		||||
        vol = self._create_vol(self.backend)
 | 
			
		||||
        data = self._write_data(vol)
 | 
			
		||||
 | 
			
		||||
        attach = vol.attach()
 | 
			
		||||
        read_data = self._read_data(vol, len(data))
 | 
			
		||||
 | 
			
		||||
        # TODO(geguileo: This will not work on Windows, for that we need to
 | 
			
		||||
        # pass delete=False and do the manual deletion ourselves.
 | 
			
		||||
        with tempfile.NamedTemporaryFile() as f:
 | 
			
		||||
            f.write(data)
 | 
			
		||||
            f.flush()
 | 
			
		||||
            self._root_execute('dd', 'if=' + f.name, of=attach.path)
 | 
			
		||||
        self.assertEqual(data, read_data)
 | 
			
		||||
 | 
			
		||||
        # Detach without removing the mapping of the volume since it's faster
 | 
			
		||||
        attach.detach()
 | 
			
		||||
    def test_extend(self):
 | 
			
		||||
        vol = self._create_vol(self.backend)
 | 
			
		||||
        original_size = vol.size
 | 
			
		||||
        result_original_size = self._get_vol_size(vol)
 | 
			
		||||
        self.assertEqual(original_size, result_original_size)
 | 
			
		||||
 | 
			
		||||
        # Reattach, using old mapping, to validate data is there
 | 
			
		||||
        attach.attach()
 | 
			
		||||
        stdout = self._root_execute('dd', 'if=' + attach.path, count=1,
 | 
			
		||||
                                    ibs=len(data))
 | 
			
		||||
        new_size = vol.size + 1
 | 
			
		||||
        vol.extend(new_size)
 | 
			
		||||
 | 
			
		||||
        self.assertEqual(data, stdout)
 | 
			
		||||
        vol.detach()
 | 
			
		||||
        self.assertEqual(new_size, vol.size)
 | 
			
		||||
        result_new_size = self._get_vol_size(vol)
 | 
			
		||||
        self.assertEqual(new_size, result_new_size)
 | 
			
		||||
 | 
			
		||||
    def test_clone(self):
 | 
			
		||||
        vol = self._create_vol(self.backend)
 | 
			
		||||
        original_size = self._get_vol_size(vol, do_detach=False)
 | 
			
		||||
        data = self._write_data(vol)
 | 
			
		||||
 | 
			
		||||
        new_vol = vol.clone()
 | 
			
		||||
        self.assertEqual(vol.size, new_vol.size)
 | 
			
		||||
 | 
			
		||||
        cloned_size = self._get_vol_size(new_vol, do_detach=False)
 | 
			
		||||
        read_data = self._read_data(new_vol, len(data))
 | 
			
		||||
        self.assertEqual(original_size, cloned_size)
 | 
			
		||||
        self.assertEqual(data, read_data)
 | 
			
		||||
 | 
			
		||||
    def test_create_volume_from_snapshot(self):
 | 
			
		||||
        # Create a volume and write some data
 | 
			
		||||
        vol = self._create_vol(self.backend)
 | 
			
		||||
        original_size = self._get_vol_size(vol, do_detach=False)
 | 
			
		||||
        data = self._write_data(vol)
 | 
			
		||||
 | 
			
		||||
        # Take a snapshot
 | 
			
		||||
        snap = vol.create_snapshot()
 | 
			
		||||
        self.assertEqual(vol.size, snap.volume_size)
 | 
			
		||||
 | 
			
		||||
        # Change the data in the volume
 | 
			
		||||
        reversed_data = data[::-1]
 | 
			
		||||
        self._write_data(vol, data=reversed_data)
 | 
			
		||||
 | 
			
		||||
        # Create a new volume from the snapshot with the original data
 | 
			
		||||
        new_vol = snap.create_volume()
 | 
			
		||||
        self.assertEqual(vol.size, new_vol.size)
 | 
			
		||||
 | 
			
		||||
        created_size = self._get_vol_size(new_vol, do_detach=False)
 | 
			
		||||
        read_data = self._read_data(new_vol, len(data))
 | 
			
		||||
        self.assertEqual(original_size, created_size)
 | 
			
		||||
        self.assertEqual(data, read_data)
 | 
			
		||||
 | 
			
		||||
    def test_connect_disconnect_volume(self):
 | 
			
		||||
        # TODO(geguileo): Implement the test
 | 
			
		||||
@@ -149,7 +207,3 @@ class BackendFunctBasic(base_tests.BaseFunctTestCase):
 | 
			
		||||
    def test_connect_disconnect_multiple_times(self):
 | 
			
		||||
        # TODO(geguileo): Implement the test
 | 
			
		||||
        pass
 | 
			
		||||
 | 
			
		||||
    def test_stats_with_creation(self):
 | 
			
		||||
        # TODO(geguileo): Implement the test
 | 
			
		||||
        pass
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user