From 3879e96080a8abc099d48c5fd40afad7a35b802b Mon Sep 17 00:00:00 2001 From: mulhern Date: Thu, 29 Aug 2024 22:42:52 -0400 Subject: [PATCH] Run a python-based test to revert a filesystem Signed-off-by: mulhern --- .github/workflows/support.yml | 1 + tests-fmf/python.fmf | 6 +- tests/client-dbus/Makefile | 4 + tests/client-dbus/tests/udev/test_revert.py | 120 ++++++++++++++++++++ 4 files changed, 129 insertions(+), 2 deletions(-) create mode 100644 tests/client-dbus/tests/udev/test_revert.py diff --git a/.github/workflows/support.yml b/.github/workflows/support.yml index 8e7fe8cadf..d44d0f91f7 100644 --- a/.github/workflows/support.yml +++ b/.github/workflows/support.yml @@ -43,6 +43,7 @@ jobs: python3-dbus-client-gen python3-dbus-python-client-gen python3-justbytes + python3-libmount python3-psutil python3-pyudev python3-semantic_version diff --git a/tests-fmf/python.fmf b/tests-fmf/python.fmf index 9ae54f24e3..3f9a3305e2 100644 --- a/tests-fmf/python.fmf +++ b/tests-fmf/python.fmf @@ -8,6 +8,8 @@ require: - python3-dbus - python3-dbus-client-gen - python3-dbus-python-client-gen + - python3-justbytes + - python3-libmount - python3-psutil - python3-pyudev @@ -28,7 +30,7 @@ environment: /legacy/loop: summary: Run Python tests that use loopbacked device framework - test: make -f Makefile tang-tests dump-metadata-tests startup-tests + test: make -f Makefile tang-tests dump-metadata-tests startup-tests revert-tests /v2/udev: summary: Run Python udev tests @@ -36,4 +38,4 @@ environment: /v2/loop: summary: Run Python tests that use loopbacked device framework - test: make -f Makefile tang-tests dump-metadata-tests startup-tests + test: make -f Makefile tang-tests dump-metadata-tests startup-tests revert-tests diff --git a/tests/client-dbus/Makefile b/tests/client-dbus/Makefile index db20f1460b..8a9cddbf7b 100644 --- a/tests/client-dbus/Makefile +++ b/tests/client-dbus/Makefile @@ -38,3 +38,7 @@ filesystem-predict-tests: .PHONY: dump-metadata-tests dump-metadata-tests: python3 -m unittest ${UNITTEST_OPTS} tests.udev.test_dump + +.PHONY: revert-tests +revert-tests: + python3 -m unittest ${UNITTEST_OPTS} tests.udev.test_revert diff --git a/tests/client-dbus/tests/udev/test_revert.py b/tests/client-dbus/tests/udev/test_revert.py new file mode 100644 index 0000000000..fd9d3a71ac --- /dev/null +++ b/tests/client-dbus/tests/udev/test_revert.py @@ -0,0 +1,120 @@ +# Copyright 2021 Red Hat, Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +""" +Test reverting a filesystem. +""" + +# isort: STDLIB +import os +import tempfile + +# isort: THIRDPARTY +import libmount +from justbytes import Range + +# isort: LOCAL +from stratisd_client_dbus import Filesystem + +from ._utils import ( + Pool, + ServiceContextManager, + UdevTest, + create_pool, + get_object, + random_string, +) + + +class TestRevert(UdevTest): + """ + Test reverting a filesystem. + """ + + def test_revert(self): # pylint: disable=too-many-locals + """ + Schedule a revert and verify that it has succeeded when the pool is + restarted. + """ + mountdir = tempfile.mkdtemp("_stratis_mnt") + + with ServiceContextManager(): + device_tokens = self._lb_mgr.create_devices(2) + + pool_name = random_string(5) + + (_, (pool_object_path, _)) = create_pool( + pool_name, self._lb_mgr.device_files(device_tokens) + ) + + fs_name = "fs1" + fs_size = Range(1024**3) + ((_, fs_object_paths), return_code, message) = ( + Pool.Methods.CreateFilesystems( + get_object(pool_object_path), + {"specs": [(fs_name, str(fs_size.magnitude), (False, ""))]}, + ) + ) + + if return_code != 0: + raise RuntimeError( + f"Failed to create a requested filesystem: {message}" + ) + + filepath = f"/dev/stratis/{pool_name}/{fs_name}" + + mountcxt = libmount.Context( # pylint: disable=no-member + target=mountdir, source=filepath + ) + mountcxt.mount() + + file1 = "file1.txt" + with open(os.path.join(mountdir, file1), encoding="utf-8", mode="w") as fd: + print(file1, file=fd) + + snap_name = "snap1" + ((_, snap_object_path), return_code, message) = ( + Pool.Methods.SnapshotFilesystem( + get_object(pool_object_path), + {"origin": fs_object_paths[0], "snapshot_name": snap_name}, + ) + ) + + file2 = "file2.txt" + with open(os.path.join(mountdir, file2), encoding="utf-8", mode="w") as fd: + print(file2, file=fd) + + Filesystem.Properties.MergeScheduled.set(get_object(snap_object_path), True) + mountcxt.umount() + + self.assertTrue(os.path.exists(f"/dev/stratis/{pool_name}/{snap_name}")) + + with ServiceContextManager(): + self.wait_for_pools(1) + + mountcxt = libmount.Context( # pylint: disable=no-member + target=mountdir, source=filepath + ) + mountcxt.mount() + + with open(os.path.join(mountdir, file1), encoding="utf-8") as fd: + self.assertEqual(fd.read(), file1) + + with self.assertRaises(FileNotFoundError): + # pylint: disable=consider-using-with + open(os.path.join(mountdir, file2), encoding="utf-8") + + mountcxt.umount() + + self.assertFalse(os.path.exists(f"/dev/stratis/{pool_name}/{snap_name}"))