@@ -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.
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+ 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
4560func 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+
93111func testPullAndUnpack (t * testing.T , name string , newRegistry newRegistryFunc ) {
94112 type args struct {
95113 dockerRootDir string
@@ -134,7 +152,7 @@ func testPullAndUnpack(t *testing.T, name string, newRegistry newRegistryFunc) {
134152 dockerRootDir : "testdata/golden" ,
135153 img : "/olmtest/kiali:1.4.2" ,
136154 pullErrCount : 1 ,
137- pullErr : errors . New ( "dummy" ) ,
155+ pullErr : & httpError { statusCode : http . StatusTooManyRequests } ,
138156 },
139157 expected : expected {
140158 checksum : dirChecksum (t , "testdata/golden/bundles/kiali" ),
@@ -158,10 +176,12 @@ func testPullAndUnpack(t *testing.T, name string, newRegistry newRegistryFunc) {
158176 dockerRootDir : "testdata/golden" ,
159177 img : "/olmtest/kiali:1.4.2" ,
160178 pullErrCount : math .MaxInt64 ,
161- pullErr : errors . New ( "dummy" ) ,
179+ pullErr : & httpError { statusCode : http . StatusTooManyRequests } ,
162180 },
163181 expected : expected {
164- pullAssertion : require .Error ,
182+ pullAssertion : func (t require.TestingT , err error , i ... interface {}) {
183+ require .Error (t , err )
184+ },
165185 },
166186 },
167187 }
@@ -171,36 +191,24 @@ func testPullAndUnpack(t *testing.T, name string, newRegistry newRegistryFunc) {
171191 ctx , close := context .WithCancel (context .Background ())
172192 defer close ()
173193
174- configOpts := []libimage.ConfigOpt {}
175-
194+ var middlewares []func (next http.Handler ) http.Handler
176195 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- })
196+ middlewares = append (middlewares , failureMiddleware (tt .args .pullErrCount , tt .args .pullErr ))
195197 }
196198
197- host , cafile , err := libimage .RunDockerRegistry (ctx , tt .args .dockerRootDir , configOpts ... )
198- require .NoError (t , err )
199+ t .Log ("starting docker registry" )
200+ dockerServer := libimage .RunDockerRegistry (ctx , tt .args .dockerRootDir , middlewares ... )
201+ defer dockerServer .Close ()
202+ t .Log ("started docker registry" )
199203
200- r , cleanup := newRegistry (t , cafile )
204+ r , cleanup := newRegistry (t , dockerServer . Certificate () )
201205 defer cleanup ()
202206
203- ref := image .SimpleReference (host + tt .args .img )
207+ url , err := url .Parse (dockerServer .URL )
208+ require .NoError (t , err )
209+
210+ ref := image .SimpleReference (fmt .Sprintf ("%s%s" , url .Host , tt .args .img ))
211+ t .Log ("pulling image" , ref )
204212 tt .expected .pullAssertion (t , r .Pull (ctx , ref ))
205213
206214 if tt .expected .checksum != "" {
@@ -303,3 +311,24 @@ func (f *mockBlobStore) ServeBlob(ctx context.Context, w http.ResponseWriter, r
303311func (f * mockBlobStore ) Delete (ctx context.Context , dgst digest.Digest ) error {
304312 return f .base .Delete (ctx , dgst )
305313}
314+
315+ func failureMiddleware (totalCount int , err error ) func (next http.Handler ) http.Handler {
316+ return func (next http.Handler ) http.Handler {
317+ count := 0
318+ return http .HandlerFunc (func (w http.ResponseWriter , r * http.Request ) {
319+ if count >= totalCount {
320+ next .ServeHTTP (w , r )
321+ return
322+ }
323+ count ++
324+ statusCode := http .StatusInternalServerError
325+
326+ var httpErr * httpError
327+ if errors .As (err , & httpErr ) {
328+ statusCode = httpErr .statusCode
329+ }
330+
331+ http .Error (w , err .Error (), statusCode )
332+ })
333+ }
334+ }
0 commit comments