github.com/iqoqo/nomad@v0.11.3-0.20200911112621-d7021c74d101/client/pluginmanager/drivermanager/instance_test.go (about) 1 package drivermanager 2 3 import ( 4 "context" 5 "fmt" 6 "testing" 7 8 log "github.com/hashicorp/go-hclog" 9 "github.com/hashicorp/go-plugin" 10 "github.com/hashicorp/nomad/helper/pluginutils/loader" 11 "github.com/hashicorp/nomad/helper/pluginutils/singleton" 12 "github.com/hashicorp/nomad/helper/testlog" 13 "github.com/hashicorp/nomad/plugins/base" 14 dtu "github.com/hashicorp/nomad/plugins/drivers/testutils" 15 "github.com/stretchr/testify/mock" 16 "github.com/stretchr/testify/require" 17 ) 18 19 type mockedCatalog struct { 20 mock.Mock 21 } 22 23 func (m *mockedCatalog) Dispense(name, pluginType string, cfg *base.AgentConfig, logger log.Logger) (loader.PluginInstance, error) { 24 args := m.Called(name, pluginType, cfg, logger) 25 return loader.MockBasicExternalPlugin(&dtu.MockDriver{}, "0.1.0"), args.Error(0) 26 } 27 28 func (m *mockedCatalog) Reattach(name, pluginType string, config *plugin.ReattachConfig) (loader.PluginInstance, error) { 29 args := m.Called(name, pluginType, config) 30 return loader.MockBasicExternalPlugin(&dtu.MockDriver{}, "0.1.0"), args.Error(0) 31 } 32 33 func (m *mockedCatalog) Catalog() map[string][]*base.PluginInfoResponse { 34 m.Called() 35 return map[string][]*base.PluginInfoResponse{ 36 base.PluginTypeDriver: {&base.PluginInfoResponse{Name: "mock", Type: base.PluginTypeDriver}}, 37 } 38 } 39 40 func (m *mockedCatalog) resetMock() { 41 m.ExpectedCalls = []*mock.Call{} 42 m.Calls = []mock.Call{} 43 } 44 45 func TestInstanceManager_dispense(t *testing.T) { 46 ctx, cancel := context.WithCancel(context.Background()) 47 cat := new(mockedCatalog) 48 cat.Test(t) 49 var fetchRet bool 50 i := &instanceManager{ 51 logger: testlog.HCLogger(t), 52 ctx: ctx, 53 cancel: cancel, 54 loader: cat, 55 storeReattach: func(*plugin.ReattachConfig) error { return nil }, 56 fetchReattach: func() (*plugin.ReattachConfig, bool) { return nil, fetchRet }, 57 pluginConfig: &base.AgentConfig{}, 58 id: &loader.PluginID{Name: "mock", PluginType: base.PluginTypeDriver}, 59 updateNodeFromDriver: noopUpdater, 60 eventHandlerFactory: noopEventHandlerFactory, 61 firstFingerprintCh: make(chan struct{}), 62 } 63 require := require.New(t) 64 65 // First test the happy path, no reattach config is stored, plugin dispenses without error 66 fetchRet = false 67 cat.On("Dispense", mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(nil) 68 plug, err := i.dispense() 69 require.NoError(err) 70 cat.AssertNumberOfCalls(t, "Dispense", 1) 71 cat.AssertNumberOfCalls(t, "Reattach", 0) 72 73 // Dispensing a second time should not dispense a new plugin from the catalog, but reuse the existing 74 plug2, err := i.dispense() 75 require.NoError(err) 76 cat.AssertNumberOfCalls(t, "Dispense", 1) 77 cat.AssertNumberOfCalls(t, "Reattach", 0) 78 require.Same(plug, plug2) 79 80 // If the plugin has exited test that the manager attempts to retry dispense 81 cat.resetMock() 82 i.plugin = nil 83 cat.On("Dispense", mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(singleton.SingletonPluginExited) 84 _, err = i.dispense() 85 require.Error(err) 86 cat.AssertNumberOfCalls(t, "Dispense", 2) 87 cat.AssertNumberOfCalls(t, "Reattach", 0) 88 89 // Test that when a reattach config exists it attempts plugin reattachment 90 // First case is when plugin reattachment is successful 91 fetchRet = true 92 cat.resetMock() 93 i.plugin = nil 94 cat.On("Dispense", mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(nil) 95 cat.On("Reattach", mock.Anything, mock.Anything, mock.Anything).Return(nil) 96 plug, err = i.dispense() 97 require.NoError(err) 98 cat.AssertNumberOfCalls(t, "Dispense", 0) 99 cat.AssertNumberOfCalls(t, "Reattach", 1) 100 // Dispensing a second time should not dispense a new plugin from the catalog 101 plug2, err = i.dispense() 102 require.NoError(err) 103 cat.AssertNumberOfCalls(t, "Dispense", 0) 104 cat.AssertNumberOfCalls(t, "Reattach", 1) 105 require.Same(plug, plug2) 106 107 // Finally test when reattachment fails. A new plugin should be dispensed 108 cat.resetMock() 109 i.plugin = nil 110 cat.On("Dispense", mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(nil) 111 cat.On("Reattach", mock.Anything, mock.Anything, mock.Anything).Return(fmt.Errorf("failed to dispense")) 112 plug, err = i.dispense() 113 require.NoError(err) 114 cat.AssertNumberOfCalls(t, "Dispense", 1) 115 cat.AssertNumberOfCalls(t, "Reattach", 1) 116 // Dispensing a second time should not dispense a new plugin from the catalog 117 plug2, err = i.dispense() 118 require.NoError(err) 119 cat.AssertNumberOfCalls(t, "Dispense", 1) 120 cat.AssertNumberOfCalls(t, "Reattach", 1) 121 require.Same(plug, plug2) 122 123 }