v0.4.4 edcdd4c

containers_fake_test.go RawHistoryFolder

1// SPDX-License-Identifier: MIT
2
3package executor
4
5import (
6	"os"
7	"path/filepath"
8	"testing"
9	"time"
10)
11
12// fakeCtrDocker is a docker CLI for the container steps: it records every
13// call (one argument per line between "--" markers, like fakeDocker) and
14// answers like the real one. Behaviour is chosen by files in its directory:
15//
16//	pull_fail        N: the first N pulls fail
17//	health           words, one per inspect: starting, healthy, unhealthy
18//	create_fail      docker create exits 125
19//	exec_out         what docker exec prints
20//	exec_vars        names of variables docker exec prints ("VAR NAME=value")
21//	hang_exec        docker exec waits until it gets a signal
22type fakeCtr struct {
23	dir, bin, log string
24}
25
26func newFakeCtr(t *testing.T) *fakeCtr {
27	t.Helper()
28	d := t.TempDir()
29	f := &fakeCtr{dir: d, bin: filepath.Join(d, "docker"), log: filepath.Join(d, "calls")}
30	script := `#!/bin/sh
31D=` + d + `
32{ echo "--"; for a in "$@"; do printf "%s\n" "$a"; done; echo "ENV:CVAR=$CVAR:EMPTYV=${EMPTYV-unset}:PATH=$PATH"; } >> $D/calls
33[ "$1" = "--config" ] && { CFG=$2; shift 2; }
34hang() { if [ -f $D/hang_ignore ]; then trap '' INT; trap 'exit 143' TERM; else trap 'exit 130' INT TERM; fi; while :; do sleep 0.05; done; }
35[ -f $D/hang_$1 ] && hang
36if [ -f $D/hang_for ]; then case "$*" in *"$(cat $D/hang_for)"*) hang ;; esac; fi
37case "$1" in
38version) echo "'1.48'" ;;
39ps) case "$*" in *--quiet*) [ -f $D/created ] && cat $D/created ;; *status=running*) id=$(echo "$*" | sed 's/.*id=\([^ ]*\).*/\1/'); echo "$id Up Less than a second" ;; esac ;;
40network) if [ "$2" = rm ]; then
41    [ -f $D/netrm_fail ] && { echo "Error response from daemon: network is busy"; exit 1; }
42    [ -f $D/netrm_absent ] && { echo "Error response from daemon: network $3 not found"; exit 1; }
43  fi ;;
44login) cat > $D/login_stdin
45  if [ -f $D/lock_cfg ]; then mkdir -p $CFG/sub; : > $CFG/sub/f; chmod 500 $CFG/sub; fi ;;
46pull) if [ -f $D/pull_fail ]; then n=$(cat $D/pull_fail); if [ "$n" -gt 0 ]; then echo $((n-1)) > $D/pull_fail; echo "pull denied"; exit 1; fi; fi; echo "pulled $2" ;;
47create) [ -f $D/create_fail ] && { echo "unknown flag"; exit 125; }
48  [ -f $D/create_out ] && { cat $D/create_out; exit 0; }
49  n=$(cat $D/seq 2>/dev/null || echo 0); n=$((n+1)); echo $n > $D/seq; id=$(printf "%064d" $n); echo $id >> $D/created
50  [ -f $D/hang_create_after ] && hang
51  echo $id ;;
52start) echo "$2" ;;
53inspect) case "$*" in
54  *Healthcheck*) if [ -s $D/health ]; then w=$(head -1 $D/health); sed -i 1d $D/health; echo "$w"; fi ;;
55  *Config.Env*) printf 'HOME=/github/home\nGITHUB_ACTIONS=true\nPATH=/usr/bin:/bin\n' ;;
56  esac ;;
57port) [ -f $D/ports ] && cat $D/ports ;;
58logs) echo "service log of $3" ;;
59rm) [ -f $D/rm_fail ] && { echo "Error response from daemon: cannot remove container: boom"; exit 1; }
60  [ -f $D/rm_absent ] && { echo "Error response from daemon: No such container: $3"; exit 1; }
61  [ -f $D/created ] && { grep -v "^$3$" $D/created > $D/created.n; mv $D/created.n $D/created; }
62  echo "$3" ;;
63exec) if [ -f $D/add_path ]; then f=$(echo "$GITHUB_PATH" | sed "s#^/__w#$(cat $D/add_path)#"); echo /added >> "$f"; fi
64  [ -f $D/exec_env ] && echo "ENV GITHUB_WORKSPACE=$GITHUB_WORKSPACE RUNNER_TEMP=$RUNNER_TEMP HOME=${HOME:-<unset>} GITHUB_OUTPUT=$GITHUB_OUTPUT GITHUB_EVENT_PATH=$GITHUB_EVENT_PATH"
65  [ -f $D/exec_vars ] && for v in $(cat $D/exec_vars); do eval "echo \"VAR $v=\${$v-unset}\""; done
66  [ -f $D/hang_exec ] && { trap 'exit 130' INT TERM; while :; do sleep 0.05; done; }
67  [ -f $D/exec_out ] && cat $D/exec_out
68  if [ -f $D/exec_exit ]; then n=$(cat $D/exec_exit); [ "$n" != 0 ] && echo 0 > $D/exec_exit && exit $n; fi ;;
69esac
70exit 0
71`
72	if err := os.WriteFile(f.bin, []byte(script), 0o755); err != nil {
73		t.Fatal(err)
74	}
75	return f
76}
77
78func (f *fakeCtr) set(t *testing.T, name, content string) {
79	t.Helper()
80	if err := os.WriteFile(filepath.Join(f.dir, name), []byte(content), 0o644); err != nil {
81		t.Fatal(err)
82	}
83}
84
85func (f *fakeCtr) calls(t *testing.T) [][]string { return calls(t, f.log) }
86
87// verbs are the docker subcommands called, in order.
88func (f *fakeCtr) verbs(t *testing.T) []string {
89	var out []string
90	for _, c := range f.calls(t) {
91		if c[0] == "--config" && len(c) > 2 {
92			c = c[2:]
93		}
94		v := c[0]
95		if v == "network" && len(c) > 1 {
96			v += " " + c[1]
97		}
98		out = append(out, v)
99	}
100	return out
101}
102
103// ctrRun runs a workflow whose job has the given container/services YAML.
104func ctrRun(t *testing.T, f *fakeCtr, jobYAML, steps string, tweak func(*Config)) (*recorder, Result) {
105	t.Helper()
106	return ctrRunC(t, f, nil, jobYAML, steps, tweak)
107}
108
109func ctrRunC(t *testing.T, f *fakeCtr, cancel *Canceller, jobYAML, steps string, tweak func(*Config)) (*recorder, Result) {
110	t.Helper()
111	needTools(t, "bash")
112	return runLocalC(t, cancel, wfHead+jobYAML+"    steps:\n"+steps, "j", func(c *Config) {
113		c.Actions.DockerPath = f.bin
114		c.Actions.Backoff = func() time.Duration { return time.Millisecond }
115		c.Actions.ExternalsDir = fakeNode(t)
116		if tweak != nil {
117			tweak(c)
118		}
119	})
120}
121
122// concl is the conclusion of the step called name.
123func (r *recorder) concl(name string) Conclusion {
124	r.mu.Lock()
125	defer r.mu.Unlock()
126	for _, s := range r.steps {
127		if s.Name == name {
128			return s.Conclusion
129		}
130	}
131	return ""
132}

Keyboard shortcuts

Single-key shortcuts are on. ctrl k and esc work whatever this says.

ctrl k :
go to a section, branch, tag, file or repository
?
this list
j k
move the row cursor down / up
enter
open the row under the cursor; on Files, a directory opens or closes in place
↑ ↓ ← → home end
in the file tree (focus on a row): previous / next row, close / open a directory or go to its parent / first entry, first / last row. They never open a file
l h
on Files: open a directory or a file / close a directory or go up to its parent, then to the parent page. Elsewhere: into the side panel (on a merge request, its files) / back to the content; there j k move between its controls
g g G
first / last row
/
filter the list; on Files, find a file anywhere in the repository (esc clears, enter opens the best match)
b
switch branch or tag
g s g f g c g b g m g i g r g a
tabs: summary, files, commits, branches & tags, merge requests, issues, releases, actions (when available)
g h
home
w
wide mode: use the whole width of the screen, or not (remembered)
y
copy a permalink pinned to the commit
d u x
diff: split / unified / collapse or expand all
e E
diff: the whole file in view / every file, with the lines the hunks hide
n
merge request: next note in the diff
esc
close a dialog, leave a field

Branches 4

Tags 11

↑↓ moveenter openesc close