xref: /freebsd/tests/sys/geom/class/union/union_test.sh (revision 06c3fb2749bda94cb5201f81ffdb8fa6c3161b2e)
1# SPDX-License-Identifier: BSD-2-Clause
2#
3# Copyright (c) 2023 The FreeBSD Foundation
4#
5# This software was developed1 by Yan-Hao Wang <bses30074@gmail.com>
6# under sponsorship from the FreeBSD Foundation.
7#
8# Redistribution and use in source and binary forms, with or without
9# modification, are permitted provided that the following conditions
10# are met:
11# 1. Redistributions of source code must retain the above copyright
12#    notice, this list of conditions and the following disclaimer.
13# 2. Redistributions in binary form must reproduce the above copyright
14#    notice, this list of conditions and the following disclaimer in the
15#    documentation and/or other materials provided with the distribution.
16#
17# THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
18# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20# ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
21# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27# SUCH DAMAGE.
28#
29
30. $(atf_get_srcdir)/conf.sh
31
32atf_test_case create cleanup
33create_head()
34{
35    atf_set "descr" "Test gunion create and destroy"
36    atf_set "require.user" "root"
37}
38create_body()
39{
40    gunion_test_setup
41
42    attach_md upperdev -s 1m
43    attach_md lowerdev -s 1m
44    newfs -U "/dev/${lowerdev}"
45
46    atf_check gunion create "$upperdev" "$lowerdev"
47    guniondev="${upperdev}-${lowerdev}.union"
48    atf_check -o inline:"/dev/${guniondev}\n" ls "/dev/${guniondev}"
49    atf_check -o ignore fsck -p -f "/dev/${guniondev}"
50
51    atf_check gunion destroy "$guniondev"
52    atf_check -s not-exit:0 -o ignore -e ignore ls "/dev/${guniondev}"
53}
54create_cleanup()
55{
56    gunion_test_cleanup
57}
58
59atf_test_case basic cleanup
60basic_head()
61{
62    atf_set "descr" "Check gunion doesn't affect lowerdev status and lowerdev can't be mounted when being in a gunion"
63    atf_set "require.user" "root"
64}
65basic_body()
66{
67    gunion_test_setup
68
69    attach_md upperdev -s 1m
70    attach_md lowerdev -s 1m
71    newfs -U "/dev/${lowerdev}"
72    mkdir lowermnt
73    mkdir gunionmnt
74
75    mount "/dev/${lowerdev}" lowermnt
76    echo "lower file" > lower_file
77    cp lower_file lowermnt/lower_file
78    sync
79    umount lowermnt
80
81    gunion create "$upperdev" "$lowerdev"
82    guniondev="${upperdev}-${lowerdev}.union"
83    atf_check -s not-exit:0 -o ignore -e ignore mount "/dev/${lowerdev}" lowermnt
84
85    mount "/dev/${guniondev}" gunionmnt
86    echo "update lower file" >> gunionmnt/lower_file
87    echo "gunion file" > gunion_file
88    cp gunion_file gunionmnt/gunion_file
89    sync
90    umount gunionmnt
91
92    gunion destroy "$guniondev"
93    mount "/dev/${lowerdev}" lowermnt
94    checksum lowermnt/lower_file lower_file
95    atf_check -s not-exit:0  -o ignore -e ignore ls lowermnt/gunion_file
96}
97basic_cleanup()
98{
99    gunion_test_cleanup
100}
101
102atf_test_case commit cleanup
103commit_head()
104{
105    atf_set "descr" "Test basic gunion commit without option"
106    atf_set "require.user" "root"
107}
108commit_body()
109{
110    gunion_test_setup
111
112    attach_md upperdev -s 1m
113    attach_md lowerdev -s 1m
114    newfs -U "/dev/${lowerdev}"
115    mkdir lowermnt
116    mkdir gunionmnt
117
118    mount "/dev/${lowerdev}" lowermnt
119    echo "lower file" > lower_file
120    cp lower_file lowermnt/lower_file
121    sync
122    umount lowermnt
123
124    gunion create "$upperdev" "$lowerdev"
125    guniondev="${upperdev}-${lowerdev}.union"
126    mount "/dev/${guniondev}" gunionmnt
127    checksum gunionmnt/lower_file lower_file
128
129    echo "update lower file" >> lower_file
130    cp -f lower_file gunionmnt/lower_file
131    echo "gunion file" > gunion_file
132    cp gunion_file gunionmnt/gunion_file
133    sync
134    umount gunionmnt
135    atf_check gunion commit "$guniondev"
136    gunion destroy "$guniondev"
137
138    atf_check -o ignore fsck -p -f "/dev/${lowerdev}"
139    mount "/dev/${lowerdev}" lowermnt
140    checksum lowermnt/lower_file lower_file
141    checksum lowermnt/gunion_file gunion_file
142}
143commit_cleanup()
144{
145    gunion_test_cleanup
146}
147
148atf_test_case offset cleanup
149offset_head()
150{
151    atf_set "descr" "Test gunion create with -o offset option"
152    atf_set "require.user" "root"
153}
154offset_body()
155{
156    gunion_test_setup
157
158    attach_md upperdev -s 1m
159    attach_md lowerdev -s 1m
160    gpart create -s GPT "/dev/${lowerdev}"
161    gpart add -t freebsd-ufs "$lowerdev"
162    newfs "/dev/${lowerdev}p1"
163    gpt_entry_1=$(gpart show "/dev/${lowerdev}")
164    mkdir gunionmnt
165
166    secsize="$(diskinfo "/dev/${lowerdev}" | awk '{print $2}')"
167    p1_start_sector="$(gpart show -p "/dev/${lowerdev}" | grep ${lowerdev}p1 | awk '{print $1}')"
168    offset_size="$((secsize * p1_start_sector))"
169
170    gunion create -o "$offset_size" "$upperdev" "$lowerdev"
171    guniondev="${upperdev}-${lowerdev}.union"
172
173    atf_check -o ignore fsck -p -f "/dev/${guniondev}"
174    atf_check mount "/dev/${guniondev}" gunionmnt
175    umount gunionmnt
176    gunion destroy "$guniondev"
177
178    gpt_entry_2=$(gpart show "/dev/${lowerdev}")
179    atf_check_equal "$gpt_entry_1" "$gpt_entry_2"
180}
181offset_cleanup()
182{
183    gunion_test_cleanup
184}
185
186atf_test_case size cleanup
187size_head()
188{
189    atf_set "descr" "Test gunion create with -s size option"
190    atf_set "require.user" "root"
191}
192size_body()
193{
194    gunion_test_setup
195
196    attach_md upperdev -s 2m
197    attach_md lowerdev -s 1m
198    newfs -U "/dev/${lowerdev}"
199
200    gunion create -s 2m "$upperdev" "$lowerdev"
201    guniondev="${upperdev}-${lowerdev}.union"
202    echo "$guniondev" > guniondev
203
204    size="$(diskinfo "/dev/$guniondev" | awk '{print $3}')"
205    atf_check_equal "2097152" "$size" # 2 MB = 2097152 bytes
206}
207size_cleanup()
208{
209    gunion_test_cleanup
210}
211
212atf_test_case secsize cleanup
213secsize_head()
214{
215    atf_set "descr" "Test gunion create with -S secsize option"
216    atf_set "require.user" "root"
217}
218secsize_body()
219{
220    gunion_test_setup
221
222    attach_md upperdev -s 1m
223    attach_md lowerdev -s 1m
224    newfs -S 512 -U "/dev/${lowerdev}"
225    lower_secsize="$(diskinfo "/dev/${lowerdev}" | awk '{print $2}')"
226    atf_check_equal "512" "$lower_secsize"
227
228    gunion create -S 1024 "$upperdev" "$lowerdev"
229    guniondev="${upperdev}-${lowerdev}.union"
230    echo "$guniondev" > guniondev
231
232    secsize="$(diskinfo "/dev/${guniondev}" | awk '{print $2}')"
233    atf_check_equal "1024" "$secsize"
234}
235secsize_cleanup()
236{
237    gunion_test_cleanup
238}
239
240atf_test_case gunionname cleanup
241gunionname_head()
242{
243    atf_set "descr" "Test gunion create with -Z gunionname option"
244    atf_set "require.user" "root"
245}
246gunionname_body()
247{
248    gunion_test_setup
249
250    attach_md upperdev -s 1m
251    attach_md lowerdev -s 1m
252    newfs -U "/dev/${lowerdev}"
253
254    gunion create -Z gunion1 "$upperdev" "$lowerdev"
255    echo "gunion1.union" > guniondev
256    atf_check -o inline:"/dev/gunion1.union\n" ls /dev/gunion1.union
257}
258gunionname_cleanup()
259{
260    gunion_test_cleanup
261}
262
263atf_test_case revert cleanup
264revert_head()
265{
266    atf_set "descr" "Test gunion revert"
267    atf_set "require.user" "root"
268}
269revert_body()
270{
271    gunion_test_setup
272
273    attach_md upperdev -s 1m
274    attach_md lowerdev -s 1m
275    newfs -U "/dev/${lowerdev}"
276    mkdir lowermnt
277    mkdir gunionmnt
278
279    mount "/dev/${lowerdev}" lowermnt
280    echo "lower file" > lower_file
281    cp lower_file lowermnt/lower_file
282    sync
283    umount lowermnt
284
285    atf_check gunion create "$upperdev" "$lowerdev"
286    guniondev="${upperdev}-${lowerdev}.union"
287    mount "/dev/${guniondev}" gunionmnt
288
289    echo "update lower file" >> gunionmnt/lower_file
290    echo "gunion file" > gunion_file
291    cp gunion_file gunionmnt/gunion_file
292    sync
293    umount gunionmnt
294    atf_check gunion revert "$guniondev"
295
296    mount "/dev/${guniondev}" gunionmnt
297    checksum gunionmnt/lower_file lower_file
298    atf_check -s not-exit:0 -o ignore -e ignore ls gunionmnt/gunion_file
299
300    umount gunionmnt
301    gunion destroy "$guniondev"
302}
303revert_cleanup()
304{
305    gunion_test_cleanup
306}
307
308atf_init_test_cases()
309{
310    atf_add_test_case create
311    atf_add_test_case basic
312    atf_add_test_case commit
313    atf_add_test_case offset
314    atf_add_test_case size
315    atf_add_test_case secsize
316    atf_add_test_case gunionname
317    atf_add_test_case revert
318}
319
320checksum()
321{
322    src=$1
323    work=$2
324
325    if [ ! -e "$src" ]; then
326        atf_fail "file not exist"
327    fi
328    if [ ! -e "$work" ]; then
329        atf_fail "file not exist"
330    fi
331
332    src_checksum=$(md5 -q "$src")
333    work_checksum=$(md5 -q "$work")
334
335    if [ "$work_checksum" != "$src_checksum" ]; then
336        atf_fail "md5 checksum didn't match with ${src} and ${work}"
337    fi
338}
339