aboutsummaryrefslogtreecommitdiffstats
path: root/tests/lib.sh
blob: 4f62890c72f3ebbdac284ecea096658f8713bc0a (plain)
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
# Helpers for preparing and checking scenarios, sourced on the machine
# populate deploys to.
set -efu

fail() {
  printf 'FAIL: %s\n' "$*" >&2
  exit 1
}

# usage: expect_eq WHAT ACTUAL EXPECTED
expect_eq() {
  if test "$2" != "$3"; then
    fail "$1: expected '$3', got '$2'"
  fi
}

nix() {
  command nix --extra-experimental-features 'nix-command flakes' "$@"
}

# Evaluates a flake output without network access to the fixtures, so all
# inputs must be in the store.  An empty cache directory keeps Nix from
# restoring inputs from its fetcher cache.
nix_eval() {
  nix_eval_cache=$(mktemp -d)
  nix_eval_status=0
  env \
      XDG_CACHE_HOME="$nix_eval_cache" \
      http_proxy=http://127.0.0.1:9 https_proxy=http://127.0.0.1:9 \
      HTTP_PROXY=http://127.0.0.1:9 HTTPS_PROXY=http://127.0.0.1:9 \
      all_proxy=http://127.0.0.1:9 ALL_PROXY=http://127.0.0.1:9 \
      no_proxy= NO_PROXY= \
    nix --extra-experimental-features 'nix-command flakes' eval --raw "$@" ||
    nix_eval_status=$?
  rm -fR "$nix_eval_cache"
  return "$nix_eval_status"
}

# Evaluates a flake output, fetching missing inputs.
nix_eval_online() {
  nix eval --raw "$@"
}

# Collects garbage if KROPS_TEST_GC is set, so evaluating afterwards checks
# that delivered store paths are registered as garbage collector roots.
gc() {
  if test -n "${KROPS_TEST_GC-}"; then
    nix-store --gc >/dev/null
  fi
}

# Canaries are files outside the target directories, which populate must
# never change, whatever the target directories contain.  Some scenarios
# point links at them.  The manifest lists every entry with its type, mode,
# and link target, and every file with its checksum.
canary_manifest() {
  {
    find /var/krops/canary /var/krops/sibling /var/krops-outside \
        -printf '%y %m %p -> %l\n'
    find /var/krops/canary /var/krops/sibling /var/krops-outside \
        -type f -exec sha256sum {} +
  } 2>&1 | sort
}

# Creates the canaries, unless they are there unchanged: a file beside the
# target directories, a directory beside them, and a directory elsewhere
# with files, a read-only directory, and a Git work tree with a changed and
# an untracked file, which resetting and cleaning would lose.
canary_setup() {
  if test -e /var/krops-outside.manifest &&
      canary_manifest | cmp -s - /var/krops-outside.manifest; then
    return
  fi
  rm -fR /var/krops/canary /var/krops/sibling /var/krops-outside
  mkdir -p /var/krops/sibling /var/krops-outside/dir/sub
  echo canary > /var/krops/canary
  echo sibling > /var/krops/sibling/file
  echo outside > /var/krops-outside/file
  echo outside > /var/krops-outside/dir/file
  echo outside > /var/krops-outside/dir/sub/file
  chmod a-w /var/krops-outside/dir/sub/file /var/krops-outside/dir/sub
  git init -q /var/krops-outside/repo
  (
    cd /var/krops-outside/repo
    echo tracked > tracked
    git add tracked
    GIT_CONFIG_GLOBAL=/dev/null GIT_CONFIG_NOSYSTEM=1 \
      git -c user.name=krops -c user.email=spam@krebsco.de commit -q -m canary
    echo changed > tracked
    echo untracked > untracked
  )
  canary_manifest > /var/krops-outside.manifest
}

# Fails if a canary changed, or if a store path that an entry of the target
# directory $T links to doesn't match its hash anymore.
canary_check() {
  if ! canary_manifest | cmp -s - /var/krops-outside.manifest; then
    canary_manifest | diff /var/krops-outside.manifest - >&2 || :
    fail "something outside the target directory changed"
  fi
  if test -n "${T-}" && test -d "$T"; then
    ls -A "$T" | while IFS= read -r canary_name; do
      canary_link=$(readlink "$T/$canary_name" 2>/dev/null) || continue
      case $canary_link in
        /nix/store/*)
          nix-store --verify-path \
              "$(printf '%s\n' "$canary_link" | cut -d/ -f1-4)" ||
            fail "$T/$canary_name links to a store path that changed"
          ;;
      esac
    done
  fi
}