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 }