From 67552a8f6e0133829b9ef0c34f784b177f5c8153 Mon Sep 17 00:00:00 2001 From: Yecheng Fu Date: Tue, 11 Dec 2018 13:02:52 +0800 Subject: [PATCH] Add unit test to verify generated volume names. --- .../cache/desired_state_of_world_test.go | 162 ++++++++++++++++++ pkg/volume/testing/testing.go | 88 ++++++++++ 2 files changed, 250 insertions(+) diff --git a/pkg/kubelet/volumemanager/cache/desired_state_of_world_test.go b/pkg/kubelet/volumemanager/cache/desired_state_of_world_test.go index 42707169d92..b7df006316e 100644 --- a/pkg/kubelet/volumemanager/cache/desired_state_of_world_test.go +++ b/pkg/kubelet/volumemanager/cache/desired_state_of_world_test.go @@ -117,6 +117,168 @@ func Test_AddPodToVolume_Positive_ExistingPodExistingVolume(t *testing.T) { verifyVolumeExistsWithSpecNameInVolumeDsw(t, podName, volumeSpec.Name(), dsw) } +// Call AddPodToVolume() on different pods for different kinds of volumes +// Verities generated names are same for different pods if volume is device mountable or attachable +// Verities generated names are different for different pods if volume is not device mountble and attachable +func Test_AddPodToVolume_Positive_NamesForDifferentPodsAndDifferentVolumes(t *testing.T) { + // Arrange + fakeVolumeHost := volumetesting.NewFakeVolumeHost( + "", /* rootDir */ + nil, /* kubeClient */ + nil, /* plugins */ + ) + plugins := []volume.VolumePlugin{ + &volumetesting.FakeBasicVolumePlugin{ + Plugin: volumetesting.FakeVolumePlugin{ + PluginName: "basic", + }, + }, + &volumetesting.FakeDeviceMountableVolumePlugin{ + FakeBasicVolumePlugin: volumetesting.FakeBasicVolumePlugin{ + Plugin: volumetesting.FakeVolumePlugin{ + PluginName: "device-mountable", + }, + }, + }, + &volumetesting.FakeAttachableVolumePlugin{ + FakeDeviceMountableVolumePlugin: volumetesting.FakeDeviceMountableVolumePlugin{ + FakeBasicVolumePlugin: volumetesting.FakeBasicVolumePlugin{ + Plugin: volumetesting.FakeVolumePlugin{ + PluginName: "attachable", + }, + }, + }, + }, + } + volumePluginMgr := volume.VolumePluginMgr{} + volumePluginMgr.InitPlugins(plugins, nil /* prober */, fakeVolumeHost) + dsw := NewDesiredStateOfWorld(&volumePluginMgr) + + testcases := map[string]struct { + pod1 *v1.Pod + pod2 *v1.Pod + same bool + }{ + "basic": { + &v1.Pod{ + ObjectMeta: metav1.ObjectMeta{ + Name: "pod1", + UID: "pod1uid", + }, + Spec: v1.PodSpec{ + Volumes: []v1.Volume{ + { + Name: "basic", + VolumeSource: v1.VolumeSource{}, + }, + }, + }, + }, + &v1.Pod{ + ObjectMeta: metav1.ObjectMeta{ + Name: "pod2", + UID: "pod2uid", + }, + Spec: v1.PodSpec{ + Volumes: []v1.Volume{ + { + Name: "basic", + VolumeSource: v1.VolumeSource{}, + }, + }, + }, + }, + false, + }, + "device-mountable": { + &v1.Pod{ + ObjectMeta: metav1.ObjectMeta{ + Name: "pod1", + UID: "pod1uid", + }, + Spec: v1.PodSpec{ + Volumes: []v1.Volume{ + { + Name: "device-mountable", + VolumeSource: v1.VolumeSource{}, + }, + }, + }, + }, + &v1.Pod{ + ObjectMeta: metav1.ObjectMeta{ + Name: "pod2", + UID: "pod2uid", + }, + Spec: v1.PodSpec{ + Volumes: []v1.Volume{ + { + Name: "device-mountable", + VolumeSource: v1.VolumeSource{}, + }, + }, + }, + }, + true, + }, + "attachable": { + &v1.Pod{ + ObjectMeta: metav1.ObjectMeta{ + Name: "pod1", + UID: "pod1uid", + }, + Spec: v1.PodSpec{ + Volumes: []v1.Volume{ + { + Name: "attachable", + VolumeSource: v1.VolumeSource{}, + }, + }, + }, + }, + &v1.Pod{ + ObjectMeta: metav1.ObjectMeta{ + Name: "pod2", + UID: "pod2uid", + }, + Spec: v1.PodSpec{ + Volumes: []v1.Volume{ + { + Name: "attachable", + VolumeSource: v1.VolumeSource{}, + }, + }, + }, + }, + true, + }, + } + + // Act & Assert + for name, v := range testcases { + volumeSpec1 := &volume.Spec{Volume: &v.pod1.Spec.Volumes[0]} + volumeSpec2 := &volume.Spec{Volume: &v.pod2.Spec.Volumes[0]} + generatedVolumeName1, err1 := dsw.AddPodToVolume(util.GetUniquePodName(v.pod1), v.pod1, volumeSpec1, volumeSpec1.Name(), "") + generatedVolumeName2, err2 := dsw.AddPodToVolume(util.GetUniquePodName(v.pod2), v.pod2, volumeSpec2, volumeSpec2.Name(), "") + if err1 != nil { + t.Fatalf("test %q: AddPodToVolume failed. Expected: Actual: <%v>", name, err1) + } + if err2 != nil { + t.Fatalf("test %q: AddPodToVolume failed. Expected: Actual: <%v>", name, err2) + } + if v.same { + if generatedVolumeName1 != generatedVolumeName2 { + t.Fatalf("test %q: AddPodToVolume should generate same names, but got %q != %q", name, generatedVolumeName1, generatedVolumeName2) + } + } else { + if generatedVolumeName1 == generatedVolumeName2 { + t.Fatalf("test %q: AddPodToVolume should generate different names, but got %q == %q", name, generatedVolumeName1, generatedVolumeName2) + } + } + } + +} + // Populates data struct with a new volume/pod // Calls DeletePodFromVolume() to removes the pod // Verifies newly added pod/volume are deleted diff --git a/pkg/volume/testing/testing.go b/pkg/volume/testing/testing.go index 4c116aa5934..2791d9bd910 100644 --- a/pkg/volume/testing/testing.go +++ b/pkg/volume/testing/testing.go @@ -504,6 +504,94 @@ func (plugin *FakeVolumePlugin) VolumeLimitKey(spec *Spec) string { return plugin.LimitKey } +// FakeBasicVolumePlugin implements a basic volume plugin. It wrappers on +// FakeVolumePlugin but implements VolumePlugin interface only. +// It is useful to test logic involving plugin interfaces. +type FakeBasicVolumePlugin struct { + Plugin FakeVolumePlugin +} + +func (f *FakeBasicVolumePlugin) GetPluginName() string { + return f.Plugin.GetPluginName() +} + +func (f *FakeBasicVolumePlugin) GetVolumeName(spec *Spec) (string, error) { + return f.Plugin.GetVolumeName(spec) +} + +// CanSupport tests whether the plugin supports a given volume specification by +// testing volume spec name begins with plugin name or not. +// This is useful to choose plugin by volume in testing. +func (f *FakeBasicVolumePlugin) CanSupport(spec *Spec) bool { + return strings.HasPrefix(spec.Name(), f.GetPluginName()) +} + +func (f *FakeBasicVolumePlugin) ConstructVolumeSpec(ame, mountPath string) (*Spec, error) { + return f.Plugin.ConstructVolumeSpec(ame, mountPath) +} + +func (f *FakeBasicVolumePlugin) Init(ost VolumeHost) error { + return f.Plugin.Init(ost) +} + +func (f *FakeBasicVolumePlugin) NewMounter(spec *Spec, pod *v1.Pod, opts VolumeOptions) (Mounter, error) { + return f.Plugin.NewMounter(spec, pod, opts) +} + +func (f *FakeBasicVolumePlugin) NewUnmounter(volName string, podUID types.UID) (Unmounter, error) { + return f.Plugin.NewUnmounter(volName, podUID) +} + +func (f *FakeBasicVolumePlugin) RequiresRemount() bool { + return f.Plugin.RequiresRemount() +} + +func (f *FakeBasicVolumePlugin) SupportsBulkVolumeVerification() bool { + return f.Plugin.SupportsBulkVolumeVerification() +} + +func (f *FakeBasicVolumePlugin) SupportsMountOption() bool { + return f.Plugin.SupportsMountOption() +} + +var _ VolumePlugin = &FakeBasicVolumePlugin{} + +// FakeDeviceMountableVolumePlugin implements an device mountable plugin based on FakeBasicVolumePlugin. +type FakeDeviceMountableVolumePlugin struct { + FakeBasicVolumePlugin +} + +func (f *FakeDeviceMountableVolumePlugin) NewDeviceMounter() (DeviceMounter, error) { + return f.Plugin.NewDeviceMounter() +} + +func (f *FakeDeviceMountableVolumePlugin) NewDeviceUnmounter() (DeviceUnmounter, error) { + return f.Plugin.NewDeviceUnmounter() +} + +func (f *FakeDeviceMountableVolumePlugin) GetDeviceMountRefs(deviceMountPath string) ([]string, error) { + return f.Plugin.GetDeviceMountRefs(deviceMountPath) +} + +var _ VolumePlugin = &FakeDeviceMountableVolumePlugin{} +var _ DeviceMountableVolumePlugin = &FakeDeviceMountableVolumePlugin{} + +// FakeAttachableVolumePlugin implements an attachable plugin based on FakeDeviceMountableVolumePlugin. +type FakeAttachableVolumePlugin struct { + FakeDeviceMountableVolumePlugin +} + +func (f *FakeAttachableVolumePlugin) NewAttacher() (Attacher, error) { + return f.Plugin.NewAttacher() +} + +func (f *FakeAttachableVolumePlugin) NewDetacher() (Detacher, error) { + return f.Plugin.NewDetacher() +} + +var _ VolumePlugin = &FakeAttachableVolumePlugin{} +var _ AttachableVolumePlugin = &FakeAttachableVolumePlugin{} + type FakeFileVolumePlugin struct { }