@@ -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,59 @@ 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.
3235type 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+ return caDir
51+ }
52+
53+ func poolForCert (serverCert * x509.Certificate ) * x509.CertPool {
54+ rootCAs := x509 .NewCertPool ()
55+ rootCAs .AddCert (serverCert )
4256 return rootCAs
4357}
4458
4559func TestRegistries (t * testing.T ) {
4660 registries := map [string ]newRegistryFunc {
47- "containerd" : func (t * testing.T , cafile string ) (image.Registry , cleanupFunc ) {
61+ "containersimage" : func (t * testing.T , serverCert * x509.Certificate ) (image.Registry , cleanupFunc ) {
62+ caDir := caDirForCert (t , serverCert )
63+ sourceCtx := & types.SystemContext {
64+ OCICertPath : caDir ,
65+ DockerCertPath : caDir ,
66+ DockerPerHostCertDirPath : caDir ,
67+ }
68+ r , err := containersimageregistry .New (sourceCtx , containersimageregistry .ForceTemporaryImageCache ())
69+ require .NoError (t , err )
70+ cleanup := func () {
71+ require .NoError (t , os .RemoveAll (caDir ))
72+ require .NoError (t , r .Destroy ())
73+ }
74+ return r , cleanup
75+ },
76+ "containerd" : func (t * testing.T , serverCert * x509.Certificate ) (image.Registry , cleanupFunc ) {
4877 val , err := rand .Int (rand .Reader , big .NewInt (math .MaxInt64 ))
4978 require .NoError (t , err )
5079 r , err := containerdregistry .NewRegistry (
5180 containerdregistry .WithLog (logrus .New ().WithField ("test" , t .Name ())),
5281 containerdregistry .WithCacheDir (fmt .Sprintf ("cache-%x" , val )),
53- containerdregistry .WithRootCAs (poolForCertFile ( t , cafile )),
82+ containerdregistry .WithRootCAs (poolForCert ( serverCert )),
5483 )
5584 require .NoError (t , err )
5685 cleanup := func () {
@@ -59,37 +88,25 @@ func TestRegistries(t *testing.T) {
5988
6089 return r , cleanup
6190 },
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- // },
8691 }
8792
8893 for name , registry := range registries {
8994 testPullAndUnpack (t , name , registry )
9095 }
9196}
9297
98+ type httpError struct {
99+ statusCode int
100+ error error
101+ }
102+
103+ func (e * httpError ) Error () string {
104+ if e .error != nil {
105+ return e .error .Error ()
106+ }
107+ return http .StatusText (e .statusCode )
108+ }
109+
93110func testPullAndUnpack (t * testing.T , name string , newRegistry newRegistryFunc ) {
94111 type args struct {
95112 dockerRootDir string
@@ -134,7 +151,7 @@ func testPullAndUnpack(t *testing.T, name string, newRegistry newRegistryFunc) {
134151 dockerRootDir : "testdata/golden" ,
135152 img : "/olmtest/kiali:1.4.2" ,
136153 pullErrCount : 1 ,
137- pullErr : errors . New ( "dummy" ) ,
154+ pullErr : & httpError { statusCode : http . StatusTooManyRequests } ,
138155 },
139156 expected : expected {
140157 checksum : dirChecksum (t , "testdata/golden/bundles/kiali" ),
@@ -158,10 +175,12 @@ func testPullAndUnpack(t *testing.T, name string, newRegistry newRegistryFunc) {
158175 dockerRootDir : "testdata/golden" ,
159176 img : "/olmtest/kiali:1.4.2" ,
160177 pullErrCount : math .MaxInt64 ,
161- pullErr : errors . New ( "dummy" ) ,
178+ pullErr : & httpError { statusCode : http . StatusTooManyRequests } ,
162179 },
163180 expected : expected {
164- pullAssertion : require .Error ,
181+ pullAssertion : func (t require.TestingT , err error , i ... interface {}) {
182+ require .Error (t , err )
183+ },
165184 },
166185 },
167186 }
@@ -171,36 +190,24 @@ func testPullAndUnpack(t *testing.T, name string, newRegistry newRegistryFunc) {
171190 ctx , close := context .WithCancel (context .Background ())
172191 defer close ()
173192
174- configOpts := []libimage.ConfigOpt {}
175-
193+ var middlewares []func (next http.Handler ) http.Handler
176194 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- })
195+ middlewares = append (middlewares , failureMiddleware (tt .args .pullErrCount , tt .args .pullErr ))
195196 }
196197
197- host , cafile , err := libimage .RunDockerRegistry (ctx , tt .args .dockerRootDir , configOpts ... )
198- require .NoError (t , err )
198+ t .Log ("starting docker registry" )
199+ dockerServer := libimage .RunDockerRegistry (ctx , tt .args .dockerRootDir , middlewares ... )
200+ defer dockerServer .Close ()
201+ t .Log ("started docker registry" )
199202
200- r , cleanup := newRegistry (t , cafile )
203+ r , cleanup := newRegistry (t , dockerServer . Certificate () )
201204 defer cleanup ()
202205
203- ref := image .SimpleReference (host + tt .args .img )
206+ url , err := url .Parse (dockerServer .URL )
207+ require .NoError (t , err )
208+
209+ ref := image .SimpleReference (fmt .Sprintf ("%s%s" , url .Host , tt .args .img ))
210+ t .Log ("pulling image" , ref )
204211 tt .expected .pullAssertion (t , r .Pull (ctx , ref ))
205212
206213 if tt .expected .checksum != "" {
@@ -303,3 +310,24 @@ func (f *mockBlobStore) ServeBlob(ctx context.Context, w http.ResponseWriter, r
303310func (f * mockBlobStore ) Delete (ctx context.Context , dgst digest.Digest ) error {
304311 return f .base .Delete (ctx , dgst )
305312}
313+
314+ func failureMiddleware (totalCount int , err error ) func (next http.Handler ) http.Handler {
315+ return func (next http.Handler ) http.Handler {
316+ count := 0
317+ return http .HandlerFunc (func (w http.ResponseWriter , r * http.Request ) {
318+ if count >= totalCount {
319+ next .ServeHTTP (w , r )
320+ return
321+ }
322+ count ++
323+ statusCode := http .StatusInternalServerError
324+
325+ var httpErr * httpError
326+ if errors .As (err , & httpErr ) {
327+ statusCode = httpErr .statusCode
328+ }
329+
330+ http .Error (w , err .Error (), statusCode )
331+ })
332+ }
333+ }
0 commit comments