v3.0.0 f19f453

config_test.go RawHistoryFolder

1package services
2
3import (
4	"testing"
5
6	"github.com/stretchr/testify/assert"
7	"github.com/stretchr/testify/require"
8
9	"github.com/bnema/gordon/internal/domain"
10)
11
12func TestToDomainRejectsDuplicateServiceNames(t *testing.T) {
13	configs := []Config{
14		{Name: "cache", Image: "redis:7", Enabled: true},
15		{Name: "cache", Image: "redis:7", Enabled: true},
16	}
17
18	_, err := ToDomain(configs)
19
20	require.ErrorContains(t, err, "duplicate service name")
21}
22
23func TestToDomainRejectsServiceNamesWithDuplicateRuntimeIdentifier(t *testing.T) {
24	configs := []Config{
25		{Name: "cache.api", Image: "redis:7", Enabled: true},
26		{Name: "cache_api", Image: "redis:7", Enabled: true},
27	}
28
29	_, err := ToDomain(configs)
30
31	require.ErrorContains(t, err, "runtime identifier")
32}
33
34func TestConfigToDomainRejectsNonPositiveReadinessTimeout(t *testing.T) {
35	for _, timeout := range []string{"0s", "-1s"} {
36		t.Run(timeout, func(t *testing.T) {
37			cfg := Config{
38				Name:    "cache",
39				Image:   "redis:7",
40				Enabled: true,
41				Readiness: ReadinessConfig{
42					Type:    domain.StandaloneServiceReadinessTCP,
43					Timeout: timeout,
44				},
45			}
46
47			_, err := cfg.ToDomain()
48
49			require.ErrorContains(t, err, "readiness timeout")
50			require.ErrorContains(t, err, "positive")
51		})
52	}
53}
54
55func TestConfigToDomainRejectsExplicitNoCleanupAction(t *testing.T) {
56	preserveVolumes := false
57	removeContainer := false
58	cfg := Config{
59		Name:    "cache",
60		Image:   "redis:7",
61		Enabled: true,
62		Cleanup: CleanupConfig{PreserveVolumes: &preserveVolumes, RemoveContainer: &removeContainer},
63	}
64
65	_, err := cfg.ToDomain()
66
67	require.ErrorContains(t, err, "preserve_volumes=false")
68	require.ErrorContains(t, err, "remove_container=false")
69}
70
71func TestConfigToDomainMapsExplicitPublicPorts(t *testing.T) {
72	cfg := Config{
73		Name:    "game",
74		Image:   "game:latest",
75		Enabled: true,
76		Ports: []PortConfig{{
77			Name:      "rcon",
78			Container: 28016,
79			Protocol:  domain.NetworkProtocolTCP,
80			Publish:   "127.0.0.1:38016",
81			Public:    true,
82		}},
83	}
84
85	svc, err := cfg.ToDomain()
86
87	require.NoError(t, err)
88	require.Len(t, svc.Ports, 1)
89	assert.True(t, svc.Ports[0].Public)
90}
91
92func TestResolveVolumeMountsUsesExplicitVolumesAsIs(t *testing.T) {
93	explicit := []domain.StandaloneServiceVolume{
94		{Source: "rust-data", Target: "/steamcmd/rust", ReadOnly: false},
95		{Source: "/srv/config", Target: "/config", ReadOnly: true},
96	}
97
98	mounts := ResolveVolumeMounts("gordon", "rust.example.com", explicit, []string{"/ignored"})
99
100	assert.Equal(t, []ResolvedVolumeMount{
101		{Source: "rust-data", Target: "/steamcmd/rust", ReadOnly: false},
102		{Source: "/srv/config", Target: "/config", ReadOnly: true},
103	}, mounts)
104}
105
106func TestResolveVolumeMountsUsesImageDiscoveredVolumesWhenExplicitOmitted(t *testing.T) {
107	mounts := ResolveVolumeMounts("gordon", "rust.example.com", nil, []string{"/steamcmd/rust", "/var/lib/data"})
108
109	assert.Equal(t, []ResolvedVolumeMount{
110		{Source: "gordon-rust-example-com-steamcmd-rust", Target: "/steamcmd/rust", Managed: true},
111		{Source: "gordon-rust-example-com-var-lib-data", Target: "/var/lib/data", Managed: true},
112	}, mounts)
113}
114
115func TestResolveVolumeMountsReturnsEmptyForStatelessImage(t *testing.T) {
116	mounts := ResolveVolumeMounts("gordon", "stateless.example.com", nil, nil)
117
118	assert.Empty(t, mounts)
119}
120
121func TestManagedServiceVolumeNameIsDeterministicAndGordonCompatible(t *testing.T) {
122	assert.Equal(t, "gordon-rust-example-com-var-lib-data", ManagedServiceVolumeName("gordon", "rust.example.com", "/var/lib/data"))
123	assert.Equal(t, "gordon-rust-example-com-data", ManagedServiceVolumeName("gordon", "rust.example.com", "/data"))
124}

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