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  }