@@ -33,6 +33,7 @@ import (
33
33
"golang.org/x/net/context"
34
34
"google.golang.org/grpc/codes"
35
35
"google.golang.org/grpc/status"
36
+ "google.golang.org/protobuf/types/known/timestamppb"
36
37
mount "k8s.io/mount-utils"
37
38
)
38
39
@@ -827,3 +828,184 @@ func TestCopyVolume(t *testing.T) {
827
828
})
828
829
}
829
830
}
831
+
832
+ func TestCreateSnapshot (t * testing.T ) {
833
+ cases := []struct {
834
+ desc string
835
+ req * csi.CreateSnapshotRequest
836
+ expResp * csi.CreateSnapshotResponse
837
+ expectErr bool
838
+ prepare func () error
839
+ cleanup func () error
840
+ }{
841
+ {
842
+ desc : "create snapshot with valid request" ,
843
+ req : & csi.CreateSnapshotRequest {
844
+ SourceVolumeId : "nfs-server.default.svc.cluster.local#share#subdir#src-pv-name" ,
845
+ Name : "snapshot-name" ,
846
+ },
847
+ expResp : & csi.CreateSnapshotResponse {
848
+ Snapshot : & csi.Snapshot {
849
+ SnapshotId : "nfs-server.default.svc.cluster.local#share#snapshot-name#snapshot-name#src-pv-name" ,
850
+ SourceVolumeId : "nfs-server.default.svc.cluster.local#share#subdir#src-pv-name" ,
851
+ ReadyToUse : true ,
852
+ SizeBytes : 1 , // doesn't match exact size, just denotes non-zero size expected
853
+ CreationTime : timestamppb .Now (), // doesn't match exact timestamp, just denotes non-zero ts expected
854
+ },
855
+ },
856
+ prepare : func () error { return os .MkdirAll ("/tmp/src-pv-name/subdir" , 0777 ) },
857
+ cleanup : func () error { return os .RemoveAll ("/tmp/src-pv-name" ) },
858
+ },
859
+ {
860
+ desc : "create snapshot from nonexisting volume" ,
861
+ req : & csi.CreateSnapshotRequest {
862
+ SourceVolumeId : "nfs-server.default.svc.cluster.local#share#subdir#src-pv-name" ,
863
+ Name : "snapshot-name" ,
864
+ },
865
+ expectErr : true ,
866
+ },
867
+ }
868
+ for _ , test := range cases {
869
+ t .Run (test .desc , func (t * testing.T ) {
870
+ if test .prepare != nil {
871
+ if err := test .prepare (); err != nil {
872
+ t .Errorf (`[test: %s] prepare failed: "%v"` , test .desc , err )
873
+ }
874
+ }
875
+ cs := initTestController (t )
876
+ resp , err := cs .CreateSnapshot (context .TODO (), test .req )
877
+ if (err == nil ) == test .expectErr {
878
+ t .Errorf (`[test: %s] Error expectation mismatch, expected error: "%v", received: %q` , test .desc , test .expectErr , err )
879
+ }
880
+ if err := matchCreateSnapshotResponse (test .expResp , resp ); err != nil {
881
+ t .Errorf ("[test: %s] failed %q: got resp %+v, expected %+v" , test .desc , err , resp , test .expResp )
882
+ }
883
+ if test .cleanup != nil {
884
+ if err := test .cleanup (); err != nil {
885
+ t .Errorf (`[test: %s] cleanup failed: "%v"` , test .desc , err )
886
+ }
887
+ }
888
+ })
889
+ }
890
+ }
891
+
892
+ func TestDeleteSnapshot (t * testing.T ) {
893
+ cases := []struct {
894
+ desc string
895
+ req * csi.DeleteSnapshotRequest
896
+ expResp * csi.DeleteSnapshotResponse
897
+ expectErr bool
898
+ prepare func () error
899
+ cleanup func () error
900
+ }{
901
+ {
902
+ desc : "delete valid snapshot" ,
903
+ req : & csi.DeleteSnapshotRequest {
904
+ SnapshotId : "nfs-server.default.svc.cluster.local#share#snapshot-name#snapshot-name#src-pv-name" ,
905
+ },
906
+ expResp : & csi.DeleteSnapshotResponse {},
907
+ prepare : func () error {
908
+ if err := os .MkdirAll ("/tmp/snapshot-name/snapshot-name/" , 0777 ); err != nil {
909
+ return err
910
+ }
911
+ f , err := os .OpenFile ("/tmp/snapshot-name/snapshot-name/src-pv-name.tar.gz" , os .O_CREATE , 0777 )
912
+ if err != nil {
913
+ return err
914
+ }
915
+ return f .Close ()
916
+ },
917
+ cleanup : func () error { return os .RemoveAll ("/tmp/snapshot-name" ) },
918
+ },
919
+ {
920
+ desc : "delete nonexisting snapshot" ,
921
+ req : & csi.DeleteSnapshotRequest {
922
+ SnapshotId : "nfs-server.default.svc.cluster.local#share#snapshot-name#snapshot-name#src-pv-name" ,
923
+ },
924
+ expResp : & csi.DeleteSnapshotResponse {},
925
+ },
926
+ {
927
+ desc : "delete snapshot with improper id" ,
928
+ req : & csi.DeleteSnapshotRequest {
929
+ SnapshotId : "incorrect-snap-id" ,
930
+ },
931
+ expResp : & csi.DeleteSnapshotResponse {},
932
+ },
933
+ {
934
+ desc : "delete valid snapshot with mount options" ,
935
+ req : & csi.DeleteSnapshotRequest {
936
+ SnapshotId : "nfs-server.default.svc.cluster.local#share#snapshot-name#snapshot-name#src-pv-name" ,
937
+ Secrets : map [string ]string {"mountoptions" : "nfsvers=4.1" },
938
+ },
939
+ expResp : & csi.DeleteSnapshotResponse {},
940
+ prepare : func () error {
941
+ if err := os .MkdirAll ("/tmp/snapshot-name/snapshot-name/" , 0777 ); err != nil {
942
+ return err
943
+ }
944
+ f , err := os .OpenFile ("/tmp/snapshot-name/snapshot-name/src-pv-name.tar.gz" , os .O_CREATE , 0777 )
945
+ if err != nil {
946
+ return err
947
+ }
948
+ return f .Close ()
949
+ },
950
+ cleanup : func () error { return os .RemoveAll ("/tmp/snapshot-name" ) },
951
+ },
952
+ }
953
+ for _ , test := range cases {
954
+ t .Run (test .desc , func (t * testing.T ) {
955
+ if test .prepare != nil {
956
+ if err := test .prepare (); err != nil {
957
+ t .Errorf (`[test: %s] prepare failed: "%v"` , test .desc , err )
958
+ }
959
+ }
960
+ cs := initTestController (t )
961
+ resp , err := cs .DeleteSnapshot (context .TODO (), test .req )
962
+ if (err == nil ) == test .expectErr {
963
+ t .Errorf (`[test: %s] Error expectation mismatch, expected error: "%v", received: %q` , test .desc , test .expectErr , err )
964
+ }
965
+ if ! reflect .DeepEqual (test .expResp , resp ) {
966
+ t .Errorf ("[test: %s] got resp %+v, expected %+v" , test .desc , resp , test .expResp )
967
+ }
968
+ if test .cleanup != nil {
969
+ if err := test .cleanup (); err != nil {
970
+ t .Errorf (`[test: %s] cleanup failed: "%v"` , test .desc , err )
971
+ }
972
+ }
973
+ })
974
+ }
975
+ }
976
+
977
+ func matchCreateSnapshotResponse (e , r * csi.CreateSnapshotResponse ) error {
978
+ if e == nil && r == nil {
979
+ return nil
980
+ }
981
+ if e == nil || e .Snapshot == nil {
982
+ return fmt .Errorf ("expected nil response" )
983
+ }
984
+ if r == nil || r .Snapshot == nil {
985
+ return fmt .Errorf ("unexpected nil response" )
986
+ }
987
+ es , rs := e .Snapshot , r .Snapshot
988
+
989
+ var errs []string
990
+ // comparing ts and size just for presence, not the exact value
991
+ if es .CreationTime .IsValid () != rs .CreationTime .IsValid () {
992
+ errs = append (errs , "CreationTime" )
993
+ }
994
+ if (es .SizeBytes == 0 ) != (rs .SizeBytes == 0 ) {
995
+ errs = append (errs , "SizeBytes" )
996
+ }
997
+ // comparing remaining fields for exact match
998
+ if es .ReadyToUse != rs .ReadyToUse {
999
+ errs = append (errs , "ReadyToUse" )
1000
+ }
1001
+ if es .SnapshotId != rs .SnapshotId {
1002
+ errs = append (errs , "SnapshotId" )
1003
+ }
1004
+ if es .SourceVolumeId != rs .SourceVolumeId {
1005
+ errs = append (errs , "SourceVolumeId" )
1006
+ }
1007
+ if len (errs ) == 0 {
1008
+ return nil
1009
+ }
1010
+ return fmt .Errorf ("mismatch CreateSnapshotResponse in fields: %v" , strings .Join (errs , ", " ))
1011
+ }
0 commit comments