v0.19.0 d7aa01a

resident_lease_test.go RawHistoryFolder

1package subagents
2
3import (
4	"bufio"
5	"context"
6	"errors"
7	"fmt"
8	"os"
9	"os/exec"
10	"testing"
11	"time"
12)
13
14func TestResidentJournalLeaseExcludesOtherProcess(t *testing.T) {
15	if os.Getenv("ZUT_RESIDENT_LEASE_HELPER") == "1" {
16		journal, err := OpenResidentJournal(os.Getenv("ZUT_RESIDENT_LEASE_ROOT"), "child")
17		if err != nil {
18			t.Fatal(err)
19		}
20		fmt.Fprintln(os.Stdout, "ready")
21		if _, err := bufio.NewReader(os.Stdin).ReadString('\n'); err != nil {
22			t.Fatal(err)
23		}
24		if err := journal.Close(); err != nil {
25			t.Fatal(err)
26		}
27		return
28	}
29
30	root := t.TempDir()
31	ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
32	defer cancel()
33	cmd := exec.CommandContext(ctx, os.Args[0], "-test.run=^TestResidentJournalLeaseExcludesOtherProcess$")
34	defer func() {
35		if cmd.Process != nil {
36			_ = cmd.Process.Kill()
37		}
38		_ = cmd.Wait()
39	}()
40	cmd.Env = append(os.Environ(), "ZUT_RESIDENT_LEASE_HELPER=1", "ZUT_RESIDENT_LEASE_ROOT="+root)
41	stdout, err := cmd.StdoutPipe()
42	if err != nil {
43		t.Fatal(err)
44	}
45	stdin, err := cmd.StdinPipe()
46	if err != nil {
47		t.Fatal(err)
48	}
49	if err := cmd.Start(); err != nil {
50		t.Fatal(err)
51	}
52	ready, err := bufio.NewReader(stdout).ReadString('\n')
53	if err != nil {
54		t.Fatal(err)
55	}
56	if ready != "ready\n" {
57		t.Fatalf("helper readiness = %q", ready)
58	}
59	if _, err := OpenResidentJournal(root, "child"); !errors.Is(err, ErrResidentLeaseBusy) {
60		t.Fatalf("OpenResidentJournal while other process owns lease = %v, want ErrResidentLeaseBusy", err)
61	}
62	if _, err := fmt.Fprintln(stdin); err != nil {
63		t.Fatal(err)
64	}
65	if err := stdin.Close(); err != nil {
66		t.Fatal(err)
67	}
68	if err := cmd.Wait(); err != nil {
69		t.Fatal(err)
70	}
71	journal, err := OpenResidentJournal(root, "child")
72	if err != nil {
73		t.Fatalf("OpenResidentJournal after owner exit: %v", err)
74	}
75	if err := journal.Close(); err != nil {
76		t.Fatal(err)
77	}
78}
79
80func TestResidentJournalLeaseExcludesSecondOwner(t *testing.T) {
81	root := t.TempDir()
82	first, err := OpenResidentJournal(root, "child")
83	if err != nil {
84		t.Fatal(err)
85	}
86	defer first.Close()
87	if _, err := OpenResidentJournal(root, "child"); !errors.Is(err, ErrResidentLeaseBusy) {
88		t.Fatalf("second OpenResidentJournal error = %v, want ErrResidentLeaseBusy", err)
89	}
90	if err := first.Close(); err != nil {
91		t.Fatal(err)
92	}
93	second, err := OpenResidentJournal(root, "child")
94	if err != nil {
95		t.Fatalf("OpenResidentJournal after Close: %v", err)
96	}
97	if err := second.Close(); err != nil {
98		t.Fatal(err)
99	}
100}

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 1

Tags 477

↑↓ moveenter openesc close