v3.3.1 31f1eec

push_integration_test.go RawHistoryFolder

1package cli
2
3import (
4	"context"
5	"fmt"
6	"io"
7	"net/http"
8	"net/http/httptest"
9	"strings"
10	"testing"
11
12	climocks "github.com/bnema/gordon/internal/adapters/in/cli/mocks"
13	"github.com/bnema/zerowrap"
14	v1 "github.com/google/go-containerregistry/pkg/v1"
15	"github.com/google/go-containerregistry/pkg/v1/random"
16	"github.com/stretchr/testify/assert"
17	"github.com/stretchr/testify/mock"
18	"github.com/stretchr/testify/require"
19
20	registryhttp "github.com/bnema/gordon/internal/adapters/in/http/registry"
21	"github.com/bnema/gordon/internal/adapters/out/filesystem"
22	"github.com/bnema/gordon/internal/domain"
23	registrysvc "github.com/bnema/gordon/internal/usecase/registry"
24	"github.com/bnema/gordon/pkg/registrypush"
25)
26
27func TestIntegration_TagAndPush_NativeRegistry(t *testing.T) {
28	t.Parallel()
29
30	ctx := context.Background()
31	harness := newCLITestRegistry(t, 95*1024*1024)
32	defer harness.Close()
33
34	img, err := random.Image(512, 1)
35	require.NoError(t, err)
36
37	registry := strings.TrimPrefix(harness.server.URL, "http://")
38	versionRef := registry + "/testapp:v1.0.0"
39	latestRef := registry + "/testapp:latest"
40
41	ops := climocks.NewMockpushImageOps(t)
42	ops.On("Tag", mock.Anything, mock.Anything, mock.Anything).Return(nil)
43	ops.On("Exists", mock.Anything, registry+"/testapp:v1.0.0").Return(true, nil)
44	ops.EXPECT().Push(mock.Anything, mock.Anything).RunAndReturn(func(ctx context.Context, ref string) error {
45		pusher := registrypush.New(
46			registrypush.WithChunkSize(256),
47			registrypush.WithTransport(harness.server.Client().Transport),
48			registrypush.WithImageSource(func(context.Context, string) (v1.Image, error) {
49				return img, nil
50			}),
51		)
52		return pusher.Push(ctx, ref)
53	})
54
55	err = tagAndPush(ctx, io.Discard, ops, imagePush{
56		Registry:   registry,
57		ImageName:  "testapp",
58		SourceRef:  versionRef,
59		Version:    "v1.0.0",
60		VersionRef: versionRef,
61		LatestRef:  latestRef,
62	})
63	require.NoError(t, err)
64
65	harness.RequireManifest(t, "v1.0.0")
66	harness.RequireManifest(t, "latest")
67	harness.RequireBlobs(ctx, t, img)
68}
69
70type cliTestRegistry struct {
71	server *httptest.Server
72}
73
74func newCLITestRegistry(t *testing.T, maxBlobChunkSize int64) *cliTestRegistry {
75	t.Helper()
76
77	log := zerowrap.Default()
78	rootDir := t.TempDir()
79
80	blobStore, err := filesystem.NewBlobStorage(rootDir, log)
81	require.NoError(t, err)
82
83	manifestStore, err := filesystem.NewManifestStorage(rootDir, log)
84	require.NoError(t, err)
85
86	svc := registrysvc.NewService(blobStore, manifestStore, cliNoopEventPublisher{})
87	handler := registryhttp.NewHandler(svc, log, maxBlobChunkSize)
88
89	return &cliTestRegistry{server: httptest.NewServer(handler)}
90}
91
92func (h *cliTestRegistry) Close() {
93	h.server.Close()
94}
95
96func (h *cliTestRegistry) RequireManifest(t *testing.T, tag string) {
97	t.Helper()
98
99	req, err := http.NewRequest(http.MethodGet, fmt.Sprintf("%s/v2/testapp/manifests/%s", h.server.URL, tag), nil)
100	require.NoError(t, err)
101
102	resp, err := h.server.Client().Do(req)
103	require.NoError(t, err)
104	defer resp.Body.Close()
105
106	assert.Equal(t, http.StatusOK, resp.StatusCode)
107}
108
109func (h *cliTestRegistry) RequireBlobs(ctx context.Context, t *testing.T, img v1.Image) {
110	t.Helper()
111
112	layers, err := img.Layers()
113	require.NoError(t, err)
114
115	for _, layer := range layers {
116		digest, digestErr := layer.Digest()
117		require.NoError(t, digestErr)
118
119		req, reqErr := http.NewRequestWithContext(ctx, http.MethodGet, fmt.Sprintf("%s/v2/testapp/blobs/%s", h.server.URL, digest.String()), nil)
120		require.NoError(t, reqErr)
121
122		resp, respErr := h.server.Client().Do(req)
123		require.NoError(t, respErr)
124		assert.Equal(t, http.StatusOK, resp.StatusCode)
125		require.NoError(t, resp.Body.Close())
126	}
127}
128
129type cliNoopEventPublisher struct{}
130
131func (cliNoopEventPublisher) Publish(domain.EventType, any) error {
132	return nil
133}

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