Skip to content

Commit bb96323

Browse files
committed
add containersimageregistry to standard registry test suite
Signed-off-by: Joe Lanford <[email protected]>
1 parent 1dde4b5 commit bb96323

File tree

6 files changed

+146
-283
lines changed

6 files changed

+146
-283
lines changed

Diff for: Makefile

+1-1
Original file line numberDiff line numberDiff line change
@@ -73,7 +73,7 @@ static: build
7373

7474
.PHONY: unit
7575
unit:
76-
$(GO) test -coverprofile=coverage.out $(SPECIFIC_UNIT_TEST) $(SPECIFIC_SKIP_UNIT_TEST) $(TAGS) $(TEST_RACE) -count=1 ./pkg/... ./alpha/...
76+
$(GO) test -coverprofile=coverage.out --coverpkg=./... $(SPECIFIC_UNIT_TEST) $(SPECIFIC_SKIP_UNIT_TEST) $(TAGS) $(TEST_RACE) -count=1 ./pkg/... ./alpha/...
7777

7878
.PHONY: tidy
7979
tidy:

Diff for: go.mod

-3
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,6 @@ require (
3030
github.com/opencontainers/image-spec v1.1.1
3131
github.com/operator-framework/api v0.30.0
3232
github.com/otiai10/copy v1.14.1
33-
github.com/phayes/freeport v0.0.0-20180830031419-95f893ade6f2
3433
github.com/pkg/errors v0.9.1
3534
github.com/sirupsen/logrus v1.9.3
3635
github.com/spf13/cobra v1.9.1
@@ -73,7 +72,6 @@ require (
7372
github.com/antlr4-go/antlr/v4 v4.13.0 // indirect
7473
github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2 // indirect
7574
github.com/beorn7/perks v1.0.1 // indirect
76-
github.com/bshuster-repo/logrus-logstash-hook v1.0.0 // indirect
7775
github.com/cenkalti/backoff/v4 v4.3.0 // indirect
7876
github.com/cespare/xxhash/v2 v2.3.0 // indirect
7977
github.com/containerd/cgroups/v3 v3.0.3 // indirect
@@ -87,7 +85,6 @@ require (
8785
github.com/containers/libtrust v0.0.0-20230121012942-c1716e8a8d01 // indirect
8886
github.com/containers/ocicrypt v1.2.1 // indirect
8987
github.com/containers/storage v1.57.2 // indirect
90-
github.com/coreos/go-systemd/v22 v22.5.0 // indirect
9188
github.com/cyberphone/json-canonicalization v0.0.0-20231217050601-ba74d44ecf5f // indirect
9289
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect
9390
github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f // indirect

Diff for: go.sum

-5
Original file line numberDiff line numberDiff line change
@@ -38,8 +38,6 @@ github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM=
3838
github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw=
3939
github.com/blang/semver/v4 v4.0.0 h1:1PFHFE6yCCTv8C1TeyNNarDzntLi7wMI5i/pzqYIsAM=
4040
github.com/blang/semver/v4 v4.0.0/go.mod h1:IbckMUScFkM3pff0VJDNKRiT6TG/YpiHIM2yvyW5YoQ=
41-
github.com/bshuster-repo/logrus-logstash-hook v1.0.0 h1:e+C0SB5R1pu//O4MQ3f9cFuPGoOVeF2fE4Og9otCc70=
42-
github.com/bshuster-repo/logrus-logstash-hook v1.0.0/go.mod h1:zsTqEiSzDgAa/8GZR7E1qaXrhYNDKBYy5/dWPTIflbk=
4341
github.com/bsm/ginkgo/v2 v2.7.0/go.mod h1:AiKlXPm7ItEHNc/2+OkrNG4E0ITzojb9/xWzvQ9XZ9w=
4442
github.com/bsm/ginkgo/v2 v2.12.0 h1:Ny8MWAHyOepLGlLKYmXG4IEkioBysk6GpaRTLC8zwWs=
4543
github.com/bsm/ginkgo/v2 v2.12.0/go.mod h1:SwYbGRRDovPVboqFv0tPTcG1sN61LM1Z4ARdbAV9g4c=
@@ -174,7 +172,6 @@ github.com/go-task/slim-sprig/v3 v3.0.0 h1:sUs3vkvUymDpBKi3qH1YSqBQk9+9D/8M2mN1v
174172
github.com/go-task/slim-sprig/v3 v3.0.0/go.mod h1:W848ghGpv3Qj3dhTPRyJypKRiqCdHZiAzKg9hl15HA8=
175173
github.com/go-test/deep v1.1.1 h1:0r/53hagsehfO4bzD2Pgr/+RgHqhmf+k1Bpse2cTu1U=
176174
github.com/go-test/deep v1.1.1/go.mod h1:5C2ZWiW0ErCdrYzpqxLbTX7MG14M9iiw8DgHncVwcsE=
177-
github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA=
178175
github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
179176
github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q=
180177
github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q=
@@ -355,8 +352,6 @@ github.com/otiai10/mint v1.6.3 h1:87qsV/aw1F5as1eH1zS/yqHY85ANKVMgkDrf9rcxbQs=
355352
github.com/otiai10/mint v1.6.3/go.mod h1:MJm72SBthJjz8qhefc4z1PYEieWmy8Bku7CjcAqyUSM=
356353
github.com/pelletier/go-toml v1.9.5 h1:4yBQzkHv+7BHq2PQUZF3Mx0IYxG7LsP222s7Agd3ve8=
357354
github.com/pelletier/go-toml v1.9.5/go.mod h1:u1nR/EPcESfeI/szUZKdtJ0xRNbUoANCkoOuaOx1Y+c=
358-
github.com/phayes/freeport v0.0.0-20180830031419-95f893ade6f2 h1:JhzVVoYvbOACxoUmOs6V/G4D5nPVUW73rKvXxP4XUJc=
359-
github.com/phayes/freeport v0.0.0-20180830031419-95f893ade6f2/go.mod h1:iIss55rKnNBTvrwdmkUpLnDpZoAHvWaiq5+iMmen4AE=
360355
github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
361356
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
362357
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=

Diff for: pkg/image/registry_test.go

+116-71
Original file line numberDiff line numberDiff line change
@@ -4,19 +4,21 @@ import (
44
"context"
55
"crypto/rand"
66
"crypto/x509"
7+
"encoding/pem"
78
"errors"
89
"fmt"
910
"io"
1011
"math"
1112
"math/big"
1213
"net/http"
14+
"net/url"
1315
"os"
16+
"path/filepath"
1417
"sync"
1518
"testing"
1619

17-
distribution "github.com/distribution/distribution/v3"
18-
"github.com/distribution/distribution/v3/configuration"
19-
repositorymiddleware "github.com/distribution/distribution/v3/registry/middleware/repository"
20+
"github.com/containers/image/v5/types"
21+
"github.com/distribution/distribution/v3"
2022
"github.com/distribution/reference"
2123
"github.com/opencontainers/go-digest"
2224
"github.com/sirupsen/logrus"
@@ -25,32 +27,60 @@ import (
2527

2628
"github.com/operator-framework/operator-registry/pkg/image"
2729
"github.com/operator-framework/operator-registry/pkg/image/containerdregistry"
30+
"github.com/operator-framework/operator-registry/pkg/image/containersimageregistry"
2831
libimage "github.com/operator-framework/operator-registry/pkg/lib/image"
2932
)
3033

3134
// cleanupFunc is a function that cleans up after some test infra.
3235
type cleanupFunc func()
3336

3437
// newRegistryFunc is a function that creates and returns a new image.Registry to test its cleanupFunc.
35-
type newRegistryFunc func(t *testing.T, cafile string) (image.Registry, cleanupFunc)
38+
type newRegistryFunc func(t *testing.T, serverCert *x509.Certificate) (image.Registry, cleanupFunc)
3639

37-
func poolForCertFile(t *testing.T, file string) *x509.CertPool {
38-
rootCAs := x509.NewCertPool()
39-
certs, err := os.ReadFile(file)
40+
func caDirForCert(t *testing.T, serverCert *x509.Certificate) string {
41+
caDir, err := os.MkdirTemp("", "opm-registry-test-ca-")
42+
require.NoError(t, err)
43+
caFile, err := os.Create(filepath.Join(caDir, "ca.crt"))
4044
require.NoError(t, err)
41-
require.True(t, rootCAs.AppendCertsFromPEM(certs))
45+
46+
require.NoError(t, pem.Encode(caFile, &pem.Block{
47+
Type: "CERTIFICATE",
48+
Bytes: serverCert.Raw,
49+
}))
50+
require.NoError(t, caFile.Close())
51+
return caDir
52+
}
53+
54+
func poolForCert(serverCert *x509.Certificate) *x509.CertPool {
55+
rootCAs := x509.NewCertPool()
56+
rootCAs.AddCert(serverCert)
4257
return rootCAs
4358
}
4459

4560
func TestRegistries(t *testing.T) {
4661
registries := map[string]newRegistryFunc{
47-
"containerd": func(t *testing.T, cafile string) (image.Registry, cleanupFunc) {
62+
"containersimage": func(t *testing.T, serverCert *x509.Certificate) (image.Registry, cleanupFunc) {
63+
caDir := caDirForCert(t, serverCert)
64+
sourceCtx := &types.SystemContext{
65+
OCICertPath: caDir,
66+
DockerCertPath: caDir,
67+
DockerPerHostCertDirPath: caDir,
68+
}
69+
r, err := containersimageregistry.New(sourceCtx, containersimageregistry.ForceTemporaryImageCache())
70+
require.NoError(t, err)
71+
cleanup := func() {
72+
require.NoError(t, os.RemoveAll(caDir))
73+
require.NoError(t, r.Destroy())
74+
}
75+
return r, cleanup
76+
},
77+
"containerd": func(t *testing.T, serverCert *x509.Certificate) (image.Registry, cleanupFunc) {
4878
val, err := rand.Int(rand.Reader, big.NewInt(math.MaxInt64))
4979
require.NoError(t, err)
5080
r, err := containerdregistry.NewRegistry(
5181
containerdregistry.WithLog(logrus.New().WithField("test", t.Name())),
5282
containerdregistry.WithCacheDir(fmt.Sprintf("cache-%x", val)),
53-
containerdregistry.WithRootCAs(poolForCertFile(t, cafile)),
83+
containerdregistry.WithRootCAs(poolForCert(serverCert)),
5484
)
5585
require.NoError(t, err)
5686
cleanup := func() {
@@ -59,37 +89,25 @@ func TestRegistries(t *testing.T) {
5989

6090
return r, cleanup
6191
},
62-
// TODO: enable docker tests - currently blocked on a cross-platform way to configure either insecure registries
63-
// or CA certs
64-
//"docker": func(t *testing.T, cafile string) (image.Registry, cleanupFunc) {
65-
// r, err := execregistry.NewRegistry(containertools.DockerTool,
66-
// logrus.New().WithField("test", t.Name()),
67-
// cafile,
68-
// )
69-
// require.NoError(t, err)
70-
// cleanup := func() {
71-
// require.NoError(t, r.Destroy())
72-
// }
73-
//
74-
// return r, cleanup
75-
//},
76-
// TODO: Enable buildah tests
77-
// func(t *testing.T) image.Registry {
78-
// r, err := buildahregistry.NewRegistry(
79-
// buildahregistry.WithLog(logrus.New().WithField("test", t.Name())),
80-
// buildahregistry.WithCacheDir(fmt.Sprintf("cache-%x", rand.Int())),
81-
// )
82-
// require.NoError(t, err)
83-
84-
// return r
85-
// },
8692
}
8793

8894
for name, registry := range registries {
8995
testPullAndUnpack(t, name, registry)
9096
}
9197
}
9298

99+
type httpError struct {
100+
statusCode int
101+
error error
102+
}
103+
104+
func (e *httpError) Error() string {
105+
if e.error != nil {
106+
return e.error.Error()
107+
}
108+
return http.StatusText(e.statusCode)
109+
}
110+
93111
func testPullAndUnpack(t *testing.T, name string, newRegistry newRegistryFunc) {
94112
type args struct {
95113
dockerRootDir string
@@ -100,7 +118,18 @@ func testPullAndUnpack(t *testing.T, name string, newRegistry newRegistryFunc) {
100118
type expected struct {
101119
checksum string
102120
pullAssertion require.ErrorAssertionFunc
121+
labels map[string]string
103122
}
123+
124+
expectedLabels := map[string]string{
125+
"operators.operatorframework.io.bundle.mediatype.v1": "registry+v1",
126+
"operators.operatorframework.io.bundle.manifests.v1": "manifests/",
127+
"operators.operatorframework.io.bundle.metadata.v1": "metadata/",
128+
"operators.operatorframework.io.bundle.package.v1": "kiali",
129+
"operators.operatorframework.io.bundle.channels.v1": "stable,alpha",
130+
"operators.operatorframework.io.bundle.channel.default.v1": "stable",
131+
}
132+
104133
tests := []struct {
105134
description string
106135
args args
@@ -114,6 +143,7 @@ func testPullAndUnpack(t *testing.T, name string, newRegistry newRegistryFunc) {
114143
},
115144
expected: expected{
116145
checksum: dirChecksum(t, "testdata/golden/bundles/kiali"),
146+
labels: expectedLabels,
117147
pullAssertion: require.NoError,
118148
},
119149
},
@@ -125,6 +155,7 @@ func testPullAndUnpack(t *testing.T, name string, newRegistry newRegistryFunc) {
125155
},
126156
expected: expected{
127157
checksum: dirChecksum(t, "testdata/golden/bundles/kiali"),
158+
labels: expectedLabels,
128159
pullAssertion: require.NoError,
129160
},
130161
},
@@ -134,10 +165,11 @@ func testPullAndUnpack(t *testing.T, name string, newRegistry newRegistryFunc) {
134165
dockerRootDir: "testdata/golden",
135166
img: "/olmtest/kiali:1.4.2",
136167
pullErrCount: 1,
137-
pullErr: errors.New("dummy"),
168+
pullErr: &httpError{statusCode: http.StatusTooManyRequests},
138169
},
139170
expected: expected{
140171
checksum: dirChecksum(t, "testdata/golden/bundles/kiali"),
172+
labels: expectedLabels,
141173
pullAssertion: require.NoError,
142174
},
143175
},
@@ -158,7 +190,7 @@ func testPullAndUnpack(t *testing.T, name string, newRegistry newRegistryFunc) {
158190
dockerRootDir: "testdata/golden",
159191
img: "/olmtest/kiali:1.4.2",
160192
pullErrCount: math.MaxInt64,
161-
pullErr: errors.New("dummy"),
193+
pullErr: &httpError{statusCode: http.StatusTooManyRequests},
162194
},
163195
expected: expected{
164196
pullAssertion: require.Error,
@@ -168,51 +200,43 @@ func testPullAndUnpack(t *testing.T, name string, newRegistry newRegistryFunc) {
168200
for _, tt := range tests {
169201
t.Run(tt.description, func(t *testing.T) {
170202
logrus.SetLevel(logrus.DebugLevel)
171-
ctx, close := context.WithCancel(context.Background())
172-
defer close()
173-
174-
configOpts := []libimage.ConfigOpt{}
203+
ctx, cancel := context.WithCancel(context.Background())
204+
defer cancel()
175205

206+
var middlewares []func(next http.Handler) http.Handler
176207
if tt.args.pullErrCount > 0 {
177-
configOpts = append(configOpts, func(config *configuration.Configuration) {
178-
if config.Middleware == nil {
179-
config.Middleware = make(map[string][]configuration.Middleware)
180-
}
181-
182-
mockRepo := &mockRepo{blobStore: &mockBlobStore{
183-
maxCount: tt.args.pullErrCount,
184-
err: tt.args.pullErr,
185-
}}
186-
val, err := rand.Int(rand.Reader, big.NewInt(math.MaxInt64))
187-
require.NoError(t, err)
188-
189-
middlewareName := fmt.Sprintf("test-%x", val)
190-
require.NoError(t, repositorymiddleware.Register(middlewareName, mockRepo.init))
191-
config.Middleware["repository"] = append(config.Middleware["repository"], configuration.Middleware{
192-
Name: middlewareName,
193-
})
194-
})
208+
middlewares = append(middlewares, failureMiddleware(tt.args.pullErrCount, tt.args.pullErr))
195209
}
196210

197-
host, cafile, err := libimage.RunDockerRegistry(ctx, tt.args.dockerRootDir, configOpts...)
198-
require.NoError(t, err)
211+
dockerServer := libimage.RunDockerRegistry(ctx, tt.args.dockerRootDir, middlewares...)
212+
defer dockerServer.Close()
199213

200-
r, cleanup := newRegistry(t, cafile)
214+
r, cleanup := newRegistry(t, dockerServer.Certificate())
201215
defer cleanup()
202216

203-
ref := image.SimpleReference(host + tt.args.img)
204-
tt.expected.pullAssertion(t, r.Pull(ctx, ref))
217+
url, err := url.Parse(dockerServer.URL)
218+
require.NoError(t, err)
205219

206-
if tt.expected.checksum != "" {
207-
// Copy golden manifests to a temp dir
208-
dir := "kiali-unpacked"
209-
require.NoError(t, r.Unpack(ctx, ref, dir))
220+
ref := image.SimpleReference(fmt.Sprintf("%s%s", url.Host, tt.args.img))
221+
t.Log("pulling image", ref)
222+
pullErr := r.Pull(ctx, ref)
223+
tt.expected.pullAssertion(t, pullErr)
224+
if pullErr != nil {
225+
return
226+
}
210227

211-
checksum := dirChecksum(t, dir)
212-
require.Equal(t, tt.expected.checksum, checksum)
228+
labels, err := r.Labels(ctx, ref)
229+
require.NoError(t, err)
230+
require.Equal(t, tt.expected.labels, labels)
213231

214-
require.NoError(t, os.RemoveAll(dir))
215-
}
232+
// Copy golden manifests to a temp dir
233+
dir := "kiali-unpacked"
234+
require.NoError(t, r.Unpack(ctx, ref, dir))
235+
236+
checksum := dirChecksum(t, dir)
237+
require.Equal(t, tt.expected.checksum, checksum)
238+
239+
require.NoError(t, os.RemoveAll(dir))
216240
})
217241
}
218242
}
@@ -303,3 +327,24 @@ func (f *mockBlobStore) ServeBlob(ctx context.Context, w http.ResponseWriter, r
303327
func (f *mockBlobStore) Delete(ctx context.Context, dgst digest.Digest) error {
304328
return f.base.Delete(ctx, dgst)
305329
}
330+
331+
func failureMiddleware(totalCount int, err error) func(next http.Handler) http.Handler {
332+
return func(next http.Handler) http.Handler {
333+
count := 0
334+
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
335+
if count >= totalCount {
336+
next.ServeHTTP(w, r)
337+
return
338+
}
339+
count++
340+
statusCode := http.StatusInternalServerError
341+
342+
var httpErr *httpError
343+
if errors.As(err, &httpErr) {
344+
statusCode = httpErr.statusCode
345+
}
346+
347+
http.Error(w, err.Error(), statusCode)
348+
})
349+
}
350+
}

0 commit comments

Comments
 (0)