Skip to content

Commit 0db6bf1

Browse files
committed
add test coverage for package client
1 parent 55602d6 commit 0db6bf1

File tree

3 files changed

+81
-1
lines changed

3 files changed

+81
-1
lines changed
Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
// SPDX-FileCopyrightText: 2026 SAP SE or an SAP affiliate company
2+
// SPDX-License-Identifier: Apache-2.0
3+
4+
package client_test
5+
6+
import (
7+
"io"
8+
"testing"
9+
10+
"github.com/sapcc/go-bits/assert"
11+
"github.com/sapcc/go-bits/easypg"
12+
"github.com/sapcc/go-bits/must"
13+
14+
"github.com/sapcc/keppel/internal/client"
15+
"github.com/sapcc/keppel/internal/models"
16+
"github.com/sapcc/keppel/internal/test"
17+
)
18+
19+
func TestMain(m *testing.M) {
20+
easypg.WithTestDB(m, func() int { return m.Run() })
21+
}
22+
23+
func TestRepoClientBasic(t *testing.T) {
24+
ctx := t.Context()
25+
test.WithRoundTripper(func(tt *test.RoundTripper) {
26+
s := test.NewSetup(t,
27+
test.WithAccount(models.Account{Name: "test1", AuthTenantID: "test1authtenant"}),
28+
test.WithQuotas,
29+
)
30+
const hostName = "registry.example.org"
31+
tt.Handlers[hostName] = s.Handler
32+
s.AD.ExpectedUserName = "alice"
33+
s.AD.ExpectedPassword = "swordfish"
34+
s.AD.GrantedPermissions = "pull:test1authtenant,push:test1authtenant"
35+
36+
rc := &client.RepoClient{
37+
Scheme: "http",
38+
Host: "registry.example.org",
39+
RepoName: "test1/foo",
40+
UserName: s.AD.ExpectedUserName,
41+
Password: s.AD.ExpectedPassword,
42+
}
43+
44+
// test uploading an image using RepoClient
45+
img := test.GenerateImage(
46+
test.GenerateExampleLayer(1),
47+
)
48+
49+
digest := must.ReturnT(rc.UploadMonolithicBlob(ctx, img.Layers[0].Contents))(t)
50+
assert.Equal(t, digest, img.Layers[0].Digest)
51+
52+
digest = must.ReturnT(rc.UploadMonolithicBlob(ctx, img.Config.Contents))(t)
53+
assert.Equal(t, digest, img.Config.Digest)
54+
55+
digest = must.ReturnT(rc.UploadManifest(ctx, img.Manifest.Contents, img.Manifest.MediaType, "latest"))(t)
56+
assert.Equal(t, digest, img.Manifest.Digest)
57+
58+
// test downloading the same image using RepoClient
59+
buf, mediaType, err := rc.DownloadManifest(ctx, models.ManifestReference{Tag: "latest"}, nil)
60+
must.SucceedT(t, err)
61+
assert.Equal(t, string(buf), string(img.Manifest.Contents))
62+
assert.Equal(t, mediaType, img.Manifest.MediaType)
63+
64+
readCloser, sizeBytes, err := rc.DownloadBlob(ctx, img.Config.Digest)
65+
buf = must.ReturnT(io.ReadAll(readCloser))(t)
66+
must.SucceedT(t, readCloser.Close())
67+
assert.Equal(t, sizeBytes, uint64(len(img.Config.Contents)))
68+
assert.Equal(t, string(buf), string(img.Config.Contents))
69+
70+
readCloser, sizeBytes, err = rc.DownloadBlob(ctx, img.Layers[0].Digest)
71+
buf = must.ReturnT(io.ReadAll(readCloser))(t)
72+
must.SucceedT(t, readCloser.Close())
73+
assert.Equal(t, sizeBytes, uint64(len(img.Layers[0].Contents)))
74+
assert.Equal(t, string(buf), string(img.Layers[0].Contents))
75+
})
76+
}

internal/client/upload.go

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,8 @@ func (c *RepoClient) UploadMonolithicBlob(ctx context.Context, contents []byte)
2323
Path: "blobs/uploads/",
2424
Query: url.Values{"digest": []string{d.String()}},
2525
Headers: http.Header{
26-
"Content-Type": {"application/octet-stream"},
26+
"Content-Length": {strconv.FormatUint(uint64(len(contents)), 10)},
27+
"Content-Type": {"application/octet-stream"},
2728
},
2829
Body: bytes.NewReader(contents),
2930
ExpectStatus: http.StatusCreated,

internal/test/content.go

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -95,6 +95,9 @@ func GenerateImage(layers ...Bytes) Image {
9595
return GenerateImageWithCustomConfig(nil, layers...)
9696
}
9797

98+
// GenerateImageWithCustomConfig is like GenerateImage, but allows customizing
99+
// the contents of the image config. The supplied change function will be called
100+
// on the default config, and the result will be used as the config blob.
98101
func GenerateImageWithCustomConfig(change func(map[string]any), layers ...Bytes) Image {
99102
config := map[string]any{
100103
"architecture": "amd64",

0 commit comments

Comments
 (0)