github.com/castai/kvisor@v1.7.1-0.20240516114728-b3572a2607b5/cmd/controller/kube/client_test.go (about)

     1  package kube
     2  
     3  import (
     4  	"context"
     5  	"fmt"
     6  	"reflect"
     7  	"sync"
     8  	"testing"
     9  	"time"
    10  
    11  	"github.com/castai/kvisor/pkg/logging"
    12  	"github.com/samber/lo"
    13  	"github.com/stretchr/testify/require"
    14  	appsv1 "k8s.io/api/apps/v1"
    15  	corev1 "k8s.io/api/core/v1"
    16  	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
    17  	"k8s.io/apimachinery/pkg/types"
    18  	"k8s.io/client-go/informers"
    19  	"k8s.io/client-go/kubernetes/fake"
    20  )
    21  
    22  func TestClient(t *testing.T) {
    23  	ctx := context.Background()
    24  	log := logging.NewTestLog()
    25  
    26  	t.Run("call event handlers and listeners", func(t *testing.T) {
    27  		r := require.New(t)
    28  		dep1 := newTestDeployment()
    29  		pod1 := newTestPod()
    30  		clientset := fake.NewSimpleClientset(dep1, pod1)
    31  		lis := &mockListener{items: map[types.UID]Object{}}
    32  		informersFactory := informers.NewSharedInformerFactory(clientset, 0)
    33  		client := NewClient(log, "castai-kvisor", "kvisor", Version{}, clientset)
    34  		client.RegisterHandlers(informersFactory)
    35  		client.RegisterPodsHandlers(informersFactory)
    36  		client.RegisterKubernetesChangeListener(lis)
    37  		informersFactory.Start(ctx.Done())
    38  		informersFactory.WaitForCacheSync(ctx.Done())
    39  
    40  		// Assert added deployment.
    41  		r.Eventually(func() bool {
    42  			items := lis.getItems()
    43  			if len(items) == 2 {
    44  				return true
    45  			}
    46  			return false
    47  		}, 2*time.Second, 10*time.Millisecond)
    48  
    49  		r.NoError(clientset.AppsV1().Deployments(dep1.Namespace).Delete(ctx, dep1.Name, metav1.DeleteOptions{}))
    50  
    51  		// Assert deployment is deleted.
    52  		r.Eventually(func() bool {
    53  			items := lis.getItems()
    54  			if len(items) == 1 {
    55  				item := items[0]
    56  				if reflect.TypeOf(item) != reflect.TypeOf(&corev1.Pod{}) {
    57  					t.Fatal("expected to keep pod after deployment delete")
    58  				}
    59  				return true
    60  			}
    61  			return false
    62  		}, 2*time.Second, 10*time.Millisecond)
    63  	})
    64  }
    65  
    66  func aa(ob Object) {
    67  	fmt.Println(reflect.TypeOf(ob))
    68  }
    69  
    70  type mockListener struct {
    71  	items map[types.UID]Object
    72  	mu    sync.Mutex
    73  }
    74  
    75  func (m *mockListener) RequiredTypes() []reflect.Type {
    76  	return []reflect.Type{
    77  		reflect.TypeOf(&corev1.Pod{}),
    78  		reflect.TypeOf(&appsv1.Deployment{}),
    79  	}
    80  }
    81  
    82  func (m *mockListener) getItems() []Object {
    83  	m.mu.Lock()
    84  	defer m.mu.Unlock()
    85  	return lo.Values(m.items)
    86  }
    87  
    88  func (m *mockListener) OnAdd(obj Object) {
    89  	m.mu.Lock()
    90  	defer m.mu.Unlock()
    91  	m.items[obj.GetUID()] = obj
    92  }
    93  
    94  func (m *mockListener) OnDelete(obj Object) {
    95  	m.mu.Lock()
    96  	defer m.mu.Unlock()
    97  	delete(m.items, obj.GetUID())
    98  }
    99  
   100  func (m *mockListener) OnUpdate(obj Object) {
   101  	m.mu.Lock()
   102  	defer m.mu.Unlock()
   103  	m.items[obj.GetUID()] = obj
   104  }
   105  
   106  func newTestDeployment() *appsv1.Deployment {
   107  	return &appsv1.Deployment{
   108  		TypeMeta: metav1.TypeMeta{Kind: "Deployment", APIVersion: "v1"},
   109  		ObjectMeta: metav1.ObjectMeta{
   110  			Name:      "nginx-1",
   111  			Namespace: "default",
   112  			UID:       types.UID("111b56a9-ab5e-4a35-93af-f092e2f63011"),
   113  			OwnerReferences: []metav1.OwnerReference{
   114  				{
   115  					UID:        types.UID("owner"),
   116  					APIVersion: "v1",
   117  					Kind:       "Node",
   118  					Controller: lo.ToPtr(true),
   119  					Name:       "node1",
   120  				},
   121  			},
   122  			Labels: map[string]string{"subscriber": "test"},
   123  		},
   124  		Spec: appsv1.DeploymentSpec{
   125  			Template: corev1.PodTemplateSpec{
   126  				Spec: corev1.PodSpec{
   127  					NodeName: "n1",
   128  					Containers: []corev1.Container{
   129  						{
   130  							Name:  "nginx",
   131  							Image: "nginx:1.23",
   132  						},
   133  					},
   134  				},
   135  			},
   136  		},
   137  		Status: appsv1.DeploymentStatus{
   138  			Replicas: 1,
   139  		},
   140  	}
   141  }
   142  
   143  func newTestPod() *corev1.Pod {
   144  	return &corev1.Pod{
   145  		ObjectMeta: metav1.ObjectMeta{
   146  			Name:      "p1",
   147  			Namespace: "default",
   148  			UID:       types.UID("111b56a9-ab5e-4a35-93af-f092e2f63022"),
   149  		},
   150  	}
   151  }