123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329 |
- /*
- Copyright 2017 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 flexvolume
- import (
- "fmt"
- "path/filepath"
- "testing"
- "github.com/fsnotify/fsnotify"
- "github.com/stretchr/testify/assert"
- utilfs "k8s.io/kubernetes/pkg/util/filesystem"
- "k8s.io/kubernetes/pkg/volume"
- "k8s.io/utils/exec"
- )
- const (
- pluginDir = "/flexvolume"
- driverName = "fake-driver"
- )
- // Probes a driver installed before prober initialization.
- func TestProberExistingDriverBeforeInit(t *testing.T) {
- // Arrange
- driverPath, _, watcher, prober := initTestEnvironment(t)
- // Act
- events, err := prober.Probe()
- // Assert
- // Probe occurs, 1 plugin should be returned, and 2 watches (pluginDir and all its
- // current subdirectories) registered.
- assert.Equal(t, 1, len(events))
- assert.Equal(t, volume.ProbeAddOrUpdate, events[0].Op)
- assert.Equal(t, pluginDir, watcher.watches[0])
- assert.Equal(t, driverPath, watcher.watches[1])
- assert.NoError(t, err)
- // Should no longer probe.
- // Act
- events, err = prober.Probe()
- // Assert
- assert.Equal(t, 0, len(events))
- assert.NoError(t, err)
- }
- // Probes newly added drivers after prober is running.
- func TestProberAddRemoveDriver(t *testing.T) {
- // Arrange
- _, fs, watcher, prober := initTestEnvironment(t)
- prober.Probe()
- events, err := prober.Probe()
- assert.Equal(t, 0, len(events))
- // Call probe after a file is added. Should return 1 event.
- // add driver
- const driverName2 = "fake-driver2"
- driverPath := filepath.Join(pluginDir, driverName2)
- executablePath := filepath.Join(driverPath, driverName2)
- installDriver(driverName2, fs)
- watcher.TriggerEvent(fsnotify.Create, driverPath)
- watcher.TriggerEvent(fsnotify.Create, executablePath)
- // Act
- events, err = prober.Probe()
- // Assert
- assert.Equal(t, 1, len(events))
- assert.Equal(t, volume.ProbeAddOrUpdate, events[0].Op) // 1 newly added
- assert.Equal(t, driverPath, watcher.watches[len(watcher.watches)-1]) // Checks most recent watch
- assert.NoError(t, err)
- // Call probe again, should return 0 event.
- // Act
- events, err = prober.Probe()
- // Assert
- assert.Equal(t, 0, len(events))
- assert.NoError(t, err)
- // Call probe after a non-driver file is added in a subdirectory. should return 1 event.
- fp := filepath.Join(driverPath, "dummyfile")
- fs.Create(fp)
- watcher.TriggerEvent(fsnotify.Create, fp)
- // Act
- events, err = prober.Probe()
- // Assert
- assert.Equal(t, 1, len(events))
- assert.Equal(t, volume.ProbeAddOrUpdate, events[0].Op)
- assert.NoError(t, err)
- // Call probe again, should return 0 event.
- // Act
- events, err = prober.Probe()
- // Assert
- assert.Equal(t, 0, len(events))
- assert.NoError(t, err)
- // Call probe after a subdirectory is added in a driver directory. should return 1 event.
- subdirPath := filepath.Join(driverPath, "subdir")
- fs.Create(subdirPath)
- watcher.TriggerEvent(fsnotify.Create, subdirPath)
- // Act
- events, err = prober.Probe()
- // Assert
- assert.Equal(t, 1, len(events))
- assert.Equal(t, volume.ProbeAddOrUpdate, events[0].Op)
- assert.NoError(t, err)
- // Call probe again, should return 0 event.
- // Act
- events, err = prober.Probe()
- // Assert
- assert.Equal(t, 0, len(events))
- assert.NoError(t, err)
- // Call probe after a subdirectory is removed in a driver directory. should return 1 event.
- fs.Remove(subdirPath)
- watcher.TriggerEvent(fsnotify.Remove, subdirPath)
- // Act
- events, err = prober.Probe()
- // Assert
- assert.Equal(t, 1, len(events))
- assert.Equal(t, volume.ProbeAddOrUpdate, events[0].Op)
- assert.NoError(t, err)
- // Call probe again, should return 0 event.
- // Act
- events, err = prober.Probe()
- // Assert
- assert.Equal(t, 0, len(events))
- assert.NoError(t, err)
- // Call probe after a driver executable and driver directory is remove. should return 1 event.
- fs.Remove(executablePath)
- fs.Remove(driverPath)
- watcher.TriggerEvent(fsnotify.Remove, executablePath)
- watcher.TriggerEvent(fsnotify.Remove, driverPath)
- // Act and Assert: 1 ProbeRemove event
- events, err = prober.Probe()
- assert.Equal(t, 1, len(events))
- assert.Equal(t, volume.ProbeRemove, events[0].Op)
- assert.NoError(t, err)
- // Act and Assert: 0 event
- events, err = prober.Probe()
- assert.Equal(t, 0, len(events))
- assert.NoError(t, err)
- }
- // Tests the behavior when no drivers exist in the plugin directory.
- func TestEmptyPluginDir(t *testing.T) {
- // Arrange
- fs := utilfs.NewFakeFs()
- watcher := newFakeWatcher()
- prober := &flexVolumeProber{
- pluginDir: pluginDir,
- watcher: watcher,
- fs: fs,
- factory: fakePluginFactory{error: false},
- }
- prober.Init()
- // Act
- events, err := prober.Probe()
- // Assert
- assert.Equal(t, 0, len(events))
- assert.NoError(t, err)
- }
- // Issue an event to remove plugindir. New directory should still be watched.
- func TestRemovePluginDir(t *testing.T) {
- // Arrange
- driverPath, fs, watcher, _ := initTestEnvironment(t)
- fs.RemoveAll(pluginDir)
- watcher.TriggerEvent(fsnotify.Remove, filepath.Join(driverPath, driverName))
- watcher.TriggerEvent(fsnotify.Remove, driverPath)
- watcher.TriggerEvent(fsnotify.Remove, pluginDir)
- // Act: The handler triggered by the above events should have already handled the event appropriately.
- // Assert
- assert.Equal(t, 3, len(watcher.watches)) // 2 from initial setup, 1 from new watch.
- assert.Equal(t, pluginDir, watcher.watches[len(watcher.watches)-1])
- }
- // Issue an event to remove plugindir. New directory should still be watched.
- func TestNestedDriverDir(t *testing.T) {
- // Arrange
- _, fs, watcher, _ := initTestEnvironment(t)
- // Assert
- assert.Equal(t, 2, len(watcher.watches)) // 2 from initial setup
- // test add testDriverName
- testDriverName := "testDriverName"
- testDriverPath := filepath.Join(pluginDir, testDriverName)
- fs.MkdirAll(testDriverPath, 0666)
- watcher.TriggerEvent(fsnotify.Create, testDriverPath)
- // Assert
- assert.Equal(t, 3, len(watcher.watches)) // 2 from initial setup, 1 from new watch.
- assert.Equal(t, testDriverPath, watcher.watches[len(watcher.watches)-1])
- // test add nested subdir inside testDriverName
- basePath := testDriverPath
- for i := 0; i < 10; i++ {
- subdirName := "subdirName"
- subdirPath := filepath.Join(basePath, subdirName)
- fs.MkdirAll(subdirPath, 0666)
- watcher.TriggerEvent(fsnotify.Create, subdirPath)
- // Assert
- assert.Equal(t, 4+i, len(watcher.watches)) // 3 + newly added
- assert.Equal(t, subdirPath, watcher.watches[len(watcher.watches)-1])
- basePath = subdirPath
- }
- }
- // Issue multiple events and probe multiple times.
- func TestProberMultipleEvents(t *testing.T) {
- const iterations = 5
- // Arrange
- _, fs, watcher, prober := initTestEnvironment(t)
- for i := 0; i < iterations; i++ {
- newDriver := fmt.Sprintf("multi-event-driver%d", 1)
- installDriver(newDriver, fs)
- driverPath := filepath.Join(pluginDir, newDriver)
- watcher.TriggerEvent(fsnotify.Create, driverPath)
- watcher.TriggerEvent(fsnotify.Create, filepath.Join(driverPath, newDriver))
- }
- // Act
- events, err := prober.Probe()
- // Assert
- assert.Equal(t, 2, len(events))
- assert.Equal(t, volume.ProbeAddOrUpdate, events[0].Op)
- assert.Equal(t, volume.ProbeAddOrUpdate, events[1].Op)
- assert.NoError(t, err)
- for i := 0; i < iterations-1; i++ {
- events, err = prober.Probe()
- assert.Equal(t, 0, len(events))
- assert.NoError(t, err)
- }
- }
- func TestProberError(t *testing.T) {
- fs := utilfs.NewFakeFs()
- watcher := newFakeWatcher()
- prober := &flexVolumeProber{
- pluginDir: pluginDir,
- watcher: watcher,
- fs: fs,
- factory: fakePluginFactory{error: true},
- }
- installDriver(driverName, fs)
- prober.Init()
- _, err := prober.Probe()
- assert.Error(t, err)
- }
- // Installs a mock driver (an empty file) in the mock fs.
- func installDriver(driverName string, fs utilfs.Filesystem) {
- driverPath := filepath.Join(pluginDir, driverName)
- fs.MkdirAll(driverPath, 0666)
- fs.Create(filepath.Join(driverPath, driverName))
- }
- // Initializes mocks, installs a single driver in the mock fs, then initializes prober.
- func initTestEnvironment(t *testing.T) (
- driverPath string,
- fs utilfs.Filesystem,
- watcher *fakeWatcher,
- prober volume.DynamicPluginProber) {
- fs = utilfs.NewFakeFs()
- watcher = newFakeWatcher()
- prober = &flexVolumeProber{
- pluginDir: pluginDir,
- watcher: watcher,
- fs: fs,
- factory: fakePluginFactory{error: false},
- }
- driverPath = filepath.Join(pluginDir, driverName)
- installDriver(driverName, fs)
- prober.Init()
- assert.NotNilf(t, watcher.eventHandler,
- "Expect watch event handler to be registered after prober init, but is not.")
- return
- }
- // Fake Flexvolume plugin
- type fakePluginFactory struct {
- error bool // Indicates whether an error should be returned.
- }
- var _ PluginFactory = fakePluginFactory{}
- func (m fakePluginFactory) NewFlexVolumePlugin(_, driverName string, _ exec.Interface) (volume.VolumePlugin, error) {
- if m.error {
- return nil, fmt.Errorf("Flexvolume plugin error")
- }
- // Dummy Flexvolume plugin. Prober never interacts with the plugin.
- return &flexVolumePlugin{driverName: driverName}, nil
- }
|