github.com/redhat-appstudio/release-service@v0.0.0-20240507143925-083712697924/controllers/releaseplanadmission/adapter_test.go (about) 1 /* 2 Copyright 2023. 3 4 Licensed under the Apache License, Version 2.0 (the "License"); 5 you may not use this file except in compliance with the License. 6 You may obtain a copy of the License at 7 8 http://www.apache.org/licenses/LICENSE-2.0 9 10 Unless required by applicable law or agreed to in writing, software 11 distributed under the License is distributed on an "AS IS" BASIS, 12 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 See the License for the specific language governing permissions and 14 limitations under the License. 15 */ 16 17 package releaseplanadmission 18 19 import ( 20 "fmt" 21 "reflect" 22 "time" 23 24 toolkit "github.com/konflux-ci/operator-toolkit/loader" 25 . "github.com/onsi/ginkgo/v2" 26 . "github.com/onsi/gomega" 27 "github.com/redhat-appstudio/release-service/api/v1alpha1" 28 "github.com/redhat-appstudio/release-service/loader" 29 "github.com/redhat-appstudio/release-service/metadata" 30 tektonutils "github.com/redhat-appstudio/release-service/tekton/utils" 31 32 "k8s.io/apimachinery/pkg/api/meta" 33 metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" 34 ctrl "sigs.k8s.io/controller-runtime" 35 ) 36 37 var _ = Describe("ReleasePlanAdmission adapter", Ordered, func() { 38 var ( 39 createReleasePlanAdmissionAndAdapter func() *adapter 40 createResources func() 41 deleteResources func() 42 43 releasePlan *v1alpha1.ReleasePlan 44 ) 45 46 AfterAll(func() { 47 deleteResources() 48 }) 49 50 BeforeAll(func() { 51 createResources() 52 }) 53 54 Context("When newAdapter is called", func() { 55 It("creates and return a new adapter", func() { 56 Expect(reflect.TypeOf(newAdapter(ctx, k8sClient, nil, loader.NewLoader(), &ctrl.Log))).To(Equal(reflect.TypeOf(&adapter{}))) 57 }) 58 }) 59 60 Context("When EnsureMatchingInformationIsSet is called", func() { 61 var adapter *adapter 62 63 AfterEach(func() { 64 _ = adapter.client.Delete(ctx, adapter.releasePlanAdmission) 65 }) 66 67 BeforeEach(func() { 68 adapter = createReleasePlanAdmissionAndAdapter() 69 }) 70 71 It("should RequeueWithError if error occurs when looking for ReleasePlans", func() { 72 adapter.ctx = toolkit.GetMockedContext(ctx, []toolkit.MockData{ 73 { 74 ContextKey: loader.MatchedReleasePlansContextKey, 75 Err: fmt.Errorf("some error"), 76 }, 77 }) 78 79 result, err := adapter.EnsureMatchingInformationIsSet() 80 Expect(result.RequeueRequest && !result.CancelRequest).To(BeTrue()) 81 Expect(err).To(HaveOccurred()) 82 Expect(adapter.releasePlanAdmission.Status.ReleasePlans).To(BeNil()) 83 }) 84 85 It("should mark the ReleasePlanAdmission as unmatched if no ReleasePlans are found", func() { 86 adapter.releasePlanAdmission.Status.ReleasePlans = []v1alpha1.MatchedReleasePlan{{Name: "foo"}} 87 adapter.ctx = toolkit.GetMockedContext(ctx, []toolkit.MockData{ 88 { 89 ContextKey: loader.MatchedReleasePlansContextKey, 90 Resource: &v1alpha1.ReleasePlanList{}, 91 }, 92 }) 93 94 result, err := adapter.EnsureMatchingInformationIsSet() 95 Expect(!result.RequeueRequest && !result.CancelRequest).To(BeTrue()) 96 Expect(err).NotTo(HaveOccurred()) 97 Expect(adapter.releasePlanAdmission.Status.ReleasePlans).To(Equal([]v1alpha1.MatchedReleasePlan{})) 98 for i := range adapter.releasePlanAdmission.Status.Conditions { 99 if adapter.releasePlanAdmission.Status.Conditions[i].Type == "Matched" { 100 Expect(adapter.releasePlanAdmission.Status.Conditions[i].Status).To(Equal(metav1.ConditionFalse)) 101 } 102 } 103 }) 104 105 It("should mark the ReleasePlanAdmission as matched if ReleasePlans are found", func() { 106 secondReleasePlan := releasePlan.DeepCopy() 107 secondReleasePlan.Name = "rp-two" 108 adapter.ctx = toolkit.GetMockedContext(ctx, []toolkit.MockData{ 109 { 110 ContextKey: loader.MatchedReleasePlansContextKey, 111 Resource: &v1alpha1.ReleasePlanList{ 112 Items: []v1alpha1.ReleasePlan{ 113 *releasePlan, 114 *secondReleasePlan, 115 }, 116 }, 117 }, 118 }) 119 120 result, err := adapter.EnsureMatchingInformationIsSet() 121 Expect(!result.RequeueRequest && !result.CancelRequest).To(BeTrue()) 122 Expect(err).NotTo(HaveOccurred()) 123 Expect(adapter.releasePlanAdmission.Status.ReleasePlans).To(HaveLen(2)) 124 for i := range adapter.releasePlanAdmission.Status.Conditions { 125 if adapter.releasePlanAdmission.Status.Conditions[i].Type == "Matched" { 126 Expect(adapter.releasePlanAdmission.Status.Conditions[i].Status).To(Equal(metav1.ConditionTrue)) 127 } 128 } 129 }) 130 131 It("should overwrite previously matched ReleasePlans", func() { 132 adapter.releasePlanAdmission.Status.ReleasePlans = []v1alpha1.MatchedReleasePlan{ 133 {Name: "rp-two", Active: false}, 134 {Name: "foo", Active: false}, 135 } 136 secondReleasePlan := releasePlan.DeepCopy() 137 secondReleasePlan.Name = "rp-two" 138 139 adapter.ctx = toolkit.GetMockedContext(ctx, []toolkit.MockData{ 140 { 141 ContextKey: loader.MatchedReleasePlansContextKey, 142 Resource: &v1alpha1.ReleasePlanList{ 143 Items: []v1alpha1.ReleasePlan{ 144 *releasePlan, 145 *secondReleasePlan, 146 }, 147 }, 148 }, 149 }) 150 151 result, err := adapter.EnsureMatchingInformationIsSet() 152 Expect(!result.RequeueRequest && !result.CancelRequest).To(BeTrue()) 153 Expect(err).NotTo(HaveOccurred()) 154 Expect(adapter.releasePlanAdmission.Status.ReleasePlans).To(HaveLen(2)) 155 for i := range adapter.releasePlanAdmission.Status.Conditions { 156 if adapter.releasePlanAdmission.Status.Conditions[i].Type == "Matched" { 157 Expect(adapter.releasePlanAdmission.Status.Conditions[i].Status).To(Equal(metav1.ConditionTrue)) 158 } 159 } 160 for _, releasePlan := range adapter.releasePlanAdmission.Status.ReleasePlans { 161 Expect(releasePlan.Name).NotTo(Equal("foo")) 162 } 163 }) 164 165 It("should update the condition time if only the auto-release label on a ReleasePlan changes", func() { 166 testReleasePlan := releasePlan.DeepCopy() 167 testReleasePlan.Labels = map[string]string{} 168 adapter.ctx = toolkit.GetMockedContext(ctx, []toolkit.MockData{ 169 { 170 ContextKey: loader.MatchedReleasePlansContextKey, 171 Resource: &v1alpha1.ReleasePlanList{ 172 Items: []v1alpha1.ReleasePlan{ 173 *testReleasePlan, 174 }, 175 }, 176 }, 177 }) 178 179 adapter.EnsureMatchingInformationIsSet() 180 condition := meta.FindStatusCondition(adapter.releasePlanAdmission.Status.Conditions, "Matched") 181 lastTransitionTime := condition.LastTransitionTime 182 time.Sleep(1 * time.Second) 183 184 testReleasePlan.Labels[metadata.AutoReleaseLabel] = "true" 185 adapter.ctx = toolkit.GetMockedContext(ctx, []toolkit.MockData{ 186 { 187 ContextKey: loader.MatchedReleasePlansContextKey, 188 Resource: &v1alpha1.ReleasePlanList{ 189 Items: []v1alpha1.ReleasePlan{ 190 *testReleasePlan, 191 }, 192 }, 193 }, 194 }) 195 196 adapter.EnsureMatchingInformationIsSet() 197 condition = meta.FindStatusCondition(adapter.releasePlanAdmission.Status.Conditions, "Matched") 198 Expect(condition.LastTransitionTime).NotTo(Equal(lastTransitionTime)) 199 Expect(adapter.releasePlanAdmission.Status.ReleasePlans).To(HaveLen(1)) 200 Expect(adapter.releasePlanAdmission.Status.ReleasePlans[0].Active).To(BeTrue()) 201 }) 202 }) 203 204 createReleasePlanAdmissionAndAdapter = func() *adapter { 205 releasePlanAdmission := &v1alpha1.ReleasePlanAdmission{ 206 ObjectMeta: metav1.ObjectMeta{ 207 Name: "rpa", 208 Namespace: "default", 209 }, 210 Spec: v1alpha1.ReleasePlanAdmissionSpec{ 211 Applications: []string{"application"}, 212 Origin: "default", 213 Pipeline: &tektonutils.Pipeline{ 214 PipelineRef: tektonutils.PipelineRef{ 215 Resolver: "bundles", 216 Params: []tektonutils.Param{ 217 {Name: "bundle", Value: "quay.io/some/bundle"}, 218 {Name: "name", Value: "release-pipeline"}, 219 {Name: "kind", Value: "pipeline"}, 220 }, 221 }, 222 }, 223 Policy: "policy", 224 }, 225 } 226 Expect(k8sClient.Create(ctx, releasePlanAdmission)).To(Succeed()) 227 releasePlan.Kind = "ReleasePlanAdmission" 228 229 return newAdapter(ctx, k8sClient, releasePlanAdmission, loader.NewMockLoader(), &ctrl.Log) 230 } 231 232 createResources = func() { 233 releasePlan = &v1alpha1.ReleasePlan{ 234 ObjectMeta: metav1.ObjectMeta{ 235 GenerateName: "releaseplan-", 236 Namespace: "default", 237 }, 238 Spec: v1alpha1.ReleasePlanSpec{ 239 Application: "application", 240 Target: "default", 241 }, 242 } 243 Expect(k8sClient.Create(ctx, releasePlan)).To(Succeed()) 244 } 245 246 deleteResources = func() { 247 Expect(k8sClient.Delete(ctx, releasePlan)).To(Succeed()) 248 } 249 250 })