github.com/kubewharf/katalyst-core@v0.5.3/pkg/controller/monitor/cnr_indicator_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  	v1 "k8s.io/api/core/v1"
    27  	"k8s.io/apimachinery/pkg/api/resource"
    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  	"github.com/kubewharf/katalyst-api/pkg/consts"
    34  	katalyst_base "github.com/kubewharf/katalyst-core/cmd/base"
    35  	"github.com/kubewharf/katalyst-core/cmd/katalyst-agent/app/options"
    36  	metricspool "github.com/kubewharf/katalyst-core/pkg/metrics/metrics-pool"
    37  )
    38  
    39  func Test_checkNumaExclusiveAnomaly(t *testing.T) {
    40  	t.Parallel()
    41  
    42  	type fields struct {
    43  		pods []*v1.Pod
    44  		cnr  *v1alpha1.CustomNodeResource
    45  	}
    46  
    47  	tests := []struct {
    48  		name       string
    49  		fields     fields
    50  		wantResult bool
    51  	}{
    52  		{
    53  			name: "numa exclusive anomaly with numa binding and numa exclusive pod",
    54  			fields: fields{
    55  				pods: []*v1.Pod{
    56  					{
    57  						ObjectMeta: metav1.ObjectMeta{
    58  							Name:      "test-pod1",
    59  							Namespace: "test-namespace",
    60  							Annotations: map[string]string{
    61  								consts.PodAnnotationQoSLevelKey: consts.PodAnnotationQoSLevelDedicatedCores,
    62  								consts.PodAnnotationMemoryEnhancementKey: `{
    63  									"numa_binding": "true", 
    64  									"numa_exclusive": "true"
    65  								  }`,
    66  							},
    67  						},
    68  					},
    69  					{
    70  						ObjectMeta: metav1.ObjectMeta{
    71  							Name:      "test-pod2",
    72  							Namespace: "test-namespace",
    73  							Annotations: map[string]string{
    74  								consts.PodAnnotationQoSLevelKey: consts.PodAnnotationQoSLevelDedicatedCores,
    75  								consts.PodAnnotationMemoryEnhancementKey: `{
    76  									"numa_binding": "true", 
    77  									"numa_exclusive": "true"
    78  								  }`,
    79  							},
    80  						},
    81  					},
    82  				},
    83  				cnr: &v1alpha1.CustomNodeResource{
    84  					ObjectMeta: metav1.ObjectMeta{
    85  						Name: "test",
    86  					},
    87  					Status: v1alpha1.CustomNodeResourceStatus{
    88  						TopologyZone: []*v1alpha1.TopologyZone{
    89  							{
    90  								Type: v1alpha1.TopologyTypeSocket,
    91  								Children: []*v1alpha1.TopologyZone{
    92  									{
    93  										Type: v1alpha1.TopologyTypeNIC,
    94  										Attributes: []v1alpha1.Attribute{
    95  											{
    96  												Name:  "katalyst.kubewharf.io/resource_identifier",
    97  												Value: "enp0s3",
    98  											},
    99  										},
   100  										Name: "eth0",
   101  									},
   102  									{
   103  										Type: v1alpha1.TopologyTypeNuma,
   104  										Allocations: []*v1alpha1.Allocation{
   105  											{
   106  												Consumer: "test-namespace/test-pod1/13414141",
   107  											},
   108  											{
   109  												Consumer: "test-namespace/test-pod2/31413414",
   110  											},
   111  										},
   112  										Name: "0",
   113  									},
   114  								},
   115  							},
   116  						},
   117  					},
   118  				},
   119  			},
   120  			wantResult: true,
   121  		},
   122  		{
   123  			name: "numa exclusive anomaly test with non numa binding and non numa exclusive pod",
   124  			fields: fields{
   125  				pods: []*v1.Pod{
   126  					{
   127  						ObjectMeta: metav1.ObjectMeta{
   128  							Name:      "test-pod1",
   129  							Namespace: "test-namespace",
   130  						},
   131  					},
   132  					{
   133  						ObjectMeta: metav1.ObjectMeta{
   134  							Name:      "test-pod2",
   135  							Namespace: "test-namespace",
   136  						},
   137  					},
   138  				},
   139  				cnr: &v1alpha1.CustomNodeResource{
   140  					ObjectMeta: metav1.ObjectMeta{
   141  						Name: "test",
   142  					},
   143  					Status: v1alpha1.CustomNodeResourceStatus{
   144  						TopologyZone: []*v1alpha1.TopologyZone{
   145  							{
   146  								Type: v1alpha1.TopologyTypeSocket,
   147  								Children: []*v1alpha1.TopologyZone{
   148  									{
   149  										Type: v1alpha1.TopologyTypeNIC,
   150  										Attributes: []v1alpha1.Attribute{
   151  											{
   152  												Name:  "katalyst.kubewharf.io/resource_identifier",
   153  												Value: "enp0s3",
   154  											},
   155  										},
   156  										Name: "eth0",
   157  									},
   158  									{
   159  										Type: v1alpha1.TopologyTypeNuma,
   160  										Allocations: []*v1alpha1.Allocation{
   161  											{
   162  												Consumer: "test-namespace/test-pod1/13414141",
   163  											},
   164  											{
   165  												Consumer: "test-namespace/test-pod2/31413414",
   166  											},
   167  										},
   168  										Name: "0",
   169  									},
   170  								},
   171  							},
   172  						},
   173  					},
   174  				},
   175  			},
   176  			wantResult: false,
   177  		},
   178  		{
   179  			name: "numa exclusive anomaly with non numa binding and numa exclusive pod",
   180  			fields: fields{
   181  				pods: []*v1.Pod{
   182  					{
   183  						ObjectMeta: metav1.ObjectMeta{
   184  							Name:      "test-pod1",
   185  							Namespace: "test-namespace",
   186  							Annotations: map[string]string{
   187  								consts.PodAnnotationQoSLevelKey: consts.PodAnnotationQoSLevelDedicatedCores,
   188  								consts.PodAnnotationMemoryEnhancementKey: `{
   189  									"numa_binding": "false", 
   190  									"numa_exclusive": "true"
   191  								  }`,
   192  							},
   193  						},
   194  					},
   195  					{
   196  						ObjectMeta: metav1.ObjectMeta{
   197  							Name:      "test-pod2",
   198  							Namespace: "test-namespace",
   199  							Annotations: map[string]string{
   200  								consts.PodAnnotationQoSLevelKey: consts.PodAnnotationQoSLevelDedicatedCores,
   201  								consts.PodAnnotationMemoryEnhancementKey: `{
   202  									"numa_binding": "true", 
   203  									"numa_exclusive": "false"
   204  								  }`,
   205  							},
   206  						},
   207  					},
   208  				},
   209  				cnr: &v1alpha1.CustomNodeResource{
   210  					ObjectMeta: metav1.ObjectMeta{
   211  						Name: "test",
   212  					},
   213  					Status: v1alpha1.CustomNodeResourceStatus{
   214  						TopologyZone: []*v1alpha1.TopologyZone{
   215  							{
   216  								Type: v1alpha1.TopologyTypeSocket,
   217  								Children: []*v1alpha1.TopologyZone{
   218  									{
   219  										Type: v1alpha1.TopologyTypeNIC,
   220  										Attributes: []v1alpha1.Attribute{
   221  											{
   222  												Name:  "katalyst.kubewharf.io/resource_identifier",
   223  												Value: "enp0s3",
   224  											},
   225  										},
   226  										Name: "eth0",
   227  									},
   228  									{
   229  										Type: v1alpha1.TopologyTypeNuma,
   230  										Allocations: []*v1alpha1.Allocation{
   231  											{
   232  												Consumer: "test-namespace/test-pod1/13414141",
   233  											},
   234  											{
   235  												Consumer: "test-namespace/test-pod2/31413414",
   236  											},
   237  										},
   238  										Name: "0",
   239  									},
   240  								},
   241  							},
   242  						},
   243  					},
   244  				},
   245  			},
   246  			wantResult: false,
   247  		},
   248  		{
   249  			name: "numa exclusive anomaly with numa binding and non numa exclusive pod",
   250  			fields: fields{
   251  				pods: []*v1.Pod{
   252  					{
   253  						ObjectMeta: metav1.ObjectMeta{
   254  							Name:      "test-pod1",
   255  							Namespace: "test-namespace",
   256  							Annotations: map[string]string{
   257  								consts.PodAnnotationQoSLevelKey: consts.PodAnnotationQoSLevelDedicatedCores,
   258  								consts.PodAnnotationMemoryEnhancementKey: `{
   259  									"numa_binding": "true", 
   260  									"numa_exclusive": "false"
   261  								  }`,
   262  							},
   263  						},
   264  					},
   265  					{
   266  						ObjectMeta: metav1.ObjectMeta{
   267  							Name:      "test-pod2",
   268  							Namespace: "test-namespace",
   269  						},
   270  					},
   271  				},
   272  				cnr: &v1alpha1.CustomNodeResource{
   273  					ObjectMeta: metav1.ObjectMeta{
   274  						Name: "test",
   275  					},
   276  					Status: v1alpha1.CustomNodeResourceStatus{
   277  						TopologyZone: []*v1alpha1.TopologyZone{
   278  							{
   279  								Type: v1alpha1.TopologyTypeSocket,
   280  								Children: []*v1alpha1.TopologyZone{
   281  									{
   282  										Type: v1alpha1.TopologyTypeNIC,
   283  										Attributes: []v1alpha1.Attribute{
   284  											{
   285  												Name:  "katalyst.kubewharf.io/resource_identifier",
   286  												Value: "enp0s3",
   287  											},
   288  										},
   289  										Name: "eth0",
   290  									},
   291  									{
   292  										Type: v1alpha1.TopologyTypeNuma,
   293  										Allocations: []*v1alpha1.Allocation{
   294  											{
   295  												Consumer: "test-namespace/test-pod1/13414141",
   296  											},
   297  											{
   298  												Consumer: "test-namespace/test-pod2/31413414",
   299  											},
   300  										},
   301  										Name: "0",
   302  									},
   303  								},
   304  							},
   305  						},
   306  					},
   307  				},
   308  			},
   309  			wantResult: false,
   310  		},
   311  	}
   312  	for _, tt := range tests {
   313  		tt := tt
   314  
   315  		t.Run(tt.name, func(t *testing.T) {
   316  			t.Parallel()
   317  
   318  			genericCtx, err := katalyst_base.GenerateFakeGenericContext([]runtime.Object{tt.fields.pods[0], tt.fields.pods[1]}, []runtime.Object{tt.fields.cnr})
   319  			assert.NoError(t, err)
   320  
   321  			conf, err := options.NewOptions().Config()
   322  			require.NoError(t, err)
   323  			require.NotNil(t, conf)
   324  
   325  			ctrl, err := NewCNRMonitorController(
   326  				context.Background(),
   327  				conf.GenericConfiguration,
   328  				conf.GenericControllerConfiguration,
   329  				conf.CNRMonitorConfig,
   330  				genericCtx.Client,
   331  				genericCtx.KubeInformerFactory.Core().V1().Nodes(),
   332  				genericCtx.KubeInformerFactory.Core().V1().Pods(),
   333  				genericCtx.InternalInformerFactory.Node().V1alpha1().CustomNodeResources(),
   334  				metricspool.DummyMetricsEmitterPool.GetDefaultMetricsEmitter(metricspool.DummyMetricsEmitterPool{}),
   335  			)
   336  			assert.NoError(t, err)
   337  
   338  			// test cache synced
   339  			genericCtx.KubeInformerFactory.Start(ctrl.ctx.Done())
   340  			genericCtx.InternalInformerFactory.Start(ctrl.ctx.Done())
   341  
   342  			cache.WaitForCacheSync(ctrl.ctx.Done(), ctrl.cnrListerSynced, ctrl.podListerSynced)
   343  			time.Sleep(100 * time.Millisecond)
   344  
   345  			result := ctrl.checkNumaExclusiveAnomaly(tt.fields.cnr)
   346  			assert.Equal(t, tt.wantResult, result)
   347  		})
   348  	}
   349  }
   350  
   351  func Test_checkNumaAllocatableSumAnomaly(t *testing.T) {
   352  	t.Parallel()
   353  
   354  	type fields struct {
   355  		node *v1.Node
   356  		cnr  *v1alpha1.CustomNodeResource
   357  	}
   358  
   359  	tests := []struct {
   360  		name       string
   361  		fields     fields
   362  		wantResult bool
   363  	}{
   364  		{
   365  			name: "numa allocatable sum anomaly not found",
   366  			fields: fields{
   367  				node: &v1.Node{
   368  					ObjectMeta: metav1.ObjectMeta{
   369  						Name: "test",
   370  					},
   371  					Status: v1.NodeStatus{
   372  						Allocatable: v1.ResourceList{
   373  							v1.ResourceCPU:    *resource.NewQuantity(int64(6), resource.DecimalSI),
   374  							v1.ResourceMemory: *resource.NewQuantity(int64(2000), resource.BinarySI),
   375  						},
   376  						Capacity: v1.ResourceList{
   377  							v1.ResourceCPU:    *resource.NewQuantity(int64(6), resource.DecimalSI),
   378  							v1.ResourceMemory: *resource.NewQuantity(int64(2000), resource.BinarySI),
   379  						},
   380  					},
   381  				},
   382  				cnr: &v1alpha1.CustomNodeResource{
   383  					ObjectMeta: metav1.ObjectMeta{
   384  						Name: "test",
   385  					},
   386  					Status: v1alpha1.CustomNodeResourceStatus{
   387  						TopologyZone: []*v1alpha1.TopologyZone{
   388  							{
   389  								Type: v1alpha1.TopologyTypeSocket,
   390  								Children: []*v1alpha1.TopologyZone{
   391  									{
   392  										Type: v1alpha1.TopologyTypeNIC,
   393  										Attributes: []v1alpha1.Attribute{
   394  											{
   395  												Name:  "katalyst.kubewharf.io/resource_identifier",
   396  												Value: "enp0s3",
   397  											},
   398  										},
   399  										Name: "eth0",
   400  									},
   401  									{
   402  										Type: v1alpha1.TopologyTypeNuma,
   403  										Resources: v1alpha1.Resources{
   404  											Allocatable: &v1.ResourceList{
   405  												v1.ResourceCPU:    *resource.NewQuantity(int64(3), resource.DecimalSI),
   406  												v1.ResourceMemory: *resource.NewQuantity(int64(1000), resource.BinarySI),
   407  											},
   408  										},
   409  										Name: "0",
   410  									},
   411  									{
   412  										Type: v1alpha1.TopologyTypeNuma,
   413  										Resources: v1alpha1.Resources{
   414  											Allocatable: &v1.ResourceList{
   415  												v1.ResourceCPU:    *resource.NewQuantity(int64(3), resource.DecimalSI),
   416  												v1.ResourceMemory: *resource.NewQuantity(int64(1000), resource.BinarySI),
   417  											},
   418  										},
   419  										Name: "1",
   420  									},
   421  								},
   422  							},
   423  						},
   424  					},
   425  				},
   426  			},
   427  			wantResult: false,
   428  		},
   429  		{
   430  			name: "numa allocatable sum anomaly found",
   431  			fields: fields{
   432  				node: &v1.Node{
   433  					ObjectMeta: metav1.ObjectMeta{
   434  						Name: "test",
   435  					},
   436  					Status: v1.NodeStatus{
   437  						Allocatable: v1.ResourceList{
   438  							v1.ResourceCPU:    *resource.NewQuantity(int64(5), resource.DecimalSI),
   439  							v1.ResourceMemory: *resource.NewQuantity(int64(1000), resource.BinarySI),
   440  						},
   441  						Capacity: v1.ResourceList{
   442  							v1.ResourceCPU:    *resource.NewQuantity(int64(5), resource.DecimalSI),
   443  							v1.ResourceMemory: *resource.NewQuantity(int64(1000), resource.BinarySI),
   444  						},
   445  					},
   446  				},
   447  				cnr: &v1alpha1.CustomNodeResource{
   448  					ObjectMeta: metav1.ObjectMeta{
   449  						Name: "test",
   450  					},
   451  					Status: v1alpha1.CustomNodeResourceStatus{
   452  						TopologyZone: []*v1alpha1.TopologyZone{
   453  							{
   454  								Type: v1alpha1.TopologyTypeSocket,
   455  								Children: []*v1alpha1.TopologyZone{
   456  									{
   457  										Type: v1alpha1.TopologyTypeNIC,
   458  										Attributes: []v1alpha1.Attribute{
   459  											{
   460  												Name:  "katalyst.kubewharf.io/resource_identifier",
   461  												Value: "enp0s3",
   462  											},
   463  										},
   464  										Name: "eth0",
   465  									},
   466  									{
   467  										Type: v1alpha1.TopologyTypeNuma,
   468  										Resources: v1alpha1.Resources{
   469  											Allocatable: &v1.ResourceList{
   470  												v1.ResourceCPU:    *resource.NewQuantity(int64(3), resource.DecimalSI),
   471  												v1.ResourceMemory: *resource.NewQuantity(int64(1000), resource.BinarySI),
   472  											},
   473  										},
   474  										Name: "0",
   475  									},
   476  								},
   477  							},
   478  							{
   479  								Type: v1alpha1.TopologyTypeSocket,
   480  								Children: []*v1alpha1.TopologyZone{
   481  									{
   482  										Type: v1alpha1.TopologyTypeNuma,
   483  										Resources: v1alpha1.Resources{
   484  											Allocatable: &v1.ResourceList{
   485  												v1.ResourceCPU:    *resource.NewQuantity(int64(3), resource.DecimalSI),
   486  												v1.ResourceMemory: *resource.NewQuantity(int64(1000), resource.BinarySI),
   487  											},
   488  										},
   489  										Name: "0",
   490  									},
   491  								},
   492  							},
   493  						},
   494  					},
   495  				},
   496  			},
   497  			wantResult: true,
   498  		},
   499  	}
   500  	for _, tt := range tests {
   501  		tt := tt
   502  		t.Run(tt.name, func(t *testing.T) {
   503  			t.Parallel()
   504  
   505  			genericCtx, err := katalyst_base.GenerateFakeGenericContext([]runtime.Object{tt.fields.node}, []runtime.Object{tt.fields.cnr})
   506  			assert.NoError(t, err)
   507  
   508  			conf, err := options.NewOptions().Config()
   509  			require.NoError(t, err)
   510  			require.NotNil(t, conf)
   511  
   512  			ctrl, err := NewCNRMonitorController(
   513  				context.Background(),
   514  				conf.GenericConfiguration,
   515  				conf.GenericControllerConfiguration,
   516  				conf.CNRMonitorConfig,
   517  				genericCtx.Client,
   518  				genericCtx.KubeInformerFactory.Core().V1().Nodes(),
   519  				genericCtx.KubeInformerFactory.Core().V1().Pods(),
   520  				genericCtx.InternalInformerFactory.Node().V1alpha1().CustomNodeResources(),
   521  				metricspool.DummyMetricsEmitterPool.GetDefaultMetricsEmitter(metricspool.DummyMetricsEmitterPool{}),
   522  			)
   523  			assert.NoError(t, err)
   524  
   525  			// test cache synced
   526  			genericCtx.KubeInformerFactory.Start(ctrl.ctx.Done())
   527  			genericCtx.InternalInformerFactory.Start(ctrl.ctx.Done())
   528  
   529  			cache.WaitForCacheSync(ctrl.ctx.Done(), ctrl.cnrListerSynced, ctrl.podListerSynced)
   530  			time.Sleep(100 * time.Millisecond)
   531  
   532  			result := ctrl.checkNumaAllocatableSumAnomaly(tt.fields.cnr)
   533  			assert.Equal(t, tt.wantResult, result)
   534  		})
   535  	}
   536  }
   537  
   538  func Test_checkPodAllocationSumAnomaly(t *testing.T) {
   539  	t.Parallel()
   540  
   541  	type fields struct {
   542  		pods []*v1.Pod
   543  		cnr  *v1alpha1.CustomNodeResource
   544  	}
   545  
   546  	tests := []struct {
   547  		name       string
   548  		fields     fields
   549  		wantResult bool
   550  	}{
   551  		{
   552  			name: "pod allocatable sum anomaly not found",
   553  			fields: fields{
   554  				pods: []*v1.Pod{
   555  					{
   556  						ObjectMeta: metav1.ObjectMeta{
   557  							Name:      "test-pod1",
   558  							Namespace: "test-namespace",
   559  							Annotations: map[string]string{
   560  								consts.PodAnnotationQoSLevelKey: consts.PodAnnotationQoSLevelDedicatedCores,
   561  								consts.PodAnnotationMemoryEnhancementKey: `{
   562  									"numa_binding": "true", 
   563  									"numa_exclusive": "false"
   564  								}`,
   565  							},
   566  						},
   567  					},
   568  				},
   569  				cnr: &v1alpha1.CustomNodeResource{
   570  					ObjectMeta: metav1.ObjectMeta{
   571  						Name: "test",
   572  					},
   573  					Status: v1alpha1.CustomNodeResourceStatus{
   574  						TopologyZone: []*v1alpha1.TopologyZone{
   575  							{
   576  								Type: v1alpha1.TopologyTypeSocket,
   577  								Children: []*v1alpha1.TopologyZone{
   578  									{
   579  										Type: v1alpha1.TopologyTypeNIC,
   580  										Attributes: []v1alpha1.Attribute{
   581  											{
   582  												Name:  "katalyst.kubewharf.io/resource_identifier",
   583  												Value: "enp0s3",
   584  											},
   585  										},
   586  										Name: "eth0",
   587  									},
   588  									{
   589  										Type: v1alpha1.TopologyTypeNuma,
   590  										Allocations: []*v1alpha1.Allocation{
   591  											{
   592  												Consumer: "test-namespace/test-pod1/13414141",
   593  												Requests: &v1.ResourceList{
   594  													v1.ResourceCPU:    *resource.NewQuantity(int64(3), resource.DecimalSI),
   595  													v1.ResourceMemory: *resource.NewQuantity(int64(1000), resource.BinarySI),
   596  												},
   597  											},
   598  										},
   599  										Resources: v1alpha1.Resources{
   600  											Allocatable: &v1.ResourceList{
   601  												v1.ResourceCPU:    *resource.NewQuantity(int64(3), resource.DecimalSI),
   602  												v1.ResourceMemory: *resource.NewQuantity(int64(1000), resource.BinarySI),
   603  											},
   604  										},
   605  										Name: "0",
   606  									},
   607  								},
   608  							},
   609  						},
   610  					},
   611  				},
   612  			},
   613  			wantResult: false,
   614  		},
   615  		{
   616  			name: "pod allocatable sum anomaly found",
   617  			fields: fields{
   618  				pods: []*v1.Pod{
   619  					{
   620  						ObjectMeta: metav1.ObjectMeta{
   621  							Name:      "test-pod1",
   622  							Namespace: "test-namespace",
   623  							Annotations: map[string]string{
   624  								consts.PodAnnotationQoSLevelKey: consts.PodAnnotationQoSLevelDedicatedCores,
   625  								consts.PodAnnotationMemoryEnhancementKey: `{
   626  									"numa_binding": "true", 
   627  									"numa_exclusive": "false"
   628  								}`,
   629  							},
   630  						},
   631  					},
   632  				},
   633  				cnr: &v1alpha1.CustomNodeResource{
   634  					ObjectMeta: metav1.ObjectMeta{
   635  						Name: "test",
   636  					},
   637  					Status: v1alpha1.CustomNodeResourceStatus{
   638  						TopologyZone: []*v1alpha1.TopologyZone{
   639  							{
   640  								Type: v1alpha1.TopologyTypeSocket,
   641  								Children: []*v1alpha1.TopologyZone{
   642  									{
   643  										Type: v1alpha1.TopologyTypeNIC,
   644  										Attributes: []v1alpha1.Attribute{
   645  											{
   646  												Name:  "katalyst.kubewharf.io/resource_identifier",
   647  												Value: "enp0s3",
   648  											},
   649  										},
   650  										Name: "eth0",
   651  									},
   652  									{
   653  										Type: v1alpha1.TopologyTypeNuma,
   654  										Allocations: []*v1alpha1.Allocation{
   655  											{
   656  												Consumer: "test-namespace/test-pod1/13414141",
   657  												Requests: &v1.ResourceList{
   658  													v1.ResourceCPU:    *resource.NewQuantity(int64(4), resource.DecimalSI),
   659  													v1.ResourceMemory: *resource.NewQuantity(int64(1001), resource.BinarySI),
   660  												},
   661  											},
   662  										},
   663  										Resources: v1alpha1.Resources{
   664  											Allocatable: &v1.ResourceList{
   665  												v1.ResourceCPU:    *resource.NewQuantity(int64(3), resource.DecimalSI),
   666  												v1.ResourceMemory: *resource.NewQuantity(int64(1000), resource.BinarySI),
   667  											},
   668  										},
   669  										Name: "0",
   670  									},
   671  								},
   672  							},
   673  						},
   674  					},
   675  				},
   676  			},
   677  			wantResult: true,
   678  		},
   679  	}
   680  	for _, tt := range tests {
   681  		tt := tt
   682  		t.Run(tt.name, func(t *testing.T) {
   683  			t.Parallel()
   684  
   685  			genericCtx, err := katalyst_base.GenerateFakeGenericContext([]runtime.Object{tt.fields.pods[0]}, []runtime.Object{tt.fields.cnr})
   686  			assert.NoError(t, err)
   687  
   688  			conf, err := options.NewOptions().Config()
   689  			require.NoError(t, err)
   690  			require.NotNil(t, conf)
   691  
   692  			ctrl, err := NewCNRMonitorController(
   693  				context.Background(),
   694  				conf.GenericConfiguration,
   695  				conf.GenericControllerConfiguration,
   696  				conf.CNRMonitorConfig,
   697  				genericCtx.Client,
   698  				genericCtx.KubeInformerFactory.Core().V1().Nodes(),
   699  				genericCtx.KubeInformerFactory.Core().V1().Pods(),
   700  				genericCtx.InternalInformerFactory.Node().V1alpha1().CustomNodeResources(),
   701  				metricspool.DummyMetricsEmitterPool.GetDefaultMetricsEmitter(metricspool.DummyMetricsEmitterPool{}),
   702  			)
   703  			assert.NoError(t, err)
   704  
   705  			// test cache synced
   706  			genericCtx.KubeInformerFactory.Start(ctrl.ctx.Done())
   707  			genericCtx.InternalInformerFactory.Start(ctrl.ctx.Done())
   708  
   709  			cache.WaitForCacheSync(ctrl.ctx.Done(), ctrl.cnrListerSynced, ctrl.podListerSynced)
   710  			time.Sleep(100 * time.Millisecond)
   711  
   712  			result := ctrl.checkPodAllocationSumAnomaly(tt.fields.cnr)
   713  			assert.Equal(t, tt.wantResult, result)
   714  		})
   715  	}
   716  }
   717  
   718  func Test_checkAndEmitCNRReportLantencyMetric(t *testing.T) {
   719  	t.Parallel()
   720  
   721  	cnr := &v1alpha1.CustomNodeResource{
   722  		ObjectMeta: metav1.ObjectMeta{
   723  			Name: "test",
   724  		},
   725  		Status: v1alpha1.CustomNodeResourceStatus{
   726  			TopologyZone: []*v1alpha1.TopologyZone{
   727  				{
   728  					Type: v1alpha1.TopologyTypeSocket,
   729  					Children: []*v1alpha1.TopologyZone{
   730  						{
   731  							Type: v1alpha1.TopologyTypeNIC,
   732  							Attributes: []v1alpha1.Attribute{
   733  								{
   734  									Name:  "katalyst.kubewharf.io/resource_identifier",
   735  									Value: "enp0s3",
   736  								},
   737  							},
   738  							Name: "eth0",
   739  						},
   740  						{
   741  							Type: v1alpha1.TopologyTypeNuma,
   742  							Allocations: []*v1alpha1.Allocation{
   743  								{
   744  									Consumer: "test-namespace/test-pod1/1111111111",
   745  									Requests: &v1.ResourceList{
   746  										v1.ResourceCPU:    *resource.NewQuantity(int64(3), resource.DecimalSI),
   747  										v1.ResourceMemory: *resource.NewQuantity(int64(1000), resource.BinarySI),
   748  									},
   749  								},
   750  							},
   751  							Resources: v1alpha1.Resources{
   752  								Allocatable: &v1.ResourceList{
   753  									v1.ResourceCPU:    *resource.NewQuantity(int64(3), resource.DecimalSI),
   754  									v1.ResourceMemory: *resource.NewQuantity(int64(1000), resource.BinarySI),
   755  								},
   756  							},
   757  							Name: "0",
   758  						},
   759  					},
   760  				},
   761  			},
   762  		},
   763  	}
   764  
   765  	genericCtx, err := katalyst_base.GenerateFakeGenericContext([]runtime.Object{}, []runtime.Object{cnr})
   766  	assert.NoError(t, err)
   767  
   768  	conf, err := options.NewOptions().Config()
   769  	require.NoError(t, err)
   770  	require.NotNil(t, conf)
   771  
   772  	ctrl, err := NewCNRMonitorController(
   773  		context.Background(),
   774  		conf.GenericConfiguration,
   775  		conf.GenericControllerConfiguration,
   776  		conf.CNRMonitorConfig,
   777  		genericCtx.Client,
   778  		genericCtx.KubeInformerFactory.Core().V1().Nodes(),
   779  		genericCtx.KubeInformerFactory.Core().V1().Pods(),
   780  		genericCtx.InternalInformerFactory.Node().V1alpha1().CustomNodeResources(),
   781  		metricspool.DummyMetricsEmitterPool.GetDefaultMetricsEmitter(metricspool.DummyMetricsEmitterPool{}),
   782  	)
   783  
   784  	ctrl.podTimeMap.Store("test-namespace/test-pod1/1111111111", time.Now())
   785  	time.Sleep(2 * time.Millisecond)
   786  	assert.NoError(t, err)
   787  
   788  	err = ctrl.checkAndEmitCNRReportLantencyMetric(cnr)
   789  	assert.NoError(t, err)
   790  	if _, ok := ctrl.podTimeMap.Load("test-namespace/test-pod1/1111111111"); ok {
   791  		t.Errorf("podTimeMap should not have key test-namespace/test-pod1/1111111111")
   792  	}
   793  }