/* 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 awsebs import ( "errors" "testing" "k8s.io/klog" "k8s.io/api/core/v1" "k8s.io/apimachinery/pkg/api/resource" "k8s.io/apimachinery/pkg/types" "k8s.io/kubernetes/pkg/cloudprovider/providers/aws" "k8s.io/kubernetes/pkg/volume" volumetest "k8s.io/kubernetes/pkg/volume/testing" ) func TestGetVolumeName_Volume(t *testing.T) { plugin := newPlugin() name := aws.KubernetesVolumeID("my-aws-volume") spec := createVolSpec(name, false) volumeName, err := plugin.GetVolumeName(spec) if err != nil { t.Errorf("GetVolumeName error: %v", err) } if volumeName != string(name) { t.Errorf("GetVolumeName error: expected %s, got %s", name, volumeName) } } func TestGetVolumeName_PersistentVolume(t *testing.T) { plugin := newPlugin() name := aws.KubernetesVolumeID("my-aws-pv") spec := createPVSpec(name, true) volumeName, err := plugin.GetVolumeName(spec) if err != nil { t.Errorf("GetVolumeName error: %v", err) } if volumeName != string(name) { t.Errorf("GetVolumeName error: expected %s, got %s", name, volumeName) } } // One testcase for TestAttachDetach table test below type testcase struct { name aws.KubernetesVolumeID // For fake AWS: attach attachCall detach detachCall 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) { diskName := aws.KubernetesVolumeID("disk") nodeName := types.NodeName("instance") spec := createVolSpec(diskName, false) attachError := errors.New("Fake attach error") detachError := errors.New("Fake detach error") tests := []testcase{ // Successful Attach call { name: "Attach_Positive", attach: attachCall{diskName, nodeName, "/dev/sda", nil}, test: func(testcase *testcase) (string, error) { attacher := newAttacher(testcase) return attacher.Attach(spec, nodeName) }, expectedDevice: "/dev/sda", }, // 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", detach: detachCall{diskName, nodeName, "/dev/sda", nil}, test: func(testcase *testcase) (string, error) { detacher := newDetacher(testcase) mountPath := "/mnt/" + string(diskName) return "", detacher.Detach(mountPath, nodeName) }, }, // Detach fails { name: "Detach_Negative", detach: detachCall{diskName, nodeName, "", detachError}, test: func(testcase *testcase) (string, error) { detacher := newDetacher(testcase) mountPath := "/mnt/" + string(diskName) return "", detacher.Detach(mountPath, 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 gcePersistentDiskPlugin with fake cloud, NewAttacher // and NewDetacher won't work. func newPlugin() *awsElasticBlockStorePlugin { host := volumetest.NewFakeVolumeHost("/tmp", nil, nil) plugins := ProbeVolumePlugins() plugin := plugins[0] plugin.Init(host) return plugin.(*awsElasticBlockStorePlugin) } func newAttacher(testcase *testcase) *awsElasticBlockStoreAttacher { return &awsElasticBlockStoreAttacher{ host: nil, awsVolumes: testcase, } } func newDetacher(testcase *testcase) *awsElasticBlockStoreDetacher { return &awsElasticBlockStoreDetacher{ awsVolumes: testcase, } } func createVolSpec(name aws.KubernetesVolumeID, readOnly bool) *volume.Spec { return &volume.Spec{ Volume: &v1.Volume{ VolumeSource: v1.VolumeSource{ AWSElasticBlockStore: &v1.AWSElasticBlockStoreVolumeSource{ VolumeID: string(name), ReadOnly: readOnly, }, }, }, } } func createPVSpec(name aws.KubernetesVolumeID, readOnly bool) *volume.Spec { return &volume.Spec{ PersistentVolume: &v1.PersistentVolume{ Spec: v1.PersistentVolumeSpec{ PersistentVolumeSource: v1.PersistentVolumeSource{ AWSElasticBlockStore: &v1.AWSElasticBlockStoreVolumeSource{ VolumeID: string(name), ReadOnly: readOnly, }, }, }, }, } } // Fake AWS implementation type attachCall struct { diskName aws.KubernetesVolumeID nodeName types.NodeName retDeviceName string ret error } type detachCall struct { diskName aws.KubernetesVolumeID nodeName types.NodeName retDeviceName string ret error } type diskIsAttachedCall struct { diskName aws.KubernetesVolumeID nodeName types.NodeName isAttached bool ret error } func (testcase *testcase) AttachDisk(diskName aws.KubernetesVolumeID, 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 "", errors.New("Unexpected AttachDisk call: wrong diskName") } if expected.nodeName != nodeName { testcase.t.Errorf("Unexpected AttachDisk call: expected nodeName %s, got %s", expected.nodeName, nodeName) return "", errors.New("Unexpected AttachDisk call: wrong nodeName") } klog.V(4).Infof("AttachDisk call: %s, %s, returning %q, %v", diskName, nodeName, expected.retDeviceName, expected.ret) return expected.retDeviceName, expected.ret } func (testcase *testcase) DetachDisk(diskName aws.KubernetesVolumeID, nodeName types.NodeName) (string, 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 "", errors.New("Unexpected DetachDisk call: wrong diskName") } if expected.nodeName != nodeName { testcase.t.Errorf("Unexpected DetachDisk call: expected nodeName %s, got %s", expected.nodeName, nodeName) return "", errors.New("Unexpected DetachDisk call: wrong nodeName") } klog.V(4).Infof("DetachDisk call: %s, %s, returning %q, %v", diskName, nodeName, expected.retDeviceName, expected.ret) return expected.retDeviceName, expected.ret } func (testcase *testcase) DiskIsAttached(diskName aws.KubernetesVolumeID, nodeName types.NodeName) (bool, error) { // DetachDisk no longer relies on DiskIsAttached api call return false, nil } func (testcase *testcase) DisksAreAttached(nodeDisks map[types.NodeName][]aws.KubernetesVolumeID) (map[types.NodeName]map[aws.KubernetesVolumeID]bool, error) { return nil, errors.New("Not implemented") } func (testcase *testcase) CreateDisk(volumeOptions *aws.VolumeOptions) (volumeName aws.KubernetesVolumeID, err error) { return "", errors.New("Not implemented") } func (testcase *testcase) DeleteDisk(volumeName aws.KubernetesVolumeID) (bool, error) { return false, errors.New("Not implemented") } func (testcase *testcase) GetVolumeLabels(volumeName aws.KubernetesVolumeID) (map[string]string, error) { return map[string]string{}, errors.New("Not implemented") } func (testcase *testcase) GetDiskPath(volumeName aws.KubernetesVolumeID) (string, error) { return "", errors.New("Not implemented") } func (testcase *testcase) ResizeDisk( volumeName aws.KubernetesVolumeID, oldSize resource.Quantity, newSize resource.Quantity) (resource.Quantity, error) { return oldSize, errors.New("Not implemented") }