v3.0.0 f19f453

managed_count_test.go RawHistoryFolder

1package apps_test
2
3import (
4	"context"
5	"errors"
6	"testing"
7
8	"github.com/stretchr/testify/assert"
9	"github.com/stretchr/testify/require"
10
11	"github.com/bnema/gordon/internal/domain"
12	"github.com/bnema/gordon/internal/usecase/apps"
13)
14
15// fakeAppStateReader is an in-memory AppStateReader for lifecycle scenarios.
16type fakeAppStateReader struct {
17	active  map[string]domain.AppActive
18	stopped map[string]bool
19	listErr error
20}
21
22func newFakeAppStateReader() *fakeAppStateReader {
23	return &fakeAppStateReader{active: map[string]domain.AppActive{}, stopped: map[string]bool{}}
24}
25
26func (f *fakeAppStateReader) ListApps(context.Context) ([]string, error) {
27	if f.listErr != nil {
28		return nil, f.listErr
29	}
30	names := make([]string, 0, len(f.active))
31	for name := range f.active {
32		names = append(names, name)
33	}
34	return names, nil
35}
36
37func (f *fakeAppStateReader) LoadActive(_ context.Context, app string) (domain.AppActive, bool, error) {
38	a, ok := f.active[app]
39	return a, ok, nil
40}
41
42func (f *fakeAppStateReader) LoadIntent(_ context.Context, app string) (domain.AppStopIntent, error) {
43	return domain.AppStopIntent{App: app, Stopped: f.stopped[app]}, nil
44}
45
46func activeWith(app string, containers ...string) domain.AppActive {
47	services := map[string]domain.AppEffectiveService{}
48	for i, c := range containers {
49		services[string(rune('a'+i))] = domain.AppEffectiveService{Container: c}
50	}
51	return domain.AppActive{App: app, Services: services}
52}
53
54func TestCountManagedContainers_Lifecycle(t *testing.T) {
55	ctx := context.Background()
56	state := newFakeAppStateReader()
57	count := func() int64 {
58		t.Helper()
59		n, err := apps.CountManagedContainers(ctx, state)
60		require.NoError(t, err)
61		return n
62	}
63
64	// Boot with no apps.
65	assert.Equal(t, int64(0), count())
66
67	// Boot hydration: persisted ACTIVE state is counted immediately.
68	state.active["web"] = activeWith("web", "c1", "c2")
69	state.active["db"] = activeWith("db", "c3")
70	assert.Equal(t, int64(3), count())
71
72	// Failed deploy of a new service leaves it without a container.
73	state.active["web"] = activeWith("web", "c1", "c2", "")
74	assert.Equal(t, int64(3), count())
75
76	// Stop excludes the app; start restores it.
77	state.stopped["web"] = true
78	assert.Equal(t, int64(1), count())
79	state.stopped["web"] = false
80	assert.Equal(t, int64(3), count())
81
82	// Remove retires the app state.
83	delete(state.active, "db")
84	assert.Equal(t, int64(2), count())
85}
86
87func TestCountManagedContainers_Error(t *testing.T) {
88	state := newFakeAppStateReader()
89	state.listErr = errors.New("boom")
90	_, err := apps.CountManagedContainers(context.Background(), state)
91	require.ErrorContains(t, err, "boom")
92}

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 7

Tags 106

↑↓ moveenter openesc close