From cebc0af62e2827bd2e97a0f0b4691c1dacdf52ed Mon Sep 17 00:00:00 2001 From: Christopher Zell Date: Tue, 22 Nov 2022 08:20:11 +0100 Subject: [PATCH 1/4] feat: create instance for specific version Allow to create a process instance for given version and process ID --- go-chaos/cmd/verify.go | 70 ++++++++++++++++++++++++++---------------- 1 file changed, 43 insertions(+), 27 deletions(-) diff --git a/go-chaos/cmd/verify.go b/go-chaos/cmd/verify.go index fb189fd36..70bdfd806 100644 --- a/go-chaos/cmd/verify.go +++ b/go-chaos/cmd/verify.go @@ -19,11 +19,17 @@ import ( "fmt" "time" + "github.com/camunda/zeebe/clients/go/v8/pkg/commands" "github.com/camunda/zeebe/clients/go/v8/pkg/zbc" "github.com/spf13/cobra" "github.com/zeebe-io/zeebe-chaos/go-chaos/internal" ) +var ( + version int + bpmnProcessId string +) + func init() { rootCmd.AddCommand(verifyCmd) verifyCmd.AddCommand(verifyReadinessCmd) @@ -33,6 +39,8 @@ func init() { verifySteadyStateCmd.Flags().StringVar(&processModelPath, "processModelPath", "", "Specify the path to a BPMN process model, which should be deployed and an instance should be created of.") verifySteadyStateCmd.Flags().StringVar(&variables, "variables", "", "Specify the variables for the process instance. Expect json string.") verifySteadyStateCmd.Flags().BoolVar(&awaitResult, "awaitResult", false, "Specify whether the completion of the created process instance should be awaited.") + verifySteadyStateCmd.Flags().IntVar(&version, "version", -1, "Specify the version for which the instance should be created.") + verifySteadyStateCmd.Flags().StringVar(&bpmnProcessId, "bpmnProcessId", "", "Specify the BPMN process ID for which the instance should be created.") } var verifyCmd = &cobra.Command{ @@ -48,14 +56,10 @@ var verifyReadinessCmd = &cobra.Command{ Run: func(cmd *cobra.Command, args []string) { k8Client, err := internal.CreateK8Client() - if err != nil { - panic(err) - } + ensureNoError(err) err = k8Client.AwaitReadiness() - if err != nil { - panic(err.Error()) - } + ensureNoError(err) fmt.Printf("All Zeebe nodes are running.\n") }, @@ -68,48 +72,60 @@ var verifySteadyStateCmd = &cobra.Command{ A process model will be deployed and process instances are created until the required partition is reached.`, Run: func(cmd *cobra.Command, args []string) { k8Client, err := internal.CreateK8Client() - if err != nil { - panic(err) - } + ensureNoError(err) port := 26500 closeFn := k8Client.MustGatewayPortForward(port, port) defer closeFn() zbClient, err := internal.CreateZeebeClient(port) - if err != nil { - panic(err.Error()) - } + ensureNoError(err) defer zbClient.Close() - processDefinitionKey, err := internal.DeployModel(zbClient, processModelPath) - if err != nil { - panic(err.Error()) - } - - err = internal.CreateProcessInstanceOnPartition(func() (int64, error) { - return createInstance(zbClient, processDefinitionKey) - }, int32(partitionId), 30*time.Second) - if err != nil { - panic(err.Error()) - } + processInstanceCreator := createProcessInstanceCreator(zbClient) + err = internal.CreateProcessInstanceOnPartition(processInstanceCreator, int32(partitionId), 30*time.Second) + ensureNoError(err) fmt.Printf("The steady-state was successfully verified!\n") }, } -func createInstance(zbClient zbc.Client, processDefinitionKey int64) (int64, error) { - if Verbose { - fmt.Printf("Create process instance with defition key %d [variables: '%s', awaitResult: %t]\n", processDefinitionKey, variables, awaitResult) +func createProcessInstanceCreator(zbClient zbc.Client) internal.ProcessInstanceCreator { + var processInstanceCreator internal.ProcessInstanceCreator + if version > 0 { + if Verbose { + fmt.Printf("Create process instance with BPMN process ID %s and version %d [variables: '%s', awaitResult: %t]\n", bpmnProcessId, version, variables, awaitResult) + } + + processInstanceCreator = func() (int64, error) { + commandStep3 := zbClient.NewCreateInstanceCommand().BPMNProcessId(bpmnProcessId).Version(int32(version)) + return createInstanceWithCommand(commandStep3) + } + } else { + processDefinitionKey, err := internal.DeployModel(zbClient, processModelPath) + ensureNoError(err) + + if Verbose { + fmt.Printf("Create process instance with defition key %d [variables: '%s', awaitResult: %t]\n", processDefinitionKey, variables, awaitResult) + } + + processInstanceCreator = func() (int64, error) { + commandStep3 := zbClient.NewCreateInstanceCommand().ProcessDefinitionKey(processDefinitionKey) + + return createInstanceWithCommand(commandStep3) + } } + return processInstanceCreator +} - commandStep3 := zbClient.NewCreateInstanceCommand().ProcessDefinitionKey(processDefinitionKey) +func createInstanceWithCommand(commandStep3 commands.CreateInstanceCommandStep3) (int64, error) { if len(variables) != 0 { _, err := commandStep3.VariablesFromString(variables) if err != nil { return 0, err } } + if awaitResult { instanceWithResultResponse, err := commandStep3.WithResult().Send(context.TODO()) if err != nil { From a095a98ab775cabe4bd938129a2ab7623ac3b6b8 Mon Sep 17 00:00:00 2001 From: Christopher Zell Date: Tue, 22 Nov 2022 09:05:59 +0100 Subject: [PATCH 2/4] test: add fake for ZeebeClient Add fake implementation of the Zeebe client. Can be used for unit tests to verify whether the right properties are set. Should be continously extended to increase test coverage. --- go-chaos/internal/fake.go | 81 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 81 insertions(+) create mode 100644 go-chaos/internal/fake.go diff --git a/go-chaos/internal/fake.go b/go-chaos/internal/fake.go new file mode 100644 index 000000000..2a95a6b44 --- /dev/null +++ b/go-chaos/internal/fake.go @@ -0,0 +1,81 @@ +// Copyright 2022 Camunda Services GmbH +// +// 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 internal + +import ( + "context" + + "github.com/camunda/zeebe/clients/go/v8/pkg/commands" + "github.com/camunda/zeebe/clients/go/v8/pkg/pb" + "github.com/camunda/zeebe/clients/go/v8/pkg/zbc" +) + +/* +Fake implementation of the Zeebe client. + +Can be used for unit tests to verify whether the right properties are set. Should be continously extended to +increase test coverage. +*/ +type FakeClient struct { + zbc.Client + commands.CreateInstanceCommandStep1 + commands.CreateInstanceCommandStep2 + commands.CreateInstanceCommandStep3 + commands.DispatchCreateInstanceCommand + + fakeResultCommand FakeResultCommand + + processId string + version int32 + vars string + awaitResult bool +} + +type FakeResultCommand struct { + commands.CreateInstanceWithResultCommandStep1 + commands.DispatchCreateInstanceWithResultCommand +} + +func (f *FakeClient) NewCreateInstanceCommand() commands.CreateInstanceCommandStep1 { + return f +} + +func (f *FakeClient) BPMNProcessId(id string) commands.CreateInstanceCommandStep2 { + f.processId = id + return f +} + +func (f *FakeClient) Version(v int32) commands.CreateInstanceCommandStep3 { + f.version = v + return f +} + +func (f *FakeClient) VariablesFromString(json string) (commands.CreateInstanceCommandStep3, error) { + f.vars = json + return f, nil +} + +func (f *FakeClient) WithResult() commands.CreateInstanceWithResultCommandStep1 { + f.awaitResult = true + return &f.fakeResultCommand +} + +func (f *FakeClient) Send(ctx context.Context) (*pb.CreateProcessInstanceResponse, error) { + return &pb.CreateProcessInstanceResponse{ProcessInstanceKey: 0xCAFE}, nil +} + +func (f *FakeResultCommand) Send(ctx context.Context) (*pb.CreateProcessInstanceWithResultResponse, error) { + return &pb.CreateProcessInstanceWithResultResponse{ProcessInstanceKey: 0xCAFE}, nil +} From fb5ab75da6309fa77f25a8eb2fe1a5c825db1a85 Mon Sep 17 00:00:00 2001 From: Christopher Zell Date: Tue, 22 Nov 2022 09:07:06 +0100 Subject: [PATCH 3/4] refactor: move code to create PI Move the code for creating the process instances to the internal package --- go-chaos/cmd/verify.go | 62 +++++--------------------------------- go-chaos/internal/zeebe.go | 62 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 70 insertions(+), 54 deletions(-) diff --git a/go-chaos/cmd/verify.go b/go-chaos/cmd/verify.go index 70bdfd806..e5377793e 100644 --- a/go-chaos/cmd/verify.go +++ b/go-chaos/cmd/verify.go @@ -15,12 +15,9 @@ package cmd import ( - "context" "fmt" "time" - "github.com/camunda/zeebe/clients/go/v8/pkg/commands" - "github.com/camunda/zeebe/clients/go/v8/pkg/zbc" "github.com/spf13/cobra" "github.com/zeebe-io/zeebe-chaos/go-chaos/internal" ) @@ -82,60 +79,17 @@ A process model will be deployed and process instances are created until the req ensureNoError(err) defer zbClient.Close() - processInstanceCreator := createProcessInstanceCreator(zbClient) + processInstanceCreator, err := internal.CreateProcessInstanceCreator(zbClient, internal.ProcessInstanceCreationOptions{ + BpmnProcessId: bpmnProcessId, + Version: int32(version), + ProcessModelPath: processModelPath, + AwaitResult: awaitResult, + Variables: variables, + }) + ensureNoError(err) err = internal.CreateProcessInstanceOnPartition(processInstanceCreator, int32(partitionId), 30*time.Second) ensureNoError(err) fmt.Printf("The steady-state was successfully verified!\n") }, } - -func createProcessInstanceCreator(zbClient zbc.Client) internal.ProcessInstanceCreator { - var processInstanceCreator internal.ProcessInstanceCreator - if version > 0 { - if Verbose { - fmt.Printf("Create process instance with BPMN process ID %s and version %d [variables: '%s', awaitResult: %t]\n", bpmnProcessId, version, variables, awaitResult) - } - - processInstanceCreator = func() (int64, error) { - commandStep3 := zbClient.NewCreateInstanceCommand().BPMNProcessId(bpmnProcessId).Version(int32(version)) - return createInstanceWithCommand(commandStep3) - } - } else { - processDefinitionKey, err := internal.DeployModel(zbClient, processModelPath) - ensureNoError(err) - - if Verbose { - fmt.Printf("Create process instance with defition key %d [variables: '%s', awaitResult: %t]\n", processDefinitionKey, variables, awaitResult) - } - - processInstanceCreator = func() (int64, error) { - commandStep3 := zbClient.NewCreateInstanceCommand().ProcessDefinitionKey(processDefinitionKey) - - return createInstanceWithCommand(commandStep3) - } - } - return processInstanceCreator -} - -func createInstanceWithCommand(commandStep3 commands.CreateInstanceCommandStep3) (int64, error) { - if len(variables) != 0 { - _, err := commandStep3.VariablesFromString(variables) - if err != nil { - return 0, err - } - } - - if awaitResult { - instanceWithResultResponse, err := commandStep3.WithResult().Send(context.TODO()) - if err != nil { - return 0, err - } - return instanceWithResultResponse.ProcessInstanceKey, nil - } - instanceResponse, err := commandStep3.Send(context.TODO()) - if err != nil { - return 0, err - } - return instanceResponse.ProcessInstanceKey, nil -} diff --git a/go-chaos/internal/zeebe.go b/go-chaos/internal/zeebe.go index ac0ba799d..6f0da5c63 100644 --- a/go-chaos/internal/zeebe.go +++ b/go-chaos/internal/zeebe.go @@ -22,6 +22,7 @@ import ( "os" "time" + "github.com/camunda/zeebe/clients/go/v8/pkg/commands" "github.com/camunda/zeebe/clients/go/v8/pkg/pb" "github.com/camunda/zeebe/clients/go/v8/pkg/zbc" "google.golang.org/grpc" @@ -257,6 +258,67 @@ func readBPMNFileOrDefault(fileName string) ([]byte, string, error) { return bpmnBytes, fileName, nil } +type ProcessInstanceCreationOptions struct { + Version int32 + BpmnProcessId string + ProcessModelPath string + Variables string + AwaitResult bool +} + +func CreateProcessInstanceCreator(zbClient zbc.Client, options ProcessInstanceCreationOptions) (ProcessInstanceCreator, error) { + var processInstanceCreator ProcessInstanceCreator + if options.Version > 0 { + if Verbosity { + fmt.Printf("Create process instance with BPMN process ID %s and version %d [variables: '%s', awaitResult: %t]\n", + options.BpmnProcessId, options.Version, options.Variables, options.AwaitResult) + } + + processInstanceCreator = func() (int64, error) { + commandStep3 := zbClient.NewCreateInstanceCommand().BPMNProcessId(options.BpmnProcessId).Version(int32(options.Version)) + return createInstanceWithCommand(commandStep3, options) + } + } else { + processDefinitionKey, err := DeployModel(zbClient, options.ProcessModelPath) + if err != nil { + return nil, err + } + + if Verbosity { + fmt.Printf("Create process instance with defition key %d [variables: '%s', awaitResult: %t]\n", processDefinitionKey, options.Variables, options.AwaitResult) + } + + processInstanceCreator = func() (int64, error) { + commandStep3 := zbClient.NewCreateInstanceCommand().ProcessDefinitionKey(processDefinitionKey) + + return createInstanceWithCommand(commandStep3, options) + } + } + return processInstanceCreator, nil +} + +func createInstanceWithCommand(commandStep3 commands.CreateInstanceCommandStep3, options ProcessInstanceCreationOptions) (int64, error) { + if len(options.Variables) != 0 { + _, err := commandStep3.VariablesFromString(options.Variables) + if err != nil { + return 0, err + } + } + + if options.AwaitResult { + instanceWithResultResponse, err := commandStep3.WithResult().Send(context.TODO()) + if err != nil { + return 0, err + } + return instanceWithResultResponse.ProcessInstanceKey, nil + } + instanceResponse, err := commandStep3.Send(context.TODO()) + if err != nil { + return 0, err + } + return instanceResponse.ProcessInstanceKey, nil +} + type ProcessInstanceCreator func() (int64, error) func CreateProcessInstanceOnPartition(piCreator ProcessInstanceCreator, requiredPartition int32, timeout time.Duration) error { From 965f96adf60efed215747690b3d601362daf6c38 Mon Sep 17 00:00:00 2001 From: Christopher Zell Date: Tue, 22 Nov 2022 09:07:48 +0100 Subject: [PATCH 4/4] test: new tests for PI creation Use the new fake implementation to test the PI creation Right now the deployment is hard to test, since it doesn't return interfaces --- go-chaos/internal/zeebe_test.go | 52 +++++++++++++++++++++++++++++++++ 1 file changed, 52 insertions(+) diff --git a/go-chaos/internal/zeebe_test.go b/go-chaos/internal/zeebe_test.go index 327cf3675..aa709e893 100644 --- a/go-chaos/internal/zeebe_test.go +++ b/go-chaos/internal/zeebe_test.go @@ -22,6 +22,7 @@ import ( "github.com/camunda/zeebe/clients/go/v8/pkg/pb" "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" ) func Test_ExtractNodeId(t *testing.T) { @@ -327,3 +328,54 @@ func Test_ShouldReadGivenFile(t *testing.T) { err = os.RemoveAll(fileName) assert.NoError(t, err) } + +func Test_ShouldSetVersionAndProcessIdWhenUsingPICreator(t *testing.T) { + // given + options := ProcessInstanceCreationOptions{BpmnProcessId: "processId", Version: 10} + fakeClient := &FakeClient{} + creator, err := CreateProcessInstanceCreator(fakeClient, options) + require.NoError(t, err) + + // when + processInstanceKey, err := creator() + + // then + assert.Equal(t, int64(0xCAFE), processInstanceKey) + assert.Equal(t, int32(10), fakeClient.version) + assert.Equal(t, "processId", fakeClient.processId) +} + +func Test_ShouldSetVariablesForVersionAndProcessIdWhenUsingPICreator(t *testing.T) { + // given + options := ProcessInstanceCreationOptions{BpmnProcessId: "processId", Version: 10, Variables: "{\"foo\":123}"} + fakeClient := &FakeClient{} + creator, err := CreateProcessInstanceCreator(fakeClient, options) + require.NoError(t, err) + + // when + processInstanceKey, err := creator() + + // then + assert.Equal(t, int64(0xCAFE), processInstanceKey) + assert.Equal(t, int32(10), fakeClient.version) + assert.Equal(t, "processId", fakeClient.processId) + assert.Equal(t, "{\"foo\":123}", fakeClient.vars) +} + +func Test_ShouldAwaitResultForProcessInstanceWithVersionAndProcessIdWhenUsingPICreator(t *testing.T) { + // given + options := ProcessInstanceCreationOptions{BpmnProcessId: "processId", Version: 10, Variables: "{\"foo\":123}", AwaitResult: true} + fakeClient := &FakeClient{} + creator, err := CreateProcessInstanceCreator(fakeClient, options) + require.NoError(t, err) + + // when + processInstanceKey, err := creator() + + // then + assert.Equal(t, int64(0xCAFE), processInstanceKey) + assert.Equal(t, int32(10), fakeClient.version) + assert.Equal(t, "processId", fakeClient.processId) + assert.Equal(t, "{\"foo\":123}", fakeClient.vars) + assert.True(t, fakeClient.awaitResult) +}