diff --git a/modules/cli/docs/generated/errors-list.md b/modules/cli/docs/generated/errors-list.md index 2cc6582a2..b7f22085d 100644 --- a/modules/cli/docs/generated/errors-list.md +++ b/modules/cli/docs/generated/errors-list.md @@ -272,11 +272,16 @@ The `galasactl` tool can generate the following errors: - GAL1270E: Failed to get tags from the Galasa service. Unexpected http status code {} received from the server. Error details from the server are: '{}' - GAL1271E: Failed to get tags from the Galasa service. Unexpected http status code {} received from the server. Error details from the server are not in the json format. - GAL1272E: Failed to get tags from the Galasa service. Sending the put request to the Galasa service failed. Cause is {} -- GAL1273E: User '{}' specified with the --user flag does not have permission to launch tests. -- GAL1274E: Invalid Java method name. Method name should not be blank. Use the --help flag for more information, or refer to the documentation at https://galasa.dev/docs/reference -- GAL1275E: Invalid Java method name '{}' should start with a letter (a-z, A-Z), not '{}'. Use the --help flag for more information, or refer to the documentation at https://galasa.dev/docs/reference -- GAL1276E: Invalid Java method name '{}' should not contain the '{}' character. Use the --help flag for more information, or refer to the documentation at https://galasa.dev/docs/reference -- GAL1277E: Invalid Java method name. Method name '{}' is a reserved Java keyword. Use the --help flag for more information, or refer to the documentation at https://galasa.dev/docs/reference +- GAL1273E: Invalid update request. The tag '{}' cannot be added and deleted in the same command. +- GAL1274E: Invalid update request. The flag '{}' must be used when attempting to update a run. +- GAL1275E: The run named '{}' could not be updated because it was not found by the Galasa service. Try listing runs using 'galasactl runs get' to identify the one you wish to update. +- GAL1276E: Failed to update run. Did not recieve an HTTP response. Cause is {} +- GAL1277E: An attempt to update a run named '{}' failed. Unexpected http status code {} received from the server. +- GAL1278E: An attempt to update a run named '{}' failed. Unexpected http status code {} received from the server. Error details from the server could not be read. Cause: {} +- GAL1279E: An attempt to update a run named '{}' failed. Unexpected http status code {} received from the server. Error details from the server are not in a valid json format. Cause: '{}' +- GAL1280E: An attempt to update a run named '{}' failed. Unexpected http status code {} received from the server. Error details from the server are: '{}' +- GAL1281E: An attempt to update a run named '{}' failed. Unexpected http status code {} received from the server. Error details from the server are not in the json format. +- GAL1282E: Invalid tag name '{}' provided. Tag names cannot be empty and must only contain characters in the Latin-1 character set. - GAL2000W: Warning: Maven configuration file settings.xml should contain a reference to a Galasa repository so that the galasa OBR can be resolved. The official release repository is '{}', and 'pre-release' repository is '{}' - GAL2501I: Downloaded {} artifacts to folder '{}' diff --git a/modules/cli/docs/generated/galasactl_runs.md b/modules/cli/docs/generated/galasactl_runs.md index 1302bddc0..12aa10735 100644 --- a/modules/cli/docs/generated/galasactl_runs.md +++ b/modules/cli/docs/generated/galasactl_runs.md @@ -33,4 +33,5 @@ Assembles, submits and monitors test runs in Galasa Ecosystem * [galasactl runs prepare](galasactl_runs_prepare.md) - prepares a list of tests * [galasactl runs reset](galasactl_runs_reset.md) - reset an active run in the ecosystem * [galasactl runs submit](galasactl_runs_submit.md) - submit a list of tests to the ecosystem +* [galasactl runs update](galasactl_runs_update.md) - Update the record of an existing test run on a Galasa service. diff --git a/modules/cli/docs/generated/galasactl_runs_update.md b/modules/cli/docs/generated/galasactl_runs_update.md new file mode 100644 index 000000000..4624a1a34 --- /dev/null +++ b/modules/cli/docs/generated/galasactl_runs_update.md @@ -0,0 +1,35 @@ +## galasactl runs update + +Update the record of an existing test run on a Galasa service. + +### Synopsis + +Update the record of an existing test run on a Galasa service. + +``` +galasactl runs update [flags] +``` + +### Options + +``` + --add-tags strings Comma-separated list of tags to add. Multiple uses of this flag are permitted. + -h, --help Displays the options for the 'runs update' command. + --name string the name of the test run we want to update + --remove-tags strings Comma-separated list of tags to remove. Multiple uses of this flag are permitted. +``` + +### Options inherited from parent commands + +``` + -b, --bootstrap string Bootstrap URL. Should start with 'http://' or 'file://'. If it starts with neither, it is assumed to be a fully-qualified path. If missing, it defaults to use the 'bootstrap.properties' file in your GALASA_HOME. Example: http://example.com/bootstrap, file:///user/myuserid/.galasa/bootstrap.properties , file://C:/Users/myuserid/.galasa/bootstrap.properties + --galasahome string Path to a folder where Galasa will read and write files and configuration settings. The default is '${HOME}/.galasa'. This overrides the GALASA_HOME environment variable which may be set instead. + -l, --log string File to which log information will be sent. Any folder referred to must exist. An existing file will be overwritten. Specify "-" to log to stderr. Defaults to not logging. + --rate-limit-retries int The maximum number of retries that should be made when requests to the Galasa Service fail due to rate limits being exceeded. Must be a whole number. Defaults to 3 retries (default 3) + --rate-limit-retry-backoff-secs float The amount of time in seconds to wait before retrying a command if it failed due to rate limits being exceeded. Defaults to 1 second. (default 1) +``` + +### SEE ALSO + +* [galasactl runs](galasactl_runs.md) - Manage test runs in the ecosystem + diff --git a/modules/cli/pkg/cmd/commandCollection.go b/modules/cli/pkg/cmd/commandCollection.go index a44affe69..0897a9d3e 100644 --- a/modules/cli/pkg/cmd/commandCollection.go +++ b/modules/cli/pkg/cmd/commandCollection.go @@ -55,6 +55,7 @@ const ( COMMAND_NAME_RUNS_SUBMIT = "runs submit" COMMAND_NAME_RUNS_SUBMIT_LOCAL = "runs submit local" COMMAND_NAME_RUNS_RESET = "runs reset" + COMMAND_NAME_RUNS_UPDATE = "runs update" COMMAND_NAME_RUNS_CANCEL = "runs cancel" COMMAND_NAME_RUNS_CLEANUP = "runs cleanup" COMMAND_NAME_RUNS_CLEANUP_LOCAL = "runs cleanup local" @@ -344,6 +345,7 @@ func (commands *commandCollectionImpl) addRunsCommands(factory spi.Factory, root var runsSubmitCommand spi.GalasaCommand var runsSubmitLocalCommand spi.GalasaCommand var runsResetCommand spi.GalasaCommand + var runsUpdateCommand spi.GalasaCommand var runsCancelCommand spi.GalasaCommand var runsDeleteCommand spi.GalasaCommand var runsCleanupCommand spi.GalasaCommand @@ -363,9 +365,12 @@ func (commands *commandCollectionImpl) addRunsCommands(factory spi.Factory, root if err == nil { runsResetCommand, err = NewRunsResetCommand(factory, runsCommand, commsFlagSet) if err == nil { - runsCancelCommand, err = NewRunsCancelCommand(factory, runsCommand, commsFlagSet) + runsUpdateCommand, err = NewRunsUpdateCommand(factory, runsCommand, commsFlagSet) if err == nil { - runsDeleteCommand, err = NewRunsDeleteCommand(factory, runsCommand, commsFlagSet) + runsCancelCommand, err = NewRunsCancelCommand(factory, runsCommand, commsFlagSet) + if err == nil { + runsDeleteCommand, err = NewRunsDeleteCommand(factory, runsCommand, commsFlagSet) + } } } } @@ -389,6 +394,7 @@ func (commands *commandCollectionImpl) addRunsCommands(factory spi.Factory, root commands.commandMap[runsSubmitCommand.Name()] = runsSubmitCommand commands.commandMap[runsSubmitLocalCommand.Name()] = runsSubmitLocalCommand commands.commandMap[runsResetCommand.Name()] = runsResetCommand + commands.commandMap[runsUpdateCommand.Name()] = runsUpdateCommand commands.commandMap[runsCancelCommand.Name()] = runsCancelCommand commands.commandMap[runsDeleteCommand.Name()] = runsDeleteCommand commands.commandMap[runsCleanupCommand.Name()] = runsCleanupCommand diff --git a/modules/cli/pkg/cmd/runsUpdate.go b/modules/cli/pkg/cmd/runsUpdate.go new file mode 100644 index 000000000..762c4c60b --- /dev/null +++ b/modules/cli/pkg/cmd/runsUpdate.go @@ -0,0 +1,143 @@ +/* + * Copyright contributors to the Galasa project + * + * SPDX-License-Identifier: EPL-2.0 + */ +package cmd + +import ( + "github.com/galasa-dev/cli/pkg/api" + "github.com/galasa-dev/cli/pkg/runs" + "github.com/galasa-dev/cli/pkg/spi" + "github.com/galasa-dev/cli/pkg/utils" + "github.com/spf13/cobra" +) + +// Objective: Allow the user to do this: +// runs update --name U12345 --add-tags tag1,tag2 --remove-tags tag3 + +// Variables set by cobra's command-line parsing. +type RunsUpdateCmdValues struct { + runName string + addTags []string + removeTags []string +} + +type RunsUpdateCommand struct { + values *RunsUpdateCmdValues + cobraCommand *cobra.Command +} + +func NewRunsUpdateCommand(factory spi.Factory, runsCommand spi.GalasaCommand, commsFlagSet GalasaFlagSet) (spi.GalasaCommand, error) { + cmd := new(RunsUpdateCommand) + err := cmd.init(factory, runsCommand, commsFlagSet) + return cmd, err +} + +// ------------------------------------------------------------------------------------------------ +// Public methods +// ------------------------------------------------------------------------------------------------ +func (cmd *RunsUpdateCommand) Name() string { + return COMMAND_NAME_RUNS_UPDATE +} + +func (cmd *RunsUpdateCommand) CobraCommand() *cobra.Command { + return cmd.cobraCommand +} + +func (cmd *RunsUpdateCommand) Values() interface{} { + return cmd.values +} + +// ------------------------------------------------------------------------------------------------ +// Private methods +// ------------------------------------------------------------------------------------------------ +func (cmd *RunsUpdateCommand) init(factory spi.Factory, runsCommand spi.GalasaCommand, commsFlagSet GalasaFlagSet) error { + var err error + cmd.values = &RunsUpdateCmdValues{} + cmd.cobraCommand, err = cmd.createCobraCommand(factory, runsCommand, commsFlagSet.Values().(*CommsFlagSetValues)) + return err +} + +func (cmd *RunsUpdateCommand) createCobraCommand( + factory spi.Factory, + runsCommand spi.GalasaCommand, + commsFlagSetValues *CommsFlagSetValues, +) (*cobra.Command, error) { + + var err error + + runsUpdateCobraCmd := &cobra.Command{ + Use: "update", + Short: "Update the record of an existing test run on a Galasa service.", + Long: "Update the record of an existing test run on a Galasa service.", + Args: cobra.NoArgs, + Aliases: []string{"runs update"}, + RunE: func(cobraCmd *cobra.Command, args []string) error { + return cmd.executeRunsUpdate(factory, commsFlagSetValues) + }, + } + + runsUpdateCobraCmd.Flags().StringVar(&cmd.values.runName, "name", "", "the name of the test run we want to update") + runsUpdateCobraCmd.MarkFlagRequired("name") + + runsUpdateCobraCmd.Flags().StringSliceVar(&cmd.values.addTags, "add-tags", nil, "Comma-separated list of tags to add. Multiple uses of this flag are permitted.") + runsUpdateCobraCmd.Flags().StringSliceVar(&cmd.values.removeTags, "remove-tags", nil, "Comma-separated list of tags to remove. Multiple uses of this flag are permitted.") + + runsCommand.CobraCommand().AddCommand(runsUpdateCobraCmd) + + return runsUpdateCobraCmd, err +} + +func (cmd *RunsUpdateCommand) executeRunsUpdate( + factory spi.Factory, + commsFlagSetValues *CommsFlagSetValues, +) error { + + var err error + + // Operations on the file system will all be relative to the current folder. + fileSystem := factory.GetFileSystem() + + err = utils.CaptureLog(fileSystem, commsFlagSetValues.logFileName) + if err == nil { + commsFlagSetValues.isCapturingLogs = true + + // Get the ability to query environment variables. + env := factory.GetEnvironment() + + var galasaHome spi.GalasaHome + galasaHome, err = utils.NewGalasaHome(fileSystem, env, commsFlagSetValues.CmdParamGalasaHomePath) + if err == nil { + + var commsClient api.APICommsClient + commsClient, err = api.NewAPICommsClient( + commsFlagSetValues.bootstrap, + commsFlagSetValues.maxRetries, + commsFlagSetValues.retryBackoffSeconds, + factory, + galasaHome, + ) + + if err == nil { + + var console = factory.GetStdOutConsole() + byteReader := factory.GetByteReader() + timeService := factory.GetTimeService() + + // Call to process the command in a unit-testable way. + err = runs.RunsUpdate( + cmd.values.runName, + cmd.values.addTags, + cmd.values.removeTags, + console, + commsClient, + timeService, + byteReader, + ) + } + } + } + + return err +} diff --git a/modules/cli/pkg/cmd/runsUpdate_test.go b/modules/cli/pkg/cmd/runsUpdate_test.go new file mode 100644 index 000000000..05cef96b4 --- /dev/null +++ b/modules/cli/pkg/cmd/runsUpdate_test.go @@ -0,0 +1,244 @@ +/* + * Copyright contributors to the Galasa project + * + * SPDX-License-Identifier: EPL-2.0 + */ +package cmd + +import ( + "strings" + "testing" + + "github.com/galasa-dev/cli/pkg/utils" + "github.com/stretchr/testify/assert" +) + +func TestRunsUpdateCommandInCommandCollection(t *testing.T) { + + factory := utils.NewMockFactory() + commands, _ := NewCommandCollection(factory) + + runsUpdateCommand, err := commands.GetCommand(COMMAND_NAME_RUNS_UPDATE) + assert.Nil(t, err) + + assert.Equal(t, COMMAND_NAME_RUNS_UPDATE, runsUpdateCommand.Name()) + assert.NotNil(t, runsUpdateCommand.Values()) + assert.IsType(t, &RunsUpdateCmdValues{}, runsUpdateCommand.Values()) + assert.NotNil(t, runsUpdateCommand.CobraCommand()) +} + +func TestRunsUpdateHelpFlagSetCorrectly(t *testing.T) { + // Given... + factory := utils.NewMockFactory() + + var args []string = []string{"runs", "update", "--help"} + + // When... + err := Execute(factory, args) + + // Then... + assert.Nil(t, err) + + // Check what the user saw is reasonable. + checkOutput("Displays the options for the 'runs update' command.", "", factory, t) +} + +func TestRunsUpdateNoFlagsReturnsError(t *testing.T) { + // Given... + factory := utils.NewMockFactory() + + var args []string = []string{"runs", "update"} + + // When... + err := Execute(factory, args) + + // Then... + assert.NotNil(t, err) + assert.Contains(t, err.Error(), "required flag(s)") + assert.Contains(t, err.Error(), "name") + + // Check what the user saw was reasonable + checkOutput("", "Error:", factory, t) +} + +func TestRunsUpdateNameFlagWithAddTagsReturnsOk(t *testing.T) { + // Given... + factory := utils.NewMockFactory() + commandCollection, cmd := setupTestCommandCollection(COMMAND_NAME_RUNS_UPDATE, factory, t) + + var args []string = []string{"runs", "update", "--name", "U12345", "--add-tags", "tag1,tag2"} + + // When... + err := commandCollection.Execute(args) + + // Then... + assert.Nil(t, err) + + // Check what the user saw was reasonable + checkOutput("", "", factory, t) + + assert.Equal(t, "U12345", cmd.Values().(*RunsUpdateCmdValues).runName) + assert.Contains(t, cmd.Values().(*RunsUpdateCmdValues).addTags, "tag1") + assert.Contains(t, cmd.Values().(*RunsUpdateCmdValues).addTags, "tag2") +} + +func TestRunsUpdateNameFlagWithRemoveTagsReturnsOk(t *testing.T) { + // Given... + factory := utils.NewMockFactory() + commandCollection, cmd := setupTestCommandCollection(COMMAND_NAME_RUNS_UPDATE, factory, t) + + var args []string = []string{"runs", "update", "--name", "U12345", "--remove-tags", "tag3,tag4"} + + // When... + err := commandCollection.Execute(args) + + // Then... + assert.Nil(t, err) + + // Check what the user saw was reasonable + checkOutput("", "", factory, t) + + assert.Equal(t, "U12345", cmd.Values().(*RunsUpdateCmdValues).runName) + assert.Contains(t, cmd.Values().(*RunsUpdateCmdValues).removeTags, "tag3") + assert.Contains(t, cmd.Values().(*RunsUpdateCmdValues).removeTags, "tag4") +} + +func TestRunsUpdateNameFlagWithBothAddAndRemoveTagsReturnsOk(t *testing.T) { + // Given... + factory := utils.NewMockFactory() + commandCollection, cmd := setupTestCommandCollection(COMMAND_NAME_RUNS_UPDATE, factory, t) + + var args []string = []string{"runs", "update", "--name", "U12345", "--add-tags", "tag1", "--remove-tags", "tag2"} + + // When... + err := commandCollection.Execute(args) + + // Then... + assert.Nil(t, err) + + // Check what the user saw was reasonable + checkOutput("", "", factory, t) + + assert.Equal(t, "U12345", cmd.Values().(*RunsUpdateCmdValues).runName) + assert.Contains(t, cmd.Values().(*RunsUpdateCmdValues).addTags, "tag1") + assert.Contains(t, cmd.Values().(*RunsUpdateCmdValues).removeTags, "tag2") +} + +func TestRunsUpdateWithMultipleAddTagsFlagsReturnsOk(t *testing.T) { + // Given... + factory := utils.NewMockFactory() + commandCollection, cmd := setupTestCommandCollection(COMMAND_NAME_RUNS_UPDATE, factory, t) + + tag1 := "my-test-tag-1" + tag2 := "my-test-tag-2" + + var args []string = []string{"runs", "update", "--name", "U12345", "--add-tags", tag1, "--add-tags", tag2} + + // When... + err := commandCollection.Execute(args) + + // Then... + assert.Nil(t, err) + + // Check what the user saw was reasonable + checkOutput("", "", factory, t) + + addTags := cmd.Values().(*RunsUpdateCmdValues).addTags + assert.Contains(t, addTags, tag1) + assert.Contains(t, addTags, tag2) +} + +func TestRunsUpdateWithCommaSeparatedAddTagsFlagReturnsOk(t *testing.T) { + // Given... + factory := utils.NewMockFactory() + commandCollection, cmd := setupTestCommandCollection(COMMAND_NAME_RUNS_UPDATE, factory, t) + + tag1 := "my-test-tag-1" + tag2 := "my-test-tag-2" + tags := []string{tag1, tag2} + commaSeparatedTags := strings.Join(tags, ",") + + var args []string = []string{"runs", "update", "--name", "U12345", "--add-tags", commaSeparatedTags} + + // When... + err := commandCollection.Execute(args) + + // Then... + assert.Nil(t, err) + + // Check what the user saw was reasonable + checkOutput("", "", factory, t) + + actualTags := cmd.Values().(*RunsUpdateCmdValues).addTags + assert.Contains(t, actualTags, tag1) + assert.Contains(t, actualTags, tag2) +} + +func TestRunsUpdateWithMultipleRemoveTagsFlagsReturnsOk(t *testing.T) { + // Given... + factory := utils.NewMockFactory() + commandCollection, cmd := setupTestCommandCollection(COMMAND_NAME_RUNS_UPDATE, factory, t) + + tag1 := "my-test-tag-1" + tag2 := "my-test-tag-2" + + var args []string = []string{"runs", "update", "--name", "U12345", "--remove-tags", tag1, "--remove-tags", tag2} + + // When... + err := commandCollection.Execute(args) + + // Then... + assert.Nil(t, err) + + // Check what the user saw was reasonable + checkOutput("", "", factory, t) + + removeTags := cmd.Values().(*RunsUpdateCmdValues).removeTags + assert.Contains(t, removeTags, tag1) + assert.Contains(t, removeTags, tag2) +} + +func TestRunsUpdateWithCommaSeparatedRemoveTagsFlagReturnsOk(t *testing.T) { + // Given... + factory := utils.NewMockFactory() + commandCollection, cmd := setupTestCommandCollection(COMMAND_NAME_RUNS_UPDATE, factory, t) + + tag1 := "my-test-tag-1" + tag2 := "my-test-tag-2" + tags := []string{tag1, tag2} + commaSeparatedTags := strings.Join(tags, ",") + + var args []string = []string{"runs", "update", "--name", "U12345", "--remove-tags", commaSeparatedTags} + + // When... + err := commandCollection.Execute(args) + + // Then... + assert.Nil(t, err) + + // Check what the user saw was reasonable + checkOutput("", "", factory, t) + + actualTags := cmd.Values().(*RunsUpdateCmdValues).removeTags + assert.Contains(t, actualTags, tag1) + assert.Contains(t, actualTags, tag2) +} + +func TestRunsUpdateMultipleNameFlagsOverridesToLast(t *testing.T) { + // Given... + factory := utils.NewMockFactory() + commandCollection, cmd := setupTestCommandCollection(COMMAND_NAME_RUNS_UPDATE, factory, t) + + var args []string = []string{"runs", "update", "--name", "C2020", "--name", "C4091", "--add-tags", "tag1"} + + // When... + err := commandCollection.Execute(args) + + // Then... + assert.Nil(t, err) + + // Check what the user saw was reasonable + checkOutput("", "", factory, t) + + assert.Equal(t, "C4091", cmd.Values().(*RunsUpdateCmdValues).runName) +} diff --git a/modules/cli/pkg/errors/errorMessage.go b/modules/cli/pkg/errors/errorMessage.go index 31a0a0fd5..e24900893 100644 --- a/modules/cli/pkg/errors/errorMessage.go +++ b/modules/cli/pkg/errors/errorMessage.go @@ -460,7 +460,10 @@ var ( GALASA_ERROR_UPDATE_MONITOR_EXPLANATION_NOT_JSON = NewMessageType("GAL1232E: Failed to update a monitor named '%s'. Unexpected http status code %v received from the server. Error details from the server are not in the json format.", 1232, STACK_TRACE_NOT_WANTED) // Runs cleanup local errors - GALASA_ERROR_INVALID_GLOB_PATTERN_PROVIDED = NewMessageType("GAL1248E: Unsupported glob pattern character provided. Only alphanumeric (A-Z, a-z, 0-9), '.', '?', and '*' characters can be provided in the '--includes-pattern' and '--excludes-pattern' flags.", 1248, STACK_TRACE_NOT_WANTED) + GALASA_ERROR_INVALID_GLOB_PATTERN_PROVIDED = NewMessageType("GAL1248E: Unsupported glob pattern character provided. Only alphanumeric (A-Z, a-z, 0-9), '.', '?', and '*' characters can be provided in the '--includes-pattern' and '--excludes-pattern' flags.", 1248, STACK_TRACE_NOT_WANTED) + + // General Tag errors + GALASA_ERROR_TAGS_INVALID_NAME = NewMessageType("GAL1256E: Invalid tag name provided. The name provided with the --name flag cannot be empty and must only contain characters in the Latin-1 character set.", 1256, STACK_TRACE_NOT_WANTED) // Tags delete errors GALASA_ERROR_FAILED_TO_DELETE_TAG = NewMessageType("GAL1249E: Failed to delete the tag with the given name from the Galasa service", 1249, STACK_TRACE_NOT_WANTED) @@ -470,18 +473,17 @@ var ( GALASA_ERROR_DELETE_TAG_SERVER_REPORTED_ERROR = NewMessageType("GAL1253E: Failed to delete a tag named '%s'. Unexpected http status code %v received from the server. Error details from the server are: '%s'", 1253, STACK_TRACE_NOT_WANTED) GALASA_ERROR_DELETE_TAG_EXPLANATION_NOT_JSON = NewMessageType("GAL1254E: Failed to delete a tag named '%s'. Unexpected http status code %v received from the server. Error details from the server are not in the json format.", 1254, STACK_TRACE_NOT_WANTED) GALASA_ERROR_DELETE_TAG_REQUEST_FAILED = NewMessageType("GAL1255E: Failed to delete a tag named '%s'. Failed to send a request to the Galasa service. Cause is %v", 1255, STACK_TRACE_NOT_WANTED) - GALASA_ERROR_INVALID_TAG_NAME = NewMessageType("GAL1256E: Invalid tag name provided. The name provided with the --name flag cannot be empty and must only contain characters in the Latin-1 character set.", 1256, STACK_TRACE_NOT_WANTED) GALASA_ERROR_TAG_NOT_FOUND = NewMessageType("GAL1257E: No such tag named '%v' exists within the Galasa service.", 1257, STACK_TRACE_NOT_WANTED) // Tags set errors - GALASA_ERROR_FAILED_TO_SET_TAG = NewMessageType("GAL1258E: Failed to set the tag with the given name on the Galasa service", 1258, STACK_TRACE_NOT_WANTED) - GALASA_ERROR_SET_TAG_NO_RESPONSE_CONTENT = NewMessageType("GAL1259E: Failed to set a tag named '%s'. Unexpected http status code %v received from the server.", 1259, STACK_TRACE_NOT_WANTED) - GALASA_ERROR_SET_TAG_RESPONSE_BODY_UNREADABLE = NewMessageType("GAL1260E: Failed to set a tag named '%s'. Unexpected http status code %v received from the server. Error details from the server could not be read. Cause: %s", 1260, STACK_TRACE_NOT_WANTED) - GALASA_ERROR_SET_TAG_UNPARSEABLE_CONTENT = NewMessageType("GAL1261E: Failed to set a tag named '%s'. Unexpected http status code %v received from the server. Error details from the server are not in a valid json format. Cause: '%s'", 1261, STACK_TRACE_NOT_WANTED) - GALASA_ERROR_SET_TAG_SERVER_REPORTED_ERROR = NewMessageType("GAL1262E: Failed to set a tag named '%s'. Unexpected http status code %v received from the server. Error details from the server are: '%s'", 1262, STACK_TRACE_NOT_WANTED) - GALASA_ERROR_SET_TAG_EXPLANATION_NOT_JSON = NewMessageType("GAL1263E: Failed to set a tag named '%s'. Unexpected http status code %v received from the server. Error details from the server are not in the json format.", 1263, STACK_TRACE_NOT_WANTED) - GALASA_ERROR_SET_TAG_REQUEST_FAILED = NewMessageType("GAL1264E: Failed to set a tag named '%s'. Sending the put request to the Galasa service failed. Cause is %v", 1264, STACK_TRACE_NOT_WANTED) - GALASA_ERROR_INVALID_TAG_DESCRIPTION = NewMessageType("GAL1265E: Invalid tag description provided. The description provided with the --description flag cannot only contain spaces or tabs, and must only contain characters in the Latin-1 character set.", 1265, STACK_TRACE_NOT_WANTED) + GALASA_ERROR_FAILED_TO_SET_TAG = NewMessageType("GAL1258E: Failed to set the tag with the given name on the Galasa service", 1258, STACK_TRACE_NOT_WANTED) + GALASA_ERROR_SET_TAG_NO_RESPONSE_CONTENT = NewMessageType("GAL1259E: Failed to set a tag named '%s'. Unexpected http status code %v received from the server.", 1259, STACK_TRACE_NOT_WANTED) + GALASA_ERROR_SET_TAG_RESPONSE_BODY_UNREADABLE = NewMessageType("GAL1260E: Failed to set a tag named '%s'. Unexpected http status code %v received from the server. Error details from the server could not be read. Cause: %s", 1260, STACK_TRACE_NOT_WANTED) + GALASA_ERROR_SET_TAG_UNPARSEABLE_CONTENT = NewMessageType("GAL1261E: Failed to set a tag named '%s'. Unexpected http status code %v received from the server. Error details from the server are not in a valid json format. Cause: '%s'", 1261, STACK_TRACE_NOT_WANTED) + GALASA_ERROR_SET_TAG_SERVER_REPORTED_ERROR = NewMessageType("GAL1262E: Failed to set a tag named '%s'. Unexpected http status code %v received from the server. Error details from the server are: '%s'", 1262, STACK_TRACE_NOT_WANTED) + GALASA_ERROR_SET_TAG_EXPLANATION_NOT_JSON = NewMessageType("GAL1263E: Failed to set a tag named '%s'. Unexpected http status code %v received from the server. Error details from the server are not in the json format.", 1263, STACK_TRACE_NOT_WANTED) + GALASA_ERROR_SET_TAG_REQUEST_FAILED = NewMessageType("GAL1264E: Failed to set a tag named '%s'. Sending the put request to the Galasa service failed. Cause is %v", 1264, STACK_TRACE_NOT_WANTED) + GALASA_ERROR_INVALID_TAG_DESCRIPTION = NewMessageType("GAL1265E: Invalid tag description provided. The description provided with the --description flag cannot only contain spaces or tabs, and must only contain characters in the Latin-1 character set.", 1265, STACK_TRACE_NOT_WANTED) // Tags get errors GALASA_ERROR_FAILED_TO_GET_TAGS = NewMessageType("GAL1266E: Failed to get tags from the Galasa service", 1266, STACK_TRACE_NOT_WANTED) @@ -498,6 +500,18 @@ var ( GALASA_ERROR_INVALID_CHAR_IN_METHOD_NAME = NewMessageType("GAL1276E: Invalid Java method name '%s' should not contain the '%s' character."+SEE_COMMAND_REFERENCE, 1276, STACK_TRACE_NOT_WANTED) GALASA_ERROR_INVALID_METHOD_RESERVED_WORD = NewMessageType("GAL1277E: Invalid Java method name. Method name '%s' is a reserved Java keyword."+SEE_COMMAND_REFERENCE, 1277, STACK_TRACE_NOT_WANTED) + // Runs update errors + GALASA_ERROR_UPDATE_RUN_INVALID_TAG_UPDATE = NewMessageType("GAL1273E: Invalid update request. The tag '%s' cannot be added and deleted in the same command.", 1273, STACK_TRACE_NOT_WANTED) + GALASA_ERROR_UPDATE_RUN_MISSING_FIELD = NewMessageType("GAL1274E: Invalid update request. The flag '%s' must be used when attempting to update a run.", 1274, STACK_TRACE_NOT_WANTED) + GALASA_ERROR_UPDATE_RUN_NOT_FOUND = NewMessageType("GAL1275E: The run named '%s' could not be updated because it was not found by the Galasa service. Try listing runs using 'galasactl runs get' to identify the one you wish to update.", 1275, STACK_TRACE_NOT_WANTED) + GALASA_ERROR_UPDATE_RUN_REQUEST_FAILED = NewMessageType("GAL1276E: Failed to update run. Did not recieve an HTTP response. Cause is %v", 1276, STACK_TRACE_NOT_WANTED) + GALASA_ERROR_UPDATE_RUN_NO_RESPONSE_CONTENT = NewMessageType("GAL1277E: An attempt to update a run named '%s' failed. Unexpected http status code %v received from the server.", 1277, STACK_TRACE_NOT_WANTED) + GALASA_ERROR_UPDATE_RUN_RESPONSE_PAYLOAD_UNREADABLE = NewMessageType("GAL1278E: An attempt to update a run named '%s' failed. Unexpected http status code %v received from the server. Error details from the server could not be read. Cause: %s", 1278, STACK_TRACE_NOT_WANTED) + GALASA_ERROR_UPDATE_RUN_UNPARSEABLE_CONTENT = NewMessageType("GAL1279E: An attempt to update a run named '%s' failed. Unexpected http status code %v received from the server. Error details from the server are not in a valid json format. Cause: '%s'", 1279, STACK_TRACE_NOT_WANTED) + GALASA_ERROR_UPDATE_RUN_SERVER_REPORTED_ERROR = NewMessageType("GAL1280E: An attempt to update a run named '%s' failed. Unexpected http status code %v received from the server. Error details from the server are: '%s'", 1280, STACK_TRACE_NOT_WANTED) + GALASA_ERROR_UPDATE_RUN_EXPLANATION_NOT_JSON = NewMessageType("GAL1281E: An attempt to update a run named '%s' failed. Unexpected http status code %v received from the server. Error details from the server are not in the json format.", 1281, STACK_TRACE_NOT_WANTED) + GALASA_ERROR_UPDATE_RUN_INVALID_TAG_NAME = NewMessageType("GAL1282E: Invalid tag name '%s' provided. Tag names cannot be empty and must only contain characters in the Latin-1 character set.", 1282, STACK_TRACE_NOT_WANTED) + // Warnings... GALASA_WARNING_MAVEN_NO_GALASA_OBR_REPO = NewMessageType("GAL2000W: Warning: Maven configuration file settings.xml should contain a reference to a Galasa repository so that the galasa OBR can be resolved. The official release repository is '%s', and 'pre-release' repository is '%s'", 2000, STACK_TRACE_WANTED) @@ -509,11 +523,11 @@ var ( GALASA_INFO_GROUP_RUNS_CANCEL_SUCCESS = NewMessageType("GAL2505I: The request to cancel runs with group name '%s' has been accepted by the server.\n", 2505, STACK_TRACE_NOT_WANTED) GALASA_INFO_GROUP_RUNS_ALREADY_FINISHED = NewMessageType("GAL2506I: The request to cancel runs with group name '%s' has been handled successfully. However, no recent active (unfinished) test runs were found which are part of that group. Archived test runs may be part of that group, which can be queried separately from the Result Archive Store.\n", 2506, STACK_TRACE_NOT_WANTED) - // >>> - // >>> Note: Please keep this up to date, to save us wondering what to allocate next... - // >>> otherwise you have to find a 'gap' in the range. - // >>> Unit tests guarantee that this number is 'free' to use for a new error message. - // >>> If you do use this number for a new error template, please increment this value. - // >>> - GALxxx_NEXT_MESSAGE_NUMBER_TO_USE = 1278 + // >>> + // >>> Note: Please keep this up to date, to save us wondering what to allocate next... + // >>> otherwise you have to find a 'gap' in the range. + // >>> Unit tests guarantee that this number is 'free' to use for a new error message. + // >>> If you do use this number for a new error template, please increment this value. + // >>> + GALxxx_NEXT_MESSAGE_NUMBER_TO_USE = 1283; ) diff --git a/modules/cli/pkg/runs/runs.go b/modules/cli/pkg/runs/runs.go index d287dba7b..ad4760222 100644 --- a/modules/cli/pkg/runs/runs.go +++ b/modules/cli/pkg/runs/runs.go @@ -89,13 +89,13 @@ func getRunIdFromRunName(runName string, return runId, err } -func createUpdateRunRequest(status string, result string) *galasaapi.UpdateRunRequest { - var UpdateRunRequest = galasaapi.NewUpdateRunRequest() +func createUpdateRunStatusRequest(status string, result string) *galasaapi.UpdateRunRequest { + var updateRunStatusRequest = galasaapi.NewUpdateRunRequest() - UpdateRunRequest.SetStatus(status) - UpdateRunRequest.SetResult(result) + updateRunStatusRequest.SetStatus(status) + updateRunStatusRequest.SetResult(result) - return UpdateRunRequest + return updateRunStatusRequest } func createGroupUpdateStatusRequest() *galasaapi.UpdateGroupStatusRequest { diff --git a/modules/cli/pkg/runs/runsCancel.go b/modules/cli/pkg/runs/runsCancel.go index 9a7865e62..8575f6027 100644 --- a/modules/cli/pkg/runs/runsCancel.go +++ b/modules/cli/pkg/runs/runsCancel.go @@ -175,8 +175,8 @@ func cancelByRunName(runName string, timeService spi.TimeService, commsClient ap if err == nil { - UpdateRunRequest := createUpdateRunRequest(CANCEL_STATUS, CANCEL_RESULT) - err = cancelRun(runName, runId, UpdateRunRequest, commsClient) + updateRunStatusRequest := createUpdateRunStatusRequest(CANCEL_STATUS, CANCEL_RESULT) + err = cancelRun(runName, runId, updateRunStatusRequest, commsClient) if err == nil { err = writeConsoleMessage(console, *galasaErrors.GALASA_INFO_RUNS_CANCEL_SUCCESS, runName) diff --git a/modules/cli/pkg/runs/runsReset.go b/modules/cli/pkg/runs/runsReset.go index 96b4147d9..e76333fbe 100644 --- a/modules/cli/pkg/runs/runsReset.go +++ b/modules/cli/pkg/runs/runsReset.go @@ -49,9 +49,9 @@ func ResetRun( if err == nil { - UpdateRunRequest := createUpdateRunRequest(RESET_STATUS, RESET_RESULT) + updateRunStatusRequest := createUpdateRunStatusRequest(RESET_STATUS, RESET_RESULT) - err = resetRun(runName, runId, UpdateRunRequest, commsClient) + err = resetRun(runName, runId, updateRunStatusRequest, commsClient) if err == nil { consoleErr := console.WriteString(fmt.Sprintf(galasaErrors.GALASA_INFO_RUNS_RESET_SUCCESS.Template, runName)) diff --git a/modules/cli/pkg/runs/runsUpdate.go b/modules/cli/pkg/runs/runsUpdate.go new file mode 100644 index 000000000..51c3f7b69 --- /dev/null +++ b/modules/cli/pkg/runs/runsUpdate.go @@ -0,0 +1,245 @@ +/* + * Copyright contributors to the Galasa project + * + * SPDX-License-Identifier: EPL-2.0 + */ +package runs + +import ( + "slices" + "context" + "log" + "net/http" + "strings" + + "github.com/galasa-dev/cli/pkg/api" + "github.com/galasa-dev/cli/pkg/embedded" + galasaErrors "github.com/galasa-dev/cli/pkg/errors" + "github.com/galasa-dev/cli/pkg/galasaapi" + "github.com/galasa-dev/cli/pkg/spi" + "github.com/galasa-dev/cli/pkg/utils" +) + +// --------------------------------------------------- + +// RunsUpdate - performs all the logic to implement the `galasactl runs update` command, +// but in a unit-testable manner. +func RunsUpdate( + runName string, + addTags []string, + removeTags []string, + console spi.Console, + commsClient api.APICommsClient, + timeService spi.TimeService, + byteReader spi.ByteReader, +) error { + var err error + + log.Printf("RunsUpdate entered.") + + err = validateRunNameAndTags(runName, addTags, removeTags) + if err != nil { + return err + } + + addTags = removeDuplicateTags(addTags) + removeTags = removeDuplicateTags(removeTags) + + // Check for tags that are both added and removed. + for _, tag := range addTags { + if (slices.Contains(removeTags, tag)) { + return galasaErrors.NewGalasaError(galasaErrors.GALASA_ERROR_UPDATE_RUN_INVALID_TAG_UPDATE, tag) + } + } + + runsQuery := NewRunsQuery( + runName, + "", // requestorParameter + "", // userParameter + "", // resultParameter + "", // group + 0, // fromAgeHours + 0, // toAgeHours + false, // shouldGetActive + false, // isNeedingMethodDetails + addTags, + timeService.Now(), + ) + + var runs []galasaapi.Run + runs, err = GetRunsFromRestApi(runsQuery, commsClient) + + if err == nil { + if len(runs) == 0 { + err = galasaErrors.NewGalasaError(galasaErrors.GALASA_ERROR_UPDATE_RUN_NOT_FOUND, runName) + } else { + err = updateRuns(runs, addTags, removeTags, commsClient, byteReader) + } + } + + log.Printf("RunsUpdate exiting. err is %v\n", err) + return err +} + +func updateRuns( + runs []galasaapi.Run, + addTags []string, + removeTags []string, + commsClient api.APICommsClient, + byteReader spi.ByteReader, +) error { + var err error + var restApiVersion string + + restApiVersion, err = embedded.GetGalasactlRestApiVersion() + if err == nil { + for _, run := range runs { + err = updateRun(run, addTags, removeTags, commsClient, byteReader, restApiVersion) + if err != nil { + break + } + } + } + + return err +} + +func updateRun( + run galasaapi.Run, + addTags []string, + removeTags []string, + commsClient api.APICommsClient, + byteReader spi.ByteReader, + restApiVersion string, +) error { + var err error + + runId := run.GetRunId() + runName := *run.GetTestStructure().RunName + + // Get current tags from the run + currentTags := run.TestStructure.GetTags() + + // Create a new tag list by filtering out tags to remove + newTags := make([]string, 0) + for _, tag := range currentTags { + if !slices.Contains(removeTags, tag) { + newTags = append(newTags, tag) + } + } + + // Add new tags that aren't already present + for _, tag := range addTags { + if !slices.Contains(newTags, tag) { + newTags = append(newTags, tag) + } + } + + // Create update request with new tags + updateRequest := createUpdateRunTagsRequest(newTags) + + err = commsClient.RunAuthenticatedCommandWithRateLimitRetries(func(apiClient *galasaapi.APIClient) error { + var err error + var context context.Context = nil + var httpResponse *http.Response + + _, httpResponse, err = apiClient.ResultArchiveStoreAPIApi.PutRasRunStatusById(context, runId). + UpdateRunRequest(*updateRequest). + ClientApiVersion(restApiVersion).Execute() + + if httpResponse != nil { + defer httpResponse.Body.Close() + } + + // Non 200-299 http status codes manifest as an error. + if err != nil { + if httpResponse == nil { + // We never got a response, error sending it? + err = galasaErrors.NewGalasaError(galasaErrors.GALASA_ERROR_UPDATE_RUN_REQUEST_FAILED, runName, err.Error()) + } else { + err = galasaErrors.HttpResponseToGalasaError( + httpResponse, + runName, + byteReader, + galasaErrors.GALASA_ERROR_UPDATE_RUN_NO_RESPONSE_CONTENT, + galasaErrors.GALASA_ERROR_UPDATE_RUN_RESPONSE_PAYLOAD_UNREADABLE, + galasaErrors.GALASA_ERROR_UPDATE_RUN_UNPARSEABLE_CONTENT, + galasaErrors.GALASA_ERROR_UPDATE_RUN_SERVER_REPORTED_ERROR, + galasaErrors.GALASA_ERROR_UPDATE_RUN_EXPLANATION_NOT_JSON, + ) + } + } + + if err == nil { + log.Printf("Run with runId '%s' and runName '%s', was updated OK.\n", runId, run.TestStructure.GetRunName()) + } + return err + }) + return err +} + +func validateRunNameAndTags(runName string, addTags []string, removeTags []string) error { + var err error + + if runName == "" { + return galasaErrors.NewGalasaError(galasaErrors.GALASA_ERROR_MISSING_NAME_FLAG, "--name") + } + + if len(addTags) == 0 && len(removeTags) == 0 { + return galasaErrors.NewGalasaError(galasaErrors.GALASA_ERROR_UPDATE_RUN_MISSING_FIELD, "--add-tags or --remove-tags") + } + + // Validate the runName as best we can without contacting the ecosystem. + err = ValidateRunName(runName) + if err != nil { + return err + } + + // Validate all tags in addTags + for _, tag := range addTags { + err = validateTagName(tag) + if err != nil { + return err + } + } + + // Validate all tags in removeTags + for _, tag := range removeTags { + err = validateTagName(tag) + if err != nil { + return err + } + } + + return nil +} + +func validateTagName(tagName string) error { + trimmedTag := strings.TrimSpace(tagName) + + if trimmedTag == "" || !utils.IsLatin1(tagName) { + return galasaErrors.NewGalasaError(galasaErrors.GALASA_ERROR_UPDATE_RUN_INVALID_TAG_NAME, tagName) + } + + return nil +} + +func removeDuplicateTags(tags []string) []string { + uniqueTags := make(map[string]struct{}, len(tags)) + for _, tag := range tags { + uniqueTags[tag] = struct{}{} + } + result := make([]string, 0, len(uniqueTags)) + for tag := range uniqueTags { + result = append(tags, tag) + } + return result +} + +func createUpdateRunTagsRequest(tags []string) *galasaapi.UpdateRunRequest { + var UpdateRunRequest = galasaapi.NewUpdateRunRequest() + + UpdateRunRequest.SetTags(tags) + + return UpdateRunRequest +} diff --git a/modules/cli/pkg/runs/runsUpdate_test.go b/modules/cli/pkg/runs/runsUpdate_test.go new file mode 100644 index 000000000..a195a061d --- /dev/null +++ b/modules/cli/pkg/runs/runsUpdate_test.go @@ -0,0 +1,763 @@ +/* + * Copyright contributors to the Galasa project + * + * SPDX-License-Identifier: EPL-2.0 + */ +package runs + +import ( + "fmt" + "net/http" + "testing" + + "github.com/galasa-dev/cli/pkg/api" + "github.com/galasa-dev/cli/pkg/utils" + "github.com/stretchr/testify/assert" +) + +const ( + RUN_U123_WITH_TAGS = `{ + "runId": "xxx123xxx", + "testStructure": { + "runName": "U123", + "bundle": "myBundleId", + "testName": "myTestPackage.MyTestName", + "testShortName": "MyTestName", + "requestor": "unitTesting", + "user": "unitTesting", + "status": "Finished", + "result": "Passed", + "queued" : "2023-05-10T06:00:13.043037Z", + "startTime": "2023-05-10T06:00:36.159003Z", + "endTime": "2023-05-10T06:02:53.823338Z", + "tags": [ + "tag1", + "tag2" + ] + }, + "artifacts": [], + "webUiUrl": "http://example.com/test-runs/xxx123xxx", + "restApiUrl": "http://example.com/api/ras/runs/xxx123xxx" + }` + + RUN_U123_NO_TAGS = `{ + "runId": "xxx123xxx", + "testStructure": { + "runName": "U123", + "bundle": "myBundleId", + "testName": "myTestPackage.MyTestName", + "testShortName": "MyTestName", + "requestor": "unitTesting", + "user": "unitTesting", + "status": "Finished", + "result": "Passed", + "queued" : "2023-05-10T06:00:13.043037Z", + "startTime": "2023-05-10T06:00:36.159003Z", + "endTime": "2023-05-10T06:02:53.823338Z" + }, + "artifacts": [], + "webUiUrl": "http://example.com/test-runs/xxx123xxx", + "restApiUrl": "http://example.com/api/ras/runs/xxx123xxx" + }` +) + +func TestRunsUpdateWithEmptyRunNameReturnsError(t *testing.T) { + // Given... + runName := "" + addTags := []string{"tag1"} + removeTags := []string{} + + mockConsole := utils.NewMockConsole() + mockTimeService := utils.NewMockTimeService() + mockByteReader := utils.NewMockByteReader() + + interactions := []utils.HttpInteraction{} + server := utils.NewMockHttpServer(t, interactions) + defer server.Server.Close() + + apiServerUrl := server.Server.URL + commsClient := api.NewMockAPICommsClient(apiServerUrl) + + // When... + err := RunsUpdate(runName, addTags, removeTags, mockConsole, commsClient, mockTimeService, mockByteReader) + + // Then... + assert.NotNil(t, err) + assert.ErrorContains(t, err, "GAL1102E") + assert.ErrorContains(t, err, "--name") +} + +func TestRunsUpdateWithNoTagsReturnsError(t *testing.T) { + // Given... + runName := "U123" + addTags := []string{} + removeTags := []string{} + + mockConsole := utils.NewMockConsole() + mockTimeService := utils.NewMockTimeService() + mockByteReader := utils.NewMockByteReader() + + interactions := []utils.HttpInteraction{} + server := utils.NewMockHttpServer(t, interactions) + defer server.Server.Close() + + apiServerUrl := server.Server.URL + commsClient := api.NewMockAPICommsClient(apiServerUrl) + + // When... + err := RunsUpdate(runName, addTags, removeTags, mockConsole, commsClient, mockTimeService, mockByteReader) + + // Then... + assert.NotNil(t, err) + assert.ErrorContains(t, err, "GAL1274E") + assert.ErrorContains(t, err, "--add-tags or --remove-tags") +} + +func TestRunsUpdateWithInvalidRunNameReturnsError(t *testing.T) { + // Given... + runName := "invalid@runname" + addTags := []string{"tag1"} + removeTags := []string{} + + mockConsole := utils.NewMockConsole() + mockTimeService := utils.NewMockTimeService() + mockByteReader := utils.NewMockByteReader() + + interactions := []utils.HttpInteraction{} + server := utils.NewMockHttpServer(t, interactions) + defer server.Server.Close() + + apiServerUrl := server.Server.URL + commsClient := api.NewMockAPICommsClient(apiServerUrl) + + // When... + err := RunsUpdate(runName, addTags, removeTags, mockConsole, commsClient, mockTimeService, mockByteReader) + + // Then... + assert.NotNil(t, err) + assert.ErrorContains(t, err, "GAL1075E") + assert.ErrorContains(t, err, runName) +} + +func TestRunsUpdateWithSameTagInAddAndRemoveReturnsError(t *testing.T) { + // Given... + runName := "U123" + addTags := []string{"tag1", "tag2"} + removeTags := []string{"tag2", "tag3"} + + mockConsole := utils.NewMockConsole() + mockTimeService := utils.NewMockTimeService() + mockByteReader := utils.NewMockByteReader() + + interactions := []utils.HttpInteraction{} + server := utils.NewMockHttpServer(t, interactions) + defer server.Server.Close() + + apiServerUrl := server.Server.URL + commsClient := api.NewMockAPICommsClient(apiServerUrl) + + // When... + err := RunsUpdate(runName, addTags, removeTags, mockConsole, commsClient, mockTimeService, mockByteReader) + + // Then... + assert.NotNil(t, err) + assert.ErrorContains(t, err, "GAL1273E") + assert.ErrorContains(t, err, "tag2") +} + +func TestRunsUpdateWithNonExistentRunReturnsError(t *testing.T) { + // Given... + runName := "U999" + addTags := []string{"tag1"} + removeTags := []string{} + + getRunsInteraction := utils.NewHttpInteraction("/ras/runs", http.MethodGet) + getRunsInteraction.WriteHttpResponseFunc = func(writer http.ResponseWriter, req *http.Request) { + writer.Header().Set("Content-Type", "application/json") + writer.WriteHeader(http.StatusOK) + writer.Write([]byte(EMPTY_RUNS_RESPONSE)) + } + + interactions := []utils.HttpInteraction{ + getRunsInteraction, + } + + server := utils.NewMockHttpServer(t, interactions) + defer server.Server.Close() + + mockConsole := utils.NewMockConsole() + mockTimeService := utils.NewMockTimeService() + mockByteReader := utils.NewMockByteReader() + apiServerUrl := server.Server.URL + commsClient := api.NewMockAPICommsClient(apiServerUrl) + + // When... + err := RunsUpdate(runName, addTags, removeTags, mockConsole, commsClient, mockTimeService, mockByteReader) + + // Then... + assert.NotNil(t, err) + assert.ErrorContains(t, err, "GAL1275E") + assert.ErrorContains(t, err, runName) +} + +func TestRunsUpdateAddTagsToRunWithExistingTagsSucceeds(t *testing.T) { + // Given... + runName := "U123" + addTags := []string{"tag3", "tag4"} + removeTags := []string{} + + getRunsInteraction := utils.NewHttpInteraction("/ras/runs", http.MethodGet) + getRunsInteraction.WriteHttpResponseFunc = func(writer http.ResponseWriter, req *http.Request) { + writer.Header().Set("Content-Type", "application/json") + writer.WriteHeader(http.StatusOK) + writer.Write([]byte(fmt.Sprintf(` + { + "nextCursor": "", + "pageSize": 100, + "amountOfRuns": 1, + "runs":[ %s ] + }`, RUN_U123_WITH_TAGS))) + } + + updateRunInteraction := utils.NewHttpInteraction("/ras/runs/xxx123xxx", http.MethodPut) + updateRunInteraction.WriteHttpResponseFunc = func(writer http.ResponseWriter, req *http.Request) { + writer.Header().Set("Content-Type", "application/json") + writer.WriteHeader(http.StatusOK) + } + + interactions := []utils.HttpInteraction{ + getRunsInteraction, + updateRunInteraction, + } + + server := utils.NewMockHttpServer(t, interactions) + defer server.Server.Close() + + mockConsole := utils.NewMockConsole() + mockTimeService := utils.NewMockTimeService() + mockByteReader := utils.NewMockByteReader() + apiServerUrl := server.Server.URL + commsClient := api.NewMockAPICommsClient(apiServerUrl) + + // When... + err := RunsUpdate(runName, addTags, removeTags, mockConsole, commsClient, mockTimeService, mockByteReader) + + // Then... + assert.Nil(t, err) +} + +func TestRunsUpdateRemoveTagsFromRunSucceeds(t *testing.T) { + // Given... + runName := "U123" + addTags := []string{} + removeTags := []string{"tag1"} + + getRunsInteraction := utils.NewHttpInteraction("/ras/runs", http.MethodGet) + getRunsInteraction.WriteHttpResponseFunc = func(writer http.ResponseWriter, req *http.Request) { + writer.Header().Set("Content-Type", "application/json") + writer.WriteHeader(http.StatusOK) + writer.Write([]byte(fmt.Sprintf(` + { + "nextCursor": "", + "pageSize": 100, + "amountOfRuns": 1, + "runs":[ %s ] + }`, RUN_U123_WITH_TAGS))) + } + + updateRunInteraction := utils.NewHttpInteraction("/ras/runs/xxx123xxx", http.MethodPut) + updateRunInteraction.WriteHttpResponseFunc = func(writer http.ResponseWriter, req *http.Request) { + writer.Header().Set("Content-Type", "application/json") + writer.WriteHeader(http.StatusOK) + } + + interactions := []utils.HttpInteraction{ + getRunsInteraction, + updateRunInteraction, + } + + server := utils.NewMockHttpServer(t, interactions) + defer server.Server.Close() + + mockConsole := utils.NewMockConsole() + mockTimeService := utils.NewMockTimeService() + mockByteReader := utils.NewMockByteReader() + apiServerUrl := server.Server.URL + commsClient := api.NewMockAPICommsClient(apiServerUrl) + + // When... + err := RunsUpdate(runName, addTags, removeTags, mockConsole, commsClient, mockTimeService, mockByteReader) + + // Then... + assert.Nil(t, err) +} + +func TestRunsUpdateAddAndRemoveTagsSucceeds(t *testing.T) { + // Given... + runName := "U123" + addTags := []string{"tag3"} + removeTags := []string{"tag1"} + + getRunsInteraction := utils.NewHttpInteraction("/ras/runs", http.MethodGet) + getRunsInteraction.WriteHttpResponseFunc = func(writer http.ResponseWriter, req *http.Request) { + writer.Header().Set("Content-Type", "application/json") + writer.WriteHeader(http.StatusOK) + writer.Write([]byte(fmt.Sprintf(` + { + "nextCursor": "", + "pageSize": 100, + "amountOfRuns": 1, + "runs":[ %s ] + }`, RUN_U123_WITH_TAGS))) + } + + updateRunInteraction := utils.NewHttpInteraction("/ras/runs/xxx123xxx", http.MethodPut) + updateRunInteraction.WriteHttpResponseFunc = func(writer http.ResponseWriter, req *http.Request) { + writer.Header().Set("Content-Type", "application/json") + writer.WriteHeader(http.StatusOK) + } + + interactions := []utils.HttpInteraction{ + getRunsInteraction, + updateRunInteraction, + } + + server := utils.NewMockHttpServer(t, interactions) + defer server.Server.Close() + + mockConsole := utils.NewMockConsole() + mockTimeService := utils.NewMockTimeService() + mockByteReader := utils.NewMockByteReader() + apiServerUrl := server.Server.URL + commsClient := api.NewMockAPICommsClient(apiServerUrl) + + // When... + err := RunsUpdate(runName, addTags, removeTags, mockConsole, commsClient, mockTimeService, mockByteReader) + + // Then... + assert.Nil(t, err) +} + +func TestRunsUpdateAddTagsToRunWithNoExistingTagsSucceeds(t *testing.T) { + // Given... + runName := "U123" + addTags := []string{"tag1", "tag2"} + removeTags := []string{} + + getRunsInteraction := utils.NewHttpInteraction("/ras/runs", http.MethodGet) + getRunsInteraction.WriteHttpResponseFunc = func(writer http.ResponseWriter, req *http.Request) { + writer.Header().Set("Content-Type", "application/json") + writer.WriteHeader(http.StatusOK) + writer.Write([]byte(fmt.Sprintf(` + { + "nextCursor": "", + "pageSize": 100, + "amountOfRuns": 1, + "runs":[ %s ] + }`, RUN_U123_NO_TAGS))) + } + + updateRunInteraction := utils.NewHttpInteraction("/ras/runs/xxx123xxx", http.MethodPut) + updateRunInteraction.WriteHttpResponseFunc = func(writer http.ResponseWriter, req *http.Request) { + writer.Header().Set("Content-Type", "application/json") + writer.WriteHeader(http.StatusOK) + } + + interactions := []utils.HttpInteraction{ + getRunsInteraction, + updateRunInteraction, + } + + server := utils.NewMockHttpServer(t, interactions) + defer server.Server.Close() + + mockConsole := utils.NewMockConsole() + mockTimeService := utils.NewMockTimeService() + mockByteReader := utils.NewMockByteReader() + apiServerUrl := server.Server.URL + commsClient := api.NewMockAPICommsClient(apiServerUrl) + + // When... + err := RunsUpdate(runName, addTags, removeTags, mockConsole, commsClient, mockTimeService, mockByteReader) + + // Then... + assert.Nil(t, err) +} + +func TestRunsUpdateWithDuplicateAddTagsRemovesDuplicates(t *testing.T) { + // Given... + runName := "U123" + addTags := []string{"tag3", "tag3", "tag4"} + removeTags := []string{} + + getRunsInteraction := utils.NewHttpInteraction("/ras/runs", http.MethodGet) + getRunsInteraction.WriteHttpResponseFunc = func(writer http.ResponseWriter, req *http.Request) { + writer.Header().Set("Content-Type", "application/json") + writer.WriteHeader(http.StatusOK) + writer.Write([]byte(fmt.Sprintf(` + { + "nextCursor": "", + "pageSize": 100, + "amountOfRuns": 1, + "runs":[ %s ] + }`, RUN_U123_WITH_TAGS))) + } + + updateRunInteraction := utils.NewHttpInteraction("/ras/runs/xxx123xxx", http.MethodPut) + updateRunInteraction.WriteHttpResponseFunc = func(writer http.ResponseWriter, req *http.Request) { + writer.Header().Set("Content-Type", "application/json") + writer.WriteHeader(http.StatusOK) + } + + interactions := []utils.HttpInteraction{ + getRunsInteraction, + updateRunInteraction, + } + + server := utils.NewMockHttpServer(t, interactions) + defer server.Server.Close() + + mockConsole := utils.NewMockConsole() + mockTimeService := utils.NewMockTimeService() + mockByteReader := utils.NewMockByteReader() + apiServerUrl := server.Server.URL + commsClient := api.NewMockAPICommsClient(apiServerUrl) + + // When... + err := RunsUpdate(runName, addTags, removeTags, mockConsole, commsClient, mockTimeService, mockByteReader) + + // Then... + assert.Nil(t, err) +} + +func TestRunsUpdateWithDuplicateRemoveTagsRemovesDuplicates(t *testing.T) { + // Given... + runName := "U123" + addTags := []string{} + removeTags := []string{"tag1", "tag1", "tag2"} + + getRunsInteraction := utils.NewHttpInteraction("/ras/runs", http.MethodGet) + getRunsInteraction.WriteHttpResponseFunc = func(writer http.ResponseWriter, req *http.Request) { + writer.Header().Set("Content-Type", "application/json") + writer.WriteHeader(http.StatusOK) + writer.Write([]byte(fmt.Sprintf(` + { + "nextCursor": "", + "pageSize": 100, + "amountOfRuns": 1, + "runs":[ %s ] + }`, RUN_U123_WITH_TAGS))) + } + + updateRunInteraction := utils.NewHttpInteraction("/ras/runs/xxx123xxx", http.MethodPut) + updateRunInteraction.WriteHttpResponseFunc = func(writer http.ResponseWriter, req *http.Request) { + writer.Header().Set("Content-Type", "application/json") + writer.WriteHeader(http.StatusOK) + } + + interactions := []utils.HttpInteraction{ + getRunsInteraction, + updateRunInteraction, + } + + server := utils.NewMockHttpServer(t, interactions) + defer server.Server.Close() + + mockConsole := utils.NewMockConsole() + mockTimeService := utils.NewMockTimeService() + mockByteReader := utils.NewMockByteReader() + apiServerUrl := server.Server.URL + commsClient := api.NewMockAPICommsClient(apiServerUrl) + + // When... + err := RunsUpdate(runName, addTags, removeTags, mockConsole, commsClient, mockTimeService, mockByteReader) + + // Then... + assert.Nil(t, err) +} + +func TestRunsUpdateWithUpdateFailureReturnsError(t *testing.T) { + // Given... + runName := "U123" + addTags := []string{"tag3"} + removeTags := []string{} + + getRunsInteraction := utils.NewHttpInteraction("/ras/runs", http.MethodGet) + getRunsInteraction.WriteHttpResponseFunc = func(writer http.ResponseWriter, req *http.Request) { + writer.Header().Set("Content-Type", "application/json") + writer.WriteHeader(http.StatusOK) + writer.Write([]byte(fmt.Sprintf(` + { + "nextCursor": "", + "pageSize": 100, + "amountOfRuns": 1, + "runs":[ %s ] + }`, RUN_U123_WITH_TAGS))) + } + + updateRunInteraction := utils.NewHttpInteraction("/ras/runs/xxx123xxx", http.MethodPut) + updateRunInteraction.WriteHttpResponseFunc = func(writer http.ResponseWriter, req *http.Request) { + writer.Header().Set("Content-Type", "application/json") + writer.WriteHeader(http.StatusInternalServerError) + writer.Write([]byte(`{"error": "Internal server error"}`)) + } + + interactions := []utils.HttpInteraction{ + getRunsInteraction, + updateRunInteraction, + } + + server := utils.NewMockHttpServer(t, interactions) + defer server.Server.Close() + + mockConsole := utils.NewMockConsole() + mockTimeService := utils.NewMockTimeService() + mockByteReader := utils.NewMockByteReader() + apiServerUrl := server.Server.URL + commsClient := api.NewMockAPICommsClient(apiServerUrl) + + // When... + err := RunsUpdate(runName, addTags, removeTags, mockConsole, commsClient, mockTimeService, mockByteReader) + + // Then... + assert.NotNil(t, err) + assert.ErrorContains(t, err, "GAL1280E") +} + +func TestRunsUpdateAddingExistingTagDoesNotDuplicate(t *testing.T) { + // Given... + runName := "U123" + addTags := []string{"tag1"} // tag1 already exists in the run + removeTags := []string{} + + getRunsInteraction := utils.NewHttpInteraction("/ras/runs", http.MethodGet) + getRunsInteraction.WriteHttpResponseFunc = func(writer http.ResponseWriter, req *http.Request) { + writer.Header().Set("Content-Type", "application/json") + writer.WriteHeader(http.StatusOK) + writer.Write([]byte(fmt.Sprintf(` + { + "nextCursor": "", + "pageSize": 100, + "amountOfRuns": 1, + "runs":[ %s ] + }`, RUN_U123_WITH_TAGS))) + } + + updateRunInteraction := utils.NewHttpInteraction("/ras/runs/xxx123xxx", http.MethodPut) + updateRunInteraction.WriteHttpResponseFunc = func(writer http.ResponseWriter, req *http.Request) { + writer.Header().Set("Content-Type", "application/json") + writer.WriteHeader(http.StatusOK) + } + + interactions := []utils.HttpInteraction{ + getRunsInteraction, + updateRunInteraction, + } + + server := utils.NewMockHttpServer(t, interactions) + defer server.Server.Close() + + mockConsole := utils.NewMockConsole() + mockTimeService := utils.NewMockTimeService() + mockByteReader := utils.NewMockByteReader() + apiServerUrl := server.Server.URL + commsClient := api.NewMockAPICommsClient(apiServerUrl) + + // When... + err := RunsUpdate(runName, addTags, removeTags, mockConsole, commsClient, mockTimeService, mockByteReader) + + // Then... + assert.Nil(t, err) +} + +func TestRunsUpdateRemovingNonExistentTagSucceeds(t *testing.T) { + // Given... + runName := "U123" + addTags := []string{} + removeTags := []string{"tag99"} // tag99 doesn't exist in the run + + getRunsInteraction := utils.NewHttpInteraction("/ras/runs", http.MethodGet) + getRunsInteraction.WriteHttpResponseFunc = func(writer http.ResponseWriter, req *http.Request) { + writer.Header().Set("Content-Type", "application/json") + writer.WriteHeader(http.StatusOK) + writer.Write([]byte(fmt.Sprintf(` + { + "nextCursor": "", + "pageSize": 100, + "amountOfRuns": 1, + "runs":[ %s ] + }`, RUN_U123_WITH_TAGS))) + } + + updateRunInteraction := utils.NewHttpInteraction("/ras/runs/xxx123xxx", http.MethodPut) + updateRunInteraction.WriteHttpResponseFunc = func(writer http.ResponseWriter, req *http.Request) { + writer.Header().Set("Content-Type", "application/json") + writer.WriteHeader(http.StatusOK) + } + + interactions := []utils.HttpInteraction{ + getRunsInteraction, + updateRunInteraction, + } + + server := utils.NewMockHttpServer(t, interactions) + defer server.Server.Close() + + mockConsole := utils.NewMockConsole() + mockTimeService := utils.NewMockTimeService() + mockByteReader := utils.NewMockByteReader() + apiServerUrl := server.Server.URL + commsClient := api.NewMockAPICommsClient(apiServerUrl) + + // When... + err := RunsUpdate(runName, addTags, removeTags, mockConsole, commsClient, mockTimeService, mockByteReader) + + // Then... + assert.Nil(t, err) +} + +func TestRunsUpdateRemoveAllTagsSucceeds(t *testing.T) { + // Given... + runName := "U123" + addTags := []string{} + removeTags := []string{"tag1", "tag2"} + + getRunsInteraction := utils.NewHttpInteraction("/ras/runs", http.MethodGet) + getRunsInteraction.WriteHttpResponseFunc = func(writer http.ResponseWriter, req *http.Request) { + writer.Header().Set("Content-Type", "application/json") + writer.WriteHeader(http.StatusOK) + writer.Write([]byte(fmt.Sprintf(` + { + "nextCursor": "", + "pageSize": 100, + "amountOfRuns": 1, + "runs":[ %s ] + }`, RUN_U123_WITH_TAGS))) + } + + updateRunInteraction := utils.NewHttpInteraction("/ras/runs/xxx123xxx", http.MethodPut) + updateRunInteraction.WriteHttpResponseFunc = func(writer http.ResponseWriter, req *http.Request) { + writer.Header().Set("Content-Type", "application/json") + writer.WriteHeader(http.StatusOK) + } + + interactions := []utils.HttpInteraction{ + getRunsInteraction, + updateRunInteraction, + } + + server := utils.NewMockHttpServer(t, interactions) + defer server.Server.Close() + + mockConsole := utils.NewMockConsole() + mockTimeService := utils.NewMockTimeService() + mockByteReader := utils.NewMockByteReader() + apiServerUrl := server.Server.URL + commsClient := api.NewMockAPICommsClient(apiServerUrl) + + // When... + err := RunsUpdate(runName, addTags, removeTags, mockConsole, commsClient, mockTimeService, mockByteReader) + + // Then... + assert.Nil(t, err) +} + +func TestRunsUpdateWithEmptyTagInAddTagsReturnsError(t *testing.T) { + // Given... + runName := "U123" + addTags := []string{""} + removeTags := []string{} + + mockConsole := utils.NewMockConsole() + mockTimeService := utils.NewMockTimeService() + mockByteReader := utils.NewMockByteReader() + + interactions := []utils.HttpInteraction{} + server := utils.NewMockHttpServer(t, interactions) + defer server.Server.Close() + + apiServerUrl := server.Server.URL + commsClient := api.NewMockAPICommsClient(apiServerUrl) + + // When... + err := RunsUpdate(runName, addTags, removeTags, mockConsole, commsClient, mockTimeService, mockByteReader) + + // Then... + assert.NotNil(t, err) + assert.ErrorContains(t, err, "GAL1282E") +} + +func TestRunsUpdateWithEmptyTagInRemoveTagsReturnsError(t *testing.T) { + // Given... + runName := "U123" + addTags := []string{} + removeTags := []string{""} + + mockConsole := utils.NewMockConsole() + mockTimeService := utils.NewMockTimeService() + mockByteReader := utils.NewMockByteReader() + + interactions := []utils.HttpInteraction{} + server := utils.NewMockHttpServer(t, interactions) + defer server.Server.Close() + + apiServerUrl := server.Server.URL + commsClient := api.NewMockAPICommsClient(apiServerUrl) + + // When... + err := RunsUpdate(runName, addTags, removeTags, mockConsole, commsClient, mockTimeService, mockByteReader) + + // Then... + assert.NotNil(t, err) + assert.ErrorContains(t, err, "GAL1282E") +} + +func TestRunsUpdateWithWhitespaceOnlyTagReturnsError(t *testing.T) { + // Given... + runName := "U123" + addTags := []string{" "} + removeTags := []string{} + + mockConsole := utils.NewMockConsole() + mockTimeService := utils.NewMockTimeService() + mockByteReader := utils.NewMockByteReader() + + interactions := []utils.HttpInteraction{} + server := utils.NewMockHttpServer(t, interactions) + defer server.Server.Close() + + apiServerUrl := server.Server.URL + commsClient := api.NewMockAPICommsClient(apiServerUrl) + + // When... + err := RunsUpdate(runName, addTags, removeTags, mockConsole, commsClient, mockTimeService, mockByteReader) + + // Then... + assert.NotNil(t, err) + assert.ErrorContains(t, err, "GAL1282E") +} + +func TestRunsUpdateWithNonLatin1TagReturnsError(t *testing.T) { + // Given... + runName := "U123" + addTags := []string{"tag-with-emoji-😀"} + removeTags := []string{} + + mockConsole := utils.NewMockConsole() + mockTimeService := utils.NewMockTimeService() + mockByteReader := utils.NewMockByteReader() + + interactions := []utils.HttpInteraction{} + server := utils.NewMockHttpServer(t, interactions) + defer server.Server.Close() + + apiServerUrl := server.Server.URL + commsClient := api.NewMockAPICommsClient(apiServerUrl) + + // When... + err := RunsUpdate(runName, addTags, removeTags, mockConsole, commsClient, mockTimeService, mockByteReader) + + // Then... + assert.NotNil(t, err) + assert.ErrorContains(t, err, "GAL1282E") +} diff --git a/modules/cli/pkg/tags/tags.go b/modules/cli/pkg/tags/tags.go new file mode 100644 index 000000000..166583f53 --- /dev/null +++ b/modules/cli/pkg/tags/tags.go @@ -0,0 +1,46 @@ +/* + * Copyright contributors to the Galasa project + * + * SPDX-License-Identifier: EPL-2.0 + */ +package tags + +import ( + "log" + "strings" + "github.com/galasa-dev/cli/pkg/utils" + galasaErrors "github.com/galasa-dev/cli/pkg/errors" +) + +func validateTagName(tagName string) error { + var err error + log.Println("Validating the provided tag name") + + err = validateStringIsLatin1AndNotBlank(tagName, galasaErrors.GALASA_ERROR_TAGS_INVALID_NAME) + + if err == nil { + log.Println("Tag name validated OK") + } + return err +} + +func validateDescription(description string) error { + var err error + log.Println("Validating the provided description") + + err = validateStringIsLatin1AndNotBlank(description, galasaErrors.GALASA_ERROR_INVALID_TAG_DESCRIPTION) + if err == nil { + log.Println("Description validated OK") + } + return err +} + +func validateStringIsLatin1AndNotBlank(str string, errMessageType *galasaErrors.MessageType) error { + var err error + str = strings.TrimSpace(str) + + if str == "" || !utils.IsLatin1(str) { + err = galasaErrors.NewGalasaError(errMessageType) + } + return err +} \ No newline at end of file diff --git a/modules/cli/pkg/tags/tagsSet.go b/modules/cli/pkg/tags/tagsSet.go index 13039b3b4..311b6c7e2 100644 --- a/modules/cli/pkg/tags/tagsSet.go +++ b/modules/cli/pkg/tags/tagsSet.go @@ -12,13 +12,11 @@ import ( "log" "math" "net/http" - "strings" "github.com/galasa-dev/cli/pkg/embedded" galasaErrors "github.com/galasa-dev/cli/pkg/errors" "github.com/galasa-dev/cli/pkg/galasaapi" "github.com/galasa-dev/cli/pkg/spi" - "github.com/galasa-dev/cli/pkg/utils" ) const ( @@ -109,36 +107,3 @@ func sendTagUpdateToRestApi( } return tagGotBack, err } - -func validateTagName(tagName string) error { - var err error - log.Println("Validating the provided tag name") - - err = validateStringIsLatin1AndNotBlank(tagName, galasaErrors.GALASA_ERROR_INVALID_TAG_NAME) - - if err == nil { - log.Println("Tag name validated OK") - } - return err -} - -func validateDescription(description string) error { - var err error - log.Println("Validating the provided description") - - err = validateStringIsLatin1AndNotBlank(description, galasaErrors.GALASA_ERROR_INVALID_TAG_DESCRIPTION) - if err == nil { - log.Println("Description validated OK") - } - return err -} - -func validateStringIsLatin1AndNotBlank(str string, errMessageType *galasaErrors.MessageType) error { - var err error - str = strings.TrimSpace(str) - - if str == "" || !utils.IsLatin1(str) { - err = galasaErrors.NewGalasaError(errMessageType) - } - return err -} \ No newline at end of file diff --git a/modules/cli/test-scripts/gherkin-runs-tests.sh b/modules/cli/test-scripts/gherkin-runs-tests.sh index 25b489801..85e8c6586 100644 --- a/modules/cli/test-scripts/gherkin-runs-tests.sh +++ b/modules/cli/test-scripts/gherkin-runs-tests.sh @@ -81,7 +81,7 @@ function SubmitLocalSimpleGherkinTest { gherkin_feature_filename="simple.feature" - feature_file_path="$ORIGINAL_DIR/temp/${gherkin_feature_filename}" + feature_file_path="$BASEDIR/temp/${gherkin_feature_filename}" cat << EOF > $feature_file_path Feature: GherkinSubmitTest @@ -95,9 +95,9 @@ Feature: GherkinSubmitTest EOF success "OK" - log_output_file=$ORIGINAL_DIR/temp/$gherkin_feature_filename.log + log_output_file=$BASEDIR/temp/$gherkin_feature_filename.log - cmd="$ORIGINAL_DIR/bin/${binary} runs submit local \ + cmd="$BASEDIR/bin/${binary} runs submit local \ --remoteMaven https://development.galasa.dev/main/maven-repo/obr \ --gherkin file://$feature_file_path \ --log $log_output_file" @@ -134,9 +134,9 @@ function SubmitTestWhichUsesACPSVariable { gherkin_feature_filename="scenario-cps-prop-use.feature" - feature_file_path="$ORIGINAL_DIR/temp/${gherkin_feature_filename}" + feature_file_path="$BASEDIR/temp/${gherkin_feature_filename}" - echo "test.fruit.name=peach" > $ORIGINAL_DIR/temp/home/cps.properties + echo "test.fruit.name=peach" > $BASEDIR/temp/home/cps.properties cat << EOF > $feature_file_path Feature: GherkinSubmitTest @@ -146,9 +146,9 @@ Feature: GherkinSubmitTest EOF success "OK" - log_output_file=$ORIGINAL_DIR/temp/$gherkin_feature_filename.log + log_output_file=$BASEDIR/temp/$gherkin_feature_filename.log - cmd="$ORIGINAL_DIR/bin/${binary} runs submit local \ + cmd="$BASEDIR/bin/${binary} runs submit local \ --remoteMaven https://development.galasa.dev/main/maven-repo/obr \ --gherkin file://$feature_file_path \ --log $log_output_file" @@ -181,7 +181,7 @@ function SubmitLocalGherkinScenarioOutlineTest { gherkin_feature_filename="scenario-outline.feature" - feature_file_path="$ORIGINAL_DIR/temp/${gherkin_feature_filename}" + feature_file_path="$BASEDIR/temp/${gherkin_feature_filename}" cat << EOF > $feature_file_path Feature: GherkinSubmitTest @@ -200,9 +200,9 @@ Feature: GherkinSubmitTest EOF success "OK" - log_output_file=$ORIGINAL_DIR/temp/$gherkin_feature_filename.log + log_output_file=$BASEDIR/temp/$gherkin_feature_filename.log - cmd="$ORIGINAL_DIR/bin/${binary} runs submit local \ + cmd="$BASEDIR/bin/${binary} runs submit local \ --remoteMaven https://development.galasa.dev/main/maven-repo/obr \ --gherkin file://$feature_file_path \ --log $log_output_file" @@ -237,7 +237,7 @@ EOF function SubmittingBadPrefixLocalGherkinTest { h1 "Submitting bad prefix gherkin feature" - cmd="$ORIGINAL_DIR/bin/${binary} runs submit local \ + cmd="$BASEDIR/bin/${binary} runs submit local \ --remoteMaven https://development.galasa.dev/main/maven-repo/obr \ --gherkin $input_file \ --log -" @@ -258,7 +258,7 @@ function SubmittingBadPrefixLocalGherkinTest { function SubmittingBadSuffixLocalGherkinTest { h1 "Submitting bad suffix gherkin feature" - cmd="$ORIGINAL_DIR/bin/${binary} runs submit local \ + cmd="$BASEDIR/bin/${binary} runs submit local \ --remoteMaven https://development.galasa.dev/main/maven-repo/obr \ --gherkin file:///gherkin \ --log -"