v2.30.1 1983e1b

json_test.go RawHistoryFolder

1package cli
2
3import (
4	"bytes"
5	"encoding/json"
6	"testing"
7	"time"
8
9	"github.com/stretchr/testify/assert"
10	"github.com/stretchr/testify/require"
11
12	"github.com/bnema/gordon/internal/adapters/dto"
13	"github.com/bnema/gordon/internal/adapters/in/cli/remote"
14	"github.com/bnema/gordon/internal/domain"
15)
16
17func TestRoutesList_JSONFlag_Accepted(t *testing.T) {
18	cmd := newRoutesListCmd()
19	f := cmd.Flags().Lookup("json")
20	assert.NotNil(t, f)
21	if f != nil {
22		assert.Equal(t, "false", f.DefValue)
23	}
24}
25
26func TestAttachmentsList_JSONFlag_Accepted(t *testing.T) {
27	cmd := newAttachmentsListCmd()
28	f := cmd.Flags().Lookup("json")
29	assert.NotNil(t, f)
30	if f != nil {
31		assert.Equal(t, "false", f.DefValue)
32	}
33}
34
35func TestSecretsList_JSONFlag_Accepted(t *testing.T) {
36	cmd := newSecretsListCmd()
37	f := cmd.Flags().Lookup("json")
38	assert.NotNil(t, f)
39	if f != nil {
40		assert.Equal(t, "false", f.DefValue)
41	}
42}
43
44func TestImagesList_JSONFlag_Accepted(t *testing.T) {
45	cmd := newImagesListCmd()
46	f := cmd.Flags().Lookup("json")
47	assert.NotNil(t, f)
48	if f != nil {
49		assert.Equal(t, "false", f.DefValue)
50	}
51}
52
53func TestBackupList_JSONFlag_Accepted(t *testing.T) {
54	cmd := newBackupListCmd()
55	f := cmd.Flags().Lookup("json")
56	assert.NotNil(t, f)
57	if f != nil {
58		assert.Equal(t, "false", f.DefValue)
59	}
60}
61
62func TestTokenList_JSONFlag_Accepted(t *testing.T) {
63	cmd := newTokenListCmd()
64	f := cmd.Flags().Lookup("json")
65	assert.NotNil(t, f)
66	if f != nil {
67		assert.Equal(t, "false", f.DefValue)
68	}
69}
70
71func TestRemotesList_JSONFlag_Accepted(t *testing.T) {
72	cmd := newRemotesListCmd()
73	f := cmd.Flags().Lookup("json")
74	assert.NotNil(t, f)
75	if f != nil {
76		assert.Equal(t, "false", f.DefValue)
77	}
78}
79
80func TestRollbackList_JSONFlag_Accepted(t *testing.T) {
81	cmd := newRollbackListCmd()
82	f := cmd.Flags().Lookup("json")
83	assert.NotNil(t, f)
84	if f != nil {
85		assert.Equal(t, "false", f.DefValue)
86	}
87}
88
89func TestImagesList_JSONShape_RoundTripsDTO(t *testing.T) {
90	createdAt := time.Date(2026, 2, 8, 12, 0, 0, 0, time.UTC)
91	images := []dto.Image{{Repository: "registry.example.com/app", Tag: "latest", Size: 12_000_000, Created: createdAt, ID: "sha256:1111", Dangling: false}}
92
93	payload, err := json.Marshal(images)
94	require.NoError(t, err)
95
96	var got []dto.Image
97	require.NoError(t, json.Unmarshal(payload, &got))
98	require.Len(t, got, 1)
99	assert.Equal(t, images[0].Repository, got[0].Repository)
100	assert.Equal(t, images[0].Tag, got[0].Tag)
101	assert.Equal(t, images[0].ID, got[0].ID)
102}
103
104func TestRollbackList_JSONShape_RoundTripsTags(t *testing.T) {
105	tags := []string{"v1.2.0", "v1.1.0"}
106	payload, err := json.Marshal(tags)
107	require.NoError(t, err)
108
109	var got []string
110	require.NoError(t, json.Unmarshal(payload, &got))
111	assert.Equal(t, tags, got)
112}
113
114func TestBackupList_JSONShape_RoundTripsJobs(t *testing.T) {
115	startedAt := time.Date(2026, 3, 1, 10, 0, 0, 0, time.UTC)
116	jobs := []domain.BackupJob{{ID: "b1", Domain: "app.example.com", DBName: "postgres", Status: domain.BackupStatusCompleted, StartedAt: startedAt}}
117
118	payload, err := json.Marshal(jobs)
119	require.NoError(t, err)
120
121	var got []domain.BackupJob
122	require.NoError(t, json.Unmarshal(payload, &got))
123	require.Len(t, got, 1)
124	assert.Equal(t, "b1", got[0].ID)
125	assert.Equal(t, "app.example.com", got[0].Domain)
126}
127
128func TestTokenList_JSONShape_RoundTripsTokens(t *testing.T) {
129	tokens := []domain.Token{{
130		ID:        "tok-1",
131		Subject:   "deploy",
132		Scopes:    []string{"admin:*:*"},
133		IssuedAt:  time.Date(2026, 3, 1, 10, 0, 0, 0, time.UTC),
134		ExpiresAt: time.Date(2026, 4, 1, 10, 0, 0, 0, time.UTC),
135	}}
136
137	payload, err := json.Marshal(tokens)
138	require.NoError(t, err)
139
140	var got []domain.Token
141	require.NoError(t, json.Unmarshal(payload, &got))
142	require.Len(t, got, 1)
143	assert.Equal(t, tokens[0].ID, got[0].ID)
144	assert.Equal(t, tokens[0].Subject, got[0].Subject)
145	assert.Equal(t, tokens[0].Scopes, got[0].Scopes)
146}
147
148func TestRemotesList_JSONShape_RoundTripsRemoteObjects(t *testing.T) {
149	items := []struct {
150		Name        string `json:"name"`
151		URL         string `json:"url"`
152		Active      bool   `json:"active"`
153		InsecureTLS bool   `json:"insecure_tls"`
154	}{
155		{Name: "prod", URL: "https://prod.example.com", Active: true, InsecureTLS: true},
156	}
157
158	payload, err := json.Marshal(items)
159	require.NoError(t, err)
160
161	var got []struct {
162		Name        string `json:"name"`
163		URL         string `json:"url"`
164		Active      bool   `json:"active"`
165		InsecureTLS bool   `json:"insecure_tls"`
166	}
167	require.NoError(t, json.Unmarshal(payload, &got))
168	require.Len(t, got, 1)
169	assert.Equal(t, "prod", got[0].Name)
170	assert.Equal(t, "https://prod.example.com", got[0].URL)
171	assert.True(t, got[0].Active)
172	assert.True(t, got[0].InsecureTLS)
173}
174
175func TestAttachmentsList_JSONShape_RoundTripsTargetPayload(t *testing.T) {
176	payload := struct {
177		Target string   `json:"target"`
178		Images []string `json:"images"`
179	}{
180		Target: "app.example.com",
181		Images: []string{"postgres:16"},
182	}
183
184	encoded, err := json.Marshal(payload)
185	require.NoError(t, err)
186
187	var got struct {
188		Target string   `json:"target"`
189		Images []string `json:"images"`
190	}
191	require.NoError(t, json.Unmarshal(encoded, &got))
192	assert.Equal(t, payload.Target, got.Target)
193	assert.Equal(t, payload.Images, got.Images)
194}
195
196func TestSecretsList_JSONShape_RoundTripsPayload(t *testing.T) {
197	payload := struct {
198		Domain      string                     `json:"domain"`
199		Keys        []string                   `json:"keys"`
200		Attachments []remote.AttachmentSecrets `json:"attachments"`
201	}{
202		Domain: "app.example.com",
203		Keys:   []string{"API_KEY"},
204		Attachments: []remote.AttachmentSecrets{{
205			Service: "postgres",
206			Keys:    []string{"POSTGRES_PASSWORD"},
207		}},
208	}
209
210	encoded, err := json.Marshal(payload)
211	require.NoError(t, err)
212
213	var got struct {
214		Domain      string                     `json:"domain"`
215		Keys        []string                   `json:"keys"`
216		Attachments []remote.AttachmentSecrets `json:"attachments"`
217	}
218	require.NoError(t, json.Unmarshal(encoded, &got))
219	assert.Equal(t, payload.Domain, got.Domain)
220	assert.Equal(t, payload.Keys, got.Keys)
221	assert.Equal(t, payload.Attachments, got.Attachments)
222}
223
224func TestSecretsList_JSONShape_NormalizesNilAttachmentsToEmptySlice(t *testing.T) {
225	payload := struct {
226		Domain      string                     `json:"domain"`
227		Keys        []string                   `json:"keys"`
228		Attachments []remote.AttachmentSecrets `json:"attachments"`
229	}{
230		Domain:      "app.example.com",
231		Keys:        []string{"API_KEY"},
232		Attachments: []remote.AttachmentSecrets{},
233	}
234
235	encoded, err := json.Marshal(payload)
236	require.NoError(t, err)
237	assert.Contains(t, string(encoded), `"attachments":[]`)
238
239	var got struct {
240		Domain      string                     `json:"domain"`
241		Keys        []string                   `json:"keys"`
242		Attachments []remote.AttachmentSecrets `json:"attachments"`
243	}
244	require.NoError(t, json.Unmarshal(encoded, &got))
245	assert.NotNil(t, got.Attachments)
246	assert.Empty(t, got.Attachments)
247}
248
249func TestRoutesList_JSONShape_RoundTripsLocalPayload(t *testing.T) {
250	payload := []struct {
251		Domain string `json:"domain"`
252		Image  string `json:"image"`
253	}{
254		{Domain: "app.example.com", Image: "app:latest"},
255	}
256
257	encoded, err := json.Marshal(payload)
258	require.NoError(t, err)
259
260	var got []struct {
261		Domain string `json:"domain"`
262		Image  string `json:"image"`
263	}
264	require.NoError(t, json.Unmarshal(encoded, &got))
265	require.Len(t, got, 1)
266	assert.Equal(t, payload[0], got[0])
267}
268
269func TestWriteJSON_ProducesValidIndentedJSON(t *testing.T) {
270	var out bytes.Buffer
271	err := writeJSON(&out, map[string]any{"ok": true})
272	require.NoError(t, err)
273
274	var got map[string]any
275	require.NoError(t, json.Unmarshal(out.Bytes(), &got))
276	assert.Equal(t, true, got["ok"])
277	assert.Contains(t, out.String(), "\n")
278}

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