@@ -69,11 +69,13 @@ func Test_SimpleRevisionGenerator_GenerateRevisionFromHelmRelease(t *testing.T)
6969 "olm.operatorframework.io/package-name" : "my-package" ,
7070 },
7171 Labels : map [string ]string {
72- "olm.operatorframework.io/owner" : "test-123" ,
72+ "olm.operatorframework.io/owner" : "test-123" ,
73+ "olm.operatorframework.io/package-name" : "my-package" ,
7374 },
7475 },
7576 Spec : ocv1.ClusterExtensionRevisionSpec {
76- Revision : 1 ,
77+ LifecycleState : ocv1 .ClusterExtensionRevisionLifecycleStateActive ,
78+ Revision : 1 ,
7779 Phases : []ocv1.ClusterExtensionRevisionPhase {
7880 {
7981 Name : "deploy" ,
@@ -758,6 +760,100 @@ func TestBoxcutter_Apply(t *testing.T) {
758760 assert .Contains (t , latest .Spec .Previous , ocv1.ClusterExtensionRevisionPrevious {Name : "rev-4" })
759761 },
760762 },
763+ {
764+ name : "annotation-only update (same phases, different annotations)" ,
765+ mockBuilder : & mockBundleRevisionBuilder {
766+ makeRevisionFunc : func (bundleFS fs.FS , ext * ocv1.ClusterExtension , objectLabels , revisionAnnotations map [string ]string ) (* ocv1.ClusterExtensionRevision , error ) {
767+ // Return revision with UPDATED annotations but SAME phases
768+ revisionLabels := map [string ]string {
769+ controllers .ClusterExtensionRevisionOwnerLabel : ext .Name ,
770+ }
771+ if pkg , ok := revisionAnnotations [labels .PackageNameKey ]; ok {
772+ revisionLabels [labels .PackageNameKey ] = pkg
773+ }
774+ return & ocv1.ClusterExtensionRevision {
775+ ObjectMeta : metav1.ObjectMeta {
776+ Annotations : revisionAnnotations ,
777+ Labels : revisionLabels ,
778+ },
779+ Spec : ocv1.ClusterExtensionRevisionSpec {
780+ Phases : []ocv1.ClusterExtensionRevisionPhase {
781+ {
782+ Name : string (applier .PhaseDeploy ),
783+ Objects : []ocv1.ClusterExtensionRevisionObject {
784+ {
785+ Object : unstructured.Unstructured {
786+ Object : map [string ]interface {}{
787+ "apiVersion" : "v1" ,
788+ "kind" : "ConfigMap" ,
789+ "metadata" : map [string ]interface {}{
790+ "name" : "test-cm" ,
791+ },
792+ },
793+ },
794+ },
795+ },
796+ },
797+ },
798+ },
799+ }, nil
800+ },
801+ },
802+ existingObjs : []client.Object {
803+ ext ,
804+ & ocv1.ClusterExtensionRevision {
805+ ObjectMeta : metav1.ObjectMeta {
806+ Name : "test-ext-1" ,
807+ Annotations : map [string ]string {
808+ labels .BundleVersionKey : "1.0.0" ,
809+ labels .PackageNameKey : "test-package" ,
810+ },
811+ Labels : map [string ]string {
812+ controllers .ClusterExtensionRevisionOwnerLabel : ext .Name ,
813+ labels .PackageNameKey : "test-package" ,
814+ },
815+ },
816+ Spec : ocv1.ClusterExtensionRevisionSpec {
817+ Revision : 1 ,
818+ Phases : []ocv1.ClusterExtensionRevisionPhase {
819+ {
820+ Name : string (applier .PhaseDeploy ),
821+ Objects : []ocv1.ClusterExtensionRevisionObject {
822+ {
823+ Object : unstructured.Unstructured {
824+ Object : map [string ]interface {}{
825+ "apiVersion" : "v1" ,
826+ "kind" : "ConfigMap" ,
827+ "metadata" : map [string ]interface {}{
828+ "name" : "test-cm" ,
829+ },
830+ },
831+ },
832+ },
833+ },
834+ },
835+ },
836+ },
837+ },
838+ },
839+ validate : func (t * testing.T , c client.Client ) {
840+ revList := & ocv1.ClusterExtensionRevisionList {}
841+ err := c .List (context .Background (), revList , client.MatchingLabels {controllers .ClusterExtensionRevisionOwnerLabel : ext .Name })
842+ require .NoError (t , err )
843+ // Should still be only 1 revision (in-place update, not new revision)
844+ require .Len (t , revList .Items , 1 )
845+
846+ rev := revList .Items [0 ]
847+ assert .Equal (t , "test-ext-1" , rev .Name )
848+ assert .Equal (t , int64 (1 ), rev .Spec .Revision )
849+ // Verify annotations were updated
850+ assert .Equal (t , "1.0.1" , rev .Annotations [labels .BundleVersionKey ])
851+ assert .Equal (t , "test-package" , rev .Annotations [labels .PackageNameKey ])
852+ // Verify labels still have package name
853+ assert .Equal (t , ext .Name , rev .Labels [controllers .ClusterExtensionRevisionOwnerLabel ])
854+ assert .Equal (t , "test-package" , rev .Labels [labels .PackageNameKey ])
855+ },
856+ },
761857 }
762858
763859 for _ , tc := range testCases {
@@ -780,7 +876,15 @@ func TestBoxcutter_Apply(t *testing.T) {
780876 testFS := fstest.MapFS {}
781877
782878 // Execute
783- installSucceeded , installStatus , err := boxcutter .Apply (t .Context (), testFS , ext , nil , nil )
879+ revisionAnnotations := map [string ]string {}
880+ if tc .name == "annotation-only update (same phases, different annotations)" {
881+ // For annotation-only update test, pass NEW annotations
882+ revisionAnnotations = map [string ]string {
883+ labels .BundleVersionKey : "1.0.1" ,
884+ labels .PackageNameKey : "test-package" ,
885+ }
886+ }
887+ installSucceeded , installStatus , err := boxcutter .Apply (t .Context (), testFS , ext , nil , revisionAnnotations )
784888
785889 // Assert
786890 if tc .expectedErr != "" {
@@ -808,13 +912,17 @@ func TestBoxcutter_Apply(t *testing.T) {
808912
809913func TestBoxcutterStorageMigrator (t * testing.T ) {
810914 t .Run ("creates revision" , func (t * testing.T ) {
915+ testScheme := runtime .NewScheme ()
916+ require .NoError (t , ocv1 .AddToScheme (testScheme ))
917+
811918 brb := & mockBundleRevisionBuilder {}
812919 mag := & mockActionGetter {}
813920 client := & clientMock {}
814921 sm := & applier.BoxcutterStorageMigrator {
815922 RevisionGenerator : brb ,
816923 ActionClientGetter : mag ,
817924 Client : client ,
925+ Scheme : testScheme ,
818926 }
819927
820928 ext := & ocv1.ClusterExtension {
@@ -828,6 +936,10 @@ func TestBoxcutterStorageMigrator(t *testing.T) {
828936 On ("Create" , mock .Anything , mock .AnythingOfType ("*v1.ClusterExtensionRevision" ), mock .Anything ).
829937 Once ().
830938 Return (nil )
939+ client .
940+ On ("Update" , mock .Anything , mock .AnythingOfType ("*v1.ClusterExtensionRevision" ), mock .Anything ).
941+ Once ().
942+ Return (nil )
831943
832944 err := sm .Migrate (t .Context (), ext , map [string ]string {"my-label" : "my-value" })
833945 require .NoError (t , err )
@@ -836,13 +948,17 @@ func TestBoxcutterStorageMigrator(t *testing.T) {
836948 })
837949
838950 t .Run ("does not create revision when revisions exist" , func (t * testing.T ) {
951+ testScheme := runtime .NewScheme ()
952+ require .NoError (t , ocv1 .AddToScheme (testScheme ))
953+
839954 brb := & mockBundleRevisionBuilder {}
840955 mag := & mockActionGetter {}
841956 client := & clientMock {}
842957 sm := & applier.BoxcutterStorageMigrator {
843958 RevisionGenerator : brb ,
844959 ActionClientGetter : mag ,
845960 Client : client ,
961+ Scheme : testScheme ,
846962 }
847963
848964 ext := & ocv1.ClusterExtension {
@@ -866,6 +982,9 @@ func TestBoxcutterStorageMigrator(t *testing.T) {
866982 })
867983
868984 t .Run ("does not create revision when no helm release" , func (t * testing.T ) {
985+ testScheme := runtime .NewScheme ()
986+ require .NoError (t , ocv1 .AddToScheme (testScheme ))
987+
869988 brb := & mockBundleRevisionBuilder {}
870989 mag := & mockActionGetter {
871990 getClientErr : driver .ErrReleaseNotFound ,
@@ -875,6 +994,7 @@ func TestBoxcutterStorageMigrator(t *testing.T) {
875994 RevisionGenerator : brb ,
876995 ActionClientGetter : mag ,
877996 Client : client ,
997+ Scheme : testScheme ,
878998 }
879999
8801000 ext := & ocv1.ClusterExtension {
@@ -905,7 +1025,15 @@ func (m *mockBundleRevisionBuilder) GenerateRevisionFromHelmRelease(
9051025 helmRelease * release.Release , ext * ocv1.ClusterExtension ,
9061026 objectLabels map [string ]string ,
9071027) (* ocv1.ClusterExtensionRevision , error ) {
908- return nil , nil
1028+ return & ocv1.ClusterExtensionRevision {
1029+ ObjectMeta : metav1.ObjectMeta {
1030+ Name : "test-revision" ,
1031+ Labels : map [string ]string {
1032+ controllers .ClusterExtensionRevisionOwnerLabel : ext .Name ,
1033+ },
1034+ },
1035+ Spec : ocv1.ClusterExtensionRevisionSpec {},
1036+ }, nil
9091037}
9101038
9111039type clientMock struct {
@@ -921,3 +1049,26 @@ func (m *clientMock) Create(ctx context.Context, obj client.Object, opts ...clie
9211049 args := m .Called (ctx , obj , opts )
9221050 return args .Error (0 )
9231051}
1052+
1053+ func (m * clientMock ) Status () client.StatusWriter {
1054+ return & statusWriterMock {mock : & m .Mock }
1055+ }
1056+
1057+ type statusWriterMock struct {
1058+ mock * mock.Mock
1059+ }
1060+
1061+ func (s * statusWriterMock ) Update (ctx context.Context , obj client.Object , opts ... client.SubResourceUpdateOption ) error {
1062+ args := s .mock .Called (ctx , obj , opts )
1063+ return args .Error (0 )
1064+ }
1065+
1066+ func (s * statusWriterMock ) Patch (ctx context.Context , obj client.Object , patch client.Patch , opts ... client.SubResourcePatchOption ) error {
1067+ args := s .mock .Called (ctx , obj , patch , opts )
1068+ return args .Error (0 )
1069+ }
1070+
1071+ func (s * statusWriterMock ) Create (ctx context.Context , obj client.Object , subResource client.Object , opts ... client.SubResourceCreateOption ) error {
1072+ args := s .mock .Called (ctx , obj , subResource , opts )
1073+ return args .Error (0 )
1074+ }
0 commit comments