github.com/kiali/kiali@v1.84.0/kubernetes/kubetest/mock.go (about) 1 package kubetest 2 3 import ( 4 "sync" 5 6 "github.com/go-jose/go-jose/jwt" 7 osapps_v1 "github.com/openshift/api/apps/v1" 8 "github.com/stretchr/testify/mock" 9 istio_fake "istio.io/client-go/pkg/clientset/versioned/fake" 10 apps_v1 "k8s.io/api/apps/v1" 11 batch_v1 "k8s.io/api/batch/v1" 12 core_v1 "k8s.io/api/core/v1" 13 "k8s.io/apimachinery/pkg/api/errors" 14 meta_v1 "k8s.io/apimachinery/pkg/apis/meta/v1" 15 "k8s.io/apimachinery/pkg/runtime/schema" 16 "k8s.io/apimachinery/pkg/version" 17 "k8s.io/client-go/tools/clientcmd/api" 18 gatewayapifake "sigs.k8s.io/gateway-api/pkg/client/clientset/versioned/fake" 19 20 "github.com/kiali/kiali/config" 21 "github.com/kiali/kiali/kubernetes" 22 ) 23 24 //// Mock for the K8SClientFactory 25 26 type K8SClientFactoryMock struct { 27 conf *config.Config 28 lock sync.RWMutex 29 Clients map[string]kubernetes.ClientInterface 30 } 31 32 // Interface guard to ensure K8SClientFactoryMock implements ClientFactory. 33 var _ kubernetes.ClientFactory = &K8SClientFactoryMock{} 34 35 // Constructor 36 // Deprecated: use NewFakeClientFactory instead since it doesn't rely on the global config.Get() 37 func NewK8SClientFactoryMock(k8s kubernetes.ClientInterface) *K8SClientFactoryMock { 38 conf := config.Get() 39 clients := map[string]kubernetes.ClientInterface{conf.KubernetesConfig.ClusterName: k8s} 40 return NewFakeClientFactory(conf, clients) 41 } 42 43 func NewFakeClientFactory(conf *config.Config, clients map[string]kubernetes.ClientInterface) *K8SClientFactoryMock { 44 return &K8SClientFactoryMock{conf: conf, Clients: clients} 45 } 46 47 // Testing specific methods 48 func (o *K8SClientFactoryMock) SetClients(clients map[string]kubernetes.ClientInterface) { 49 o.lock.Lock() 50 defer o.lock.Unlock() 51 o.Clients = clients 52 } 53 54 // Business Methods 55 func (o *K8SClientFactoryMock) GetClient(authInfo *api.AuthInfo, cluster string) (kubernetes.ClientInterface, error) { 56 o.lock.RLock() 57 defer o.lock.RUnlock() 58 return o.Clients[cluster], nil 59 } 60 61 // Business Methods 62 func (o *K8SClientFactoryMock) GetClients(authInfo *api.AuthInfo) (map[string]kubernetes.ClientInterface, error) { 63 o.lock.RLock() 64 defer o.lock.RUnlock() 65 return o.Clients, nil 66 } 67 68 func (o *K8SClientFactoryMock) GetSAClient(cluster string) kubernetes.ClientInterface { 69 o.lock.RLock() 70 defer o.lock.RUnlock() 71 return o.Clients[cluster] 72 } 73 74 func (o *K8SClientFactoryMock) GetSAClients() map[string]kubernetes.ClientInterface { 75 o.lock.RLock() 76 defer o.lock.RUnlock() 77 return o.Clients 78 } 79 80 func (o *K8SClientFactoryMock) GetSAHomeClusterClient() kubernetes.ClientInterface { 81 o.lock.RLock() 82 defer o.lock.RUnlock() 83 return o.Clients[o.conf.KubernetesConfig.ClusterName] 84 } 85 86 ///// 87 88 type K8SClientMock struct { 89 mock.Mock 90 istioClientset *istio_fake.Clientset 91 gatewayapiClientSet *gatewayapifake.Clientset 92 } 93 94 // Interface guard to ensure K8SClientMock implements ClientInterface. 95 var _ kubernetes.ClientInterface = &K8SClientMock{} 96 97 // Constructor 98 99 func NewK8SClientMock() *K8SClientMock { 100 k8s := new(K8SClientMock) 101 k8s.On("IsOpenShift").Return(true) 102 k8s.On("IsExpGatewayAPI").Return(false) 103 k8s.On("IsGatewayAPI").Return(false) 104 k8s.On("IsIstioAPI").Return(true) 105 k8s.On("GetKialiTokenForHomeCluster").Return("", "") 106 return k8s 107 } 108 109 // Business methods 110 111 // MockEmptyWorkloads setup the current mock to return empty workloads for every type of workloads (deployment, dc, rs, jobs, etc.) 112 func (o *K8SClientMock) MockEmptyWorkloads(namespace interface{}) { 113 o.On("GetDeployments", namespace).Return([]apps_v1.Deployment{}, nil) 114 o.On("GetReplicaSets", namespace).Return([]apps_v1.ReplicaSet{}, nil) 115 o.On("GetReplicationControllers", namespace).Return([]core_v1.ReplicationController{}, nil) 116 o.On("GetDeploymentConfigs", namespace).Return([]osapps_v1.DeploymentConfig{}, nil) 117 o.On("GetStatefulSets", namespace).Return([]apps_v1.StatefulSet{}, nil) 118 o.On("GetDaemonSets", namespace).Return([]apps_v1.DaemonSet{}, nil) 119 o.On("GetJobs", namespace).Return([]batch_v1.Job{}, nil) 120 o.On("GetCronJobs", namespace).Return([]batch_v1.CronJob{}, nil) 121 } 122 123 // MockEmptyWorkload setup the current mock to return an empty workload for every type of workloads (deployment, dc, rs, jobs, etc.) 124 func (o *K8SClientMock) MockEmptyWorkload(namespace interface{}, workload interface{}) { 125 gr := schema.GroupResource{ 126 Group: "test-group", 127 Resource: "test-resource", 128 } 129 notfound := errors.NewNotFound(gr, "not found") 130 o.On("GetDeployment", namespace, workload).Return(&apps_v1.Deployment{}, notfound) 131 o.On("GetStatefulSet", namespace, workload).Return(&apps_v1.StatefulSet{}, notfound) 132 o.On("GetDaemonSet", namespace, workload).Return(&apps_v1.DaemonSet{}, notfound) 133 o.On("GetDeploymentConfig", namespace, workload).Return(&osapps_v1.DeploymentConfig{}, notfound) 134 o.On("GetReplicaSets", namespace).Return([]apps_v1.ReplicaSet{}, nil) 135 o.On("GetReplicationControllers", namespace).Return([]core_v1.ReplicationController{}, nil) 136 o.On("GetJobs", namespace).Return([]batch_v1.Job{}, nil) 137 o.On("GetCronJobs", namespace).Return([]batch_v1.CronJob{}, nil) 138 } 139 140 func (o *K8SClientMock) IsOpenShift() bool { 141 args := o.Called() 142 return args.Get(0).(bool) 143 } 144 145 func (o *K8SClientMock) IsExpGatewayAPI() bool { 146 args := o.Called() 147 return args.Get(0).(bool) 148 } 149 150 func (o *K8SClientMock) IsGatewayAPI() bool { 151 args := o.Called() 152 return args.Get(0).(bool) 153 } 154 155 func (o *K8SClientMock) IsIstioAPI() bool { 156 args := o.Called() 157 return args.Get(0).(bool) 158 } 159 160 func (o *K8SClientMock) GetServerVersion() (*version.Info, error) { 161 args := o.Called() 162 return args.Get(0).(*version.Info), args.Error(1) 163 } 164 165 func (o *K8SClientMock) GetToken() string { 166 args := o.Called() 167 return args.Get(0).(string) 168 } 169 170 func (o *K8SClientMock) ClusterInfo() kubernetes.ClusterInfo { 171 args := o.Called() 172 return args.Get(0).(kubernetes.ClusterInfo) 173 } 174 175 // GetTokenSubject returns the subject of the authInfo using 176 // the TokenReview api 177 func (o *K8SClientMock) GetTokenSubject(authInfo *api.AuthInfo) (string, error) { 178 parsedToken, err := jwt.ParseSigned(authInfo.Token) 179 if err != nil { 180 return authInfo.Token, nil 181 } 182 183 var claims map[string]interface{} // generic map to store parsed token 184 err = parsedToken.UnsafeClaimsWithoutVerification(&claims) 185 if err != nil { 186 return authInfo.Token, nil 187 } 188 189 if sub, ok := claims["sub"]; ok { 190 return sub.(string), nil 191 } 192 193 return authInfo.Token, nil 194 } 195 196 func (o *K8SClientMock) ForwardGetRequest(namespace, podName string, destinationPort int, path string) ([]byte, error) { 197 args := o.Called(namespace, podName, destinationPort, path) 198 return args.Get(0).([]byte), args.Error(1) 199 } 200 201 func (o *K8SClientMock) MockService(namespace, name string) { 202 s := FakeService(namespace, name) 203 o.On("GetService", namespace, name).Return(&s, nil) 204 } 205 206 func (o *K8SClientMock) MockServices(namespace string, names []string) { 207 services := []core_v1.Service{} 208 for _, name := range names { 209 services = append(services, FakeService(namespace, name)) 210 } 211 o.On("GetServices", namespace, mock.AnythingOfType("map[string]string")).Return(services, nil) 212 o.On("GetDeployments", mock.AnythingOfType("string"), mock.AnythingOfType("string")).Return([]apps_v1.Deployment{}, nil) 213 } 214 215 func FakeService(namespace, name string) core_v1.Service { 216 return core_v1.Service{ 217 ObjectMeta: meta_v1.ObjectMeta{ 218 Name: name, 219 Namespace: namespace, 220 Labels: map[string]string{ 221 "app": name, 222 }, 223 }, 224 Spec: core_v1.ServiceSpec{ 225 ClusterIP: "fromservice", 226 Type: "ClusterIP", 227 Selector: map[string]string{"app": name}, 228 Ports: []core_v1.ServicePort{ 229 { 230 Name: "http", 231 Protocol: "TCP", 232 Port: 3001, 233 }, 234 { 235 Name: "http", 236 Protocol: "TCP", 237 Port: 3000, 238 }, 239 }, 240 }, 241 } 242 } 243 244 func FakePodList() []core_v1.Pod { 245 return []core_v1.Pod{ 246 { 247 ObjectMeta: meta_v1.ObjectMeta{ 248 Name: "reviews-v1", 249 Namespace: "ns", 250 Labels: map[string]string{"app": "reviews", "version": "v1"}, 251 Annotations: FakeIstioAnnotations(), 252 }, 253 }, 254 { 255 ObjectMeta: meta_v1.ObjectMeta{ 256 Name: "reviews-v2", 257 Namespace: "ns", 258 Labels: map[string]string{"app": "reviews", "version": "v2"}, 259 Annotations: FakeIstioAnnotations(), 260 }, 261 }, 262 { 263 ObjectMeta: meta_v1.ObjectMeta{ 264 Name: "httpbin-v1", 265 Namespace: "ns", 266 Labels: map[string]string{"app": "httpbin", "version": "v1"}, 267 Annotations: FakeIstioAnnotations(), 268 }, 269 }, 270 } 271 } 272 273 func FakeIstioAnnotations() map[string]string { 274 return map[string]string{"sidecar.istio.io/status": "{\"version\":\"\",\"initContainers\":[\"istio-init\",\"enable-core-dump\"],\"containers\":[\"istio-proxy\"],\"volumes\":[\"istio-envoy\",\"istio-certs\"]}"} 275 } 276 277 func FakeNamespace(name string) *core_v1.Namespace { 278 return &core_v1.Namespace{ 279 ObjectMeta: meta_v1.ObjectMeta{ 280 Name: name, 281 }, 282 } 283 }