Skip to content

Commit c31a501

Browse files
Improved Code Coverage for utils/errors, awsapi , persistent store
1 parent 8a33f16 commit c31a501

11 files changed

Lines changed: 6715 additions & 1218 deletions

File tree

persistent_store/crdv1_test.go

Lines changed: 829 additions & 0 deletions
Large diffs are not rendered by default.

persistent_store/in_memory_test.go

Lines changed: 1312 additions & 0 deletions
Large diffs are not rendered by default.

storage_drivers/ontap/api/abstraction_error_test.go

Lines changed: 429 additions & 0 deletions
Large diffs are not rendered by default.
Lines changed: 255 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,255 @@
1+
// Copyright 2025 NetApp, Inc. All Rights Reserved.
2+
3+
package api
4+
5+
import (
6+
"reflect"
7+
"strings"
8+
"testing"
9+
"time"
10+
11+
"github.com/stretchr/testify/assert"
12+
"github.com/stretchr/testify/require"
13+
)
14+
15+
// TestSnapmirrorTypes tests all snapmirror type methods and constants
16+
func TestSnapmirrorTypes(t *testing.T) {
17+
// Test data for all snapmirror types
18+
states := map[SnapmirrorState]bool{
19+
SnapmirrorStateUninitialized: true, // Only this should be uninitialized
20+
SnapmirrorStateSnapmirrored: false,
21+
SnapmirrorStateBrokenOffZapi: false,
22+
SnapmirrorStateBrokenOffRest: false,
23+
SnapmirrorStateSynchronizing: false,
24+
SnapmirrorStateInSync: false,
25+
SnapmirrorState("invalid"): false,
26+
}
27+
28+
statuses := map[SnapmirrorStatus]map[string]bool{
29+
SnapmirrorStatusIdle: {"IsIdle": true},
30+
SnapmirrorStatusAborting: {"IsAborting": true},
31+
SnapmirrorStatusBreaking: {"IsBreaking": true},
32+
SnapmirrorStatusTransferring: {"IsTransferring": true},
33+
SnapmirrorStatusQuiescing: {},
34+
SnapmirrorStatusFinalizing: {},
35+
SnapmirrorStatusAborted: {},
36+
SnapmirrorStatusFailed: {},
37+
SnapmirrorStatusHardAborted: {},
38+
SnapmirrorStatusQueued: {},
39+
SnapmirrorStatusSuccess: {},
40+
SnapmirrorStatus("invalid"): {},
41+
}
42+
43+
policyTypes := []struct {
44+
policyType SnapmirrorPolicyType
45+
isSync bool
46+
isAsync bool
47+
}{
48+
{SnapmirrorPolicyZAPITypeSync, true, false},
49+
{SnapmirrorPolicyRESTTypeSync, true, false},
50+
{SnapmirrorPolicyZAPITypeAsync, false, true},
51+
{SnapmirrorPolicyRESTTypeAsync, false, true},
52+
{SnapmirrorPolicyType("invalid"), false, false},
53+
}
54+
55+
// Test state methods
56+
for state, expectUninitialized := range states {
57+
assert.Equal(t, expectUninitialized, state.IsUninitialized(),
58+
"State %s IsUninitialized should return %v", state, expectUninitialized)
59+
}
60+
61+
// Test status methods
62+
for status, methods := range statuses {
63+
assert.Equal(t, methods["IsIdle"], status.IsIdle())
64+
assert.Equal(t, methods["IsAborting"], status.IsAborting())
65+
assert.Equal(t, methods["IsBreaking"], status.IsBreaking())
66+
assert.Equal(t, methods["IsTransferring"], status.IsTransferring())
67+
}
68+
69+
// Test policy type methods
70+
for _, tc := range policyTypes {
71+
assert.Equal(t, tc.isSync, tc.policyType.IsSnapmirrorPolicyTypeSync())
72+
assert.Equal(t, tc.isAsync, tc.policyType.IsSnapmirrorPolicyTypeAsync())
73+
if tc.policyType != "invalid" {
74+
assert.NotEqual(t, tc.isSync, tc.isAsync, "Cannot be both sync and async")
75+
}
76+
}
77+
}
78+
79+
// TestConstants validates all snapmirror constants and type definitions
80+
func TestConstants(t *testing.T) {
81+
// Test constant values and slice types in a single table
82+
tests := []struct {
83+
name string
84+
testFunc func(t *testing.T)
85+
}{
86+
{"PolicyRule", func(t *testing.T) {
87+
assert.Equal(t, "all_source_snapshots", SnapmirrorPolicyRuleAll)
88+
}},
89+
{"StateConstants", func(t *testing.T) {
90+
expected := map[SnapmirrorState]string{
91+
SnapmirrorStateUninitialized: "uninitialized",
92+
SnapmirrorStateSnapmirrored: "snapmirrored",
93+
SnapmirrorStateBrokenOffZapi: "broken-off",
94+
SnapmirrorStateBrokenOffRest: "broken_off",
95+
SnapmirrorStateSynchronizing: "synchronizing",
96+
SnapmirrorStateInSync: "in_sync",
97+
}
98+
for state, expectedValue := range expected {
99+
assert.Equal(t, expectedValue, string(state))
100+
}
101+
assert.NotEqual(t, SnapmirrorStateBrokenOffZapi, SnapmirrorStateBrokenOffRest)
102+
}},
103+
{"StatusConstants", func(t *testing.T) {
104+
statuses := []SnapmirrorStatus{
105+
SnapmirrorStatusIdle, SnapmirrorStatusAborting, SnapmirrorStatusBreaking,
106+
SnapmirrorStatusQuiescing, SnapmirrorStatusTransferring, SnapmirrorStatusFinalizing,
107+
SnapmirrorStatusAborted, SnapmirrorStatusFailed, SnapmirrorStatusHardAborted,
108+
SnapmirrorStatusQueued, SnapmirrorStatusSuccess,
109+
}
110+
uniqueValues := make(map[SnapmirrorStatus]bool)
111+
for _, status := range statuses {
112+
assert.NotEmpty(t, string(status))
113+
assert.False(t, uniqueValues[status], "Status should be unique")
114+
uniqueValues[status] = true
115+
}
116+
}},
117+
{"PolicyTypeConstants", func(t *testing.T) {
118+
expected := map[SnapmirrorPolicyType]string{
119+
SnapmirrorPolicyZAPITypeSync: "sync_mirror",
120+
SnapmirrorPolicyZAPITypeAsync: "async_mirror",
121+
SnapmirrorPolicyRESTTypeSync: "sync",
122+
SnapmirrorPolicyRESTTypeAsync: "async",
123+
}
124+
for policyType, expectedValue := range expected {
125+
assert.Equal(t, expectedValue, string(policyType))
126+
}
127+
}},
128+
{"SliceTypes", func(t *testing.T) {
129+
// Test all slice type definitions
130+
volumes := Volumes{&Volume{Name: "vol1"}}
131+
luns := Luns{Lun{Name: "lun1"}}
132+
snapshots := Snapshots{Snapshot{Name: "snap1"}}
133+
qtrees := Qtrees{&Qtree{Name: "qtree1"}}
134+
quotas := QuotaEntries{&QuotaEntry{Target: "quota1"}}
135+
namespaces := NVMeNamespaces{&NVMeNamespace{Name: "ns1"}}
136+
volumeNames := VolumeNameList{"vol1", "vol2"}
137+
qtreeNames := QtreeNameList{"qtree1", "qtree2"}
138+
139+
assert.Len(t, volumes, 1)
140+
assert.Len(t, luns, 1)
141+
assert.Len(t, snapshots, 1)
142+
assert.Len(t, qtrees, 1)
143+
assert.Len(t, quotas, 1)
144+
assert.Len(t, namespaces, 1)
145+
assert.Len(t, volumeNames, 2)
146+
assert.Len(t, qtreeNames, 2)
147+
}},
148+
}
149+
150+
for _, tt := range tests {
151+
t.Run(tt.name, tt.testFunc)
152+
}
153+
}
154+
155+
// TestStructValidation validates business logic and edge cases for all structs
156+
func TestStructValidation(t *testing.T) {
157+
tests := []struct {
158+
name string
159+
testFunc func(t *testing.T)
160+
}{
161+
{"VolumeLogic", func(t *testing.T) {
162+
encryptTrue, snapshotDirFalse := true, false
163+
vol := Volume{
164+
Aggregates: []string{"aggr1", "aggr2"},
165+
Encrypt: &encryptTrue,
166+
SnapshotDir: &snapshotDirFalse,
167+
SnapshotReserve: 5,
168+
}
169+
require.NotNil(t, vol.Encrypt)
170+
assert.True(t, *vol.Encrypt)
171+
require.NotNil(t, vol.SnapshotDir)
172+
assert.False(t, *vol.SnapshotDir)
173+
assert.Len(t, vol.Aggregates, 2)
174+
assert.True(t, vol.SnapshotReserve >= 0 && vol.SnapshotReserve <= 100)
175+
}},
176+
{"SnapmirrorLogic", func(t *testing.T) {
177+
endTime := time.Now()
178+
sm := Snapmirror{
179+
State: SnapmirrorStateSnapmirrored,
180+
RelationshipStatus: SnapmirrorStatusIdle,
181+
IsHealthy: true,
182+
UnhealthyReason: "",
183+
EndTransferTime: &endTime,
184+
}
185+
assert.False(t, sm.State.IsUninitialized())
186+
assert.True(t, sm.RelationshipStatus.IsIdle())
187+
assert.Empty(t, sm.UnhealthyReason)
188+
require.NotNil(t, sm.EndTransferTime)
189+
}},
190+
{"LunMappingLogic", func(t *testing.T) {
191+
spaceReserved, spaceAllocated := true, false
192+
lun := Lun{
193+
LunMaps: []LunMap{{IgroupName: "ig1", LunID: 0}, {IgroupName: "ig2", LunID: 1}},
194+
Mapped: true,
195+
SpaceReserved: &spaceReserved,
196+
SpaceAllocated: &spaceAllocated,
197+
}
198+
assert.Equal(t, len(lun.LunMaps) > 0, lun.Mapped)
199+
lunIDs := make(map[int]bool)
200+
for _, lunMap := range lun.LunMaps {
201+
assert.False(t, lunIDs[lunMap.LunID], "LUN IDs should be unique")
202+
lunIDs[lunMap.LunID] = true
203+
assert.NotEmpty(t, lunMap.IgroupName)
204+
}
205+
require.NotNil(t, lun.SpaceReserved)
206+
assert.True(t, *lun.SpaceReserved)
207+
}},
208+
{"QuotaLogic", func(t *testing.T) {
209+
quota := QuotaEntry{Target: "/vol/test/qtree1", DiskLimitBytes: 1073741824}
210+
assert.NotEmpty(t, quota.Target)
211+
assert.True(t, quota.DiskLimitBytes > 0)
212+
assert.True(t, strings.HasPrefix(quota.Target, "/"))
213+
}},
214+
{"EdgeCases", func(t *testing.T) {
215+
// Test empty structs and nil pointers
216+
var volume Volume
217+
var lun Lun
218+
assert.Empty(t, volume.Name)
219+
assert.Nil(t, volume.Encrypt)
220+
assert.Empty(t, lun.Name)
221+
222+
// Test pointer field behavior
223+
encrypt := true
224+
volume.Encrypt = &encrypt
225+
require.NotNil(t, volume.Encrypt)
226+
assert.True(t, *volume.Encrypt)
227+
228+
// Test slice boundaries
229+
lun.LunMaps = []LunMap{}
230+
assert.NotNil(t, lun.LunMaps)
231+
assert.Len(t, lun.LunMaps, 0)
232+
}},
233+
{"TypeCompatibility", func(t *testing.T) {
234+
// Test reflection and string conversion
235+
volume := Volume{Name: "test"}
236+
volumeType := reflect.TypeOf(volume)
237+
assert.Equal(t, "Volume", volumeType.Name())
238+
assert.Equal(t, reflect.Struct, volumeType.Kind())
239+
240+
nameField, exists := volumeType.FieldByName("Name")
241+
assert.True(t, exists)
242+
assert.Equal(t, "string", nameField.Type.String())
243+
244+
// Test enum string conversion
245+
state := SnapmirrorStateUninitialized
246+
assert.Equal(t, "uninitialized", string(state))
247+
customState := SnapmirrorState("custom_state")
248+
assert.Equal(t, "custom_state", string(customState))
249+
}},
250+
}
251+
252+
for _, tt := range tests {
253+
t.Run(tt.name, tt.testFunc)
254+
}
255+
}

0 commit comments

Comments
 (0)