github.com/kubewharf/katalyst-core@v0.5.3/pkg/controller/monitor/cnr_test.go (about)

     1  /*
     2  Copyright 2022 The Katalyst 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 monitor
    18  
    19  import (
    20  	"context"
    21  	"testing"
    22  	"time"
    23  
    24  	"github.com/stretchr/testify/assert"
    25  	"github.com/stretchr/testify/require"
    26  	corev1 "k8s.io/api/core/v1"
    27  	v1 "k8s.io/api/core/v1"
    28  	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
    29  	"k8s.io/apimachinery/pkg/runtime"
    30  	"k8s.io/client-go/tools/cache"
    31  
    32  	"github.com/kubewharf/katalyst-api/pkg/apis/node/v1alpha1"
    33  	katalyst_base "github.com/kubewharf/katalyst-core/cmd/base"
    34  	"github.com/kubewharf/katalyst-core/cmd/katalyst-agent/app/options"
    35  	metricspool "github.com/kubewharf/katalyst-core/pkg/metrics/metrics-pool"
    36  )
    37  
    38  func TestCNRMonitor_Run(t *testing.T) {
    39  	t.Parallel()
    40  
    41  	oldPod := &corev1.Pod{
    42  		ObjectMeta: metav1.ObjectMeta{
    43  			Name:      "pod1",
    44  			Namespace: "default",
    45  			UID:       "uid1",
    46  		},
    47  		Spec: corev1.PodSpec{
    48  			NodeName: "",
    49  		},
    50  	}
    51  
    52  	type fields struct {
    53  		pod *corev1.Pod
    54  		cnr *v1alpha1.CustomNodeResource
    55  	}
    56  	tests := []struct {
    57  		name   string
    58  		fields fields
    59  	}{
    60  		{
    61  			name: "test-pod-nodename-updated",
    62  			fields: fields{
    63  				pod: &corev1.Pod{
    64  					ObjectMeta: metav1.ObjectMeta{
    65  						Name:      "pod1",
    66  						Namespace: "default",
    67  						UID:       "uid1",
    68  					},
    69  					Spec: corev1.PodSpec{
    70  						NodeName: "node1",
    71  					},
    72  				},
    73  				cnr: &v1alpha1.CustomNodeResource{
    74  					ObjectMeta: metav1.ObjectMeta{
    75  						Name: "test",
    76  						Labels: map[string]string{
    77  							"test": "test",
    78  						},
    79  					},
    80  				},
    81  			},
    82  		},
    83  	}
    84  	for _, tt := range tests {
    85  		tt := tt
    86  		t.Run(tt.name, func(t *testing.T) {
    87  			t.Parallel()
    88  
    89  			genericCtx, err := katalyst_base.GenerateFakeGenericContext([]runtime.Object{oldPod}, []runtime.Object{tt.fields.cnr})
    90  			assert.NoError(t, err)
    91  
    92  			conf, err := options.NewOptions().Config()
    93  			require.NoError(t, err)
    94  			require.NotNil(t, conf)
    95  
    96  			ctrl, err := NewCNRMonitorController(
    97  				context.Background(),
    98  				conf.GenericConfiguration,
    99  				conf.GenericControllerConfiguration,
   100  				conf.CNRMonitorConfig,
   101  				genericCtx.Client,
   102  				genericCtx.KubeInformerFactory.Core().V1().Nodes(),
   103  				genericCtx.KubeInformerFactory.Core().V1().Pods(),
   104  				genericCtx.InternalInformerFactory.Node().V1alpha1().CustomNodeResources(),
   105  				metricspool.DummyMetricsEmitterPool.GetDefaultMetricsEmitter(metricspool.DummyMetricsEmitterPool{}),
   106  			)
   107  			assert.NoError(t, err)
   108  
   109  			// test cache synced
   110  			genericCtx.KubeInformerFactory.Start(ctrl.ctx.Done())
   111  			genericCtx.InternalInformerFactory.Start(ctrl.ctx.Done())
   112  			go ctrl.Run()
   113  
   114  			cache.WaitForCacheSync(ctrl.ctx.Done(), ctrl.cnrListerSynced, ctrl.podListerSynced)
   115  			time.Sleep(100 * time.Millisecond)
   116  
   117  			gotCNR, err := ctrl.cnrLister.Get(tt.fields.cnr.Name)
   118  			assert.NoError(t, err)
   119  			assert.Equal(t, tt.fields.cnr, gotCNR)
   120  
   121  			gotPod, err := ctrl.podLister.Pods(oldPod.Namespace).Get(oldPod.Name)
   122  			assert.NoError(t, err)
   123  			assert.Equal(t, oldPod, gotPod)
   124  
   125  			// test schedule pod to node
   126  			_, err = genericCtx.Client.KubeClient.CoreV1().Pods(tt.fields.pod.Namespace).Update(ctrl.ctx, tt.fields.pod, metav1.UpdateOptions{})
   127  			assert.NoError(t, err)
   128  			time.Sleep(100 * time.Millisecond)
   129  		})
   130  	}
   131  }
   132  
   133  func Test_gcPodTimeMap(t *testing.T) {
   134  	t.Parallel()
   135  
   136  	var (
   137  		time1 = time.Now().Add(-6 * time.Minute)
   138  		time2 = time.Now().Add(-time.Second)
   139  	)
   140  	type args struct {
   141  		pod        *corev1.Pod
   142  		podTimeMap map[string]time.Time
   143  	}
   144  	tests := []struct {
   145  		name string
   146  		args args
   147  		want map[string]time.Time
   148  	}{
   149  		{
   150  			name: "test-gc and emit timeout cnr report lantency metric",
   151  			args: args{
   152  				pod: &corev1.Pod{
   153  					ObjectMeta: metav1.ObjectMeta{
   154  						Name:      "pod1",
   155  						Namespace: "test",
   156  					},
   157  					Spec: corev1.PodSpec{
   158  						Containers: []corev1.Container{
   159  							{
   160  								Name:  "container-1",
   161  								Image: "nginx:latest",
   162  							},
   163  						},
   164  					},
   165  					Status: corev1.PodStatus{
   166  						Phase: v1.PodRunning,
   167  						ContainerStatuses: []corev1.ContainerStatus{
   168  							{
   169  								Name:         "container-1",
   170  								Ready:        true,
   171  								RestartCount: 0,
   172  							},
   173  						},
   174  					},
   175  				},
   176  				podTimeMap: map[string]time.Time{
   177  					"test/pod1/1": time1,
   178  					"test/pod2/2": time2,
   179  				},
   180  			},
   181  			want: map[string]time.Time{
   182  				"test/pod2/2": time2,
   183  			},
   184  		},
   185  		{
   186  			name: "test-no-gc",
   187  			args: args{
   188  				podTimeMap: map[string]time.Time{
   189  					"test/pod1/1": time2,
   190  				},
   191  			},
   192  			want: map[string]time.Time{
   193  				"test/pod1/1": time2,
   194  			},
   195  		},
   196  		{
   197  			name: "test-empty",
   198  			args: args{
   199  				podTimeMap: map[string]time.Time{},
   200  			},
   201  			want: map[string]time.Time{},
   202  		},
   203  	}
   204  	for _, tt := range tests {
   205  		tt := tt
   206  		t.Run(tt.name, func(t *testing.T) {
   207  			t.Parallel()
   208  
   209  			genericCtx, err := katalyst_base.GenerateFakeGenericContext([]runtime.Object{tt.args.pod}, []runtime.Object{})
   210  			assert.NoError(t, err)
   211  
   212  			conf, err := options.NewOptions().Config()
   213  			require.NoError(t, err)
   214  			require.NotNil(t, conf)
   215  
   216  			ctrl, err := NewCNRMonitorController(
   217  				context.Background(),
   218  				conf.GenericConfiguration,
   219  				conf.GenericControllerConfiguration,
   220  				conf.CNRMonitorConfig,
   221  				genericCtx.Client,
   222  				genericCtx.KubeInformerFactory.Core().V1().Nodes(),
   223  				genericCtx.KubeInformerFactory.Core().V1().Pods(),
   224  				genericCtx.InternalInformerFactory.Node().V1alpha1().CustomNodeResources(),
   225  				metricspool.DummyMetricsEmitterPool.GetDefaultMetricsEmitter(metricspool.DummyMetricsEmitterPool{}),
   226  			)
   227  			assert.NoError(t, err)
   228  
   229  			// test cache synced
   230  			genericCtx.KubeInformerFactory.Start(ctrl.ctx.Done())
   231  			genericCtx.InternalInformerFactory.Start(ctrl.ctx.Done())
   232  
   233  			cache.WaitForCacheSync(ctrl.ctx.Done(), ctrl.cnrListerSynced, ctrl.podListerSynced)
   234  			time.Sleep(100 * time.Millisecond)
   235  
   236  			for k, v := range tt.args.podTimeMap {
   237  				ctrl.podTimeMap.Store(k, v)
   238  			}
   239  
   240  			ctrl.gcPodTimeMap()
   241  
   242  			podTimeMap := map[string]time.Time{}
   243  			ctrl.podTimeMap.Range(func(k, v interface{}) bool {
   244  				podTimeMap[k.(string)] = v.(time.Time)
   245  				return true
   246  			})
   247  
   248  			assert.Equal(t, tt.want, podTimeMap)
   249  		})
   250  	}
   251  }