2023-04-10 15:36:59 +00:00
// Copyright (c) HashiCorp, Inc.
// SPDX-License-Identifier: MPL-2.0
2019-10-22 13:20:26 +00:00
package csi
import (
"context"
2020-01-24 16:20:23 +00:00
"errors"
2019-10-22 13:20:26 +00:00
"fmt"
2022-02-15 21:57:29 +00:00
"path/filepath"
2019-10-22 13:20:26 +00:00
"testing"
2022-03-23 14:39:28 +00:00
"time"
2019-10-22 13:20:26 +00:00
csipbv1 "github.com/container-storage-interface/spec/lib/go/csi"
"github.com/golang/protobuf/ptypes/wrappers"
2022-03-15 12:42:43 +00:00
"github.com/hashicorp/nomad/ci"
2020-04-30 21:12:32 +00:00
"github.com/hashicorp/nomad/nomad/structs"
2019-10-22 13:20:26 +00:00
fake "github.com/hashicorp/nomad/plugins/csi/testing"
"github.com/stretchr/testify/require"
2022-02-15 21:57:29 +00:00
"google.golang.org/grpc"
2020-05-18 12:23:17 +00:00
"google.golang.org/grpc/codes"
"google.golang.org/grpc/status"
2022-03-23 14:39:28 +00:00
"google.golang.org/protobuf/types/known/timestamppb"
2019-10-22 13:20:26 +00:00
)
2022-02-15 21:57:29 +00:00
func newTestClient ( t * testing . T ) ( * fake . IdentityClient , * fake . ControllerClient , * fake . NodeClient , CSIPlugin ) {
2019-12-18 12:18:07 +00:00
ic := fake . NewIdentityClient ( )
cc := fake . NewControllerClient ( )
nc := fake . NewNodeClient ( )
2022-02-15 21:57:29 +00:00
// we've set this as non-blocking so it won't connect to the
// socket unless a RPC is invoked
conn , err := grpc . DialContext ( context . Background ( ) ,
filepath . Join ( t . TempDir ( ) , "csi.sock" ) , grpc . WithInsecure ( ) )
if err != nil {
t . Errorf ( "failed: %v" , err )
}
2019-10-22 13:20:26 +00:00
client := & client {
2022-02-15 21:57:29 +00:00
conn : conn ,
2019-12-16 12:31:09 +00:00
identityClient : ic ,
controllerClient : cc ,
2019-12-18 12:18:07 +00:00
nodeClient : nc ,
2019-10-22 13:20:26 +00:00
}
2019-12-18 12:18:07 +00:00
return ic , cc , nc , client
2019-10-22 13:20:26 +00:00
}
func TestClient_RPC_PluginProbe ( t * testing . T ) {
2022-03-15 12:42:43 +00:00
ci . Parallel ( t )
2019-10-22 13:20:26 +00:00
cases := [ ] struct {
Name string
ResponseErr error
ProbeResponse * csipbv1 . ProbeResponse
ExpectedResponse bool
ExpectedErr error
} {
{
Name : "handles underlying grpc errors" ,
ResponseErr : fmt . Errorf ( "some grpc error" ) ,
ExpectedErr : fmt . Errorf ( "some grpc error" ) ,
} ,
{
Name : "returns false for ready when the provider returns false" ,
ProbeResponse : & csipbv1 . ProbeResponse {
Ready : & wrappers . BoolValue { Value : false } ,
} ,
ExpectedResponse : false ,
} ,
{
Name : "returns true for ready when the provider returns true" ,
ProbeResponse : & csipbv1 . ProbeResponse {
Ready : & wrappers . BoolValue { Value : true } ,
} ,
ExpectedResponse : true ,
} ,
{
/ * When a SP does not return a ready value , a CO MAY treat this as ready .
We do so because example plugins rely on this behaviour . We may
re - evaluate this decision in the future . * /
Name : "returns true for ready when the provider returns a nil wrapper" ,
ProbeResponse : & csipbv1 . ProbeResponse {
Ready : nil ,
} ,
ExpectedResponse : true ,
} ,
}
2020-05-18 12:23:17 +00:00
for _ , tc := range cases {
t . Run ( tc . Name , func ( t * testing . T ) {
2022-02-15 21:57:29 +00:00
ic , _ , _ , client := newTestClient ( t )
2019-10-22 13:20:26 +00:00
defer client . Close ( )
2020-05-18 12:23:17 +00:00
ic . NextErr = tc . ResponseErr
ic . NextPluginProbe = tc . ProbeResponse
2019-10-22 13:20:26 +00:00
resp , err := client . PluginProbe ( context . TODO ( ) )
2020-05-18 12:23:17 +00:00
if tc . ExpectedErr != nil {
require . EqualError ( t , err , tc . ExpectedErr . Error ( ) )
2019-10-22 13:20:26 +00:00
}
2020-05-18 12:23:17 +00:00
require . Equal ( t , tc . ExpectedResponse , resp )
2019-10-22 13:20:26 +00:00
} )
}
}
func TestClient_RPC_PluginInfo ( t * testing . T ) {
2022-03-15 12:42:43 +00:00
ci . Parallel ( t )
2019-10-22 13:20:26 +00:00
cases := [ ] struct {
2020-03-09 13:57:59 +00:00
Name string
ResponseErr error
InfoResponse * csipbv1 . GetPluginInfoResponse
ExpectedResponseName string
ExpectedResponseVersion string
ExpectedErr error
2019-10-22 13:20:26 +00:00
} {
{
Name : "handles underlying grpc errors" ,
ResponseErr : fmt . Errorf ( "some grpc error" ) ,
ExpectedErr : fmt . Errorf ( "some grpc error" ) ,
} ,
{
Name : "returns an error if we receive an empty `name`" ,
InfoResponse : & csipbv1 . GetPluginInfoResponse {
2020-03-09 13:57:59 +00:00
Name : "" ,
VendorVersion : "" ,
2019-10-22 13:20:26 +00:00
} ,
ExpectedErr : fmt . Errorf ( "PluginGetInfo: plugin returned empty name field" ) ,
} ,
{
Name : "returns the name when successfully retrieved and not empty" ,
InfoResponse : & csipbv1 . GetPluginInfoResponse {
2020-03-09 13:57:59 +00:00
Name : "com.hashicorp.storage" ,
VendorVersion : "1.0.1" ,
2019-10-22 13:20:26 +00:00
} ,
2020-03-09 13:57:59 +00:00
ExpectedResponseName : "com.hashicorp.storage" ,
ExpectedResponseVersion : "1.0.1" ,
2019-10-22 13:20:26 +00:00
} ,
}
2020-05-18 12:23:17 +00:00
for _ , tc := range cases {
t . Run ( tc . Name , func ( t * testing . T ) {
2022-02-15 21:57:29 +00:00
ic , _ , _ , client := newTestClient ( t )
2019-10-22 13:20:26 +00:00
defer client . Close ( )
2020-05-18 12:23:17 +00:00
ic . NextErr = tc . ResponseErr
ic . NextPluginInfo = tc . InfoResponse
2019-10-22 13:20:26 +00:00
2020-03-09 13:57:59 +00:00
name , version , err := client . PluginGetInfo ( context . TODO ( ) )
2020-05-18 12:23:17 +00:00
if tc . ExpectedErr != nil {
require . EqualError ( t , err , tc . ExpectedErr . Error ( ) )
2019-10-22 13:20:26 +00:00
}
2020-05-18 12:23:17 +00:00
require . Equal ( t , tc . ExpectedResponseName , name )
require . Equal ( t , tc . ExpectedResponseVersion , version )
2019-10-22 13:20:26 +00:00
} )
}
}
func TestClient_RPC_PluginGetCapabilities ( t * testing . T ) {
2022-03-15 12:42:43 +00:00
ci . Parallel ( t )
2019-10-22 13:20:26 +00:00
cases := [ ] struct {
Name string
ResponseErr error
Response * csipbv1 . GetPluginCapabilitiesResponse
ExpectedResponse * PluginCapabilitySet
ExpectedErr error
} {
{
Name : "handles underlying grpc errors" ,
ResponseErr : fmt . Errorf ( "some grpc error" ) ,
ExpectedErr : fmt . Errorf ( "some grpc error" ) ,
} ,
{
Name : "HasControllerService is true when it's part of the response" ,
Response : & csipbv1 . GetPluginCapabilitiesResponse {
Capabilities : [ ] * csipbv1 . PluginCapability {
{
Type : & csipbv1 . PluginCapability_Service_ {
Service : & csipbv1 . PluginCapability_Service {
Type : csipbv1 . PluginCapability_Service_CONTROLLER_SERVICE ,
} ,
} ,
} ,
} ,
} ,
ExpectedResponse : & PluginCapabilitySet { hasControllerService : true } ,
} ,
{
Name : "HasTopologies is true when it's part of the response" ,
Response : & csipbv1 . GetPluginCapabilitiesResponse {
Capabilities : [ ] * csipbv1 . PluginCapability {
{
Type : & csipbv1 . PluginCapability_Service_ {
Service : & csipbv1 . PluginCapability_Service {
Type : csipbv1 . PluginCapability_Service_VOLUME_ACCESSIBILITY_CONSTRAINTS ,
} ,
} ,
} ,
} ,
} ,
ExpectedResponse : & PluginCapabilitySet { hasTopologies : true } ,
} ,
}
2020-05-18 12:23:17 +00:00
for _ , tc := range cases {
t . Run ( tc . Name , func ( t * testing . T ) {
2022-02-15 21:57:29 +00:00
ic , _ , _ , client := newTestClient ( t )
2019-10-22 13:20:26 +00:00
defer client . Close ( )
2020-05-18 12:23:17 +00:00
ic . NextErr = tc . ResponseErr
ic . NextPluginCapabilities = tc . Response
2019-10-22 13:20:26 +00:00
resp , err := client . PluginGetCapabilities ( context . TODO ( ) )
2020-05-18 12:23:17 +00:00
if tc . ExpectedErr != nil {
require . EqualError ( t , err , tc . ExpectedErr . Error ( ) )
2019-10-22 13:20:26 +00:00
}
2020-05-18 12:23:17 +00:00
require . Equal ( t , tc . ExpectedResponse , resp )
2019-10-22 13:20:26 +00:00
} )
}
2019-12-16 12:31:09 +00:00
}
2019-10-22 13:20:26 +00:00
2019-12-18 10:57:55 +00:00
func TestClient_RPC_ControllerGetCapabilities ( t * testing . T ) {
2022-03-15 12:42:43 +00:00
ci . Parallel ( t )
2019-12-18 10:57:55 +00:00
cases := [ ] struct {
Name string
ResponseErr error
Response * csipbv1 . ControllerGetCapabilitiesResponse
ExpectedResponse * ControllerCapabilitySet
ExpectedErr error
} {
{
Name : "handles underlying grpc errors" ,
ResponseErr : fmt . Errorf ( "some grpc error" ) ,
ExpectedErr : fmt . Errorf ( "some grpc error" ) ,
} ,
{
Name : "ignores unknown capabilities" ,
Response : & csipbv1 . ControllerGetCapabilitiesResponse {
Capabilities : [ ] * csipbv1 . ControllerServiceCapability {
{
Type : & csipbv1 . ControllerServiceCapability_Rpc {
Rpc : & csipbv1 . ControllerServiceCapability_RPC {
2021-03-24 18:10:44 +00:00
Type : csipbv1 . ControllerServiceCapability_RPC_UNKNOWN ,
2019-12-18 10:57:55 +00:00
} ,
} ,
} ,
} ,
} ,
ExpectedResponse : & ControllerCapabilitySet { } ,
} ,
{
Name : "detects list volumes capabilities" ,
Response : & csipbv1 . ControllerGetCapabilitiesResponse {
Capabilities : [ ] * csipbv1 . ControllerServiceCapability {
{
Type : & csipbv1 . ControllerServiceCapability_Rpc {
Rpc : & csipbv1 . ControllerServiceCapability_RPC {
Type : csipbv1 . ControllerServiceCapability_RPC_LIST_VOLUMES ,
} ,
} ,
} ,
{
Type : & csipbv1 . ControllerServiceCapability_Rpc {
Rpc : & csipbv1 . ControllerServiceCapability_RPC {
Type : csipbv1 . ControllerServiceCapability_RPC_LIST_VOLUMES_PUBLISHED_NODES ,
} ,
} ,
} ,
} ,
} ,
ExpectedResponse : & ControllerCapabilitySet {
HasListVolumes : true ,
HasListVolumesPublishedNodes : true ,
} ,
} ,
{
Name : "detects publish capabilities" ,
Response : & csipbv1 . ControllerGetCapabilitiesResponse {
Capabilities : [ ] * csipbv1 . ControllerServiceCapability {
{
Type : & csipbv1 . ControllerServiceCapability_Rpc {
Rpc : & csipbv1 . ControllerServiceCapability_RPC {
Type : csipbv1 . ControllerServiceCapability_RPC_PUBLISH_READONLY ,
} ,
} ,
} ,
{
Type : & csipbv1 . ControllerServiceCapability_Rpc {
Rpc : & csipbv1 . ControllerServiceCapability_RPC {
Type : csipbv1 . ControllerServiceCapability_RPC_PUBLISH_UNPUBLISH_VOLUME ,
} ,
} ,
} ,
} ,
} ,
ExpectedResponse : & ControllerCapabilitySet {
HasPublishUnpublishVolume : true ,
HasPublishReadonly : true ,
} ,
} ,
}
for _ , tc := range cases {
t . Run ( tc . Name , func ( t * testing . T ) {
2022-02-15 21:57:29 +00:00
_ , cc , _ , client := newTestClient ( t )
2019-12-18 10:57:55 +00:00
defer client . Close ( )
cc . NextErr = tc . ResponseErr
cc . NextCapabilitiesResponse = tc . Response
resp , err := client . ControllerGetCapabilities ( context . TODO ( ) )
if tc . ExpectedErr != nil {
2020-05-18 12:23:17 +00:00
require . EqualError ( t , err , tc . ExpectedErr . Error ( ) )
2019-12-18 10:57:55 +00:00
}
require . Equal ( t , tc . ExpectedResponse , resp )
} )
}
}
2019-12-18 12:18:07 +00:00
func TestClient_RPC_NodeGetCapabilities ( t * testing . T ) {
2022-03-15 12:42:43 +00:00
ci . Parallel ( t )
2019-12-18 12:18:07 +00:00
cases := [ ] struct {
Name string
ResponseErr error
Response * csipbv1 . NodeGetCapabilitiesResponse
ExpectedResponse * NodeCapabilitySet
ExpectedErr error
} {
{
Name : "handles underlying grpc errors" ,
ResponseErr : fmt . Errorf ( "some grpc error" ) ,
ExpectedErr : fmt . Errorf ( "some grpc error" ) ,
} ,
{
2021-04-01 19:39:38 +00:00
Name : "detects multiple capabilities" ,
2019-12-18 12:18:07 +00:00
Response : & csipbv1 . NodeGetCapabilitiesResponse {
Capabilities : [ ] * csipbv1 . NodeServiceCapability {
{
Type : & csipbv1 . NodeServiceCapability_Rpc {
Rpc : & csipbv1 . NodeServiceCapability_RPC {
2021-04-01 19:39:38 +00:00
Type : csipbv1 . NodeServiceCapability_RPC_STAGE_UNSTAGE_VOLUME ,
2019-12-18 12:18:07 +00:00
} ,
} ,
} ,
{
Type : & csipbv1 . NodeServiceCapability_Rpc {
Rpc : & csipbv1 . NodeServiceCapability_RPC {
2021-04-01 19:39:38 +00:00
Type : csipbv1 . NodeServiceCapability_RPC_EXPAND_VOLUME ,
2019-12-18 12:18:07 +00:00
} ,
} ,
} ,
} ,
} ,
ExpectedResponse : & NodeCapabilitySet {
HasStageUnstageVolume : true ,
2021-04-01 19:39:38 +00:00
HasExpandVolume : true ,
2019-12-18 12:18:07 +00:00
} ,
} ,
}
for _ , tc := range cases {
t . Run ( tc . Name , func ( t * testing . T ) {
2022-02-15 21:57:29 +00:00
_ , _ , nc , client := newTestClient ( t )
2019-12-18 12:18:07 +00:00
defer client . Close ( )
nc . NextErr = tc . ResponseErr
nc . NextCapabilitiesResponse = tc . Response
resp , err := client . NodeGetCapabilities ( context . TODO ( ) )
if tc . ExpectedErr != nil {
2020-05-18 12:23:17 +00:00
require . EqualError ( t , err , tc . ExpectedErr . Error ( ) )
2019-12-18 12:18:07 +00:00
}
require . Equal ( t , tc . ExpectedResponse , resp )
} )
}
}
2019-12-16 12:31:09 +00:00
func TestClient_RPC_ControllerPublishVolume ( t * testing . T ) {
2022-03-15 12:42:43 +00:00
ci . Parallel ( t )
2019-12-16 12:31:09 +00:00
cases := [ ] struct {
Name string
2020-02-10 16:45:06 +00:00
Request * ControllerPublishVolumeRequest
2019-12-16 12:31:09 +00:00
ResponseErr error
Response * csipbv1 . ControllerPublishVolumeResponse
ExpectedResponse * ControllerPublishVolumeResponse
ExpectedErr error
} {
{
Name : "handles underlying grpc errors" ,
2020-05-18 12:23:17 +00:00
Request : & ControllerPublishVolumeRequest { ExternalID : "vol" , NodeID : "node" } ,
ResponseErr : status . Errorf ( codes . Internal , "some grpc error" ) ,
ExpectedErr : fmt . Errorf ( "controller plugin returned an internal error, check the plugin allocation logs for more information: rpc error: code = Internal desc = some grpc error" ) ,
2019-12-16 12:31:09 +00:00
} ,
2020-02-10 16:45:06 +00:00
{
2020-05-18 12:23:17 +00:00
Name : "handles missing NodeID" ,
Request : & ControllerPublishVolumeRequest { ExternalID : "vol" } ,
2020-02-10 16:45:06 +00:00
Response : & csipbv1 . ControllerPublishVolumeResponse { } ,
ExpectedErr : fmt . Errorf ( "missing NodeID" ) ,
} ,
2019-12-16 12:31:09 +00:00
{
2020-05-18 12:23:17 +00:00
Name : "handles PublishContext == nil" ,
Request : & ControllerPublishVolumeRequest {
ExternalID : "vol" , NodeID : "node" } ,
2019-12-16 12:31:09 +00:00
Response : & csipbv1 . ControllerPublishVolumeResponse { } ,
ExpectedResponse : & ControllerPublishVolumeResponse { } ,
} ,
{
2020-05-18 12:23:17 +00:00
Name : "handles PublishContext != nil" ,
2020-05-14 15:56:07 +00:00
Request : & ControllerPublishVolumeRequest { ExternalID : "vol" , NodeID : "node" } ,
2019-12-16 12:31:09 +00:00
Response : & csipbv1 . ControllerPublishVolumeResponse {
PublishContext : map [ string ] string {
"com.hashicorp/nomad-node-id" : "foobar" ,
"com.plugin/device" : "/dev/sdc1" ,
} ,
} ,
ExpectedResponse : & ControllerPublishVolumeResponse {
PublishContext : map [ string ] string {
"com.hashicorp/nomad-node-id" : "foobar" ,
"com.plugin/device" : "/dev/sdc1" ,
} ,
} ,
} ,
}
2020-05-18 12:23:17 +00:00
for _ , tc := range cases {
t . Run ( tc . Name , func ( t * testing . T ) {
2022-02-15 21:57:29 +00:00
_ , cc , _ , client := newTestClient ( t )
2019-12-16 12:31:09 +00:00
defer client . Close ( )
2020-05-18 12:23:17 +00:00
cc . NextErr = tc . ResponseErr
cc . NextPublishVolumeResponse = tc . Response
2019-12-16 12:31:09 +00:00
2020-05-18 12:23:17 +00:00
resp , err := client . ControllerPublishVolume ( context . TODO ( ) , tc . Request )
if tc . ExpectedErr != nil {
require . EqualError ( t , err , tc . ExpectedErr . Error ( ) )
2020-02-10 16:45:06 +00:00
}
2020-05-18 12:23:17 +00:00
require . Equal ( t , tc . ExpectedResponse , resp )
2020-02-10 16:45:06 +00:00
} )
}
}
func TestClient_RPC_ControllerUnpublishVolume ( t * testing . T ) {
2022-03-15 12:42:43 +00:00
ci . Parallel ( t )
2020-02-10 16:45:06 +00:00
cases := [ ] struct {
Name string
Request * ControllerUnpublishVolumeRequest
ResponseErr error
Response * csipbv1 . ControllerUnpublishVolumeResponse
ExpectedResponse * ControllerUnpublishVolumeResponse
ExpectedErr error
} {
{
2020-05-18 12:23:17 +00:00
Name : "handles underlying grpc errors" ,
Request : & ControllerUnpublishVolumeRequest { ExternalID : "vol" , NodeID : "node" } ,
ResponseErr : status . Errorf ( codes . Internal , "some grpc error" ) ,
ExpectedErr : fmt . Errorf ( "controller plugin returned an internal error, check the plugin allocation logs for more information: rpc error: code = Internal desc = some grpc error" ) ,
2020-02-10 16:45:06 +00:00
} ,
{
2020-05-18 12:23:17 +00:00
Name : "handles missing NodeID" ,
Request : & ControllerUnpublishVolumeRequest { ExternalID : "vol" } ,
2020-02-10 16:45:06 +00:00
ExpectedErr : fmt . Errorf ( "missing NodeID" ) ,
ExpectedResponse : nil ,
} ,
{
2020-05-18 12:23:17 +00:00
Name : "handles successful response" ,
2020-05-14 15:56:07 +00:00
Request : & ControllerUnpublishVolumeRequest { ExternalID : "vol" , NodeID : "node" } ,
2020-02-10 16:45:06 +00:00
ExpectedResponse : & ControllerUnpublishVolumeResponse { } ,
} ,
}
2020-05-18 12:23:17 +00:00
for _ , tc := range cases {
t . Run ( tc . Name , func ( t * testing . T ) {
2022-02-15 21:57:29 +00:00
_ , cc , _ , client := newTestClient ( t )
2020-02-10 16:45:06 +00:00
defer client . Close ( )
2020-05-18 12:23:17 +00:00
cc . NextErr = tc . ResponseErr
cc . NextUnpublishVolumeResponse = tc . Response
2020-02-10 16:45:06 +00:00
2020-05-18 12:23:17 +00:00
resp , err := client . ControllerUnpublishVolume ( context . TODO ( ) , tc . Request )
if tc . ExpectedErr != nil {
require . EqualError ( t , err , tc . ExpectedErr . Error ( ) )
2019-12-16 12:31:09 +00:00
}
2020-05-18 12:23:17 +00:00
require . Equal ( t , tc . ExpectedResponse , resp )
2019-12-16 12:31:09 +00:00
} )
}
2019-10-22 13:20:26 +00:00
}
2020-01-23 11:24:37 +00:00
2020-04-30 21:12:32 +00:00
func TestClient_RPC_ControllerValidateVolume ( t * testing . T ) {
2022-03-15 12:42:43 +00:00
ci . Parallel ( t )
2020-04-30 21:12:32 +00:00
cases := [ ] struct {
Name string
2020-10-08 16:53:24 +00:00
AccessType VolumeAccessType
AccessMode VolumeAccessMode
2020-04-30 21:12:32 +00:00
ResponseErr error
Response * csipbv1 . ValidateVolumeCapabilitiesResponse
ExpectedErr error
} {
{
Name : "handles underlying grpc errors" ,
2020-10-08 16:53:24 +00:00
AccessType : VolumeAccessTypeMount ,
AccessMode : VolumeAccessModeMultiNodeMultiWriter ,
2020-05-18 12:23:17 +00:00
ResponseErr : status . Errorf ( codes . Internal , "some grpc error" ) ,
ExpectedErr : fmt . Errorf ( "controller plugin returned an internal error, check the plugin allocation logs for more information: rpc error: code = Internal desc = some grpc error" ) ,
2020-04-30 21:12:32 +00:00
} ,
{
2020-10-08 16:53:24 +00:00
Name : "handles success empty capabilities" ,
AccessType : VolumeAccessTypeMount ,
AccessMode : VolumeAccessModeMultiNodeMultiWriter ,
2020-04-30 21:12:32 +00:00
Response : & csipbv1 . ValidateVolumeCapabilitiesResponse { } ,
ResponseErr : nil ,
ExpectedErr : nil ,
} ,
{
2020-10-08 16:53:24 +00:00
Name : "handles success exact match MountVolume" ,
AccessType : VolumeAccessTypeMount ,
AccessMode : VolumeAccessModeMultiNodeMultiWriter ,
2020-04-30 21:12:32 +00:00
Response : & csipbv1 . ValidateVolumeCapabilitiesResponse {
Confirmed : & csipbv1 . ValidateVolumeCapabilitiesResponse_Confirmed {
VolumeContext : map [ string ] string { } ,
VolumeCapabilities : [ ] * csipbv1 . VolumeCapability {
{
2020-05-05 19:13:07 +00:00
AccessType : & csipbv1 . VolumeCapability_Mount {
Mount : & csipbv1 . VolumeCapability_MountVolume {
FsType : "ext4" ,
MountFlags : [ ] string { "errors=remount-ro" , "noatime" } ,
} ,
2020-04-30 21:12:32 +00:00
} ,
AccessMode : & csipbv1 . VolumeCapability_AccessMode {
Mode : csipbv1 . VolumeCapability_AccessMode_MULTI_NODE_MULTI_WRITER ,
} ,
} ,
} ,
} ,
} ,
ResponseErr : nil ,
ExpectedErr : nil ,
} ,
2020-10-08 16:53:24 +00:00
{
Name : "handles success exact match BlockVolume" ,
AccessType : VolumeAccessTypeBlock ,
AccessMode : VolumeAccessModeMultiNodeMultiWriter ,
Response : & csipbv1 . ValidateVolumeCapabilitiesResponse {
Confirmed : & csipbv1 . ValidateVolumeCapabilitiesResponse_Confirmed {
VolumeCapabilities : [ ] * csipbv1 . VolumeCapability {
{
AccessType : & csipbv1 . VolumeCapability_Block {
Block : & csipbv1 . VolumeCapability_BlockVolume { } ,
} ,
AccessMode : & csipbv1 . VolumeCapability_AccessMode {
Mode : csipbv1 . VolumeCapability_AccessMode_MULTI_NODE_MULTI_WRITER ,
} ,
} ,
} ,
} ,
} ,
ResponseErr : nil ,
ExpectedErr : nil ,
} ,
2020-04-30 21:12:32 +00:00
{
2020-10-08 16:53:24 +00:00
Name : "handles failure AccessMode mismatch" ,
AccessMode : VolumeAccessModeMultiNodeMultiWriter ,
2020-04-30 21:12:32 +00:00
Response : & csipbv1 . ValidateVolumeCapabilitiesResponse {
Confirmed : & csipbv1 . ValidateVolumeCapabilitiesResponse_Confirmed {
VolumeContext : map [ string ] string { } ,
VolumeCapabilities : [ ] * csipbv1 . VolumeCapability {
{
AccessType : & csipbv1 . VolumeCapability_Block {
Block : & csipbv1 . VolumeCapability_BlockVolume { } ,
} ,
AccessMode : & csipbv1 . VolumeCapability_AccessMode {
Mode : csipbv1 . VolumeCapability_AccessMode_SINGLE_NODE_WRITER ,
} ,
} ,
} ,
} ,
} ,
ResponseErr : nil ,
2020-05-18 12:23:17 +00:00
// this is a multierror
2020-10-08 16:53:24 +00:00
ExpectedErr : fmt . Errorf ( "volume capability validation failed: 1 error occurred:\n\t* requested access mode MULTI_NODE_MULTI_WRITER, got SINGLE_NODE_WRITER\n\n" ) ,
2020-04-30 21:12:32 +00:00
} ,
2020-05-18 12:23:17 +00:00
2020-05-05 19:13:07 +00:00
{
2020-10-08 16:53:24 +00:00
Name : "handles failure MountFlags mismatch" ,
AccessType : VolumeAccessTypeMount ,
AccessMode : VolumeAccessModeMultiNodeMultiWriter ,
2020-05-05 19:13:07 +00:00
Response : & csipbv1 . ValidateVolumeCapabilitiesResponse {
Confirmed : & csipbv1 . ValidateVolumeCapabilitiesResponse_Confirmed {
VolumeContext : map [ string ] string { } ,
VolumeCapabilities : [ ] * csipbv1 . VolumeCapability {
{
AccessType : & csipbv1 . VolumeCapability_Mount {
Mount : & csipbv1 . VolumeCapability_MountVolume {
FsType : "ext4" ,
MountFlags : [ ] string { } ,
} ,
} ,
AccessMode : & csipbv1 . VolumeCapability_AccessMode {
Mode : csipbv1 . VolumeCapability_AccessMode_MULTI_NODE_MULTI_WRITER ,
} ,
} ,
} ,
} ,
} ,
ResponseErr : nil ,
2020-05-18 12:23:17 +00:00
// this is a multierror
ExpectedErr : fmt . Errorf ( "volume capability validation failed: 1 error occurred:\n\t* requested mount flags did not match available capabilities\n\n" ) ,
2020-05-05 19:13:07 +00:00
} ,
2020-10-08 16:53:24 +00:00
{
Name : "handles failure MountFlags with Block" ,
AccessType : VolumeAccessTypeBlock ,
AccessMode : VolumeAccessModeMultiNodeMultiWriter ,
Response : & csipbv1 . ValidateVolumeCapabilitiesResponse {
Confirmed : & csipbv1 . ValidateVolumeCapabilitiesResponse_Confirmed {
VolumeContext : map [ string ] string { } ,
VolumeCapabilities : [ ] * csipbv1 . VolumeCapability {
{
AccessType : & csipbv1 . VolumeCapability_Mount {
Mount : & csipbv1 . VolumeCapability_MountVolume {
FsType : "ext4" ,
MountFlags : [ ] string { } ,
} ,
} ,
AccessMode : & csipbv1 . VolumeCapability_AccessMode {
Mode : csipbv1 . VolumeCapability_AccessMode_MULTI_NODE_MULTI_WRITER ,
} ,
} ,
} ,
} ,
} ,
ResponseErr : nil ,
// this is a multierror
ExpectedErr : fmt . Errorf ( "volume capability validation failed: 1 error occurred:\n\t* 'file-system' access type was not requested but was validated by the controller\n\n" ) ,
} ,
{
Name : "handles success incomplete no AccessType" ,
AccessType : VolumeAccessTypeMount ,
AccessMode : VolumeAccessModeMultiNodeMultiWriter ,
Response : & csipbv1 . ValidateVolumeCapabilitiesResponse {
Confirmed : & csipbv1 . ValidateVolumeCapabilitiesResponse_Confirmed {
VolumeCapabilities : [ ] * csipbv1 . VolumeCapability {
{
AccessMode : & csipbv1 . VolumeCapability_AccessMode {
Mode : csipbv1 . VolumeCapability_AccessMode_MULTI_NODE_MULTI_WRITER ,
} ,
} ,
} ,
} ,
} ,
ResponseErr : nil ,
ExpectedErr : nil ,
} ,
{
Name : "handles success incomplete no AccessMode" ,
AccessType : VolumeAccessTypeBlock ,
AccessMode : VolumeAccessModeMultiNodeMultiWriter ,
Response : & csipbv1 . ValidateVolumeCapabilitiesResponse {
Confirmed : & csipbv1 . ValidateVolumeCapabilitiesResponse_Confirmed {
VolumeCapabilities : [ ] * csipbv1 . VolumeCapability {
{
AccessType : & csipbv1 . VolumeCapability_Block {
Block : & csipbv1 . VolumeCapability_BlockVolume { } ,
} ,
} ,
} ,
} ,
} ,
ResponseErr : nil ,
ExpectedErr : nil ,
} ,
2020-04-30 21:12:32 +00:00
}
2020-05-18 12:23:17 +00:00
for _ , tc := range cases {
t . Run ( tc . Name , func ( t * testing . T ) {
2022-02-15 21:57:29 +00:00
_ , cc , _ , client := newTestClient ( t )
2020-04-30 21:12:32 +00:00
defer client . Close ( )
2021-06-03 19:47:55 +00:00
requestedCaps := [ ] * VolumeCapability { {
2020-10-08 16:53:24 +00:00
AccessType : tc . AccessType ,
AccessMode : tc . AccessMode ,
2020-04-30 21:12:32 +00:00
MountVolume : & structs . CSIMountOptions { // should be ignored
FSType : "ext4" ,
MountFlags : [ ] string { "noatime" , "errors=remount-ro" } ,
} ,
2021-06-03 19:47:55 +00:00
} }
2020-05-15 12:16:01 +00:00
req := & ControllerValidateVolumeRequest {
ExternalID : "volumeID" ,
Secrets : structs . CSISecrets { } ,
Capabilities : requestedCaps ,
Parameters : map [ string ] string { } ,
Context : map [ string ] string { } ,
}
2020-05-18 12:23:17 +00:00
cc . NextValidateVolumeCapabilitiesResponse = tc . Response
cc . NextErr = tc . ResponseErr
2020-04-30 21:12:32 +00:00
2020-05-15 12:16:01 +00:00
err := client . ControllerValidateCapabilities ( context . TODO ( ) , req )
2020-05-18 12:23:17 +00:00
if tc . ExpectedErr != nil {
require . EqualError ( t , err , tc . ExpectedErr . Error ( ) )
2020-04-30 21:12:32 +00:00
} else {
2020-05-18 12:23:17 +00:00
require . NoError ( t , err , tc . Name )
2020-04-30 21:12:32 +00:00
}
} )
}
2021-03-15 20:07:52 +00:00
}
func TestClient_RPC_ControllerCreateVolume ( t * testing . T ) {
2022-03-15 12:42:43 +00:00
ci . Parallel ( t )
2021-03-15 20:07:52 +00:00
cases := [ ] struct {
Name string
CapacityRange * CapacityRange
ContentSource * VolumeContentSource
ResponseErr error
Response * csipbv1 . CreateVolumeResponse
ExpectedErr error
} {
{
Name : "handles underlying grpc errors" ,
ResponseErr : status . Errorf ( codes . Internal , "some grpc error" ) ,
ExpectedErr : fmt . Errorf ( "controller plugin returned an internal error, check the plugin allocation logs for more information: rpc error: code = Internal desc = some grpc error" ) ,
} ,
{
Name : "handles error invalid capacity range" ,
CapacityRange : & CapacityRange {
RequiredBytes : 1000 ,
LimitBytes : 500 ,
} ,
ExpectedErr : errors . New ( "LimitBytes cannot be less than RequiredBytes" ) ,
} ,
{
Name : "handles error invalid content source" ,
ContentSource : & VolumeContentSource {
SnapshotID : "snap-12345" ,
CloneID : "vol-12345" ,
} ,
ExpectedErr : errors . New (
"one of SnapshotID or CloneID must be set if ContentSource is set" ) ,
} ,
{
Name : "handles success missing source and range" ,
Response : & csipbv1 . CreateVolumeResponse { } ,
} ,
{
2022-03-01 15:15:46 +00:00
Name : "handles success with capacity range, source, and topology" ,
2021-03-15 20:07:52 +00:00
CapacityRange : & CapacityRange {
RequiredBytes : 500 ,
LimitBytes : 1000 ,
} ,
ContentSource : & VolumeContentSource {
SnapshotID : "snap-12345" ,
} ,
Response : & csipbv1 . CreateVolumeResponse {
Volume : & csipbv1 . Volume {
CapacityBytes : 1000 ,
ContentSource : & csipbv1 . VolumeContentSource {
Type : & csipbv1 . VolumeContentSource_Snapshot {
Snapshot : & csipbv1 . VolumeContentSource_SnapshotSource {
SnapshotId : "snap-12345" ,
} ,
} ,
} ,
2022-03-01 15:15:46 +00:00
AccessibleTopology : [ ] * csipbv1 . Topology {
{ Segments : map [ string ] string { "rack" : "R1" } } ,
} ,
2021-03-15 20:07:52 +00:00
} ,
} ,
} ,
}
for _ , tc := range cases {
t . Run ( tc . Name , func ( t * testing . T ) {
2022-02-15 21:57:29 +00:00
_ , cc , _ , client := newTestClient ( t )
2021-03-15 20:07:52 +00:00
defer client . Close ( )
req := & ControllerCreateVolumeRequest {
Name : "vol-123456" ,
CapacityRange : tc . CapacityRange ,
VolumeCapabilities : [ ] * VolumeCapability {
{
AccessType : VolumeAccessTypeMount ,
AccessMode : VolumeAccessModeMultiNodeMultiWriter ,
} ,
} ,
2022-03-01 15:15:46 +00:00
Parameters : map [ string ] string { } ,
Secrets : structs . CSISecrets { } ,
ContentSource : tc . ContentSource ,
AccessibilityRequirements : & TopologyRequirement {
Requisite : [ ] * Topology {
{
Segments : map [ string ] string { "rack" : "R1" } ,
} ,
{
Segments : map [ string ] string { "rack" : "R2" } ,
} ,
} ,
} ,
2021-03-15 20:07:52 +00:00
}
cc . NextCreateVolumeResponse = tc . Response
cc . NextErr = tc . ResponseErr
resp , err := client . ControllerCreateVolume ( context . TODO ( ) , req )
if tc . ExpectedErr != nil {
require . EqualError ( t , err , tc . ExpectedErr . Error ( ) )
return
}
require . NoError ( t , err , tc . Name )
if tc . Response == nil {
require . Nil ( t , resp )
return
}
if tc . CapacityRange != nil {
require . Greater ( t , resp . Volume . CapacityBytes , int64 ( 0 ) )
}
if tc . ContentSource != nil {
require . Equal ( t , tc . ContentSource . CloneID , resp . Volume . ContentSource . CloneID )
require . Equal ( t , tc . ContentSource . SnapshotID , resp . Volume . ContentSource . SnapshotID )
}
2022-03-01 15:15:46 +00:00
if tc . Response != nil && tc . Response . Volume != nil {
require . Len ( t , resp . Volume . AccessibleTopology , 1 )
require . Equal ( t ,
req . AccessibilityRequirements . Requisite [ 0 ] . Segments ,
resp . Volume . AccessibleTopology [ 0 ] . Segments ,
)
}
2021-03-15 20:07:52 +00:00
} )
}
}
func TestClient_RPC_ControllerDeleteVolume ( t * testing . T ) {
2022-03-15 12:42:43 +00:00
ci . Parallel ( t )
2021-03-15 20:07:52 +00:00
cases := [ ] struct {
Name string
Request * ControllerDeleteVolumeRequest
ResponseErr error
ExpectedErr error
} {
{
Name : "handles underlying grpc errors" ,
Request : & ControllerDeleteVolumeRequest { ExternalVolumeID : "vol-12345" } ,
ResponseErr : status . Errorf ( codes . Internal , "some grpc error" ) ,
ExpectedErr : fmt . Errorf ( "controller plugin returned an internal error, check the plugin allocation logs for more information: rpc error: code = Internal desc = some grpc error" ) ,
} ,
{
Name : "handles error missing volume ID" ,
Request : & ControllerDeleteVolumeRequest { } ,
ExpectedErr : errors . New ( "missing ExternalVolumeID" ) ,
} ,
{
Name : "handles success" ,
Request : & ControllerDeleteVolumeRequest { ExternalVolumeID : "vol-12345" } ,
} ,
}
for _ , tc := range cases {
t . Run ( tc . Name , func ( t * testing . T ) {
2022-02-15 21:57:29 +00:00
_ , cc , _ , client := newTestClient ( t )
2021-03-15 20:07:52 +00:00
defer client . Close ( )
cc . NextErr = tc . ResponseErr
err := client . ControllerDeleteVolume ( context . TODO ( ) , tc . Request )
if tc . ExpectedErr != nil {
require . EqualError ( t , err , tc . ExpectedErr . Error ( ) )
return
}
require . NoError ( t , err , tc . Name )
} )
}
}
func TestClient_RPC_ControllerListVolume ( t * testing . T ) {
2022-03-15 12:42:43 +00:00
ci . Parallel ( t )
2021-03-15 20:07:52 +00:00
cases := [ ] struct {
Name string
Request * ControllerListVolumesRequest
ResponseErr error
ExpectedErr error
} {
{
Name : "handles underlying grpc errors" ,
Request : & ControllerListVolumesRequest { } ,
ResponseErr : status . Errorf ( codes . Internal , "some grpc error" ) ,
ExpectedErr : fmt . Errorf ( "controller plugin returned an internal error, check the plugin allocation logs for more information: rpc error: code = Internal desc = some grpc error" ) ,
} ,
{
Name : "handles error invalid max entries" ,
Request : & ControllerListVolumesRequest { MaxEntries : - 1 } ,
ExpectedErr : errors . New ( "MaxEntries cannot be negative" ) ,
} ,
2020-04-30 21:12:32 +00:00
2021-03-15 20:07:52 +00:00
{
Name : "handles success" ,
Request : & ControllerListVolumesRequest { } ,
} ,
}
for _ , tc := range cases {
t . Run ( tc . Name , func ( t * testing . T ) {
2022-02-15 21:57:29 +00:00
_ , cc , _ , client := newTestClient ( t )
2021-03-15 20:07:52 +00:00
defer client . Close ( )
cc . NextErr = tc . ResponseErr
if tc . ResponseErr != nil {
// note: there's nothing interesting to assert here other than
// that we don't throw a NPE during transformation from
// protobuf to our struct
cc . NextListVolumesResponse = & csipbv1 . ListVolumesResponse {
Entries : [ ] * csipbv1 . ListVolumesResponse_Entry {
{
Volume : & csipbv1 . Volume {
CapacityBytes : 1000000 ,
VolumeId : "vol-0" ,
VolumeContext : map [ string ] string { "foo" : "bar" } ,
ContentSource : & csipbv1 . VolumeContentSource { } ,
AccessibleTopology : [ ] * csipbv1 . Topology {
{
Segments : map [ string ] string { "rack" : "A" } ,
} ,
} ,
} ,
} ,
{
Volume : & csipbv1 . Volume {
VolumeId : "vol-1" ,
AccessibleTopology : [ ] * csipbv1 . Topology {
{
Segments : map [ string ] string { "rack" : "A" } ,
} ,
} ,
} ,
} ,
{
Volume : & csipbv1 . Volume {
VolumeId : "vol-3" ,
ContentSource : & csipbv1 . VolumeContentSource {
Type : & csipbv1 . VolumeContentSource_Snapshot {
Snapshot : & csipbv1 . VolumeContentSource_SnapshotSource {
SnapshotId : "snap-12345" ,
} ,
} ,
} ,
} ,
} ,
} ,
NextToken : "abcdef" ,
}
}
resp , err := client . ControllerListVolumes ( context . TODO ( ) , tc . Request )
if tc . ExpectedErr != nil {
require . EqualError ( t , err , tc . ExpectedErr . Error ( ) )
return
}
require . NoError ( t , err , tc . Name )
require . NotNil ( t , resp )
} )
}
2020-04-30 21:12:32 +00:00
}
2021-04-01 15:16:52 +00:00
func TestClient_RPC_ControllerCreateSnapshot ( t * testing . T ) {
2022-03-15 12:42:43 +00:00
ci . Parallel ( t )
2021-04-01 15:16:52 +00:00
2022-03-23 14:39:28 +00:00
now := time . Now ( )
2021-04-01 15:16:52 +00:00
cases := [ ] struct {
Name string
Request * ControllerCreateSnapshotRequest
Response * csipbv1 . CreateSnapshotResponse
ResponseErr error
ExpectedErr error
} {
{
Name : "handles underlying grpc errors" ,
Request : & ControllerCreateSnapshotRequest {
VolumeID : "vol-12345" ,
Name : "snap-12345" ,
} ,
ResponseErr : status . Errorf ( codes . Internal , "some grpc error" ) ,
ExpectedErr : fmt . Errorf ( "controller plugin returned an internal error, check the plugin allocation logs for more information: rpc error: code = Internal desc = some grpc error" ) ,
} ,
{
Name : "handles error missing volume ID" ,
Request : & ControllerCreateSnapshotRequest { } ,
ExpectedErr : errors . New ( "missing VolumeID" ) ,
} ,
{
Name : "handles success" ,
Request : & ControllerCreateSnapshotRequest {
VolumeID : "vol-12345" ,
Name : "snap-12345" ,
} ,
Response : & csipbv1 . CreateSnapshotResponse {
Snapshot : & csipbv1 . Snapshot {
SizeBytes : 100000 ,
SnapshotId : "snap-12345" ,
SourceVolumeId : "vol-12345" ,
2022-03-23 14:39:28 +00:00
CreationTime : timestamppb . New ( now ) ,
2021-04-01 15:16:52 +00:00
ReadyToUse : true ,
} ,
} ,
} ,
}
for _ , tc := range cases {
t . Run ( tc . Name , func ( t * testing . T ) {
2022-02-15 21:57:29 +00:00
_ , cc , _ , client := newTestClient ( t )
2021-04-01 15:16:52 +00:00
defer client . Close ( )
cc . NextErr = tc . ResponseErr
cc . NextCreateSnapshotResponse = tc . Response
// note: there's nothing interesting to assert about the response
// here other than that we don't throw a NPE during transformation
// from protobuf to our struct
2022-03-23 14:39:28 +00:00
resp , err := client . ControllerCreateSnapshot ( context . TODO ( ) , tc . Request )
2021-04-01 15:16:52 +00:00
if tc . ExpectedErr != nil {
require . EqualError ( t , err , tc . ExpectedErr . Error ( ) )
} else {
require . NoError ( t , err , tc . Name )
2022-03-23 14:39:28 +00:00
require . NotZero ( t , resp . Snapshot . CreateTime )
require . Equal ( t , now . Second ( ) , time . Unix ( resp . Snapshot . CreateTime , 0 ) . Second ( ) )
2021-04-01 15:16:52 +00:00
}
} )
}
}
func TestClient_RPC_ControllerDeleteSnapshot ( t * testing . T ) {
2022-03-15 12:42:43 +00:00
ci . Parallel ( t )
2021-04-01 15:16:52 +00:00
cases := [ ] struct {
Name string
Request * ControllerDeleteSnapshotRequest
ResponseErr error
ExpectedErr error
} {
{
Name : "handles underlying grpc errors" ,
Request : & ControllerDeleteSnapshotRequest { SnapshotID : "vol-12345" } ,
ResponseErr : status . Errorf ( codes . Internal , "some grpc error" ) ,
ExpectedErr : fmt . Errorf ( "controller plugin returned an internal error, check the plugin allocation logs for more information: rpc error: code = Internal desc = some grpc error" ) ,
} ,
{
Name : "handles error missing volume ID" ,
Request : & ControllerDeleteSnapshotRequest { } ,
ExpectedErr : errors . New ( "missing SnapshotID" ) ,
} ,
{
Name : "handles success" ,
Request : & ControllerDeleteSnapshotRequest { SnapshotID : "vol-12345" } ,
} ,
}
for _ , tc := range cases {
t . Run ( tc . Name , func ( t * testing . T ) {
2022-02-15 21:57:29 +00:00
_ , cc , _ , client := newTestClient ( t )
2021-04-01 15:16:52 +00:00
defer client . Close ( )
cc . NextErr = tc . ResponseErr
err := client . ControllerDeleteSnapshot ( context . TODO ( ) , tc . Request )
if tc . ExpectedErr != nil {
require . EqualError ( t , err , tc . ExpectedErr . Error ( ) )
return
}
require . NoError ( t , err , tc . Name )
} )
}
}
func TestClient_RPC_ControllerListSnapshots ( t * testing . T ) {
2022-03-15 12:42:43 +00:00
ci . Parallel ( t )
2021-04-01 15:16:52 +00:00
cases := [ ] struct {
Name string
Request * ControllerListSnapshotsRequest
ResponseErr error
ExpectedErr error
} {
{
Name : "handles underlying grpc errors" ,
Request : & ControllerListSnapshotsRequest { } ,
ResponseErr : status . Errorf ( codes . Internal , "some grpc error" ) ,
ExpectedErr : fmt . Errorf ( "controller plugin returned an internal error, check the plugin allocation logs for more information: rpc error: code = Internal desc = some grpc error" ) ,
} ,
{
Name : "handles error invalid max entries" ,
Request : & ControllerListSnapshotsRequest { MaxEntries : - 1 } ,
ExpectedErr : errors . New ( "MaxEntries cannot be negative" ) ,
} ,
{
Name : "handles success" ,
Request : & ControllerListSnapshotsRequest { } ,
} ,
}
2022-03-23 14:39:28 +00:00
now := time . Now ( )
2021-04-01 15:16:52 +00:00
for _ , tc := range cases {
t . Run ( tc . Name , func ( t * testing . T ) {
2022-02-15 21:57:29 +00:00
_ , cc , _ , client := newTestClient ( t )
2021-04-01 15:16:52 +00:00
defer client . Close ( )
cc . NextErr = tc . ResponseErr
2022-03-23 14:39:28 +00:00
if tc . ResponseErr == nil {
2021-04-01 15:16:52 +00:00
cc . NextListSnapshotsResponse = & csipbv1 . ListSnapshotsResponse {
Entries : [ ] * csipbv1 . ListSnapshotsResponse_Entry {
{
Snapshot : & csipbv1 . Snapshot {
SizeBytes : 1000000 ,
SnapshotId : "snap-12345" ,
SourceVolumeId : "vol-12345" ,
ReadyToUse : true ,
2022-03-23 14:39:28 +00:00
CreationTime : timestamppb . New ( now ) ,
2021-04-01 15:16:52 +00:00
} ,
} ,
} ,
NextToken : "abcdef" ,
}
}
resp , err := client . ControllerListSnapshots ( context . TODO ( ) , tc . Request )
if tc . ExpectedErr != nil {
require . EqualError ( t , err , tc . ExpectedErr . Error ( ) )
return
}
require . NoError ( t , err , tc . Name )
require . NotNil ( t , resp )
2022-03-23 14:39:28 +00:00
require . Len ( t , resp . Entries , 1 )
require . NotZero ( t , resp . Entries [ 0 ] . Snapshot . CreateTime )
require . Equal ( t , now . Second ( ) ,
time . Unix ( resp . Entries [ 0 ] . Snapshot . CreateTime , 0 ) . Second ( ) )
2021-04-01 15:16:52 +00:00
} )
}
}
2020-01-23 11:24:37 +00:00
func TestClient_RPC_NodeStageVolume ( t * testing . T ) {
2022-03-15 12:42:43 +00:00
ci . Parallel ( t )
2020-01-23 11:24:37 +00:00
cases := [ ] struct {
Name string
ResponseErr error
Response * csipbv1 . NodeStageVolumeResponse
ExpectedErr error
} {
{
Name : "handles underlying grpc errors" ,
2020-05-18 12:23:17 +00:00
ResponseErr : status . Errorf ( codes . AlreadyExists , "some grpc error" ) ,
ExpectedErr : fmt . Errorf ( "volume \"foo\" is already staged to \"/path\" but with incompatible capabilities for this request: rpc error: code = AlreadyExists desc = some grpc error" ) ,
2020-01-23 11:24:37 +00:00
} ,
{
Name : "handles success" ,
ResponseErr : nil ,
ExpectedErr : nil ,
} ,
}
2020-05-18 12:23:17 +00:00
for _ , tc := range cases {
t . Run ( tc . Name , func ( t * testing . T ) {
2022-02-15 21:57:29 +00:00
_ , _ , nc , client := newTestClient ( t )
2020-01-23 11:24:37 +00:00
defer client . Close ( )
2020-05-18 12:23:17 +00:00
nc . NextErr = tc . ResponseErr
nc . NextStageVolumeResponse = tc . Response
2020-01-23 11:24:37 +00:00
2020-06-22 17:54:32 +00:00
err := client . NodeStageVolume ( context . TODO ( ) , & NodeStageVolumeRequest {
ExternalID : "foo" ,
StagingTargetPath : "/path" ,
VolumeCapability : & VolumeCapability { } ,
} )
2020-05-18 12:23:17 +00:00
if tc . ExpectedErr != nil {
require . EqualError ( t , err , tc . ExpectedErr . Error ( ) )
2020-01-23 11:24:37 +00:00
} else {
require . Nil ( t , err )
}
} )
}
}
2020-01-24 13:34:04 +00:00
func TestClient_RPC_NodeUnstageVolume ( t * testing . T ) {
2022-03-15 12:42:43 +00:00
ci . Parallel ( t )
2020-01-24 13:34:04 +00:00
cases := [ ] struct {
Name string
ResponseErr error
Response * csipbv1 . NodeUnstageVolumeResponse
ExpectedErr error
} {
{
Name : "handles underlying grpc errors" ,
2020-05-18 12:23:17 +00:00
ResponseErr : status . Errorf ( codes . Internal , "some grpc error" ) ,
ExpectedErr : fmt . Errorf ( "node plugin returned an internal error, check the plugin allocation logs for more information: rpc error: code = Internal desc = some grpc error" ) ,
2020-01-24 13:34:04 +00:00
} ,
{
Name : "handles success" ,
ResponseErr : nil ,
ExpectedErr : nil ,
} ,
}
2020-05-18 12:23:17 +00:00
for _ , tc := range cases {
t . Run ( tc . Name , func ( t * testing . T ) {
2022-02-15 21:57:29 +00:00
_ , _ , nc , client := newTestClient ( t )
2020-01-24 13:34:04 +00:00
defer client . Close ( )
2020-05-18 12:23:17 +00:00
nc . NextErr = tc . ResponseErr
nc . NextUnstageVolumeResponse = tc . Response
2020-01-24 13:34:04 +00:00
err := client . NodeUnstageVolume ( context . TODO ( ) , "foo" , "/foo" )
2020-05-18 12:23:17 +00:00
if tc . ExpectedErr != nil {
require . EqualError ( t , err , tc . ExpectedErr . Error ( ) )
2020-01-24 13:34:04 +00:00
} else {
require . Nil ( t , err )
}
} )
}
}
2020-01-24 16:20:23 +00:00
func TestClient_RPC_NodePublishVolume ( t * testing . T ) {
2022-03-15 12:42:43 +00:00
ci . Parallel ( t )
2020-01-24 16:20:23 +00:00
cases := [ ] struct {
Name string
Request * NodePublishVolumeRequest
ResponseErr error
Response * csipbv1 . NodePublishVolumeResponse
ExpectedErr error
} {
{
Name : "handles underlying grpc errors" ,
Request : & NodePublishVolumeRequest {
2020-05-14 15:56:07 +00:00
ExternalID : "foo" ,
2020-01-24 16:20:23 +00:00
TargetPath : "/dev/null" ,
VolumeCapability : & VolumeCapability { } ,
} ,
2020-05-18 12:23:17 +00:00
ResponseErr : status . Errorf ( codes . Internal , "some grpc error" ) ,
ExpectedErr : fmt . Errorf ( "node plugin returned an internal error, check the plugin allocation logs for more information: rpc error: code = Internal desc = some grpc error" ) ,
2020-01-24 16:20:23 +00:00
} ,
{
Name : "handles success" ,
Request : & NodePublishVolumeRequest {
2020-05-14 15:56:07 +00:00
ExternalID : "foo" ,
2020-01-24 16:20:23 +00:00
TargetPath : "/dev/null" ,
VolumeCapability : & VolumeCapability { } ,
} ,
ResponseErr : nil ,
ExpectedErr : nil ,
} ,
{
Name : "Performs validation of the publish volume request" ,
Request : & NodePublishVolumeRequest {
2020-05-14 15:56:07 +00:00
ExternalID : "" ,
2020-01-24 16:20:23 +00:00
} ,
ResponseErr : nil ,
2020-05-18 12:23:17 +00:00
ExpectedErr : errors . New ( "validation error: missing volume ID" ) ,
2020-01-24 16:20:23 +00:00
} ,
}
2020-05-18 12:23:17 +00:00
for _ , tc := range cases {
t . Run ( tc . Name , func ( t * testing . T ) {
2022-02-15 21:57:29 +00:00
_ , _ , nc , client := newTestClient ( t )
2020-01-24 16:20:23 +00:00
defer client . Close ( )
2020-05-18 12:23:17 +00:00
nc . NextErr = tc . ResponseErr
nc . NextPublishVolumeResponse = tc . Response
2020-01-24 16:20:23 +00:00
2020-05-18 12:23:17 +00:00
err := client . NodePublishVolume ( context . TODO ( ) , tc . Request )
if tc . ExpectedErr != nil {
require . EqualError ( t , err , tc . ExpectedErr . Error ( ) )
2020-01-24 16:20:23 +00:00
} else {
require . Nil ( t , err )
}
} )
}
}
2020-01-27 10:17:10 +00:00
func TestClient_RPC_NodeUnpublishVolume ( t * testing . T ) {
2022-03-15 12:42:43 +00:00
ci . Parallel ( t )
2022-03-23 14:39:28 +00:00
2020-01-27 10:17:10 +00:00
cases := [ ] struct {
Name string
2020-05-14 15:56:07 +00:00
ExternalID string
2020-01-27 10:17:10 +00:00
TargetPath string
ResponseErr error
Response * csipbv1 . NodeUnpublishVolumeResponse
ExpectedErr error
} {
{
Name : "handles underlying grpc errors" ,
2020-05-14 15:56:07 +00:00
ExternalID : "foo" ,
2020-01-27 10:17:10 +00:00
TargetPath : "/dev/null" ,
2020-05-18 12:23:17 +00:00
ResponseErr : status . Errorf ( codes . Internal , "some grpc error" ) ,
ExpectedErr : fmt . Errorf ( "node plugin returned an internal error, check the plugin allocation logs for more information: rpc error: code = Internal desc = some grpc error" ) ,
2020-01-27 10:17:10 +00:00
} ,
{
Name : "handles success" ,
2020-05-14 15:56:07 +00:00
ExternalID : "foo" ,
2020-01-27 10:17:10 +00:00
TargetPath : "/dev/null" ,
ResponseErr : nil ,
ExpectedErr : nil ,
} ,
{
2020-05-14 15:56:07 +00:00
Name : "Performs validation of the request args - ExternalID" ,
2020-01-27 10:17:10 +00:00
ResponseErr : nil ,
2020-05-18 12:23:17 +00:00
ExpectedErr : errors . New ( "missing volumeID" ) ,
2020-01-27 10:17:10 +00:00
} ,
{
Name : "Performs validation of the request args - TargetPath" ,
2020-05-14 15:56:07 +00:00
ExternalID : "foo" ,
2020-01-27 10:17:10 +00:00
ResponseErr : nil ,
2020-05-18 12:23:17 +00:00
ExpectedErr : errors . New ( "missing targetPath" ) ,
2020-01-27 10:17:10 +00:00
} ,
}
2020-05-18 12:23:17 +00:00
for _ , tc := range cases {
t . Run ( tc . Name , func ( t * testing . T ) {
2022-02-15 21:57:29 +00:00
_ , _ , nc , client := newTestClient ( t )
2020-01-27 10:17:10 +00:00
defer client . Close ( )
2020-05-18 12:23:17 +00:00
nc . NextErr = tc . ResponseErr
nc . NextUnpublishVolumeResponse = tc . Response
2020-01-27 10:17:10 +00:00
2020-05-18 12:23:17 +00:00
err := client . NodeUnpublishVolume ( context . TODO ( ) , tc . ExternalID , tc . TargetPath )
if tc . ExpectedErr != nil {
require . EqualError ( t , err , tc . ExpectedErr . Error ( ) )
2020-01-27 10:17:10 +00:00
} else {
require . Nil ( t , err )
}
} )
}
}