1# $FreeBSD$
2
3ATF_TEST=true
4class=mirror
5. $(atf_get_srcdir)/conf.sh
6
7atf_test_case run_latest_genid cleanup
8run_latest_genid_head()
9{
10	atf_set "descr" \
11	    "Ensure that we properly select components (latest genid) during STARTING."
12	atf_set "require.user" "root"
13}
14run_latest_genid_body()
15{
16	geom_atf_test_setup
17	if ! error_message=$(geom_load_class_if_needed nop); then
18		atf_skip "$error_message"
19	fi
20
21	f1=$(mktemp ${base}.XXXXXX)
22	f2=$(mktemp ${base}.XXXXXX)
23	f3=$(mktemp ${base}.XXXXXX)
24	rnd1=$(mktemp ${base}.XXXXXX)
25	rnd2=$(mktemp ${base}.XXXXXX)
26
27	atf_check truncate -s 2M $f1
28	atf_check truncate -s 2M $f2
29	atf_check truncate -s 2M $f3
30	dd if=/dev/urandom bs=512 count=1 of="$rnd1"
31	dd if=/dev/urandom bs=512 count=1 of="$rnd2"
32
33	md1=$(attach_md -t vnode -f ${f1})
34	md2=$(attach_md -t vnode -f ${f2})
35	md3=$(attach_md -t vnode -f ${f3})
36
37	# Use a gnop for md1 just for consistency; it's not used for anything.
38	atf_check gnop create $md1
39	atf_check gnop create $md2
40	atf_check gnop create $md3
41	# Hardcode component names so that the non-.nop device isn't tasted
42	# instead.
43	atf_check gmirror label -h $name ${md1}.nop
44	devwait
45
46	atf_check gmirror insert -h $name ${md2}.nop
47	atf_check gmirror insert -h $name ${md3}.nop
48	syncwait
49
50	# Fail mirror 3, writing known contents to mirror 1+2 block 1
51	atf_check -s exit:0 -e empty -o empty \
52	    gnop configure -w 100 ${md3}.nop
53	atf_check -s exit:0 dd if="$rnd1" bs=512 count=1 oseek=1 conv=notrunc \
54	    of=/dev/mirror/$name status=none
55
56	disconnectwait nop "${md3}.nop"
57
58	# Should have two mirrors remaining after md3 was evicted
59	atf_check [ $(gmirror status -s $name | wc -l) -eq 2 ]
60	atf_check -s exit:0 -o match:"DEGRADED  ${md1}.nop \(ACTIVE\)" \
61		gmirror status -s $name
62	atf_check -s exit:0 -o match:"DEGRADED  ${md2}.nop \(ACTIVE\)" \
63		gmirror status -s $name
64
65	# Repeat:
66	# Fail mirror 2, writing known contents to mirror 1 block 2
67	atf_check -s exit:0 -e empty -o empty \
68	    gnop configure -w 100 ${md2}.nop
69	atf_check -s exit:0 dd if="$rnd2" bs=512 count=2 oseek=1 conv=notrunc \
70	    of=/dev/mirror/$name status=none
71
72	disconnectwait nop "${md2}.nop"
73
74	# Should have one mirror remaining after md2 was evicted
75	atf_check [ $(gmirror status -s $name | wc -l) -eq 1 ]
76	atf_check -s exit:0 -o match:"DEGRADED  ${md1}.nop \(ACTIVE\)" \
77		gmirror status -s $name
78
79	# Stop the mirror and remove the pieces so gmirror can't see them.
80	atf_check gmirror stop $name
81	atf_check gnop destroy ${md1}.nop
82	atf_check gnop destroy ${md2}.nop
83	atf_check gnop destroy ${md3}.nop
84
85	# Rebuild; spin up "disk" with lowest genid
86	atf_check gnop create $md3
87	md3gen=$(gmirror dump /dev/${md3}.nop | grep genid | cut -d: -f2)
88	# Assert gmirror is referencing this component for now:
89	atf_check [ $(consumerrefs nop ${md3}.nop) = "r1w1e1" ]
90
91	# Adding newer genid should kick out old component
92	atf_check gnop create $md2
93	md2gen=$(gmirror dump /dev/${md2}.nop | grep genid | cut -d: -f2)
94	atf_check [ $md2gen -gt $md3gen ]
95
96	disconnectwait nop "${md3}.nop"
97
98	# Can't test this because 'status' doesn't exist until RUNNING:
99	#atf_check [ $(gmirror status -s $name | wc -l) -eq 1 ]
100	# But as a substitute, assert gmirror has dropped reference to staler
101	# component in favor of newer component:
102	atf_check [ $(consumerrefs nop ${md2}.nop) = "r1w1e1" ]
103
104	# ditto
105	atf_check gnop create $md1
106	md1gen=$(gmirror dump /dev/${md1}.nop | grep genid | cut -d: -f2)
107	atf_check [ $md1gen -gt $md2gen ]
108
109	disconnectwait nop "${md2}.nop"
110
111	# Assert gmirror has dropped reference to stale component in favor of
112	# newer component:
113	atf_check [ $(consumerrefs nop ${md1}.nop) = "r1w1e1" ]
114
115	# gmirror won't start the mirror automatically with only one component
116	# ($md0) of configured three, so this waits out the
117	# kern.geom.mirror.timeout:
118	devwait
119
120	atf_check [ $(gmirror status -s $name | wc -l) -eq 1 ]
121	atf_check -s exit:0 -o match:"DEGRADED  ${md1}.nop \(ACTIVE\)" \
122		gmirror status -s $name
123}
124run_latest_genid_cleanup()
125{
126	. $(atf_get_srcdir)/conf.sh
127
128	if [ -f "$TEST_MDS_FILE" ]; then
129		while read test_md; do
130			echo "# Removing test gnop: ${test_md}.nop"
131			gnop destroy -f "${test_md}.nop" 2>/dev/null || :
132		done < "$TEST_MDS_FILE"
133	fi
134	gmirror_test_cleanup
135}
136
137atf_init_test_cases()
138{
139	atf_add_test_case run_latest_genid
140}
141