
ATF_TEST=true
class=mirror
. $(atf_get_srcdir)/conf.sh

atf_test_case run_latest_genid cleanup
run_latest_genid_head()
{
	atf_set "descr" \
	    "Ensure that we properly select components (latest genid) during STARTING."
	atf_set "require.user" "root"
}
run_latest_genid_body()
{
	geom_atf_test_setup
	if ! error_message=$(geom_load_class_if_needed nop); then
		atf_skip "$error_message"
	fi

	f1=$(mktemp ${base}.XXXXXX)
	f2=$(mktemp ${base}.XXXXXX)
	f3=$(mktemp ${base}.XXXXXX)
	rnd1=$(mktemp ${base}.XXXXXX)
	rnd2=$(mktemp ${base}.XXXXXX)

	atf_check truncate -s 2M $f1
	atf_check truncate -s 2M $f2
	atf_check truncate -s 2M $f3
	dd if=/dev/urandom bs=512 count=1 of="$rnd1"
	dd if=/dev/urandom bs=512 count=1 of="$rnd2"

	attach_md md1 -t vnode -f ${f1}
	attach_md md2 -t vnode -f ${f2}
	attach_md md3 -t vnode -f ${f3}

	# Use a gnop for md1 just for consistency; it's not used for anything.
	atf_check gnop create $md1
	atf_check gnop create $md2
	atf_check gnop create $md3
	# Hardcode component names so that the non-.nop device isn't tasted
	# instead.
	atf_check gmirror label -h $name ${md1}.nop
	devwait

	atf_check gmirror insert -h $name ${md2}.nop
	atf_check gmirror insert -h $name ${md3}.nop
	syncwait

	# Fail mirror 3, writing known contents to mirror 1+2 block 1
	atf_check -s exit:0 -e empty -o empty \
	    gnop configure -w 100 ${md3}.nop
	atf_check -s exit:0 dd if="$rnd1" bs=512 count=1 oseek=1 conv=notrunc \
	    of=/dev/mirror/$name status=none

	disconnectwait nop "${md3}.nop"

	# Should have two mirrors remaining after md3 was evicted
	atf_check [ $(gmirror status -s $name | wc -l) -eq 2 ]
	atf_check -s exit:0 -o match:"DEGRADED  ${md1}.nop \(ACTIVE\)" \
		gmirror status -s $name
	atf_check -s exit:0 -o match:"DEGRADED  ${md2}.nop \(ACTIVE\)" \
		gmirror status -s $name

	# Repeat:
	# Fail mirror 2, writing known contents to mirror 1 block 2
	atf_check -s exit:0 -e empty -o empty \
	    gnop configure -w 100 ${md2}.nop
	atf_check -s exit:0 dd if="$rnd2" bs=512 count=2 oseek=1 conv=notrunc \
	    of=/dev/mirror/$name status=none

	disconnectwait nop "${md2}.nop"

	# Should have one mirror remaining after md2 was evicted
	atf_check [ $(gmirror status -s $name | wc -l) -eq 1 ]
	atf_check -s exit:0 -o match:"DEGRADED  ${md1}.nop \(ACTIVE\)" \
		gmirror status -s $name

	# Stop the mirror and remove the pieces so gmirror can't see them.
	atf_check gmirror stop $name
	atf_check gnop destroy ${md1}.nop
	atf_check gnop destroy ${md2}.nop
	atf_check gnop destroy ${md3}.nop

	# Rebuild; spin up "disk" with lowest genid
	atf_check gnop create $md3
	md3gen=$(gmirror dump /dev/${md3}.nop | grep genid | cut -d: -f2)
	# Assert gmirror is referencing this component for now:
	atf_check [ $(consumerrefs nop ${md3}.nop) = "r1w1e1" ]

	# Adding newer genid should kick out old component
	atf_check gnop create $md2
	md2gen=$(gmirror dump /dev/${md2}.nop | grep genid | cut -d: -f2)
	atf_check [ $md2gen -gt $md3gen ]

	disconnectwait nop "${md3}.nop"

	# Can't test this because 'status' doesn't exist until RUNNING:
	#atf_check [ $(gmirror status -s $name | wc -l) -eq 1 ]
	# But as a substitute, assert gmirror has dropped reference to staler
	# component in favor of newer component:
	atf_check [ $(consumerrefs nop ${md2}.nop) = "r1w1e1" ]

	# ditto
	atf_check gnop create $md1
	md1gen=$(gmirror dump /dev/${md1}.nop | grep genid | cut -d: -f2)
	atf_check [ $md1gen -gt $md2gen ]

	disconnectwait nop "${md2}.nop"

	# Assert gmirror has dropped reference to stale component in favor of
	# newer component:
	atf_check [ $(consumerrefs nop ${md1}.nop) = "r1w1e1" ]

	# gmirror won't start the mirror automatically with only one component
	# ($md0) of configured three, so this waits out the
	# kern.geom.mirror.timeout:
	devwait

	atf_check [ $(gmirror status -s $name | wc -l) -eq 1 ]
	atf_check -s exit:0 -o match:"DEGRADED  ${md1}.nop \(ACTIVE\)" \
		gmirror status -s $name
}
run_latest_genid_cleanup()
{
	. $(atf_get_srcdir)/conf.sh

	if [ -f "$TEST_MDS_FILE" ]; then
		while read test_md; do
			echo "# Removing test gnop: ${test_md}.nop"
			gnop destroy -f "${test_md}.nop" 2>/dev/null || :
		done < "$TEST_MDS_FILE"
	fi
	gmirror_test_cleanup
}

atf_init_test_cases()
{
	atf_add_test_case run_latest_genid
}
