1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292
|
#!/usr/bin/env bash
# always set logical error behaviors, enable execution tracing later if sufficient verbosity requested
set -eu
verbosity=0
# default to silent output for naked grep; -vvv+ will adjust this
GREP_OPTS=(-q)
# shell tracing output is very large from this script; only enable if >= -vvv was passed
while getopts :v opt
do case "$opt" in
v) ((verbosity+=1)) ;;
*) ;;
esac
done
if (( verbosity >= 3 ));
then
set -x
GREP_OPTS=()
fi
echo "running playbook-backed docs tests"
ansible-playbook test.yml -i inventory "$@"
# test keyword docs
ansible-doc -t keyword -l | grep "${GREP_OPTS[@]}" 'vars_prompt: list of variables to prompt for.'
ansible-doc -t keyword vars_prompt | grep "${GREP_OPTS[@]}" 'description: list of variables to prompt for.'
ansible-doc -t keyword asldkfjaslidfhals 2>&1 | grep "${GREP_OPTS[@]}" 'Skipping invalid keyword'
echo "Check if deprecation collection name is printed"
ansible-doc --playbook-dir ./ testns.testcol.randommodule 2>&1 | grep "${GREP_OPTS[@]}" "Will be removed in: testns.testcol"
# collections testing
(
unset ANSIBLE_PLAYBOOK_DIR
export ANSIBLE_NOCOLOR=1
cd "$(dirname "$0")"
echo "test fakemodule docs from collection"
# we use sed to strip the module path from the first line
current_out="$(ansible-doc --playbook-dir ./ testns.testcol.fakemodule | sed '1 s/\(^> MODULE testns\.testcol\.fakemodule\).*(.*)$/\1/')"
expected_out="$(sed '1 s/\(^> MODULE testns\.testcol\.fakemodule\).*(.*)$/\1/' fakemodule.output)"
test "$current_out" == "$expected_out"
echo "test randommodule docs from collection"
# we use sed to strip the plugin path from the first line, and fix-urls.py to unbreak and replace URLs from stable-X branches
current_out="$(ansible-doc --playbook-dir ./ testns.testcol.randommodule | sed '1 s/\(^> MODULE testns\.testcol\.randommodule\).*(.*)$/\1/' | python fix-urls.py)"
expected_out="$(sed '1 s/\(^> MODULE testns\.testcol\.randommodule\).*(.*)$/\1/' randommodule-text.output)"
test "$current_out" == "$expected_out"
echo "test yolo filter docs from collection"
# we use sed to strip the plugin path from the first line, and fix-urls.py to unbreak and replace URLs from stable-X branches
current_out="$(ansible-doc --playbook-dir ./ testns.testcol.yolo --type test | sed '1 s/\(^> TEST testns\.testcol\.yolo\).*(.*)$/\1/' | python fix-urls.py)"
expected_out="$(sed '1 s/\(^> TEST testns\.testcol\.yolo\).*(.*)$/\1/' yolo-text.output)"
test "$current_out" == "$expected_out"
# ensure we do work with valid collection name for list
ansible-doc --list testns.testcol --playbook-dir ./ 2>&1 | grep -v "Invalid collection name"
echo "ensure we do work with valid collection name for list"
ansible-doc --list testns.testcol --playbook-dir ./ 2>&1 | grep "${GREP_OPTS[@]}" -v "Invalid collection name"
echo "ensure we dont break on invalid collection name for list"
ansible-doc --list testns.testcol.fakemodule --playbook-dir ./ 2>&1 | grep "${GREP_OPTS[@]}" "Invalid collection name"
echo "filter list with more than one collection (1/2)"
output=$(ansible-doc --list testns.testcol3 testns.testcol4 --playbook-dir ./ 2>&1 | wc -l)
test "$output" -eq 2
echo "filter list with more than one collection (2/2)"
output=$(ansible-doc --list testns.testcol testns.testcol4 --playbook-dir ./ 2>&1 | wc -l)
test "$output" -eq 5
echo "testing ansible-doc output for various plugin types"
for ptype in cache inventory lookup vars filter module
do
# each plugin type adds 1 from collection
# FIXME pre=$(ansible-doc -l -t ${ptype}|wc -l)
# FIXME post=$(ansible-doc -l -t ${ptype} --playbook-dir ./|wc -l)
# FIXME test "$pre" -eq $((post - 1))
if [ "${ptype}" == "filter" ]; then
expected=5
expected_names=("b64decode" "filter_subdir.nested" "filter_subdir.noop" "noop" "ultimatequestion")
elif [ "${ptype}" == "module" ]; then
expected=4
expected_names=("fakemodule" "notrealmodule" "randommodule" "database.database_type.subdir_module")
else
expected=1
if [ "${ptype}" == "cache" ]; then expected_names=("notjsonfile");
elif [ "${ptype}" == "inventory" ]; then expected_names=("statichost");
elif [ "${ptype}" == "lookup" ]; then expected_names=("noop");
elif [ "${ptype}" == "vars" ]; then expected_names=("noop_vars_plugin"); fi
fi
echo "testing collection-filtered list for plugin ${ptype}"
justcol=$(ansible-doc -l -t ${ptype} --playbook-dir ./ testns.testcol|wc -l)
test "$justcol" -eq "$expected"
echo "validate collection plugin name display for plugin ${ptype}"
list_result=$(ansible-doc -l -t ${ptype} --playbook-dir ./ testns.testcol)
metadata_result=$(ansible-doc --metadata-dump --no-fail-on-errors -t ${ptype} --playbook-dir ./ testns.testcol)
for name in "${expected_names[@]}"; do
echo "${list_result}" | grep "${GREP_OPTS[@]}" "testns.testcol.${name}"
echo "${metadata_result}" | grep "${GREP_OPTS[@]}" "testns.testcol.${name}"
done
# ensure we get error if passing invalid collection, much less any plugins
ansible-doc -l -t ${ptype} bogus.boguscoll 2>&1 | grep "${GREP_OPTS[@]}" "unable to locate collection"
# TODO: do we want per namespace?
# ensure we get 1 plugins when restricting namespace
#justcol=$(ansible-doc -l -t ${ptype} --playbook-dir ./ testns|wc -l)
#test "$justcol" -eq 1
done
#### test role functionality
echo "testing role text output"
# we use sed to strip the role path from the first line
current_role_out="$(ansible-doc -t role -r ./roles test_role1 | sed '1 s/\(^> ROLE: \*test_role1\*\).*(.*)$/\1/')"
expected_role_out="$(sed '1 s/\(^> ROLE: \*test_role1\*\).*(.*)$/\1/' fakerole.output)"
test "$current_role_out" == "$expected_role_out"
echo "testing multiple role entrypoints"
# Two collection roles are defined, but only 1 has a role arg spec with 2 entry points
output=$(ansible-doc -t role -l --playbook-dir . testns.testcol | wc -l)
test "$output" -eq 4
echo "test listing roles with multiple collection filters"
# Two collection roles are defined, but only 1 has a role arg spec with 2 entry points
output=$(ansible-doc -t role -l --playbook-dir . testns.testcol2 testns.testcol | wc -l)
test "$output" -eq 4
echo "testing standalone roles"
# Include normal roles (no collection filter)
output=$(ansible-doc -t role -l --playbook-dir . | wc -l)
test "$output" -eq 8
echo "testing role precedence"
# Test that a role in the playbook dir with the same name as a role in the
# 'roles' subdir of the playbook dir does not appear (lower precedence).
output=$(ansible-doc -t role -l --playbook-dir . | grep -c "test_role1 from roles subdir")
test "$output" -eq 1
output=$(ansible-doc -t role -l --playbook-dir . | grep -c "test_role1 from playbook dir" || true)
test "$output" -eq 0
echo "testing role entrypoint filter"
current_role_out="$(ansible-doc -t role --playbook-dir . testns.testcol.testrole -e alternate| sed '1 s/\(^> ROLE: \*testns\.testcol\.testrole\*\).*(.*)$/\1/')"
expected_role_out="$(sed '1 s/\(^> ROLE: \*testns\.testcol\.testrole\*\).*(.*)$/\1/' fakecollrole.output)"
test "$current_role_out" == "$expected_role_out"
)
#### test add_collection_to_versions_and_dates()
echo "testing json output"
current_out="$(ansible-doc --json --playbook-dir ./ testns.testcol.randommodule | sed 's/ *$//' | sed 's/ *"filename": "[^"]*",$//')"
expected_out="$(sed 's/ *"filename": "[^"]*",$//' randommodule.output)"
test "$current_out" == "$expected_out"
echo "testing json output 2"
current_out="$(ansible-doc --json --playbook-dir ./ testns.testcol.yolo --type test | sed 's/ *$//' | sed 's/ *"filename": "[^"]*",$//')"
expected_out="$(sed 's/ *"filename": "[^"]*",$//' yolo.output)"
test "$current_out" == "$expected_out"
current_out="$(ansible-doc --json --playbook-dir ./ -t cache testns.testcol.notjsonfile | sed 's/ *$//' | sed 's/ *"filename": "[^"]*",$//')"
expected_out="$(sed 's/ *"filename": "[^"]*",$//' notjsonfile.output)"
test "$current_out" == "$expected_out"
current_out="$(ansible-doc --json --playbook-dir ./ -t lookup testns.testcol.noop | sed 's/ *$//' | sed 's/ *"filename": "[^"]*",$//')"
expected_out="$(sed 's/ *"filename": "[^"]*",$//' noop.output)"
test "$current_out" == "$expected_out"
current_out="$(ansible-doc --json --playbook-dir ./ -t vars testns.testcol.noop_vars_plugin | sed 's/ *$//' | sed 's/ *"filename": "[^"]*",$//')"
expected_out="$(sed 's/ *"filename": "[^"]*",$//' noop_vars_plugin.output)"
test "$current_out" == "$expected_out"
echo "testing metadata dump"
# just ensure it runs
ANSIBLE_LIBRARY='./nolibrary' ansible-doc --metadata-dump --playbook-dir /dev/null 1>/dev/null 2>&1
echo "test metadata dump on broken role metadata"
mkdir -p broken-docs/collections/ansible_collections/testns/testcol/roles/testrole/meta
cat <<EOF > broken-docs/collections/ansible_collections/testns/testcol/roles/testrole/meta/main.yml
---
dependencies:
galaxy_info:
argument_specs:
main:
short_description: testns.testcol.testrole short description for main entry point
description:
- Longer description for testns.testcol.testrole main entry point.
author: Ansible Core (@ansible)
options:
opt1:
description: opt1 description
broken:
type: "str"
required: true
EOF
# ensure that --metadata-dump does not fail when --no-fail-on-errors is supplied
ANSIBLE_LIBRARY='./nolibrary' ansible-doc --metadata-dump --no-fail-on-errors --playbook-dir broken-docs testns.testcol 1>/dev/null 2>&1
# ensure that --metadata-dump does fail when --no-fail-on-errors is not supplied
output=$(ANSIBLE_LIBRARY='./nolibrary' ansible-doc --metadata-dump --playbook-dir broken-docs testns.testcol 2>&1 | grep -c 'ERROR' || true)
test "${output}" -eq 1
echo "test doc list on broken role metadata"
# ensure that role doc does not fail when --no-fail-on-errors is supplied
ANSIBLE_LIBRARY='./nolibrary' ansible-doc --no-fail-on-errors --playbook-dir broken-docs testns.testcol.testrole -t role 1>/dev/null 2>&1
# ensure that role doc does fail when --no-fail-on-errors is not supplied
output=$(ANSIBLE_LIBRARY='./nolibrary' ansible-doc --playbook-dir broken-docs testns.testcol.testrole -t role 2>&1 | grep -c 'ERROR' || true)
test "${output}" -eq 1
echo "testing legacy plugin listing"
[ "$(ansible-doc -M ./library -l ansible.legacy |wc -l)" -gt "0" ]
echo "testing legacy plugin list via --playbook-dir"
[ "$(ansible-doc -l ansible.legacy --playbook-dir ./|wc -l)" -gt "0" ]
echo "testing undocumented plugin output"
[ "$(ansible-doc -M ./library -l ansible.legacy |grep -c UNDOCUMENTED)" == "6" ]
echo "testing filtering does not include any 'test_' modules"
[ "$(ansible-doc -M ./library -l ansible.builtin |grep -c test_)" == 0 ]
[ "$(ansible-doc --playbook-dir ./ -l ansible.builtin |grep -c test_)" == 0 ]
echo "testing filtering still shows modules"
count=$(ANSIBLE_LIBRARY='./nolibrary' ansible-doc -l ansible.builtin |wc -l)
[ "${count}" -gt "0" ]
[ "$(ansible-doc -M ./library -l ansible.builtin |wc -l)" == "${count}" ]
[ "$(ansible-doc --playbook-dir ./ -l ansible.builtin |wc -l)" == "${count}" ]
echo "testing sidecar docs for jinja plugins"
[ "$(ansible-doc -t test --playbook-dir ./ testns.testcol.yolo| wc -l)" -gt "0" ]
[ "$(ansible-doc -t filter --playbook-dir ./ donothing| wc -l)" -gt "0" ]
[ "$(ansible-doc -t filter --playbook-dir ./ ansible.legacy.donothing| wc -l)" -gt "0" ]
echo "testing no docs and no sidecar"
ansible-doc -t filter --playbook-dir ./ nodocs 2>&1| grep "${GREP_OPTS[@]}" -c 'missing documentation' || true
echo "testing sidecar docs for module"
[ "$(ansible-doc -M ./library test_win_module| wc -l)" -gt "0" ]
[ "$(ansible-doc --playbook-dir ./ test_win_module| wc -l)" -gt "0" ]
echo "testing duplicate DOCUMENTATION"
[ "$(ansible-doc --playbook-dir ./ double_doc| wc -l)" -gt "0" ]
echo "testing don't break on module dir"
ansible-doc --list --module-path ./modules > /dev/null
echo "testing dedupe by fqcn and not base name"
[ "$(ansible-doc -l -t filter --playbook-dir ./ |grep -c 'b64decode')" -eq "3" ]
echo "testing no duplicates for plugins that only exist in ansible.builtin when listing ansible.legacy plugins"
[ "$(ansible-doc -l -t filter --playbook-dir ./ |grep -c 'b64encode')" -eq "1" ]
echo "testing with playbook dir, legacy should override"
ansible-doc -t filter split --playbook-dir ./ -v|grep "${GREP_OPTS[@]}" histerical
pyc_src="$(pwd)/filter_plugins/other.py"
pyc_1="$(pwd)/filter_plugins/split.pyc"
pyc_2="$(pwd)/library/notaplugin.pyc"
trap 'rm -rf "$pyc_1" "$pyc_2"' EXIT
echo "testing pyc files are not used as adjacent documentation"
python -c "import py_compile; py_compile.compile('$pyc_src', cfile='$pyc_1')"
ansible-doc -t filter split --playbook-dir ./ -v|grep "${GREP_OPTS[@]}" histerical
echo "testing pyc files are not listed as plugins"
python -c "import py_compile; py_compile.compile('$pyc_src', cfile='$pyc_2')"
test "$(ansible-doc -l -t module --playbook-dir ./ 2>&1 1>/dev/null |grep -c "notaplugin")" == 0
echo "testing without playbook dir, builtin should return"
ansible-doc -t filter split -v 2>&1 |grep "${GREP_OPTS[@]}" -v histerical
echo "test 'sidecar' for no extension module with .py doc"
[ "$(ansible-doc -M ./library -l ansible.legacy |grep -v 'UNDOCUMENTED' |grep -c bogus_facts)" == "1" ]
echo "test 'sidecar' for no extension module with .yml doc"
[ "$(ansible-doc -M ./library -l ansible.legacy |grep -v 'UNDOCUMENTED' |grep -c facts_one)" == "1" ]
echo "Test j2 plugins get jinja2 instead of path"
ansible-doc -t filter map 2>&1 |grep "${GREP_OPTS[@]}" '(Jinja2)'
|