sigs.k8s.io/cluster-api@v1.7.1/internal/runtime/client/fake/fake_client.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 fake is used to help with testing functions that need a fake RuntimeClient. 18 package fake 19 20 import ( 21 "context" 22 "fmt" 23 24 "github.com/pkg/errors" 25 metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" 26 27 runtimev1 "sigs.k8s.io/cluster-api/exp/runtime/api/v1alpha1" 28 runtimecatalog "sigs.k8s.io/cluster-api/exp/runtime/catalog" 29 runtimehooksv1 "sigs.k8s.io/cluster-api/exp/runtime/hooks/api/v1alpha1" 30 runtimeclient "sigs.k8s.io/cluster-api/internal/runtime/client" 31 ) 32 33 // RuntimeClientBuilder is used to build a fake runtime client. 34 type RuntimeClientBuilder struct { 35 ready bool 36 catalog *runtimecatalog.Catalog 37 callAllResponses map[runtimecatalog.GroupVersionHook]runtimehooksv1.ResponseObject 38 callResponses map[string]runtimehooksv1.ResponseObject 39 } 40 41 // NewRuntimeClientBuilder returns a new builder for the fake runtime client. 42 func NewRuntimeClientBuilder() *RuntimeClientBuilder { 43 return &RuntimeClientBuilder{} 44 } 45 46 // WithCatalog can be use the provided catalog in the fake runtime client. 47 func (f *RuntimeClientBuilder) WithCatalog(catalog *runtimecatalog.Catalog) *RuntimeClientBuilder { 48 f.catalog = catalog 49 return f 50 } 51 52 // WithCallAllExtensionResponses can be used to dictate the responses for CallAllExtensions. 53 func (f *RuntimeClientBuilder) WithCallAllExtensionResponses(responses map[runtimecatalog.GroupVersionHook]runtimehooksv1.ResponseObject) *RuntimeClientBuilder { 54 f.callAllResponses = responses 55 return f 56 } 57 58 // WithCallExtensionResponses can be used to dictate the responses for CallExtension. 59 func (f *RuntimeClientBuilder) WithCallExtensionResponses(responses map[string]runtimehooksv1.ResponseObject) *RuntimeClientBuilder { 60 f.callResponses = responses 61 return f 62 } 63 64 // MarkReady can be used to mark the fake runtime client as either ready or not ready. 65 func (f *RuntimeClientBuilder) MarkReady(ready bool) *RuntimeClientBuilder { 66 f.ready = ready 67 return f 68 } 69 70 // Build returns the fake runtime client. 71 func (f *RuntimeClientBuilder) Build() *RuntimeClient { 72 return &RuntimeClient{ 73 isReady: f.ready, 74 callAllResponses: f.callAllResponses, 75 callResponses: f.callResponses, 76 catalog: f.catalog, 77 callAllTracker: map[string]int{}, 78 } 79 } 80 81 var _ runtimeclient.Client = &RuntimeClient{} 82 83 // RuntimeClient is a fake implementation of runtimeclient.Client. 84 type RuntimeClient struct { 85 isReady bool 86 catalog *runtimecatalog.Catalog 87 callAllResponses map[runtimecatalog.GroupVersionHook]runtimehooksv1.ResponseObject 88 callResponses map[string]runtimehooksv1.ResponseObject 89 90 callAllTracker map[string]int 91 } 92 93 // CallAllExtensions implements Client. 94 func (fc *RuntimeClient) CallAllExtensions(ctx context.Context, hook runtimecatalog.Hook, _ metav1.Object, _ runtimehooksv1.RequestObject, response runtimehooksv1.ResponseObject) error { 95 defer func() { 96 fc.callAllTracker[runtimecatalog.HookName(hook)]++ 97 }() 98 99 gvh, err := fc.catalog.GroupVersionHook(hook) 100 if err != nil { 101 return errors.Wrap(err, "failed to compute GVH") 102 } 103 104 expectedResponse, ok := fc.callAllResponses[gvh] 105 if !ok { 106 // This should actually panic because an error here would mean a mistake in the test setup. 107 panic(fmt.Sprintf("test response not available hook for %q", gvh)) 108 } 109 110 if err := fc.catalog.Convert(expectedResponse, response, ctx); err != nil { 111 // This should actually panic because an error here would mean a mistake in the test setup. 112 panic("cannot update response") 113 } 114 115 if response.GetStatus() == runtimehooksv1.ResponseStatusFailure { 116 return errors.Errorf("runtime hook %q failed", gvh) 117 } 118 return nil 119 } 120 121 // CallExtension implements Client. 122 func (fc *RuntimeClient) CallExtension(ctx context.Context, _ runtimecatalog.Hook, _ metav1.Object, name string, _ runtimehooksv1.RequestObject, response runtimehooksv1.ResponseObject) error { 123 expectedResponse, ok := fc.callResponses[name] 124 if !ok { 125 // This should actually panic because an error here would mean a mistake in the test setup. 126 panic(fmt.Sprintf("test response not available for extension %q", name)) 127 } 128 129 if err := fc.catalog.Convert(expectedResponse, response, ctx); err != nil { 130 // This should actually panic because an error here would mean a mistake in the test setup. 131 panic("cannot update response") 132 } 133 134 // If the received response is a failure then return an error. 135 if response.GetStatus() == runtimehooksv1.ResponseStatusFailure { 136 return errors.Errorf("ExtensionHandler %s failed with message %s", name, response.GetMessage()) 137 } 138 return nil 139 } 140 141 // Discover implements Client. 142 func (fc *RuntimeClient) Discover(context.Context, *runtimev1.ExtensionConfig) (*runtimev1.ExtensionConfig, error) { 143 panic("unimplemented") 144 } 145 146 // IsReady implements Client. 147 func (fc *RuntimeClient) IsReady() bool { 148 return fc.isReady 149 } 150 151 // Register implements Client. 152 func (fc *RuntimeClient) Register(_ *runtimev1.ExtensionConfig) error { 153 panic("unimplemented") 154 } 155 156 // Unregister implements Client. 157 func (fc *RuntimeClient) Unregister(_ *runtimev1.ExtensionConfig) error { 158 panic("unimplemented") 159 } 160 161 // WarmUp implements Client. 162 func (fc *RuntimeClient) WarmUp(_ *runtimev1.ExtensionConfigList) error { 163 panic("unimplemented") 164 } 165 166 // CallAllCount return the number of times a hook was called. 167 func (fc *RuntimeClient) CallAllCount(hook runtimecatalog.Hook) int { 168 return fc.callAllTracker[runtimecatalog.HookName(hook)] 169 }