From 0b608f85e9ea16e28c8532785e6f34a9383f462f Mon Sep 17 00:00:00 2001 From: Gorka Eguileor Date: Wed, 14 Mar 2018 13:35:08 +0100 Subject: [PATCH] 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. --- docs/validating_backends.rst | 78 ++++++++++++++---------- tests/functional/base_tests.py | 60 +++++++++++++++++++ tests/functional/tests_basic.py | 102 ++++++++++++++++++++++++-------- 3 files changed, 186 insertions(+), 54 deletions(-) diff --git a/docs/validating_backends.rst b/docs/validating_backends.rst index 117aa80..39ec860 100644 --- a/docs/validating_backends.rst +++ b/docs/validating_backends.rst @@ -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. diff --git a/tests/functional/base_tests.py b/tests/functional/base_tests.py index 2f70dce..5d8d598 100644 --- a/tests/functional/base_tests.py +++ b/tests/functional/base_tests.py @@ -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]) diff --git a/tests/functional/tests_basic.py b/tests/functional/tests_basic.py index 0305088..b655e33 100644 --- a/tests/functional/tests_basic.py +++ b/tests/functional/tests_basic.py @@ -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