#!/bin/ksh -p # # CDDL HEADER START # # This file and its contents are supplied under the terms of the # Common Development and Distribution License ("CDDL"), version 1.0. # You may only use this file in accordance with the terms of version # 1.0 of the CDDL. # # A full copy of the text of the CDDL should have accompanied this # source. A copy is of the CDDL is also available via the Internet # at http://www.illumos.org/license/CDDL. # # CDDL HEADER END # # # Copyright (c) 2018 Datto Inc. # . $STF_SUITE/include/libtest.shlib # # DESCRIPTION: # # STRATEGY: # 1. Ensure empty JSON is printed when there is no channel program output # 2. Compare JSON output formatting for a channel program to template # 3. Using bad command line option (-Z) gives correct error output # verify_runnable "both" function cleanup { log_must zfs destroy -r $TESTDS return 0 } log_onexit cleanup log_assert "Channel programs output valid JSON" TESTDS="$TESTPOOL/zcp-json" TESTSNAP="$TESTDS@snap0" log_must zfs create $TESTDS # 1. Ensure empty JSON is printed when there is no channel program output TESTZCP="/$TESTDS/zfs_destroy.zcp" cat > "$TESTZCP" << EOF args = ... argv = args["argv"] zfs.sync.destroy(argv[1]) EOF EMPTY_OUTPUT=("{}") log_must zfs snap $TESTSNAP 2>&1 log_must zfs list $TESTSNAP 2>&1 log_must zfs program $TESTPOOL $TESTZCP $TESTSNAP 2>&1 log_mustnot zfs list $TESTSNAP 2>&1 log_must zfs snap $TESTSNAP 2>&1 log_must zfs list $TESTSNAP 2>&1 log_must zfs program -j $TESTPOOL $TESTZCP $TESTSNAP 2>&1 log_mustnot zfs list $TESTSNAP 2>&1 log_must zfs snap $TESTSNAP 2>&1 log_must zfs list $TESTSNAP 2>&1 OUTPUT=$(zfs program -j $TESTPOOL $TESTZCP $TESTSNAP 2>&1) if [ "$OUTPUT" != "$EMPTY_OUTPUT" ]; then log_note "Got :$OUTPUT" log_note "Expected:$EMPTY_OUTPUT" log_fail "Channel program output not empty"; fi log_mustnot zfs list $TESTSNAP 2>&1 # 2. Compare JSON output formatting for a channel program to template TESTZCP="/$TESTDS/zfs_rlist.zcp" cat > "$TESTZCP" << EOF succeeded = {} failed = {} function list_recursive(root, prop) for child in zfs.list.children(root) do list_recursive(child, prop) end val, src = zfs.get_prop(root, prop) if (val == nil) then failed[root] = val else succeeded[root] = val end end args = ... argv = args["argv"] list_recursive(argv[1], argv[2]) results = {} results["succeeded"] = succeeded results["failed"] = failed return results EOF typeset -a pos_cmds=("recordsize" "type") typeset -a pos_cmds_out=( "{ \"return\": { \"failed\": {}, \"succeeded\": { \"$TESTDS\": 131072 } } }" "{ \"return\": { \"failed\": {}, \"succeeded\": { \"$TESTDS\": \"filesystem\" } } }") # # N.B. json.tool is needed to guarantee consistent ordering of fields, # sed is needed to trim trailing space in CentOS 6's json.tool output # # As of Python 3.5 the behavior of json.tool changed to keep the order # the same as the input and the --sort-keys option was added. Detect when # --sort-keys is supported and apply the option to ensure the expected order. # if python -m json.tool --sort-keys <<< "{}"; then JSON_TOOL_CMD="python -m json.tool --sort-keys" else JSON_TOOL_CMD="python -m json.tool" fi typeset -i cnt=0 typeset cmd for cmd in ${pos_cmds[@]}; do log_must zfs program $TESTPOOL $TESTZCP $TESTDS $cmd 2>&1 log_must zfs program -j $TESTPOOL $TESTZCP $TESTDS $cmd 2>&1 OUTPUT=$(zfs program -j $TESTPOOL $TESTZCP $TESTDS $cmd 2>&1 | $JSON_TOOL_CMD | sed 's/[[:space:]]*$//') if [ "$OUTPUT" != "${pos_cmds_out[$cnt]}" ]; then log_note "Got :$OUTPUT" log_note "Expected:${pos_cmds_out[$cnt]}" log_fail "Unexpected channel program output"; fi cnt=$((cnt + 1)) done # 3. Using bad command line option (-Z) gives correct error output typeset -a neg_cmds=("-Z") typeset -a neg_cmds_out=( "invalid option 'Z' usage: program [-jn] [-t ] [-m ] [lua args...] For the property list, run: zfs set|get For the delegated permission list, run: zfs allow|unallow") cnt=0 for cmd in ${neg_cmds[@]}; do log_mustnot zfs program $cmd $TESTPOOL $TESTZCP $TESTDS 2>&1 log_mustnot zfs program -j $cmd $TESTPOOL $TESTZCP $TESTDS 2>&1 OUTPUT=$(zfs program -j $cmd $TESTPOOL $TESTZCP $TESTDS 2>&1) if [ "$OUTPUT" != "${neg_cmds_out[$cnt]}" ]; then log_note "Got :$OUTPUT" log_note "Expected:${neg_cmds_out[$cnt]}" log_fail "Unexpected channel program error output"; fi cnt=$((cnt + 1)) done log_pass "Channel programs output valid JSON"