github.com/ystia/yorc/v4@v4.3.0/plugin/delegate_test.go (about)

     1  // Copyright 2018 Bull S.A.S. Atos Technologies - Bull, Rue Jean Jaures, B.P.68, 78340, Les Clayes-sous-Bois, France.
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at
     6  //
     7  //      http://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  // Unless required by applicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS,
    11  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12  // See the License for the specific language governing permissions and
    13  // limitations under the License.
    14  
    15  package plugin
    16  
    17  import (
    18  	"context"
    19  	"errors"
    20  	"testing"
    21  	"time"
    22  
    23  	plugin "github.com/hashicorp/go-plugin"
    24  	"github.com/stretchr/testify/assert"
    25  	"github.com/stretchr/testify/require"
    26  
    27  	"github.com/ystia/yorc/v4/config"
    28  	"github.com/ystia/yorc/v4/events"
    29  	"github.com/ystia/yorc/v4/prov"
    30  )
    31  
    32  type mockDelegateExecutor struct {
    33  	execDelegateCalled                                bool
    34  	ctx                                               context.Context
    35  	conf                                              config.Configuration
    36  	taskID, deploymentID, nodeName, delegateOperation string
    37  	contextCancelled                                  bool
    38  	lof                                               events.LogOptionalFields
    39  }
    40  
    41  func (m *mockDelegateExecutor) ExecDelegate(ctx context.Context, conf config.Configuration, taskID, deploymentID, nodeName, delegateOperation string) error {
    42  	m.execDelegateCalled = true
    43  	m.ctx = ctx
    44  	m.conf = conf
    45  	m.taskID = taskID
    46  	m.deploymentID = deploymentID
    47  	m.nodeName = nodeName
    48  	m.delegateOperation = delegateOperation
    49  	m.lof, _ = events.FromContext(ctx)
    50  
    51  	go func() {
    52  		<-m.ctx.Done()
    53  		m.contextCancelled = true
    54  	}()
    55  	if m.deploymentID == "TestCancel" {
    56  		<-m.ctx.Done()
    57  	}
    58  
    59  	if m.deploymentID == "TestFailure" {
    60  		return NewRPCError(errors.New("a failure occurred during plugin exec operation"))
    61  	}
    62  	return nil
    63  }
    64  
    65  func createMockDelegateExecutorClient(t *testing.T) (*mockDelegateExecutor, *plugin.RPCClient) {
    66  	mock := new(mockDelegateExecutor)
    67  	client, _ := plugin.TestPluginRPCConn(
    68  		t,
    69  		map[string]plugin.Plugin{
    70  			DelegatePluginName: &DelegatePlugin{F: func() prov.DelegateExecutor {
    71  				return mock
    72  			}},
    73  		},
    74  		nil)
    75  	return mock, client
    76  }
    77  
    78  func setupExecDelegateTestEnv(t *testing.T) (*mockDelegateExecutor, *plugin.RPCClient,
    79  	prov.DelegateExecutor, events.LogOptionalFields, context.Context) {
    80  
    81  	mock, client := createMockDelegateExecutorClient(t)
    82  	raw, err := client.Dispense(DelegatePluginName)
    83  	require.Nil(t, err)
    84  
    85  	delegate := raw.(prov.DelegateExecutor)
    86  
    87  	lof := events.LogOptionalFields{
    88  		events.WorkFlowID:    "testWF",
    89  		events.InterfaceName: "delegate",
    90  		events.OperationName: "myTest",
    91  	}
    92  	ctx := events.NewContext(context.Background(), lof)
    93  
    94  	return mock, client, delegate, lof, ctx
    95  }
    96  
    97  func TestDelegateExecutorExecDelegate(t *testing.T) {
    98  	t.Parallel()
    99  	mock, client, delegate, lof, ctx := setupExecDelegateTestEnv(t)
   100  	defer client.Close()
   101  	err := delegate.ExecDelegate(
   102  		ctx,
   103  		config.Configuration{Consul: config.Consul{Address: "test", Datacenter: "testdc"}},
   104  		"TestTaskID", "TestDepID", "TestNodeName", "TestDelegateOP")
   105  	require.Nil(t, err)
   106  	require.True(t, mock.execDelegateCalled)
   107  	require.Equal(t, "test", mock.conf.Consul.Address)
   108  	require.Equal(t, "testdc", mock.conf.Consul.Datacenter)
   109  	require.Equal(t, "TestTaskID", mock.taskID)
   110  	require.Equal(t, "TestDepID", mock.deploymentID)
   111  	require.Equal(t, "TestNodeName", mock.nodeName)
   112  	require.Equal(t, "TestDelegateOP", mock.delegateOperation)
   113  	assert.Equal(t, lof, mock.lof)
   114  }
   115  
   116  func TestDelegateExecutorExecDelegateWithFailure(t *testing.T) {
   117  	t.Parallel()
   118  	_, client, delegate, _, ctx := setupExecDelegateTestEnv(t)
   119  	defer client.Close()
   120  	err := delegate.ExecDelegate(
   121  		ctx,
   122  		config.Configuration{Consul: config.Consul{Address: "test", Datacenter: "testdc"}},
   123  		"TestTaskID", "TestFailure", "TestNodeName", "TestDelegateOP")
   124  	require.Error(t, err, "An error was expected during executing plugin operation")
   125  	require.EqualError(t, err, "a failure occurred during plugin exec operation")
   126  }
   127  
   128  func TestDelegateExecutorExecDelegateWithCancel(t *testing.T) {
   129  	t.Parallel()
   130  	mock, client := createMockDelegateExecutorClient(t)
   131  	defer client.Close()
   132  
   133  	raw, err := client.Dispense(DelegatePluginName)
   134  	require.Nil(t, err)
   135  
   136  	delegate := raw.(prov.DelegateExecutor)
   137  
   138  	lof := events.LogOptionalFields{
   139  		events.WorkFlowID:    "testWF",
   140  		events.InterfaceName: "delegate",
   141  		events.OperationName: "myTest",
   142  	}
   143  	ctx := events.NewContext(context.Background(), lof)
   144  	ctx, cancelF := context.WithCancel(ctx)
   145  	go func() {
   146  		err = delegate.ExecDelegate(
   147  			ctx,
   148  			config.Configuration{Consul: config.Consul{Address: "test", Datacenter: "testdc"}},
   149  			"TestTaskID", "TestCancel", "TestNodeName", "TestDelegateOP")
   150  		require.Nil(t, err)
   151  	}()
   152  	cancelF()
   153  	// Wait for cancellation signal to be dispatched
   154  	time.Sleep(50 * time.Millisecond)
   155  	require.True(t, mock.contextCancelled, "Context not cancelled")
   156  }
   157  
   158  func TestDelegateGetSupportedTypes(t *testing.T) {
   159  	mock := new(mockDelegateExecutor)
   160  	client, _ := plugin.TestPluginRPCConn(
   161  		t,
   162  		map[string]plugin.Plugin{
   163  			DelegatePluginName: &DelegatePlugin{
   164  				F: func() prov.DelegateExecutor {
   165  					return mock
   166  				},
   167  				SupportedTypes: []string{"tosca.my.types", "test"}},
   168  		},
   169  		nil)
   170  	defer client.Close()
   171  	raw, err := client.Dispense(DelegatePluginName)
   172  	require.Nil(t, err)
   173  	delegateExec := raw.(DelegateExecutor)
   174  
   175  	supportedTypes, err := delegateExec.GetSupportedTypes()
   176  	require.Nil(t, err)
   177  	require.Len(t, supportedTypes, 2)
   178  	require.Contains(t, supportedTypes, "tosca.my.types")
   179  	require.Contains(t, supportedTypes, "test")
   180  
   181  }