1#!/bin/ksh -p
2#
3# This file and its contents are supplied under the terms of the
4# Common Development and Distribution License ("CDDL"), version 1.0.
5# You may only use this file in accordance with the terms of version
6# 1.0 of the CDDL.
7#
8# A full copy of the text of the CDDL should have accompanied this
9# source.  A copy of the CDDL is also available via the Internet at
10# http://www.illumos.org/license/CDDL.
11#
12
13#
14# Copyright 2019 Joyent, Inc.
15#
16
17. $STF_SUITE/include/libtest.shlib
18. $STF_SUITE/tests/functional/cli_root/zfs_create/zfs_create_common.kshlib
19
20#
21# DESCRIPTION:
22# zfs create -n should perform basic sanity checking but should never create a
23# dataset.  If -v and/or -P are used, it should verbose about what would be
24# created if sanity checks pass.
25#
26# STRATEGY:
27# 1. Attempt to create a file system and a volume using various combinations of
28#    -n with -v and -P.
29#
30
31verify_runnable "both"
32
33#
34# Verifies that valid commands with -n and without -[vP]:
35# - succeed
36# - do not create a dataset
37# - do not generate output
38#
39function dry_create_no_output
40{
41	typeset -a cmd=(zfs create -n "$@")
42
43	log_note "$0: ${cmd[@]}"
44	log_must "${cmd[@]}"
45	datasetexists "$TESTPOOL/$TESTFS1" &&
46	    log_fail "$TESTPOOL/$TESTFS1 unexpectedly created by '${cmd[@]}'"
47	typeset out=$("${cmd[@]}" 2>&1)
48	[[ -z "$out" ]] ||
49	    log_fail "unexpected output '$out' from '${cmd[@]}'"
50}
51
52#
53# Verifies that commands with invalid properties or invalid property values
54# - fail
55# - do not create a dataset
56# - generate a message on stderr
57#
58function dry_create_error
59{
60	typeset -a cmd=(zfs create -n "$@")
61
62	log_note "$0: ${cmd[@]}"
63	log_mustnot "${cmd[@]}"
64	datasetexists "$TESTPOOL/$TESTFS1" &&
65	    log_fail "$TESTPOOL/$TESTFS1 unexpectedly created by '${cmd[@]}'"
66	typeset out=$("${cmd[@]}" 2>&1 >/dev/null)
67	[[ -z "$out" ]] &&
68	    log_fail "expected an error message but got none from '${cmd[@]}'"
69}
70
71#
72# Verifies that dry-run commands with parseable output
73# - succeed
74# - do not create datasets
75# - generate parseable output on stdout
76# - output matches expectations
77#
78function dry_create_parseable
79{
80	typeset -n exp=$1
81	shift
82	typeset -a cmd=(zfs create -Pn "$@")
83	typeset ds=${cmd[${#cmd[@]} - 1]}
84	typeset out
85	typeset -a toks
86	typeset -a props
87	typeset found_create=false
88
89	log_note "$0: ${cmd[@]}"
90	out=$("${cmd[@]}")
91	(( $? == 0 )) ||
92	    log_fail "unexpected failure getting stdout from '${cmd[@]}'"
93	datasetexists "$TESTPOOL/$TESTFS1" &&
94	    log_fail "$TESTPOOL/$TESTFS1 unexpectedly created by '${cmd[@]}'"
95	echo "$out" | while IFS=$'\t' read -A toks; do
96		log_note "verifying ${toks[@]}"
97		case ${toks[0]} in
98		create)
99			log_must test "${#toks[@]}" -eq 2
100			log_must test "${toks[1]}" == "$ds"
101			found_create="yes, I found create"
102			;;
103		property)
104			log_must test "${#toks[@]}" -eq 3
105			typeset prop=${toks[1]}
106			typeset val=${toks[2]}
107			if [[ -z "${exp[$prop]}" ]]; then
108				log_fail "unexpectedly got property '$prop'"
109			fi
110			# We may not know the exact value a property will take
111			# on.  This is the case for at least refreservation.
112			if [[ ${exp[$prop]} != "*" ]]; then
113				log_must test "${exp[$prop]}" == "$val"
114			fi
115			unset exp[$prop]
116			;;
117		*)
118			log_fail "Unexpected line ${toks[@]}"
119			;;
120		esac
121	done
122
123	log_must test "$found_create" == "yes, I found create"
124	log_must test "extra props: ${!exp[@]}" == "extra props: "
125}
126
127function cleanup
128{
129	if datasetexists "$TESTPOOL/$TESTFS1"; then
130		log_must zfs destroy -r "$TESTPOOL/$TESTFS1"
131	fi
132}
133log_onexit cleanup
134
135log_assert "zfs create -n creates nothing but can describe what would be" \
136	"created"
137
138# Typical creations should succeed
139dry_create_no_output "$TESTPOOL/$TESTFS1"
140dry_create_no_output -V 10m "$TESTPOOL/$TESTFS1"
141# It shouldn't do a space check right now
142dry_create_no_output -V 100t "$TESTPOOL/$TESTFS1"
143# It shouldn't create parent datasets either
144dry_create_no_output -p "$TESTPOOL/$TESTFS1/$TESTFS2"
145dry_create_no_output -pV 10m "$TESTPOOL/$TESTFS1/$TESTFS2"
146
147# Various invalid properties should be recognized and result in an error
148dry_create_error -o nosuchprop=42 "$TESTPOOL/$TESTFS1"
149dry_create_error -b 1234 -V 10m  "$TESTPOOL/$TESTFS1"
150
151# Parseable output should be parseable.
152typeset -A expect
153expect=([compression]=on)
154dry_create_parseable expect -o compression=on "$TESTPOOL/$TESTFS1"
155
156# Sparse volumes should not get a gratuitous refreservation
157expect=([volblocksize]=4096 [volsize]=$((1024 * 1024 * 10)))
158dry_create_parseable expect -b 4k -V 10m -s "$TESTPOOL/$TESTFS1"
159
160# Non-sparse volumes should have refreservation
161expect=(
162    [volblocksize]=4096
163    [volsize]=$((1024 * 1024 * 10))
164    [refreservation]="*"
165)
166dry_create_parseable expect -b 4k -V 10m "$TESTPOOL/$TESTFS1"
167
168log_pass "zfs create -n creates nothing but can describe what would be" \
169	"created"
170