From 894f271258d4c497c99fe038f7420c0a130cfa45 Mon Sep 17 00:00:00 2001 From: Sunny Guduru Date: Mon, 15 Apr 2024 14:42:04 -0700 Subject: [PATCH 1/6] added get with flags, updated flag client to have read --- cmd/flags/get.go | 80 ++++++++++++++++++++++++++++++++++++++++ internal/flags/client.go | 22 +++++++++++ 2 files changed, 102 insertions(+) create mode 100644 cmd/flags/get.go diff --git a/cmd/flags/get.go b/cmd/flags/get.go new file mode 100644 index 00000000..8f8d2387 --- /dev/null +++ b/cmd/flags/get.go @@ -0,0 +1,80 @@ +package flags + +import ( + "context" + "fmt" + + "github.com/spf13/cobra" + "github.com/spf13/viper" + + "ldcli/cmd/cliflags" + "ldcli/cmd/validators" + "ldcli/internal/flags" +) + +func NewGetCmd(client flags.Client) (*cobra.Command, error) { + cmd := &cobra.Command{ + Args: validators.Validate(), + Long: "Get a flag to check its details", + RunE: runGet(client), + Short: "Get a flag", + Use: "get", + } + + cmd.Flags().StringP(cliflags.FlagFlag, "", "", "Flag key") + err := cmd.MarkFlagRequired(cliflags.FlagFlag) + if err != nil { + return nil, err + } + err = viper.BindPFlag(cliflags.FlagFlag, cmd.Flags().Lookup(cliflags.FlagFlag)) + if err != nil { + return nil, err + } + + cmd.Flags().String(cliflags.ProjectFlag, "", "Project key") + err = cmd.MarkFlagRequired(cliflags.ProjectFlag) + if err != nil { + return nil, err + } + err = viper.BindPFlag(cliflags.ProjectFlag, cmd.Flags().Lookup(cliflags.ProjectFlag)) + if err != nil { + return nil, err + } + + cmd.Flags().String(cliflags.EnvironmentFlag, "", "Environment key") + err = cmd.MarkFlagRequired(cliflags.EnvironmentFlag) + if err != nil { + return nil, err + } + err = viper.BindPFlag(cliflags.EnvironmentFlag, cmd.Flags().Lookup(cliflags.EnvironmentFlag)) + if err != nil { + return nil, err + } + + return cmd, nil +} + +func runGet(client flags.Client) func(*cobra.Command, []string) error { + return func(cmd *cobra.Command, args []string) error { + // rebind flags used in other subcommands + _ = viper.BindPFlag(cliflags.FlagFlag, cmd.Flags().Lookup(cliflags.FlagFlag)) + _ = viper.BindPFlag(cliflags.ProjectFlag, cmd.Flags().Lookup(cliflags.ProjectFlag)) + _ = viper.BindPFlag(cliflags.EnvironmentFlag, cmd.Flags().Lookup(cliflags.EnvironmentFlag)) + + response, err := client.Read( + context.Background(), + viper.GetString(cliflags.AccessTokenFlag), + viper.GetString(cliflags.BaseURIFlag), + viper.GetString(cliflags.FlagFlag), + viper.GetString(cliflags.ProjectFlag), + viper.GetString(cliflags.EnvironmentFlag), + ) + if err != nil { + return err + } + + fmt.Fprintf(cmd.OutOrStdout(), string(response)+"\n") + + return nil + } +} diff --git a/internal/flags/client.go b/internal/flags/client.go index 2a46ab18..5ad27bf4 100644 --- a/internal/flags/client.go +++ b/internal/flags/client.go @@ -19,6 +19,7 @@ type UpdateInput struct { type Client interface { Create(ctx context.Context, accessToken, baseURI, name, key, projKey string) ([]byte, error) + Read(ctx context.Context, accessToken, baseURI, key, projKey, envKey string) ([]byte, error) Update( ctx context.Context, accessToken, @@ -54,7 +55,28 @@ func (c FlagsClient) Create( flag, _, err := client.FeatureFlagsApi.PostFeatureFlag(ctx, projectKey).FeatureFlagBody(*post).Execute() if err != nil { return nil, errors.NewLDAPIError(err) + } + + responseJSON, err := json.Marshal(flag) + if err != nil { + return nil, err + } + + return responseJSON, nil +} +func (c FlagsClient) Read( + ctx context.Context, + accessToken, + baseURI, + key, + projectKey, + environmentKey string, +) ([]byte, error) { + client := client.New(accessToken, baseURI, c.cliVersion) + flag, _, err := client.FeatureFlagsApi.GetFeatureFlag(ctx, projectKey, key).Env(environmentKey).Execute() + if err != nil { + return nil, errors.NewLDAPIError(err) } responseJSON, err := json.Marshal(flag) From 14733321f49ea12c79ed6f169198680524272be6 Mon Sep 17 00:00:00 2001 From: Sunny Guduru Date: Mon, 15 Apr 2024 14:53:28 -0700 Subject: [PATCH 2/6] added mock client read method --- internal/flags/mock_client.go | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/internal/flags/mock_client.go b/internal/flags/mock_client.go index d224f65a..cc2101ec 100644 --- a/internal/flags/mock_client.go +++ b/internal/flags/mock_client.go @@ -25,6 +25,19 @@ func (c *MockClient) Create( return args.Get(0).([]byte), args.Error(1) } +func (c *MockClient) Read( + ctx context.Context, + accessToken, + baseURI, + key, + projKey, + envKey string, +) ([]byte, error) { + args := c.Called(accessToken, baseURI, key, projKey, envKey) + + return args.Get(0).([]byte), args.Error(1) +} + func (c *MockClient) Update( ctx context.Context, accessToken, From 2c5be64046de8d65929d0d51e5e9bd16fe5472a5 Mon Sep 17 00:00:00 2001 From: Sunny Guduru Date: Mon, 15 Apr 2024 15:07:36 -0700 Subject: [PATCH 3/6] fix mock client, add tests --- cmd/flags/flags.go | 5 +++ cmd/flags/get.go | 2 +- cmd/flags/get_test.go | 91 +++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 97 insertions(+), 1 deletion(-) create mode 100644 cmd/flags/get_test.go diff --git a/cmd/flags/flags.go b/cmd/flags/flags.go index 7e1b6cd7..4fe44604 100644 --- a/cmd/flags/flags.go +++ b/cmd/flags/flags.go @@ -17,6 +17,10 @@ func NewFlagsCmd(client flags.Client) (*cobra.Command, error) { if err != nil { return nil, err } + getCmd, err := NewGetCmd(client) + if err != nil { + return nil, err + } updateCmd, err := NewUpdateCmd(client) if err != nil { return nil, err @@ -32,6 +36,7 @@ func NewFlagsCmd(client flags.Client) (*cobra.Command, error) { } cmd.AddCommand(createCmd) + cmd.AddCommand(getCmd) cmd.AddCommand(updateCmd) cmd.AddCommand(toggleOnUpdateCmd) cmd.AddCommand(toggleOffUpdateCmd) diff --git a/cmd/flags/get.go b/cmd/flags/get.go index 8f8d2387..aa488b3c 100644 --- a/cmd/flags/get.go +++ b/cmd/flags/get.go @@ -21,7 +21,7 @@ func NewGetCmd(client flags.Client) (*cobra.Command, error) { Use: "get", } - cmd.Flags().StringP(cliflags.FlagFlag, "", "", "Flag key") + cmd.Flags().String(cliflags.FlagFlag, "", "Flag key") err := cmd.MarkFlagRequired(cliflags.FlagFlag) if err != nil { return nil, err diff --git a/cmd/flags/get_test.go b/cmd/flags/get_test.go new file mode 100644 index 00000000..60135913 --- /dev/null +++ b/cmd/flags/get_test.go @@ -0,0 +1,91 @@ +package flags_test + +import ( + "ldcli/cmd" + "ldcli/internal/errors" + "ldcli/internal/flags" + "testing" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" +) + +func TestGet(t *testing.T) { + errorHelp := ". See `ldcli flags get --help` for supported flags and usage." + mockArgs := []interface{}{ + "testAccessToken", + "http://test.com", + "test-key", + "test-proj-key", + "test-env-key", + } + + t.Run("with valid flags calls API", func(t *testing.T) { + client := flags.MockClient{} + client. + On("Read", mockArgs...). + Return([]byte(cmd.ValidResponse), nil) + args := []string{ + "flags", "get", + "--access-token", "testAccessToken", + "--base-uri", "http://test.com", + "--flag", "test-key", + "--project", "test-proj-key", + "--environment", "test-env-key", + } + + output, err := cmd.CallCmd(t, nil, &client, nil, nil, args) + + require.NoError(t, err) + assert.JSONEq(t, `{"valid": true}`, string(output)) + }) + + t.Run("with valid flags from environment variables calls API", func(t *testing.T) { + teardownTest := cmd.SetupTestEnvVars(t) + defer teardownTest(t) + client := flags.MockClient{} + client. + On("Read", mockArgs...). + Return([]byte(cmd.ValidResponse), nil) + args := []string{ + "flags", "get", + "--flag", "test-key", + "--project", "test-proj-key", + "--environment", "test-env-key", + } + + output, err := cmd.CallCmd(t, nil, &client, nil, nil, args) + + require.NoError(t, err) + assert.JSONEq(t, `{"valid": true}`, string(output)) + }) + + t.Run("with an error response is an error", func(t *testing.T) { + client := flags.MockClient{} + client. + On("Read", mockArgs...). + Return([]byte(`{}`), errors.NewError("An error")) + args := []string{ + "flags", "get", + "--access-token", "testAccessToken", + "--base-uri", "http://test.com", + "--flag", "test-key", + "--project", "test-proj-key", + "--environment", "test-env-key", + } + + _, err := cmd.CallCmd(t, nil, &client, nil, nil, args) + + require.EqualError(t, err, "An error") + }) + + t.Run("with missing required flags is an error", func(t *testing.T) { + args := []string{ + "flags", "get", + } + + _, err := cmd.CallCmd(t, nil, &flags.MockClient{}, nil, nil, args) + + assert.EqualError(t, err, `required flag(s) "access-token", "environment", "flag", "project" not set`+errorHelp) + }) +} From 9409ad7cb314f3890c186be45af2f7dd3fcae6da Mon Sep 17 00:00:00 2001 From: Sunny Guduru Date: Mon, 15 Apr 2024 15:08:56 -0700 Subject: [PATCH 4/6] ported over remaining tests --- cmd/flags/get_test.go | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/cmd/flags/get_test.go b/cmd/flags/get_test.go index 60135913..19cffc71 100644 --- a/cmd/flags/get_test.go +++ b/cmd/flags/get_test.go @@ -88,4 +88,19 @@ func TestGet(t *testing.T) { assert.EqualError(t, err, `required flag(s) "access-token", "environment", "flag", "project" not set`+errorHelp) }) + + t.Run("with invalid base-uri is an error", func(t *testing.T) { + args := []string{ + "flags", "get", + "--access-token", "testAccessToken", + "--base-uri", "invalid", + "--flag", "test-key", + "--project", "test-proj-key", + "--environment", "test-env-key", + } + + _, err := cmd.CallCmd(t, nil, &flags.MockClient{}, nil, nil, args) + + assert.EqualError(t, err, "base-uri is invalid"+errorHelp) + }) } From fd753bb4664aab97320093ba3303f13634c14257 Mon Sep 17 00:00:00 2001 From: Sunny Guduru Date: Tue, 16 Apr 2024 14:12:04 -0700 Subject: [PATCH 5/6] rename READ to GET --- cmd/flags/get.go | 2 +- internal/flags/client.go | 4 ++-- internal/flags/mock_client.go | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/cmd/flags/get.go b/cmd/flags/get.go index aa488b3c..de18ba8d 100644 --- a/cmd/flags/get.go +++ b/cmd/flags/get.go @@ -61,7 +61,7 @@ func runGet(client flags.Client) func(*cobra.Command, []string) error { _ = viper.BindPFlag(cliflags.ProjectFlag, cmd.Flags().Lookup(cliflags.ProjectFlag)) _ = viper.BindPFlag(cliflags.EnvironmentFlag, cmd.Flags().Lookup(cliflags.EnvironmentFlag)) - response, err := client.Read( + response, err := client.Get( context.Background(), viper.GetString(cliflags.AccessTokenFlag), viper.GetString(cliflags.BaseURIFlag), diff --git a/internal/flags/client.go b/internal/flags/client.go index 5ad27bf4..72fbd361 100644 --- a/internal/flags/client.go +++ b/internal/flags/client.go @@ -19,7 +19,7 @@ type UpdateInput struct { type Client interface { Create(ctx context.Context, accessToken, baseURI, name, key, projKey string) ([]byte, error) - Read(ctx context.Context, accessToken, baseURI, key, projKey, envKey string) ([]byte, error) + Get(ctx context.Context, accessToken, baseURI, key, projKey, envKey string) ([]byte, error) Update( ctx context.Context, accessToken, @@ -65,7 +65,7 @@ func (c FlagsClient) Create( return responseJSON, nil } -func (c FlagsClient) Read( +func (c FlagsClient) Get( ctx context.Context, accessToken, baseURI, diff --git a/internal/flags/mock_client.go b/internal/flags/mock_client.go index cc2101ec..8dc8e17c 100644 --- a/internal/flags/mock_client.go +++ b/internal/flags/mock_client.go @@ -25,7 +25,7 @@ func (c *MockClient) Create( return args.Get(0).([]byte), args.Error(1) } -func (c *MockClient) Read( +func (c *MockClient) Get( ctx context.Context, accessToken, baseURI, From e99d5e16f4b0f1127d73723fd460eecc7c1c065d Mon Sep 17 00:00:00 2001 From: Sunny Guduru Date: Tue, 16 Apr 2024 14:14:07 -0700 Subject: [PATCH 6/6] update test --- cmd/flags/get_test.go | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/cmd/flags/get_test.go b/cmd/flags/get_test.go index 19cffc71..fb2d6752 100644 --- a/cmd/flags/get_test.go +++ b/cmd/flags/get_test.go @@ -23,7 +23,7 @@ func TestGet(t *testing.T) { t.Run("with valid flags calls API", func(t *testing.T) { client := flags.MockClient{} client. - On("Read", mockArgs...). + On("Get", mockArgs...). Return([]byte(cmd.ValidResponse), nil) args := []string{ "flags", "get", @@ -45,7 +45,7 @@ func TestGet(t *testing.T) { defer teardownTest(t) client := flags.MockClient{} client. - On("Read", mockArgs...). + On("Get", mockArgs...). Return([]byte(cmd.ValidResponse), nil) args := []string{ "flags", "get", @@ -63,7 +63,7 @@ func TestGet(t *testing.T) { t.Run("with an error response is an error", func(t *testing.T) { client := flags.MockClient{} client. - On("Read", mockArgs...). + On("Get", mockArgs...). Return([]byte(`{}`), errors.NewError("An error")) args := []string{ "flags", "get",