git: 55141f2c8991 - main - Add tests for gunion(8)

From: Li-Wen Hsu <lwhsu_at_FreeBSD.org>
Date: Thu, 16 Nov 2023 08:21:49 UTC
The branch main has been updated by lwhsu:

URL: https://cgit.FreeBSD.org/src/commit/?id=55141f2c8991b2a6adbf30bb0fe3e6cbc303f06d

commit 55141f2c8991b2a6adbf30bb0fe3e6cbc303f06d
Author:     Yan-Hao Wang <bses30074@gmail.com>
AuthorDate: 2023-11-16 07:58:49 +0000
Commit:     Li-Wen Hsu <lwhsu@FreeBSD.org>
CommitDate: 2023-11-16 08:15:33 +0000

    Add tests for gunion(8)
    
    Reviewed by:    mckusick (earlier version)
    MFC after:      3 days
    Sponsored by:   The FreeBSD Foundation
    Differential Revision:  https://reviews.freebsd.org/D41645
---
 etc/mtree/BSD.tests.dist                 |   2 +
 tests/sys/geom/class/Makefile            |   1 +
 tests/sys/geom/class/union/Makefile      |   9 +
 tests/sys/geom/class/union/conf.sh       |  40 ++++
 tests/sys/geom/class/union/union_test.sh | 338 +++++++++++++++++++++++++++++++
 5 files changed, 390 insertions(+)

diff --git a/etc/mtree/BSD.tests.dist b/etc/mtree/BSD.tests.dist
index f6f55276284a..e216767170ab 100644
--- a/etc/mtree/BSD.tests.dist
+++ b/etc/mtree/BSD.tests.dist
@@ -795,6 +795,8 @@
                 ..
                 stripe
                 ..
+                union
+                ..
                 uzip
                     etalon
                     ..
diff --git a/tests/sys/geom/class/Makefile b/tests/sys/geom/class/Makefile
index 4a21e039f185..10b01a043ddf 100644
--- a/tests/sys/geom/class/Makefile
+++ b/tests/sys/geom/class/Makefile
@@ -17,6 +17,7 @@ TESTS_SUBDIRS+=	part
 TESTS_SUBDIRS+=	raid3
 TESTS_SUBDIRS+=	shsec
 TESTS_SUBDIRS+=	stripe
+TESTS_SUBDIRS+=	union
 TESTS_SUBDIRS+=	uzip
 
 ${PACKAGE}FILES+=	geom_subr.sh
diff --git a/tests/sys/geom/class/union/Makefile b/tests/sys/geom/class/union/Makefile
new file mode 100644
index 000000000000..5ab8055fd84c
--- /dev/null
+++ b/tests/sys/geom/class/union/Makefile
@@ -0,0 +1,9 @@
+PACKAGE=	tests
+
+TESTSDIR=	${TESTSBASE}/sys/geom/class/${.CURDIR:T}
+
+ATF_TESTS_SH+=	union_test
+
+${PACKAGE}FILES+=	conf.sh
+
+.include <bsd.test.mk>
diff --git a/tests/sys/geom/class/union/conf.sh b/tests/sys/geom/class/union/conf.sh
new file mode 100644
index 000000000000..1150c7204ad3
--- /dev/null
+++ b/tests/sys/geom/class/union/conf.sh
@@ -0,0 +1,40 @@
+#!/bin/sh
+
+class="union"
+base=$(atf_get ident)
+
+attach_md()
+{
+	local test_md
+
+	test_md=$(mdconfig -a "$@") || atf_fail "failed to allocate md(4)"
+	echo $test_md >> $TEST_MDS_FILE || exit
+	echo $test_md
+}
+
+gunion_test_cleanup()
+{
+    if mount | grep -q "/gunionmnt"; then
+        umount gunionmnt
+    fi
+    if mount | grep -q "/uppermnt"; then
+        umount uppermnt
+    fi
+    if mount | grep -q "/lowermnt"; then
+        umount lowermnt
+    fi
+
+    if [ -e "guniondev" ]; then
+        gunion destroy "$(cat guniondev)"
+    fi
+
+    geom_test_cleanup
+}
+
+gunion_test_setup()
+{
+	geom_atf_test_setup
+}
+
+ATF_TEST=true
+. `dirname $0`/../geom_subr.sh
diff --git a/tests/sys/geom/class/union/union_test.sh b/tests/sys/geom/class/union/union_test.sh
new file mode 100644
index 000000000000..1872847bdf58
--- /dev/null
+++ b/tests/sys/geom/class/union/union_test.sh
@@ -0,0 +1,338 @@
+# SPDX-License-Identifier: BSD-2-Clause
+#
+# Copyright (c) 2023 The FreeBSD Foundation
+#
+# This software was developed1 by Yan-Hao Wang <bses30074@gmail.com>
+# under sponsorship from the FreeBSD Foundation.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+# 1. Redistributions of source code must retain the above copyright
+#    notice, this list of conditions and the following disclaimer.
+# 2. Redistributions in binary form must reproduce the above copyright
+#    notice, this list of conditions and the following disclaimer in the
+#    documentation and/or other materials provided with the distribution.
+#
+# THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+# ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+# SUCH DAMAGE.
+#
+
+. $(atf_get_srcdir)/conf.sh
+
+atf_test_case create cleanup
+create_head()
+{
+    atf_set "descr" "Test gunion create and destroy"
+    atf_set "require.user" "root"
+}
+create_body()
+{
+    gunion_test_setup
+
+    upperdev="$(attach_md -s 1m)"
+    lowerdev="$(attach_md -s 1m)"
+    newfs -U "/dev/${lowerdev}"
+
+    atf_check gunion create "$upperdev" "$lowerdev"
+    guniondev="${upperdev}-${lowerdev}.union"
+    atf_check -o inline:"/dev/${guniondev}\n" ls "/dev/${guniondev}"
+    atf_check -o ignore fsck -p -f "/dev/${guniondev}"
+
+    atf_check gunion destroy "$guniondev"
+    atf_check -s not-exit:0 -o ignore -e ignore ls "/dev/${guniondev}"
+}
+create_cleanup()
+{
+    gunion_test_cleanup
+}
+
+atf_test_case basic cleanup
+basic_head()
+{
+    atf_set "descr" "Check gunion doesn't affect lowerdev status and lowerdev can't be mounted when being in a gunion"
+    atf_set "require.user" "root"
+}
+basic_body()
+{
+    gunion_test_setup
+
+    upperdev="$(attach_md -s 1m)"
+    lowerdev="$(attach_md -s 1m)"
+    newfs -U "/dev/${lowerdev}"
+    mkdir lowermnt
+    mkdir gunionmnt
+
+    mount "/dev/${lowerdev}" lowermnt
+    echo "lower file" > lower_file
+    cp lower_file lowermnt/lower_file
+    sync
+    umount lowermnt
+
+    gunion create "$upperdev" "$lowerdev"
+    guniondev="${upperdev}-${lowerdev}.union"
+    atf_check -s not-exit:0 -o ignore -e ignore mount "/dev/${lowerdev}" lowermnt
+
+    mount "/dev/${guniondev}" gunionmnt
+    echo "update lower file" >> gunionmnt/lower_file
+    echo "gunion file" > gunion_file
+    cp gunion_file gunionmnt/gunion_file
+    sync
+    umount gunionmnt
+
+    gunion destroy "$guniondev"
+    mount "/dev/${lowerdev}" lowermnt
+    checksum lowermnt/lower_file lower_file
+    atf_check -s not-exit:0  -o ignore -e ignore ls lowermnt/gunion_file
+}
+basic_cleanup()
+{
+    gunion_test_cleanup
+}
+
+atf_test_case commit cleanup
+commit_head()
+{
+    atf_set "descr" "Test basic gunion commit without option"
+    atf_set "require.user" "root"
+}
+commit_body()
+{
+    gunion_test_setup
+
+    upperdev="$(attach_md -s 1m)"
+    lowerdev="$(attach_md -s 1m)"
+    newfs -U "/dev/${lowerdev}"
+    mkdir lowermnt
+    mkdir gunionmnt
+
+    mount "/dev/${lowerdev}" lowermnt
+    echo "lower file" > lower_file
+    cp lower_file lowermnt/lower_file
+    sync
+    umount lowermnt
+
+    gunion create "$upperdev" "$lowerdev"
+    guniondev="${upperdev}-${lowerdev}.union"
+    mount "/dev/${guniondev}" gunionmnt
+    checksum gunionmnt/lower_file lower_file
+
+    echo "update lower file" >> lower_file
+    cp -f lower_file gunionmnt/lower_file
+    echo "gunion file" > gunion_file
+    cp gunion_file gunionmnt/gunion_file
+    sync
+    umount gunionmnt
+    atf_check gunion commit "$guniondev"
+    gunion destroy "$guniondev"
+
+    atf_check -o ignore fsck -p -f "/dev/${lowerdev}"
+    mount "/dev/${lowerdev}" lowermnt
+    checksum lowermnt/lower_file lower_file
+    checksum lowermnt/gunion_file gunion_file
+}
+commit_cleanup()
+{
+    gunion_test_cleanup
+}
+
+atf_test_case offset cleanup
+offset_head()
+{
+    atf_set "descr" "Test gunion create with -o offset option"
+    atf_set "require.user" "root"
+}
+offset_body()
+{
+    gunion_test_setup
+
+    upperdev="$(attach_md -s 1m)"
+    lowerdev="$(attach_md -s 1m)"
+    gpart create -s GPT "/dev/${lowerdev}"
+    gpart add -t freebsd-ufs "$lowerdev"
+    newfs "/dev/${lowerdev}p1"
+    gpt_entry_1=$(gpart show "/dev/${lowerdev}")
+    mkdir gunionmnt
+
+    secsize="$(diskinfo "/dev/${lowerdev}" | awk '{print $2}')"
+    p1_start_sector="$(gpart show -p "/dev/${lowerdev}" | grep ${lowerdev}p1 | awk '{print $1}')"
+    offset_size="$((secsize * p1_start_sector))"
+
+    gunion create -o "$offset_size" "$upperdev" "$lowerdev"
+    guniondev="${upperdev}-${lowerdev}.union"
+
+    atf_check -o ignore fsck -p -f "/dev/${guniondev}"
+    atf_check mount "/dev/${guniondev}" gunionmnt
+    umount gunionmnt
+    gunion destroy "$guniondev"
+
+    gpt_entry_2=$(gpart show "/dev/${lowerdev}")
+    atf_check_equal "$gpt_entry_1" "$gpt_entry_2"
+}
+offset_cleanup()
+{
+    gunion_test_cleanup
+}
+
+atf_test_case size cleanup
+size_head()
+{
+    atf_set "descr" "Test gunion create with -s size option"
+    atf_set "require.user" "root"
+}
+size_body()
+{
+    gunion_test_setup
+
+    upperdev="$(attach_md -s 2m)"
+    lowerdev="$(attach_md -s 1m)"
+    newfs -U "/dev/${lowerdev}"
+
+    gunion create -s 2m "$upperdev" "$lowerdev"
+    guniondev="${upperdev}-${lowerdev}.union"
+    echo "$guniondev" > guniondev
+
+    size="$(diskinfo "/dev/$guniondev" | awk '{print $3}')"
+    atf_check_equal "2097152" "$size" # 2 MB = 2097152 bytes
+}
+size_cleanup()
+{
+    gunion_test_cleanup
+}
+
+atf_test_case secsize cleanup
+secsize_head()
+{
+    atf_set "descr" "Test gunion create with -S secsize option"
+    atf_set "require.user" "root"
+}
+secsize_body()
+{
+    gunion_test_setup
+
+    upperdev="$(attach_md -s 1m)"
+    lowerdev="$(attach_md -s 1m)"
+    newfs -S 512 -U "/dev/${lowerdev}"
+    lower_secsize="$(diskinfo "/dev/${lowerdev}" | awk '{print $2}')"
+    atf_check_equal "512" "$lower_secsize"
+
+    gunion create -S 1024 "$upperdev" "$lowerdev"
+    guniondev="${upperdev}-${lowerdev}.union"
+    echo "$guniondev" > guniondev
+
+    secsize="$(diskinfo "/dev/${guniondev}" | awk '{print $2}')"
+    atf_check_equal "1024" "$secsize"
+}
+secsize_cleanup()
+{
+    gunion_test_cleanup
+}
+
+atf_test_case gunionname cleanup
+gunionname_head()
+{
+    atf_set "descr" "Test gunion create with -Z gunionname option"
+    atf_set "require.user" "root"
+}
+gunionname_body()
+{
+    gunion_test_setup
+
+    upperdev="$(attach_md -s 1m)"
+    lowerdev="$(attach_md -s 1m)"
+    newfs -U "/dev/${lowerdev}"
+
+    gunion create -Z gunion1 "$upperdev" "$lowerdev"
+    echo "gunion1.union" > guniondev
+    atf_check -o inline:"/dev/gunion1.union\n" ls /dev/gunion1.union
+}
+gunionname_cleanup()
+{
+    gunion_test_cleanup
+}
+
+atf_test_case revert cleanup
+revert_head()
+{
+    atf_set "descr" "Test gunion revert"
+    atf_set "require.user" "root"
+}
+revert_body()
+{
+    gunion_test_setup
+
+    upperdev="$(attach_md -s 1m)"
+    lowerdev="$(attach_md -s 1m)"
+    newfs -U "/dev/${lowerdev}"
+    mkdir lowermnt
+    mkdir gunionmnt
+
+    mount "/dev/${lowerdev}" lowermnt
+    echo "lower file" > lower_file
+    cp lower_file lowermnt/lower_file
+    sync
+    umount lowermnt
+
+    atf_check gunion create "$upperdev" "$lowerdev"
+    guniondev="${upperdev}-${lowerdev}.union"
+    mount "/dev/${guniondev}" gunionmnt
+
+    echo "update lower file" >> gunionmnt/lower_file
+    echo "gunion file" > gunion_file
+    cp gunion_file gunionmnt/gunion_file
+    sync
+    umount gunionmnt
+    atf_check gunion revert "$guniondev"
+
+    mount "/dev/${guniondev}" gunionmnt
+    checksum gunionmnt/lower_file lower_file
+    atf_check -s not-exit:0 -o ignore -e ignore ls gunionmnt/gunion_file
+
+    umount gunionmnt
+    gunion destroy "$guniondev"
+}
+revert_cleanup()
+{
+    gunion_test_cleanup
+}
+
+atf_init_test_cases()
+{
+    atf_add_test_case create
+    atf_add_test_case basic
+    atf_add_test_case commit
+    atf_add_test_case offset
+    atf_add_test_case size
+    atf_add_test_case secsize
+    atf_add_test_case gunionname
+    atf_add_test_case revert
+}
+
+checksum()
+{
+    src=$1
+    work=$2
+
+    if [ ! -e "$src" ]; then
+        atf_fail "file not exist"
+    fi
+    if [ ! -e "$work" ]; then
+        atf_fail "file not exist"
+    fi
+
+    src_checksum=$(md5 -q "$src")
+    work_checksum=$(md5 -q "$work")
+
+    if [ "$work_checksum" != "$src_checksum" ]; then
+        atf_fail "md5 checksum didn't match with ${src} and ${work}"
+    fi
+}