@@ -68,12 +68,17 @@ func Test_SimpleRevisionGenerator_GenerateRevisionFromHelmRelease(t *testing.T)
6868 "olm.operatorframework.io/bundle-version" : "1.2.0" ,
6969 "olm.operatorframework.io/package-name" : "my-package" ,
7070 },
71+ // Both owner and package-name labels are required:
72+ // - owner: identifies which ClusterExtension owns this revision (for label-based queries)
73+ // - package-name: needed by BoxcutterRevisionStatesGetter to populate RevisionMetadata.Package field
7174 Labels : map [string ]string {
72- "olm.operatorframework.io/owner" : "test-123" ,
75+ "olm.operatorframework.io/owner" : "test-123" ,
76+ "olm.operatorframework.io/package-name" : "my-package" ,
7377 },
7478 },
7579 Spec : ocv1.ClusterExtensionRevisionSpec {
76- Revision : 1 ,
80+ LifecycleState : ocv1 .ClusterExtensionRevisionLifecycleStateActive ,
81+ Revision : 1 ,
7782 Phases : []ocv1.ClusterExtensionRevisionPhase {
7883 {
7984 Name : "deploy" ,
@@ -758,6 +763,100 @@ func TestBoxcutter_Apply(t *testing.T) {
758763 assert .Contains (t , latest .Spec .Previous , ocv1.ClusterExtensionRevisionPrevious {Name : "rev-4" })
759764 },
760765 },
766+ {
767+ name : "annotation-only update (same phases, different annotations)" ,
768+ mockBuilder : & mockBundleRevisionBuilder {
769+ makeRevisionFunc : func (bundleFS fs.FS , ext * ocv1.ClusterExtension , objectLabels , revisionAnnotations map [string ]string ) (* ocv1.ClusterExtensionRevision , error ) {
770+ // Return revision with UPDATED annotations but SAME phases
771+ revisionLabels := map [string ]string {
772+ controllers .ClusterExtensionRevisionOwnerLabel : ext .Name ,
773+ }
774+ if pkg , ok := revisionAnnotations [labels .PackageNameKey ]; ok {
775+ revisionLabels [labels .PackageNameKey ] = pkg
776+ }
777+ return & ocv1.ClusterExtensionRevision {
778+ ObjectMeta : metav1.ObjectMeta {
779+ Annotations : revisionAnnotations ,
780+ Labels : revisionLabels ,
781+ },
782+ Spec : ocv1.ClusterExtensionRevisionSpec {
783+ Phases : []ocv1.ClusterExtensionRevisionPhase {
784+ {
785+ Name : string (applier .PhaseDeploy ),
786+ Objects : []ocv1.ClusterExtensionRevisionObject {
787+ {
788+ Object : unstructured.Unstructured {
789+ Object : map [string ]interface {}{
790+ "apiVersion" : "v1" ,
791+ "kind" : "ConfigMap" ,
792+ "metadata" : map [string ]interface {}{
793+ "name" : "test-cm" ,
794+ },
795+ },
796+ },
797+ },
798+ },
799+ },
800+ },
801+ },
802+ }, nil
803+ },
804+ },
805+ existingObjs : []client.Object {
806+ ext ,
807+ & ocv1.ClusterExtensionRevision {
808+ ObjectMeta : metav1.ObjectMeta {
809+ Name : "test-ext-1" ,
810+ Annotations : map [string ]string {
811+ labels .BundleVersionKey : "1.0.0" ,
812+ labels .PackageNameKey : "test-package" ,
813+ },
814+ Labels : map [string ]string {
815+ controllers .ClusterExtensionRevisionOwnerLabel : ext .Name ,
816+ labels .PackageNameKey : "test-package" ,
817+ },
818+ },
819+ Spec : ocv1.ClusterExtensionRevisionSpec {
820+ Revision : 1 ,
821+ Phases : []ocv1.ClusterExtensionRevisionPhase {
822+ {
823+ Name : string (applier .PhaseDeploy ),
824+ Objects : []ocv1.ClusterExtensionRevisionObject {
825+ {
826+ Object : unstructured.Unstructured {
827+ Object : map [string ]interface {}{
828+ "apiVersion" : "v1" ,
829+ "kind" : "ConfigMap" ,
830+ "metadata" : map [string ]interface {}{
831+ "name" : "test-cm" ,
832+ },
833+ },
834+ },
835+ },
836+ },
837+ },
838+ },
839+ },
840+ },
841+ },
842+ validate : func (t * testing.T , c client.Client ) {
843+ revList := & ocv1.ClusterExtensionRevisionList {}
844+ err := c .List (context .Background (), revList , client.MatchingLabels {controllers .ClusterExtensionRevisionOwnerLabel : ext .Name })
845+ require .NoError (t , err )
846+ // Should still be only 1 revision (in-place update, not new revision)
847+ require .Len (t , revList .Items , 1 )
848+
849+ rev := revList .Items [0 ]
850+ assert .Equal (t , "test-ext-1" , rev .Name )
851+ assert .Equal (t , int64 (1 ), rev .Spec .Revision )
852+ // Verify annotations were updated
853+ assert .Equal (t , "1.0.1" , rev .Annotations [labels .BundleVersionKey ])
854+ assert .Equal (t , "test-package" , rev .Annotations [labels .PackageNameKey ])
855+ // Verify labels still have package name
856+ assert .Equal (t , ext .Name , rev .Labels [controllers .ClusterExtensionRevisionOwnerLabel ])
857+ assert .Equal (t , "test-package" , rev .Labels [labels .PackageNameKey ])
858+ },
859+ },
761860 }
762861
763862 for _ , tc := range testCases {
@@ -780,7 +879,15 @@ func TestBoxcutter_Apply(t *testing.T) {
780879 testFS := fstest.MapFS {}
781880
782881 // Execute
783- installSucceeded , installStatus , err := boxcutter .Apply (t .Context (), testFS , ext , nil , nil )
882+ revisionAnnotations := map [string ]string {}
883+ if tc .name == "annotation-only update (same phases, different annotations)" {
884+ // For annotation-only update test, pass NEW annotations
885+ revisionAnnotations = map [string ]string {
886+ labels .BundleVersionKey : "1.0.1" ,
887+ labels .PackageNameKey : "test-package" ,
888+ }
889+ }
890+ installSucceeded , installStatus , err := boxcutter .Apply (t .Context (), testFS , ext , nil , revisionAnnotations )
784891
785892 // Assert
786893 if tc .expectedErr != "" {
@@ -808,13 +915,17 @@ func TestBoxcutter_Apply(t *testing.T) {
808915
809916func TestBoxcutterStorageMigrator (t * testing.T ) {
810917 t .Run ("creates revision" , func (t * testing.T ) {
918+ testScheme := runtime .NewScheme ()
919+ require .NoError (t , ocv1 .AddToScheme (testScheme ))
920+
811921 brb := & mockBundleRevisionBuilder {}
812922 mag := & mockActionGetter {}
813923 client := & clientMock {}
814924 sm := & applier.BoxcutterStorageMigrator {
815925 RevisionGenerator : brb ,
816926 ActionClientGetter : mag ,
817927 Client : client ,
928+ Scheme : testScheme ,
818929 }
819930
820931 ext := & ocv1.ClusterExtension {
@@ -828,6 +939,10 @@ func TestBoxcutterStorageMigrator(t *testing.T) {
828939 On ("Create" , mock .Anything , mock .AnythingOfType ("*v1.ClusterExtensionRevision" ), mock .Anything ).
829940 Once ().
830941 Return (nil )
942+ client .
943+ On ("Update" , mock .Anything , mock .AnythingOfType ("*v1.ClusterExtensionRevision" ), mock .Anything ).
944+ Once ().
945+ Return (nil )
831946
832947 err := sm .Migrate (t .Context (), ext , map [string ]string {"my-label" : "my-value" })
833948 require .NoError (t , err )
@@ -836,13 +951,17 @@ func TestBoxcutterStorageMigrator(t *testing.T) {
836951 })
837952
838953 t .Run ("does not create revision when revisions exist" , func (t * testing.T ) {
954+ testScheme := runtime .NewScheme ()
955+ require .NoError (t , ocv1 .AddToScheme (testScheme ))
956+
839957 brb := & mockBundleRevisionBuilder {}
840958 mag := & mockActionGetter {}
841959 client := & clientMock {}
842960 sm := & applier.BoxcutterStorageMigrator {
843961 RevisionGenerator : brb ,
844962 ActionClientGetter : mag ,
845963 Client : client ,
964+ Scheme : testScheme ,
846965 }
847966
848967 ext := & ocv1.ClusterExtension {
@@ -866,6 +985,9 @@ func TestBoxcutterStorageMigrator(t *testing.T) {
866985 })
867986
868987 t .Run ("does not create revision when no helm release" , func (t * testing.T ) {
988+ testScheme := runtime .NewScheme ()
989+ require .NoError (t , ocv1 .AddToScheme (testScheme ))
990+
869991 brb := & mockBundleRevisionBuilder {}
870992 mag := & mockActionGetter {
871993 getClientErr : driver .ErrReleaseNotFound ,
@@ -875,6 +997,7 @@ func TestBoxcutterStorageMigrator(t *testing.T) {
875997 RevisionGenerator : brb ,
876998 ActionClientGetter : mag ,
877999 Client : client ,
1000+ Scheme : testScheme ,
8781001 }
8791002
8801003 ext := & ocv1.ClusterExtension {
@@ -905,7 +1028,15 @@ func (m *mockBundleRevisionBuilder) GenerateRevisionFromHelmRelease(
9051028 helmRelease * release.Release , ext * ocv1.ClusterExtension ,
9061029 objectLabels map [string ]string ,
9071030) (* ocv1.ClusterExtensionRevision , error ) {
908- return nil , nil
1031+ return & ocv1.ClusterExtensionRevision {
1032+ ObjectMeta : metav1.ObjectMeta {
1033+ Name : "test-revision" ,
1034+ Labels : map [string ]string {
1035+ controllers .ClusterExtensionRevisionOwnerLabel : ext .Name ,
1036+ },
1037+ },
1038+ Spec : ocv1.ClusterExtensionRevisionSpec {},
1039+ }, nil
9091040}
9101041
9111042type clientMock struct {
@@ -921,3 +1052,26 @@ func (m *clientMock) Create(ctx context.Context, obj client.Object, opts ...clie
9211052 args := m .Called (ctx , obj , opts )
9221053 return args .Error (0 )
9231054}
1055+
1056+ func (m * clientMock ) Status () client.StatusWriter {
1057+ return & statusWriterMock {mock : & m .Mock }
1058+ }
1059+
1060+ type statusWriterMock struct {
1061+ mock * mock.Mock
1062+ }
1063+
1064+ func (s * statusWriterMock ) Update (ctx context.Context , obj client.Object , opts ... client.SubResourceUpdateOption ) error {
1065+ args := s .mock .Called (ctx , obj , opts )
1066+ return args .Error (0 )
1067+ }
1068+
1069+ func (s * statusWriterMock ) Patch (ctx context.Context , obj client.Object , patch client.Patch , opts ... client.SubResourcePatchOption ) error {
1070+ args := s .mock .Called (ctx , obj , patch , opts )
1071+ return args .Error (0 )
1072+ }
1073+
1074+ func (s * statusWriterMock ) Create (ctx context.Context , obj client.Object , subResource client.Object , opts ... client.SubResourceCreateOption ) error {
1075+ args := s .mock .Called (ctx , obj , subResource , opts )
1076+ return args .Error (0 )
1077+ }
0 commit comments