main 5041353

admission_gate_test.go RawHistoryFolder

1package process
2
3import (
4	"context"
5	"sync"
6	"testing"
7	"time"
8
9	"github.com/stretchr/testify/require"
10)
11
12func TestAdmissionGateAcquireRelease(t *testing.T) {
13	gate := NewAdmissionGate()
14	require.True(t, gate.Acquire())
15	require.True(t, gate.Acquire())
16	require.Equal(t, 2, gate.Active())
17	gate.Release()
18	require.Equal(t, 1, gate.Active())
19	gate.Release()
20	require.Equal(t, 0, gate.Active())
21}
22
23func TestAdmissionGateCloseStopsAdmission(t *testing.T) {
24	gate := NewAdmissionGate()
25	require.True(t, gate.Acquire())
26	gate.Close()
27	require.True(t, gate.Closed())
28	require.False(t, gate.Acquire(), "closed gate must refuse new leases")
29	require.Equal(t, 1, gate.Active(), "in-flight lease survives close")
30	gate.Release()
31	require.Equal(t, 0, gate.Active())
32}
33
34func TestAdmissionGateWaitDrained(t *testing.T) {
35	gate := NewAdmissionGate()
36	gate.Acquire()
37	done := make(chan bool, 1)
38	go func() {
39		ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
40		defer cancel()
41		done <- gate.WaitDrained(ctx)
42	}()
43	select {
44	case <-done:
45		t.Fatal("drain must not complete while a lease is held")
46	case <-time.After(50 * time.Millisecond):
47	}
48	gate.Release()
49	select {
50	case drained := <-done:
51		require.True(t, drained)
52	case <-time.After(5 * time.Second):
53		t.Fatal("drain must complete after release")
54	}
55}
56
57func TestAdmissionGateWaitDrainedExpiry(t *testing.T) {
58	gate := NewAdmissionGate()
59	gate.Acquire()
60	ctx, cancel := context.WithTimeout(context.Background(), 50*time.Millisecond)
61	defer cancel()
62	require.False(t, gate.WaitDrained(ctx), "expiry must not hang shutdown")
63	gate.Release()
64}
65
66func TestAdmissionGateOnDrained(t *testing.T) {
67	gate := NewAdmissionGate()
68	var mu sync.Mutex
69	calls := 0
70	gate.OnDrained(func() {
71		mu.Lock()
72		calls++
73		mu.Unlock()
74	})
75	gate.Acquire()
76	gate.Release()
77	mu.Lock()
78	defer mu.Unlock()
79	require.Equal(t, 1, calls)
80}
81
82func TestAdmissionGateConcurrent(t *testing.T) {
83	gate := NewAdmissionGate()
84	var wg sync.WaitGroup
85	for range 32 {
86		wg.Add(1)
87		go func() {
88			defer wg.Done()
89			if gate.Acquire() {
90				gate.Release()
91			}
92		}()
93	}
94	wg.Wait()
95	require.Equal(t, 0, gate.Active())
96}

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 8

Tags 42

↑↓ moveenter openesc close