11package release
22
33import (
4+ "bytes"
45 "context"
6+ "encoding/json"
7+ "os"
8+ "path/filepath"
9+ "slices"
510 "strings"
611 "testing"
712
@@ -12,6 +17,138 @@ import (
1217 metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
1318)
1419
20+ // createImageStream builds an ImageStream with tags for the given names.
21+ func createImageStream (names ... string ) * imageapi.ImageStream {
22+ is := & imageapi.ImageStream {
23+ TypeMeta : metav1.TypeMeta {
24+ Kind : "ImageStream" ,
25+ APIVersion : "image.openshift.io/v1" ,
26+ },
27+ }
28+ for _ , name := range names {
29+ is .Spec .Tags = append (is .Spec .Tags , imageapi.TagReference {
30+ Name : name ,
31+ From : & corev1.ObjectReference {
32+ Kind : "DockerImage" ,
33+ Name : "example.com/" + name + ":latest" ,
34+ },
35+ })
36+ }
37+ return is
38+ }
39+
40+ // writeImageReferences creates an image-references file in dir with the given tag names.
41+ func writeImageReferences (t * testing.T , dir string , names []string ) {
42+ t .Helper ()
43+ is := createImageStream (names ... )
44+ data , err := json .Marshal (is )
45+ if err != nil {
46+ t .Fatalf ("failed to marshal image-references: %v" , err )
47+ }
48+ if err := os .WriteFile (filepath .Join (dir , "image-references" ), data , 0644 ); err != nil {
49+ t .Fatalf ("failed to write image-references: %v" , err )
50+ }
51+ }
52+
53+ // tagNames returns the names of all tags in the image stream.
54+ func tagNames (is * imageapi.ImageStream ) []string {
55+ var names []string
56+ for _ , tag := range is .Spec .Tags {
57+ names = append (names , tag .Name )
58+ }
59+ return names
60+ }
61+
62+ func TestPruneUnreferencedImageStreams (t * testing.T ) {
63+
64+ t .Run ("images referenced by operator image-references are kept" , func (t * testing.T ) {
65+ dir := t .TempDir ()
66+ operatorDir := filepath .Join (dir , "my-operator" )
67+ if err := os .MkdirAll (operatorDir , 0777 ); err != nil {
68+ t .Fatal (err )
69+ }
70+ writeImageReferences (t , operatorDir , []string {"helper-image" })
71+
72+ is := createImageStream ("my-operator" , "helper-image" , "unreferenced-image" )
73+ metadata := map [string ]imageData {
74+ "my-operator" : {Directory : operatorDir },
75+ }
76+
77+ if err := pruneUnreferencedImageStreams (& bytes.Buffer {}, is , metadata , []string {"my-operator" }); err != nil {
78+ t .Fatal (err )
79+ }
80+
81+ names := tagNames (is )
82+ if ! slices .Contains (names , "my-operator" ) {
83+ t .Error ("expected my-operator to be kept (in include list)" )
84+ }
85+ if ! slices .Contains (names , "helper-image" ) {
86+ t .Error ("expected helper-image to be kept (referenced by operator image-references)" )
87+ }
88+ if slices .Contains (names , "unreferenced-image" ) {
89+ t .Error ("expected unreferenced-image to be pruned" )
90+ }
91+ })
92+
93+ t .Run ("base image image-references prevents pruning" , func (t * testing.T ) {
94+ dir := t .TempDir ()
95+
96+ operatorDir := filepath .Join (dir , "my-operator" )
97+ if err := os .MkdirAll (operatorDir , 0777 ); err != nil {
98+ t .Fatal (err )
99+ }
100+ writeImageReferences (t , operatorDir , []string {"operator-dep" })
101+
102+ baseDir := filepath .Join (dir , "cluster-version-operator" )
103+ if err := os .MkdirAll (baseDir , 0777 ); err != nil {
104+ t .Fatal (err )
105+ }
106+ writeImageReferences (t , baseDir , []string {"cluster-update-console-plugin" })
107+
108+ is := createImageStream ("cluster-version-operator" , "my-operator" , "operator-dep" , "cluster-update-console-plugin" )
109+ metadata := map [string ]imageData {
110+ "my-operator" : {Directory : operatorDir },
111+ "cluster-version-operator" : {Directory : baseDir },
112+ }
113+
114+ if err := pruneUnreferencedImageStreams (& bytes.Buffer {}, is , metadata , []string {"cluster-version-operator" , "my-operator" }); err != nil {
115+ t .Fatal (err )
116+ }
117+
118+ names := tagNames (is )
119+ if ! slices .Contains (names , "cluster-update-console-plugin" ) {
120+ t .Error ("expected cluster-update-console-plugin to be kept (referenced by base image image-references)" )
121+ }
122+ if ! slices .Contains (names , "operator-dep" ) {
123+ t .Error ("expected operator-dep to be kept (referenced by operator image-references)" )
124+ }
125+ })
126+
127+ t .Run ("without base image image-references the image is pruned" , func (t * testing.T ) {
128+ dir := t .TempDir ()
129+
130+ operatorDir := filepath .Join (dir , "my-operator" )
131+ if err := os .MkdirAll (operatorDir , 0777 ); err != nil {
132+ t .Fatal (err )
133+ }
134+ writeImageReferences (t , operatorDir , []string {"operator-dep" })
135+
136+ is := createImageStream ("cluster-version-operator" , "my-operator" , "operator-dep" , "cluster-update-console-plugin" )
137+ metadata := map [string ]imageData {
138+ "my-operator" : {Directory : operatorDir },
139+ }
140+
141+ if err := pruneUnreferencedImageStreams (& bytes.Buffer {}, is , metadata , []string {"cluster-version-operator" , "my-operator" }); err != nil {
142+ t .Fatal (err )
143+ }
144+
145+ names := tagNames (is )
146+ if slices .Contains (names , "cluster-update-console-plugin" ) {
147+ t .Error ("expected cluster-update-console-plugin to be pruned (not referenced by any image-references)" )
148+ }
149+ })
150+ }
151+
15152func TestMirrorImages (t * testing.T ) {
16153 ctx := context .Background ()
17154
0 commit comments