1#!/bin/ksh -p
2#
3# CDDL HEADER START
4#
5# This file and its contents are supplied under the terms of the
6# Common Development and Distribution License ("CDDL"), version 1.0.
7# You may only use this file in accordance with the terms of version
8# 1.0 of the CDDL.
9#
10# A full copy of the text of the CDDL should have accompanied this
11# source.  A copy is of the CDDL is also available via the Internet
12# at http://www.illumos.org/license/CDDL.
13#
14# CDDL HEADER END
15#
16
17#
18# Copyright (c) 2018 Datto Inc.
19# Copyright (c) 2019 by Delphix. All rights reserved.
20#
21
22. $STF_SUITE/include/libtest.shlib
23
24#
25# DESCRIPTION:
26#
27# STRATEGY:
28#	1. Compare JSON output formatting for a channel program to template
29#	2. Using bad command line option (-Z) gives correct error output
30#
31
32verify_runnable "both"
33
34function cleanup
35{
36	log_must zfs destroy $TESTDS
37	return 0
38}
39log_onexit cleanup
40
41log_assert "Channel programs output valid JSON"
42
43TESTDS="$TESTPOOL/zcp-json"
44log_must zfs create $TESTDS
45
46TESTZCP="/$TESTDS/zfs_rlist.zcp"
47cat > "$TESTZCP" << EOF
48	succeeded = {}
49	failed = {}
50
51	function list_recursive(root, prop)
52		for child in zfs.list.children(root) do
53			list_recursive(child, prop)
54		end
55		val, src  = zfs.get_prop(root, prop)
56		if (val == nil) then
57			failed[root] = val
58		else
59			succeeded[root] = val
60		end
61	end
62
63	args = ...
64
65	argv = args["argv"]
66
67	list_recursive(argv[1], argv[2])
68
69	results = {}
70	results["succeeded"] = succeeded
71	results["failed"] = failed
72	return results
73EOF
74
75# 1. Compare JSON output formatting for a channel program to template
76typeset -a pos_cmds=("recordsize" "type")
77typeset -a pos_cmds_out=(
78"{
79    \"return\": {
80        \"failed\": {},
81        \"succeeded\": {
82            \"$TESTDS\": 131072
83        }
84    }
85}"
86"{
87    \"return\": {
88        \"failed\": {},
89        \"succeeded\": {
90            \"$TESTDS\": \"filesystem\"
91        }
92    }
93}")
94
95#
96# N.B. json.tool is needed to guarantee consistent ordering of fields,
97# sed is needed to trim trailing space in CentOS 6's json.tool output
98#
99# As of Python 3.5 the behavior of json.tool changed to keep the order
100# the same as the input and the --sort-keys option was added.  Detect when
101# --sort-keys is supported and apply the option to ensure the expected order.
102#
103if python -m json.tool --sort-keys <<< "{}"; then
104	JSON_TOOL_CMD="python -m json.tool --sort-keys"
105else
106	JSON_TOOL_CMD="python -m json.tool"
107fi
108
109typeset -i cnt=0
110typeset cmd
111for cmd in ${pos_cmds[@]}; do
112	log_must zfs program $TESTPOOL $TESTZCP $TESTDS $cmd 2>&1
113	log_must zfs program -j $TESTPOOL $TESTZCP $TESTDS $cmd 2>&1
114	OUTPUT=$(zfs program -j $TESTPOOL $TESTZCP $TESTDS $cmd 2>&1 |
115	    $JSON_TOOL_CMD | sed 's/[[:space:]]*$//')
116	if [ "$OUTPUT" != "${pos_cmds_out[$cnt]}" ]; then
117		log_note "Got     :$OUTPUT"
118		log_note "Expected:${pos_cmds_out[$cnt]}"
119		log_fail "Unexpected channel program output";
120	fi
121	cnt=$((cnt + 1))
122done
123
124# 2. Using bad command line option (-Z) gives correct error output
125typeset -a neg_cmds=("-Z")
126typeset -a neg_cmds_out=(
127"invalid option 'Z'
128usage:
129	program [-jn] [-t <instruction limit>] [-m <memory limit (b)>]
130	    <pool> <program file> [lua args...]
131
132For the property list, run: zfs set|get
133
134For the delegated permission list, run: zfs allow|unallow")
135cnt=0
136for cmd in ${neg_cmds[@]}; do
137	log_mustnot zfs program $cmd $TESTPOOL $TESTZCP $TESTDS 2>&1
138	log_mustnot zfs program -j $cmd $TESTPOOL $TESTZCP $TESTDS 2>&1
139	OUTPUT=$(zfs program -j $cmd $TESTPOOL $TESTZCP $TESTDS 2>&1)
140	if [ "$OUTPUT" != "${neg_cmds_out[$cnt]}" ]; then
141		log_note "Got     :$OUTPUT"
142		log_note "Expected:${neg_cmds_out[$cnt]}"
143		log_fail "Unexpected channel program error output";
144	fi
145	cnt=$((cnt + 1))
146done
147
148log_pass "Channel programs output valid JSON"
149