From aefd8960a3c8e055f554371d8f40dfbe8cd87926 Mon Sep 17 00:00:00 2001 From: Miroslav Asenov Date: Mon, 16 Apr 2018 15:14:53 +0300 Subject: Add test case DHT Distribution based on key value Changes: - Add more log end points - Include dht glusto's functions - Fix count log parameters - Convert docstring to google style docstring on helper function - Renamed test class Change-Id: Ib919e86c8c79e8bdad4007bc9d77d76b031ecb3d --- tests/functional/dht/test_dht_hash_value.py | 219 ++++++++++++++++++++++++++++ 1 file changed, 219 insertions(+) create mode 100644 tests/functional/dht/test_dht_hash_value.py (limited to 'tests/functional/dht') diff --git a/tests/functional/dht/test_dht_hash_value.py b/tests/functional/dht/test_dht_hash_value.py new file mode 100644 index 000000000..fd83576cf --- /dev/null +++ b/tests/functional/dht/test_dht_hash_value.py @@ -0,0 +1,219 @@ +# Copyright (C) 2017-2018 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 +# 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. +# Test - Distribution based on hash value + +from random import choice, randint +from uuid import uuid4 + +from glusto.core import Glusto as g + +from glustolibs.gluster.brick_libs import get_all_bricks +from glustolibs.gluster.constants import FILETYPE_DIRS +from glustolibs.gluster.constants import \ + TEST_FILE_EXISTS_ON_HASHED_BRICKS as FILE_ON_HASHED_BRICKS +from glustolibs.gluster.constants import TEST_LAYOUT_IS_COMPLETE +from glustolibs.gluster.dht_test_utils import validate_files_in_dir +from glustolibs.gluster.exceptions import ExecutionError +from glustolibs.gluster.gluster_base_class import GlusterBaseClass, runs_on +from glustolibs.gluster.glusterdir import mkdir, rmdir +from glustolibs.gluster.glusterfile import (file_exists, get_fattr, + get_fattr_list) + + +@runs_on([['replicated', 'distributed', 'distributed-replicated', + 'dispersed', 'distributed-dispersed'], + ['glusterfs']]) +class TestDHTHashValue(GlusterBaseClass): + def setUp(self): + GlusterBaseClass.setUp.im_func(self) + # Setup Volume + ret = self.setup_volume_and_mount_volume(self.mounts) + + if not ret: + g.log.error("Failed to Setup and Mount Volume") + raise ExecutionError("Failed to Setup and Mount Volume") + + self.temp_folder = '/tmp/%s' % uuid4() + + @classmethod + def create_files(cls, host, root, files, content): + """This method is responsible to create file structure by given + sequence with the same content for all of the files + Args: + host (str): Remote host + root (str): root file directory + files (list|tuple): Sequence of file paths + content (str): Textual file content for each of files. + Returns: + bool: True on success, False on error + """ + for item in files: + dir_name = root + file_name = item + if item.find('/') != -1: + segments = item.split('/') + folders_tree = "/".join(segments[:-1]) + file_name = segments[-1] + dir_name = '{root}/{folders_tree}'.format( + root=root, folders_tree=folders_tree) + mkdir(host, dir_name, parents=True) + cmd = 'echo "{content}" > {root}/{file}'.format(root=dir_name, + file=file_name, + content=content) + ret, _, _ = g.run(host, cmd) + if ret != 0: + g.log.error('Error on file creation %s', cmd) + return False + return True + + def test_distribution_hash_value(self): + """Test case tests DHT of files and directories based on hash value + """ + # pylint: disable=too-many-locals + for client_index, mount_obj in enumerate(self.mounts): + client_host = mount_obj.client_system + mountpoint = mount_obj.mountpoint + + # Create directory for initial data + g.log.debug("Creating temporary folder on client's machine %s:%s", + client_host, self.temp_folder) + if not mkdir(client_host, self.temp_folder): + g.log.error("Failed create temporary directory " + "on client machine %s:%s", + client_host, self.temp_folder) + raise ExecutionError("Failed create temporary directory " + "on client machine %s:%s" % + (client_host, self.temp_folder)) + g.log.info('Created temporary directory on client machine %s:%s', + client_host, self.temp_folder) + # Prepare a set of data + files = ["{prefix}{file_name}_{client_index}". + format(file_name=file_name, + client_index=client_index, + prefix='' if randint(1, 6) % 2 + else choice('ABCD') + '/') + for file_name in map(chr, range(97, 123))] + ret = self.create_files(client_host, self.temp_folder, + files, + "Lorem Ipsum is simply dummy text of the " + "printing and typesetting industry.") + self.assertTrue(ret, "Failed creating a set of files and dirs " + "on %s:%s" % (client_host, self.temp_folder)) + g.log.info('Created data set on client machine on folder %s:%s', + client_host, self.temp_folder) + + # Copy prepared data to mount point + cmd = ('cp -vr {source}/* {destination}'.format( + source=self.temp_folder, + destination=mountpoint)) + ret, _, _ = g.run(client_host, cmd) + self.assertEqual(ret, 0, "Copy data to mount point %s:%s Failed") + g.log.info('Copied prepared data to mount point %s:%s', + client_host, mountpoint) + + # Verify that hash layout values are set on each + # bricks for the dir + g.log.debug("Verifying DHT layout") + ret = validate_files_in_dir(client_host, mountpoint, + test_type=TEST_LAYOUT_IS_COMPLETE) + self.assertTrue(ret, "TEST_LAYOUT_IS_COMPLETE: FAILED") + g.log.info("TEST_LAYOUT_IS_COMPLETE: PASS on %s:%s ", + client_host, mountpoint) + + g.log.debug("Verifying files and directories") + ret = validate_files_in_dir(client_host, mountpoint, + test_type=FILE_ON_HASHED_BRICKS, + file_type=FILETYPE_DIRS) + self.assertTrue(ret, "TEST_FILE_EXISTS_ON_HASHED_BRICKS: FAILED") + g.log.info("TEST_FILE_EXISTS_ON_HASHED_BRICKS: PASS") + + # Verify "trusted.gfid" extended attribute of the + # directory/file on all the bricks + gfids = dict() + g.log.debug("Check if trusted.gfid is presented on the bricks") + for brick_item in get_all_bricks(self.mnode, self.volname): + brick_host, brick_dir = brick_item.split(':') + + for target_destination in files: + if not file_exists(brick_host, '{brick_dir}/{dest}'. + format(brick_dir=brick_dir, + dest=target_destination)): + continue + ret = get_fattr(brick_host, '%s/%s' % + (brick_dir, target_destination), + 'trusted.gfid') + self.assertIsNotNone(ret, + "trusted.gfid is not presented " + "on %s/%s" % (brick_dir, + target_destination)) + g.log.info("Verified trusted.gfid on brick %s:%s", + brick_item, target_destination) + gfids.setdefault(target_destination, []).append(ret) + + g.log.debug('Check if trusted.gfid is same on all the bricks') + self.assertTrue(all([False if len(set(gfids[k])) > 1 else True + for k in gfids]), + "trusted.gfid should be same on all the bricks") + g.log.info('trusted.gfid is same on all the bricks') + # Verify that mount point shows pathinfo xattr. + g.log.debug("Check if pathinfo is presented on mount point " + "%s:%s", client_host, mountpoint) + ret = get_fattr(client_host, mountpoint, + 'trusted.glusterfs.pathinfo') + self.assertIsNotNone(ret, "pathinfo is not presented on mount " + "point %s:%s" % (client_host, + mountpoint)) + + g.log.info('trusted.glusterfs.pathinfo is presented on mount' + ' point %s:%s', client_host, mountpoint) + + # Mount point should not display xattr: + # trusted.gfid and trusted.glusterfs.dht + g.log.debug("Check if trusted.gfid and trusted.glusterfs.dht are " + "not presented on mount point %s:%s", client_host, + mountpoint) + attributes = get_fattr_list(client_host, mountpoint) + self.assertFalse('trusted.gfid' in attributes, + "Expected: Mount point should't display xattr:" + "{xattr}. Actual: xattrs {xattr} is " + "presented on mount point". + format(xattr='trusted.gfid')) + self.assertFalse('trusted.glusterfs.dht' in attributes, + "Expected: Mount point should't display xattr:" + "{xattr}. Actual: xattrs {xattr} is " + "presented on mount point". + format(xattr='trusted.glusterfs.dht')) + + g.log.info("trusted.gfid and trusted.glusterfs.dht are not " + "presented on mount point %s:%s", client_host, + mountpoint) + g.log.info('Files and dirs are stored on bricks based on hash value') + + def tearDown(self): + g.log.info("Tear down") + + for mount_point in self.mounts: + g.log.debug('Removing temporary folder %s', + self.temp_folder) + rmdir(mount_point.client_system, self.temp_folder, + force=True) + + g.log.info("Starting to Unmount Volume and Cleanup Volume") + ret = self.unmount_volume_and_cleanup_volume(self.mounts) + if not ret: + g.log.error("Failed to Setup and Mount Volume") + raise ExecutionError('Failed to unmount and clean volumes') + GlusterBaseClass.tearDown.im_func(self) -- cgit