v0.10.0 d5d679d

watchdog_test.go RawHistoryFolder

1package watchdog
2
3import (
4	"context"
5	"os"
6	"path/filepath"
7	"strings"
8	"sync/atomic"
9	"testing"
10	"testing/synctest"
11	"time"
12
13	"github.com/bnema/zerowrap"
14)
15
16// stuckOwnerLoop blocks like an owner goroutine that never reaches its
17// select again; the dump must name it.
18func stuckOwnerLoop(ctx context.Context, release <-chan struct{}) {
19	select {
20	case <-release:
21	case <-ctx.Done():
22	}
23}
24
25func TestStalledLoopIsDumpedOnce(t *testing.T) {
26	dir := t.TempDir()
27	synctest.Test(t, func(t *testing.T) {
28		ctx, cancel := context.WithCancel(context.Background())
29		release := make(chan struct{})
30		var answered atomic.Int32
31		probes := func() []Probe {
32			return []Probe{
33				{Name: "stuck", Ping: func() { stuckOwnerLoop(ctx, release) }},
34				{Name: "fine", Ping: func() { answered.Add(1) }},
35			}
36		}
37		done := make(chan struct{})
38		go func() {
39			defer close(done)
40			Run(ctx, probes, Options{Dir: dir, Every: 10 * time.Millisecond, Timeout: 50 * time.Millisecond, Log: zerowrap.Default()})
41		}()
42		dumps := func() []string {
43			m, _ := filepath.Glob(filepath.Join(dir, "stall-*.txt"))
44			return m
45		}
46		time.Sleep(40 * time.Millisecond)
47		synctest.Wait()
48		if d := dumps(); len(d) != 0 {
49			t.Fatalf("dumped before the timeout: %v", d)
50		}
51		time.Sleep(30 * time.Millisecond)
52		synctest.Wait()
53		d := dumps()
54		if len(d) != 1 || !strings.HasSuffix(d[0], "-stuck.txt") {
55			t.Fatalf("dumps %v", d)
56		}
57		// Still stuck: no second dump.
58		time.Sleep(time.Second)
59		synctest.Wait()
60		if again := dumps(); len(again) != 1 {
61			t.Fatalf("dumps after the first %v", again)
62		}
63		data, err := os.ReadFile(d[0])
64		if err != nil {
65			t.Fatal(err)
66		}
67		if !strings.Contains(string(data), "stuckOwnerLoop") {
68			t.Fatalf("dump does not name the stuck function:\n%s", data)
69		}
70		if n := answered.Load(); n < 50 {
71			t.Fatalf("a healthy loop was probed %d times in 1 s", n)
72		}
73		// Run waits for its probes: a stuck one ends with ctx.
74		cancel()
75		<-done
76	})
77}

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 23

Tags 10

↑↓ moveenter openesc close