Skip to content

Commit

Permalink
chore: add unit tests for state-rdma-device-plugin (#983)
Browse files Browse the repository at this point in the history
This PR adds unit tests for `state-rdma-device-plugin`.
To be able to add unit tests for the rdma dp we have to rename it to
state_rdma_device_plugin.go first.
  • Loading branch information
adrianchiris authored Jul 18, 2024
2 parents 0fd31b9 + b97d927 commit 6800708
Show file tree
Hide file tree
Showing 11 changed files with 146 additions and 17 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
*.swp
*.swo
*~
.vscode

# Helm charts
deployment/network-operator/Chart.lock
Expand Down
4 changes: 2 additions & 2 deletions api/v1alpha1/validator/nicclusterpolicy_webhook.go
Original file line number Diff line number Diff line change
Expand Up @@ -546,8 +546,8 @@ func (w *nicClusterPolicyValidator) validateContainerResources(
}
if policy.Spec.RdmaSharedDevicePlugin != nil {
states["rdmaSharedDevicePlugin"] = stateRenderData{
policy.Spec.RdmaSharedDevicePlugin, state.NewStateSharedDp,
filepath.Join(manifestBaseDir, "state-rdma-device-plugin"),
policy.Spec.RdmaSharedDevicePlugin, state.NewStateRDMASharedDevicePlugin,
filepath.Join(manifestBaseDir, "state-rdma-shared-device-plugin"),
}
}
if policy.Spec.SriovDevicePlugin != nil {
Expand Down
10 changes: 9 additions & 1 deletion pkg/state/common_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -38,9 +38,17 @@ import (
)

func getTestCatalog() state.InfoCatalog {
return getTestCatalogForOpenshift(false)
}

func getOpenshiftTestCatalog() state.InfoCatalog {
return getTestCatalogForOpenshift(true)
}

func getTestCatalogForOpenshift(isOpenshift bool) state.InfoCatalog {
catalog := state.NewInfoCatalog()
clusterTypeProvider := clustertype_mocks.Provider{}
clusterTypeProvider.On("IsOpenshift").Return(false)
clusterTypeProvider.On("IsOpenshift").Return(isOpenshift)
staticConfigProvider := staticconfig_mocks.Provider{}
staticConfigProvider.On("GetStaticConfig").Return(staticconfig.StaticConfig{CniBinDirectory: ""})
catalog.Add(state.InfoTypeStaticConfig, &staticConfigProvider)
Expand Down
4 changes: 2 additions & 2 deletions pkg/state/factory.go
Original file line number Diff line number Diff line change
Expand Up @@ -79,8 +79,8 @@ func newNicClusterPolicyStates(k8sAPIClient client.Client) ([]State, error) {
return nil, errors.Wrapf(err, "failed to create OFED driver State")
}

sharedDpState, _, err := NewStateSharedDp(
k8sAPIClient, filepath.Join(manifestBaseDir, "state-rdma-device-plugin"))
sharedDpState, _, err := NewStateRDMASharedDevicePlugin(
k8sAPIClient, filepath.Join(manifestBaseDir, "state-rdma-shared-device-plugin"))
if err != nil {
return nil, errors.Wrapf(err, "failed to create Shared Device plugin State")
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,16 +35,16 @@ import (
"github.com/Mellanox/network-operator/pkg/utils"
)

// NewStateSharedDp creates a new shared device plugin state
func NewStateSharedDp(
// NewStateRDMASharedDevicePlugin creates a new shared device plugin state
func NewStateRDMASharedDevicePlugin(
k8sAPIClient client.Client, manifestDir string) (State, ManifestRenderer, error) {
files, err := utils.GetFilesWithSuffix(manifestDir, render.ManifestFileSuffix...)
if err != nil {
return nil, nil, errors.Wrap(err, "failed to get files from manifest dir")
}

renderer := render.NewRenderer(files)
state := &stateSharedDp{
state := &stateRDMASharedDevicePlugin{
stateSkel: stateSkel{
name: "state-RDMA-device-plugin",
description: "RDMA shared device plugin deployed in the cluster",
Expand All @@ -54,29 +54,29 @@ func NewStateSharedDp(
return state, state, nil
}

type stateSharedDp struct {
type stateRDMASharedDevicePlugin struct {
stateSkel
}

type sharedDpRuntimeSpec struct {
type stateRDMASharedDevicePluginSpec struct {
runtimeSpec
// is true if cluster type is Openshift
IsOpenshift bool
ContainerResources ContainerResourcesMap
}
type sharedDpManifestRenderData struct {
type stateRDMASharedDevicePluginManifestRenderData struct {
CrSpec *mellanoxv1alpha1.DevicePluginSpec
Tolerations []v1.Toleration
NodeAffinity *v1.NodeAffinity
DeployInitContainer bool
RuntimeSpec *sharedDpRuntimeSpec
RuntimeSpec *stateRDMASharedDevicePluginSpec
}

// Sync attempt to get the system to match the desired state which State represent.
// a sync operation must be relatively short and must not block the execution thread.
//
//nolint:dupl
func (s *stateSharedDp) Sync(
func (s *stateRDMASharedDevicePlugin) Sync(
ctx context.Context, customResource interface{}, infoCatalog InfoCatalog) (SyncState, error) {
reqLogger := log.FromContext(ctx)
cr := customResource.(*mellanoxv1alpha1.NicClusterPolicy)
Expand Down Expand Up @@ -128,15 +128,15 @@ func (s *stateSharedDp) Sync(
}

// Get a map of source kinds that should be watched for the state keyed by the source kind name
func (s *stateSharedDp) GetWatchSources() map[string]client.Object {
func (s *stateRDMASharedDevicePlugin) GetWatchSources() map[string]client.Object {
wr := make(map[string]client.Object)
wr["DaemonSet"] = &appsv1.DaemonSet{}
wr["ConfigMap"] = &v1.ConfigMap{}
return wr
}

//nolint:dupl
func (s *stateSharedDp) GetManifestObjects(
func (s *stateRDMASharedDevicePlugin) GetManifestObjects(
_ context.Context, cr *mellanoxv1alpha1.NicClusterPolicy,
catalog InfoCatalog, reqLogger logr.Logger) ([]*unstructured.Unstructured, error) {
if cr == nil || cr.Spec.RdmaSharedDevicePlugin == nil {
Expand All @@ -147,12 +147,12 @@ func (s *stateSharedDp) GetManifestObjects(
if clusterInfo == nil {
return nil, errors.New("clusterInfo provider required")
}
renderData := &sharedDpManifestRenderData{
renderData := &stateRDMASharedDevicePluginManifestRenderData{
CrSpec: cr.Spec.RdmaSharedDevicePlugin,
Tolerations: cr.Spec.Tolerations,
NodeAffinity: cr.Spec.NodeAffinity,
DeployInitContainer: cr.Spec.OFEDDriver != nil,
RuntimeSpec: &sharedDpRuntimeSpec{
RuntimeSpec: &stateRDMASharedDevicePluginSpec{
runtimeSpec: runtimeSpec{config.FromEnv().State.NetworkOperatorResourceNamespace},
IsOpenshift: clusterInfo.IsOpenshift(),
ContainerResources: createContainerResourcesMap(cr.Spec.RdmaSharedDevicePlugin.ContainerResources),
Expand Down
120 changes: 120 additions & 0 deletions pkg/state/state_rdma_shared_device_plugin_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,120 @@
/*
2024 NVIDIA CORPORATION & AFFILIATES
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

package state_test

import (
"context"

. "github.com/onsi/ginkgo/v2"
. "github.com/onsi/gomega"

"github.com/go-logr/logr"
v1 "k8s.io/api/core/v1"
"k8s.io/apimachinery/pkg/api/resource"
"k8s.io/apimachinery/pkg/runtime"
"sigs.k8s.io/controller-runtime/pkg/client"
"sigs.k8s.io/controller-runtime/pkg/client/fake"
"sigs.k8s.io/controller-runtime/pkg/log"

netattdefv1 "github.com/k8snetworkplumbingwg/network-attachment-definition-client/pkg/apis/k8s.cni.cncf.io/v1"

mellanoxv1alpha1 "github.com/Mellanox/network-operator/api/v1alpha1"
"github.com/Mellanox/network-operator/pkg/state"
)

var _ = Describe("RDMA Shared Device Plugin", func() {

var ctx context.Context
var rdmaDPState state.State
var rdmaDPRenderer state.ManifestRenderer
var testLogger logr.Logger
var catalog state.InfoCatalog
var client client.Client
var manifestDir string

BeforeEach(func() {
ctx = context.Background()
scheme := runtime.NewScheme()
Expect(mellanoxv1alpha1.AddToScheme(scheme)).NotTo(HaveOccurred())
Expect(netattdefv1.AddToScheme(scheme)).NotTo(HaveOccurred())
client = fake.NewClientBuilder().WithScheme(scheme).Build()
manifestDir = "../../manifests/state-rdma-shared-device-plugin"
s, r, err := state.NewStateRDMASharedDevicePlugin(client, manifestDir)
Expect(err).NotTo(HaveOccurred())
rdmaDPState = s
rdmaDPRenderer = r
catalog = getTestCatalog()
testLogger = log.Log.WithName("testLog")
})

Context("should render", func() {
It("Kubernetes manifests", func() {
cr := getRDMASharedDevicePlugin()
objs, err := rdmaDPRenderer.GetManifestObjects(ctx, cr, catalog, testLogger)
Expect(err).NotTo(HaveOccurred())
// We only expect a single manifest here, which should be the DaemonSet.
// The other manifests are only if RuntimeSpec.IsOpenshift == true.
Expect(len(objs)).To(Equal(1))
GetManifestObjectsTest(ctx, cr, catalog, &cr.Spec.RdmaSharedDevicePlugin.ImageSpec, rdmaDPRenderer)
})
It("Openshift manifests", func() {
cr := getRDMASharedDevicePlugin()
openshiftCatalog := getOpenshiftTestCatalog()
objs, err := rdmaDPRenderer.GetManifestObjects(ctx, cr, openshiftCatalog, testLogger)
Expect(err).NotTo(HaveOccurred())
Expect(len(objs)).To(Equal(4))
GetManifestObjectsTest(ctx, cr, catalog, &cr.Spec.RdmaSharedDevicePlugin.ImageSpec, rdmaDPRenderer)
})
})
Context("should sync", func() {
It("wihtout any errors", func() {
cr := getRDMASharedDevicePlugin()
err := client.Create(ctx, cr)
Expect(err).NotTo(HaveOccurred())
status, err := rdmaDPState.Sync(ctx, cr, catalog)
Expect(err).NotTo(HaveOccurred())
// We do not expect that the sync state (i.e. the DaemonSet) will be ready.
// There is no real Kubernetes cluster in the unit tests and thus the Pods cannot be scheduled.
Expect(status).To(BeEquivalentTo(state.SyncStateNotReady))
})
})
})

func getRDMASharedDevicePlugin() *mellanoxv1alpha1.NicClusterPolicy {
cr := getTestClusterPolicyWithBaseFields()
imageSpec := getTestImageSpec()
cr.Name = "nic-cluster-policy"
cr.Spec.RdmaSharedDevicePlugin = &mellanoxv1alpha1.DevicePluginSpec{
ImageSpecWithConfig: mellanoxv1alpha1.ImageSpecWithConfig{
ImageSpec: *imageSpec,
},
}
cr.Spec.RdmaSharedDevicePlugin.ContainerResources = []mellanoxv1alpha1.ResourceRequirements{
{
Name: "rdma-shared-dp",
Requests: v1.ResourceList{
"cpu": resource.MustParse("150m"),
"memory": resource.MustParse("150Mi"),
},
Limits: v1.ResourceList{
"cpu": resource.MustParse("150m"),
"memory": resource.MustParse("200Mi"),
},
},
}
return cr
}

0 comments on commit 6800708

Please sign in to comment.