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	    log_fail "unexpected failure getting stdout from '${cmd[@]}'"
92	datasetexists "$TESTPOOL/$TESTFS1" &&
93	    log_fail "$TESTPOOL/$TESTFS1 unexpectedly created by '${cmd[@]}'"
94	while IFS=$'\t' read -A toks; do
95		log_note "verifying ${toks[@]}"
96		case ${toks[0]} in
97		create)
98			log_must test "${#toks[@]}" -eq 2
99			log_must test "${toks[1]}" == "$ds"
100			found_create="yes, I found create"
101			;;
102		property)
103			log_must test "${#toks[@]}" -eq 3
104			typeset prop=${toks[1]}
105			typeset val=${toks[2]}
106			if [[ -z "${exp[$prop]}" ]]; then
107				log_fail "unexpectedly got property '$prop'"
108			fi
109			# We may not know the exact value a property will take
110			# on.  This is the case for at least refreservation.
111			if [[ ${exp[$prop]} != "*" ]]; then
112				log_must test "${exp[$prop]}" == "$val"
113			fi
114			unset exp[$prop]
115			;;
116		*)
117			log_fail "Unexpected line ${toks[@]}"
118			;;
119		esac
120	done <<<"$out"
121
122	log_must test "$found_create" == "yes, I found create"
123	log_must test "extra props: ${!exp[@]}" == "extra props: "
124}
125
126function cleanup
127{
128	datasetexists "$TESTPOOL/$TESTFS1" && \
129		destroy_dataset "$TESTPOOL/$TESTFS1" -r
130}
131log_onexit cleanup
132
133log_assert "zfs create -n creates nothing but can describe what would be" \
134	"created"
135
136# Typical creations should succeed
137dry_create_no_output "$TESTPOOL/$TESTFS1"
138dry_create_no_output -V 10m "$TESTPOOL/$TESTFS1"
139# It shouldn't do a space check right now
140dry_create_no_output -V 100t "$TESTPOOL/$TESTFS1"
141# It shouldn't create parent datasets either
142dry_create_no_output -p "$TESTPOOL/$TESTFS1/$TESTFS2"
143dry_create_no_output -pV 10m "$TESTPOOL/$TESTFS1/$TESTFS2"
144
145# Various invalid properties should be recognized and result in an error
146dry_create_error -o nosuchprop=42 "$TESTPOOL/$TESTFS1"
147dry_create_error -b 1234 -V 10m  "$TESTPOOL/$TESTFS1"
148
149# Parseable output should be parseable.
150typeset -A expect
151expect=([compression]=on)
152dry_create_parseable expect -o compression=on "$TESTPOOL/$TESTFS1"
153
154# Sparse volumes should not get a gratuitous refreservation
155expect=([volblocksize]=4096 [volsize]=$((1024 * 1024 * 10)))
156dry_create_parseable expect -b 4k -V 10m -s "$TESTPOOL/$TESTFS1"
157
158# Non-sparse volumes should have refreservation
159expect=(
160    [volblocksize]=4096
161    [volsize]=$((1024 * 1024 * 10))
162    [refreservation]="*"
163)
164dry_create_parseable expect -b 4k -V 10m "$TESTPOOL/$TESTFS1"
165
166log_pass "zfs create -n creates nothing but can describe what would be" \
167	"created"
168