#!/bin/sh # One dispatcher; every fake in this directory is a symlink to it. # # The old version of this file did two things wrong, and both let real bugs # through: # # it always succeeded so no test could ever reach an installer's failure # path -- the apt and npm one-at-a-time retries, the # "did not install" report, and cmd_install's non-zero # exit were all unreachable, and all three survived # being deleted outright. # it failed OPEN the fakes were PREPENDED to $PATH, so a package # manager with no fake here fell through to the real # one. An audit of this suite invoked the host's real # `brew`. A fake that is missing must be an ERROR, not # a silent hand-off to the machine. # # The second is fixed by seal.sh, which builds a directory holding exactly the # tools a run may touch -- fakes for anything that installs, downloads or needs # root, real binaries for the pure ones -- and runs dotup under `env -i` with # that directory as the WHOLE of PATH. Anything not listed is command-not-found. # # ---------------------------------------------------------------- failure --- # FAKE_FAIL is a comma-separated list of injections: # # FAKE_FAIL=brew brew exits 1 every time # FAKE_FAIL=apt-get:batch apt-get fails only when asked for >1 package, # which is what a real "unable to locate package" # inside a batch looks like: the batch dies and # the one-at-a-time retry is the only thing that # saves the other thirty. # FAKE_FAIL=npm:batch the same shape for npm. # FAKE_FAIL=curl:deb curl fails only for the .deb download. # # Several may be combined: FAKE_FAIL=brew,apt-get:batch set -u me=${0##*/} printf '%s %s\n' "$me" "$*" >> "${DOTUP_TEST_LOG:?DOTUP_TEST_LOG unset}" # The mode this run injects for THIS tool: "always", a tool-specific word, or # empty for "behave". mode= _oldifs=$IFS IFS=, for _e in ${FAKE_FAIL:-}; do case $_e in "$me") mode=always; break ;; "$me":*) mode=${_e#*:}; break ;; esac done IFS=$_oldifs [ "$mode" = always ] && exit 1 # Count the package-ish arguments of a batch call: everything after the # subcommand that is not a flag and not the flag's value. count_pkgs() { n=0 for a in "$@"; do case $a in -*|install|update|show|get|tool|-g|-y|--*) continue ;; *=*) continue ;; esac n=$((n + 1)) done printf '%s\n' "$n" } case $me in apt-get) case ${1:-} in update) exit 0 ;; esac [ "$mode" = batch ] && [ "$(count_pkgs "$@")" -gt 1 ] && exit 1 exit 0 ;; npm) [ "$mode" = batch ] && [ "$(count_pkgs "$@")" -gt 1 ] && exit 1 exit 0 ;; apt-cache) # Stand in for a real apt cache. Two names are special, and both are real # behaviours of stock Ubuntu that the installer has to tell apart: # # gh genuinely absent -- `apt-cache policy` prints nothing. The # manifest's real example of a name that falls through to brew. # docker-ce present in the cache but with `Candidate: (none)`, because # something else Conflicts/Replaces it. `apt-cache show` exits # 0 for this, which is why the old probe kept it in the batch # and let apt refuse all thirty packages at once. case ${1:-} in policy) case ${2:-} in gh) exit 0 ;; docker-ce) printf '%s:\n Installed: (none)\n Candidate: (none)\n' "$2"; exit 0 ;; esac printf '%s:\n Installed: (none)\n Candidate: 1.0-fake\n' "$2"; exit 0 ;; esac case ${2:-} in gh) exit 100 ;; esac printf 'Package: %s\n' "${2:-}"; exit 0 ;; unzip) # `unzip -oq -d ` -- produce the one member ensure_bws looks for. d=; prev= for a in "$@"; do [ "$prev" = -d ] && { d=$a; break; }; prev=$a; done [ -n "$d" ] || exit 1 mkdir -p "$d" && printf '#!/bin/sh\necho "bws 2.1.0"\n' > "$d/bws" \ && chmod 755 "$d/bws" && exit 0 exit 1 ;; dpkg) # install_deb fills %a in a gh: asset name from this. case ${1:-} in --print-architecture) echo amd64 ;; esac exit 0 ;; chezmoi) # `chezmoi init --apply --source DIR -c CFG URL`. Produce the shape the # caller checks for -- a source tree with a .git in it -- and NOTHING else, # at the caller's umask, so a missing `chmod -R go-rwx` is visible as a mode. src=; prev= for a in "$@"; do [ "$prev" = --source ] && { src=$a; break; }; prev=$a; done [ -n "$src" ] || exit 0 mkdir -p "$src/.git" && : > "$src/.git/config" && : > "$src/README" || exit 1 exit 0 ;; curl) . "$(dirname "$0")/_curl" ;; fzf) # The picker's own fzf, and the only fake here whose ARGV is the thing # under test. `--bind` strings are built across a dozen continued lines, so # one stray comment between them silently truncates the command and the # picker draws with two binds instead of seven. Dump argv one argument per # line -- a bind that lost its continuation cannot masquerade as one that # survived -- and behave like an accept: read the piped rows, print nothing. case ${1:-} in --version) echo "${FAKE_FZF_VERSION:-9.9.9} (fake)"; exit 0 ;; esac [ -n "${FAKE_FZF_ARGV:-}" ] && printf '%s\n' "$@" > "$FAKE_FZF_ARGV" cat > /dev/null exit "${FAKE_FZF_RC:-0}" ;; esac exit 0