kubernetes/pkg/volume/vsphere_volume/attacher_test.go
Claudiu Belu 38092cb458 unittests: Fixes unit tests for Windows (part 2)
Currently, there are some unit tests that are failing on Windows due to
various reasons:

- volume mounting is a bit different on Windows: Mount will create the
  parent dirs and mklink at the volume path later (otherwise mklink will
  raise an error).
- os.Chmod is not working as intended on Windows.
- path.Dir() will always return "." on Windows, and filepath.Dir()
  should be used instead (which works correctly).
- on Windows, you can't typically run binaries without extensions. If
  the file C:\\foo.bat exists, we can still run C:\\foo because Windows
  will append one of the supported file extensions ($env:PATHEXT) to it
  and run it.
- Windows file permissions do not work the same way as the Linux ones.
- /tmp directory being used, which might not exist on Windows. Instead,
  the OS-specific Temp directory should be used.

Fixes a few other issues:

- rbd.go: Return error in a case in which an error is encountered. This
  will prevent "rbd: failed to setup" and "rbd: successfully setup" log
  messages to be logged at the same time.
2022-08-01 18:56:32 +03:00

336 lines
9.8 KiB
Go

//go:build !providerless
// +build !providerless
/*
Copyright 2016 The Kubernetes Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package vsphere_volume
import (
"errors"
"fmt"
"os"
"path/filepath"
"testing"
v1 "k8s.io/api/core/v1"
"k8s.io/apimachinery/pkg/types"
"k8s.io/kubernetes/pkg/volume"
volumetest "k8s.io/kubernetes/pkg/volume/testing"
"k8s.io/legacy-cloud-providers/vsphere/vclib"
"k8s.io/klog/v2"
)
var (
// diskNameErr is the error when disk name is wrong.
diskNameErr = errors.New("wrong diskName")
// nodeNameErr is the error when node name is wrong.
nodeNameErr = errors.New("wrong nodeName")
)
func TestGetDeviceName_Volume(t *testing.T) {
plugin := newPlugin(t)
volPath := "[local] volumes/test"
spec := createVolSpec(volPath)
deviceName, err := plugin.GetVolumeName(spec)
if err != nil {
t.Errorf("GetDeviceName error: %v", err)
}
if deviceName != volPath {
t.Errorf("GetDeviceName error: expected %s, got %s", volPath, deviceName)
}
}
func TestGetDeviceName_PersistentVolume(t *testing.T) {
plugin := newPlugin(t)
volPath := "[local] volumes/test"
spec := createPVSpec(volPath)
deviceName, err := plugin.GetVolumeName(spec)
if err != nil {
t.Errorf("GetDeviceName error: %v", err)
}
if deviceName != volPath {
t.Errorf("GetDeviceName error: expected %s, got %s", volPath, deviceName)
}
}
// One testcase for TestAttachDetach table test below
type testcase struct {
name string
// For fake vSphere:
attach attachCall
detach detachCall
diskIsAttached diskIsAttachedCall
t *testing.T
// Actual test to run
test func(test *testcase) (string, error)
// Expected return of the test
expectedDevice string
expectedError error
}
func TestAttachDetach(t *testing.T) {
uuid := "00000000000000"
diskName := "[local] volumes/test"
nodeName := types.NodeName("host")
spec := createVolSpec(diskName)
expectedDevice := filepath.FromSlash("/dev/disk/by-id/wwn-0x" + uuid)
attachError := errors.New("fake attach error")
detachError := errors.New("fake detach error")
diskCheckError := errors.New("fake DiskIsAttached error")
tests := []testcase{
// Successful Attach call
{
name: "Attach_Positive",
attach: attachCall{diskName, nodeName, uuid, nil},
test: func(testcase *testcase) (string, error) {
attacher := newAttacher(testcase)
return attacher.Attach(spec, nodeName)
},
expectedDevice: expectedDevice,
},
// Attach call fails
{
name: "Attach_Negative",
attach: attachCall{diskName, nodeName, "", attachError},
test: func(testcase *testcase) (string, error) {
attacher := newAttacher(testcase)
return attacher.Attach(spec, nodeName)
},
expectedError: attachError,
},
// Detach succeeds
{
name: "Detach_Positive",
diskIsAttached: diskIsAttachedCall{diskName, nodeName, true, nil},
detach: detachCall{diskName, nodeName, nil},
test: func(testcase *testcase) (string, error) {
detacher := newDetacher(testcase)
return "", detacher.Detach(diskName, nodeName)
},
},
// Disk is already detached
{
name: "Detach_Positive_AlreadyDetached",
diskIsAttached: diskIsAttachedCall{diskName, nodeName, false, nil},
test: func(testcase *testcase) (string, error) {
detacher := newDetacher(testcase)
return "", detacher.Detach(diskName, nodeName)
},
},
// Detach succeeds when DiskIsAttached fails
{
name: "Detach_Positive_CheckFails",
diskIsAttached: diskIsAttachedCall{diskName, nodeName, false, diskCheckError},
detach: detachCall{diskName, nodeName, nil},
test: func(testcase *testcase) (string, error) {
detacher := newDetacher(testcase)
return "", detacher.Detach(diskName, nodeName)
},
},
// Detach fails
{
name: "Detach_Negative",
diskIsAttached: diskIsAttachedCall{diskName, nodeName, false, diskCheckError},
detach: detachCall{diskName, nodeName, detachError},
test: func(testcase *testcase) (string, error) {
detacher := newDetacher(testcase)
return "", detacher.Detach(diskName, nodeName)
},
expectedError: detachError,
},
}
for _, testcase := range tests {
testcase.t = t
device, err := testcase.test(&testcase)
if err != testcase.expectedError {
t.Errorf("%s failed: expected err=%q, got %q", testcase.name, testcase.expectedError.Error(), err.Error())
}
if device != testcase.expectedDevice {
t.Errorf("%s failed: expected device=%q, got %q", testcase.name, testcase.expectedDevice, device)
}
t.Logf("Test %q succeeded", testcase.name)
}
}
// newPlugin creates a new vsphereVolumePlugin with fake cloud, NewAttacher
// and NewDetacher won't work.
func newPlugin(t *testing.T) *vsphereVolumePlugin {
host := volumetest.NewFakeVolumeHost(t, os.TempDir(), nil, nil)
plugins := ProbeVolumePlugins()
plugin := plugins[0]
plugin.Init(host)
return plugin.(*vsphereVolumePlugin)
}
func newAttacher(testcase *testcase) *vsphereVMDKAttacher {
return &vsphereVMDKAttacher{
host: nil,
vsphereVolumes: testcase,
}
}
func newDetacher(testcase *testcase) *vsphereVMDKDetacher {
return &vsphereVMDKDetacher{
vsphereVolumes: testcase,
}
}
func createVolSpec(name string) *volume.Spec {
return &volume.Spec{
Volume: &v1.Volume{
VolumeSource: v1.VolumeSource{
VsphereVolume: &v1.VsphereVirtualDiskVolumeSource{
VolumePath: name,
},
},
},
}
}
func createPVSpec(name string) *volume.Spec {
return &volume.Spec{
PersistentVolume: &v1.PersistentVolume{
Spec: v1.PersistentVolumeSpec{
PersistentVolumeSource: v1.PersistentVolumeSource{
VsphereVolume: &v1.VsphereVirtualDiskVolumeSource{
VolumePath: name,
},
},
},
},
}
}
// Fake vSphere implementation
type attachCall struct {
diskName string
nodeName types.NodeName
retDeviceUUID string
ret error
}
type detachCall struct {
diskName string
nodeName types.NodeName
ret error
}
type diskIsAttachedCall struct {
diskName string
nodeName types.NodeName
isAttached bool
ret error
}
func (testcase *testcase) AttachDisk(diskName string, storagePolicyName string, nodeName types.NodeName) (string, error) {
expected := &testcase.attach
if expected.diskName == "" && expected.nodeName == "" {
// testcase.attach looks uninitialized, test did not expect to call
// AttachDisk
testcase.t.Errorf("Unexpected AttachDisk call!")
return "", errors.New("unexpected AttachDisk call")
}
if expected.diskName != diskName {
testcase.t.Errorf("Unexpected AttachDisk call: expected diskName %s, got %s", expected.diskName, diskName)
return "", fmt.Errorf(`unexpected AttachDisk call: %w`, diskNameErr)
}
if expected.nodeName != nodeName {
testcase.t.Errorf("Unexpected AttachDisk call: expected nodeName %s, got %s", expected.nodeName, nodeName)
return "", fmt.Errorf(`unexpected AttachDisk call: %w`, nodeNameErr)
}
klog.V(4).Infof("AttachDisk call: %s, %s, returning %q, %v", diskName, nodeName, expected.retDeviceUUID, expected.ret)
return expected.retDeviceUUID, expected.ret
}
func (testcase *testcase) DetachDisk(diskName string, nodeName types.NodeName) error {
expected := &testcase.detach
if expected.diskName == "" && expected.nodeName == "" {
// testcase.detach looks uninitialized, test did not expect to call
// DetachDisk
testcase.t.Errorf("Unexpected DetachDisk call!")
return errors.New("unexpected DetachDisk call")
}
if expected.diskName != diskName {
testcase.t.Errorf("Unexpected DetachDisk call: expected diskName %s, got %s", expected.diskName, diskName)
return fmt.Errorf(`unexpected DetachDisk call: %w`, diskNameErr)
}
if expected.nodeName != nodeName {
testcase.t.Errorf("Unexpected DetachDisk call: expected nodeName %s, got %s", expected.nodeName, nodeName)
return fmt.Errorf(`unexpected DetachDisk call: %w`, nodeNameErr)
}
klog.V(4).Infof("DetachDisk call: %s, %s, returning %v", diskName, nodeName, expected.ret)
return expected.ret
}
func (testcase *testcase) DiskIsAttached(diskName string, nodeName types.NodeName) (bool, string, error) {
expected := &testcase.diskIsAttached
if expected.diskName == "" && expected.nodeName == "" {
// testcase.diskIsAttached looks uninitialized, test did not expect to
// call DiskIsAttached
testcase.t.Errorf("Unexpected DiskIsAttached call!")
return false, diskName, errors.New("unexpected DiskIsAttached call")
}
if expected.diskName != diskName {
testcase.t.Errorf("Unexpected DiskIsAttached call: expected diskName %s, got %s", expected.diskName, diskName)
return false, diskName, fmt.Errorf(`unexpected DiskIsAttached call: %w`, diskNameErr)
}
if expected.nodeName != nodeName {
testcase.t.Errorf("Unexpected DiskIsAttached call: expected nodeName %s, got %s", expected.nodeName, nodeName)
return false, diskName, fmt.Errorf(`unexpected DiskIsAttached call: %w`, nodeNameErr)
}
klog.V(4).Infof("DiskIsAttached call: %s, %s, returning %v, %v", diskName, nodeName, expected.isAttached, expected.ret)
return expected.isAttached, diskName, expected.ret
}
func (testcase *testcase) DisksAreAttached(nodeVolumes map[types.NodeName][]string) (map[types.NodeName]map[string]bool, error) {
return nil, errors.New("not implemented")
}
func (testcase *testcase) CreateVolume(volumeOptions *vclib.VolumeOptions) (volumePath string, err error) {
return "", errors.New("not implemented")
}
func (testcase *testcase) DeleteVolume(vmDiskPath string) error {
return errors.New("not implemented")
}