Skip to content

Commit e538a03

Browse files
Praveenrajmaniwlan0
authored andcommitted
Add tests for Publish and Unpublish volumes
1 parent eaf5bb6 commit e538a03

File tree

3 files changed

+264
-50
lines changed

3 files changed

+264
-50
lines changed

pkg/node/fake_node_server.go

Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
// This file is part of MinIO Direct CSI
2+
// Copyright (c) 2021 MinIO, Inc.
3+
//
4+
// This program is free software: you can redistribute it and/or modify
5+
// it under the terms of the GNU Affero General Public License as published by
6+
// the Free Software Foundation, either version 3 of the License, or
7+
// (at your option) any later version.
8+
//
9+
// This program is distributed in the hope that it will be useful,
10+
// but WITHOUT ANY WARRANTY; without even the implied warranty of
11+
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12+
// GNU Affero General Public License for more details.
13+
//
14+
// You should have received a copy of the GNU Affero General Public License
15+
// along with this program. If not, see <http://www.gnu.org/licenses/>.
16+
17+
package node
18+
19+
import (
20+
"context"
21+
22+
fakedirect "github.com/minio/direct-csi/pkg/clientset/fake"
23+
)
24+
25+
const (
26+
testNodeName = "test-node"
27+
)
28+
29+
type fakeVolumeMounter struct {
30+
mountArgs struct {
31+
source string
32+
destination string
33+
volumeID string
34+
size int64
35+
readOnly bool
36+
}
37+
unmountArgs struct {
38+
target string
39+
}
40+
}
41+
42+
func (f *fakeVolumeMounter) MountVolume(_ context.Context, src, dest, vID string, size int64, readOnly bool) error {
43+
f.mountArgs.source = src
44+
f.mountArgs.destination = dest
45+
f.mountArgs.volumeID = vID
46+
f.mountArgs.size = size
47+
f.mountArgs.readOnly = readOnly
48+
return nil
49+
}
50+
51+
func (f *fakeVolumeMounter) UnmountVolume(targetPath string) error {
52+
f.unmountArgs.target = targetPath
53+
return nil
54+
}
55+
56+
func createFakeNodeServer() *NodeServer {
57+
return &NodeServer{
58+
NodeID: testNodeName,
59+
Identity: "test-identity",
60+
Rack: "test-rack",
61+
Zone: "test-zone",
62+
Region: "test-region",
63+
directcsiClient: fakedirect.NewSimpleClientset(),
64+
mounter: &fakeVolumeMounter{},
65+
}
66+
}

pkg/node/publish_unpublish_test.go

Lines changed: 187 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,187 @@
1+
// This file is part of MinIO Direct CSI
2+
// Copyright (c) 2021 MinIO, Inc.
3+
//
4+
// This program is free software: you can redistribute it and/or modify
5+
// it under the terms of the GNU Affero General Public License as published by
6+
// the Free Software Foundation, either version 3 of the License, or
7+
// (at your option) any later version.
8+
//
9+
// This program is distributed in the hope that it will be useful,
10+
// but WITHOUT ANY WARRANTY; without even the implied warranty of
11+
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12+
// GNU Affero General Public License for more details.
13+
//
14+
// You should have received a copy of the GNU Affero General Public License
15+
// along with this program. If not, see <http://www.gnu.org/licenses/>.
16+
17+
package node
18+
19+
import (
20+
"context"
21+
"io/ioutil"
22+
"os"
23+
"strings"
24+
"testing"
25+
26+
"github.com/container-storage-interface/spec/lib/go/csi"
27+
"github.com/minio/direct-csi/pkg/utils"
28+
29+
directcsi "github.com/minio/direct-csi/pkg/apis/direct.csi.min.io/v1beta1"
30+
fakedirect "github.com/minio/direct-csi/pkg/clientset/fake"
31+
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
32+
)
33+
34+
func TestPublishUnpublishVolume(t *testing.T) {
35+
testVolumeName50MB := "test_volume_50MB"
36+
37+
createTestDir := func(prefix string) (string, error) {
38+
tDir, err := ioutil.TempDir("", prefix)
39+
if err != nil {
40+
return "", err
41+
}
42+
return tDir, nil
43+
}
44+
45+
testStagingPath, tErr := createTestDir("test_staging_")
46+
if tErr != nil {
47+
t.Fatalf("Could not create test dirs: %v", tErr)
48+
}
49+
defer os.RemoveAll(testStagingPath)
50+
51+
testContainerPath, tErr := createTestDir("test_container_")
52+
if tErr != nil {
53+
t.Fatalf("Could not create test dirs: %v", tErr)
54+
}
55+
defer os.RemoveAll(testContainerPath)
56+
57+
testVol := &directcsi.DirectCSIVolume{
58+
TypeMeta: utils.DirectCSIVolumeTypeMeta(strings.Join([]string{directcsi.Group, directcsi.Version}, "/")),
59+
ObjectMeta: metav1.ObjectMeta{
60+
Name: testVolumeName50MB,
61+
Finalizers: []string{
62+
string(directcsi.DirectCSIVolumeFinalizerPurgeProtection),
63+
},
64+
},
65+
Status: directcsi.DirectCSIVolumeStatus{
66+
NodeName: testNodeName,
67+
StagingPath: testStagingPath,
68+
TotalCapacity: mb20,
69+
Conditions: []metav1.Condition{
70+
{
71+
Type: string(directcsi.DirectCSIVolumeConditionStaged),
72+
Status: metav1.ConditionTrue,
73+
Message: "",
74+
Reason: string(directcsi.DirectCSIVolumeReasonInUse),
75+
LastTransitionTime: metav1.Now(),
76+
},
77+
{
78+
Type: string(directcsi.DirectCSIVolumeConditionPublished),
79+
Status: metav1.ConditionFalse,
80+
Message: "",
81+
Reason: string(directcsi.DirectCSIVolumeReasonNotInUse),
82+
LastTransitionTime: metav1.Now(),
83+
},
84+
{
85+
Type: string(directcsi.DirectCSIVolumeConditionReady),
86+
Status: metav1.ConditionTrue,
87+
Message: "",
88+
Reason: string(directcsi.DirectCSIVolumeReasonReady),
89+
LastTransitionTime: metav1.Now(),
90+
},
91+
},
92+
},
93+
}
94+
95+
publishVolumeRequest := csi.NodePublishVolumeRequest{
96+
VolumeId: testVolumeName50MB,
97+
StagingTargetPath: testStagingPath,
98+
TargetPath: testContainerPath,
99+
VolumeCapability: &csi.VolumeCapability{
100+
AccessType: &csi.VolumeCapability_Mount{
101+
Mount: &csi.VolumeCapability_MountVolume{
102+
FsType: "xfs",
103+
},
104+
},
105+
AccessMode: &csi.VolumeCapability_AccessMode{
106+
Mode: csi.VolumeCapability_AccessMode_SINGLE_NODE_WRITER,
107+
},
108+
},
109+
Readonly: false,
110+
}
111+
112+
unpublishVolumeRequest := csi.NodeUnpublishVolumeRequest{
113+
VolumeId: testVolumeName50MB,
114+
TargetPath: testContainerPath,
115+
}
116+
117+
ctx := context.TODO()
118+
ns := createFakeNodeServer()
119+
ns.directcsiClient = fakedirect.NewSimpleClientset(testVol)
120+
directCSIClient := ns.directcsiClient.DirectV1beta1()
121+
122+
// Publish volume test
123+
if _, err := ns.NodePublishVolume(ctx, &publishVolumeRequest); err != nil {
124+
t.Fatalf("[%s] PublishVolume failed. Error: %v", publishVolumeRequest.VolumeId, err)
125+
}
126+
127+
volObj, gErr := directCSIClient.DirectCSIVolumes().Get(ctx, publishVolumeRequest.GetVolumeId(), metav1.GetOptions{
128+
TypeMeta: utils.DirectCSIVolumeTypeMeta(strings.Join([]string{directcsi.Group, directcsi.Version}, "/")),
129+
})
130+
if gErr != nil {
131+
t.Fatalf("Volume (%s) not found. Error: %v", publishVolumeRequest.GetVolumeId(), gErr)
132+
}
133+
134+
// Check if mount args were set correctly
135+
if ns.mounter.(*fakeVolumeMounter).mountArgs.source != testStagingPath {
136+
t.Errorf("Wrong source argument passed for mounting. Expected: %v, Got: %v", testStagingPath, ns.mounter.(*fakeVolumeMounter).mountArgs.source)
137+
}
138+
if ns.mounter.(*fakeVolumeMounter).mountArgs.destination != testContainerPath {
139+
t.Errorf("Wrong destination argument passed for mounting. Expected: %v, Got: %v", testContainerPath, ns.mounter.(*fakeVolumeMounter).mountArgs.destination)
140+
}
141+
if ns.mounter.(*fakeVolumeMounter).mountArgs.volumeID != publishVolumeRequest.GetVolumeId() {
142+
t.Errorf("Wrong volumeID argument passed for mounting. Expected: %v, Got: %v", publishVolumeRequest.GetVolumeId(), ns.mounter.(*fakeVolumeMounter).mountArgs.volumeID)
143+
}
144+
if ns.mounter.(*fakeVolumeMounter).mountArgs.size != int64(0) {
145+
t.Errorf("Wrong size argument passed for mounting. Expected: 0, Got: %v", ns.mounter.(*fakeVolumeMounter).mountArgs.size)
146+
}
147+
if ns.mounter.(*fakeVolumeMounter).mountArgs.readOnly != publishVolumeRequest.GetReadonly() {
148+
t.Errorf("Wrong readOnly argument passed for mounting. Expected: %v, Got: %v", publishVolumeRequest.GetReadonly(), ns.mounter.(*fakeVolumeMounter).mountArgs.readOnly)
149+
}
150+
151+
// Check if status fields were set correctly
152+
if volObj.Status.ContainerPath != testContainerPath {
153+
t.Errorf("Wrong ContainerPath set in the volume object. Expected %v, Got: %v", testContainerPath, volObj.Status.ContainerPath)
154+
}
155+
156+
// Check if conditions were toggled correctly
157+
if !utils.IsCondition(volObj.Status.Conditions, string(directcsi.DirectCSIVolumeConditionPublished), metav1.ConditionTrue, string(directcsi.DirectCSIVolumeReasonInUse), "") {
158+
t.Errorf("unexpected status.conditions after publishing = %v", volObj.Status.Conditions)
159+
}
160+
161+
// Unpublish volume test
162+
if _, err := ns.NodeUnpublishVolume(ctx, &unpublishVolumeRequest); err != nil {
163+
t.Fatalf("[%s] PublishVolume failed. Error: %v", unpublishVolumeRequest.VolumeId, err)
164+
}
165+
166+
volObj, gErr = directCSIClient.DirectCSIVolumes().Get(ctx, unpublishVolumeRequest.GetVolumeId(), metav1.GetOptions{
167+
TypeMeta: utils.DirectCSIVolumeTypeMeta(strings.Join([]string{directcsi.Group, directcsi.Version}, "/")),
168+
})
169+
if gErr != nil {
170+
t.Fatalf("Volume (%s) not found. Error: %v", unpublishVolumeRequest.GetVolumeId(), gErr)
171+
}
172+
173+
// Check if unmount args were set correctly
174+
if ns.mounter.(*fakeVolumeMounter).unmountArgs.target != unpublishVolumeRequest.GetTargetPath() {
175+
t.Errorf("Wrong target argument passed for unmounting. Expected: %v, Got: %v", unpublishVolumeRequest.GetTargetPath(), ns.mounter.(*fakeVolumeMounter).unmountArgs.target)
176+
}
177+
178+
// Check if the status fields were unset
179+
if volObj.Status.ContainerPath != "" {
180+
t.Errorf("StagingPath was not set to empty. Got: %v", volObj.Status.ContainerPath)
181+
}
182+
183+
// Check if the conditions were toggled correctly
184+
if !utils.IsCondition(volObj.Status.Conditions, string(directcsi.DirectCSIVolumeConditionPublished), metav1.ConditionFalse, string(directcsi.DirectCSIVolumeReasonNotInUse), "") {
185+
t.Errorf("unexpected status.conditions after unstaging = %v", volObj.Status.Conditions)
186+
}
187+
}

pkg/node/stage_unstage_test.go

Lines changed: 11 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -24,10 +24,10 @@ import (
2424
"strings"
2525
"testing"
2626

27+
"github.com/container-storage-interface/spec/lib/go/csi"
2728
"github.com/minio/direct-csi/pkg/utils"
2829
"k8s.io/apimachinery/pkg/runtime"
2930

30-
"github.com/container-storage-interface/spec/lib/go/csi"
3131
directcsi "github.com/minio/direct-csi/pkg/apis/direct.csi.min.io/v1beta1"
3232
fakedirect "github.com/minio/direct-csi/pkg/clientset/fake"
3333
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
@@ -40,49 +40,8 @@ const (
4040
mb50 = 50 * MB
4141
mb100 = 100 * MB
4242
mb20 = 20 * MB
43-
44-
testNodeName = "test-node"
4543
)
4644

47-
type fakeVolumeMounter struct {
48-
mountArgs struct {
49-
source string
50-
destination string
51-
volumeID string
52-
size int64
53-
readOnly bool
54-
}
55-
unmountArgs struct {
56-
target string
57-
}
58-
}
59-
60-
func (f *fakeVolumeMounter) MountVolume(_ context.Context, src, dest, vID string, size int64, readOnly bool) error {
61-
f.mountArgs.source = src
62-
f.mountArgs.destination = dest
63-
f.mountArgs.volumeID = vID
64-
f.mountArgs.size = size
65-
f.mountArgs.readOnly = readOnly
66-
return nil
67-
}
68-
69-
func (f *fakeVolumeMounter) UnmountVolume(targetPath string) error {
70-
f.unmountArgs.target = targetPath
71-
return nil
72-
}
73-
74-
func createFakeNodeServer() *NodeServer {
75-
return &NodeServer{
76-
NodeID: testNodeName,
77-
Identity: "test-identity",
78-
Rack: "test-rack",
79-
Zone: "test-zone",
80-
Region: "test-region",
81-
directcsiClient: fakedirect.NewSimpleClientset(),
82-
mounter: &fakeVolumeMounter{},
83-
}
84-
}
85-
8645
func TestStageUnstageVolume(t *testing.T) {
8746
testDriveName := "test_drive"
8847
testVolumeName50MB := "test_volume_50MB"
@@ -177,6 +136,7 @@ func TestStageUnstageVolume(t *testing.T) {
177136
directCSIClient := ns.directcsiClient.DirectV1beta1()
178137
hostPath := filepath.Join(testMountPointDir, testVolumeName50MB)
179138

139+
// Stage Volume test
180140
if _, err := ns.NodeStageVolume(ctx, &stageVolumeRequest); err != nil {
181141
t.Fatalf("[%s] StageVolume failed. Error: %v", stageVolumeRequest.VolumeId, err)
182142
}
@@ -188,61 +148,62 @@ func TestStageUnstageVolume(t *testing.T) {
188148
t.Fatalf("Volume (%s) not found. Error: %v", stageVolumeRequest.GetVolumeId(), gErr)
189149
}
190150

151+
// Check if mount arguments were passed correctly
191152
if ns.mounter.(*fakeVolumeMounter).mountArgs.source != hostPath {
192153
t.Errorf("Wrong source argument passed for mounting. Expected: %v, Got: %v", filepath.Join(testMountPointDir, testVolumeName50MB), ns.mounter.(*fakeVolumeMounter).mountArgs.source)
193154
}
194-
195155
if ns.mounter.(*fakeVolumeMounter).mountArgs.destination != stageVolumeRequest.GetStagingTargetPath() {
196156
t.Errorf("Wrong destination argument passed for mounting. Expected: %v, Got: %v", stageVolumeRequest.GetStagingTargetPath(), ns.mounter.(*fakeVolumeMounter).mountArgs.destination)
197157
}
198-
199158
if ns.mounter.(*fakeVolumeMounter).mountArgs.volumeID != stageVolumeRequest.GetVolumeId() {
200159
t.Errorf("Wrong volumeID argument passed for mounting. Expected: %v, Got: %v", stageVolumeRequest.GetVolumeId(), ns.mounter.(*fakeVolumeMounter).mountArgs.volumeID)
201160
}
202-
203161
if ns.mounter.(*fakeVolumeMounter).mountArgs.size != volObj.Status.TotalCapacity {
204162
t.Errorf("Wrong size argument passed for mounting. Expected: %v, Got: %v", volObj.Status.TotalCapacity, ns.mounter.(*fakeVolumeMounter).mountArgs.size)
205163
}
206-
207164
if ns.mounter.(*fakeVolumeMounter).mountArgs.readOnly {
208165
t.Errorf("Wrong readOnly argument passed for mounting. Expected: False, Got: %v", ns.mounter.(*fakeVolumeMounter).mountArgs.readOnly)
209166
}
210167

168+
// Check if status fields were set correctly
211169
if volObj.Status.HostPath != hostPath {
212170
t.Errorf("Wrong HostPath set in the volume object. Expected %v, Got: %v", hostPath, volObj.Status.HostPath)
213171
}
214-
215172
if volObj.Status.StagingPath != stageVolumeRequest.GetStagingTargetPath() {
216173
t.Errorf("Wrong StagingPath set in the volume object. Expected %v, Got: %v", stageVolumeRequest.GetStagingTargetPath(), volObj.Status.StagingPath)
217174
}
218175

176+
// Check if conditions were toggled correctly
219177
if !utils.IsCondition(volObj.Status.Conditions, string(directcsi.DirectCSIVolumeConditionStaged), metav1.ConditionTrue, string(directcsi.DirectCSIVolumeReasonInUse), "") {
220178
t.Errorf("unexpected status.conditions after staging = %v", volObj.Status.Conditions)
221179
}
222180

181+
// Unstage Volume test
223182
if _, err := ns.NodeUnstageVolume(ctx, &unstageVolumeRequest); err != nil {
224183
t.Fatalf("[%s] UnstageVolume failed. Error: %v", unstageVolumeRequest.VolumeId, err)
225184
}
226185

227-
volObj, gErr = directCSIClient.DirectCSIVolumes().Get(ctx, stageVolumeRequest.GetVolumeId(), metav1.GetOptions{
186+
volObj, gErr = directCSIClient.DirectCSIVolumes().Get(ctx, unstageVolumeRequest.GetVolumeId(), metav1.GetOptions{
228187
TypeMeta: utils.DirectCSIVolumeTypeMeta(strings.Join([]string{directcsi.Group, directcsi.Version}, "/")),
229188
})
230189
if gErr != nil {
231-
t.Fatalf("Volume (%s) not found. Error: %v", stageVolumeRequest.GetVolumeId(), gErr)
190+
t.Fatalf("Volume (%s) not found. Error: %v", unstageVolumeRequest.GetVolumeId(), gErr)
232191
}
233192

193+
// Check if unmount arguments were set correctly
234194
if ns.mounter.(*fakeVolumeMounter).unmountArgs.target != unstageVolumeRequest.GetStagingTargetPath() {
235195
t.Errorf("Wrong target argument passed for unmounting. Expected: %v, Got: %v", unstageVolumeRequest.GetStagingTargetPath(), ns.mounter.(*fakeVolumeMounter).unmountArgs.target)
236196
}
237197

198+
// Check if status fields were set correctly
238199
if volObj.Status.HostPath != "" {
239200
t.Errorf("Hostpath was not set to empty. Got: %v", volObj.Status.HostPath)
240201
}
241-
242202
if volObj.Status.StagingPath != "" {
243203
t.Errorf("StagingPath was not set to empty. Got: %v", volObj.Status.StagingPath)
244204
}
245205

206+
// Check if conditions were toggled correctly
246207
if !utils.IsCondition(volObj.Status.Conditions, string(directcsi.DirectCSIVolumeConditionStaged), metav1.ConditionFalse, string(directcsi.DirectCSIVolumeReasonNotInUse), "") {
247208
t.Errorf("unexpected status.conditions after unstaging = %v", volObj.Status.Conditions)
248209
}

0 commit comments

Comments
 (0)