github.com/alibaba/ilogtail/pkg@v0.0.0-20250526110833-c53b480d046c/helper/k8smeta/k8s_meta_deferred_deletion_meta_store_test.go (about)

     1  package k8smeta
     2  
     3  import (
     4  	"testing"
     5  	"time"
     6  
     7  	"github.com/stretchr/testify/assert"
     8  	corev1 "k8s.io/api/core/v1"
     9  	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
    10  	"k8s.io/client-go/tools/cache"
    11  )
    12  
    13  func TestDeferredDeletion(t *testing.T) {
    14  	eventCh := make(chan *K8sMetaEvent)
    15  	stopCh := make(chan struct{})
    16  	gracePeriod := 1
    17  	cache := NewDeferredDeletionMetaStore(eventCh, stopCh, int64(gracePeriod), cache.MetaNamespaceKeyFunc, generatePodIPKey)
    18  	cache.Start()
    19  	pod := &corev1.Pod{
    20  		ObjectMeta: metav1.ObjectMeta{
    21  			Name:      "test",
    22  			Namespace: "default",
    23  		},
    24  		Status: corev1.PodStatus{
    25  			PodIP: "127.0.0.1",
    26  		},
    27  	}
    28  	eventCh <- &K8sMetaEvent{
    29  		EventType: EventTypeAdd,
    30  		Object: &ObjectWrapper{
    31  			Raw: pod,
    32  		},
    33  	}
    34  	cache.lock.RLock()
    35  	if _, ok := cache.Items["default/test"]; !ok {
    36  		t.Errorf("failed to add object to cache")
    37  	}
    38  	cache.lock.RUnlock()
    39  	assert.Equal(t, 1, len(cache.Get([]string{"127.0.0.1"})))
    40  	eventCh <- &K8sMetaEvent{
    41  		EventType: EventTypeDelete,
    42  		Object: &ObjectWrapper{
    43  			Raw: pod,
    44  		},
    45  	}
    46  	eventCh <- &K8sMetaEvent{
    47  		EventType: EventTypeDelete,
    48  		Object: &ObjectWrapper{
    49  			Raw: pod,
    50  		},
    51  	}
    52  	time.Sleep(10 * time.Millisecond)
    53  	cache.lock.RLock()
    54  	if item, ok := cache.Items["default/test"]; !ok {
    55  		t.Error("failed to deferred delete object from cache")
    56  	} else {
    57  		assert.Equal(t, true, item.Deleted)
    58  	}
    59  	cache.lock.RUnlock()
    60  	assert.Equal(t, 1, len(cache.Get([]string{"127.0.0.1"})))
    61  	time.Sleep(time.Duration(gracePeriod+1) * time.Second)
    62  	cache.lock.RLock()
    63  	if _, ok := cache.Items["default/test"]; ok {
    64  		t.Error("failed to delete object from cache")
    65  	}
    66  	cache.lock.RUnlock()
    67  	assert.Equal(t, 0, len(cache.Get([]string{"127.0.0.1"})))
    68  }
    69  
    70  func TestDeferredDeletionWithAddEvent(t *testing.T) {
    71  	eventCh := make(chan *K8sMetaEvent)
    72  	stopCh := make(chan struct{})
    73  	gracePeriod := 1
    74  	cache := NewDeferredDeletionMetaStore(eventCh, stopCh, int64(gracePeriod), cache.MetaNamespaceKeyFunc, generatePodIPKey)
    75  	cache.Start()
    76  	pod := &corev1.Pod{
    77  		ObjectMeta: metav1.ObjectMeta{
    78  			Name:      "test",
    79  			Namespace: "default",
    80  		},
    81  		Status: corev1.PodStatus{
    82  			PodIP: "127.0.0.1",
    83  		},
    84  	}
    85  	eventCh <- &K8sMetaEvent{
    86  		EventType: EventTypeAdd,
    87  		Object: &ObjectWrapper{
    88  			Raw: pod,
    89  		},
    90  	}
    91  	cache.lock.RLock()
    92  	if _, ok := cache.Items["default/test"]; !ok {
    93  		t.Errorf("failed to add object to cache")
    94  	}
    95  	cache.lock.RUnlock()
    96  	eventCh <- &K8sMetaEvent{
    97  		EventType: EventTypeDelete,
    98  		Object: &ObjectWrapper{
    99  			Raw: pod,
   100  		},
   101  	}
   102  	// add again
   103  	pod2 := &corev1.Pod{
   104  		ObjectMeta: metav1.ObjectMeta{
   105  			Name:      "test",
   106  			Namespace: "default",
   107  		},
   108  		Status: corev1.PodStatus{
   109  			PodIP: "127.0.0.2",
   110  		},
   111  	}
   112  	eventCh <- &K8sMetaEvent{
   113  		EventType: EventTypeAdd,
   114  		Object: &ObjectWrapper{
   115  			Raw: pod2,
   116  		},
   117  	}
   118  	time.Sleep(10 * time.Millisecond)
   119  	cache.lock.RLock()
   120  	if item, ok := cache.Items["default/test"]; !ok {
   121  		t.Error("failed to deferred delete object from cache")
   122  	} else {
   123  		assert.Equal(t, false, item.Deleted)
   124  	}
   125  	cache.lock.RUnlock()
   126  	assert.Equal(t, 0, len(cache.Get([]string{"127.0.0.1"})))
   127  	assert.Equal(t, 1, len(cache.Get([]string{"127.0.0.2"})))
   128  	time.Sleep(time.Duration(gracePeriod+1) * time.Second)
   129  	cache.lock.RLock()
   130  	if _, ok := cache.Items["default/test"]; !ok {
   131  		t.Error("should not delete object from cache")
   132  	}
   133  	cache.lock.RUnlock()
   134  	assert.Equal(t, 1, len(cache.Get([]string{"127.0.0.2"})))
   135  }
   136  
   137  func TestRegisterWaitManagerReady(t *testing.T) {
   138  	eventCh := make(chan *K8sMetaEvent)
   139  	stopCh := make(chan struct{})
   140  	gracePeriod := 1
   141  	cache := NewDeferredDeletionMetaStore(eventCh, stopCh, int64(gracePeriod), cache.MetaNamespaceKeyFunc)
   142  	manager := GetMetaManagerInstance()
   143  	cache.RegisterSendFunc("test", func(kme []*K8sMetaEvent) {}, 100)
   144  	select {
   145  	case <-cache.eventCh:
   146  		t.Error("should not receive event before manager is ready")
   147  	case <-time.After(2 * time.Second):
   148  	}
   149  	manager.ready.Store(true)
   150  	select {
   151  	case <-cache.eventCh:
   152  	case <-time.After(2 * time.Second):
   153  		t.Error("should receive timer event immediately after manager is ready")
   154  	}
   155  }
   156  
   157  func TestTimerSend(t *testing.T) {
   158  	eventCh := make(chan *K8sMetaEvent)
   159  	stopCh := make(chan struct{})
   160  	manager := GetMetaManagerInstance()
   161  	manager.ready.Store(true)
   162  	gracePeriod := 1
   163  	cache := NewDeferredDeletionMetaStore(eventCh, stopCh, int64(gracePeriod), cache.MetaNamespaceKeyFunc)
   164  	cache.Items["default/test"] = &ObjectWrapper{
   165  		Raw: &corev1.Pod{
   166  			ObjectMeta: metav1.ObjectMeta{
   167  				Name:      "test",
   168  				Namespace: "default",
   169  			},
   170  		},
   171  	}
   172  	cache.Start()
   173  	resultCh := make(chan struct{})
   174  	cache.RegisterSendFunc("test", func(kmes []*K8sMetaEvent) {
   175  		resultCh <- struct{}{}
   176  	}, 1)
   177  	go func() {
   178  		time.Sleep(3 * time.Second)
   179  		close(stopCh)
   180  	}()
   181  	count := 0
   182  	for {
   183  		select {
   184  		case <-resultCh:
   185  			count++
   186  		case <-stopCh:
   187  			if count < 3 {
   188  				t.Errorf("should receive 3 timer events, but got %d", count)
   189  			}
   190  			return
   191  		}
   192  	}
   193  }
   194  
   195  func TestFilter(t *testing.T) {
   196  	eventCh := make(chan *K8sMetaEvent)
   197  	stopCh := make(chan struct{})
   198  	gracePeriod := 1
   199  	cache := NewDeferredDeletionMetaStore(eventCh, stopCh, int64(gracePeriod), cache.MetaNamespaceKeyFunc)
   200  	cache.Items["default/test"] = &ObjectWrapper{
   201  		Raw: &corev1.Pod{
   202  			ObjectMeta: metav1.ObjectMeta{
   203  				Name:      "test",
   204  				Namespace: "default",
   205  				Labels: map[string]string{
   206  					"app": "test",
   207  				},
   208  			},
   209  		},
   210  	}
   211  	cache.Items["default/test2"] = &ObjectWrapper{
   212  		Raw: &corev1.Pod{
   213  			ObjectMeta: metav1.ObjectMeta{
   214  				Name:      "test2",
   215  				Namespace: "default",
   216  				Labels: map[string]string{
   217  					"app": "test2",
   218  				},
   219  			},
   220  		},
   221  	}
   222  	cache.Items["default/test3"] = &ObjectWrapper{
   223  		Raw: &corev1.Pod{
   224  			ObjectMeta: metav1.ObjectMeta{
   225  				Name:      "test3",
   226  				Namespace: "default",
   227  				Labels: map[string]string{
   228  					"app": "test2",
   229  				},
   230  			},
   231  		},
   232  	}
   233  	objs := cache.Filter(func(obj *ObjectWrapper) bool {
   234  		return obj.Raw.(*corev1.Pod).Labels["app"] == "test2"
   235  	}, 1)
   236  	assert.Len(t, objs, 1)
   237  	assert.Equal(t, "test2", objs[0].Raw.(*corev1.Pod).Labels["app"])
   238  
   239  	objs = cache.Filter(nil, 10)
   240  	assert.Len(t, objs, 3)
   241  }
   242  
   243  func TestGet(t *testing.T) {
   244  	eventCh := make(chan *K8sMetaEvent)
   245  	stopCh := make(chan struct{})
   246  	gracePeriod := 1
   247  	cache := NewDeferredDeletionMetaStore(eventCh, stopCh, int64(gracePeriod), cache.MetaNamespaceKeyFunc, generateCommonKey)
   248  	cache.Start()
   249  	eventCh <- &K8sMetaEvent{
   250  		EventType: EventTypeAdd,
   251  		Object: &ObjectWrapper{
   252  			Raw: &corev1.Pod{
   253  				ObjectMeta: metav1.ObjectMeta{
   254  					Name:      "test",
   255  					Namespace: "default",
   256  				},
   257  			},
   258  		},
   259  	}
   260  	eventCh <- &K8sMetaEvent{
   261  		EventType: EventTypeAdd,
   262  		Object: &ObjectWrapper{
   263  			Raw: &corev1.Pod{
   264  				ObjectMeta: metav1.ObjectMeta{
   265  					Name:      "test2",
   266  					Namespace: "default",
   267  				},
   268  			},
   269  		},
   270  	}
   271  	eventCh <- &K8sMetaEvent{
   272  		EventType: EventTypeAdd,
   273  		Object: &ObjectWrapper{
   274  			Raw: nil,
   275  		},
   276  	}
   277  	// nil object in cache
   278  	cache.Items["default/test3"] = &ObjectWrapper{
   279  		Raw: nil,
   280  	}
   281  	cache.Index["default/test3"] = IndexItem{
   282  		Keys: map[string]struct{}{
   283  			"default/test3": {},
   284  		},
   285  	}
   286  	// in index but not in cache
   287  	cache.Index["default/test4"] = IndexItem{
   288  		Keys: map[string]struct{}{
   289  			"default/test4": {},
   290  		},
   291  	}
   292  
   293  	time.Sleep(10 * time.Millisecond)
   294  	objs := cache.Get([]string{"default/test", "default/test2", "default/test3", "default/test4", "default/test5"})
   295  	assert.Len(t, objs, 2)
   296  	assert.Equal(t, "test", objs["default/test"][0].Raw.(*corev1.Pod).Name)
   297  	assert.Equal(t, "test2", objs["default/test2"][0].Raw.(*corev1.Pod).Name)
   298  }
   299  
   300  func TestIndex(t *testing.T) {
   301  	eventCh := make(chan *K8sMetaEvent)
   302  	stopCh := make(chan struct{})
   303  	gracePeriod := 1
   304  	cache := NewDeferredDeletionMetaStore(eventCh, stopCh, int64(gracePeriod), cache.MetaNamespaceKeyFunc, generateCommonKey)
   305  	cache.Start()
   306  	// add
   307  	pod := &corev1.Pod{
   308  		ObjectMeta: metav1.ObjectMeta{
   309  			Name:      "test",
   310  			Namespace: "default",
   311  		},
   312  	}
   313  	eventCh <- &K8sMetaEvent{
   314  		EventType: EventTypeAdd,
   315  		Object: &ObjectWrapper{
   316  			Raw: pod,
   317  		},
   318  	}
   319  	pod2 := &corev1.Pod{
   320  		ObjectMeta: metav1.ObjectMeta{
   321  			Name:      "test2",
   322  			Namespace: "default",
   323  		},
   324  	}
   325  	eventCh <- &K8sMetaEvent{
   326  		EventType: EventTypeAdd,
   327  		Object: &ObjectWrapper{
   328  			Raw: pod2,
   329  		},
   330  	}
   331  	time.Sleep(time.Millisecond * 10)
   332  	cache.lock.RLock()
   333  	assert.Equal(t, 2, len(cache.Items))
   334  	assert.Equal(t, 2, len(cache.Index))
   335  	for _, idx := range cache.Index {
   336  		assert.Equal(t, 1, len(idx.Keys))
   337  	}
   338  	cache.lock.RUnlock()
   339  
   340  	// update
   341  	eventCh <- &K8sMetaEvent{
   342  		EventType: EventTypeUpdate,
   343  		Object: &ObjectWrapper{
   344  			Raw: pod,
   345  		},
   346  	}
   347  	eventCh <- &K8sMetaEvent{
   348  		EventType: EventTypeUpdate,
   349  		Object: &ObjectWrapper{
   350  			Raw: pod2,
   351  		},
   352  	}
   353  	time.Sleep(time.Millisecond * 10)
   354  	cache.lock.RLock()
   355  	assert.Equal(t, 2, len(cache.Items))
   356  	assert.Equal(t, 2, len(cache.Index))
   357  	for _, idx := range cache.Index {
   358  		assert.Equal(t, 1, len(idx.Keys))
   359  	}
   360  	cache.lock.RUnlock()
   361  
   362  	// delete
   363  	eventCh <- &K8sMetaEvent{
   364  		EventType: EventTypeDelete,
   365  		Object: &ObjectWrapper{
   366  			Raw: pod,
   367  		},
   368  	}
   369  	eventCh <- &K8sMetaEvent{
   370  		EventType: EventTypeDelete,
   371  		Object: &ObjectWrapper{
   372  			Raw: pod2,
   373  		},
   374  	}
   375  	time.Sleep(time.Duration(gracePeriod) * time.Second)
   376  	time.Sleep(time.Millisecond * 10)
   377  	cache.lock.RLock()
   378  	assert.Equal(t, 0, len(cache.Items))
   379  	assert.Equal(t, 0, len(cache.Index))
   380  	cache.lock.RUnlock()
   381  }
   382  
   383  func TestRegisterAndUnRegisterSendFunc(t *testing.T) {
   384  	eventCh := make(chan *K8sMetaEvent)
   385  	stopCh := make(chan struct{})
   386  	gracePeriod := 1
   387  	cache := NewDeferredDeletionMetaStore(eventCh, stopCh, int64(gracePeriod), cache.MetaNamespaceKeyFunc)
   388  	cache.Start()
   389  	counter := 0
   390  	interval := 1
   391  	cache.RegisterSendFunc("test", func(kme []*K8sMetaEvent) {
   392  		counter++
   393  	}, interval)
   394  	pod := &corev1.Pod{
   395  		ObjectMeta: metav1.ObjectMeta{
   396  			Name:      "test",
   397  			Namespace: "default",
   398  		},
   399  	}
   400  	eventCh <- &K8sMetaEvent{
   401  		EventType: EventTypeAdd,
   402  		Object: &ObjectWrapper{
   403  			Raw: pod,
   404  		},
   405  	}
   406  	eventCh <- &K8sMetaEvent{
   407  		EventType: EventTypeDelete,
   408  		Object: &ObjectWrapper{
   409  			Raw: pod,
   410  		},
   411  	}
   412  	eventCh <- &K8sMetaEvent{
   413  		EventType: "not exist",
   414  		Object: &ObjectWrapper{
   415  			Raw: pod,
   416  		},
   417  	}
   418  	time.Sleep(10 * time.Millisecond)
   419  	assert.Equal(t, 3, counter) // 1 for add event, 1 for timer event, 1 for delete event
   420  	cache.UnRegisterSendFunc("test")
   421  	time.Sleep(10 * time.Millisecond)
   422  	pod2 := &corev1.Pod{
   423  		ObjectMeta: metav1.ObjectMeta{
   424  			Name:      "test2",
   425  			Namespace: "default",
   426  		},
   427  	}
   428  	eventCh <- &K8sMetaEvent{
   429  		EventType: EventTypeAdd,
   430  		Object: &ObjectWrapper{
   431  			Raw: pod2,
   432  		},
   433  	}
   434  	time.Sleep(time.Duration(interval) * time.Second)
   435  	assert.Equal(t, 3, counter)
   436  }