v2.31.0-dev12 6a38a35

attachments_push_test.go RawHistoryFolder

1package cli
2
3import (
4	"bytes"
5	"context"
6	"testing"
7
8	"github.com/bnema/gordon/internal/adapters/dto"
9	climocks "github.com/bnema/gordon/internal/adapters/in/cli/mocks"
10	"github.com/bnema/gordon/internal/adapters/in/cli/remote"
11	"github.com/bnema/gordon/internal/domain"
12	"github.com/stretchr/testify/assert"
13	"github.com/stretchr/testify/mock"
14	"github.com/stretchr/testify/require"
15)
16
17type attachmentPushTestControlPlane struct {
18	findAttachmentTargets func(context.Context, string) ([]string, error)
19	getStatus             func(context.Context) (*remote.Status, error)
20}
21
22var _ ControlPlane = (*attachmentPushTestControlPlane)(nil)
23
24func (c *attachmentPushTestControlPlane) ListRoutesWithDetails(context.Context) ([]remote.RouteInfo, error) {
25	panic("unexpected call")
26}
27
28func (c *attachmentPushTestControlPlane) GetHealth(context.Context) (map[string]*remote.RouteHealth, error) {
29	panic("unexpected call")
30}
31
32func (c *attachmentPushTestControlPlane) GetRoute(context.Context, string) (*domain.Route, error) {
33	panic("unexpected call")
34}
35
36func (c *attachmentPushTestControlPlane) FindRoutesByImage(context.Context, string) ([]domain.Route, error) {
37	panic("unexpected call")
38}
39
40func (c *attachmentPushTestControlPlane) AddRoute(context.Context, domain.Route) error {
41	panic("unexpected call")
42}
43
44func (c *attachmentPushTestControlPlane) UpdateRoute(context.Context, domain.Route) error {
45	panic("unexpected call")
46}
47
48func (c *attachmentPushTestControlPlane) RemoveRoute(context.Context, string) error {
49	panic("unexpected call")
50}
51
52func (c *attachmentPushTestControlPlane) Bootstrap(context.Context, dto.BootstrapRequest) (*dto.BootstrapResponse, error) {
53	panic("unexpected call")
54}
55
56func (c *attachmentPushTestControlPlane) ListSecretsWithAttachments(context.Context, string) (*remote.SecretsListResult, error) {
57	panic("unexpected call")
58}
59
60func (c *attachmentPushTestControlPlane) SetSecrets(context.Context, string, map[string]string) error {
61	panic("unexpected call")
62}
63
64func (c *attachmentPushTestControlPlane) DeleteSecret(context.Context, string, string) error {
65	panic("unexpected call")
66}
67
68func (c *attachmentPushTestControlPlane) SetAttachmentSecrets(context.Context, string, string, map[string]string) error {
69	panic("unexpected call")
70}
71
72func (c *attachmentPushTestControlPlane) DeleteAttachmentSecret(context.Context, string, string, string) error {
73	panic("unexpected call")
74}
75
76func (c *attachmentPushTestControlPlane) GetAllAttachmentsConfig(context.Context) (map[string][]string, error) {
77	panic("unexpected call")
78}
79
80func (c *attachmentPushTestControlPlane) GetAttachmentsConfig(context.Context, string) ([]string, error) {
81	panic("unexpected call")
82}
83
84func (c *attachmentPushTestControlPlane) FindAttachmentTargetsByImage(ctx context.Context, imageName string) ([]string, error) {
85	if c.findAttachmentTargets != nil {
86		return c.findAttachmentTargets(ctx, imageName)
87	}
88	return nil, nil
89}
90
91func (c *attachmentPushTestControlPlane) AddAttachment(context.Context, string, string) error {
92	panic("unexpected call")
93}
94
95func (c *attachmentPushTestControlPlane) RemoveAttachment(context.Context, string, string) error {
96	panic("unexpected call")
97}
98
99func (c *attachmentPushTestControlPlane) GetAutoRouteAllowedDomains(context.Context) ([]string, error) {
100	panic("unexpected call")
101}
102
103func (c *attachmentPushTestControlPlane) AddAutoRouteAllowedDomain(context.Context, string) error {
104	panic("unexpected call")
105}
106
107func (c *attachmentPushTestControlPlane) RemoveAutoRouteAllowedDomain(context.Context, string) error {
108	panic("unexpected call")
109}
110
111func (c *attachmentPushTestControlPlane) GetTLSStatus(context.Context) (*dto.TLSStatusResponse, error) {
112	return &dto.TLSStatusResponse{}, nil
113}
114
115func (c *attachmentPushTestControlPlane) GetStatus(ctx context.Context) (*remote.Status, error) {
116	if c.getStatus != nil {
117		return c.getStatus(ctx)
118	}
119	panic("unexpected call")
120}
121
122func (c *attachmentPushTestControlPlane) Reload(context.Context) error {
123	panic("unexpected call")
124}
125
126func (c *attachmentPushTestControlPlane) ListNetworks(context.Context) ([]*domain.NetworkInfo, error) {
127	panic("unexpected call")
128}
129
130func (c *attachmentPushTestControlPlane) GetConfig(context.Context) (*remote.Config, error) {
131	panic("unexpected call")
132}
133
134func (c *attachmentPushTestControlPlane) DeployIntent(context.Context, string) error {
135	panic("unexpected call")
136}
137
138func (c *attachmentPushTestControlPlane) Deploy(context.Context, string) (*remote.DeployResult, error) {
139	panic("unexpected call")
140}
141
142func (c *attachmentPushTestControlPlane) Restart(context.Context, string, bool) (*remote.RestartResult, error) {
143	panic("unexpected call")
144}
145
146func (c *attachmentPushTestControlPlane) ListTags(context.Context, string) ([]string, error) {
147	panic("unexpected call")
148}
149
150func (c *attachmentPushTestControlPlane) ListBackups(context.Context, string) ([]dto.BackupJob, error) {
151	panic("unexpected call")
152}
153
154func (c *attachmentPushTestControlPlane) BackupStatus(context.Context) ([]dto.BackupJob, error) {
155	panic("unexpected call")
156}
157
158func (c *attachmentPushTestControlPlane) RunBackup(context.Context, string, string) (*dto.BackupRunResponse, error) {
159	panic("unexpected call")
160}
161
162func (c *attachmentPushTestControlPlane) DetectDatabases(context.Context, string) ([]dto.DatabaseInfo, error) {
163	panic("unexpected call")
164}
165
166func (c *attachmentPushTestControlPlane) GetProcessLogs(context.Context, int) ([]string, error) {
167	panic("unexpected call")
168}
169
170func (c *attachmentPushTestControlPlane) GetContainerLogs(context.Context, string, int) ([]string, error) {
171	panic("unexpected call")
172}
173
174func (c *attachmentPushTestControlPlane) StreamProcessLogs(context.Context, int) (<-chan string, error) {
175	panic("unexpected call")
176}
177
178func (c *attachmentPushTestControlPlane) StreamContainerLogs(context.Context, string, int) (<-chan string, error) {
179	panic("unexpected call")
180}
181
182func (c *attachmentPushTestControlPlane) ListVolumes(context.Context) ([]dto.Volume, error) {
183	panic("unexpected call")
184}
185
186func (c *attachmentPushTestControlPlane) PruneVolumes(context.Context, dto.VolumePruneRequest) (*dto.VolumePruneResponse, error) {
187	panic("unexpected call")
188}
189
190func TestResolveAttachmentImage_OneTarget(t *testing.T) {
191	cp := &attachmentPushTestControlPlane{
192		findAttachmentTargets: func(context.Context, string) ([]string, error) {
193			return []string{"app.example.com"}, nil
194		},
195		getStatus: func(context.Context) (*remote.Status, error) {
196			return &remote.Status{RegistryDomain: "registry.example.com"}, nil
197		},
198	}
199
200	registry, imageName, targets, err := resolveAttachmentImage(context.Background(), cp, "postgres")
201
202	require.NoError(t, err)
203	assert.Equal(t, "registry.example.com", registry)
204	assert.Equal(t, "postgres", imageName)
205	assert.Equal(t, []string{"app.example.com"}, targets)
206}
207
208func TestResolveAttachmentImage_MultipleTargets(t *testing.T) {
209	cp := &attachmentPushTestControlPlane{
210		findAttachmentTargets: func(context.Context, string) ([]string, error) {
211			return []string{"app.example.com", "backend"}, nil
212		},
213		getStatus: func(context.Context) (*remote.Status, error) {
214			return &remote.Status{RegistryDomain: "registry.example.com"}, nil
215		},
216	}
217
218	registry, imageName, targets, err := resolveAttachmentImage(context.Background(), cp, "redis")
219
220	require.NoError(t, err)
221	assert.Equal(t, "registry.example.com", registry)
222	assert.Equal(t, "redis", imageName)
223	assert.Equal(t, []string{"app.example.com", "backend"}, targets)
224}
225
226func TestResolveAttachmentImage_NotConfigured(t *testing.T) {
227	cp := &attachmentPushTestControlPlane{
228		findAttachmentTargets: func(context.Context, string) ([]string, error) {
229			return nil, nil
230		},
231	}
232
233	_, _, _, err := resolveAttachmentImage(context.Background(), cp, "postgres")
234
235	require.Error(t, err)
236	assert.Contains(t, err.Error(), "not configured as an attachment")
237}
238
239func TestAttachmentPushCmd_NoDeploy(t *testing.T) {
240	origResolveControlPlane := resolveControlPlaneFn
241	origDetermineVersion := determineVersionFn
242	origNewImageOps := newImageOpsFn
243	t.Cleanup(func() {
244		resolveControlPlaneFn = origResolveControlPlane
245		determineVersionFn = origDetermineVersion
246		newImageOpsFn = origNewImageOps
247	})
248
249	cp := &attachmentPushTestControlPlane{
250		findAttachmentTargets: func(context.Context, string) ([]string, error) {
251			return []string{"app.example.com"}, nil
252		},
253		getStatus: func(context.Context) (*remote.Status, error) {
254			return &remote.Status{RegistryDomain: "registry.example.com"}, nil
255		},
256	}
257
258	resolveControlPlaneFn = func(string) (*controlPlaneHandle, error) {
259		return &controlPlaneHandle{plane: cp}, nil
260	}
261	determineVersionFn = func(context.Context, string) string { return "v1.2.3" }
262	pushCalled := false
263	newImageOpsFn = func() (pushImageOps, error) {
264		m := climocks.NewMockpushImageOps(t)
265		m.On("Tag", mock.Anything, mock.Anything, mock.Anything).Return(nil)
266		m.On("Exists", mock.Anything, mock.Anything).Return(true, nil)
267		m.On("Push", mock.Anything, mock.Anything).Run(func(mock.Arguments) {
268			pushCalled = true
269		}).Return(nil)
270		return m, nil
271	}
272
273	cmd := newAttachmentsPushCmd()
274	out := new(bytes.Buffer)
275	cmd.SetOut(out)
276	cmd.SetErr(out)
277	cmd.SetArgs([]string{"postgres"})
278
279	err := cmd.Execute()
280
281	require.NoError(t, err)
282	assert.True(t, pushCalled)
283	assert.Contains(t, out.String(), "Push complete")
284}
285
286func TestAttachmentPushCmd_TaggedImageInputBuildsValidRefs(t *testing.T) {
287	origResolveControlPlane := resolveControlPlaneFn
288	origDetermineVersion := determineVersionFn
289	origNewImageOps := newImageOpsFn
290	t.Cleanup(func() {
291		resolveControlPlaneFn = origResolveControlPlane
292		determineVersionFn = origDetermineVersion
293		newImageOpsFn = origNewImageOps
294	})
295
296	cp := &attachmentPushTestControlPlane{
297		findAttachmentTargets: func(context.Context, string) ([]string, error) {
298			return []string{"app.example.com"}, nil
299		},
300		getStatus: func(context.Context) (*remote.Status, error) {
301			return &remote.Status{RegistryDomain: "registry.example.com"}, nil
302		},
303	}
304
305	resolveControlPlaneFn = func(string) (*controlPlaneHandle, error) {
306		return &controlPlaneHandle{plane: cp}, nil
307	}
308	determineVersionFn = func(context.Context, string) string { return "v1.2.3" }
309
310	var gotVersionRef string
311	var gotLatestRef string
312	newImageOpsFn = func() (pushImageOps, error) {
313		m := climocks.NewMockpushImageOps(t)
314		m.On("Tag", mock.Anything, mock.Anything, mock.Anything).Return(nil)
315		m.On("Exists", mock.Anything, mock.Anything).Return(true, nil)
316		m.On("Push", mock.Anything, mock.Anything).Run(func(args mock.Arguments) {
317			ref := args.Get(1).(string)
318			if gotVersionRef == "" {
319				gotVersionRef = ref
320			} else if gotLatestRef == "" {
321				gotLatestRef = ref
322			}
323		}).Return(nil)
324		return m, nil
325	}
326
327	cmd := newAttachmentsPushCmd()
328	cmd.SetOut(new(bytes.Buffer))
329	cmd.SetErr(new(bytes.Buffer))
330	cmd.SetArgs([]string{"postgres:18"})
331
332	err := cmd.Execute()
333
334	require.NoError(t, err)
335	assert.Equal(t, "registry.example.com/postgres:v1.2.3", gotVersionRef)
336	assert.Equal(t, "registry.example.com/postgres:latest", gotLatestRef)
337}
338
339func TestNormalizeAttachmentImageName_PreservesNamespaceWithoutRegistryHost(t *testing.T) {
340	got := normalizeAttachmentImageName("myorg/postgres:18")
341
342	assert.Equal(t, "myorg/postgres", got)
343}

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