@@ -33,6 +33,7 @@ import (
3333 "golang.org/x/net/context"
3434 "google.golang.org/grpc/codes"
3535 "google.golang.org/grpc/status"
36+ "google.golang.org/protobuf/types/known/timestamppb"
3637 mount "k8s.io/mount-utils"
3738)
3839
@@ -827,3 +828,184 @@ func TestCopyVolume(t *testing.T) {
827828 })
828829 }
829830}
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