Skip to content

Commit 07b6e64

Browse files
author
ethanholen-hpe
committed
added additional tests to import
1 parent c59e861 commit 07b6e64

File tree

1 file changed

+329
-0
lines changed

1 file changed

+329
-0
lines changed
Lines changed: 329 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,329 @@
1+
package import_
2+
3+
import (
4+
"encoding/csv"
5+
"strings"
6+
"testing"
7+
8+
"github.com/Cray-HPE/cani/pkg/devicetypes"
9+
"github.com/google/uuid"
10+
)
11+
12+
// newTestDevice creates a CaniDeviceType with an initialised ProviderMetadata map.
13+
func newTestDevice() *devicetypes.CaniDeviceType {
14+
return &devicetypes.CaniDeviceType{
15+
ProviderMetadata: make(map[string]any),
16+
}
17+
}
18+
19+
// newTestInventory creates an Inventory pre-populated with the supplied devices.
20+
func newTestInventory(devices map[uuid.UUID]*devicetypes.CaniDeviceType) *devicetypes.Inventory {
21+
return &devicetypes.Inventory{
22+
Devices: devices,
23+
}
24+
}
25+
26+
func TestImportCSVFromReader(t *testing.T) {
27+
devID := uuid.New()
28+
inv := newTestInventory(map[uuid.UUID]*devicetypes.CaniDeviceType{
29+
devID: newTestDevice(),
30+
})
31+
32+
tests := []struct {
33+
name string
34+
csv string
35+
wantModified int
36+
wantTotal int
37+
expectErr bool
38+
}{
39+
{
40+
name: "updates device from valid CSV",
41+
csv: "ID,Role,SubRole,Nid\n" + devID.String() + ",Compute,UAN,42\n",
42+
wantModified: 1,
43+
wantTotal: 1,
44+
expectErr: false,
45+
},
46+
{
47+
name: "empty CSV returns error",
48+
csv: "",
49+
expectErr: true,
50+
},
51+
}
52+
53+
for _, tt := range tests {
54+
t.Run(tt.name, func(t *testing.T) {
55+
reader := csv.NewReader(strings.NewReader(tt.csv))
56+
mod, total, err := importCSVFromReader(reader, inv)
57+
58+
if tt.expectErr && err == nil {
59+
t.Error("expected error but got none")
60+
}
61+
if !tt.expectErr && err != nil {
62+
t.Errorf("unexpected error: %v", err)
63+
}
64+
if !tt.expectErr {
65+
if mod != tt.wantModified {
66+
t.Errorf("modified = %d, want %d", mod, tt.wantModified)
67+
}
68+
if total != tt.wantTotal {
69+
t.Errorf("total = %d, want %d", total, tt.wantTotal)
70+
}
71+
}
72+
})
73+
}
74+
}
75+
76+
func TestHasIDColumn(t *testing.T) {
77+
tests := []struct {
78+
name string
79+
headers []string
80+
want bool
81+
}{
82+
{
83+
name: "contains ID header",
84+
headers: []string{"Name", "ID", "Role"},
85+
want: true,
86+
},
87+
{
88+
name: "missing ID header",
89+
headers: []string{"Name", "Role"},
90+
want: false,
91+
},
92+
}
93+
94+
for _, tt := range tests {
95+
t.Run(tt.name, func(t *testing.T) {
96+
got := hasIDColumn(tt.headers)
97+
if got != tt.want {
98+
t.Errorf("hasIDColumn() = %t, want %t", got, tt.want)
99+
}
100+
})
101+
}
102+
}
103+
104+
func TestRowToMap(t *testing.T) {
105+
tests := []struct {
106+
name string
107+
headers []string
108+
row []string
109+
wantKey string
110+
wantVal string
111+
}{
112+
{
113+
name: "maps header to normalised key",
114+
headers: []string{"id", "role"},
115+
row: []string{"abc-123", "Compute"},
116+
wantKey: "Role",
117+
wantVal: "Compute",
118+
},
119+
{
120+
name: "row shorter than headers",
121+
headers: []string{"id", "role"},
122+
row: []string{"abc-123"},
123+
wantKey: "Role",
124+
wantVal: "",
125+
},
126+
}
127+
128+
for _, tt := range tests {
129+
t.Run(tt.name, func(t *testing.T) {
130+
m := rowToMap(tt.headers, tt.row)
131+
got := m[tt.wantKey]
132+
if got != tt.wantVal {
133+
t.Errorf("rowToMap()[%q] = %q, want %q", tt.wantKey, got, tt.wantVal)
134+
}
135+
})
136+
}
137+
}
138+
139+
func TestNormalizeHeader(t *testing.T) {
140+
tests := []struct {
141+
name string
142+
input string
143+
want string
144+
}{
145+
{
146+
name: "known header normalises",
147+
input: " role ",
148+
want: "Role",
149+
},
150+
{
151+
name: "unknown header passes through",
152+
input: "CustomField",
153+
want: "CustomField",
154+
},
155+
}
156+
157+
for _, tt := range tests {
158+
t.Run(tt.name, func(t *testing.T) {
159+
got := normalizeHeader(tt.input)
160+
if got != tt.want {
161+
t.Errorf("normalizeHeader(%q) = %q, want %q", tt.input, got, tt.want)
162+
}
163+
})
164+
}
165+
}
166+
167+
func TestSetDeviceFields(t *testing.T) {
168+
tests := []struct {
169+
name string
170+
values map[string]string
171+
want bool
172+
checkFn func(t *testing.T, dev *devicetypes.CaniDeviceType)
173+
}{
174+
{
175+
name: "sets Role and Nid",
176+
values: map[string]string{"Role": "Compute", "Nid": "42"},
177+
want: true,
178+
checkFn: func(t *testing.T, dev *devicetypes.CaniDeviceType) {
179+
sub, _ := dev.GetProviderSubMap("csm")
180+
if sub["role"] != "Compute" {
181+
t.Errorf("role = %v, want Compute", sub["role"])
182+
}
183+
if sub["nid"] != 42 {
184+
t.Errorf("nid = %v, want 42", sub["nid"])
185+
}
186+
},
187+
},
188+
{
189+
name: "no matching fields returns false",
190+
values: map[string]string{"Unknown": "value"},
191+
want: false,
192+
},
193+
}
194+
195+
for _, tt := range tests {
196+
t.Run(tt.name, func(t *testing.T) {
197+
dev := newTestDevice()
198+
got := setDeviceFields(dev, tt.values)
199+
if got != tt.want {
200+
t.Errorf("setDeviceFields() = %t, want %t", got, tt.want)
201+
}
202+
if tt.checkFn != nil {
203+
tt.checkFn(t, dev)
204+
}
205+
})
206+
}
207+
}
208+
209+
func TestSetCSMMetaString(t *testing.T) {
210+
tests := []struct {
211+
name string
212+
initial string
213+
value string
214+
want bool
215+
}{
216+
{
217+
name: "sets new value",
218+
initial: "",
219+
value: "Compute",
220+
want: true,
221+
},
222+
{
223+
name: "same value returns false",
224+
initial: "Compute",
225+
value: "Compute",
226+
want: false,
227+
},
228+
}
229+
230+
for _, tt := range tests {
231+
t.Run(tt.name, func(t *testing.T) {
232+
dev := newTestDevice()
233+
if tt.initial != "" {
234+
dev.SetProviderMeta("csm", "role", tt.initial)
235+
}
236+
got := setCSMMetaString(dev, "role", tt.value)
237+
if got != tt.want {
238+
t.Errorf("setCSMMetaString() = %t, want %t", got, tt.want)
239+
}
240+
})
241+
}
242+
}
243+
244+
func TestSetCSMMetaNid(t *testing.T) {
245+
tests := []struct {
246+
name string
247+
value string
248+
want bool
249+
}{
250+
{
251+
name: "sets valid integer",
252+
value: "42",
253+
want: true,
254+
},
255+
{
256+
name: "invalid integer returns false",
257+
value: "not-a-number",
258+
want: false,
259+
},
260+
}
261+
262+
for _, tt := range tests {
263+
t.Run(tt.name, func(t *testing.T) {
264+
dev := newTestDevice()
265+
got := setCSMMetaNid(dev, tt.value)
266+
if got != tt.want {
267+
t.Errorf("setCSMMetaNid() = %t, want %t", got, tt.want)
268+
}
269+
})
270+
}
271+
}
272+
273+
func TestSetCSMMetaAlias(t *testing.T) {
274+
tests := []struct {
275+
name string
276+
value string
277+
want bool
278+
}{
279+
{
280+
name: "sets new alias",
281+
value: "nid000042",
282+
want: true,
283+
},
284+
{
285+
name: "empty value on nil aliases returns false",
286+
value: "",
287+
want: false,
288+
},
289+
}
290+
291+
for _, tt := range tests {
292+
t.Run(tt.name, func(t *testing.T) {
293+
dev := newTestDevice()
294+
got := setCSMMetaAlias(dev, tt.value)
295+
if got != tt.want {
296+
t.Errorf("setCSMMetaAlias() = %t, want %t", got, tt.want)
297+
}
298+
})
299+
}
300+
}
301+
302+
func TestSetCSMMetaVlan(t *testing.T) {
303+
tests := []struct {
304+
name string
305+
value string
306+
want bool
307+
}{
308+
{
309+
name: "sets valid vlan",
310+
value: "100",
311+
want: true,
312+
},
313+
{
314+
name: "invalid vlan returns false",
315+
value: "abc",
316+
want: false,
317+
},
318+
}
319+
320+
for _, tt := range tests {
321+
t.Run(tt.name, func(t *testing.T) {
322+
dev := newTestDevice()
323+
got := setCSMMetaVlan(dev, tt.value)
324+
if got != tt.want {
325+
t.Errorf("setCSMMetaVlan() = %t, want %t", got, tt.want)
326+
}
327+
})
328+
}
329+
}

0 commit comments

Comments
 (0)