main 5041353

list_sessions_test.go RawHistoryFolder

1package usecase_test
2
3import (
4	"testing"
5	"time"
6
7	"github.com/bnema/dumber/internal/application/usecase"
8	"github.com/bnema/dumber/internal/domain/entity"
9	repomocks "github.com/bnema/dumber/internal/domain/repository/mocks"
10	"github.com/stretchr/testify/assert"
11	"github.com/stretchr/testify/require"
12)
13
14func TestListSessionsUseCase_Execute_ReturnsSessionsWithState(t *testing.T) {
15	ctx := testContext()
16
17	sessionRepo := repomocks.NewMockSessionRepository(t)
18	stateRepo := repomocks.NewMockSessionStateRepository(t)
19
20	endedAt := time.Now().Add(-time.Hour)
21	sessions := []*entity.Session{
22		{
23			ID:        "20251224_120000_abc1",
24			Type:      entity.SessionTypeBrowser,
25			StartedAt: time.Now().Add(-2 * time.Hour),
26			EndedAt:   &endedAt,
27		},
28		{
29			ID:        "20251224_130000_def2",
30			Type:      entity.SessionTypeBrowser,
31			StartedAt: time.Now().Add(-time.Hour),
32			EndedAt:   nil, // Active
33		},
34	}
35
36	states := []*entity.SessionState{
37		{
38			SessionID: "20251224_120000_abc1",
39			SavedAt:   time.Now().Add(-time.Hour),
40			Tabs: []entity.TabSnapshot{
41				{ID: "tab1"},
42				{ID: "tab2"},
43			},
44		},
45	}
46
47	sessionRepo.EXPECT().GetRecent(ctx, 50).Return(sessions, nil)
48	stateRepo.EXPECT().GetAllSnapshots(ctx).Return(states, nil)
49
50	uc := usecase.NewListSessionsUseCase(sessionRepo, stateRepo)
51
52	output, err := uc.Execute(ctx, "", 50)
53	require.NoError(t, err)
54	require.NotNil(t, output)
55	require.Len(t, output.Sessions, 2)
56
57	// Active session should be first (or current, but we have no current)
58	// The sorting puts active sessions before inactive
59	activeSession := output.Sessions[0]
60	assert.True(t, activeSession.IsActive)
61
62	// Check session with state has tab count
63	var sessionWithState *entity.SessionInfo
64	for i := range output.Sessions {
65		if output.Sessions[i].Session.ID == "20251224_120000_abc1" {
66			sessionWithState = &output.Sessions[i]
67			break
68		}
69	}
70	require.NotNil(t, sessionWithState)
71	assert.Equal(t, 2, sessionWithState.TabCount)
72}
73
74func TestListSessionsUseCase_GetPurgeableSessions_ReturnsOnlyInactive(t *testing.T) {
75	ctx := testContext()
76
77	sessionRepo := repomocks.NewMockSessionRepository(t)
78	stateRepo := repomocks.NewMockSessionStateRepository(t)
79
80	endedAt := time.Now().Add(-time.Hour)
81	sessions := []*entity.Session{
82		{
83			ID:        "20251224_120000_inactive1",
84			Type:      entity.SessionTypeBrowser,
85			StartedAt: time.Now().Add(-3 * time.Hour),
86			EndedAt:   &endedAt, // Ended - purgeable
87		},
88		{
89			ID:        "20251224_130000_active1",
90			Type:      entity.SessionTypeBrowser,
91			StartedAt: time.Now().Add(-time.Hour),
92			EndedAt:   nil, // Active - NOT purgeable
93		},
94		{
95			ID:        "20251224_140000_inactive2",
96			Type:      entity.SessionTypeBrowser,
97			StartedAt: time.Now().Add(-2 * time.Hour),
98			EndedAt:   &endedAt, // Ended - purgeable
99		},
100	}
101
102	sessionRepo.EXPECT().GetRecent(ctx, 1000).Return(sessions, nil)
103	stateRepo.EXPECT().GetAllSnapshots(ctx).Return(nil, nil)
104	stateRepo.EXPECT().GetTotalSnapshotsSize(ctx).Return(int64(12345), nil)
105
106	uc := usecase.NewListSessionsUseCase(sessionRepo, stateRepo)
107
108	output, err := uc.GetPurgeableSessions(ctx)
109	require.NoError(t, err)
110	require.NotNil(t, output)
111
112	// Should only have 2 inactive sessions, not the active one
113	require.Len(t, output.Sessions, 2)
114	assert.Equal(t, int64(12345), output.TotalSize)
115
116	// Verify all returned sessions are inactive
117	for _, s := range output.Sessions {
118		assert.False(t, s.Info.IsActive, "session %s should not be active", s.Info.Session.ID)
119		assert.True(t, s.Selected, "sessions should be selected by default")
120	}
121}
122
123func TestListSessionsUseCase_GetPurgeableSessions_EmptyWhenAllActive(t *testing.T) {
124	ctx := testContext()
125
126	sessionRepo := repomocks.NewMockSessionRepository(t)
127	stateRepo := repomocks.NewMockSessionStateRepository(t)
128
129	sessions := []*entity.Session{
130		{
131			ID:        "20251224_130000_active1",
132			Type:      entity.SessionTypeBrowser,
133			StartedAt: time.Now().Add(-time.Hour),
134			EndedAt:   nil, // Active
135		},
136	}
137
138	sessionRepo.EXPECT().GetRecent(ctx, 1000).Return(sessions, nil)
139	stateRepo.EXPECT().GetAllSnapshots(ctx).Return(nil, nil)
140	stateRepo.EXPECT().GetTotalSnapshotsSize(ctx).Return(int64(0), nil)
141
142	uc := usecase.NewListSessionsUseCase(sessionRepo, stateRepo)
143
144	output, err := uc.GetPurgeableSessions(ctx)
145	require.NoError(t, err)
146	require.NotNil(t, output)
147	require.Empty(t, output.Sessions)
148}
149
150func TestListSessionsUseCase_GetPurgeableSessions_HandlesGetSizeError(t *testing.T) {
151	ctx := testContext()
152
153	sessionRepo := repomocks.NewMockSessionRepository(t)
154	stateRepo := repomocks.NewMockSessionStateRepository(t)
155
156	endedAt := time.Now().Add(-time.Hour)
157	sessions := []*entity.Session{
158		{
159			ID:        "20251224_120000_inactive1",
160			Type:      entity.SessionTypeBrowser,
161			StartedAt: time.Now().Add(-2 * time.Hour),
162			EndedAt:   &endedAt,
163		},
164	}
165
166	sessionRepo.EXPECT().GetRecent(ctx, 1000).Return(sessions, nil)
167	stateRepo.EXPECT().GetAllSnapshots(ctx).Return(nil, nil)
168	stateRepo.EXPECT().GetTotalSnapshotsSize(ctx).Return(int64(0), assert.AnError)
169
170	uc := usecase.NewListSessionsUseCase(sessionRepo, stateRepo)
171
172	output, err := uc.GetPurgeableSessions(ctx)
173	// Should succeed even if size query fails
174	require.NoError(t, err)
175	require.NotNil(t, output)
176	require.Len(t, output.Sessions, 1)
177	assert.Equal(t, int64(0), output.TotalSize) // Size defaults to 0 on error
178}

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