From d96c7257b906bc94c3b7364063882797aba42db1 Mon Sep 17 00:00:00 2001 From: Aashir Siddiqui Date: Fri, 28 Mar 2025 15:01:23 +0000 Subject: [PATCH 1/4] CLI now supports streams command Signed-off-by: Aashir Siddiqui --- docs/generated/errors-list.md | 2 + docs/generated/galasactl.md | 1 + docs/generated/galasactl_streams.md | 29 ++++ docs/generated/galasactl_streams_get.md | 33 ++++ pkg/cmd/commandCollection.go | 26 +++ pkg/cmd/streams.go | 98 +++++++++++ pkg/cmd/streamsGet.go | 146 ++++++++++++++++ pkg/cmd/streamsGet_test.go | 63 +++++++ pkg/cmd/streams_test.go | 59 +++++++ pkg/errors/errorMessage.go | 4 + pkg/streams/streams.go | 26 +++ pkg/streams/streamsGet.go | 136 +++++++++++++++ pkg/streams/streamsGet_test.go | 205 +++++++++++++++++++++++ pkg/streams/streams_test.go | 23 +++ pkg/streamsformatter/streamsFormatter.go | 33 ++++ pkg/streamsformatter/summaryFormatter.go | 77 +++++++++ 16 files changed, 961 insertions(+) create mode 100644 docs/generated/galasactl_streams.md create mode 100644 docs/generated/galasactl_streams_get.md create mode 100644 pkg/cmd/streams.go create mode 100644 pkg/cmd/streamsGet.go create mode 100644 pkg/cmd/streamsGet_test.go create mode 100644 pkg/cmd/streams_test.go create mode 100644 pkg/streams/streams.go create mode 100644 pkg/streams/streamsGet.go create mode 100644 pkg/streams/streamsGet_test.go create mode 100644 pkg/streams/streams_test.go create mode 100644 pkg/streamsformatter/streamsFormatter.go create mode 100644 pkg/streamsformatter/summaryFormatter.go diff --git a/docs/generated/errors-list.md b/docs/generated/errors-list.md index 08062578..b772a999 100644 --- a/docs/generated/errors-list.md +++ b/docs/generated/errors-list.md @@ -227,3 +227,5 @@ The `galasactl` tool can generate the following errors: - GAL2504I: The request to cancel run '{}' has been accepted by the server. +- GAL2505I: The stream name provided by the --name field cannot be an empty string. +- GAL2506I: Could not get list of test streams from API server. Reason: '{}'. Ensure you have allocated a personal access token and configured your client program by setting your GALASA_TOKEN as an environment variable or by storing it in your galasactl.properties file diff --git a/docs/generated/galasactl.md b/docs/generated/galasactl.md index c3b73e23..f6d0eda0 100644 --- a/docs/generated/galasactl.md +++ b/docs/generated/galasactl.md @@ -24,5 +24,6 @@ A tool for controlling Galasa resources using the command-line. * [galasactl roles](galasactl_roles.md) - Manage roles stored in the Galasa service * [galasactl runs](galasactl_runs.md) - Manage test runs in the ecosystem * [galasactl secrets](galasactl_secrets.md) - Manage secrets stored in the Galasa service's credentials store +* [galasactl streams](galasactl_streams.md) - Manages test streams in an ecosystem * [galasactl users](galasactl_users.md) - Manages users in an ecosystem diff --git a/docs/generated/galasactl_streams.md b/docs/generated/galasactl_streams.md new file mode 100644 index 00000000..7e2c72ff --- /dev/null +++ b/docs/generated/galasactl_streams.md @@ -0,0 +1,29 @@ +## galasactl streams + +Manages test streams in an ecosystem + +### Synopsis + +Allows interaction with the streams servlet to return information about test streams. + +### Options + +``` + -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 + -h, --help Displays the options for the 'streams' command. + --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) +``` + +### Options inherited from parent commands + +``` + --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. +``` + +### SEE ALSO + +* [galasactl](galasactl.md) - CLI for Galasa +* [galasactl streams get](galasactl_streams_get.md) - Gets a list of test streams + diff --git a/docs/generated/galasactl_streams_get.md b/docs/generated/galasactl_streams_get.md new file mode 100644 index 00000000..9fa3ad71 --- /dev/null +++ b/docs/generated/galasactl_streams_get.md @@ -0,0 +1,33 @@ +## galasactl streams get + +Gets a list of test streams + +### Synopsis + +Get a list of test streams stored in the Galasa API server + +``` +galasactl streams get [flags] +``` + +### Options + +``` + -h, --help Displays the options for the 'streams get' command. + --name string An optional field indicating the name of a test stream +``` + +### 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 streams](galasactl_streams.md) - Manages test streams in an ecosystem + diff --git a/pkg/cmd/commandCollection.go b/pkg/cmd/commandCollection.go index 84beabf4..8aa9facb 100644 --- a/pkg/cmd/commandCollection.go +++ b/pkg/cmd/commandCollection.go @@ -69,6 +69,8 @@ const ( COMMAND_NAME_USERS_DELETE = "users delete" COMMAND_NAME_ROLES = "roles" COMMAND_NAME_ROLES_GET = "roles get" + COMMAND_NAME_STREAMS = "streams" + COMMAND_NAME_STREAMS_GET = "streams get" ) // ----------------------------------------------------------------- @@ -165,6 +167,10 @@ func (commands *commandCollectionImpl) init(factory spi.Factory) error { err = commands.addRolesCommands(factory, rootCommand, commsFlagSet) } + if err == nil { + err = commands.addStreamsCommands(factory, rootCommand, commsFlagSet) + } + if err == nil { commands.setHelpFlags() } @@ -478,6 +484,26 @@ func (commands *commandCollectionImpl) addRolesCommands(factory spi.Factory, roo return err } +func (commands *commandCollectionImpl) addStreamsCommands(factory spi.Factory, rootCommand spi.GalasaCommand, commsFlagSet GalasaFlagSet) error { + + var err error + var streamsCommand spi.GalasaCommand + var streamsGetCommand spi.GalasaCommand + + streamsCommand, err = NewStreamsCommand(rootCommand, commsFlagSet) + + if err == nil { + streamsGetCommand, err = NewStreamsGetCommand(factory, streamsCommand, commsFlagSet) + if err == nil { + commands.commandMap[streamsCommand.Name()] = streamsCommand + commands.commandMap[streamsGetCommand.Name()] = streamsGetCommand + } + } + + return err + +} + func (commands *commandCollectionImpl) setHelpFlags() { for _, command := range commands.commandMap { command.CobraCommand().Flags().BoolP("help", "h", false, "Displays the options for the '"+command.Name()+"' command.") diff --git a/pkg/cmd/streams.go b/pkg/cmd/streams.go new file mode 100644 index 00000000..87e9c2f7 --- /dev/null +++ b/pkg/cmd/streams.go @@ -0,0 +1,98 @@ +/* + * Copyright contributors to the Galasa project + * + * SPDX-License-Identifier: EPL-2.0 + */ + +package cmd + +import ( + "github.com/galasa-dev/cli/pkg/spi" + "github.com/spf13/cobra" +) + +type StreamsCmdValues struct { + name string +} + +type StreamsCommand struct { + values *StreamsCmdValues + cobraCommand *cobra.Command +} + +// ------------------------------------------------------------------------------------------------ +// Constructors methods +// ------------------------------------------------------------------------------------------------ +func NewStreamsCommand(rootCmd spi.GalasaCommand, commsFlagSet GalasaFlagSet) (spi.GalasaCommand, error) { + + cmd := new(StreamsCommand) + err := cmd.init(rootCmd, commsFlagSet) + return cmd, err + +} + +// ------------------------------------------------------------------------------------------------ +// Public methods +// ------------------------------------------------------------------------------------------------ +func (cmd *StreamsCommand) Name() string { + return COMMAND_NAME_STREAMS +} + +func (cmd *StreamsCommand) CobraCommand() *cobra.Command { + return cmd.cobraCommand +} + +func (cmd *StreamsCommand) Values() interface{} { + return cmd.values +} + +// ------------------------------------------------------------------------------------------------ +// Private methods +// ------------------------------------------------------------------------------------------------ + +func (cmd *StreamsCommand) init(rootCmd spi.GalasaCommand, commsFlagSet GalasaFlagSet) error { + + var err error + cmd.values = &StreamsCmdValues{} + cmd.cobraCommand = cmd.createCobraCommand(rootCmd, commsFlagSet) + + return err + +} + +func (cmd *StreamsCommand) createCobraCommand( + rootCommand spi.GalasaCommand, + commsFlagSet GalasaFlagSet, +) *cobra.Command { + + streamsCobraCmd := &cobra.Command{ + Use: "streams", + Short: "Manages test streams in an ecosystem", + Long: "Allows interaction with the streams servlet to return information about test streams.", + } + + streamsCobraCmd.PersistentFlags().AddFlagSet(commsFlagSet.Flags()) + rootCommand.CobraCommand().AddCommand(streamsCobraCmd) + + return streamsCobraCmd + +} + +func addStreamNameFlag(cmd *cobra.Command, isMandatory bool, streamCmdValues *StreamsCmdValues) { + + flagName := "name" + var description string + + if isMandatory { + description = "A mandatory field indicating the name of a test stream." + } else { + description = "An optional field indicating the name of a test stream" + } + + cmd.Flags().StringVar(&streamCmdValues.name, flagName, "", description) + + if isMandatory { + cmd.MarkFlagRequired(flagName) + } + +} diff --git a/pkg/cmd/streamsGet.go b/pkg/cmd/streamsGet.go new file mode 100644 index 00000000..19267ba5 --- /dev/null +++ b/pkg/cmd/streamsGet.go @@ -0,0 +1,146 @@ +/* + * Copyright contributors to the Galasa project + * + * SPDX-License-Identifier: EPL-2.0 + */ + +package cmd + +import ( + "log" + + "github.com/galasa-dev/cli/pkg/api" + "github.com/galasa-dev/cli/pkg/galasaapi" + "github.com/galasa-dev/cli/pkg/spi" + "github.com/galasa-dev/cli/pkg/streams" + "github.com/galasa-dev/cli/pkg/utils" + "github.com/spf13/cobra" +) + +// Objective: Allow user to do this: +// +// streams get +type StreamsGetCommand struct { + cobraCommand *cobra.Command +} + +// ------------------------------------------------------------------------------------------------ +// Constructors methods +// ------------------------------------------------------------------------------------------------ +func NewStreamsGetCommand( + factory spi.Factory, + streamsGetCommand spi.GalasaCommand, + commsFlagSet GalasaFlagSet, +) (spi.GalasaCommand, error) { + + cmd := new(StreamsGetCommand) + err := cmd.init(factory, streamsGetCommand, commsFlagSet) + return cmd, err + +} + +// ------------------------------------------------------------------------------------------------ +// Public methods +// ------------------------------------------------------------------------------------------------ +func (cmd *StreamsGetCommand) Name() string { + return COMMAND_NAME_STREAMS_GET +} + +func (cmd *StreamsGetCommand) CobraCommand() *cobra.Command { + return cmd.cobraCommand +} + +func (cmd *StreamsGetCommand) Values() interface{} { + return nil +} + +// ------------------------------------------------------------------------------------------------ +// Private methods +// ------------------------------------------------------------------------------------------------ +func (cmd *StreamsGetCommand) init(factory spi.Factory, streamsCommand spi.GalasaCommand, commsFlagSet GalasaFlagSet) error { + + var err error + cmd.cobraCommand, err = cmd.createCobraCmd(factory, streamsCommand, commsFlagSet) + return err + +} + +func (cmd *StreamsGetCommand) createCobraCmd( + factory spi.Factory, + streamsCommand spi.GalasaCommand, + commsFlagSet GalasaFlagSet, +) (*cobra.Command, error) { + + var err error + + commsFlagSetValues := commsFlagSet.Values().(*CommsFlagSetValues) + streamCommandValues := streamsCommand.Values().(*StreamsCmdValues) + + streamsGetCobraCmd := &cobra.Command{ + Use: "get", + Short: "Gets a list of test streams", + Long: "Get a list of test streams stored in the Galasa API server", + Aliases: []string{COMMAND_NAME_STREAMS_GET}, + RunE: func(cobraCommand *cobra.Command, args []string) error { + return cmd.executeStreamsGet( + factory, streamsCommand.Values().(*StreamsCmdValues), commsFlagSetValues, + ) + }, + } + + addStreamNameFlag(streamsGetCobraCmd, false, streamCommandValues) + streamsCommand.CobraCommand().AddCommand(streamsGetCobraCmd) + + return streamsGetCobraCmd, err + +} + +func (cmd *StreamsGetCommand) executeStreamsGet( + factory spi.Factory, + streamsCmdValues *StreamsCmdValues, + 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 + log.Println("Galasa CLI - Get users from the ecosystem") + + 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() + getStreamsFunc := func(apiClient *galasaapi.APIClient) error { + return streams.GetStreams(streamsCmdValues.name, apiClient, console) + } + + err = commsClient.RunAuthenticatedCommandWithRateLimitRetries(getStreamsFunc) + + } + + } + + } + + return err +} diff --git a/pkg/cmd/streamsGet_test.go b/pkg/cmd/streamsGet_test.go new file mode 100644 index 00000000..3400ef07 --- /dev/null +++ b/pkg/cmd/streamsGet_test.go @@ -0,0 +1,63 @@ +/* + * Copyright contributors to the Galasa project + * + * SPDX-License-Identifier: EPL-2.0 + */ + +package cmd + +import ( + "testing" + + "github.com/galasa-dev/cli/pkg/utils" + "github.com/stretchr/testify/assert" +) + +func TestStreamsGetCommandInCommandCollectionHasName(t *testing.T) { + + factory := utils.NewMockFactory() + commands, _ := NewCommandCollection(factory) + + StreamsGetCommand, err := commands.GetCommand(COMMAND_NAME_STREAMS_GET) + assert.Nil(t, err) + + assert.Equal(t, COMMAND_NAME_STREAMS_GET, StreamsGetCommand.Name()) + assert.NotNil(t, StreamsGetCommand.CobraCommand()) +} + +func TestStreamsGetHelpFlagSetCorrectly(t *testing.T) { + // Given... + factory := utils.NewMockFactory() + + var args []string = []string{"streams", "get", "--help"} + + // When... + err := Execute(factory, args) + + // Then... + // Check what the user saw is reasonable. + checkOutput("Displays the options for the 'streams get' command.", "", factory, t) + + assert.Nil(t, err) +} + +func TestStreamsGetNamespaceNameFlagsReturnsOk(t *testing.T) { + // Given... + factory := utils.NewMockFactory() + commandCollection, _ := setupTestCommandCollection(COMMAND_NAME_STREAMS_GET, factory, t) + + var args []string = []string{"streams", "get", "--name", "mystream"} + + // When... + err := commandCollection.Execute(args) + + // Then... + assert.Nil(t, err) + + // Check what the user saw was reasonable + checkOutput("", "", factory, t) + + parentCmd, err := commandCollection.GetCommand(COMMAND_NAME_STREAMS) + assert.Nil(t, err) + assert.Contains(t, parentCmd.Values().(*StreamsCmdValues).name, "mystream") +} diff --git a/pkg/cmd/streams_test.go b/pkg/cmd/streams_test.go new file mode 100644 index 00000000..a778d9d4 --- /dev/null +++ b/pkg/cmd/streams_test.go @@ -0,0 +1,59 @@ +/* + * Copyright contributors to the Galasa project + * + * SPDX-License-Identifier: EPL-2.0 + */ +package cmd + +import ( + "testing" + + "github.com/galasa-dev/cli/pkg/utils" + "github.com/stretchr/testify/assert" +) + +func TestStreamsCommandInCommandCollection(t *testing.T) { + + factory := utils.NewMockFactory() + commands, _ := NewCommandCollection(factory) + + streamsCommand, err := commands.GetCommand(COMMAND_NAME_STREAMS) + assert.Nil(t, err) + + assert.NotNil(t, streamsCommand) + assert.Equal(t, COMMAND_NAME_STREAMS, streamsCommand.Name()) + assert.NotNil(t, streamsCommand.Values()) + assert.IsType(t, &StreamsCmdValues{}, streamsCommand.Values()) + assert.NotNil(t, streamsCommand.CobraCommand()) +} + +func TestStreamsHelpFlagSetCorrectly(t *testing.T) { + // Given... + factory := utils.NewMockFactory() + + var args []string = []string{"streams", "--help"} + + // When... + err := Execute(factory, args) + + // Then... + + // Check what the user saw is reasonable. + checkOutput("Displays the options for the 'streams' command.", "", factory, t) + + assert.Nil(t, err) +} + +func TestStreamsNoCommandsProducesUsageReport(t *testing.T) { + // Given... + factory := utils.NewMockFactory() + var args []string = []string{"streams"} + + // When... + err := Execute(factory, args) + + // Then... + assert.Nil(t, err) + // Check what the user saw was reasonable + checkOutput("Usage:\n galasactl streams [command]", "", factory, t) +} diff --git a/pkg/errors/errorMessage.go b/pkg/errors/errorMessage.go index 2cb18afc..d04ce3fa 100644 --- a/pkg/errors/errorMessage.go +++ b/pkg/errors/errorMessage.go @@ -426,4 +426,8 @@ var ( GALASA_INFO_FOLDER_DOWNLOADED_TO = NewMessageType("GAL2501I: Downloaded %d artifacts to folder '%s'\n", 2501, STACK_TRACE_NOT_WANTED) GALASA_INFO_RUNS_RESET_SUCCESS = NewMessageType("GAL2503I: The request to reset run '%s' has been accepted by the server.\n", 2503, STACK_TRACE_NOT_WANTED) GALASA_INFO_RUNS_CANCEL_SUCCESS = NewMessageType("GAL2504I: The request to cancel run '%s' has been accepted by the server.\n", 2504, STACK_TRACE_NOT_WANTED) + + GALASA_ERROR_MISSING_STREAM_NAME_FLAG = NewMessageType("GAL2505I: The stream name provided by the --name field cannot be an empty string.", 2505, STACK_TRACE_NOT_WANTED) + GALASA_ERROR_RETRIEVING_STREAMS_FROM_API_SERVER = NewMessageType("GAL2506I: Could not get list of test streams from API server. Reason: '%s'."+ + " Ensure you have allocated a personal access token and configured your client program by setting your GALASA_TOKEN as an environment variable or by storing it in your galasactl.properties file", 2506, STACK_TRACE_WANTED) ) diff --git a/pkg/streams/streams.go b/pkg/streams/streams.go new file mode 100644 index 00000000..7e653c1b --- /dev/null +++ b/pkg/streams/streams.go @@ -0,0 +1,26 @@ +/* + * Copyright contributors to the Galasa project + * + * SPDX-License-Identifier: EPL-2.0 + */ + +package streams + +import ( + "strings" + + galasaErrors "github.com/galasa-dev/cli/pkg/errors" +) + +func validateStreamName(streamName string) (string, error) { + + var err error + streamName = strings.TrimSpace(streamName) + + if streamName == "" { + err = galasaErrors.NewGalasaError(galasaErrors.GALASA_ERROR_MISSING_STREAM_NAME_FLAG) + } + + return streamName, err + +} diff --git a/pkg/streams/streamsGet.go b/pkg/streams/streamsGet.go new file mode 100644 index 00000000..e9fb4a34 --- /dev/null +++ b/pkg/streams/streamsGet.go @@ -0,0 +1,136 @@ +/* + * Copyright contributors to the Galasa project + * + * SPDX-License-Identifier: EPL-2.0 + */ + +package streams + +import ( + "context" + "log" + "net/http" + + "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/streamsformatter" +) + +func GetStreams(streamName string, apiClient *galasaapi.APIClient, console spi.Console) error { + + streamData, err := getStreamsFromRestApi(streamName, apiClient) + if err == nil { + err = formatFetchedStreamsAndWriteToConsole(streamData, console) + } + + return err + +} + +func formatFetchedStreamsAndWriteToConsole(streams []galasaapi.Stream, console spi.Console) error { + + summaryFormatter := streamsformatter.NewStreamsSummaryFormatter() + outputText, err := summaryFormatter.FormatStreams(streams) + + if err == nil { + console.WriteString(outputText) + } + + return err + +} + +func getStreamsFromRestApi( + streamName string, + apiClient *galasaapi.APIClient, +) ([]galasaapi.Stream, error) { + + var context context.Context = nil + var streams []galasaapi.Stream + var err error + var restApiVersion string + + restApiVersion, err = embedded.GetGalasactlRestApiVersion() + + if streamName != "" { + streamName, err = validateStreamName(streamName) + + if err == nil { + streams, err = getStreamByName(streamName, apiClient, &context, restApiVersion) + } + + } else { + + if err == nil { + streams, err = getAllStreams(apiClient, &context, restApiVersion) + } + + } + + return streams, err + +} + +func getStreamByName( + streamName string, + apiClient *galasaapi.APIClient, + context *context.Context, + restApiVersion string, +) ([]galasaapi.Stream, error) { + + var err error + var streamIn *galasaapi.Stream + var resp *http.Response + + apiCall := apiClient.StreamsAPIApi.GetStreamByName(*context, streamName).ClientApiVersion(restApiVersion) + + streamIn, resp, err = apiCall.Execute() + + var statusCode int + if resp != nil { + defer resp.Body.Close() + statusCode = resp.StatusCode + } + + if err != nil { + log.Println("getStreamsFromRestApi - Failed to retrieve list of test streams from API server") + err = galasaErrors.NewGalasaErrorWithHttpStatusCode(statusCode, galasaErrors.GALASA_ERROR_RETRIEVING_USER_LIST_FROM_API_SERVER, err.Error()) + } + + streamsToReturn := []galasaapi.Stream{*streamIn} + return streamsToReturn, err + +} + +func getAllStreams( + apiClient *galasaapi.APIClient, + context *context.Context, + restApiVersion string, +) ([]galasaapi.Stream, error) { + + var err error + var streams []galasaapi.Stream + var resp *http.Response + + apiCall := apiClient.StreamsAPIApi.GetStreams(*context).ClientApiVersion(restApiVersion) + + streams, resp, err = apiCall.Execute() + + var statusCode int + if resp != nil { + defer resp.Body.Close() + statusCode = resp.StatusCode + } + + if err != nil { + log.Println("getStreamsFromRestApi - Failed to retrieve list of test streams from API server") + err = galasaErrors.NewGalasaErrorWithHttpStatusCode(statusCode, galasaErrors.GALASA_ERROR_RETRIEVING_STREAMS_FROM_API_SERVER, err.Error()) + } else { + log.Printf("getUserDataFromRestApi - %v test streams collected", len(streams)) + + } + + return streams, err +} diff --git a/pkg/streams/streamsGet_test.go b/pkg/streams/streamsGet_test.go new file mode 100644 index 00000000..879cf311 --- /dev/null +++ b/pkg/streams/streamsGet_test.go @@ -0,0 +1,205 @@ +/* + * Copyright contributors to the Galasa project + * + * SPDX-License-Identifier: EPL-2.0 + */ + +package streams + +import ( + "net/http" + "testing" + + "github.com/galasa-dev/cli/pkg/api" + "github.com/galasa-dev/cli/pkg/utils" + "github.com/stretchr/testify/assert" +) + +func TestMultipleStreamsGetFormatsResultsOk(t *testing.T) { + + //Given.. + + body := ` +[ + { + "apiVersion": "galasa-dev/v1alpha1", + "kind": "GalasaStream", + "metadata": { + "name": "mystream", + "url": "http://localhost:8080/api/streams/myStream", + "description": "A stream which I use to..." + }, + "data": { + "isEnabled": true, + "repository": { + "url": "http://mymavenrepo.host/testmaterial" + }, + "obrs": [ + { + "group-id": "com.ibm.zosadk.k8s", + "artifact-id": "com.ibm.zosadk.k8s.obr", + "version": "0.1.0-SNAPSHOT" + } + ], + "testCatalog": { + "url": "http://mymavenrepo.host/testmaterial/com.ibm.zosadk.k8s/com.ibm.zosadk.k8s.obr/0.1.0-SNAPSHOT/testcatalog.yaml" + } + } + }, + { + "apiVersion": "galasa-dev/v1alpha1", + "kind": "GalasaStream", + "metadata": { + "name": "mystream2", + "url": "http://localhost:8080/api/streams/myStream", + "description": "Another stream to..." + }, + "data": { + "isEnabled": true, + "repository": { + "url": "http://mymavenrepo.host/testmaterial" + }, + "obrs": [ + { + "group-id": "com.ibm.zosadk.k8s", + "artifact-id": "com.ibm.zosadk.k8s.obr", + "version": "0.1.0-SNAPSHOT" + } + ], + "testCatalog": { + "url": "http://mymavenrepo.host/testmaterial/com.ibm.zosadk.k8s/com.ibm.zosadk.k8s.obr/0.1.0-SNAPSHOT/testcatalog.yaml" + } + } + } + +] +` + + getStreamsInteraction := utils.NewHttpInteraction("/streams", http.MethodGet) + getStreamsInteraction.WriteHttpResponseFunc = func(writer http.ResponseWriter, req *http.Request) { + writer.Header().Set("Content-Type", "application/json") + writer.Header().Set("ClientApiVersion", "myVersion") + writer.WriteHeader(http.StatusOK) + writer.Write([]byte(body)) + } + + interactions := []utils.HttpInteraction{ + getStreamsInteraction, + } + + server := utils.NewMockHttpServer(t, interactions) + defer server.Server.Close() + + apiClient := api.InitialiseAPI(server.Server.URL) + console := utils.NewMockConsole() + + expectedOutput := `name state description +mystream enabled A stream which I use to... +mystream2 enabled Another stream to... + +Total:2 +` + + err := GetStreams("", apiClient, console) + + assert.Nil(t, err) + assert.Equal(t, expectedOutput, console.ReadText()) + +} + +func TestMissingStreamNameFlagReturnsBadRequest(t *testing.T) { + //Given... + + body := `{"error_code": 2505,"error_message": "GAL2505I: The stream name provided by the --name field cannot be an empty string."}` + + getStreamsInteraction := utils.NewHttpInteraction("/streams", http.MethodGet) + getStreamsInteraction.WriteHttpResponseFunc = func(writer http.ResponseWriter, req *http.Request) { + writer.Header().Set("Content-Type", "application/json") + writer.Header().Set("ClientApiVersion", "myVersion") + writer.WriteHeader(http.StatusBadRequest) // It's going to fail with an error on purpose ! + writer.Write([]byte(body)) + } + + interactions := []utils.HttpInteraction{ + getStreamsInteraction, + } + + server := utils.NewMockHttpServer(t, interactions) + defer server.Server.Close() + + apiClient := api.InitialiseAPI(server.Server.URL) + + console := utils.NewMockConsole() + expectedOutput := `GAL2505I: The stream name provided by the --name field cannot be an empty string.` + + //When + err := GetStreams(" ", apiClient, console) + + //Then + assert.NotNil(t, err) + assert.Equal(t, expectedOutput, err.Error()) +} + +func TestMultipleStreamByNameGetFormatsResultsOk(t *testing.T) { + + //Given.. + var streamName = "mystream" + + body := ` +{ + "apiVersion": "galasa-dev/v1alpha1", + "kind": "GalasaStream", + "metadata": { + "name": "mystream", + "url": "http://localhost:8080/api/streams/myStream", + "description": "A stream which I use to..." + }, + "data": { + "isEnabled": true, + "repository": { + "url": "http://mymavenrepo.host/testmaterial" + }, + "obrs": [ + { + "groupId": "com.ibm.zosadk.k8s", + "artifactId": "com.ibm.zosadk.k8s.obr", + "version": "0.1.0-SNAPSHOT" + } + ], + "testCatalog": { + "url": "http://mymavenrepo.host/testmaterial/com.ibm.zosadk.k8s/com.ibm.zosadk.k8s.obr/0.1.0-SNAPSHOT/testcatalog.yaml" + } + } +} +` + + getStreamsInteraction := utils.NewHttpInteraction("/streams/"+streamName, http.MethodGet) + getStreamsInteraction.WriteHttpResponseFunc = func(writer http.ResponseWriter, req *http.Request) { + writer.Header().Set("Content-Type", "application/json") + writer.Header().Set("ClientApiVersion", "myVersion") + writer.WriteHeader(http.StatusOK) + writer.Write([]byte(body)) + } + + interactions := []utils.HttpInteraction{ + getStreamsInteraction, + } + + server := utils.NewMockHttpServer(t, interactions) + defer server.Server.Close() + + apiClient := api.InitialiseAPI(server.Server.URL) + console := utils.NewMockConsole() + + expectedOutput := `name state description +mystream enabled A stream which I use to... + +Total:1 +` + + err := GetStreams(streamName, apiClient, console) + + assert.Nil(t, err) + assert.Equal(t, expectedOutput, console.ReadText()) + +} diff --git a/pkg/streams/streams_test.go b/pkg/streams/streams_test.go new file mode 100644 index 00000000..aac7e041 --- /dev/null +++ b/pkg/streams/streams_test.go @@ -0,0 +1,23 @@ +/* + * Copyright contributors to the Galasa project + * + * SPDX-License-Identifier: EPL-2.0 + */ + +package streams + +import ( + "testing" + + "github.com/stretchr/testify/assert" +) + +func TestValidateStreamNameFlagReturnsError_EmptyOrNullValue(t *testing.T) { + + invalidStreamName := "" + + loginId, err := validateStreamName(invalidStreamName) + + assert.NotNil(t, err) + assert.Empty(t, loginId) +} diff --git a/pkg/streamsformatter/streamsFormatter.go b/pkg/streamsformatter/streamsFormatter.go new file mode 100644 index 00000000..d97d3869 --- /dev/null +++ b/pkg/streamsformatter/streamsFormatter.go @@ -0,0 +1,33 @@ +/* + * Copyright contributors to the Galasa project + * + * SPDX-License-Identifier: EPL-2.0 + */ + +package streamsformatter + +import ( + "github.com/galasa-dev/cli/pkg/galasaapi" +) + +//Print in the following fashion: +// name state description +// mystream enabled Experimental tests +// fakestream enabled Fake tests +// +// Total:2 + +// ------------------------------------------------------ +// StreamsFormatter - implemetations can take a collection of stream results +// and turn them into a string for display to the user + +const ( + HEADER_STREAM_NAME = "name" + HEADER_STREAM_STATE = "state" + HEADER_STREAM_DESCRIPTION = "description" +) + +type StreamsFormatter interface { + FormatStreams(streamResults []galasaapi.Stream) (string, error) + GetName() string +} diff --git a/pkg/streamsformatter/summaryFormatter.go b/pkg/streamsformatter/summaryFormatter.go new file mode 100644 index 00000000..dd3f7032 --- /dev/null +++ b/pkg/streamsformatter/summaryFormatter.go @@ -0,0 +1,77 @@ +/* + * Copyright contributors to the Galasa project + * + * SPDX-License-Identifier: EPL-2.0 + */ + +package streamsformatter + +import ( + "strconv" + "strings" + + "github.com/galasa-dev/cli/pkg/galasaapi" + "github.com/galasa-dev/cli/pkg/utils" +) + +// ----------------------------------------------------- +// Summary format. +const ( + SUMMARY_FORMATTER_NAME = "summary" +) + +type StreamsSummaryFormatter struct { +} + +func NewStreamsSummaryFormatter() StreamsFormatter { + return new(StreamsSummaryFormatter) +} + +func (*StreamsSummaryFormatter) GetName() string { + return SUMMARY_FORMATTER_NAME +} + +func (*StreamsSummaryFormatter) FormatStreams(streams []galasaapi.Stream) (string, error) { + + var result string + var err error = nil + buff := strings.Builder{} + totalStreams := len(streams) + + if totalStreams > 0 { + + var table [][]string + var headers = []string{HEADER_STREAM_NAME, HEADER_STREAM_STATE, HEADER_STREAM_DESCRIPTION} + + table = append(table, headers) + + for _, stream := range streams { + + var line []string + var state string + + streamName := stream.Metadata.GetName() + streamDescription := stream.Metadata.GetDescription() + + if stream.GetData().IsEnabled != nil && *stream.GetData().IsEnabled { + state = "enabled" + } else { + state = "disabled" + } + + line = append(line, streamName, state, streamDescription) + table = append(table, line) + + } + + columnLengths := utils.CalculateMaxLengthOfEachColumn(table) + utils.WriteFormattedTableToStringBuilder(table, &buff, columnLengths) + + buff.WriteString("\n") + + } + buff.WriteString("Total:" + strconv.Itoa(totalStreams) + "\n") + + result = buff.String() + return result, err +} From 746e4f1dbe9e872f18e0b09d4721838d3cd12e57 Mon Sep 17 00:00:00 2001 From: Aashir Siddiqui Date: Wed, 2 Apr 2025 10:50:25 +0100 Subject: [PATCH 2/4] Added YAMl formatter Signed-off-by: Aashir Siddiqui --- docs/generated/errors-list.md | 5 +- docs/generated/galasactl.md | 2 +- docs/generated/galasactl_streams.md | 4 +- docs/generated/galasactl_streams_get.md | 9 +- pkg/cmd/streams.go | 4 +- pkg/cmd/streamsGet.go | 18 ++- pkg/cmd/streamsGet_test.go | 2 +- pkg/errors/errorMessage.go | 14 +- pkg/streams/streams.go | 7 + pkg/streams/streamsGet.go | 143 +++++++++++++----- pkg/streams/streamsGet_test.go | 10 +- pkg/streams/streams_test.go | 35 ++++- pkg/streamsformatter/summaryFormatter.go | 7 +- pkg/streamsformatter/summaryFormatter_test.go | 79 ++++++++++ pkg/streamsformatter/yamlFormatter.go | 91 +++++++++++ pkg/streamsformatter/yamlFormatter_test.go | 141 +++++++++++++++++ 16 files changed, 498 insertions(+), 73 deletions(-) create mode 100644 pkg/streamsformatter/summaryFormatter_test.go create mode 100644 pkg/streamsformatter/yamlFormatter.go create mode 100644 pkg/streamsformatter/yamlFormatter_test.go diff --git a/docs/generated/errors-list.md b/docs/generated/errors-list.md index b772a999..57ca01b2 100644 --- a/docs/generated/errors-list.md +++ b/docs/generated/errors-list.md @@ -214,6 +214,9 @@ The `galasactl` tool can generate the following errors: - GAL1215E: An attempt to update a user '{}' failed. Unexpected http status code {} received from the server. Error details from the server are not in a valid json format. Cause: '{}' - GAL1216E: An attempt to update a user '{}' failed. Unexpected http status code {} received from the server. Error details from the server are: '{}' - GAL1217E: An attempt to update a user '{}' failed. Unexpected http status code {} received from the server. Error details from the server are not in the json format. +- GAL1218E: The stream name provided by the --name field cannot be an empty string. +- GAL1219E: Could not get list of test streams from API server. Reason: '{}'. +- GAL1220E: The name provided with the --name flag cannot be empty and must only contain characters in the following ranges: 'a'-'z', 'A'-'Z', '0'-'9', '-' (dash), '_' (underscore). - GAL1225E: Failed to open file '{}' cause: {}. Check that this file exists, and that you have read permissions. - GAL1226E: Internal failure. Contents of gzip could be read, but not decoded. New gzip reader failed: file: {} error: {} - GAL1227E: Internal failure. Contents of gzip could not be decoded. {} error: {} @@ -227,5 +230,3 @@ The `galasactl` tool can generate the following errors: - GAL2504I: The request to cancel run '{}' has been accepted by the server. -- GAL2505I: The stream name provided by the --name field cannot be an empty string. -- GAL2506I: Could not get list of test streams from API server. Reason: '{}'. Ensure you have allocated a personal access token and configured your client program by setting your GALASA_TOKEN as an environment variable or by storing it in your galasactl.properties file diff --git a/docs/generated/galasactl.md b/docs/generated/galasactl.md index f6d0eda0..c123e705 100644 --- a/docs/generated/galasactl.md +++ b/docs/generated/galasactl.md @@ -24,6 +24,6 @@ A tool for controlling Galasa resources using the command-line. * [galasactl roles](galasactl_roles.md) - Manage roles stored in the Galasa service * [galasactl runs](galasactl_runs.md) - Manage test runs in the ecosystem * [galasactl secrets](galasactl_secrets.md) - Manage secrets stored in the Galasa service's credentials store -* [galasactl streams](galasactl_streams.md) - Manages test streams in an ecosystem +* [galasactl streams](galasactl_streams.md) - Manages test streams in a Galasa service * [galasactl users](galasactl_users.md) - Manages users in an ecosystem diff --git a/docs/generated/galasactl_streams.md b/docs/generated/galasactl_streams.md index 7e2c72ff..d6b0002d 100644 --- a/docs/generated/galasactl_streams.md +++ b/docs/generated/galasactl_streams.md @@ -1,10 +1,10 @@ ## galasactl streams -Manages test streams in an ecosystem +Manages test streams in a Galasa service ### Synopsis -Allows interaction with the streams servlet to return information about test streams. +Parent command for managing test streams in a Galasa service ### Options diff --git a/docs/generated/galasactl_streams_get.md b/docs/generated/galasactl_streams_get.md index 9fa3ad71..3ce86520 100644 --- a/docs/generated/galasactl_streams_get.md +++ b/docs/generated/galasactl_streams_get.md @@ -4,7 +4,7 @@ Gets a list of test streams ### Synopsis -Get a list of test streams stored in the Galasa API server +Get a list of test streams from the Galasa service ``` galasactl streams get [flags] @@ -13,8 +13,9 @@ galasactl streams get [flags] ### Options ``` - -h, --help Displays the options for the 'streams get' command. - --name string An optional field indicating the name of a test stream + --format string the output format of the returned streams. Supported formats are: 'summary', 'yaml'. (default "summary") + -h, --help Displays the options for the 'streams get' command. + --name string An optional field indicating the name of a test stream ``` ### Options inherited from parent commands @@ -29,5 +30,5 @@ galasactl streams get [flags] ### SEE ALSO -* [galasactl streams](galasactl_streams.md) - Manages test streams in an ecosystem +* [galasactl streams](galasactl_streams.md) - Manages test streams in a Galasa service diff --git a/pkg/cmd/streams.go b/pkg/cmd/streams.go index 87e9c2f7..1d426b76 100644 --- a/pkg/cmd/streams.go +++ b/pkg/cmd/streams.go @@ -67,8 +67,8 @@ func (cmd *StreamsCommand) createCobraCommand( streamsCobraCmd := &cobra.Command{ Use: "streams", - Short: "Manages test streams in an ecosystem", - Long: "Allows interaction with the streams servlet to return information about test streams.", + Short: "Manages test streams in a Galasa service", + Long: "Parent command for managing test streams in a Galasa service", } streamsCobraCmd.PersistentFlags().AddFlagSet(commsFlagSet.Flags()) diff --git a/pkg/cmd/streamsGet.go b/pkg/cmd/streamsGet.go index 19267ba5..2ce9f4df 100644 --- a/pkg/cmd/streamsGet.go +++ b/pkg/cmd/streamsGet.go @@ -17,11 +17,16 @@ import ( "github.com/spf13/cobra" ) +type StreamsGetCmdValues struct { + outputFormat string +} + // Objective: Allow user to do this: // // streams get type StreamsGetCommand struct { cobraCommand *cobra.Command + values *StreamsGetCmdValues } // ------------------------------------------------------------------------------------------------ @@ -51,7 +56,7 @@ func (cmd *StreamsGetCommand) CobraCommand() *cobra.Command { } func (cmd *StreamsGetCommand) Values() interface{} { - return nil + return cmd.values } // ------------------------------------------------------------------------------------------------ @@ -60,6 +65,7 @@ func (cmd *StreamsGetCommand) Values() interface{} { func (cmd *StreamsGetCommand) init(factory spi.Factory, streamsCommand spi.GalasaCommand, commsFlagSet GalasaFlagSet) error { var err error + cmd.values = &StreamsGetCmdValues{} cmd.cobraCommand, err = cmd.createCobraCmd(factory, streamsCommand, commsFlagSet) return err @@ -79,7 +85,7 @@ func (cmd *StreamsGetCommand) createCobraCmd( streamsGetCobraCmd := &cobra.Command{ Use: "get", Short: "Gets a list of test streams", - Long: "Get a list of test streams stored in the Galasa API server", + Long: "Get a list of test streams from the Galasa service", Aliases: []string{COMMAND_NAME_STREAMS_GET}, RunE: func(cobraCommand *cobra.Command, args []string) error { return cmd.executeStreamsGet( @@ -89,6 +95,10 @@ func (cmd *StreamsGetCommand) createCobraCmd( } addStreamNameFlag(streamsGetCobraCmd, false, streamCommandValues) + + formatters := streams.GetFormatterNamesAsString() + streamsGetCobraCmd.Flags().StringVar(&cmd.values.outputFormat, "format", "summary", "the output format of the returned streams. Supported formats are: "+formatters+".") + streamsCommand.CobraCommand().AddCommand(streamsGetCobraCmd) return streamsGetCobraCmd, err @@ -110,7 +120,7 @@ func (cmd *StreamsGetCommand) executeStreamsGet( if err == nil { commsFlagSetValues.isCapturingLogs = true - log.Println("Galasa CLI - Get users from the ecosystem") + log.Println("Galasa CLI - Get streams from the Galasa service") env := factory.GetEnvironment() @@ -131,7 +141,7 @@ func (cmd *StreamsGetCommand) executeStreamsGet( if err == nil { var console = factory.GetStdOutConsole() getStreamsFunc := func(apiClient *galasaapi.APIClient) error { - return streams.GetStreams(streamsCmdValues.name, apiClient, console) + return streams.GetStreams(streamsCmdValues.name, cmd.values.outputFormat, apiClient, console) } err = commsClient.RunAuthenticatedCommandWithRateLimitRetries(getStreamsFunc) diff --git a/pkg/cmd/streamsGet_test.go b/pkg/cmd/streamsGet_test.go index 3400ef07..3520a9b4 100644 --- a/pkg/cmd/streamsGet_test.go +++ b/pkg/cmd/streamsGet_test.go @@ -41,7 +41,7 @@ func TestStreamsGetHelpFlagSetCorrectly(t *testing.T) { assert.Nil(t, err) } -func TestStreamsGetNamespaceNameFlagsReturnsOk(t *testing.T) { +func TestStreamsGetNameFlagsReturnsOk(t *testing.T) { // Given... factory := utils.NewMockFactory() commandCollection, _ := setupTestCommandCollection(COMMAND_NAME_STREAMS_GET, factory, t) diff --git a/pkg/errors/errorMessage.go b/pkg/errors/errorMessage.go index d04ce3fa..1f62a70f 100644 --- a/pkg/errors/errorMessage.go +++ b/pkg/errors/errorMessage.go @@ -16,11 +16,11 @@ import ( var ( RATE_LIMIT_STATUS_CODES_MAP = map[int]struct{}{ http.StatusServiceUnavailable: {}, - http.StatusTooManyRequests: {}, - http.StatusUnauthorized: {}, + http.StatusTooManyRequests: {}, + http.StatusUnauthorized: {}, } - AUTH_STATUS_CODES_MAP = map[int]struct{} { + AUTH_STATUS_CODES_MAP = map[int]struct{}{ http.StatusUnauthorized: {}, } ) @@ -419,6 +419,10 @@ var ( GALASA_ERROR_UPDATE_USER_SERVER_REPORTED_ERROR = NewMessageType("GAL1216E: An attempt to update a user '%s' failed. Unexpected http status code %v received from the server. Error details from the server are: '%s'", 1216, STACK_TRACE_NOT_WANTED) GALASA_ERROR_UPDATE_USER_EXPLANATION_NOT_JSON = NewMessageType("GAL1217E: An attempt to update a user '%s' failed. Unexpected http status code %v received from the server. Error details from the server are not in the json format.", 1217, STACK_TRACE_NOT_WANTED) + GALASA_ERROR_MISSING_STREAM_NAME_FLAG = NewMessageType("GAL1218E: The stream name provided by the --name field cannot be an empty string.", 1218, STACK_TRACE_NOT_WANTED) + GALASA_ERROR_RETRIEVING_STREAMS_FROM_API_SERVER = NewMessageType("GAL1219E: Could not get list of test streams from API server. Reason: '%s'.", 1219, STACK_TRACE_WANTED) + GALASA_ERROR_INVALID_STREAM_NAME = NewMessageType("GAL1220E: The name provided with the --name flag cannot be empty and must only contain characters in the following ranges: 'a'-'z', 'A'-'Z', '0'-'9', '-' (dash), '_' (underscore).", 1220, STACK_TRACE_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) @@ -426,8 +430,4 @@ var ( GALASA_INFO_FOLDER_DOWNLOADED_TO = NewMessageType("GAL2501I: Downloaded %d artifacts to folder '%s'\n", 2501, STACK_TRACE_NOT_WANTED) GALASA_INFO_RUNS_RESET_SUCCESS = NewMessageType("GAL2503I: The request to reset run '%s' has been accepted by the server.\n", 2503, STACK_TRACE_NOT_WANTED) GALASA_INFO_RUNS_CANCEL_SUCCESS = NewMessageType("GAL2504I: The request to cancel run '%s' has been accepted by the server.\n", 2504, STACK_TRACE_NOT_WANTED) - - GALASA_ERROR_MISSING_STREAM_NAME_FLAG = NewMessageType("GAL2505I: The stream name provided by the --name field cannot be an empty string.", 2505, STACK_TRACE_NOT_WANTED) - GALASA_ERROR_RETRIEVING_STREAMS_FROM_API_SERVER = NewMessageType("GAL2506I: Could not get list of test streams from API server. Reason: '%s'."+ - " Ensure you have allocated a personal access token and configured your client program by setting your GALASA_TOKEN as an environment variable or by storing it in your galasactl.properties file", 2506, STACK_TRACE_WANTED) ) diff --git a/pkg/streams/streams.go b/pkg/streams/streams.go index 7e653c1b..c1b82c50 100644 --- a/pkg/streams/streams.go +++ b/pkg/streams/streams.go @@ -7,6 +7,7 @@ package streams import ( + "regexp" "strings" galasaErrors "github.com/galasa-dev/cli/pkg/errors" @@ -19,6 +20,12 @@ func validateStreamName(streamName string) (string, error) { if streamName == "" { err = galasaErrors.NewGalasaError(galasaErrors.GALASA_ERROR_MISSING_STREAM_NAME_FLAG) + } else { + // Check that stream name only contains alphanumeric characters, underscores, and hyphens + validChars := regexp.MustCompile(`^[a-zA-Z0-9_-]+$`) + if !validChars.MatchString(streamName) { + err = galasaErrors.NewGalasaError(galasaErrors.GALASA_ERROR_INVALID_STREAM_NAME) + } } return streamName, err diff --git a/pkg/streams/streamsGet.go b/pkg/streams/streamsGet.go index e9fb4a34..d6f4cb8e 100644 --- a/pkg/streams/streamsGet.go +++ b/pkg/streams/streamsGet.go @@ -10,6 +10,8 @@ import ( "context" "log" "net/http" + "sort" + "strings" "github.com/galasa-dev/cli/pkg/embedded" galasaErrors "github.com/galasa-dev/cli/pkg/errors" @@ -18,24 +20,40 @@ import ( "github.com/galasa-dev/cli/pkg/streamsformatter" ) -func GetStreams(streamName string, apiClient *galasaapi.APIClient, console spi.Console) error { +var ( + formatters = createFormatters() +) + +func GetStreams(streamName string, format string, apiClient *galasaapi.APIClient, console spi.Console) error { + + var err error + var streamData []galasaapi.Stream + + if streamName != "" { + streamName, err = validateStreamName(streamName) + } - streamData, err := getStreamsFromRestApi(streamName, apiClient) if err == nil { - err = formatFetchedStreamsAndWriteToConsole(streamData, console) + streamData, err = getStreamsFromRestApi(streamName, apiClient) + if err == nil { + err = formatFetchedStreamsAndWriteToConsole(streamData, console, format) + } } return err } -func formatFetchedStreamsAndWriteToConsole(streams []galasaapi.Stream, console spi.Console) error { +func formatFetchedStreamsAndWriteToConsole(streams []galasaapi.Stream, console spi.Console, outputFormatString string) error { - summaryFormatter := streamsformatter.NewStreamsSummaryFormatter() - outputText, err := summaryFormatter.FormatStreams(streams) + var formattedOuptut string + chosenFormatter, err := validateFormatFlag(outputFormatString) if err == nil { - console.WriteString(outputText) + formattedOuptut, err = chosenFormatter.FormatStreams(streams) + if err == nil { + console.WriteString(formattedOuptut) + } } return err @@ -47,90 +65,133 @@ func getStreamsFromRestApi( apiClient *galasaapi.APIClient, ) ([]galasaapi.Stream, error) { - var context context.Context = nil var streams []galasaapi.Stream var err error var restApiVersion string restApiVersion, err = embedded.GetGalasactlRestApiVersion() - if streamName != "" { - streamName, err = validateStreamName(streamName) - - if err == nil { - streams, err = getStreamByName(streamName, apiClient, &context, restApiVersion) + if err == nil { + if streamName != "" { + streams, err = getStreamByName(streamName, apiClient, restApiVersion) + } else { + streams, err = getAllStreams(apiClient, restApiVersion) } + } - } else { + return streams, err - if err == nil { - streams, err = getAllStreams(apiClient, &context, restApiVersion) - } +} + +func createFormatters() map[string]streamsformatter.StreamsFormatter { + + formatters := make(map[string]streamsformatter.StreamsFormatter, 0) + summaryFormatter := streamsformatter.NewStreamsSummaryFormatter() + yamlFormatter := streamsformatter.NewStreamsYamlFormatter() + formatters[summaryFormatter.GetName()] = summaryFormatter + formatters[yamlFormatter.GetName()] = yamlFormatter + + return formatters + +} + +func GetFormatterNamesAsString() string { + names := make([]string, 0, len(formatters)) + for name := range formatters { + names = append(names, name) } + sort.Strings(names) + formatterNames := strings.Builder{} - return streams, err + for index, formatterName := range names { + if index != 0 { + formatterNames.WriteString(", ") + } + formatterNames.WriteString("'" + formatterName + "'") + } + + return formatterNames.String() } func getStreamByName( streamName string, apiClient *galasaapi.APIClient, - context *context.Context, restApiVersion string, ) ([]galasaapi.Stream, error) { var err error var streamIn *galasaapi.Stream var resp *http.Response + var context context.Context = nil + var streamsToReturn []galasaapi.Stream - apiCall := apiClient.StreamsAPIApi.GetStreamByName(*context, streamName).ClientApiVersion(restApiVersion) + apiCall := apiClient.StreamsAPIApi.GetStreamByName(context, streamName).ClientApiVersion(restApiVersion) streamIn, resp, err = apiCall.Execute() - var statusCode int - if resp != nil { - defer resp.Body.Close() - statusCode = resp.StatusCode - } + if err == nil { + var statusCode int + if resp != nil { + defer resp.Body.Close() + statusCode = resp.StatusCode + } - if err != nil { - log.Println("getStreamsFromRestApi - Failed to retrieve list of test streams from API server") - err = galasaErrors.NewGalasaErrorWithHttpStatusCode(statusCode, galasaErrors.GALASA_ERROR_RETRIEVING_USER_LIST_FROM_API_SERVER, err.Error()) + if statusCode != 200 { + log.Println("getStreamsFromRestApi - Failed to retrieve list of test streams from API server") + err = galasaErrors.NewGalasaErrorWithHttpStatusCode(statusCode, galasaErrors.GALASA_ERROR_RETRIEVING_STREAMS_FROM_API_SERVER, err.Error()) + } + streamsToReturn = []galasaapi.Stream{*streamIn} } - streamsToReturn := []galasaapi.Stream{*streamIn} return streamsToReturn, err } func getAllStreams( apiClient *galasaapi.APIClient, - context *context.Context, restApiVersion string, ) ([]galasaapi.Stream, error) { var err error var streams []galasaapi.Stream var resp *http.Response + var context context.Context = nil - apiCall := apiClient.StreamsAPIApi.GetStreams(*context).ClientApiVersion(restApiVersion) + apiCall := apiClient.StreamsAPIApi.GetStreams(context).ClientApiVersion(restApiVersion) streams, resp, err = apiCall.Execute() - var statusCode int - if resp != nil { - defer resp.Body.Close() - statusCode = resp.StatusCode - } + if err == nil { - if err != nil { - log.Println("getStreamsFromRestApi - Failed to retrieve list of test streams from API server") - err = galasaErrors.NewGalasaErrorWithHttpStatusCode(statusCode, galasaErrors.GALASA_ERROR_RETRIEVING_STREAMS_FROM_API_SERVER, err.Error()) - } else { - log.Printf("getUserDataFromRestApi - %v test streams collected", len(streams)) + var statusCode int + if resp != nil { + defer resp.Body.Close() + statusCode = resp.StatusCode + } + if statusCode == 200 { + log.Printf("getUserDataFromRestApi - %v test streams collected", len(streams)) + } else { + log.Println("getStreamsFromRestApi - Failed to retrieve list of test streams from API server") + err = galasaErrors.NewGalasaErrorWithHttpStatusCode(statusCode, galasaErrors.GALASA_ERROR_RETRIEVING_STREAMS_FROM_API_SERVER, err.Error()) + statusCode = 500 + } } return streams, err } + +func validateFormatFlag(outputFormatString string) (streamsformatter.StreamsFormatter, error) { + var err error + + chosenFormatter, isPresent := formatters[outputFormatString] + + if !isPresent { + err = galasaErrors.NewGalasaError(galasaErrors.GALASA_ERROR_INVALID_OUTPUT_FORMAT, outputFormatString, GetFormatterNamesAsString()) + } + + return chosenFormatter, err + +} diff --git a/pkg/streams/streamsGet_test.go b/pkg/streams/streamsGet_test.go index 879cf311..56436e55 100644 --- a/pkg/streams/streamsGet_test.go +++ b/pkg/streams/streamsGet_test.go @@ -100,7 +100,7 @@ mystream2 enabled Another stream to... Total:2 ` - err := GetStreams("", apiClient, console) + err := GetStreams("", "summary", apiClient, console) assert.Nil(t, err) assert.Equal(t, expectedOutput, console.ReadText()) @@ -110,7 +110,7 @@ Total:2 func TestMissingStreamNameFlagReturnsBadRequest(t *testing.T) { //Given... - body := `{"error_code": 2505,"error_message": "GAL2505I: The stream name provided by the --name field cannot be an empty string."}` + body := `{"error_code": 1218,"error_message": "GAL1218E: The stream name provided by the --name field cannot be an empty string."}` getStreamsInteraction := utils.NewHttpInteraction("/streams", http.MethodGet) getStreamsInteraction.WriteHttpResponseFunc = func(writer http.ResponseWriter, req *http.Request) { @@ -130,10 +130,10 @@ func TestMissingStreamNameFlagReturnsBadRequest(t *testing.T) { apiClient := api.InitialiseAPI(server.Server.URL) console := utils.NewMockConsole() - expectedOutput := `GAL2505I: The stream name provided by the --name field cannot be an empty string.` + expectedOutput := `GAL1218E: The stream name provided by the --name field cannot be an empty string.` //When - err := GetStreams(" ", apiClient, console) + err := GetStreams(" ", "summary", apiClient, console) //Then assert.NotNil(t, err) @@ -197,7 +197,7 @@ mystream enabled A stream which I use to... Total:1 ` - err := GetStreams(streamName, apiClient, console) + err := GetStreams(streamName, "summary", apiClient, console) assert.Nil(t, err) assert.Equal(t, expectedOutput, console.ReadText()) diff --git a/pkg/streams/streams_test.go b/pkg/streams/streams_test.go index aac7e041..69bd5d5c 100644 --- a/pkg/streams/streams_test.go +++ b/pkg/streams/streams_test.go @@ -16,8 +16,39 @@ func TestValidateStreamNameFlagReturnsError_EmptyOrNullValue(t *testing.T) { invalidStreamName := "" - loginId, err := validateStreamName(invalidStreamName) + streamName, err := validateStreamName(invalidStreamName) assert.NotNil(t, err) - assert.Empty(t, loginId) + assert.Empty(t, streamName) +} + +func TestValidateStreamNameRegexFlagReturnsError(t *testing.T) { + + invalidStreamName := "my.stream" + + streamName, err := validateStreamName(invalidStreamName) + + assert.NotNil(t, err) + assert.ErrorContains(t, err, "GAL1220E") + assert.NotEmpty(t, streamName) +} + +func TestValidateStreamNameRegexWithUnderScoreFlagReturnsNoError(t *testing.T) { + + validStreamName := "my_stream" + + streamName, err := validateStreamName(validStreamName) + + assert.Nil(t, err) + assert.NotEmpty(t, streamName) +} + +func TestValidateStreamNameRegexWithDashFlagReturnsNoError(t *testing.T) { + + validStreamName := "my-stream" + + streamName, err := validateStreamName(validStreamName) + + assert.Nil(t, err) + assert.NotEmpty(t, streamName) } diff --git a/pkg/streamsformatter/summaryFormatter.go b/pkg/streamsformatter/summaryFormatter.go index dd3f7032..9126c454 100644 --- a/pkg/streamsformatter/summaryFormatter.go +++ b/pkg/streamsformatter/summaryFormatter.go @@ -31,6 +31,9 @@ func (*StreamsSummaryFormatter) GetName() string { return SUMMARY_FORMATTER_NAME } +var ENABLED_STATE = "enabled" +var DISABLED_STATE = "disabled" + func (*StreamsSummaryFormatter) FormatStreams(streams []galasaapi.Stream) (string, error) { var result string @@ -54,9 +57,9 @@ func (*StreamsSummaryFormatter) FormatStreams(streams []galasaapi.Stream) (strin streamDescription := stream.Metadata.GetDescription() if stream.GetData().IsEnabled != nil && *stream.GetData().IsEnabled { - state = "enabled" + state = ENABLED_STATE } else { - state = "disabled" + state = DISABLED_STATE } line = append(line, streamName, state, streamDescription) diff --git a/pkg/streamsformatter/summaryFormatter_test.go b/pkg/streamsformatter/summaryFormatter_test.go new file mode 100644 index 00000000..43f7f490 --- /dev/null +++ b/pkg/streamsformatter/summaryFormatter_test.go @@ -0,0 +1,79 @@ +/* + * Copyright contributors to the Galasa project + * + * SPDX-License-Identifier: EPL-2.0 + */ + +package streamsformatter + +import ( + "testing" + + "github.com/galasa-dev/cli/pkg/galasaapi" + "github.com/stretchr/testify/assert" +) + +func CreateMockStream(streamName string, isEnabled bool, description string) *galasaapi.Stream { + + var stream = galasaapi.NewStream() + var streamMetadata = galasaapi.NewStreamMetadata() + var streamData = galasaapi.NewStreamData() + + streamMetadata.SetName(streamName) + streamMetadata.SetDescription(description) + streamData.SetIsEnabled(isEnabled) + + stream.SetData(*streamData) + stream.SetMetadata(*streamMetadata) + + return stream + +} + +func TestStreamsSummaryFormatterSingleDataReturnsCorrectly(t *testing.T) { + // Given... + formatter := NewStreamsSummaryFormatter() + // No data to format...x + streams := make([]galasaapi.Stream, 0) + stream1 := CreateMockStream("mystream", true, "My test stream") + streams = append(streams, *stream1) + + // When... + actualFormattedOutput, err := formatter.FormatStreams(streams) + + // Then... + assert.Nil(t, err) + expectedFormattedOutput := + `name state description +mystream enabled My test stream + +Total:1 +` + assert.Equal(t, expectedFormattedOutput, actualFormattedOutput) +} + +func TestStreamsSummaryFormatterMultipleDataSeperatesWithNewLine(t *testing.T) { + // For.. + formatter := NewStreamsSummaryFormatter() + // No data to format... + streams := make([]galasaapi.Stream, 0) + stream1 := CreateMockStream("mystream", true, "This is a test stream") + stream2 := CreateMockStream("my-test-stream", false, "Dummy test stream") + stream3 := CreateMockStream("example_stream", true, "Hello stream") + streams = append(streams, *stream1, *stream2, *stream3) + + // When... + actualFormattedOutput, err := formatter.FormatStreams(streams) + + // Then... + assert.Nil(t, err) + expectedFormattedOutput := + `name state description +mystream enabled This is a test stream +my-test-stream disabled Dummy test stream +example_stream enabled Hello stream + +Total:3 +` + assert.Equal(t, expectedFormattedOutput, actualFormattedOutput) +} diff --git a/pkg/streamsformatter/yamlFormatter.go b/pkg/streamsformatter/yamlFormatter.go new file mode 100644 index 00000000..8189452b --- /dev/null +++ b/pkg/streamsformatter/yamlFormatter.go @@ -0,0 +1,91 @@ +/* + * Copyright contributors to the Galasa project + * + * SPDX-License-Identifier: EPL-2.0 + */ + +package streamsformatter + +import ( + "strings" + + "github.com/galasa-dev/cli/pkg/galasaapi" + "gopkg.in/yaml.v3" +) + +const ( + YAML_FORMATTER_NAME = "yaml" +) + +type StreamsYamlFormatter struct { +} + +func NewStreamsYamlFormatter() StreamsFormatter { + return new(StreamsYamlFormatter) +} + +func (*StreamsYamlFormatter) GetName() string { + return YAML_FORMATTER_NAME +} + +func (*StreamsYamlFormatter) FormatStreams(streams []galasaapi.Stream) (string, error) { + var err error + buff := strings.Builder{} + + for index, stream := range streams { + if index > 0 { + buff.WriteString("---\n") + } + + type ObrInfo struct { + MavenGroupID string `yaml:"maven-group-id"` + MavenArtifactID string `yaml:"maven-artifact-id"` + MavenVersion string `yaml:"maven-version"` + } + + type RepositoryURL struct { + URL string `yaml:"url"` + } + + type StreamYAML struct { + APIVersion string `yaml:"apiVersion"` + Kind string `yaml:"kind"` + Metadata struct { + Name string `yaml:"name"` + Description string `yaml:"description"` + } `yaml:"metadata"` + Data struct { + Repository []RepositoryURL `yaml:"repository"` + TestCatalog []RepositoryURL `yaml:"testCatalog"` + Obrs []ObrInfo `yaml:"obrs"` + } `yaml:"data"` + } + + streamYAML := StreamYAML{ + APIVersion: "galasa-dev/v1alpha1", + Kind: "GalasaStream", + } + streamYAML.Metadata.Name = *stream.Metadata.Name + streamYAML.Metadata.Description = *stream.Metadata.Description + + // Add repository and test catalog + streamYAML.Data.Repository = []RepositoryURL{{URL: *stream.Data.Repository.Url}} + streamYAML.Data.TestCatalog = []RepositoryURL{{URL: *stream.Data.TestCatalog.Url}} + + // Add the obrs section + streamYAML.Data.Obrs = []ObrInfo{ + { + MavenGroupID: *stream.Data.Obrs[0].GroupId, + MavenArtifactID: *stream.Data.Obrs[0].ArtifactId, + MavenVersion: *stream.Data.Obrs[0].Version, + }, + } + + yamlBytes, err := yaml.Marshal(streamYAML) + if err == nil { + buff.Write(yamlBytes) + } + } + + return buff.String(), err +} diff --git a/pkg/streamsformatter/yamlFormatter_test.go b/pkg/streamsformatter/yamlFormatter_test.go new file mode 100644 index 00000000..7ad0f89e --- /dev/null +++ b/pkg/streamsformatter/yamlFormatter_test.go @@ -0,0 +1,141 @@ +/* + * Copyright contributors to the Galasa project + * + * SPDX-License-Identifier: EPL-2.0 + */ + +package streamsformatter + +import ( + "fmt" + "testing" + + "github.com/galasa-dev/cli/pkg/galasaapi" + "github.com/stretchr/testify/assert" +) + +const ( + STREAM_DESCRIPTION = "This a Galasa test stream" + MAVEN_REPO_URL = "mvn:myGroup/myArtifact/0.38.0/obr" + TEST_CATALOG_URL = "http://my/test/catalog.json" + MAVEN_GROUP_ID = "myGroup" + MAVEN_ARTIFACT_ID = "myArtifact" + MAVEN_VERSION = "0.38.0" +) + +func createMockTestStreamYamlFormat(streamName string) *galasaapi.Stream { + var stream = galasaapi.NewStream() + + stream.SetKind("GalasaStream") + stream.SetApiVersion("galasa-dev/v1alpha1") + + var streamMetadata = galasaapi.NewStreamMetadata() + streamMetadata.SetDescription(STREAM_DESCRIPTION) + streamMetadata.SetName(streamName) + stream.SetMetadata(*streamMetadata) + + var streamData = galasaapi.NewStreamData() + var testCatalog = galasaapi.NewStreamTestCatalog() + var streamRepoUrl = galasaapi.NewStreamRepository() + + streamRepoUrl.SetUrl(MAVEN_REPO_URL) + testCatalog.SetUrl(TEST_CATALOG_URL) + streamData.SetRepository(*streamRepoUrl) + streamData.SetTestCatalog(*testCatalog) + + // Create OBR data + groupId := MAVEN_GROUP_ID + artifactId := MAVEN_ARTIFACT_ID + version := MAVEN_VERSION + + obrData := galasaapi.StreamOBRData{ + GroupId: &groupId, + ArtifactId: &artifactId, + Version: &version, + } + + obrsSlice := []galasaapi.StreamOBRData{obrData} + streamData.SetObrs(obrsSlice) + + stream.SetData(*streamData) + + return stream +} + +func generateExpectedStreamYaml(streamName string) string { + return fmt.Sprintf( + `apiVersion: galasa-dev/v1alpha1 +kind: GalasaStream +metadata: + name: %s + description: %s +data: + repository: + - url: %s + testCatalog: + - url: %s + obrs: + - maven-group-id: %s + maven-artifact-id: %s + maven-version: %s`, + streamName, STREAM_DESCRIPTION, MAVEN_REPO_URL, TEST_CATALOG_URL, MAVEN_GROUP_ID, MAVEN_ARTIFACT_ID, MAVEN_VERSION) +} + +func TestSecretsYamlFormatterNoDataReturnsBlankString(t *testing.T) { + // Given... + formatter := NewStreamsYamlFormatter() + formattableStreams := make([]galasaapi.Stream, 0) + + // When... + actualFormattedOutput, err := formatter.FormatStreams(formattableStreams) + + // Then... + assert.Nil(t, err) + expectedFormattedOutput := "" + assert.Equal(t, expectedFormattedOutput, actualFormattedOutput) +} + +func TestStreamsYamlFormatterSingleDataReturnsCorrectly(t *testing.T) { + // Given.. + formatter := NewStreamsYamlFormatter() + formattableStreams := make([]galasaapi.Stream, 0) + streamName := "mystream" + + stream1 := createMockTestStreamYamlFormat(streamName) + formattableStreams = append(formattableStreams, *stream1) + + // When... + actualFormattedOutput, err := formatter.FormatStreams(formattableStreams) + + // Then... + assert.Nil(t, err) + expectedFormattedOutput := generateExpectedStreamYaml(streamName) + "\n" + assert.Equal(t, expectedFormattedOutput, actualFormattedOutput) +} + +func TestStreamsYamlFormatterMultipleDataReturnsCorrectly(t *testing.T) { + // Given.. + formatter := NewStreamsYamlFormatter() + formattableStreams := make([]galasaapi.Stream, 0) + streamName1 := "mystream" + streamName2 := "mystream2" + + stream1 := createMockTestStreamYamlFormat(streamName1) + stream2 := createMockTestStreamYamlFormat(streamName2) + formattableStreams = append(formattableStreams, *stream1, *stream2) + + // When... + actualFormattedOutput, err := formatter.FormatStreams(formattableStreams) + + // Then... + assert.Nil(t, err) + expectedFormatted1Output := generateExpectedStreamYaml(streamName1) + expectedFormatted2Output := generateExpectedStreamYaml(streamName2) + + expectedFormattedOutput := fmt.Sprintf(`%s +--- +%s +`, expectedFormatted1Output, expectedFormatted2Output) + + assert.Equal(t, expectedFormattedOutput, actualFormattedOutput) +} From eb13a051c569daf315aac5fbe982e96ed56e5b57 Mon Sep 17 00:00:00 2001 From: Aashir Siddiqui Date: Wed, 2 Apr 2025 15:30:30 +0100 Subject: [PATCH 3/4] Enhanced error handling and added unit tests Signed-off-by: Aashir Siddiqui --- docs/generated/errors-list.md | 8 ++ pkg/cmd/streamsGet.go | 5 +- pkg/cmd/streamsGet_test.go | 42 +++++++++ pkg/errors/errorMessage.go | 12 ++- pkg/streams/streams.go | 10 +- pkg/streams/streamsGet.go | 93 +++++++++++-------- pkg/streams/streamsGet_test.go | 74 ++++++++++++++- pkg/streams/streams_test.go | 2 +- pkg/streamsformatter/summaryFormatter.go | 5 +- pkg/streamsformatter/summaryFormatter_test.go | 6 +- pkg/streamsformatter/yamlFormatter.go | 59 +++--------- pkg/streamsformatter/yamlFormatter_test.go | 16 ++-- 12 files changed, 217 insertions(+), 115 deletions(-) diff --git a/docs/generated/errors-list.md b/docs/generated/errors-list.md index e594e363..cf53ad81 100644 --- a/docs/generated/errors-list.md +++ b/docs/generated/errors-list.md @@ -229,6 +229,14 @@ The `galasactl` tool can generate the following errors: - GAL1230E: Failed to update a monitor named '{}'. Unexpected http status code {} received from the server. Error details from the server are not in a valid json format. Cause: '{}' - GAL1231E: Failed to update a monitor named '{}'. Unexpected http status code {} received from the server. Error details from the server are: '{}' - GAL1232E: Failed to update a monitor named '{}'. Unexpected http status code {} received from the server. Error details from the server are not in the json format. +- GAL1233E: The stream name provided by the --name field cannot be an empty string. +- GAL1234E: Could not get list of test streams from API server. Reason: '{}'. +- GAL1235E: The name provided with the --name flag cannot be empty and must only contain characters in the following ranges: 'a'-'z', 'A'-'Z', '0'-'9', '-' (dash), '_' (underscore). +- GAL1236E: Failed to get streams. Unexpected http status code {} received from the server. +- GAL1237E: Failed to get streams. Unexpected http status code {} received from the server. Error details from the server could not be read. Cause: {} +- GAL1238E: Failed to get streams. Unexpected http status code {} received from the server. Error details from the server are not in a valid json format. Cause: '{}' +- GAL1239E: Failed to get streams. Unexpected http status code {} received from the server. Error details from the server are: '{}' +- GAL1240E: Failed to get streams. Unexpected http status code {} received from the server. Error details from the server are not in the json format. - 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/pkg/cmd/streamsGet.go b/pkg/cmd/streamsGet.go index 2ce9f4df..9daf85bb 100644 --- a/pkg/cmd/streamsGet.go +++ b/pkg/cmd/streamsGet.go @@ -139,9 +139,12 @@ func (cmd *StreamsGetCommand) executeStreamsGet( ) if err == nil { + var console = factory.GetStdOutConsole() + var byteReader = factory.GetByteReader() + getStreamsFunc := func(apiClient *galasaapi.APIClient) error { - return streams.GetStreams(streamsCmdValues.name, cmd.values.outputFormat, apiClient, console) + return streams.GetStreams(streamsCmdValues.name, cmd.values.outputFormat, apiClient, console,byteReader) } err = commsClient.RunAuthenticatedCommandWithRateLimitRetries(getStreamsFunc) diff --git a/pkg/cmd/streamsGet_test.go b/pkg/cmd/streamsGet_test.go index 3520a9b4..def3ff47 100644 --- a/pkg/cmd/streamsGet_test.go +++ b/pkg/cmd/streamsGet_test.go @@ -61,3 +61,45 @@ func TestStreamsGetNameFlagsReturnsOk(t *testing.T) { assert.Nil(t, err) assert.Contains(t, parentCmd.Values().(*StreamsCmdValues).name, "mystream") } + +func TestStreamsGetFormatFlagYamlValueReturnsOk(t *testing.T) { + // Given... + factory := utils.NewMockFactory() + commandCollection, _ := setupTestCommandCollection(COMMAND_NAME_STREAMS_GET, factory, t) + + var args []string = []string{"streams", "get", "--name", "mystream", "--format", "yaml"} + + // When... + err := commandCollection.Execute(args) + + // Then... + assert.Nil(t, err) + + // Check what the user saw was reasonable + checkOutput("", "", factory, t) + + parentCmd, err := commandCollection.GetCommand(COMMAND_NAME_STREAMS) + assert.Nil(t, err) + assert.Contains(t, parentCmd.Values().(*StreamsCmdValues).name, "mystream") +} + +func TestStreamsGetFormatFlagYamlSummaryReturnsOk(t *testing.T) { + // Given... + factory := utils.NewMockFactory() + commandCollection, _ := setupTestCommandCollection(COMMAND_NAME_STREAMS_GET, factory, t) + + var args []string = []string{"streams", "get", "--name", "mystream", "--format", "summary"} + + // When... + err := commandCollection.Execute(args) + + // Then... + assert.Nil(t, err) + + // Check what the user saw was reasonable + checkOutput("", "", factory, t) + + parentCmd, err := commandCollection.GetCommand(COMMAND_NAME_STREAMS) + assert.Nil(t, err) + assert.Contains(t, parentCmd.Values().(*StreamsCmdValues).name, "mystream") +} diff --git a/pkg/errors/errorMessage.go b/pkg/errors/errorMessage.go index ddfd3fd1..1321382a 100644 --- a/pkg/errors/errorMessage.go +++ b/pkg/errors/errorMessage.go @@ -419,9 +419,15 @@ var ( GALASA_ERROR_UPDATE_USER_SERVER_REPORTED_ERROR = NewMessageType("GAL1216E: An attempt to update a user '%s' failed. Unexpected http status code %v received from the server. Error details from the server are: '%s'", 1216, STACK_TRACE_NOT_WANTED) GALASA_ERROR_UPDATE_USER_EXPLANATION_NOT_JSON = NewMessageType("GAL1217E: An attempt to update a user '%s' failed. Unexpected http status code %v received from the server. Error details from the server are not in the json format.", 1217, STACK_TRACE_NOT_WANTED) - GALASA_ERROR_MISSING_STREAM_NAME_FLAG = NewMessageType("GAL1218E: The stream name provided by the --name field cannot be an empty string.", 1218, STACK_TRACE_NOT_WANTED) - GALASA_ERROR_RETRIEVING_STREAMS_FROM_API_SERVER = NewMessageType("GAL1219E: Could not get list of test streams from API server. Reason: '%s'.", 1219, STACK_TRACE_WANTED) - GALASA_ERROR_INVALID_STREAM_NAME = NewMessageType("GAL1220E: The name provided with the --name flag cannot be empty and must only contain characters in the following ranges: 'a'-'z', 'A'-'Z', '0'-'9', '-' (dash), '_' (underscore).", 1220, STACK_TRACE_WANTED) + GALASA_ERROR_MISSING_STREAM_NAME_FLAG = NewMessageType("GAL1233E: The stream name provided by the --name field cannot be an empty string.", 1233, STACK_TRACE_NOT_WANTED) + GALASA_ERROR_RETRIEVING_STREAMS_FROM_API_SERVER = NewMessageType("GAL1234E: Could not get list of test streams from API server. Reason: '%s'.", 1234, STACK_TRACE_WANTED) + GALASA_ERROR_INVALID_STREAM_NAME = NewMessageType("GAL1235E: The name provided with the --name flag cannot be empty and must only contain characters in the following ranges: 'a'-'z', 'A'-'Z', '0'-'9', '-' (dash), '_' (underscore).", 1235, STACK_TRACE_WANTED) + GALASA_ERROR_GET_STREAMS_NO_RESPONSE_CONTENT = NewMessageType("GAL1236E: Failed to get streams. Unexpected http status code %v received from the server.", 1236, STACK_TRACE_NOT_WANTED) + GALASA_ERROR_GET_STREAMS_RESPONSE_BODY_UNREADABLE = NewMessageType("GAL1237E: Failed to get streams. Unexpected http status code %v received from the server. Error details from the server could not be read. Cause: %s", 1237, STACK_TRACE_NOT_WANTED) + GALASA_ERROR_GET_STREAMS_UNPARSEABLE_CONTENT = NewMessageType("GAL1238E: Failed to get streams. Unexpected http status code %v received from the server. Error details from the server are not in a valid json format. Cause: '%s'", 1238, STACK_TRACE_NOT_WANTED) + GALASA_ERROR_GET_STREAMS_SERVER_REPORTED_ERROR = NewMessageType("GAL1239E: Failed to get streams. Unexpected http status code %v received from the server. Error details from the server are: '%s'", 1239, STACK_TRACE_NOT_WANTED) + GALASA_ERROR_GET_STREAMS_EXPLANATION_NOT_JSON = NewMessageType("GAL1240E: Failed to get streams. Unexpected http status code %v received from the server. Error details from the server are not in the json format.", 1240, STACK_TRACE_NOT_WANTED) + // When getting multiple monitors... GALASA_ERROR_GET_MONITORS_REQUEST_FAILED = NewMessageType("GAL1218E: Failed to get monitors. Sending the get request to the Galasa service failed. Cause is %v", 1218, STACK_TRACE_NOT_WANTED) GALASA_ERROR_GET_MONITORS_NO_RESPONSE_CONTENT = NewMessageType("GAL1219E: Failed to get monitors. Unexpected http status code %v received from the server.", 1219, STACK_TRACE_NOT_WANTED) diff --git a/pkg/streams/streams.go b/pkg/streams/streams.go index c1b82c50..e645fd4b 100644 --- a/pkg/streams/streams.go +++ b/pkg/streams/streams.go @@ -7,10 +7,10 @@ package streams import ( - "regexp" "strings" galasaErrors "github.com/galasa-dev/cli/pkg/errors" + "github.com/galasa-dev/cli/pkg/utils" ) func validateStreamName(streamName string) (string, error) { @@ -21,11 +21,9 @@ func validateStreamName(streamName string) (string, error) { if streamName == "" { err = galasaErrors.NewGalasaError(galasaErrors.GALASA_ERROR_MISSING_STREAM_NAME_FLAG) } else { - // Check that stream name only contains alphanumeric characters, underscores, and hyphens - validChars := regexp.MustCompile(`^[a-zA-Z0-9_-]+$`) - if !validChars.MatchString(streamName) { - err = galasaErrors.NewGalasaError(galasaErrors.GALASA_ERROR_INVALID_STREAM_NAME) - } + if !utils.IsNameValid(streamName) { + err = galasaErrors.NewGalasaError(galasaErrors.GALASA_ERROR_INVALID_STREAM_NAME) + } } return streamName, err diff --git a/pkg/streams/streamsGet.go b/pkg/streams/streamsGet.go index d6f4cb8e..12694fa4 100644 --- a/pkg/streams/streamsGet.go +++ b/pkg/streams/streamsGet.go @@ -24,19 +24,22 @@ var ( formatters = createFormatters() ) -func GetStreams(streamName string, format string, apiClient *galasaapi.APIClient, console spi.Console) error { +func GetStreams(streamName string, format string, apiClient *galasaapi.APIClient, console spi.Console, byteReader spi.ByteReader) error { - var err error var streamData []galasaapi.Stream - if streamName != "" { - streamName, err = validateStreamName(streamName) - } + chosenFormatter, err := validateFormatFlag(format) if err == nil { - streamData, err = getStreamsFromRestApi(streamName, apiClient) + if streamName != "" { + streamName, err = validateStreamName(streamName) + } + if err == nil { - err = formatFetchedStreamsAndWriteToConsole(streamData, console, format) + streamData, err = getStreamsFromRestApi(streamName, apiClient, byteReader) + if err == nil { + err = formatFetchedStreamsAndWriteToConsole(streamData, console, chosenFormatter) + } } } @@ -44,16 +47,11 @@ func GetStreams(streamName string, format string, apiClient *galasaapi.APIClient } -func formatFetchedStreamsAndWriteToConsole(streams []galasaapi.Stream, console spi.Console, outputFormatString string) error { - - var formattedOuptut string - chosenFormatter, err := validateFormatFlag(outputFormatString) +func formatFetchedStreamsAndWriteToConsole(streams []galasaapi.Stream, console spi.Console, formatter streamsformatter.StreamsFormatter) error { + formattedOutput, err := formatter.FormatStreams(streams) if err == nil { - formattedOuptut, err = chosenFormatter.FormatStreams(streams) - if err == nil { - console.WriteString(formattedOuptut) - } + console.WriteString(formattedOutput) } return err @@ -63,6 +61,7 @@ func formatFetchedStreamsAndWriteToConsole(streams []galasaapi.Stream, console s func getStreamsFromRestApi( streamName string, apiClient *galasaapi.APIClient, + byteReader spi.ByteReader, ) ([]galasaapi.Stream, error) { var streams []galasaapi.Stream @@ -73,9 +72,9 @@ func getStreamsFromRestApi( if err == nil { if streamName != "" { - streams, err = getStreamByName(streamName, apiClient, restApiVersion) + streams, err = getStreamByName(streamName, apiClient, restApiVersion, byteReader) } else { - streams, err = getAllStreams(apiClient, restApiVersion) + streams, err = getAllStreams(apiClient, restApiVersion, byteReader) } } @@ -119,6 +118,7 @@ func getStreamByName( streamName string, apiClient *galasaapi.APIClient, restApiVersion string, + byteReader spi.ByteReader, ) ([]galasaapi.Stream, error) { var err error @@ -131,20 +131,31 @@ func getStreamByName( streamIn, resp, err = apiCall.Execute() - if err == nil { - var statusCode int - if resp != nil { - defer resp.Body.Close() - statusCode = resp.StatusCode - } + if resp != nil { + defer resp.Body.Close() + } + + if err != nil { - if statusCode != 200 { + if resp == nil { + err = galasaErrors.NewGalasaError(galasaErrors.GALASA_ERROR_RETRIEVING_STREAMS_FROM_API_SERVER, err.Error()) + } else { + err = galasaErrors.HttpResponseToGalasaError( + resp, + "", + byteReader, + galasaErrors.GALASA_ERROR_GET_STREAMS_NO_RESPONSE_CONTENT, + galasaErrors.GALASA_ERROR_GET_STREAMS_RESPONSE_BODY_UNREADABLE, + galasaErrors.GALASA_ERROR_GET_STREAMS_UNPARSEABLE_CONTENT, + galasaErrors.GALASA_ERROR_GET_STREAMS_SERVER_REPORTED_ERROR, + galasaErrors.GALASA_ERROR_GET_STREAMS_EXPLANATION_NOT_JSON, + ) log.Println("getStreamsFromRestApi - Failed to retrieve list of test streams from API server") - err = galasaErrors.NewGalasaErrorWithHttpStatusCode(statusCode, galasaErrors.GALASA_ERROR_RETRIEVING_STREAMS_FROM_API_SERVER, err.Error()) } - streamsToReturn = []galasaapi.Stream{*streamIn} + } + streamsToReturn = []galasaapi.Stream{*streamIn} return streamsToReturn, err } @@ -152,6 +163,7 @@ func getStreamByName( func getAllStreams( apiClient *galasaapi.APIClient, restApiVersion string, + byteReader spi.ByteReader, ) ([]galasaapi.Stream, error) { var err error @@ -163,21 +175,28 @@ func getAllStreams( streams, resp, err = apiCall.Execute() - if err == nil { + if resp != nil { + defer resp.Body.Close() + } - var statusCode int - if resp != nil { - defer resp.Body.Close() - statusCode = resp.StatusCode - } + if err != nil { - if statusCode == 200 { - log.Printf("getUserDataFromRestApi - %v test streams collected", len(streams)) + if resp == nil { + err = galasaErrors.NewGalasaError(galasaErrors.GALASA_ERROR_RETRIEVING_STREAMS_FROM_API_SERVER, err.Error()) } else { - log.Println("getStreamsFromRestApi - Failed to retrieve list of test streams from API server") - err = galasaErrors.NewGalasaErrorWithHttpStatusCode(statusCode, galasaErrors.GALASA_ERROR_RETRIEVING_STREAMS_FROM_API_SERVER, err.Error()) - statusCode = 500 + err = galasaErrors.HttpResponseToGalasaError( + resp, + "", + byteReader, + galasaErrors.GALASA_ERROR_GET_STREAMS_NO_RESPONSE_CONTENT, + galasaErrors.GALASA_ERROR_GET_STREAMS_RESPONSE_BODY_UNREADABLE, + galasaErrors.GALASA_ERROR_GET_STREAMS_UNPARSEABLE_CONTENT, + galasaErrors.GALASA_ERROR_GET_STREAMS_SERVER_REPORTED_ERROR, + galasaErrors.GALASA_ERROR_GET_STREAMS_EXPLANATION_NOT_JSON, + ) } + log.Println("getStreamsFromRestApi - Failed to retrieve list of test streams from API server") + } return streams, err diff --git a/pkg/streams/streamsGet_test.go b/pkg/streams/streamsGet_test.go index 56436e55..54ac28c2 100644 --- a/pkg/streams/streamsGet_test.go +++ b/pkg/streams/streamsGet_test.go @@ -83,6 +83,8 @@ func TestMultipleStreamsGetFormatsResultsOk(t *testing.T) { writer.Write([]byte(body)) } + mockByteReader := utils.NewMockByteReader() + interactions := []utils.HttpInteraction{ getStreamsInteraction, } @@ -100,7 +102,7 @@ mystream2 enabled Another stream to... Total:2 ` - err := GetStreams("", "summary", apiClient, console) + err := GetStreams("", "summary", apiClient, console, mockByteReader) assert.Nil(t, err) assert.Equal(t, expectedOutput, console.ReadText()) @@ -110,7 +112,7 @@ Total:2 func TestMissingStreamNameFlagReturnsBadRequest(t *testing.T) { //Given... - body := `{"error_code": 1218,"error_message": "GAL1218E: The stream name provided by the --name field cannot be an empty string."}` + body := `{"error_code": 1233,"error_message": "GAL1233E: The stream name provided by the --name field cannot be an empty string."}` getStreamsInteraction := utils.NewHttpInteraction("/streams", http.MethodGet) getStreamsInteraction.WriteHttpResponseFunc = func(writer http.ResponseWriter, req *http.Request) { @@ -119,6 +121,7 @@ func TestMissingStreamNameFlagReturnsBadRequest(t *testing.T) { writer.WriteHeader(http.StatusBadRequest) // It's going to fail with an error on purpose ! writer.Write([]byte(body)) } + mockByteReader := utils.NewMockByteReader() interactions := []utils.HttpInteraction{ getStreamsInteraction, @@ -130,10 +133,10 @@ func TestMissingStreamNameFlagReturnsBadRequest(t *testing.T) { apiClient := api.InitialiseAPI(server.Server.URL) console := utils.NewMockConsole() - expectedOutput := `GAL1218E: The stream name provided by the --name field cannot be an empty string.` + expectedOutput := `GAL1233E: The stream name provided by the --name field cannot be an empty string.` //When - err := GetStreams(" ", "summary", apiClient, console) + err := GetStreams(" ", "summary", apiClient, console, mockByteReader) //Then assert.NotNil(t, err) @@ -180,6 +183,7 @@ func TestMultipleStreamByNameGetFormatsResultsOk(t *testing.T) { writer.WriteHeader(http.StatusOK) writer.Write([]byte(body)) } + mockByteReader := utils.NewMockByteReader() interactions := []utils.HttpInteraction{ getStreamsInteraction, @@ -197,9 +201,69 @@ mystream enabled A stream which I use to... Total:1 ` - err := GetStreams(streamName, "summary", apiClient, console) + err := GetStreams(streamName, "summary", apiClient, console, mockByteReader) assert.Nil(t, err) assert.Equal(t, expectedOutput, console.ReadText()) } + +func TestTryGettingAnythingWithAnInvalidFormatterNameFailsImmediately(t *testing.T) { + // Not expecting any iteractions... + interactions := []utils.HttpInteraction{} + + server := utils.NewMockHttpServer(t, interactions) + defer server.Server.Close() + + console := utils.NewMockConsole() + apiServerUrl := server.Server.URL + apiClient := api.InitialiseAPI(apiServerUrl) + mockByteReader := utils.NewMockByteReader() + + err := GetStreams( + "mystream", + "asdfghjk", + apiClient, + console, + mockByteReader) + + assert.NotNil(t, err, "Expected an error, didn't get one!") + assert.Contains(t, err.Error(), "GAL1067E") +} + +func TestCanGetAStreamByNameWhenStreamExistsFindsItOkSummaryFormat(t *testing.T) { + // Given... + outputFormat := "summary" + + // Create the expected HTTP interactions with the API server. + getStreamInteraction := utils.NewHttpInteraction("/streams", http.MethodGet) + getStreamInteraction.WriteHttpResponseFunc = func(writer http.ResponseWriter, req *http.Request) { + writer.Header().Set("Content-Type", "application/json") + writer.WriteHeader(http.StatusOK) + writer.Write([]byte("Not valid json format output from fake service")) + } + + interactions := []utils.HttpInteraction{ + getStreamInteraction, + } + + server := utils.NewMockHttpServer(t, interactions) + defer server.Server.Close() + + console := utils.NewMockConsole() + apiServerUrl := server.Server.URL + apiClient := api.InitialiseAPI(apiServerUrl) + mockByteReader := utils.NewMockByteReader() + + // When... + err := GetStreams( + "", + outputFormat, + apiClient, + console, + mockByteReader) + + // Then... + assert.NotNil(t, err, "GetStreams returned an error when none was expected") + assert.Contains(t, err.Error(), "GAL1238E") +} diff --git a/pkg/streams/streams_test.go b/pkg/streams/streams_test.go index 69bd5d5c..10e3c8af 100644 --- a/pkg/streams/streams_test.go +++ b/pkg/streams/streams_test.go @@ -29,7 +29,7 @@ func TestValidateStreamNameRegexFlagReturnsError(t *testing.T) { streamName, err := validateStreamName(invalidStreamName) assert.NotNil(t, err) - assert.ErrorContains(t, err, "GAL1220E") + assert.ErrorContains(t, err, "GAL1235E") assert.NotEmpty(t, streamName) } diff --git a/pkg/streamsformatter/summaryFormatter.go b/pkg/streamsformatter/summaryFormatter.go index 9126c454..cfa533ef 100644 --- a/pkg/streamsformatter/summaryFormatter.go +++ b/pkg/streamsformatter/summaryFormatter.go @@ -18,6 +18,8 @@ import ( // Summary format. const ( SUMMARY_FORMATTER_NAME = "summary" + ENABLED_STATE = "enabled" + DISABLED_STATE = "disabled" ) type StreamsSummaryFormatter struct { @@ -31,9 +33,6 @@ func (*StreamsSummaryFormatter) GetName() string { return SUMMARY_FORMATTER_NAME } -var ENABLED_STATE = "enabled" -var DISABLED_STATE = "disabled" - func (*StreamsSummaryFormatter) FormatStreams(streams []galasaapi.Stream) (string, error) { var result string diff --git a/pkg/streamsformatter/summaryFormatter_test.go b/pkg/streamsformatter/summaryFormatter_test.go index 43f7f490..9e8983db 100644 --- a/pkg/streamsformatter/summaryFormatter_test.go +++ b/pkg/streamsformatter/summaryFormatter_test.go @@ -33,7 +33,7 @@ func CreateMockStream(streamName string, isEnabled bool, description string) *ga func TestStreamsSummaryFormatterSingleDataReturnsCorrectly(t *testing.T) { // Given... formatter := NewStreamsSummaryFormatter() - // No data to format...x + streams := make([]galasaapi.Stream, 0) stream1 := CreateMockStream("mystream", true, "My test stream") streams = append(streams, *stream1) @@ -53,9 +53,9 @@ Total:1 } func TestStreamsSummaryFormatterMultipleDataSeperatesWithNewLine(t *testing.T) { - // For.. + //Given.. formatter := NewStreamsSummaryFormatter() - // No data to format... + streams := make([]galasaapi.Stream, 0) stream1 := CreateMockStream("mystream", true, "This is a test stream") stream2 := CreateMockStream("my-test-stream", false, "Dummy test stream") diff --git a/pkg/streamsformatter/yamlFormatter.go b/pkg/streamsformatter/yamlFormatter.go index 8189452b..2a84c74e 100644 --- a/pkg/streamsformatter/yamlFormatter.go +++ b/pkg/streamsformatter/yamlFormatter.go @@ -33,59 +33,22 @@ func (*StreamsYamlFormatter) FormatStreams(streams []galasaapi.Stream) (string, buff := strings.Builder{} for index, stream := range streams { - if index > 0 { - buff.WriteString("---\n") - } - - type ObrInfo struct { - MavenGroupID string `yaml:"maven-group-id"` - MavenArtifactID string `yaml:"maven-artifact-id"` - MavenVersion string `yaml:"maven-version"` - } + content := "" - type RepositoryURL struct { - URL string `yaml:"url"` - } - - type StreamYAML struct { - APIVersion string `yaml:"apiVersion"` - Kind string `yaml:"kind"` - Metadata struct { - Name string `yaml:"name"` - Description string `yaml:"description"` - } `yaml:"metadata"` - Data struct { - Repository []RepositoryURL `yaml:"repository"` - TestCatalog []RepositoryURL `yaml:"testCatalog"` - Obrs []ObrInfo `yaml:"obrs"` - } `yaml:"data"` - } - - streamYAML := StreamYAML{ - APIVersion: "galasa-dev/v1alpha1", - Kind: "GalasaStream", - } - streamYAML.Metadata.Name = *stream.Metadata.Name - streamYAML.Metadata.Description = *stream.Metadata.Description - - // Add repository and test catalog - streamYAML.Data.Repository = []RepositoryURL{{URL: *stream.Data.Repository.Url}} - streamYAML.Data.TestCatalog = []RepositoryURL{{URL: *stream.Data.TestCatalog.Url}} - - // Add the obrs section - streamYAML.Data.Obrs = []ObrInfo{ - { - MavenGroupID: *stream.Data.Obrs[0].GroupId, - MavenArtifactID: *stream.Data.Obrs[0].ArtifactId, - MavenVersion: *stream.Data.Obrs[0].Version, - }, + if index > 0 { + content += "---\n" } - yamlBytes, err := yaml.Marshal(streamYAML) + var yamlRepresentationBytes []byte + yamlRepresentationBytes, err = yaml.Marshal(stream) if err == nil { - buff.Write(yamlBytes) + yamlStr := string(yamlRepresentationBytes) + content += yamlStr } + + buff.WriteString(content) } - return buff.String(), err + result := buff.String() + return result, err } diff --git a/pkg/streamsformatter/yamlFormatter_test.go b/pkg/streamsformatter/yamlFormatter_test.go index 7ad0f89e..027582ca 100644 --- a/pkg/streamsformatter/yamlFormatter_test.go +++ b/pkg/streamsformatter/yamlFormatter_test.go @@ -17,7 +17,7 @@ import ( const ( STREAM_DESCRIPTION = "This a Galasa test stream" MAVEN_REPO_URL = "mvn:myGroup/myArtifact/0.38.0/obr" - TEST_CATALOG_URL = "http://my/test/catalog.json" + TEST_CATALOG_URL = "mvn:myGroup/myArtifact/0.38.0/obr" MAVEN_GROUP_ID = "myGroup" MAVEN_ARTIFACT_ID = "myArtifact" MAVEN_VERSION = "0.38.0" @@ -71,14 +71,14 @@ metadata: description: %s data: repository: - - url: %s - testCatalog: - - url: %s + url: %s obrs: - - maven-group-id: %s - maven-artifact-id: %s - maven-version: %s`, - streamName, STREAM_DESCRIPTION, MAVEN_REPO_URL, TEST_CATALOG_URL, MAVEN_GROUP_ID, MAVEN_ARTIFACT_ID, MAVEN_VERSION) + - group-id: %s + artifact-id: %s + version: %s + testCatalog: + url: %s`, + streamName, STREAM_DESCRIPTION, MAVEN_REPO_URL, MAVEN_GROUP_ID, MAVEN_ARTIFACT_ID, MAVEN_VERSION, TEST_CATALOG_URL) } func TestSecretsYamlFormatterNoDataReturnsBlankString(t *testing.T) { From 2d8c561b687a7c8f1718d891dd52e2e7430a58c4 Mon Sep 17 00:00:00 2001 From: Aashir Siddiqui Date: Wed, 2 Apr 2025 15:40:41 +0100 Subject: [PATCH 4/4] Changed test name Signed-off-by: Aashir Siddiqui --- pkg/streams/streamsGet_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkg/streams/streamsGet_test.go b/pkg/streams/streamsGet_test.go index 54ac28c2..40f14ab4 100644 --- a/pkg/streams/streamsGet_test.go +++ b/pkg/streams/streamsGet_test.go @@ -231,7 +231,7 @@ func TestTryGettingAnythingWithAnInvalidFormatterNameFailsImmediately(t *testing assert.Contains(t, err.Error(), "GAL1067E") } -func TestCanGetAStreamByNameWhenStreamExistsFindsItOkSummaryFormat(t *testing.T) { +func TestCanGetAStreamByNameWhenStreamExistsGivesUnexpectedErrorSummaryFormat(t *testing.T) { // Given... outputFormat := "summary"