@@ -2,8 +2,10 @@ package image
22
33import (
44 "archive/tar"
5+ "bytes"
56 "context"
67 "errors"
8+ "fmt"
79 "io"
810 "io/fs"
911 "iter"
@@ -20,6 +22,7 @@ import (
2022 ocispecv1 "github.com/opencontainers/image-spec/specs-go/v1"
2123 "github.com/stretchr/testify/assert"
2224 "github.com/stretchr/testify/require"
25+ "helm.sh/helm/v3/pkg/registry"
2326
2427 fsutil "github.com/operator-framework/operator-controller/internal/shared/util/fs"
2528)
@@ -144,6 +147,67 @@ func TestDiskCacheFetch(t *testing.T) {
144147 }
145148}
146149
150+ func TestDiskCacheStore_HelmChart (t * testing.T ) {
151+ const myOwner = "myOwner"
152+ myCanonicalRef := mustParseCanonical (t , "my.registry.io/ns/chart@sha256:5891b5b522d5df086d0ff0b110fbd9d21bb4fc7163af34d08286a2e846f6be03" )
153+ myTaggedRef , err := reference .WithTag (reference .TrimNamed (myCanonicalRef ), "test-tag" )
154+ require .NoError (t , err )
155+
156+ testCases := []struct {
157+ name string
158+ ownerID string
159+ srcRef reference.Named
160+ canonicalRef reference.Canonical
161+ imgConfig ocispecv1.Image
162+ layers iter.Seq [LayerData ]
163+ filterFunc func (context.Context , reference.Named , ocispecv1.Image ) (archive.Filter , error )
164+ setup func (* testing.T , * diskCache )
165+ expect func (* testing.T , * diskCache , fs.FS , time.Time , error )
166+ }{
167+ {
168+ name : "returns no error if layer read contains helm chart" ,
169+ ownerID : myOwner ,
170+ srcRef : myTaggedRef ,
171+ canonicalRef : myCanonicalRef ,
172+ layers : func () iter.Seq [LayerData ] {
173+ testChart := mockHelmChartTgz (t ,
174+ []fileContent {
175+ {
176+ name : "testchart/Chart.yaml" ,
177+ content : []byte ("apiVersion: v2\n name: testchart\n version: 0.1.0" ),
178+ },
179+ {
180+ name : "testchart/templates/deployment.yaml" ,
181+ content : []byte ("kind: Deployment\n apiVersion: apps/v1" ),
182+ },
183+ },
184+ )
185+ return func (yield func (LayerData ) bool ) {
186+ yield (LayerData {Reader : bytes .NewBuffer (testChart ), MediaType : registry .ChartLayerMediaType })
187+ }
188+ }(),
189+ expect : func (t * testing.T , cache * diskCache , fsys fs.FS , modTime time.Time , err error ) {
190+ require .NoError (t , err )
191+ },
192+ },
193+ }
194+ for _ , tc := range testCases {
195+ t .Run (tc .name , func (t * testing.T ) {
196+ dc := & diskCache {
197+ basePath : t .TempDir (),
198+ filterFunc : tc .filterFunc ,
199+ }
200+ if tc .setup != nil {
201+ tc .setup (t , dc )
202+ }
203+ fsys , modTime , err := dc .Store (context .Background (), tc .ownerID , tc .srcRef , tc .canonicalRef , tc .imgConfig , tc .layers )
204+ require .NotNil (t , tc .expect , "test case must include an expect function" )
205+ tc .expect (t , dc , fsys , modTime , err )
206+ require .NoError (t , fsutil .DeleteReadOnlyRecursive (dc .basePath ))
207+ })
208+ }
209+ }
210+
147211func TestDiskCacheStore (t * testing.T ) {
148212 const myOwner = "myOwner"
149213 myCanonicalRef := mustParseCanonical (t , "my.registry.io/ns/repo@sha256:5891b5b522d5df086d0ff0b110fbd9d21bb4fc7163af34d08286a2e846f6be03" )
@@ -585,6 +649,123 @@ func TestDiskCacheGarbageCollection(t *testing.T) {
585649 }
586650}
587651
652+ func Test_storeChartLayer (t * testing.T ) {
653+ tmp := t .TempDir ()
654+ type args struct {
655+ path string
656+ data LayerData
657+ }
658+ type want struct {
659+ errStr string
660+ }
661+
662+ tests := []struct {
663+ name string
664+ args args
665+ want want
666+ }{
667+ {
668+ name : "store chart layer to given path" ,
669+ args : args {
670+ path : tmp ,
671+ data : LayerData {
672+ Index : 0 ,
673+ MediaType : registry .ChartLayerMediaType ,
674+ Reader : bytes .NewBuffer (mockHelmChartTgz (t ,
675+ []fileContent {
676+ {
677+ name : "testchart/Chart.yaml" ,
678+ content : []byte ("apiVersion: v2\n name: testchart\n version: 0.1.0" ),
679+ },
680+ {
681+ name : "testchart/templates/deployment.yaml" ,
682+ content : []byte ("kind: Deployment\n apiVersion: apps/v1" ),
683+ },
684+ },
685+ )),
686+ },
687+ },
688+ },
689+ {
690+ name : "store invalid chart layer" ,
691+ args : args {
692+ path : tmp ,
693+ data : LayerData {
694+ Index : 0 ,
695+ MediaType : registry .ChartLayerMediaType ,
696+ Reader : bytes .NewBuffer (mockHelmChartTgz (t ,
697+ []fileContent {
698+ {
699+ name : "testchart/Chart.yaml" ,
700+ content : []byte ("apiVersion: v2\n name: testchart\n version: 0.1.0" ),
701+ },
702+ {
703+ name : "testchart/deployment.yaml" ,
704+ content : []byte ("kind: Deployment\n apiVersion: apps/v1" ),
705+ },
706+ },
707+ )),
708+ },
709+ },
710+ want : want {
711+ errStr : "inspecting chart layer: templates directory not found" ,
712+ },
713+ },
714+ {
715+ name : "store existing from dummy reader" ,
716+ args : args {
717+ path : tmp ,
718+ data : LayerData {
719+ Index : 0 ,
720+ MediaType : registry .ChartLayerMediaType ,
721+ Reader : & dummyReader {},
722+ },
723+ },
724+ want : want {
725+ errStr : "error reading layer[0]: something went wrong" ,
726+ },
727+ },
728+ {
729+ name : "handle chart layer data" ,
730+ args : args {
731+ path : tmp ,
732+ data : LayerData {
733+ Index : 0 ,
734+ MediaType : registry .ChartLayerMediaType ,
735+ Err : fmt .Errorf ("invalid layer data" ),
736+ Reader : bytes .NewBuffer (mockHelmChartTgz (t ,
737+ []fileContent {
738+ {
739+ name : "testchart/Chart.yaml" ,
740+ content : []byte ("apiVersion: v2\n name: testchart\n version: 0.1.0" ),
741+ },
742+ {
743+ name : "testchart/deployment.yaml" ,
744+ content : []byte ("kind: Deployment\n apiVersion: apps/v1" ),
745+ },
746+ },
747+ )),
748+ },
749+ },
750+ want : want {
751+ errStr : "error found in layer data: invalid layer data" ,
752+ },
753+ },
754+ }
755+
756+ for _ , tc := range tests {
757+ t .Run (tc .name , func (t * testing.T ) {
758+ err := storeChartLayer (tc .args .path , tc .args .data )
759+ if tc .want .errStr != "" {
760+ require .Error (t , err )
761+ require .EqualError (t , err , tc .want .errStr , "chart store error" )
762+ } else {
763+ require .NoError (t , err )
764+ }
765+ })
766+ }
767+ }
768+
588769func mustParseCanonical (t * testing.T , s string ) reference.Canonical {
589770 n , err := reference .ParseNamed (s )
590771 require .NoError (t , err )
@@ -619,3 +800,11 @@ func fsTarReader(fsys fs.FS) io.ReadCloser {
619800 }()
620801 return pr
621802}
803+
804+ type dummyReader struct {}
805+
806+ var _ io.Reader = & dummyReader {}
807+
808+ func (r * dummyReader ) Read (p []byte ) (int , error ) {
809+ return 0 , errors .New ("something went wrong" )
810+ }
0 commit comments