diff --git a/Makefile b/Makefile index 8beb2a9..64f2cdb 100644 --- a/Makefile +++ b/Makefile @@ -10,6 +10,10 @@ define runtox @cd "$(ROOT_DIR)" && tox -e $1 endef +.PHONY: selftest +selftest: + $(call runtox, "selftest") + .PHONY: test test: $(call runtox, "pytest") diff --git a/selftest/test-info1.yml b/selftest/test-info1.yml new file mode 100644 index 0000000..f1a689c --- /dev/null +++ b/selftest/test-info1.yml @@ -0,0 +1,30 @@ +# Server hostname to be tested +server: server_name + +# Users to use for authentication +users: + user1: user1password + user2: user2password + +# Backend filesystem of the exported shares +backend: glusterfs + +# shares: List of dict of exported shares +shares: + # share export1 + export1: + # If present, it means the share is pre-mounted + # at the location given + path: /mnt/share/export1-cephfs-vfs + backend: + # If present override default backend filesystem + name: cephfs.vfs + # If present, use these credentials to perform the + # tests for this share + users: + test2: x + # If present, override the server to test for this share + server: hostname1 + # share name export2 + export2: + # Use default values set for this share diff --git a/selftest/test-info2.yml b/selftest/test-info2.yml new file mode 100644 index 0000000..373692a --- /dev/null +++ b/selftest/test-info2.yml @@ -0,0 +1,12 @@ +public_interfaces: + - "192.168.123.10" + - "192.168.123.11" + +exported_sharenames: + - "gluster-vol" + +test_users: + - {"username": "test1", "password": "x"} + - {"username": "test2", "password": "x"} + +test_backend: glusterfs \ No newline at end of file diff --git a/selftest/test_testhelper.py b/selftest/test_testhelper.py new file mode 100644 index 0000000..b157f95 --- /dev/null +++ b/selftest/test_testhelper.py @@ -0,0 +1,62 @@ +import testhelper +from pathlib import Path + + +def test_read_yaml1(): + testinfo = testhelper.read_yaml("test-info1.yml") + + export1 = testinfo["shares"]["export1"] + assert export1["server"] == "hostname1" + assert export1["path"] == "/mnt/share/export1-cephfs-vfs" + assert export1["backend"]["name"] == "cephfs.vfs" + assert "user1" not in export1["users"] + assert "test2" in export1["users"] + assert export1["users"]["test2"] == "x" + + export2 = testinfo["shares"]["export2"] + assert export2["server"] == "server_name" + assert "path" not in export2 + assert export2["backend"]["name"] == "glusterfs" + assert "test2" not in export2["users"] + assert "user2" in export2["users"] + assert export2["users"]["user2"] == "user2password" + + +def test_read_yaml2(): + testinfo = testhelper.read_yaml("test-info2.yml") + + export = testinfo["shares"]["gluster-vol"] + assert export["server"] == "192.168.123.10" + assert "path" not in export + assert export["backend"]["name"] == "glusterfs" + assert "user1" not in export["users"] + assert "test1" in export["users"] + assert export["users"]["test1"] == "x" + + +def test_get_share(): + testinfo = testhelper.read_yaml("test-info1.yml") + export2 = testhelper.get_share(testinfo, "export2") + assert export2["server"] == "server_name" + assert "path" not in export2 + assert export2["backend"]["name"] == "glusterfs" + assert "test2" not in export2["users"] + assert "user2" in export2["users"] + assert export2["users"]["user2"] == "user2password" + + +def test_list_premounted(): + testinfo = testhelper.read_yaml("test-info1.yml") + premounted = testhelper.get_premounted_shares(testinfo) + assert len(premounted) == 1 + assert Path("/mnt/share/export1-cephfs-vfs") in premounted + + +def test_generate_exported_shares(): + testinfo = testhelper.read_yaml("test-info1.yml") + arr = [] + for sharename in testhelper.get_exported_shares(testinfo): + share = testhelper.get_share(testinfo, sharename) + arr.append((share["server"], share["name"])) + assert len(arr) == 1 + assert ("server_name", "export2") in arr diff --git a/test-info.yml.example b/test-info.yml.example index e84c89c..f1a689c 100644 --- a/test-info.yml.example +++ b/test-info.yml.example @@ -1,20 +1,30 @@ -private_interfaces: - - "192.168.122.100" - - "192.168.122.101" +# Server hostname to be tested +server: server_name -public_interfaces: - - "192.168.123.10" - - "192.168.123.11" +# Users to use for authentication +users: + user1: user1password + user2: user2password -exported_sharenames: - - "gluster-vol" +# Backend filesystem of the exported shares +backend: glusterfs -test_users: - - {"username": "test1", "password": "x"} - - {"username": "test2", "password": "x"} - -test_backend: glusterfs - -premounted_shares: - - "/testdir1" - - "/testdir2" \ No newline at end of file +# shares: List of dict of exported shares +shares: + # share export1 + export1: + # If present, it means the share is pre-mounted + # at the location given + path: /mnt/share/export1-cephfs-vfs + backend: + # If present override default backend filesystem + name: cephfs.vfs + # If present, use these credentials to perform the + # tests for this share + users: + test2: x + # If present, override the server to test for this share + server: hostname1 + # share name export2 + export2: + # Use default values set for this share diff --git a/testcases/consistency/test_consistency.py b/testcases/consistency/test_consistency.py index 555c835..aeb4982 100755 --- a/testcases/consistency/test_consistency.py +++ b/testcases/consistency/test_consistency.py @@ -61,9 +61,9 @@ def generate_consistency_check( if not test_info_file: return [] arr = [] - for ipaddr in test_info_file["public_interfaces"]: - for share_name in test_info_file["exported_sharenames"]: - arr.append((ipaddr, share_name)) + for share in testhelper.get_exported_shares(test_info): + s = testhelper.get_share(test_info, share) + arr.append((s["server"], s["name"])) return arr diff --git a/testcases/containers/test_containers.py b/testcases/containers/test_containers.py index 8569e19..ee1d423 100755 --- a/testcases/containers/test_containers.py +++ b/testcases/containers/test_containers.py @@ -66,12 +66,11 @@ def containers_check(ipaddr: str, share_name: str, test: str) -> None: def generate_containers_test() -> typing.List[typing.Tuple[str, str, str]]: - # Use the first given public_interface for our tests - ipaddr = test_info["public_interfaces"][0] arr = [] - for share_name in test_info["exported_sharenames"]: + for share_name in testhelper.get_exported_shares(test_info): + server = testhelper.get_share(test_info, share_name)["server"] for test in container_tests.keys(): - arr.append((ipaddr, share_name, test)) + arr.append((server, share_name, test)) return arr diff --git a/testcases/misc/conftest.py b/testcases/misc/conftest.py index 21e0531..c495fbc 100644 --- a/testcases/misc/conftest.py +++ b/testcases/misc/conftest.py @@ -46,12 +46,12 @@ def setup_mount( def gen_params() -> typing.List[typing.Any]: - ipaddr = test_info["public_interfaces"][0] - exported_sharenames = test_info.get("exported_sharenames", []) + exported_sharenames = testhelper.get_exported_shares(test_info) arr = [] for share_name in exported_sharenames: + server = testhelper.get_share(test_info, share_name)["server"] arr.append( - pytest.param((ipaddr, share_name), id=f"{ipaddr}-{share_name}") + pytest.param((server, share_name), id=f"{server}-{share_name}") ) return arr diff --git a/testcases/smbtorture/test_smbtorture.py b/testcases/smbtorture/test_smbtorture.py index e266c36..6c053b2 100755 --- a/testcases/smbtorture/test_smbtorture.py +++ b/testcases/smbtorture/test_smbtorture.py @@ -48,7 +48,8 @@ def smbtorture(share_name: str, test: str, tmp_output: Path) -> bool: "--expected-failures=" + script_root + "/selftest/" + filter ) flapping_list = ["flapping", "flapping.d"] - test_backend = test_info.get("test_backend") + share = testhelper.get_share(test_info, share_name) + test_backend = share["backend"].get("name") if test_backend is not None: flapping_file = "flapping." + test_backend flapping_file_path = os.path.join( @@ -114,7 +115,7 @@ def list_smbtorture_tests(): def generate_smbtorture_tests() -> typing.List[typing.Tuple[str, str]]: smbtorture_info = list_smbtorture_tests() arr = [] - for share_name in test_info.get("exported_sharenames", []): + for share_name in testhelper.get_exported_shares(test_info): for torture_test in smbtorture_info: arr.append((share_name, torture_test)) return arr diff --git a/testhelper/testhelper.py b/testhelper/testhelper.py index 47b51c6..457ca9f 100644 --- a/testhelper/testhelper.py +++ b/testhelper/testhelper.py @@ -4,17 +4,63 @@ from pathlib import Path -def read_yaml(test_info): +def _get_default_backend(test_info: dict) -> str: + return test_info.get("backend") or test_info.get("test_backend", "xfs") + + +def _get_default_server(test_info: dict) -> str: + return ( + test_info.get("server") + or test_info.get("public_interfaces", ["localhost"])[0] + ) + + +def _get_default_users(test_info: dict) -> typing.Dict[str, str]: + default_users = test_info.get("users", {}) + if not default_users: + for user in test_info.get("test_users", []): + default_users[user["username"]] = user["password"] + return default_users + + +def read_yaml(test_info_file): """Returns a dict containing the contents of the yaml file. Parameters: - test_info: filename of yaml file. + test_info_file: filename of yaml file. Returns: dict: The parsed test information yml as a dictionary. """ - with open(test_info) as f: + with open(test_info_file) as f: test_info = yaml.load(f, Loader=yaml.FullLoader) + + shares = test_info.get("shares", {}) + + # Copy exported_sharenames to shares + # Todo - remove once sit-environment is updated + for sharename in test_info.get("exported_sharenames", []): + assert sharename not in shares, "Duplicate share name present" + shares[sharename] = {} + + # Add missing fields with defaults + # Todo : Remove old field names once sit-environment is updated + default_backend = _get_default_backend(test_info) + default_server = _get_default_server(test_info) + default_users = _get_default_users(test_info) + + for sharename in shares: + if shares[sharename] is None: + shares[sharename] = {"name": sharename} + share = shares[sharename] + share.setdefault("name", sharename) + share.setdefault("backend", {}) + share.setdefault("server", default_server) + share.setdefault("users", default_users) + share["backend"].setdefault("name", default_backend) + + test_info["shares"] = shares + return test_info @@ -48,11 +94,14 @@ def get_mount_parameters(test_info: dict, share: str) -> typing.Dict[str, str]: test_info: Dict containing the parsed yaml file. share: The share for which to get the mount_params """ + s = get_share(test_info, share) + server = s["server"] + users = list(s["users"].keys()) return gen_mount_params( - test_info["public_interfaces"][0], + server, share, - test_info["test_users"][0]["username"], - test_info["test_users"][0]["password"], + users[0], + s["users"][users[0]], ) @@ -76,6 +125,46 @@ def generate_random_bytes(size: int) -> bytes: return rba[:size] +def get_shares(test_info: dict) -> dict: + """ + Get list of shares + + Parameters: + test_info: Dict containing the parsed yaml file. + Returns: + list of dict of shares + """ + return test_info["shares"] + + +def get_share(test_info: dict, sharename: str) -> dict: + """ + Get share dict for a given sharename + + Parameters: + test_info: Dict containing the parsed yaml file. + sharename: name of the share + Returns: + dict of the share + """ + shares = get_shares(test_info) + assert sharename in shares.keys(), "Share not found" + return shares[sharename] + + +def is_premounted_share(share: dict) -> bool: + """ + Check if the share is a premounted share + + Parameters: + share: dict of the share + Returns: + bool + """ + mntdir = share.get("path") + return mntdir is not None + + def get_premounted_shares(test_info: dict) -> typing.List[Path]: """ Get list of premounted shares @@ -85,5 +174,20 @@ def get_premounted_shares(test_info: dict) -> typing.List[Path]: Returns: list of paths with shares """ - premounted_shares = test_info.get("premounted_shares", []) - return [Path(mnt) for mnt in premounted_shares] + share_values = get_shares(test_info).values() + return [Path(s["path"]) for s in share_values if is_premounted_share(s)] + + +def get_exported_shares(test_info: dict) -> typing.List[str]: + """Get the list of exported shares + + Parameters: + test_info: Dict containing the parsed yaml file. + Returns: + list of exported shares + """ + arr = [] + for share in get_shares(test_info).values(): + if not is_premounted_share(share): + arr.append(share["name"]) + return arr diff --git a/tox.ini b/tox.ini index 05aa6d1..a2646b6 100644 --- a/tox.ini +++ b/tox.ini @@ -32,6 +32,13 @@ deps = changedir = {toxinidir} commands = pytest -vrfEsxXpP testcases/consistency +[testenv:selftest] +deps = + pytest + pyyaml +changedir = {toxinidir}/selftest +commands = pytest -vrfEsxXpP . + [testenv:flake8] deps = flake8 changedir = {toxinidir}