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  }