github.com/kubewharf/katalyst-core@v0.5.3/pkg/agent/qrm-plugins/network/staticpolicy/policy_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 staticpolicy
    18  
    19  import (
    20  	"context"
    21  	"fmt"
    22  	"io/ioutil"
    23  	"net"
    24  	"os"
    25  	"sort"
    26  	"testing"
    27  
    28  	info "github.com/google/cadvisor/info/v1"
    29  	"github.com/stretchr/testify/assert"
    30  	"github.com/stretchr/testify/require"
    31  	v1 "k8s.io/api/core/v1"
    32  	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
    33  	"k8s.io/apimachinery/pkg/runtime"
    34  	"k8s.io/apimachinery/pkg/util/uuid"
    35  	pluginapi "k8s.io/kubelet/pkg/apis/resourceplugin/v1alpha1"
    36  
    37  	apinode "github.com/kubewharf/katalyst-api/pkg/apis/node/v1alpha1"
    38  	"github.com/kubewharf/katalyst-api/pkg/consts"
    39  	katalyst_base "github.com/kubewharf/katalyst-core/cmd/base"
    40  	"github.com/kubewharf/katalyst-core/cmd/katalyst-agent/app/agent"
    41  	"github.com/kubewharf/katalyst-core/cmd/katalyst-agent/app/options"
    42  	"github.com/kubewharf/katalyst-core/pkg/agent/qrm-plugins/network/state"
    43  	"github.com/kubewharf/katalyst-core/pkg/agent/qrm-plugins/util"
    44  	"github.com/kubewharf/katalyst-core/pkg/config"
    45  	"github.com/kubewharf/katalyst-core/pkg/metaserver"
    46  	metaserveragent "github.com/kubewharf/katalyst-core/pkg/metaserver/agent"
    47  	"github.com/kubewharf/katalyst-core/pkg/metaserver/agent/pod"
    48  	"github.com/kubewharf/katalyst-core/pkg/metaserver/external"
    49  	"github.com/kubewharf/katalyst-core/pkg/metrics"
    50  	"github.com/kubewharf/katalyst-core/pkg/util/machine"
    51  )
    52  
    53  const (
    54  	testSharedNetClsId    = "12345"
    55  	testReclaimedNetClsId = "12346"
    56  
    57  	testDefaultSharedNetClsId    = 22345
    58  	testDefaultReclaimedNetClsId = 22346
    59  	testDefaultDedicatedNetClsId = 22347
    60  
    61  	testIPv4ResourceAllocationAnnotationKey             = "qrm.katalyst.kubewharf.io/inet_addr"
    62  	testIPv6ResourceAllocationAnnotationKey             = "qrm.katalyst.kubewharf.io/inet_addr_ipv6"
    63  	testNetNSPathResourceAllocationAnnotationKey        = "qrm.katalyst.kubewharf.io/netns_path"
    64  	testNetInterfaceNameResourceAllocationAnnotationKey = "qrm.katalyst.kubewharf.io/nic_name"
    65  	testNetClassIDResourceAllocationAnnotationKey       = "qrm.katalyst.kubewharf.io/netcls_id"
    66  	testNetBandwidthResourceAllocationAnnotationKey     = "qrm.katalyst.kubewharf.io/net_bandwidth"
    67  
    68  	testHostPreferEnhancementValue    = "{\"namespace_type\": \"host_ns_preferred\"}"
    69  	testNotHostPreferEnhancementValue = "{\"namespace_type\": \"anti_host_ns_preferred\"}"
    70  	testHostEnhancementValue          = "{\"namespace_type\": \"host_ns\"}"
    71  
    72  	testEth0Name               = "eth0"
    73  	testEth0AffinitiveNUMANode = 0
    74  	testEth0NSAbsolutePath     = ""
    75  	testEth0NSName             = ""
    76  
    77  	testEth1Name               = "eth1"
    78  	testEth1AffinitiveNUMANode = 1
    79  
    80  	testEth2Name               = "eth2"
    81  	testEth2AffinitiveNUMANode = 2
    82  	testEth2NSAbsolutePath     = "/var/run/ns2"
    83  	testEth2NSName             = "ns2"
    84  )
    85  
    86  var (
    87  	testEth0IPv4 = net.ParseIP("1.1.1.1").String()
    88  	testEth2IPv6 = net.ParseIP("::ffff:192.0.2.1").String()
    89  )
    90  
    91  func generateTestConfiguration(t *testing.T) *config.Configuration {
    92  	testConfiguration, err := options.NewOptions().Config()
    93  	require.NoError(t, err)
    94  	require.NotNil(t, testConfiguration)
    95  	return testConfiguration
    96  }
    97  
    98  func makeMetaServer() *metaserver.MetaServer {
    99  	cpuTopology, _ := machine.GenerateDummyCPUTopology(16, 2, 4)
   100  
   101  	return &metaserver.MetaServer{
   102  		MetaAgent: &metaserveragent.MetaAgent{
   103  			KatalystMachineInfo: &machine.KatalystMachineInfo{
   104  				CPUTopology:      cpuTopology,
   105  				ExtraNetworkInfo: &machine.ExtraNetworkInfo{},
   106  			},
   107  		},
   108  		ExternalManager: external.InitExternalManager(&pod.PodFetcherStub{}),
   109  	}
   110  }
   111  
   112  func makeTestGenericContext(t *testing.T) *agent.GenericContext {
   113  	genericCtx, err := katalyst_base.GenerateFakeGenericContext([]runtime.Object{})
   114  	assert.NoError(t, err)
   115  
   116  	return &agent.GenericContext{
   117  		GenericContext: genericCtx,
   118  		MetaServer:     makeMetaServer(),
   119  		PluginManager:  nil,
   120  	}
   121  }
   122  
   123  func makeStaticPolicy(t *testing.T, hasNic bool) *StaticPolicy {
   124  	agentCtx := makeTestGenericContext(t)
   125  	wrappedEmitter := agentCtx.EmitterPool.GetDefaultMetricsEmitter().WithTags(NetworkResourcePluginPolicyNameStatic, metrics.MetricTag{
   126  		Key: util.QRMPluginPolicyTagName,
   127  		Val: NetworkResourcePluginPolicyNameStatic,
   128  	})
   129  
   130  	cpuTopology, err := machine.GenerateDummyCPUTopology(16, 2, 4)
   131  	assert.NoError(t, err)
   132  	agentCtx.KatalystMachineInfo.CPUTopology = cpuTopology
   133  
   134  	mockQrmConfig := generateTestConfiguration(t).QRMPluginsConfiguration
   135  	mockQrmConfig.ReservedBandwidth = 4000
   136  	mockQrmConfig.EgressCapacityRate = 0.9
   137  	mockQrmConfig.IngressCapacityRate = 0.85
   138  
   139  	nics := makeNICs(hasNic)
   140  	availableNICs := filterNICsByAvailability(nics, nil, nil)
   141  	reservation := make(map[string]uint32)
   142  	if hasNic {
   143  		assert.Len(t, availableNICs, 2)
   144  
   145  		expectedReservation := map[string]uint32{
   146  			testEth0Name: 4000,
   147  		}
   148  		var err error
   149  		reservation, err = getReservedBandwidth(availableNICs, mockQrmConfig.ReservedBandwidth, FirstNIC)
   150  		assert.NoError(t, err)
   151  		assert.Equal(t, expectedReservation, reservation)
   152  	}
   153  
   154  	tmpDir, err := ioutil.TempDir("", "checkpoint")
   155  	assert.NoError(t, err)
   156  	defer os.RemoveAll(tmpDir)
   157  
   158  	stateImpl, err := state.NewCheckpointState(mockQrmConfig, tmpDir, NetworkPluginStateFileName,
   159  		NetworkResourcePluginPolicyNameStatic, &info.MachineInfo{}, availableNICs, reservation, false)
   160  	assert.NoError(t, err)
   161  
   162  	return &StaticPolicy{
   163  		qosConfig:  generateTestConfiguration(t).QoSConfiguration,
   164  		qrmConfig:  mockQrmConfig,
   165  		emitter:    wrappedEmitter,
   166  		metaServer: agentCtx.MetaServer,
   167  		stopCh:     make(chan struct{}),
   168  		name:       fmt.Sprintf("%s_%s", "qrm_network_plugin", NetworkResourcePluginPolicyNameStatic),
   169  		qosLevelToNetClassMap: map[string]uint32{
   170  			consts.PodAnnotationQoSLevelSharedCores:    testDefaultSharedNetClsId,
   171  			consts.PodAnnotationQoSLevelReclaimedCores: testDefaultReclaimedNetClsId,
   172  			consts.PodAnnotationQoSLevelDedicatedCores: testDefaultDedicatedNetClsId,
   173  		},
   174  		agentCtx:                                 agentCtx,
   175  		nics:                                     availableNICs,
   176  		state:                                    stateImpl,
   177  		podLevelNetClassAnnoKey:                  consts.PodAnnotationNetClassKey,
   178  		podLevelNetAttributesAnnoKeys:            []string{},
   179  		ipv4ResourceAllocationAnnotationKey:      testIPv4ResourceAllocationAnnotationKey,
   180  		ipv6ResourceAllocationAnnotationKey:      testIPv6ResourceAllocationAnnotationKey,
   181  		netNSPathResourceAllocationAnnotationKey: testNetNSPathResourceAllocationAnnotationKey,
   182  		netInterfaceNameResourceAllocationAnnotationKey: testNetInterfaceNameResourceAllocationAnnotationKey,
   183  		netClassIDResourceAllocationAnnotationKey:       testNetClassIDResourceAllocationAnnotationKey,
   184  		netBandwidthResourceAllocationAnnotationKey:     testNetBandwidthResourceAllocationAnnotationKey,
   185  	}
   186  }
   187  
   188  func makeNICs(hasNics bool) []machine.InterfaceInfo {
   189  	v4 := net.ParseIP(testEth0IPv4)
   190  	v6 := net.ParseIP(testEth2IPv6)
   191  
   192  	if hasNics {
   193  		return []machine.InterfaceInfo{
   194  			{
   195  				Iface:    testEth0Name,
   196  				Speed:    25000,
   197  				NumaNode: testEth0AffinitiveNUMANode,
   198  				Enable:   true,
   199  				Addr: &machine.IfaceAddr{
   200  					IPV4: []*net.IP{&v4},
   201  				},
   202  				NSAbsolutePath: testEth0NSAbsolutePath,
   203  				NSName:         testEth0NSName,
   204  			},
   205  			{
   206  				Iface:    testEth1Name,
   207  				Speed:    25000,
   208  				NumaNode: testEth1AffinitiveNUMANode,
   209  				Enable:   false,
   210  				Addr:     &machine.IfaceAddr{},
   211  			},
   212  			{
   213  				Iface:    testEth2Name,
   214  				Speed:    25000,
   215  				NumaNode: testEth2AffinitiveNUMANode,
   216  				Enable:   true,
   217  				Addr: &machine.IfaceAddr{
   218  					IPV6: []*net.IP{&v6},
   219  				},
   220  				NSAbsolutePath: testEth2NSAbsolutePath,
   221  				NSName:         testEth2NSName,
   222  			},
   223  		}
   224  	} else {
   225  		return []machine.InterfaceInfo{
   226  			{
   227  				Iface:    testEth0Name,
   228  				Speed:    25000,
   229  				NumaNode: testEth0AffinitiveNUMANode,
   230  				Enable:   false,
   231  				Addr: &machine.IfaceAddr{
   232  					IPV4: []*net.IP{&v4},
   233  				},
   234  				NSAbsolutePath: testEth0NSAbsolutePath,
   235  				NSName:         testEth0NSName,
   236  			},
   237  			{
   238  				Iface:    testEth1Name,
   239  				Speed:    25000,
   240  				NumaNode: testEth1AffinitiveNUMANode,
   241  				Enable:   false,
   242  				Addr:     &machine.IfaceAddr{},
   243  			},
   244  			{
   245  				Iface:    testEth2Name,
   246  				Speed:    25000,
   247  				NumaNode: testEth2AffinitiveNUMANode,
   248  				Enable:   false,
   249  				Addr: &machine.IfaceAddr{
   250  					IPV6: []*net.IP{&v6},
   251  				},
   252  				NSAbsolutePath: testEth2NSAbsolutePath,
   253  				NSName:         testEth2NSName,
   254  			},
   255  		}
   256  	}
   257  }
   258  
   259  func TestNewStaticPolicy(t *testing.T) {
   260  	t.Parallel()
   261  
   262  	agentCtx := makeTestGenericContext(t)
   263  	agentCtx.KatalystMachineInfo.ExtraNetworkInfo.Interface = makeNICs(true)
   264  	agentCtx.MachineInfo = &info.MachineInfo{}
   265  
   266  	conf := generateTestConfiguration(t)
   267  	conf.QRMPluginsConfiguration.ReservedBandwidth = 4000
   268  	conf.QRMPluginsConfiguration.EgressCapacityRate = 0.9
   269  	conf.QRMPluginsConfiguration.IngressCapacityRate = 0.85
   270  
   271  	tmpDir, err := ioutil.TempDir("", "checkpoint")
   272  	assert.NoError(t, err)
   273  	defer os.RemoveAll(tmpDir)
   274  	conf.GenericQRMPluginConfiguration.StateFileDirectory = tmpDir
   275  
   276  	neetToRun, policy, err := NewStaticPolicy(agentCtx, conf, nil, NetworkResourcePluginPolicyNameStatic)
   277  	assert.NoError(t, err)
   278  	assert.NotNil(t, policy)
   279  	assert.True(t, neetToRun)
   280  
   281  	// no valid nics on this node
   282  	agentCtxInvalid := agentCtx
   283  	agentCtxInvalid.KatalystMachineInfo.ExtraNetworkInfo.Interface = makeNICs(false)
   284  	neetToRun, policy, err = NewStaticPolicy(agentCtxInvalid, conf, nil, NetworkResourcePluginPolicyNameStatic)
   285  	assert.NoError(t, err)
   286  	assert.NotNil(t, policy)
   287  	assert.True(t, neetToRun)
   288  }
   289  
   290  func TestRemovePod(t *testing.T) {
   291  	t.Parallel()
   292  
   293  	policy := makeStaticPolicy(t, true)
   294  	assert.NotNil(t, policy)
   295  
   296  	podID := string(uuid.NewUUID())
   297  	testName := "test"
   298  	var bwReq float64 = 5000
   299  
   300  	// create a new Pod with bandwidth request
   301  	addReq := &pluginapi.ResourceRequest{
   302  		PodUid:         podID,
   303  		PodNamespace:   testName,
   304  		PodName:        testName,
   305  		ContainerName:  testName,
   306  		ContainerType:  pluginapi.ContainerType_MAIN,
   307  		ContainerIndex: 0,
   308  		ResourceName:   string(consts.ResourceNetBandwidth),
   309  		Hint: &pluginapi.TopologyHint{
   310  			Nodes:     []uint64{0, 1},
   311  			Preferred: true,
   312  		},
   313  		ResourceRequests: map[string]float64{
   314  			string(consts.ResourceNetBandwidth): bwReq,
   315  		},
   316  		Labels: map[string]string{
   317  			consts.PodAnnotationQoSLevelKey: consts.PodAnnotationQoSLevelSharedCores,
   318  		},
   319  		Annotations: map[string]string{
   320  			consts.PodAnnotationNetClassKey:           testSharedNetClsId,
   321  			consts.PodAnnotationQoSLevelKey:           consts.PodAnnotationQoSLevelSharedCores,
   322  			consts.PodAnnotationNetworkEnhancementKey: testHostPreferEnhancementValue,
   323  		},
   324  	}
   325  
   326  	resp, err := policy.Allocate(context.Background(), addReq)
   327  
   328  	// verify the state
   329  	allocationInfo := policy.state.GetAllocationInfo(podID, testName)
   330  	machineState := policy.state.GetMachineState()
   331  	podEntries := policy.state.GetPodEntries()
   332  	assert.NoError(t, err)
   333  	assert.NotNil(t, resp)
   334  	assert.Equal(t, allocationInfo.IfName, testEth0Name)
   335  	assert.Equal(t, allocationInfo.Egress, uint32(bwReq))
   336  	assert.Equal(t, allocationInfo.Ingress, uint32(bwReq))
   337  	assert.Len(t, machineState, 2)
   338  	assert.Len(t, machineState[testEth0Name].PodEntries, 1)
   339  	assert.EqualValues(t, machineState[testEth0Name].PodEntries[podID][testName], allocationInfo)
   340  	assert.Len(t, podEntries, 1)
   341  	assert.EqualValues(t, podEntries, machineState[testEth0Name].PodEntries)
   342  
   343  	// remove the pod
   344  	delReq := &pluginapi.RemovePodRequest{
   345  		PodUid: podID,
   346  	}
   347  
   348  	_, err = policy.RemovePod(context.TODO(), delReq)
   349  	assert.NoError(t, err)
   350  
   351  	// verify the state again
   352  	allocationInfo = policy.state.GetAllocationInfo(podID, testName)
   353  	machineState = policy.state.GetMachineState()
   354  	podEntries = policy.state.GetPodEntries()
   355  	assert.Nil(t, allocationInfo)
   356  	assert.Len(t, machineState, 2)
   357  	assert.Len(t, machineState[testEth0Name].PodEntries, 0)
   358  	assert.Len(t, podEntries, 0)
   359  }
   360  
   361  func TestAllocate(t *testing.T) {
   362  	t.Parallel()
   363  
   364  	testName := "test"
   365  
   366  	// common cases
   367  	testCases := []struct {
   368  		description  string
   369  		noError      bool
   370  		req          *pluginapi.ResourceRequest
   371  		expectedResp *pluginapi.ResourceAllocationResponse
   372  	}{
   373  		{
   374  			description: "req for init container",
   375  			noError:     true,
   376  			req: &pluginapi.ResourceRequest{
   377  				PodUid:         string(uuid.NewUUID()),
   378  				PodNamespace:   testName,
   379  				PodName:        testName,
   380  				ContainerName:  testName,
   381  				ContainerType:  pluginapi.ContainerType_INIT,
   382  				ContainerIndex: 0,
   383  				ResourceName:   string(consts.ResourceNetBandwidth),
   384  				ResourceRequests: map[string]float64{
   385  					string(consts.ResourceNetBandwidth): 5000,
   386  				},
   387  				Labels: map[string]string{
   388  					consts.PodAnnotationQoSLevelKey: consts.PodAnnotationQoSLevelSharedCores,
   389  				},
   390  				Annotations: map[string]string{
   391  					consts.PodAnnotationQoSLevelKey: consts.PodAnnotationQoSLevelSharedCores,
   392  				},
   393  			},
   394  			expectedResp: &pluginapi.ResourceAllocationResponse{
   395  				PodNamespace:     testName,
   396  				PodName:          testName,
   397  				ContainerName:    testName,
   398  				ContainerType:    pluginapi.ContainerType_INIT,
   399  				ContainerIndex:   0,
   400  				ResourceName:     string(consts.ResourceNetBandwidth),
   401  				AllocationResult: nil,
   402  				Labels: map[string]string{
   403  					consts.PodAnnotationQoSLevelKey: consts.PodAnnotationQoSLevelSharedCores,
   404  				},
   405  				Annotations: map[string]string{
   406  					consts.PodAnnotationQoSLevelKey: consts.PodAnnotationQoSLevelSharedCores,
   407  				},
   408  			},
   409  		},
   410  		{
   411  			description: "req for shared_cores main container with host netns preference",
   412  			noError:     true,
   413  			req: &pluginapi.ResourceRequest{
   414  				PodUid:         string(uuid.NewUUID()),
   415  				PodNamespace:   testName,
   416  				PodName:        testName,
   417  				ContainerName:  testName,
   418  				ContainerType:  pluginapi.ContainerType_MAIN,
   419  				ContainerIndex: 0,
   420  				ResourceName:   string(consts.ResourceNetBandwidth),
   421  				Hint: &pluginapi.TopologyHint{
   422  					Nodes:     []uint64{0, 1},
   423  					Preferred: true,
   424  				},
   425  				ResourceRequests: map[string]float64{
   426  					string(consts.ResourceNetBandwidth): 5000,
   427  				},
   428  				Labels: map[string]string{
   429  					consts.PodAnnotationQoSLevelKey: consts.PodAnnotationQoSLevelSharedCores,
   430  				},
   431  				Annotations: map[string]string{
   432  					consts.PodAnnotationNetClassKey:           testSharedNetClsId,
   433  					consts.PodAnnotationQoSLevelKey:           consts.PodAnnotationQoSLevelSharedCores,
   434  					consts.PodAnnotationNetworkEnhancementKey: testHostPreferEnhancementValue,
   435  				},
   436  			},
   437  			expectedResp: &pluginapi.ResourceAllocationResponse{
   438  				PodNamespace:   testName,
   439  				PodName:        testName,
   440  				ContainerName:  testName,
   441  				ContainerType:  pluginapi.ContainerType_MAIN,
   442  				ContainerIndex: 0,
   443  				ResourceName:   string(consts.ResourceNetBandwidth),
   444  				AllocationResult: &pluginapi.ResourceAllocation{
   445  					ResourceAllocation: map[string]*pluginapi.ResourceAllocationInfo{
   446  						string(consts.ResourceNetBandwidth): {
   447  							IsNodeResource:    true,
   448  							IsScalarResource:  true,
   449  							AllocatedQuantity: 5000,
   450  							AllocationResult:  machine.NewCPUSet(0, 1).String(),
   451  							Annotations: map[string]string{
   452  								testIPv4ResourceAllocationAnnotationKey:             testEth0IPv4,
   453  								testIPv6ResourceAllocationAnnotationKey:             "",
   454  								testNetInterfaceNameResourceAllocationAnnotationKey: testEth0Name,
   455  								testNetClassIDResourceAllocationAnnotationKey:       testSharedNetClsId,
   456  								testNetBandwidthResourceAllocationAnnotationKey:     "5000",
   457  							},
   458  							ResourceHints: &pluginapi.ListOfTopologyHints{
   459  								Hints: []*pluginapi.TopologyHint{
   460  									{
   461  										Nodes:     []uint64{0, 1},
   462  										Preferred: true,
   463  									},
   464  								},
   465  							},
   466  						},
   467  					},
   468  				},
   469  				Labels: map[string]string{
   470  					consts.PodAnnotationQoSLevelKey: consts.PodAnnotationQoSLevelSharedCores,
   471  				},
   472  				Annotations: map[string]string{
   473  					consts.PodAnnotationQoSLevelKey:                     consts.PodAnnotationQoSLevelSharedCores,
   474  					consts.PodAnnotationNetworkEnhancementNamespaceType: consts.PodAnnotationNetworkEnhancementNamespaceTypeHostPrefer,
   475  				},
   476  			},
   477  		},
   478  		{
   479  			description: "req for reclaimed_cores main container with not host netns preference",
   480  			noError:     true,
   481  			req: &pluginapi.ResourceRequest{
   482  				PodUid:         string(uuid.NewUUID()),
   483  				PodNamespace:   testName,
   484  				PodName:        testName,
   485  				ContainerName:  testName,
   486  				ContainerType:  pluginapi.ContainerType_MAIN,
   487  				ContainerIndex: 0,
   488  				ResourceName:   string(consts.ResourceNetBandwidth),
   489  				Hint: &pluginapi.TopologyHint{
   490  					Nodes:     []uint64{2, 3},
   491  					Preferred: true,
   492  				},
   493  				ResourceRequests: map[string]float64{
   494  					string(consts.ResourceNetBandwidth): 5000,
   495  				},
   496  				Annotations: map[string]string{
   497  					consts.PodAnnotationNetClassKey:           testReclaimedNetClsId,
   498  					consts.PodAnnotationQoSLevelKey:           consts.PodAnnotationQoSLevelReclaimedCores,
   499  					consts.PodAnnotationNetworkEnhancementKey: testNotHostPreferEnhancementValue,
   500  				},
   501  				Labels: map[string]string{
   502  					consts.PodAnnotationQoSLevelKey: consts.PodAnnotationQoSLevelReclaimedCores,
   503  				},
   504  			},
   505  			expectedResp: &pluginapi.ResourceAllocationResponse{
   506  				PodNamespace:   testName,
   507  				PodName:        testName,
   508  				ContainerName:  testName,
   509  				ContainerType:  pluginapi.ContainerType_MAIN,
   510  				ContainerIndex: 0,
   511  				ResourceName:   string(consts.ResourceNetBandwidth),
   512  				AllocationResult: &pluginapi.ResourceAllocation{
   513  					ResourceAllocation: map[string]*pluginapi.ResourceAllocationInfo{
   514  						string(consts.ResourceNetBandwidth): {
   515  							IsNodeResource:    true,
   516  							IsScalarResource:  true,
   517  							AllocatedQuantity: 5000,
   518  							AllocationResult:  machine.NewCPUSet(2, 3).String(),
   519  							Annotations: map[string]string{
   520  								testIPv4ResourceAllocationAnnotationKey:             "",
   521  								testIPv6ResourceAllocationAnnotationKey:             testEth2IPv6,
   522  								testNetNSPathResourceAllocationAnnotationKey:        testEth2NSAbsolutePath,
   523  								testNetInterfaceNameResourceAllocationAnnotationKey: testEth2Name,
   524  								testNetClassIDResourceAllocationAnnotationKey:       testReclaimedNetClsId,
   525  								testNetBandwidthResourceAllocationAnnotationKey:     "5000",
   526  							},
   527  							ResourceHints: &pluginapi.ListOfTopologyHints{
   528  								Hints: []*pluginapi.TopologyHint{
   529  									{
   530  										Nodes:     []uint64{2, 3},
   531  										Preferred: true,
   532  									},
   533  								},
   534  							},
   535  						},
   536  					},
   537  				},
   538  				Labels: map[string]string{
   539  					consts.PodAnnotationQoSLevelKey: consts.PodAnnotationQoSLevelReclaimedCores,
   540  				},
   541  				Annotations: map[string]string{
   542  					consts.PodAnnotationQoSLevelKey:                     consts.PodAnnotationQoSLevelReclaimedCores,
   543  					consts.PodAnnotationNetworkEnhancementNamespaceType: consts.PodAnnotationNetworkEnhancementNamespaceTypeNotHostPrefer,
   544  				},
   545  			},
   546  		},
   547  		{
   548  			description: "req for dedicated_cores main container with host netns guarantee",
   549  			noError:     true,
   550  			req: &pluginapi.ResourceRequest{
   551  				PodUid:         string(uuid.NewUUID()),
   552  				PodNamespace:   testName,
   553  				PodName:        testName,
   554  				ContainerName:  testName,
   555  				ContainerType:  pluginapi.ContainerType_MAIN,
   556  				ContainerIndex: 0,
   557  				ResourceName:   string(consts.ResourceNetBandwidth),
   558  				Hint: &pluginapi.TopologyHint{
   559  					Nodes:     []uint64{0, 1},
   560  					Preferred: true,
   561  				},
   562  				ResourceRequests: map[string]float64{
   563  					string(consts.ResourceNetBandwidth): 5000,
   564  				},
   565  				Annotations: map[string]string{
   566  					consts.PodAnnotationQoSLevelKey:           consts.PodAnnotationQoSLevelDedicatedCores,
   567  					consts.PodAnnotationNetworkEnhancementKey: testHostEnhancementValue,
   568  				},
   569  				Labels: map[string]string{
   570  					consts.PodAnnotationQoSLevelKey: consts.PodAnnotationQoSLevelDedicatedCores,
   571  				},
   572  			},
   573  			expectedResp: &pluginapi.ResourceAllocationResponse{
   574  				PodNamespace:   testName,
   575  				PodName:        testName,
   576  				ContainerName:  testName,
   577  				ContainerType:  pluginapi.ContainerType_MAIN,
   578  				ContainerIndex: 0,
   579  				ResourceName:   string(consts.ResourceNetBandwidth),
   580  				AllocationResult: &pluginapi.ResourceAllocation{
   581  					ResourceAllocation: map[string]*pluginapi.ResourceAllocationInfo{
   582  						string(consts.ResourceNetBandwidth): {
   583  							IsNodeResource:    true,
   584  							IsScalarResource:  true,
   585  							AllocatedQuantity: 5000,
   586  							AllocationResult:  machine.NewCPUSet(0, 1).String(),
   587  							Annotations: map[string]string{
   588  								testIPv4ResourceAllocationAnnotationKey:             testEth0IPv4,
   589  								testIPv6ResourceAllocationAnnotationKey:             "",
   590  								testNetInterfaceNameResourceAllocationAnnotationKey: testEth0Name,
   591  								testNetClassIDResourceAllocationAnnotationKey:       fmt.Sprintf("%d", testDefaultDedicatedNetClsId),
   592  								testNetBandwidthResourceAllocationAnnotationKey:     "5000",
   593  							},
   594  							ResourceHints: &pluginapi.ListOfTopologyHints{
   595  								Hints: []*pluginapi.TopologyHint{
   596  									{
   597  										Nodes:     []uint64{0, 1},
   598  										Preferred: true,
   599  									},
   600  								},
   601  							},
   602  						},
   603  					},
   604  				},
   605  				Labels: map[string]string{
   606  					consts.PodAnnotationQoSLevelKey: consts.PodAnnotationQoSLevelDedicatedCores,
   607  				},
   608  				Annotations: map[string]string{
   609  					consts.PodAnnotationQoSLevelKey:                     consts.PodAnnotationQoSLevelDedicatedCores,
   610  					consts.PodAnnotationNetworkEnhancementNamespaceType: consts.PodAnnotationNetworkEnhancementNamespaceTypeHost,
   611  				},
   612  			},
   613  		},
   614  		{
   615  			description: "req for dedicated_cores main container with host netns guarantee and exceeded bandwidth over the 1st NIC",
   616  			noError:     false,
   617  			req: &pluginapi.ResourceRequest{
   618  				PodUid:         string(uuid.NewUUID()),
   619  				PodNamespace:   testName,
   620  				PodName:        testName,
   621  				ContainerName:  testName,
   622  				ContainerType:  pluginapi.ContainerType_MAIN,
   623  				ContainerIndex: 0,
   624  				ResourceName:   string(consts.ResourceNetBandwidth),
   625  				Hint: &pluginapi.TopologyHint{
   626  					Nodes:     []uint64{0, 1},
   627  					Preferred: true,
   628  				},
   629  				ResourceRequests: map[string]float64{
   630  					string(consts.ResourceNetBandwidth): 20000,
   631  				},
   632  				Annotations: map[string]string{
   633  					consts.PodAnnotationQoSLevelKey:           consts.PodAnnotationQoSLevelDedicatedCores,
   634  					consts.PodAnnotationNetworkEnhancementKey: testHostEnhancementValue,
   635  				},
   636  				Labels: map[string]string{
   637  					consts.PodAnnotationQoSLevelKey: consts.PodAnnotationQoSLevelDedicatedCores,
   638  				},
   639  			},
   640  			expectedResp: nil,
   641  		},
   642  		{
   643  			description: "req for dedicated_cores main container with host netns guarantee and exceeded bandwidth over the 1st NIC which is preferred",
   644  			noError:     false,
   645  			req: &pluginapi.ResourceRequest{
   646  				PodUid:         string(uuid.NewUUID()),
   647  				PodNamespace:   testName,
   648  				PodName:        testName,
   649  				ContainerName:  testName,
   650  				ContainerType:  pluginapi.ContainerType_MAIN,
   651  				ContainerIndex: 0,
   652  				ResourceName:   string(consts.ResourceNetBandwidth),
   653  				Hint: &pluginapi.TopologyHint{
   654  					Nodes:     []uint64{0, 1},
   655  					Preferred: true,
   656  				},
   657  				ResourceRequests: map[string]float64{
   658  					string(consts.ResourceNetBandwidth): 20000,
   659  				},
   660  				Annotations: map[string]string{
   661  					consts.PodAnnotationQoSLevelKey:           consts.PodAnnotationQoSLevelDedicatedCores,
   662  					consts.PodAnnotationNetworkEnhancementKey: testHostPreferEnhancementValue,
   663  				},
   664  				Labels: map[string]string{
   665  					consts.PodAnnotationQoSLevelKey: consts.PodAnnotationQoSLevelDedicatedCores,
   666  				},
   667  			},
   668  			expectedResp: &pluginapi.ResourceAllocationResponse{
   669  				PodNamespace:   testName,
   670  				PodName:        testName,
   671  				ContainerName:  testName,
   672  				ContainerType:  pluginapi.ContainerType_MAIN,
   673  				ContainerIndex: 0,
   674  				ResourceName:   string(consts.ResourceNetBandwidth),
   675  				AllocationResult: &pluginapi.ResourceAllocation{
   676  					ResourceAllocation: map[string]*pluginapi.ResourceAllocationInfo{
   677  						string(consts.ResourceNetBandwidth): {
   678  							IsNodeResource:    true,
   679  							IsScalarResource:  true,
   680  							AllocatedQuantity: 20000,
   681  							AllocationResult:  machine.NewCPUSet(2, 3).String(),
   682  							Annotations: map[string]string{
   683  								testIPv4ResourceAllocationAnnotationKey:             testEth2IPv6,
   684  								testIPv6ResourceAllocationAnnotationKey:             "",
   685  								testNetInterfaceNameResourceAllocationAnnotationKey: testEth2Name,
   686  								testNetClassIDResourceAllocationAnnotationKey:       fmt.Sprintf("%d", testDefaultDedicatedNetClsId),
   687  								testNetBandwidthResourceAllocationAnnotationKey:     "20000",
   688  							},
   689  							ResourceHints: &pluginapi.ListOfTopologyHints{
   690  								Hints: []*pluginapi.TopologyHint{
   691  									{
   692  										Nodes:     []uint64{2, 3},
   693  										Preferred: false,
   694  									},
   695  								},
   696  							},
   697  						},
   698  					},
   699  				},
   700  				Labels: map[string]string{
   701  					consts.PodAnnotationQoSLevelKey: consts.PodAnnotationQoSLevelDedicatedCores,
   702  				},
   703  				Annotations: map[string]string{
   704  					consts.PodAnnotationQoSLevelKey:                     consts.PodAnnotationQoSLevelDedicatedCores,
   705  					consts.PodAnnotationNetworkEnhancementNamespaceType: consts.PodAnnotationNetworkEnhancementNamespaceTypeHostPrefer,
   706  				},
   707  			},
   708  		},
   709  	}
   710  
   711  	for _, tc := range testCases {
   712  		staticPolicy := makeStaticPolicy(t, true)
   713  		resp, err := staticPolicy.Allocate(context.Background(), tc.req)
   714  		if tc.noError {
   715  			assert.NoError(t, err)
   716  			assert.NotNil(t, resp)
   717  
   718  			tc.expectedResp.PodUid = tc.req.PodUid
   719  			t.Logf("expect: %v", tc.expectedResp.AllocationResult)
   720  			t.Logf("actucal: %v", resp.AllocationResult)
   721  			assert.Equalf(t, tc.expectedResp, resp, "failed in test case: %s", tc.description)
   722  		} else {
   723  			assert.Error(t, err)
   724  			assert.Nil(t, resp)
   725  		}
   726  	}
   727  
   728  	// no valid nics on this node
   729  	testCasesNoNic := []struct {
   730  		description  string
   731  		noError      bool
   732  		req          *pluginapi.ResourceRequest
   733  		expectedResp *pluginapi.ResourceAllocationResponse
   734  	}{
   735  		{
   736  			description: "req for shared_cores main container with host netns preference when no valid nic on this node",
   737  			noError:     false,
   738  			req: &pluginapi.ResourceRequest{
   739  				PodUid:         string(uuid.NewUUID()),
   740  				PodNamespace:   testName,
   741  				PodName:        testName,
   742  				ContainerName:  testName,
   743  				ContainerType:  pluginapi.ContainerType_MAIN,
   744  				ContainerIndex: 0,
   745  				ResourceName:   string(consts.ResourceNetBandwidth),
   746  				Hint: &pluginapi.TopologyHint{
   747  					Nodes:     []uint64{0, 1},
   748  					Preferred: true,
   749  				},
   750  				ResourceRequests: map[string]float64{
   751  					string(consts.ResourceNetBandwidth): 5000,
   752  				},
   753  				Labels: map[string]string{
   754  					consts.PodAnnotationQoSLevelKey: consts.PodAnnotationQoSLevelSharedCores,
   755  				},
   756  				Annotations: map[string]string{
   757  					consts.PodAnnotationNetClassKey:           testSharedNetClsId,
   758  					consts.PodAnnotationQoSLevelKey:           consts.PodAnnotationQoSLevelSharedCores,
   759  					consts.PodAnnotationNetworkEnhancementKey: testHostPreferEnhancementValue,
   760  				},
   761  			},
   762  			expectedResp: nil,
   763  		},
   764  		{
   765  			description: "0 bandwidth req for shared_cores main container with host netns preference when no valid nic on this node",
   766  			noError:     false,
   767  			req: &pluginapi.ResourceRequest{
   768  				PodUid:         string(uuid.NewUUID()),
   769  				PodNamespace:   testName,
   770  				PodName:        testName,
   771  				ContainerName:  testName,
   772  				ContainerType:  pluginapi.ContainerType_MAIN,
   773  				ContainerIndex: 0,
   774  				ResourceName:   string(consts.ResourceNetBandwidth),
   775  				Hint: &pluginapi.TopologyHint{
   776  					Nodes:     []uint64{0, 1},
   777  					Preferred: true,
   778  				},
   779  				ResourceRequests: map[string]float64{
   780  					string(consts.ResourceNetBandwidth): 0,
   781  				},
   782  				Labels: map[string]string{
   783  					consts.PodAnnotationQoSLevelKey: consts.PodAnnotationQoSLevelSharedCores,
   784  				},
   785  				Annotations: map[string]string{
   786  					consts.PodAnnotationNetClassKey:           testSharedNetClsId,
   787  					consts.PodAnnotationQoSLevelKey:           consts.PodAnnotationQoSLevelSharedCores,
   788  					consts.PodAnnotationNetworkEnhancementKey: testHostPreferEnhancementValue,
   789  				},
   790  			},
   791  			expectedResp: nil,
   792  		},
   793  	}
   794  	staticPolicy := makeStaticPolicy(t, false)
   795  	for _, tc := range testCasesNoNic {
   796  		resp, err := staticPolicy.Allocate(context.Background(), tc.req)
   797  		if tc.noError {
   798  			assert.Error(t, err)
   799  			assert.EqualError(t, err, "failed to meet the bandwidth requirement of 5000 Mbps")
   800  			assert.Nil(t, resp)
   801  		}
   802  	}
   803  }
   804  
   805  func TestGetNetClassID(t *testing.T) {
   806  	t.Parallel()
   807  
   808  	staticPolicy := makeStaticPolicy(t, true)
   809  	staticPolicy.qosLevelToNetClassMap = map[string]uint32{
   810  		consts.PodAnnotationQoSLevelReclaimedCores: 10,
   811  		consts.PodAnnotationQoSLevelSharedCores:    20,
   812  		consts.PodAnnotationQoSLevelDedicatedCores: 30,
   813  		consts.PodAnnotationQoSLevelSystemCores:    70,
   814  	}
   815  	staticPolicy.podLevelNetClassAnnoKey = consts.PodAnnotationNetClassKey
   816  
   817  	testCases := []struct {
   818  		description     string
   819  		pod             *v1.Pod
   820  		expectedClassID uint32
   821  	}{
   822  		{
   823  			description: "get net class id for shared_cores",
   824  			pod: &v1.Pod{
   825  				ObjectMeta: metav1.ObjectMeta{
   826  					Name: "test-pod-1",
   827  					Annotations: map[string]string{
   828  						consts.PodAnnotationQoSLevelKey: consts.PodAnnotationQoSLevelSharedCores,
   829  					},
   830  					Labels: map[string]string{
   831  						consts.PodAnnotationQoSLevelKey: consts.PodAnnotationQoSLevelSharedCores,
   832  					},
   833  				},
   834  			},
   835  			expectedClassID: 20,
   836  		},
   837  		{
   838  			description: "get net class id for reclaimed_cores",
   839  			pod: &v1.Pod{
   840  				ObjectMeta: metav1.ObjectMeta{
   841  					Name: "test-pod-1",
   842  					Annotations: map[string]string{
   843  						consts.PodAnnotationQoSLevelKey: consts.PodAnnotationQoSLevelReclaimedCores,
   844  					},
   845  					Labels: map[string]string{
   846  						consts.PodAnnotationQoSLevelKey: consts.PodAnnotationQoSLevelReclaimedCores,
   847  					},
   848  				},
   849  			},
   850  			expectedClassID: 10,
   851  		},
   852  		{
   853  			description: "get net class id for dedicated_cores",
   854  			pod: &v1.Pod{
   855  				ObjectMeta: metav1.ObjectMeta{
   856  					Name: "test-pod-1",
   857  					Annotations: map[string]string{
   858  						consts.PodAnnotationQoSLevelKey: consts.PodAnnotationQoSLevelDedicatedCores,
   859  					},
   860  					Labels: map[string]string{
   861  						consts.PodAnnotationQoSLevelKey: consts.PodAnnotationQoSLevelDedicatedCores,
   862  					},
   863  				},
   864  			},
   865  			expectedClassID: 30,
   866  		},
   867  		{
   868  			description: "get net class id for system_cores",
   869  			pod: &v1.Pod{
   870  				ObjectMeta: metav1.ObjectMeta{
   871  					Name: "test-pod-1",
   872  					Annotations: map[string]string{
   873  						consts.PodAnnotationQoSLevelKey: consts.PodAnnotationQoSLevelSystemCores,
   874  					},
   875  					Labels: map[string]string{
   876  						consts.PodAnnotationQoSLevelKey: consts.PodAnnotationQoSLevelSystemCores,
   877  					},
   878  				},
   879  			},
   880  			expectedClassID: 70,
   881  		},
   882  		{
   883  			description: "get pod-level net class id",
   884  			pod: &v1.Pod{
   885  				ObjectMeta: metav1.ObjectMeta{
   886  					Name: "test-pod-1",
   887  					Annotations: map[string]string{
   888  						consts.PodAnnotationQoSLevelKey:      consts.PodAnnotationQoSLevelSharedCores,
   889  						staticPolicy.podLevelNetClassAnnoKey: fmt.Sprintf("%d", 100),
   890  					},
   891  					Labels: map[string]string{
   892  						consts.PodAnnotationQoSLevelKey: consts.PodAnnotationQoSLevelSharedCores,
   893  					},
   894  				},
   895  			},
   896  			expectedClassID: 100,
   897  		},
   898  	}
   899  
   900  	for _, tc := range testCases {
   901  		gotClassID, err := staticPolicy.getNetClassID(tc.pod.Annotations, staticPolicy.podLevelNetClassAnnoKey)
   902  		assert.NoError(t, err)
   903  		assert.Equal(t, tc.expectedClassID, gotClassID)
   904  	}
   905  }
   906  
   907  func TestName(t *testing.T) {
   908  	t.Parallel()
   909  
   910  	policy := makeStaticPolicy(t, true)
   911  	assert.NotNil(t, policy)
   912  
   913  	assert.Equal(t, "qrm_network_plugin_static", policy.Name())
   914  }
   915  
   916  func TestResourceName(t *testing.T) {
   917  	t.Parallel()
   918  
   919  	policy := makeStaticPolicy(t, true)
   920  	assert.NotNil(t, policy)
   921  
   922  	assert.Equal(t, string(consts.ResourceNetBandwidth), policy.ResourceName())
   923  }
   924  
   925  func TestGetTopologyHints(t *testing.T) {
   926  	t.Parallel()
   927  
   928  	testName := "test"
   929  
   930  	// common cases
   931  	testCases := []struct {
   932  		description  string
   933  		req          *pluginapi.ResourceRequest
   934  		expectedResp *pluginapi.ResourceHintsResponse
   935  	}{
   936  		{
   937  			description: "req for init container",
   938  			req: &pluginapi.ResourceRequest{
   939  				PodUid:         string(uuid.NewUUID()),
   940  				PodNamespace:   testName,
   941  				PodName:        testName,
   942  				ContainerName:  testName,
   943  				ContainerType:  pluginapi.ContainerType_INIT,
   944  				ContainerIndex: 0,
   945  				ResourceName:   string(consts.ResourceNetBandwidth),
   946  				ResourceRequests: map[string]float64{
   947  					string(consts.ResourceNetBandwidth): 5000,
   948  				},
   949  				Labels: map[string]string{
   950  					consts.PodAnnotationQoSLevelKey: consts.PodAnnotationQoSLevelSharedCores,
   951  				},
   952  				Annotations: map[string]string{
   953  					consts.PodAnnotationQoSLevelKey: consts.PodAnnotationQoSLevelSharedCores,
   954  				},
   955  			},
   956  			expectedResp: &pluginapi.ResourceHintsResponse{
   957  				PodNamespace:   testName,
   958  				PodName:        testName,
   959  				ContainerName:  testName,
   960  				ContainerType:  pluginapi.ContainerType_INIT,
   961  				ContainerIndex: 0,
   962  				ResourceName:   string(consts.ResourceNetBandwidth),
   963  				ResourceHints: map[string]*pluginapi.ListOfTopologyHints{
   964  					string(consts.ResourceNetBandwidth): nil,
   965  				},
   966  				Labels: map[string]string{
   967  					consts.PodAnnotationQoSLevelKey: consts.PodAnnotationQoSLevelSharedCores,
   968  				},
   969  				Annotations: map[string]string{
   970  					consts.PodAnnotationQoSLevelKey: consts.PodAnnotationQoSLevelSharedCores,
   971  				},
   972  			},
   973  		},
   974  		{
   975  			description: "req for shared_cores main container with host netns preference",
   976  			req: &pluginapi.ResourceRequest{
   977  				PodUid:         string(uuid.NewUUID()),
   978  				PodNamespace:   testName,
   979  				PodName:        testName,
   980  				ContainerName:  testName,
   981  				ContainerType:  pluginapi.ContainerType_MAIN,
   982  				ContainerIndex: 0,
   983  				ResourceName:   string(consts.ResourceNetBandwidth),
   984  				ResourceRequests: map[string]float64{
   985  					string(consts.ResourceNetBandwidth): 5000,
   986  				},
   987  				Labels: map[string]string{
   988  					consts.PodAnnotationQoSLevelKey: consts.PodAnnotationQoSLevelSharedCores,
   989  				},
   990  				Annotations: map[string]string{
   991  					consts.PodAnnotationNetClassKey:           testSharedNetClsId,
   992  					consts.PodAnnotationQoSLevelKey:           consts.PodAnnotationQoSLevelSharedCores,
   993  					consts.PodAnnotationNetworkEnhancementKey: testHostPreferEnhancementValue,
   994  				},
   995  			},
   996  			expectedResp: &pluginapi.ResourceHintsResponse{
   997  				PodNamespace:   testName,
   998  				PodName:        testName,
   999  				ContainerName:  testName,
  1000  				ContainerType:  pluginapi.ContainerType_MAIN,
  1001  				ContainerIndex: 0,
  1002  				ResourceName:   string(consts.ResourceNetBandwidth),
  1003  				ResourceHints: map[string]*pluginapi.ListOfTopologyHints{
  1004  					string(consts.ResourceNetBandwidth): {
  1005  						Hints: []*pluginapi.TopologyHint{
  1006  							{
  1007  								Nodes:     []uint64{0, 1},
  1008  								Preferred: true,
  1009  							},
  1010  							{
  1011  								Nodes:     []uint64{2, 3},
  1012  								Preferred: false,
  1013  							},
  1014  							{
  1015  								Nodes:     []uint64{0, 1, 2, 3},
  1016  								Preferred: false,
  1017  							},
  1018  						},
  1019  					},
  1020  				},
  1021  				Labels: map[string]string{
  1022  					consts.PodAnnotationQoSLevelKey: consts.PodAnnotationQoSLevelSharedCores,
  1023  				},
  1024  				Annotations: map[string]string{
  1025  					consts.PodAnnotationQoSLevelKey:                     consts.PodAnnotationQoSLevelSharedCores,
  1026  					consts.PodAnnotationNetworkEnhancementNamespaceType: consts.PodAnnotationNetworkEnhancementNamespaceTypeHostPrefer,
  1027  				},
  1028  			},
  1029  		},
  1030  		{
  1031  			description: "req for reclaimed_cores main container with not host netns preference",
  1032  			req: &pluginapi.ResourceRequest{
  1033  				PodUid:         string(uuid.NewUUID()),
  1034  				PodNamespace:   testName,
  1035  				PodName:        testName,
  1036  				ContainerName:  testName,
  1037  				ContainerType:  pluginapi.ContainerType_MAIN,
  1038  				ContainerIndex: 0,
  1039  				ResourceName:   string(consts.ResourceNetBandwidth),
  1040  				ResourceRequests: map[string]float64{
  1041  					string(consts.ResourceNetBandwidth): 5000,
  1042  				},
  1043  				Annotations: map[string]string{
  1044  					consts.PodAnnotationNetClassKey:           testReclaimedNetClsId,
  1045  					consts.PodAnnotationQoSLevelKey:           consts.PodAnnotationQoSLevelReclaimedCores,
  1046  					consts.PodAnnotationNetworkEnhancementKey: testNotHostPreferEnhancementValue,
  1047  				},
  1048  				Labels: map[string]string{
  1049  					consts.PodAnnotationQoSLevelKey: consts.PodAnnotationQoSLevelReclaimedCores,
  1050  				},
  1051  			},
  1052  			expectedResp: &pluginapi.ResourceHintsResponse{
  1053  				PodNamespace:   testName,
  1054  				PodName:        testName,
  1055  				ContainerName:  testName,
  1056  				ContainerType:  pluginapi.ContainerType_MAIN,
  1057  				ContainerIndex: 0,
  1058  				ResourceName:   string(consts.ResourceNetBandwidth),
  1059  				ResourceHints: map[string]*pluginapi.ListOfTopologyHints{
  1060  					string(consts.ResourceNetBandwidth): {
  1061  						Hints: []*pluginapi.TopologyHint{
  1062  							{
  1063  								Nodes:     []uint64{0, 1},
  1064  								Preferred: false,
  1065  							},
  1066  							{
  1067  								Nodes:     []uint64{2, 3},
  1068  								Preferred: true,
  1069  							},
  1070  							{
  1071  								Nodes:     []uint64{0, 1, 2, 3},
  1072  								Preferred: false,
  1073  							},
  1074  						},
  1075  					},
  1076  				},
  1077  				Labels: map[string]string{
  1078  					consts.PodAnnotationQoSLevelKey: consts.PodAnnotationQoSLevelReclaimedCores,
  1079  				},
  1080  				Annotations: map[string]string{
  1081  					consts.PodAnnotationQoSLevelKey:                     consts.PodAnnotationQoSLevelReclaimedCores,
  1082  					consts.PodAnnotationNetworkEnhancementNamespaceType: consts.PodAnnotationNetworkEnhancementNamespaceTypeNotHostPrefer,
  1083  				},
  1084  			},
  1085  		},
  1086  		{
  1087  			description: "req for dedicated_cores main container with host netns guarantee",
  1088  			req: &pluginapi.ResourceRequest{
  1089  				PodUid:         string(uuid.NewUUID()),
  1090  				PodNamespace:   testName,
  1091  				PodName:        testName,
  1092  				ContainerName:  testName,
  1093  				ContainerType:  pluginapi.ContainerType_MAIN,
  1094  				ContainerIndex: 0,
  1095  				ResourceName:   string(consts.ResourceNetBandwidth),
  1096  				ResourceRequests: map[string]float64{
  1097  					string(consts.ResourceNetBandwidth): 5000,
  1098  				},
  1099  				Annotations: map[string]string{
  1100  					consts.PodAnnotationQoSLevelKey:           consts.PodAnnotationQoSLevelDedicatedCores,
  1101  					consts.PodAnnotationNetworkEnhancementKey: testHostEnhancementValue,
  1102  				},
  1103  				Labels: map[string]string{
  1104  					consts.PodAnnotationQoSLevelKey: consts.PodAnnotationQoSLevelDedicatedCores,
  1105  				},
  1106  			},
  1107  			expectedResp: &pluginapi.ResourceHintsResponse{
  1108  				PodNamespace:   testName,
  1109  				PodName:        testName,
  1110  				ContainerName:  testName,
  1111  				ContainerType:  pluginapi.ContainerType_MAIN,
  1112  				ContainerIndex: 0,
  1113  				ResourceName:   string(consts.ResourceNetBandwidth),
  1114  				ResourceHints: map[string]*pluginapi.ListOfTopologyHints{
  1115  					string(consts.ResourceNetBandwidth): {
  1116  						Hints: []*pluginapi.TopologyHint{
  1117  							{
  1118  								Nodes:     []uint64{0, 1},
  1119  								Preferred: true,
  1120  							},
  1121  						},
  1122  					},
  1123  				},
  1124  				Labels: map[string]string{
  1125  					consts.PodAnnotationQoSLevelKey: consts.PodAnnotationQoSLevelDedicatedCores,
  1126  				},
  1127  				Annotations: map[string]string{
  1128  					consts.PodAnnotationQoSLevelKey:                     consts.PodAnnotationQoSLevelDedicatedCores,
  1129  					consts.PodAnnotationNetworkEnhancementNamespaceType: consts.PodAnnotationNetworkEnhancementNamespaceTypeHost,
  1130  				},
  1131  			},
  1132  		},
  1133  		{
  1134  			description: "req for dedicated_cores main container with exceeded bandwidth over the 1st NIC which is preferred",
  1135  			req: &pluginapi.ResourceRequest{
  1136  				PodUid:         string(uuid.NewUUID()),
  1137  				PodNamespace:   testName,
  1138  				PodName:        testName,
  1139  				ContainerName:  testName,
  1140  				ContainerType:  pluginapi.ContainerType_MAIN,
  1141  				ContainerIndex: 0,
  1142  				ResourceName:   string(consts.ResourceNetBandwidth),
  1143  				ResourceRequests: map[string]float64{
  1144  					string(consts.ResourceNetBandwidth): 20000,
  1145  				},
  1146  				Annotations: map[string]string{
  1147  					consts.PodAnnotationQoSLevelKey:           consts.PodAnnotationQoSLevelDedicatedCores,
  1148  					consts.PodAnnotationNetworkEnhancementKey: testHostPreferEnhancementValue,
  1149  				},
  1150  				Labels: map[string]string{
  1151  					consts.PodAnnotationQoSLevelKey: consts.PodAnnotationQoSLevelDedicatedCores,
  1152  				},
  1153  			},
  1154  			expectedResp: &pluginapi.ResourceHintsResponse{
  1155  				PodNamespace:   testName,
  1156  				PodName:        testName,
  1157  				ContainerName:  testName,
  1158  				ContainerType:  pluginapi.ContainerType_MAIN,
  1159  				ContainerIndex: 0,
  1160  				ResourceName:   string(consts.ResourceNetBandwidth),
  1161  				ResourceHints: map[string]*pluginapi.ListOfTopologyHints{
  1162  					string(consts.ResourceNetBandwidth): {
  1163  						Hints: []*pluginapi.TopologyHint{
  1164  							{
  1165  								Nodes:     []uint64{2, 3},
  1166  								Preferred: false,
  1167  							},
  1168  							{
  1169  								Nodes:     []uint64{0, 1, 2, 3},
  1170  								Preferred: false,
  1171  							},
  1172  						},
  1173  					},
  1174  				},
  1175  				Labels: map[string]string{
  1176  					consts.PodAnnotationQoSLevelKey: consts.PodAnnotationQoSLevelDedicatedCores,
  1177  				},
  1178  				Annotations: map[string]string{
  1179  					consts.PodAnnotationQoSLevelKey:                     consts.PodAnnotationQoSLevelDedicatedCores,
  1180  					consts.PodAnnotationNetworkEnhancementNamespaceType: consts.PodAnnotationNetworkEnhancementNamespaceTypeHostPrefer,
  1181  				},
  1182  			},
  1183  		},
  1184  		{
  1185  			description: "req for dedicated_cores main container with exceeded bandwidth over the 1st NIC which is required",
  1186  			req: &pluginapi.ResourceRequest{
  1187  				PodUid:         string(uuid.NewUUID()),
  1188  				PodNamespace:   testName,
  1189  				PodName:        testName,
  1190  				ContainerName:  testName,
  1191  				ContainerType:  pluginapi.ContainerType_MAIN,
  1192  				ContainerIndex: 0,
  1193  				ResourceName:   string(consts.ResourceNetBandwidth),
  1194  				ResourceRequests: map[string]float64{
  1195  					string(consts.ResourceNetBandwidth): 20000,
  1196  				},
  1197  				Annotations: map[string]string{
  1198  					consts.PodAnnotationQoSLevelKey:           consts.PodAnnotationQoSLevelDedicatedCores,
  1199  					consts.PodAnnotationNetworkEnhancementKey: testHostEnhancementValue,
  1200  				},
  1201  				Labels: map[string]string{
  1202  					consts.PodAnnotationQoSLevelKey: consts.PodAnnotationQoSLevelDedicatedCores,
  1203  				},
  1204  			},
  1205  			expectedResp: &pluginapi.ResourceHintsResponse{
  1206  				PodNamespace:   testName,
  1207  				PodName:        testName,
  1208  				ContainerName:  testName,
  1209  				ContainerType:  pluginapi.ContainerType_MAIN,
  1210  				ContainerIndex: 0,
  1211  				ResourceName:   string(consts.ResourceNetBandwidth),
  1212  				ResourceHints: map[string]*pluginapi.ListOfTopologyHints{
  1213  					string(consts.ResourceNetBandwidth): {
  1214  						Hints: []*pluginapi.TopologyHint{},
  1215  					},
  1216  				},
  1217  				Labels: map[string]string{
  1218  					consts.PodAnnotationQoSLevelKey: consts.PodAnnotationQoSLevelDedicatedCores,
  1219  				},
  1220  				Annotations: map[string]string{
  1221  					consts.PodAnnotationQoSLevelKey:                     consts.PodAnnotationQoSLevelDedicatedCores,
  1222  					consts.PodAnnotationNetworkEnhancementNamespaceType: consts.PodAnnotationNetworkEnhancementNamespaceTypeHost,
  1223  				},
  1224  			},
  1225  		},
  1226  	}
  1227  
  1228  	for _, tc := range testCases {
  1229  		staticPolicy := makeStaticPolicy(t, true)
  1230  
  1231  		resp, err := staticPolicy.GetTopologyHints(context.Background(), tc.req)
  1232  		assert.NoError(t, err)
  1233  		assert.NotNil(t, resp)
  1234  
  1235  		tc.expectedResp.PodUid = tc.req.PodUid
  1236  
  1237  		compareHint := func(a, b *pluginapi.TopologyHint) bool {
  1238  			if a == nil {
  1239  				return true
  1240  			} else if b == nil {
  1241  				return false
  1242  			}
  1243  
  1244  			aset, _ := machine.NewCPUSetUint64(a.Nodes...)
  1245  			bset, _ := machine.NewCPUSetUint64(b.Nodes...)
  1246  
  1247  			asetStr := aset.String()
  1248  			bsetStr := bset.String()
  1249  
  1250  			if asetStr < bsetStr {
  1251  				return true
  1252  			} else if asetStr > bsetStr {
  1253  				return false
  1254  			} else if a.Preferred {
  1255  				return true
  1256  			} else {
  1257  				return false
  1258  			}
  1259  		}
  1260  
  1261  		if resp.ResourceHints[string(consts.ResourceNetBandwidth)] != nil {
  1262  			sort.SliceStable(resp.ResourceHints[string(consts.ResourceNetBandwidth)].Hints, func(i, j int) bool {
  1263  				return compareHint(resp.ResourceHints[string(consts.ResourceNetBandwidth)].Hints[i],
  1264  					resp.ResourceHints[string(consts.ResourceNetBandwidth)].Hints[j])
  1265  			})
  1266  		}
  1267  
  1268  		if tc.expectedResp.ResourceHints[string(consts.ResourceNetBandwidth)] != nil {
  1269  			sort.SliceStable(tc.expectedResp.ResourceHints[string(consts.ResourceNetBandwidth)].Hints, func(i, j int) bool {
  1270  				return compareHint(tc.expectedResp.ResourceHints[string(consts.ResourceNetBandwidth)].Hints[i],
  1271  					tc.expectedResp.ResourceHints[string(consts.ResourceNetBandwidth)].Hints[j])
  1272  			})
  1273  		}
  1274  
  1275  		assert.Equalf(t, tc.expectedResp, resp, "failed in test case: %s", tc.description)
  1276  	}
  1277  
  1278  	// no valid nics on this node ()
  1279  	staticPolicy := makeStaticPolicy(t, false)
  1280  	resp, err := staticPolicy.GetTopologyHints(context.Background(), testCases[1].req)
  1281  	assert.NoError(t, err)
  1282  	assert.NotNil(t, resp)
  1283  	assert.Equal(t, map[string]*pluginapi.ListOfTopologyHints{
  1284  		resp.ResourceName: {
  1285  			Hints: []*pluginapi.TopologyHint{},
  1286  		},
  1287  	}, resp.ResourceHints)
  1288  }
  1289  
  1290  func TestGetResourcesAllocation(t *testing.T) {
  1291  	t.Parallel()
  1292  
  1293  	policy := makeStaticPolicy(t, true)
  1294  	assert.NotNil(t, policy)
  1295  
  1296  	_, err := policy.GetResourcesAllocation(context.TODO(), &pluginapi.GetResourcesAllocationRequest{})
  1297  	assert.NoError(t, err)
  1298  }
  1299  
  1300  func TestGetTopologyAwareResources(t *testing.T) {
  1301  	t.Parallel()
  1302  
  1303  	podID := string(uuid.NewUUID())
  1304  	testName := "test"
  1305  	var bwReq float64 = 5000
  1306  
  1307  	testCases := []struct {
  1308  		description                   string
  1309  		hasNic                        bool
  1310  		addReq                        *pluginapi.ResourceRequest
  1311  		req                           *pluginapi.GetTopologyAwareResourcesRequest
  1312  		expectedTopologyAwareQuantity *pluginapi.TopologyAwareQuantity
  1313  	}{
  1314  		{
  1315  			description: "has valid nics and a valid Pod",
  1316  			hasNic:      true,
  1317  			addReq: &pluginapi.ResourceRequest{
  1318  				PodUid:         podID,
  1319  				PodNamespace:   testName,
  1320  				PodName:        testName,
  1321  				ContainerName:  testName,
  1322  				ContainerType:  pluginapi.ContainerType_MAIN,
  1323  				ContainerIndex: 0,
  1324  				ResourceName:   string(consts.ResourceNetBandwidth),
  1325  				Hint: &pluginapi.TopologyHint{
  1326  					Nodes:     []uint64{0, 1},
  1327  					Preferred: true,
  1328  				},
  1329  				ResourceRequests: map[string]float64{
  1330  					string(consts.ResourceNetBandwidth): bwReq,
  1331  				},
  1332  				Labels: map[string]string{
  1333  					consts.PodAnnotationQoSLevelKey: consts.PodAnnotationQoSLevelSharedCores,
  1334  				},
  1335  				Annotations: map[string]string{
  1336  					consts.PodAnnotationNetClassKey:           testSharedNetClsId,
  1337  					consts.PodAnnotationQoSLevelKey:           consts.PodAnnotationQoSLevelSharedCores,
  1338  					consts.PodAnnotationNetworkEnhancementKey: testHostPreferEnhancementValue,
  1339  				},
  1340  			},
  1341  			req: &pluginapi.GetTopologyAwareResourcesRequest{
  1342  				PodUid:        podID,
  1343  				ContainerName: testName,
  1344  			},
  1345  			expectedTopologyAwareQuantity: &pluginapi.TopologyAwareQuantity{
  1346  				ResourceValue: bwReq,
  1347  				Node:          uint64(0),
  1348  				Name:          testEth0Name,
  1349  				Type:          string(apinode.TopologyTypeNIC),
  1350  				TopologyLevel: pluginapi.TopologyLevel_SOCKET,
  1351  				Annotations: map[string]string{
  1352  					// testEth0NSName is empty, so remove the prefix
  1353  					consts.ResourceAnnotationKeyResourceIdentifier: testEth0Name,
  1354  					consts.ResourceAnnotationKeyNICNetNSName:       "",
  1355  				},
  1356  			},
  1357  		},
  1358  		{
  1359  			description: "has no valid nic",
  1360  			hasNic:      false,
  1361  			addReq: &pluginapi.ResourceRequest{
  1362  				PodUid:         podID,
  1363  				PodNamespace:   testName,
  1364  				PodName:        testName,
  1365  				ContainerName:  testName,
  1366  				ContainerType:  pluginapi.ContainerType_MAIN,
  1367  				ContainerIndex: 0,
  1368  				ResourceName:   string(consts.ResourceNetBandwidth),
  1369  				Hint: &pluginapi.TopologyHint{
  1370  					Nodes:     []uint64{0, 1},
  1371  					Preferred: true,
  1372  				},
  1373  				ResourceRequests: map[string]float64{
  1374  					string(consts.ResourceNetBandwidth): 0,
  1375  				},
  1376  				Labels: map[string]string{
  1377  					consts.PodAnnotationQoSLevelKey: consts.PodAnnotationQoSLevelSharedCores,
  1378  				},
  1379  				Annotations: map[string]string{
  1380  					consts.PodAnnotationNetClassKey:           testSharedNetClsId,
  1381  					consts.PodAnnotationQoSLevelKey:           consts.PodAnnotationQoSLevelSharedCores,
  1382  					consts.PodAnnotationNetworkEnhancementKey: testHostPreferEnhancementValue,
  1383  				},
  1384  			},
  1385  			req: &pluginapi.GetTopologyAwareResourcesRequest{
  1386  				PodUid:        podID,
  1387  				ContainerName: testName,
  1388  			},
  1389  			expectedTopologyAwareQuantity: nil,
  1390  		},
  1391  	}
  1392  
  1393  	for _, tc := range testCases {
  1394  		policy := makeStaticPolicy(t, tc.hasNic)
  1395  		assert.NotNil(t, policy)
  1396  
  1397  		_, err := policy.Allocate(context.Background(), tc.addReq)
  1398  		if tc.hasNic {
  1399  			assert.NoError(t, err)
  1400  		}
  1401  
  1402  		resp, err := policy.GetTopologyAwareResources(context.TODO(), tc.req)
  1403  		assert.NoError(t, err)
  1404  		assert.NotNil(t, resp)
  1405  		if tc.hasNic {
  1406  			assert.Len(t, resp.ContainerTopologyAwareResources.AllocatedResources, 1)
  1407  			assert.Equal(t, resp.ContainerTopologyAwareResources.AllocatedResources[string(consts.ResourceNetBandwidth)].AggregatedQuantity, bwReq)
  1408  			assert.Len(t, resp.ContainerTopologyAwareResources.AllocatedResources[string(consts.ResourceNetBandwidth)].TopologyAwareQuantityList, 1)
  1409  
  1410  			assert.Equal(t, resp.ContainerTopologyAwareResources.AllocatedResources[string(consts.ResourceNetBandwidth)].TopologyAwareQuantityList[0], tc.expectedTopologyAwareQuantity)
  1411  		} else {
  1412  			assert.Equal(t, &pluginapi.GetTopologyAwareResourcesResponse{}, resp)
  1413  		}
  1414  	}
  1415  }
  1416  
  1417  func TestGetTopologyAwareAllocatableResources(t *testing.T) {
  1418  	t.Parallel()
  1419  
  1420  	testCases := []struct {
  1421  		description                     string
  1422  		hasNic                          bool
  1423  		expectedAllocatableQuantityList []*pluginapi.TopologyAwareQuantity
  1424  		expectedCapacityQuantityList    []*pluginapi.TopologyAwareQuantity
  1425  	}{
  1426  		{
  1427  			description: "has valid nics",
  1428  			hasNic:      true,
  1429  			expectedAllocatableQuantityList: []*pluginapi.TopologyAwareQuantity{
  1430  				{
  1431  					ResourceValue: float64(17250),
  1432  					Node:          uint64(0),
  1433  					Name:          testEth0Name,
  1434  					Type:          string(apinode.TopologyTypeNIC),
  1435  					TopologyLevel: pluginapi.TopologyLevel_SOCKET,
  1436  					Annotations: map[string]string{
  1437  						// testEth0NSName is empty, so remove the prefix
  1438  						consts.ResourceAnnotationKeyResourceIdentifier: testEth0Name,
  1439  						consts.ResourceAnnotationKeyNICNetNSName:       "",
  1440  					},
  1441  				},
  1442  				{
  1443  					ResourceValue: float64(21250),
  1444  					Node:          uint64(1),
  1445  					Name:          testEth2Name,
  1446  					Type:          string(apinode.TopologyTypeNIC),
  1447  					TopologyLevel: pluginapi.TopologyLevel_SOCKET,
  1448  					Annotations: map[string]string{
  1449  						consts.ResourceAnnotationKeyResourceIdentifier: fmt.Sprintf("%s-%s", testEth2NSName, testEth2Name),
  1450  						consts.ResourceAnnotationKeyNICNetNSName:       testEth2NSName,
  1451  					},
  1452  				},
  1453  			},
  1454  			expectedCapacityQuantityList: []*pluginapi.TopologyAwareQuantity{
  1455  				{
  1456  					ResourceValue: float64(21250),
  1457  					Node:          uint64(0),
  1458  					Name:          testEth0Name,
  1459  					Type:          string(apinode.TopologyTypeNIC),
  1460  					TopologyLevel: pluginapi.TopologyLevel_SOCKET,
  1461  					Annotations: map[string]string{
  1462  						// testEth0NSName is empty, so remove the prefix
  1463  						consts.ResourceAnnotationKeyResourceIdentifier: testEth0Name,
  1464  						consts.ResourceAnnotationKeyNICNetNSName:       "",
  1465  					},
  1466  				},
  1467  				{
  1468  					ResourceValue: float64(21250),
  1469  					Node:          uint64(1),
  1470  					Name:          testEth2Name,
  1471  					Type:          string(apinode.TopologyTypeNIC),
  1472  					TopologyLevel: pluginapi.TopologyLevel_SOCKET,
  1473  					Annotations: map[string]string{
  1474  						consts.ResourceAnnotationKeyResourceIdentifier: fmt.Sprintf("%s-%s", testEth2NSName, testEth2Name),
  1475  						consts.ResourceAnnotationKeyNICNetNSName:       testEth2NSName,
  1476  					},
  1477  				},
  1478  			},
  1479  		},
  1480  		{
  1481  			description:                     "has no valid nic",
  1482  			hasNic:                          false,
  1483  			expectedAllocatableQuantityList: make([]*pluginapi.TopologyAwareQuantity, 0),
  1484  			expectedCapacityQuantityList:    make([]*pluginapi.TopologyAwareQuantity, 0),
  1485  		},
  1486  	}
  1487  
  1488  	for _, tc := range testCases {
  1489  		policy := makeStaticPolicy(t, tc.hasNic)
  1490  		assert.NotNil(t, policy)
  1491  
  1492  		resp, err := policy.GetTopologyAwareAllocatableResources(context.TODO(), &pluginapi.GetTopologyAwareAllocatableResourcesRequest{})
  1493  		assert.NotNil(t, resp)
  1494  		assert.NoError(t, err)
  1495  
  1496  		if tc.hasNic {
  1497  			assert.Equal(t, resp.AllocatableResources[string(consts.ResourceNetBandwidth)].AggregatedAllocatableQuantity, tc.expectedAllocatableQuantityList[0].ResourceValue+tc.expectedAllocatableQuantityList[1].ResourceValue)
  1498  			assert.Equal(t, resp.AllocatableResources[string(consts.ResourceNetBandwidth)].AggregatedCapacityQuantity, tc.expectedCapacityQuantityList[0].ResourceValue+tc.expectedCapacityQuantityList[1].ResourceValue)
  1499  			assert.Len(t, resp.AllocatableResources[string(consts.ResourceNetBandwidth)].TopologyAwareAllocatableQuantityList, len(tc.expectedAllocatableQuantityList))
  1500  			assert.Len(t, resp.AllocatableResources[string(consts.ResourceNetBandwidth)].TopologyAwareCapacityQuantityList, len(tc.expectedCapacityQuantityList))
  1501  
  1502  			assert.Equal(t, resp.AllocatableResources[string(consts.ResourceNetBandwidth)].TopologyAwareAllocatableQuantityList, tc.expectedAllocatableQuantityList)
  1503  			assert.Equal(t, resp.AllocatableResources[string(consts.ResourceNetBandwidth)].TopologyAwareCapacityQuantityList, tc.expectedCapacityQuantityList)
  1504  		} else {
  1505  			assert.Equal(t, float64(0), resp.AllocatableResources[string(consts.ResourceNetBandwidth)].AggregatedAllocatableQuantity)
  1506  			assert.Equal(t, float64(0), resp.AllocatableResources[string(consts.ResourceNetBandwidth)].AggregatedCapacityQuantity)
  1507  			assert.Len(t, resp.AllocatableResources[string(consts.ResourceNetBandwidth)].TopologyAwareAllocatableQuantityList, 0)
  1508  			assert.Len(t, resp.AllocatableResources[string(consts.ResourceNetBandwidth)].TopologyAwareCapacityQuantityList, 0)
  1509  		}
  1510  	}
  1511  }
  1512  
  1513  func TestGetResourcePluginOptions(t *testing.T) {
  1514  	t.Parallel()
  1515  
  1516  	policy := makeStaticPolicy(t, true)
  1517  	assert.NotNil(t, policy)
  1518  
  1519  	expectedResp := &pluginapi.ResourcePluginOptions{
  1520  		PreStartRequired:      false,
  1521  		WithTopologyAlignment: true,
  1522  		NeedReconcile:         false,
  1523  	}
  1524  
  1525  	resp, err := policy.GetResourcePluginOptions(context.TODO(), &pluginapi.Empty{})
  1526  	assert.NoError(t, err)
  1527  	assert.Equal(t, expectedResp, resp)
  1528  }
  1529  
  1530  func TestPreStartContainer(t *testing.T) {
  1531  	t.Parallel()
  1532  
  1533  	policy := makeStaticPolicy(t, true)
  1534  	assert.NotNil(t, policy)
  1535  
  1536  	req := &pluginapi.PreStartContainerRequest{
  1537  		PodUid:        string(uuid.NewUUID()),
  1538  		PodNamespace:  "test-namespace",
  1539  		PodName:       "test-pod-name",
  1540  		ContainerName: "test-container-name",
  1541  	}
  1542  
  1543  	_, err := policy.PreStartContainer(context.TODO(), req)
  1544  	assert.NoError(t, err)
  1545  }