github.com/redhat-appstudio/release-service@v0.0.0-20240507045911-a8558ef3422a/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  })