github.com/redhat-appstudio/release-service@v0.0.0-20240507143925-083712697924/controllers/releaseplan/adapter_test.go (about)

     1  /*
     2  Copyright 2022.
     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 releaseplan
    18  
    19  import (
    20  	"reflect"
    21  	"time"
    22  
    23  	toolkit "github.com/konflux-ci/operator-toolkit/loader"
    24  	. "github.com/onsi/ginkgo/v2"
    25  	. "github.com/onsi/gomega"
    26  	"github.com/redhat-appstudio/release-service/api/v1alpha1"
    27  	"github.com/redhat-appstudio/release-service/loader"
    28  	"k8s.io/apimachinery/pkg/api/meta"
    29  
    30  	applicationapiv1alpha1 "github.com/redhat-appstudio/application-api/api/v1alpha1"
    31  	tektonutils "github.com/redhat-appstudio/release-service/tekton/utils"
    32  
    33  	"k8s.io/apimachinery/pkg/api/errors"
    34  	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
    35  	"k8s.io/apimachinery/pkg/runtime/schema"
    36  	ctrl "sigs.k8s.io/controller-runtime"
    37  )
    38  
    39  var _ = Describe("ReleasePlan adapter", Ordered, func() {
    40  	var (
    41  		createReleasePlanAndAdapter func() *adapter
    42  		createResources             func()
    43  		deleteResources             func()
    44  
    45  		application          *applicationapiv1alpha1.Application
    46  		releasePlanAdmission *v1alpha1.ReleasePlanAdmission
    47  	)
    48  
    49  	AfterAll(func() {
    50  		deleteResources()
    51  	})
    52  
    53  	BeforeAll(func() {
    54  		createResources()
    55  	})
    56  
    57  	Context("When newAdapter is called", func() {
    58  		It("creates and return a new adapter", func() {
    59  			Expect(reflect.TypeOf(newAdapter(ctx, k8sClient, nil, loader.NewLoader(), &ctrl.Log))).To(Equal(reflect.TypeOf(&adapter{})))
    60  		})
    61  	})
    62  
    63  	Context("When EnsureOwnerReferenceIsSet is called", func() {
    64  		var adapter *adapter
    65  
    66  		AfterEach(func() {
    67  			_ = adapter.client.Delete(ctx, adapter.releasePlan)
    68  		})
    69  
    70  		BeforeEach(func() {
    71  			adapter = createReleasePlanAndAdapter()
    72  		})
    73  
    74  		It("should not fail if the Application does not exist", func() {
    75  			adapter.ctx = toolkit.GetMockedContext(ctx, []toolkit.MockData{
    76  				{
    77  					ContextKey: loader.ApplicationContextKey,
    78  					Err:        errors.NewNotFound(schema.GroupResource{}, ""),
    79  				},
    80  			})
    81  
    82  			result, err := adapter.EnsureOwnerReferenceIsSet()
    83  			Expect(result.RequeueRequest && !result.CancelRequest).To(BeTrue())
    84  			Expect(result.RequeueDelay).To(Equal(time.Minute))
    85  			Expect(err).NotTo(HaveOccurred())
    86  			Expect(adapter.releasePlan.OwnerReferences).To(HaveLen(0))
    87  		})
    88  
    89  		It("should set the owner reference", func() {
    90  			adapter.ctx = toolkit.GetMockedContext(ctx, []toolkit.MockData{
    91  				{
    92  					ContextKey: loader.ApplicationContextKey,
    93  					Resource:   application,
    94  				},
    95  			})
    96  
    97  			Expect(adapter.releasePlan.OwnerReferences).To(HaveLen(0))
    98  			result, err := adapter.EnsureOwnerReferenceIsSet()
    99  			Expect(!result.RequeueRequest && !result.CancelRequest).To(BeTrue())
   100  			Expect(err).NotTo(HaveOccurred())
   101  			Expect(adapter.releasePlan.OwnerReferences).To(HaveLen(1))
   102  		})
   103  
   104  		It("should delete the releasePlan if the owner is deleted", func() {
   105  			newApplication := &applicationapiv1alpha1.Application{
   106  				ObjectMeta: metav1.ObjectMeta{
   107  					GenerateName: "application-",
   108  					Namespace:    "default",
   109  				},
   110  			}
   111  			Expect(k8sClient.Create(ctx, newApplication)).To(Succeed())
   112  
   113  			adapter.ctx = toolkit.GetMockedContext(ctx, []toolkit.MockData{
   114  				{
   115  					ContextKey: loader.ApplicationContextKey,
   116  					Resource:   newApplication,
   117  				},
   118  			})
   119  
   120  			Expect(adapter.releasePlan.OwnerReferences).To(HaveLen(0))
   121  			result, err := adapter.EnsureOwnerReferenceIsSet()
   122  			Expect(!result.RequeueRequest && !result.CancelRequest).To(BeTrue())
   123  			Expect(err).NotTo(HaveOccurred())
   124  			Expect(adapter.releasePlan.OwnerReferences).To(HaveLen(1))
   125  
   126  			Expect(k8sClient.Delete(ctx, newApplication)).To(Succeed())
   127  			_, err = adapter.loader.GetReleasePlan(ctx, k8sClient, &v1alpha1.Release{
   128  				Spec: v1alpha1.ReleaseSpec{
   129  					ReleasePlan: adapter.releasePlan.Name,
   130  				},
   131  			})
   132  			Expect(err).To(HaveOccurred())
   133  		})
   134  	})
   135  
   136  	Context("When EnsureMatchingInformationIsSet is called", func() {
   137  		var adapter *adapter
   138  
   139  		AfterEach(func() {
   140  			_ = adapter.client.Delete(ctx, adapter.releasePlan)
   141  		})
   142  
   143  		BeforeEach(func() {
   144  			adapter = createReleasePlanAndAdapter()
   145  		})
   146  
   147  		It("should mark the ReleasePlan as unmatched if the ReleasePlanAdmission is not found", func() {
   148  			adapter.ctx = toolkit.GetMockedContext(ctx, []toolkit.MockData{
   149  				{
   150  					ContextKey: loader.MatchedReleasePlanAdmissionContextKey,
   151  					Err:        errors.NewNotFound(schema.GroupResource{}, ""),
   152  				},
   153  			})
   154  
   155  			result, err := adapter.EnsureMatchingInformationIsSet()
   156  			Expect(!result.RequeueRequest && !result.CancelRequest).To(BeTrue())
   157  			Expect(err).NotTo(HaveOccurred())
   158  			Expect(adapter.releasePlan.Status.ReleasePlanAdmission).To(Equal(v1alpha1.MatchedReleasePlanAdmission{}))
   159  		})
   160  
   161  		It("should mark the ReleasePlan as matched", func() {
   162  			adapter.ctx = toolkit.GetMockedContext(ctx, []toolkit.MockData{
   163  				{
   164  					ContextKey: loader.MatchedReleasePlanAdmissionContextKey,
   165  					Resource:   releasePlanAdmission,
   166  				},
   167  			})
   168  
   169  			result, err := adapter.EnsureMatchingInformationIsSet()
   170  			Expect(!result.RequeueRequest && !result.CancelRequest).To(BeTrue())
   171  			Expect(err).NotTo(HaveOccurred())
   172  			Expect(adapter.releasePlan.Status.ReleasePlanAdmission.Name).To(Equal(
   173  				releasePlanAdmission.Namespace + "/" + releasePlanAdmission.Name))
   174  		})
   175  
   176  		It("should not update the lastTransitionTime in the condition if the matched ReleasePlanAdmission hasn't changed", func() {
   177  			adapter.ctx = toolkit.GetMockedContext(ctx, []toolkit.MockData{
   178  				{
   179  					ContextKey: loader.MatchedReleasePlanAdmissionContextKey,
   180  					Resource:   releasePlanAdmission,
   181  				},
   182  			})
   183  
   184  			adapter.EnsureMatchingInformationIsSet()
   185  			condition := meta.FindStatusCondition(adapter.releasePlan.Status.Conditions, "Matched")
   186  			lastTransitionTime := condition.LastTransitionTime
   187  			adapter.EnsureMatchingInformationIsSet()
   188  			condition = meta.FindStatusCondition(adapter.releasePlan.Status.Conditions, "Matched")
   189  			Expect(condition.LastTransitionTime).To(Equal(lastTransitionTime))
   190  		})
   191  	})
   192  
   193  	createReleasePlanAndAdapter = func() *adapter {
   194  		releasePlan := &v1alpha1.ReleasePlan{
   195  			ObjectMeta: metav1.ObjectMeta{
   196  				GenerateName: "releaseplan-",
   197  				Namespace:    "default",
   198  			},
   199  			Spec: v1alpha1.ReleasePlanSpec{
   200  				Application: application.Name,
   201  				Target:      "default",
   202  			},
   203  		}
   204  		Expect(k8sClient.Create(ctx, releasePlan)).To(Succeed())
   205  		releasePlan.Kind = "ReleasePlan"
   206  
   207  		return newAdapter(ctx, k8sClient, releasePlan, loader.NewMockLoader(), &ctrl.Log)
   208  	}
   209  
   210  	createResources = func() {
   211  		application = &applicationapiv1alpha1.Application{
   212  			ObjectMeta: metav1.ObjectMeta{
   213  				Name:      "application",
   214  				Namespace: "default",
   215  			},
   216  			Spec: applicationapiv1alpha1.ApplicationSpec{
   217  				DisplayName: "application",
   218  			},
   219  		}
   220  		Expect(k8sClient.Create(ctx, application)).To(Succeed())
   221  
   222  		releasePlanAdmission = &v1alpha1.ReleasePlanAdmission{
   223  			ObjectMeta: metav1.ObjectMeta{
   224  				Name:      "rpa",
   225  				Namespace: "default",
   226  			},
   227  			Spec: v1alpha1.ReleasePlanAdmissionSpec{
   228  				Applications: []string{application.Name},
   229  				Origin:       "default",
   230  				Pipeline: &tektonutils.Pipeline{
   231  					PipelineRef: tektonutils.PipelineRef{
   232  						Resolver: "bundles",
   233  						Params: []tektonutils.Param{
   234  							{Name: "bundle", Value: "quay.io/some/bundle"},
   235  							{Name: "name", Value: "release-pipeline"},
   236  							{Name: "kind", Value: "pipeline"},
   237  						},
   238  					},
   239  				},
   240  				Policy: "policy",
   241  			},
   242  		}
   243  		Expect(k8sClient.Create(ctx, releasePlanAdmission)).To(Succeed())
   244  	}
   245  
   246  	deleteResources = func() {
   247  		Expect(k8sClient.Delete(ctx, application)).To(Succeed())
   248  		Expect(k8sClient.Delete(ctx, releasePlanAdmission)).To(Succeed())
   249  	}
   250  
   251  })