diff --git a/tools/cli/admin_config_store_commands.go b/tools/cli/admin_config_store_commands.go index 129be337d31..308fc23886d 100644 --- a/tools/cli/admin_config_store_commands.go +++ b/tools/cli/admin_config_store_commands.go @@ -24,6 +24,7 @@ import ( "encoding/json" "fmt" "sort" + "strings" "github.com/olekukonko/tablewriter" "github.com/urfave/cli/v2" @@ -110,7 +111,22 @@ func AdminUpdateDynamicConfig(c *cli.Context) error { if err != nil { return commoncli.Problem("Required flag not found", err) } - dcValues := c.StringSlice(FlagDynamicConfigValue) + dcValuesRaw := c.StringSlice(FlagDynamicConfigValue) + + // WORKAROUND: urfave/cli v2 StringSliceFlag splits on commas by default. + // This breaks JSON values. Try reassembling the split pieces. + var dcValues []string + if len(dcValuesRaw) > 1 && strings.HasPrefix(dcValuesRaw[0], "{") { + assembled := strings.Join(dcValuesRaw, ",") + var test interface{} + if json.Unmarshal([]byte(assembled), &test) == nil { + dcValues = []string{assembled} + } else { + dcValues = dcValuesRaw + } + } else { + dcValues = dcValuesRaw + } ctx, cancel, err := newContext(c) defer cancel() diff --git a/tools/cli/admin_config_store_commands_test.go b/tools/cli/admin_config_store_commands_test.go index 37786da4603..c8444812368 100644 --- a/tools/cli/admin_config_store_commands_test.go +++ b/tools/cli/admin_config_store_commands_test.go @@ -24,6 +24,7 @@ package cli import ( "context" + "encoding/json" "testing" "github.com/stretchr/testify/assert" @@ -166,6 +167,91 @@ func TestAdminUpdateDynamicConfig(t *testing.T) { }, errContains: "Failed to update dynamic config value", }, + { + name: "update with simple boolean value", + cmdline: `cadence admin config update --name test.config --value ` + `'{"Value":true,"Filters":[]}'`, + setupMocks: func(td *cliTestData) { + td.mockAdminClient.EXPECT().UpdateDynamicConfig(gomock.Any(), gomock.Any()). + DoAndReturn(func(_ context.Context, request *types.UpdateDynamicConfigRequest, _ ...yarpc.CallOption) error { + assert.Equal(t, "test.config", request.ConfigName) + assert.Len(t, request.ConfigValues, 1) + + // Verify the value is correctly parsed + var actualValue interface{} + err := json.Unmarshal(request.ConfigValues[0].Value.Data, &actualValue) + assert.NoError(t, err) + assert.Equal(t, true, actualValue) + + // Verify no filters + assert.Empty(t, request.ConfigValues[0].Filters) + + return nil + }) + }, + errContains: "", + }, + { + name: "update with map value and no filters", + cmdline: `cadence admin config update --name frontend.validSearchAttributes --value ` + `'{"Value":{"DomainID":1,"WorkflowID":1},"Filters":[]}'`, + setupMocks: func(td *cliTestData) { + td.mockAdminClient.EXPECT().UpdateDynamicConfig(gomock.Any(), gomock.Any()). + DoAndReturn(func(_ context.Context, request *types.UpdateDynamicConfigRequest, _ ...yarpc.CallOption) error { + assert.Equal(t, "frontend.validSearchAttributes", request.ConfigName) + assert.Len(t, request.ConfigValues, 1) + + // Verify the value is correctly parsed + var actualValue interface{} + err := json.Unmarshal(request.ConfigValues[0].Value.Data, &actualValue) + assert.NoError(t, err) + + expectedValue := map[string]interface{}{ + "DomainID": float64(1), // JSON numbers unmarshal to float64 + "WorkflowID": float64(1), + } + assert.Equal(t, expectedValue, actualValue) + + // Verify no filters + assert.Empty(t, request.ConfigValues[0].Filters) + + return nil + }) + }, + errContains: "", + }, + { + name: "update with map value and filters", + cmdline: `cadence admin config update --name frontend.validSearchAttributes --value ` + `'{"Value":{"DomainID":1,"WorkflowID":1},"Filters":[{"Name":"domainName","Value":"test-domain"}]}'`, + setupMocks: func(td *cliTestData) { + td.mockAdminClient.EXPECT().UpdateDynamicConfig(gomock.Any(), gomock.Any()). + DoAndReturn(func(_ context.Context, request *types.UpdateDynamicConfigRequest, _ ...yarpc.CallOption) error { + assert.Equal(t, "frontend.validSearchAttributes", request.ConfigName) + assert.Len(t, request.ConfigValues, 1) + + // Verify the value is correctly parsed + var actualValue interface{} + err := json.Unmarshal(request.ConfigValues[0].Value.Data, &actualValue) + assert.NoError(t, err) + + expectedValue := map[string]interface{}{ + "DomainID": float64(1), + "WorkflowID": float64(1), + } + assert.Equal(t, expectedValue, actualValue) + + // Verify filters + assert.Len(t, request.ConfigValues[0].Filters, 1) + assert.Equal(t, "domainName", request.ConfigValues[0].Filters[0].Name) + + var filterValue interface{} + err = json.Unmarshal(request.ConfigValues[0].Filters[0].Value.Data, &filterValue) + assert.NoError(t, err) + assert.Equal(t, "test-domain", filterValue) + + return nil + }) + }, + errContains: "", + }, } for _, tt := range tests {