sigs.k8s.io/cluster-api@v1.7.1/exp/runtime/catalog/test/catalog_test.go (about)

     1  /*
     2  Copyright 2022 The Kubernetes Authors.
     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 test contains catalog tests
    18  // Note: They have to be outside the catalog package to be realistic. Otherwise using
    19  // test types with different versions would result in a cyclic dependency and thus
    20  // wouldn't be possible.
    21  package test
    22  
    23  import (
    24  	"testing"
    25  
    26  	. "github.com/onsi/gomega"
    27  	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
    28  	"k8s.io/apimachinery/pkg/runtime"
    29  	"k8s.io/apimachinery/pkg/runtime/schema"
    30  
    31  	runtimecatalog "sigs.k8s.io/cluster-api/exp/runtime/catalog"
    32  	"sigs.k8s.io/cluster-api/internal/runtime/test/v1alpha1"
    33  	"sigs.k8s.io/cluster-api/internal/runtime/test/v1alpha2"
    34  )
    35  
    36  var c = runtimecatalog.New()
    37  
    38  func init() {
    39  	_ = v1alpha1.AddToCatalog(c)
    40  	_ = v1alpha2.AddToCatalog(c)
    41  }
    42  
    43  func TestCatalog(t *testing.T) {
    44  	g := NewWithT(t)
    45  
    46  	verify := func(hook runtimecatalog.Hook, expectedGV schema.GroupVersion) {
    47  		// Test GroupVersionHook
    48  		hookGVH, err := c.GroupVersionHook(hook)
    49  		g.Expect(err).ToNot(HaveOccurred())
    50  		g.Expect(hookGVH.GroupVersion()).To(BeComparableTo(expectedGV))
    51  		g.Expect(hookGVH.Hook).To(Equal("FakeHook"))
    52  
    53  		// Test Request
    54  		requestGVK, err := c.Request(hookGVH)
    55  		g.Expect(err).ToNot(HaveOccurred())
    56  		g.Expect(requestGVK.GroupVersion()).To(BeComparableTo(expectedGV))
    57  		g.Expect(requestGVK.Kind).To(Equal("FakeRequest"))
    58  
    59  		// Test Response
    60  		responseGVK, err := c.Response(hookGVH)
    61  		g.Expect(err).ToNot(HaveOccurred())
    62  		g.Expect(responseGVK.GroupVersion()).To(BeComparableTo(expectedGV))
    63  		g.Expect(responseGVK.Kind).To(Equal("FakeResponse"))
    64  
    65  		// Test NewRequest
    66  		request, err := c.NewRequest(hookGVH)
    67  		g.Expect(err).ToNot(HaveOccurred())
    68  
    69  		// Test NewResponse
    70  		response, err := c.NewResponse(hookGVH)
    71  		g.Expect(err).ToNot(HaveOccurred())
    72  
    73  		// Test ValidateRequest/ValidateResponse
    74  		g.Expect(c.ValidateRequest(hookGVH, request)).To(Succeed())
    75  		g.Expect(c.ValidateResponse(hookGVH, response)).To(Succeed())
    76  	}
    77  
    78  	verify(v1alpha1.FakeHook, v1alpha1.GroupVersion)
    79  	verify(v1alpha2.FakeHook, v1alpha2.GroupVersion)
    80  }
    81  
    82  func TestValidateRequest(t *testing.T) {
    83  	v1alpha1Hook, err := c.GroupVersionHook(v1alpha1.FakeHook)
    84  	if err != nil {
    85  		panic("failed to get GVH of hook")
    86  	}
    87  	v1alpha1HookRequest, err := c.NewRequest(v1alpha1Hook)
    88  	if err != nil {
    89  		panic("failed to create request for hook")
    90  	}
    91  
    92  	v1alpha2Hook, err := c.GroupVersionHook(v1alpha2.FakeHook)
    93  	if err != nil {
    94  		panic("failed to get GVH of hook")
    95  	}
    96  
    97  	tests := []struct {
    98  		name      string
    99  		hook      runtimecatalog.GroupVersionHook
   100  		request   runtime.Object
   101  		wantError bool
   102  	}{
   103  		{
   104  			name:      "should succeed when hook and request match",
   105  			hook:      v1alpha1Hook,
   106  			request:   v1alpha1HookRequest,
   107  			wantError: false,
   108  		},
   109  		{
   110  			name:      "should error when hook and request do not match",
   111  			hook:      v1alpha2Hook,
   112  			request:   v1alpha1HookRequest,
   113  			wantError: true,
   114  		},
   115  	}
   116  
   117  	for _, tt := range tests {
   118  		t.Run(tt.name, func(t *testing.T) {
   119  			g := NewWithT(t)
   120  			err := c.ValidateRequest(tt.hook, tt.request)
   121  			if tt.wantError {
   122  				g.Expect(err).To(HaveOccurred())
   123  			} else {
   124  				g.Expect(err).ToNot(HaveOccurred())
   125  			}
   126  		})
   127  	}
   128  }
   129  
   130  func TestValidateResponse(t *testing.T) {
   131  	v1alpha1Hook, err := c.GroupVersionHook(v1alpha1.FakeHook)
   132  	if err != nil {
   133  		panic("failed to get GVH of hook")
   134  	}
   135  	v1alpha1HookResponse, err := c.NewResponse(v1alpha1Hook)
   136  	if err != nil {
   137  		panic("failed to create request for hook")
   138  	}
   139  
   140  	v1alpha2Hook, err := c.GroupVersionHook(v1alpha2.FakeHook)
   141  	if err != nil {
   142  		panic("failed to get GVH of hook")
   143  	}
   144  
   145  	tests := []struct {
   146  		name      string
   147  		hook      runtimecatalog.GroupVersionHook
   148  		response  runtime.Object
   149  		wantError bool
   150  	}{
   151  		{
   152  			name:      "should succeed when hook and response match",
   153  			hook:      v1alpha1Hook,
   154  			response:  v1alpha1HookResponse,
   155  			wantError: false,
   156  		},
   157  		{
   158  			name:      "should error when hook and response do not match",
   159  			hook:      v1alpha2Hook,
   160  			response:  v1alpha1HookResponse,
   161  			wantError: true,
   162  		},
   163  	}
   164  
   165  	for _, tt := range tests {
   166  		t.Run(tt.name, func(t *testing.T) {
   167  			g := NewWithT(t)
   168  			err := c.ValidateResponse(tt.hook, tt.response)
   169  			if tt.wantError {
   170  				g.Expect(err).To(HaveOccurred())
   171  			} else {
   172  				g.Expect(err).ToNot(HaveOccurred())
   173  			}
   174  		})
   175  	}
   176  }
   177  
   178  func TestHookName(t *testing.T) {
   179  	g := NewWithT(t)
   180  	expected := "FakeHook"
   181  	actual := runtimecatalog.HookName(v1alpha1.FakeHook)
   182  	g.Expect(actual).To(Equal(expected))
   183  }
   184  
   185  type GoodRequest struct {
   186  	metav1.TypeMeta `json:",inline"`
   187  
   188  	First string `json:"first"`
   189  }
   190  
   191  func (in *GoodRequest) DeepCopyObject() runtime.Object {
   192  	panic("implement me!")
   193  }
   194  
   195  // BadRequest does not implement runtime.Object interface (missing DeepCopyObject function).
   196  type BadRequest struct {
   197  	metav1.TypeMeta `json:",inline"`
   198  
   199  	First string `json:"first"`
   200  }
   201  
   202  type GoodResponse struct {
   203  	metav1.TypeMeta `json:",inline"`
   204  
   205  	First string `json:"first"`
   206  }
   207  
   208  func (out *GoodResponse) DeepCopyObject() runtime.Object {
   209  	panic("implement me!")
   210  }
   211  
   212  // BadResponse does not implement runtime.Object interface (missing DeepCopyObject function).
   213  type BadResponse struct {
   214  	metav1.TypeMeta `json:",inline"`
   215  
   216  	First string `json:"first"`
   217  }
   218  
   219  func GoodHook(*GoodRequest, *GoodResponse) {}
   220  
   221  func HookWithReturn(*GoodRequest) *GoodResponse { return nil }
   222  
   223  func HookWithNoInputs() {}
   224  
   225  func HookWithThreeInputs(*GoodRequest, *GoodRequest, *GoodResponse) {}
   226  
   227  func HookWithBadRequestAndResponse(*BadRequest, *BadResponse) {}
   228  
   229  func TestAddHook(t *testing.T) {
   230  	c := runtimecatalog.New()
   231  
   232  	tests := []struct {
   233  		name      string
   234  		hook      runtimecatalog.Hook
   235  		hookMeta  *runtimecatalog.HookMeta
   236  		wantPanic bool
   237  	}{
   238  		{
   239  			name:      "should pass for valid hook",
   240  			hook:      GoodHook,
   241  			hookMeta:  &runtimecatalog.HookMeta{},
   242  			wantPanic: false,
   243  		},
   244  		{
   245  			name:      "should fail for hook with a return value",
   246  			hook:      HookWithReturn,
   247  			hookMeta:  &runtimecatalog.HookMeta{},
   248  			wantPanic: true,
   249  		},
   250  		{
   251  			name:      "should fail for a hook with no inputs",
   252  			hook:      HookWithNoInputs,
   253  			hookMeta:  &runtimecatalog.HookMeta{},
   254  			wantPanic: true,
   255  		},
   256  		{
   257  			name:      "should fail for a hook with more than two arguments",
   258  			hook:      HookWithThreeInputs,
   259  			hookMeta:  &runtimecatalog.HookMeta{},
   260  			wantPanic: true,
   261  		},
   262  		{
   263  			name:      "should fail for hook with bad request and response arguments",
   264  			hook:      HookWithBadRequestAndResponse,
   265  			hookMeta:  &runtimecatalog.HookMeta{},
   266  			wantPanic: true,
   267  		},
   268  		{
   269  			name:      "should fail if the hookMeta is nil",
   270  			hook:      GoodHook,
   271  			hookMeta:  nil,
   272  			wantPanic: true,
   273  		},
   274  	}
   275  
   276  	for _, tt := range tests {
   277  		t.Run(tt.name, func(t *testing.T) {
   278  			g := NewWithT(t)
   279  			testFunc := func() {
   280  				c.AddHook(v1alpha1.GroupVersion, tt.hook, tt.hookMeta)
   281  			}
   282  			if tt.wantPanic {
   283  				g.Expect(testFunc).Should(Panic())
   284  			} else {
   285  				g.Expect(testFunc).ShouldNot(Panic())
   286  			}
   287  		})
   288  	}
   289  }