sigs.k8s.io/cluster-api@v1.7.1/internal/runtime/registry/registry_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 registry
    18  
    19  import (
    20  	"testing"
    21  
    22  	. "github.com/onsi/gomega"
    23  	"github.com/onsi/gomega/format"
    24  	"github.com/onsi/gomega/types"
    25  	"github.com/pkg/errors"
    26  	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
    27  	"k8s.io/utils/ptr"
    28  
    29  	runtimev1 "sigs.k8s.io/cluster-api/exp/runtime/api/v1alpha1"
    30  	runtimecatalog "sigs.k8s.io/cluster-api/exp/runtime/catalog"
    31  )
    32  
    33  func TestColdRegistry(t *testing.T) {
    34  	g := NewWithT(t)
    35  
    36  	r := New()
    37  	g.Expect(r.IsReady()).To(BeFalse())
    38  
    39  	// Add, Remove, List and Get should fail with a cold registry.
    40  	g.Expect(r.Add(&runtimev1.ExtensionConfig{})).ToNot(Succeed())
    41  	g.Expect(r.Remove(&runtimev1.ExtensionConfig{})).ToNot(Succeed())
    42  	_, err := r.List(runtimecatalog.GroupHook{Group: "foo", Hook: "bak"})
    43  	g.Expect(err).To(HaveOccurred())
    44  	_, err = r.Get("foo")
    45  	g.Expect(err).To(HaveOccurred())
    46  }
    47  
    48  func TestWarmUpRegistry(t *testing.T) {
    49  	g := NewWithT(t)
    50  
    51  	extensionConfigList := &runtimev1.ExtensionConfigList{
    52  		Items: []runtimev1.ExtensionConfig{
    53  			{
    54  				ObjectMeta: metav1.ObjectMeta{
    55  					Name: "test-extension",
    56  				},
    57  				Status: runtimev1.ExtensionConfigStatus{
    58  					Handlers: []runtimev1.ExtensionHandler{
    59  						{
    60  							Name: "handler.test-extension",
    61  							RequestHook: runtimev1.GroupVersionHook{
    62  								APIVersion: "foo/v1alpha1",
    63  								Hook:       "bak",
    64  							},
    65  						},
    66  					},
    67  				},
    68  			},
    69  		},
    70  	}
    71  
    72  	// WarmUp registry.
    73  	r := New()
    74  	g.Expect(r.WarmUp(extensionConfigList)).To(Succeed())
    75  	g.Expect(r.IsReady()).To(BeTrue())
    76  
    77  	// A second WarmUp should fail, registry should stay ready.
    78  	g.Expect(r.WarmUp(extensionConfigList)).ToNot(Succeed())
    79  	g.Expect(r.IsReady()).To(BeTrue())
    80  
    81  	// Add, Remove, List and Get should work with a warmed up registry.
    82  	g.Expect(r.Add(&runtimev1.ExtensionConfig{})).To(Succeed())
    83  	g.Expect(r.Remove(&runtimev1.ExtensionConfig{})).To(Succeed())
    84  
    85  	registrations, err := r.List(runtimecatalog.GroupHook{Group: "foo", Hook: "bak"})
    86  	g.Expect(err).ToNot(HaveOccurred())
    87  	g.Expect(registrations).To(HaveLen(1))
    88  	g.Expect(registrations[0].Name).To(Equal("handler.test-extension"))
    89  
    90  	registration, err := r.Get("handler.test-extension")
    91  	g.Expect(err).ToNot(HaveOccurred())
    92  	g.Expect(registration.Name).To(Equal("handler.test-extension"))
    93  }
    94  
    95  func TestRegistry(t *testing.T) {
    96  	g := NewWithT(t)
    97  
    98  	extension1 := &runtimev1.ExtensionConfig{
    99  		ObjectMeta: metav1.ObjectMeta{
   100  			Name: "extension1",
   101  		},
   102  		Spec: runtimev1.ExtensionConfigSpec{
   103  			ClientConfig: runtimev1.ClientConfig{
   104  				URL: ptr.To("https://extesions1.com/"),
   105  			},
   106  		},
   107  		Status: runtimev1.ExtensionConfigStatus{
   108  			Handlers: []runtimev1.ExtensionHandler{
   109  				{
   110  					Name: "foo.extension1",
   111  					RequestHook: runtimev1.GroupVersionHook{
   112  						APIVersion: "hook.runtime.cluster.x-k8s.io/v1alpha1",
   113  						Hook:       "BeforeClusterUpgrade",
   114  					},
   115  				},
   116  				{
   117  					Name: "bar.extension1",
   118  					RequestHook: runtimev1.GroupVersionHook{
   119  						APIVersion: "hook.runtime.cluster.x-k8s.io/v1alpha1",
   120  						Hook:       "BeforeClusterUpgrade",
   121  					},
   122  				},
   123  				{
   124  					Name: "baz.extension1",
   125  					RequestHook: runtimev1.GroupVersionHook{
   126  						APIVersion: "hook.runtime.cluster.x-k8s.io/v1alpha1",
   127  						Hook:       "AfterClusterUpgrade",
   128  					},
   129  				},
   130  			},
   131  		},
   132  	}
   133  
   134  	extension2 := &runtimev1.ExtensionConfig{
   135  		ObjectMeta: metav1.ObjectMeta{
   136  			Name: "extension2",
   137  		},
   138  		Spec: runtimev1.ExtensionConfigSpec{
   139  			ClientConfig: runtimev1.ClientConfig{
   140  				URL: ptr.To("https://extesions2.com/"),
   141  			},
   142  		},
   143  		Status: runtimev1.ExtensionConfigStatus{
   144  			Handlers: []runtimev1.ExtensionHandler{
   145  				{
   146  					Name: "qux.extension2",
   147  					RequestHook: runtimev1.GroupVersionHook{
   148  						APIVersion: "hook.runtime.cluster.x-k8s.io/v1alpha1",
   149  						Hook:       "AfterClusterUpgrade",
   150  					},
   151  				},
   152  			},
   153  		},
   154  	}
   155  
   156  	// WarmUp with extension1
   157  	e := New()
   158  	err := e.WarmUp(&runtimev1.ExtensionConfigList{Items: []runtimev1.ExtensionConfig{*extension1}})
   159  	g.Expect(err).ToNot(HaveOccurred())
   160  	g.Expect(e.IsReady()).To(BeTrue())
   161  
   162  	// Get an extension by name
   163  	registration, err := e.Get("foo.extension1")
   164  	g.Expect(err).ToNot(HaveOccurred())
   165  	g.Expect(registration.Name).To(Equal("foo.extension1"))
   166  
   167  	// List all BeforeClusterUpgrade extensions
   168  	registrations, err := e.List(runtimecatalog.GroupHook{Group: "hook.runtime.cluster.x-k8s.io", Hook: "BeforeClusterUpgrade"})
   169  	g.Expect(err).ToNot(HaveOccurred())
   170  	g.Expect(registrations).To(HaveLen(2))
   171  	g.Expect(registrations).To(ContainExtension("foo.extension1"))
   172  	g.Expect(registrations).To(ContainExtension("bar.extension1"))
   173  
   174  	// List all AfterClusterUpgrade extensions
   175  	registrations, err = e.List(runtimecatalog.GroupHook{Group: "hook.runtime.cluster.x-k8s.io", Hook: "AfterClusterUpgrade"})
   176  	g.Expect(err).ToNot(HaveOccurred())
   177  	g.Expect(registrations).To(HaveLen(1))
   178  	g.Expect(registrations).To(ContainExtension("baz.extension1"))
   179  
   180  	// Add extension2 with one more AfterClusterUpgrade and check it is there
   181  	g.Expect(e.Add(extension2)).To(Succeed())
   182  
   183  	registrations, err = e.List(runtimecatalog.GroupHook{Group: "hook.runtime.cluster.x-k8s.io", Hook: "AfterClusterUpgrade"})
   184  	g.Expect(err).ToNot(HaveOccurred())
   185  	g.Expect(registrations).To(HaveLen(2))
   186  	g.Expect(registrations).To(ContainExtension("baz.extension1"))
   187  	g.Expect(registrations).To(ContainExtension("qux.extension2"))
   188  
   189  	// Remove extension1 and check everything is updated
   190  	g.Expect(e.Remove(extension1)).To(Succeed())
   191  
   192  	registrations, err = e.List(runtimecatalog.GroupHook{Group: "hook.runtime.cluster.x-k8s.io", Hook: "BeforeClusterUpgrade"})
   193  	g.Expect(err).ToNot(HaveOccurred())
   194  	g.Expect(registrations).To(BeEmpty())
   195  
   196  	registrations, err = e.List(runtimecatalog.GroupHook{Group: "hook.runtime.cluster.x-k8s.io", Hook: "AfterClusterUpgrade"})
   197  	g.Expect(err).ToNot(HaveOccurred())
   198  	g.Expect(registrations).To(HaveLen(1))
   199  	g.Expect(registrations).To(ContainExtension("qux.extension2"))
   200  }
   201  
   202  func ContainExtension(name string) types.GomegaMatcher {
   203  	return &ContainExtensionMatcher{
   204  		name: name,
   205  	}
   206  }
   207  
   208  type ContainExtensionMatcher struct {
   209  	name string
   210  }
   211  
   212  func (matcher *ContainExtensionMatcher) Match(actual interface{}) (success bool, err error) {
   213  	ext, ok := actual.([]*ExtensionRegistration)
   214  	if !ok {
   215  		return false, errors.Errorf("Expecting *ExtensionRegistration, got %t", actual)
   216  	}
   217  
   218  	for _, e := range ext {
   219  		if e.Name == matcher.name {
   220  			return true, nil
   221  		}
   222  	}
   223  	return false, nil
   224  }
   225  
   226  func (matcher *ContainExtensionMatcher) FailureMessage(actual interface{}) (message string) {
   227  	return format.Message(actual, "to contain element matching", matcher.name)
   228  }
   229  
   230  func (matcher *ContainExtensionMatcher) NegatedFailureMessage(actual interface{}) (message string) {
   231  	return format.Message(actual, "not to contain element matching", matcher.name)
   232  }