runtime_residency_test.go RawHistoryFolder

1package usecase
2
3import (
4	"testing"
5	"time"
6
7	"github.com/stretchr/testify/require"
8)
9
10func TestRuntimeResidencyDisabledQuitsOnLastWindow(t *testing.T) {
11	r := NewRuntimeResidency(0)
12	r.WindowOpened(time.Now())
13	decision := r.WindowClosed(time.Now())
14	require.Equal(t, ResidencyQuit, decision.Action)
15	require.False(t, r.Armed())
16}
17
18func TestRuntimeResidencyNegativeTimeoutDisables(t *testing.T) {
19	r := NewRuntimeResidency(-time.Second)
20	r.WindowOpened(time.Now())
21	require.Equal(t, ResidencyQuit, r.WindowClosed(time.Now()).Action)
22}
23
24func TestRuntimeResidencyFirstIdleArmsDeadline(t *testing.T) {
25	now := time.Now()
26	r := NewRuntimeResidency(time.Minute)
27	r.WindowOpened(now)
28	decision := r.WindowClosed(now)
29	require.Equal(t, ResidencyArm, decision.Action)
30	require.Equal(t, now.Add(time.Minute), decision.Deadline)
31	require.True(t, r.Armed())
32	gen := decision.Generation
33
34	expiry := r.HandleExpiry(now.Add(2*time.Minute), gen)
35	require.Equal(t, ResidencyQuit, expiry.Action)
36	require.False(t, r.Armed())
37}
38
39func TestRuntimeResidencyReopenCancelsDeadline(t *testing.T) {
40	now := time.Now()
41	r := NewRuntimeResidency(time.Minute)
42	r.WindowOpened(now)
43	arm := r.WindowClosed(now)
44	require.Equal(t, ResidencyArm, arm.Action)
45
46	cancel := r.WindowOpened(now)
47	require.Equal(t, ResidencyCancel, cancel.Action)
48	require.False(t, r.Armed())
49
50	stale := r.HandleExpiry(now.Add(2*time.Minute), arm.Generation)
51	require.Equal(t, ResidencyNone, stale.Action)
52}
53
54func TestRuntimeResidencyFailedReopenRestoresIdle(t *testing.T) {
55	now := time.Now()
56	r := NewRuntimeResidency(time.Minute)
57	r.WindowOpened(now)
58	require.Equal(t, ResidencyArm, r.WindowClosed(now).Action)
59
60	// Optimistic open followed by failure: the hold must not leak, idle
61	// eligibility returns.
62	r.WindowOpened(now)
63	decision := r.OpenFailed(now)
64	require.Equal(t, ResidencyArm, decision.Action)
65	require.True(t, r.Armed())
66}
67
68func TestRuntimeResidencyPopupRemainingPreventsIdle(t *testing.T) {
69	now := time.Now()
70	r := NewRuntimeResidency(time.Minute)
71	r.WindowOpened(now)
72	r.WindowOpened(now)
73	decision := r.WindowClosed(now)
74	require.Equal(t, ResidencyNone, decision.Action)
75	require.False(t, r.Armed())
76}
77
78func TestRuntimeResidencyDuplicateCloseIsIdempotent(t *testing.T) {
79	r := NewRuntimeResidency(0)
80	decision := r.WindowClosed(time.Now())
81	require.Equal(t, ResidencyQuit, decision.Action)
82	again := r.WindowClosed(time.Now())
83	require.Equal(t, ResidencyQuit, again.Action)
84}
85
86func TestRuntimeResidencyStaleExpiryIgnored(t *testing.T) {
87	now := time.Now()
88	r := NewRuntimeResidency(time.Minute)
89	r.WindowOpened(now)
90	first := r.WindowClosed(now)
91	r.WindowOpened(now)
92	second := r.WindowClosed(now)
93	require.NotEqual(t, first.Generation, second.Generation)
94
95	require.Equal(t, ResidencyNone, r.HandleExpiry(now, first.Generation).Action)
96	require.True(t, r.Armed())
97	require.Equal(t, ResidencyQuit, r.HandleExpiry(now, second.Generation).Action)
98}
99
100func TestRuntimeResidencyExplicitQuitNeverWaits(t *testing.T) {
101	now := time.Now()
102	r := NewRuntimeResidency(time.Minute)
103	r.WindowOpened(now)
104	require.Equal(t, ResidencyArm, r.WindowClosed(now).Action)
105	require.True(t, r.Armed())
106
107	decision := r.ShutdownRequested()
108	require.Equal(t, ResidencyQuit, decision.Action)
109	require.False(t, r.Armed())
110}
111
112func TestRuntimeResidencyWorkBlocksIdleUntilDrained(t *testing.T) {
113	now := time.Now()
114	r := NewRuntimeResidency(time.Minute)
115	r.WindowOpened(now)
116	r.WorkStarted(now)
117	decision := r.WindowClosed(now)
118	require.Equal(t, ResidencyNone, decision.Action)
119	require.False(t, r.Armed())
120
121	drained := r.WorkFinished(now)
122	require.Equal(t, ResidencyArm, drained.Action)
123	require.True(t, r.Armed())
124}
125
126func TestRuntimeResidencyWorkCancelsArmedDeadline(t *testing.T) {
127	now := time.Now()
128	r := NewRuntimeResidency(time.Minute)
129	r.WindowOpened(now)
130	require.Equal(t, ResidencyArm, r.WindowClosed(now).Action)
131	require.Equal(t, ResidencyCancel, r.WorkStarted(now).Action)
132	require.False(t, r.Armed())
133}

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