Skip to content

Commit ac6fdf7

Browse files
authored
nmstate: NodeNetworkState added unit tests (rh-ecosystem-edge#608)
Co-authored-by: nkononov <[email protected]>
1 parent cf47bbd commit ac6fdf7

File tree

2 files changed

+352
-6
lines changed

2 files changed

+352
-6
lines changed

pkg/nmstate/nodenetworkstate.go

Lines changed: 18 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -9,11 +9,10 @@ import (
99
"github.com/golang/glog"
1010
"golang.org/x/exp/slices"
1111

12-
nmstateV1alpha1 "github.com/nmstate/kubernetes-nmstate/api/v1alpha1"
13-
1412
"github.com/openshift-kni/eco-goinfra/pkg/clients"
1513
"github.com/openshift-kni/eco-goinfra/pkg/msg"
1614

15+
nmstateV1alpha1 "github.com/nmstate/kubernetes-nmstate/api/v1alpha1"
1716
k8serrors "k8s.io/apimachinery/pkg/api/errors"
1817
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
1918
goclient "sigs.k8s.io/controller-runtime/pkg/client"
@@ -30,7 +29,7 @@ type StateBuilder struct {
3029
// Created NodeNetworkState object on the cluster.
3130
Object *nmstateV1alpha1.NodeNetworkState
3231
// API client to interact with the cluster.
33-
apiClient *clients.Settings
32+
apiClient goclient.Client
3433
// errorMsg is processed before NodeNetworkState object is created.
3534
errorMsg string
3635
}
@@ -183,8 +182,21 @@ func (builder *StateBuilder) GetSriovVfs(sriovInterfaceName string) ([]Vf, error
183182
func PullNodeNetworkState(apiClient *clients.Settings, name string) (*StateBuilder, error) {
184183
glog.V(100).Infof("Pulling NodeNetworkState object name:%s", name)
185184

185+
if apiClient == nil {
186+
glog.V(100).Infof("The apiClient cannot be nil")
187+
188+
return nil, fmt.Errorf("the apiClient cannot be nil")
189+
}
190+
191+
err := apiClient.AttachScheme(nmstateV1alpha1.AddToScheme)
192+
if err != nil {
193+
glog.V(100).Infof("Failed to add nmstate v1 scheme to client schemes")
194+
195+
return nil, err
196+
}
197+
186198
stateBuilder := StateBuilder{
187-
apiClient: apiClient,
199+
apiClient: apiClient.Client,
188200
Object: &nmstateV1alpha1.NodeNetworkState{
189201
ObjectMeta: metav1.ObjectMeta{
190202
Name: name,
@@ -195,11 +207,11 @@ func PullNodeNetworkState(apiClient *clients.Settings, name string) (*StateBuild
195207
if name == "" {
196208
glog.V(100).Infof("The name of the NodeNetworkState is empty")
197209

198-
stateBuilder.errorMsg = "NodeNetworkState 'name' cannot be empty"
210+
return nil, fmt.Errorf("nodeNetworkState 'name' cannot be empty")
199211
}
200212

201213
if !stateBuilder.Exists() {
202-
return nil, fmt.Errorf("NodeNetworkState object %s does not exist", name)
214+
return nil, fmt.Errorf("nodeNetworkState object %s does not exist", name)
203215
}
204216

205217
return &stateBuilder, nil

pkg/nmstate/nodenetworkstate_test.go

Lines changed: 334 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,334 @@
1+
package nmstate
2+
3+
import (
4+
"fmt"
5+
"testing"
6+
7+
"github.com/nmstate/kubernetes-nmstate/api/shared"
8+
nmstateV1alpha1 "github.com/nmstate/kubernetes-nmstate/api/v1alpha1"
9+
"github.com/openshift-kni/eco-goinfra/pkg/clients"
10+
"github.com/stretchr/testify/assert"
11+
"gopkg.in/yaml.v2"
12+
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
13+
"k8s.io/apimachinery/pkg/runtime"
14+
)
15+
16+
var (
17+
nmstateV1alpha1TestSchemes = []clients.SchemeAttacher{
18+
nmstateV1alpha1.AddToScheme,
19+
}
20+
sriovExistingInterface = "ensf0"
21+
vfNumber = 10
22+
)
23+
24+
func TestPullNodeNetworkState(t *testing.T) {
25+
generateNodeNetState := func(name string) *nmstateV1alpha1.NodeNetworkState {
26+
return &nmstateV1alpha1.NodeNetworkState{
27+
ObjectMeta: metav1.ObjectMeta{
28+
Name: name,
29+
},
30+
Status: shared.NodeNetworkStateStatus{},
31+
}
32+
}
33+
34+
testCases := []struct {
35+
name string
36+
expectedError bool
37+
addToRuntimeObjects bool
38+
expectedErrorText string
39+
client bool
40+
}{
41+
{
42+
name: "test1",
43+
expectedError: false,
44+
addToRuntimeObjects: true,
45+
client: true,
46+
},
47+
{
48+
name: "",
49+
expectedError: true,
50+
expectedErrorText: "nodeNetworkState 'name' cannot be empty",
51+
addToRuntimeObjects: true,
52+
client: true,
53+
},
54+
{
55+
name: "test1",
56+
expectedError: true,
57+
expectedErrorText: "nodeNetworkState object test1 does not exist",
58+
addToRuntimeObjects: false,
59+
client: true,
60+
},
61+
{
62+
name: "test1",
63+
expectedError: true,
64+
expectedErrorText: "the apiClient cannot be nil",
65+
addToRuntimeObjects: true,
66+
client: false,
67+
},
68+
}
69+
70+
for _, testCase := range testCases {
71+
// Pre-populate the runtime objects
72+
var runtimeObjects []runtime.Object
73+
74+
var testSettings *clients.Settings
75+
76+
testNodeNetState := generateNodeNetState(testCase.name)
77+
78+
if testCase.addToRuntimeObjects {
79+
runtimeObjects = append(runtimeObjects, testNodeNetState)
80+
}
81+
82+
if testCase.client {
83+
testSettings = clients.GetTestClients(clients.TestClientParams{
84+
K8sMockObjects: runtimeObjects,
85+
SchemeAttachers: nmstateV1alpha1TestSchemes,
86+
})
87+
}
88+
89+
// Test the Pull method
90+
builderResult, err := PullNodeNetworkState(testSettings, testCase.name)
91+
92+
// Check the error
93+
if testCase.expectedError {
94+
assert.NotNil(t, err)
95+
96+
// Check the error message
97+
if testCase.expectedErrorText != "" {
98+
assert.Equal(t, testCase.expectedErrorText, err.Error())
99+
}
100+
} else {
101+
assert.Nil(t, err)
102+
assert.Equal(t, testNodeNetState.Name, builderResult.Object.Name)
103+
assert.Equal(t, testNodeNetState.Namespace, builderResult.Object.Namespace)
104+
}
105+
}
106+
}
107+
108+
func TestStateBuilderGet(t *testing.T) {
109+
testCases := []struct {
110+
nodeNetStateBuilder *StateBuilder
111+
expectedError error
112+
}{
113+
{
114+
nodeNetStateBuilder: buildValidNodeNetworkStateTestBuilder(buildTestClientWithDummyNodeNetworkStateObject()),
115+
expectedError: nil,
116+
},
117+
{
118+
nodeNetStateBuilder: buildValidNodeNetworkStateTestBuilder(clients.GetTestClients(clients.TestClientParams{})),
119+
expectedError: fmt.Errorf("nodenetworkstates.nmstate.io \"nmstatename\" not found"),
120+
},
121+
}
122+
123+
for _, testCase := range testCases {
124+
nodeNetState, err := testCase.nodeNetStateBuilder.Get()
125+
if testCase.expectedError != nil {
126+
assert.Equal(t, err.Error(), testCase.expectedError.Error())
127+
} else {
128+
assert.Equal(t, err, testCase.expectedError)
129+
}
130+
131+
if testCase.expectedError == nil {
132+
assert.Equal(t, nodeNetState.Name, testCase.nodeNetStateBuilder.Object.Name)
133+
}
134+
}
135+
}
136+
137+
func TestStateBuilderExist(t *testing.T) {
138+
testCases := []struct {
139+
testNodeNetState *StateBuilder
140+
expectedStatus bool
141+
}{
142+
{
143+
testNodeNetState: buildValidNodeNetworkStateTestBuilder(buildTestClientWithDummyNodeNetworkStateObject()),
144+
expectedStatus: true,
145+
},
146+
{
147+
testNodeNetState: buildValidNodeNetworkStateTestBuilder(clients.GetTestClients(clients.TestClientParams{})),
148+
expectedStatus: false,
149+
},
150+
}
151+
152+
for _, testCase := range testCases {
153+
exists := testCase.testNodeNetState.Exists()
154+
assert.Equal(t, testCase.expectedStatus, exists)
155+
}
156+
}
157+
158+
func TestStateBuilderGetTotalVFs(t *testing.T) {
159+
testCases := []struct {
160+
testNodeNetState *StateBuilder
161+
sriovInterfaceName string
162+
vfsNumber int
163+
expectedError error
164+
}{
165+
{
166+
testNodeNetState: buildValidNodeNetworkStateTestBuilder(buildTestClientWithDummyNodeNetworkStateObject()),
167+
sriovInterfaceName: sriovExistingInterface,
168+
vfsNumber: vfNumber,
169+
expectedError: nil,
170+
},
171+
{
172+
testNodeNetState: buildValidNodeNetworkStateTestBuilder(buildTestClientWithDummyNodeNetworkStateObject()),
173+
sriovInterfaceName: "invalidname",
174+
vfsNumber: 0,
175+
expectedError: fmt.Errorf("failed to find interface invalidname"),
176+
},
177+
{
178+
testNodeNetState: buildValidNodeNetworkStateTestBuilder(buildTestClientWithDummyNodeNetworkStateObject()),
179+
sriovInterfaceName: "",
180+
vfsNumber: 0,
181+
expectedError: fmt.Errorf("the sriovInterfaceName is empty sting"),
182+
},
183+
}
184+
185+
for _, testCase := range testCases {
186+
vfsNumber, err := testCase.testNodeNetState.GetTotalVFs(testCase.sriovInterfaceName)
187+
assert.Equal(t, err, testCase.expectedError)
188+
assert.Equal(t, vfsNumber, testCase.vfsNumber)
189+
}
190+
}
191+
192+
func TestStateBuilderGetInterfaceType(t *testing.T) {
193+
testCases := []struct {
194+
testNodeNetState *StateBuilder
195+
interfaceName string
196+
interfaceType string
197+
expectedError error
198+
}{
199+
{
200+
testNodeNetState: buildValidNodeNetworkStateTestBuilder(buildTestClientWithDummyNodeNetworkStateObject()),
201+
interfaceName: sriovExistingInterface,
202+
interfaceType: "ethernet",
203+
expectedError: nil,
204+
},
205+
{
206+
testNodeNetState: buildValidNodeNetworkStateTestBuilder(buildTestClientWithDummyNodeNetworkStateObject()),
207+
interfaceName: "",
208+
interfaceType: "ethernet",
209+
expectedError: fmt.Errorf("the interfaceName is empty sting"),
210+
},
211+
{
212+
testNodeNetState: buildValidNodeNetworkStateTestBuilder(buildTestClientWithDummyNodeNetworkStateObject()),
213+
interfaceName: sriovExistingInterface,
214+
interfaceType: "",
215+
expectedError: fmt.Errorf("invalid interfaceType parameter"),
216+
},
217+
{
218+
testNodeNetState: buildValidNodeNetworkStateTestBuilder(buildTestClientWithDummyNodeNetworkStateObject()),
219+
interfaceName: "test",
220+
interfaceType: "ethernet",
221+
expectedError: fmt.Errorf("failed to find interface test or it is not a ethernet type"),
222+
},
223+
}
224+
225+
for _, testCase := range testCases {
226+
networkInterface, err := testCase.testNodeNetState.GetInterfaceType(testCase.interfaceName, testCase.interfaceType)
227+
assert.Equal(t, err, testCase.expectedError)
228+
229+
if testCase.expectedError == nil {
230+
assert.Equal(t, networkInterface.Name, testCase.interfaceName)
231+
assert.Equal(t, networkInterface.Type, testCase.interfaceType)
232+
}
233+
}
234+
}
235+
236+
func TestStateBuilderGetSriovVfs(t *testing.T) {
237+
testCases := []struct {
238+
testNodeNetState *StateBuilder
239+
interfaceName string
240+
expectedError error
241+
vfsInUse int
242+
}{
243+
{
244+
testNodeNetState: buildValidNodeNetworkStateTestBuilder(buildTestClientWithDummyNodeNetworkStateObject()),
245+
interfaceName: sriovExistingInterface,
246+
vfsInUse: 1,
247+
expectedError: nil,
248+
},
249+
{
250+
testNodeNetState: buildValidNodeNetworkStateTestBuilder(buildTestClientWithDummyNodeNetworkStateObject()),
251+
interfaceName: "",
252+
expectedError: fmt.Errorf("the sriovInterfaceName is empty sting"),
253+
},
254+
{
255+
testNodeNetState: buildValidNodeNetworkStateTestBuilder(buildTestClientWithDummyNodeNetworkStateObject()),
256+
interfaceName: "test",
257+
expectedError: fmt.Errorf("failed to find interface test or SR-IOV VFs are not configured on it"),
258+
},
259+
}
260+
261+
for _, testCase := range testCases {
262+
vfsList, err := testCase.testNodeNetState.GetSriovVfs(testCase.interfaceName)
263+
assert.Equal(t, err, testCase.expectedError)
264+
265+
if testCase.expectedError == nil {
266+
assert.Equal(t, testCase.vfsInUse, len(vfsList))
267+
}
268+
}
269+
}
270+
271+
// buildValidTestBuilder returns a valid Builder for testing purposes.
272+
func buildValidNodeNetworkStateTestBuilder(apiClient *clients.Settings) *StateBuilder {
273+
return newNodeNetworkStateBuilder(apiClient, defaultNMStateName)
274+
}
275+
276+
func buildTestClientWithDummyNodeNetworkStateObject() *clients.Settings {
277+
return clients.GetTestClients(clients.TestClientParams{
278+
K8sMockObjects: buildDummyNodeNetworkStateObject(),
279+
SchemeAttachers: nmstateV1alpha1TestSchemes,
280+
})
281+
}
282+
283+
func buildDummyNodeNetworkStateObject() []runtime.Object {
284+
return append([]runtime.Object{}, &nmstateV1alpha1.NodeNetworkState{
285+
ObjectMeta: metav1.ObjectMeta{
286+
Name: defaultNMStateName,
287+
},
288+
})
289+
}
290+
291+
// newNodeNetworkStateBuilder creates a new instance of NodeNetworkStateBuilder Builder.
292+
func newNodeNetworkStateBuilder(apiClient *clients.Settings, name string) *StateBuilder {
293+
desiredState := DesiredState{
294+
Interfaces: []NetworkInterface{
295+
{
296+
Name: sriovExistingInterface,
297+
Type: "ethernet",
298+
State: "up",
299+
Ethernet: Ethernet{
300+
Sriov: Sriov{
301+
TotalVfs: &vfNumber,
302+
Vfs: []Vf{{
303+
ID: 123,
304+
},
305+
},
306+
},
307+
},
308+
},
309+
},
310+
}
311+
byteDesiredState, _ := yaml.Marshal(desiredState)
312+
err := apiClient.AttachScheme(nmstateV1alpha1.AddToScheme)
313+
314+
if err != nil {
315+
return nil
316+
}
317+
318+
builder := StateBuilder{
319+
apiClient: apiClient.Client,
320+
Object: &nmstateV1alpha1.NodeNetworkState{
321+
ObjectMeta: metav1.ObjectMeta{
322+
Name: name,
323+
},
324+
325+
Status: shared.NodeNetworkStateStatus{
326+
CurrentState: shared.State{
327+
Raw: byteDesiredState,
328+
},
329+
},
330+
},
331+
}
332+
333+
return &builder
334+
}

0 commit comments

Comments
 (0)