Skip to content

Commit

Permalink
add tests
Browse files Browse the repository at this point in the history
  • Loading branch information
yuandrew committed Nov 13, 2024
1 parent 0560556 commit 64b9aa6
Show file tree
Hide file tree
Showing 9 changed files with 178 additions and 22 deletions.
8 changes: 4 additions & 4 deletions temporalcli/commands.gen.go
Original file line number Diff line number Diff line change
Expand Up @@ -1261,9 +1261,9 @@ func NewTemporalOperatorSearchAttributeCommand(cctx *CommandContext, parent *Tem
s.Command.Use = "search-attribute"
s.Command.Short = "Search Attribute operations"
if hasHighlighting {
s.Command.Long = "Create, list, or remove Search Attributes fields stored in a Workflow\nExecution's metadata:\n\n\x1b[1mtemporal operator search-attribute create \\\n --name YourAttributeName \\\n --type Keyword\x1b[0m\n\nSupported types include: Text, Keyword, Int, Double, Bool, Datetime, and\nKeywordList.\n\nIf you wish to delete a Search Attribute, please contact support\nat https://support.temporal.io."
s.Command.Long = "Create, list, or remove Search Attributes fields stored in a Workflow\nExecution's metadata:\n\n\x1b[1mtemporal operator search-attribute create \\\n --name YourAttributeName \\\n --type Keyword\x1b[0m\n\nSupported types include: text, keyword, int, double, bool, datetime, and\nkeyword-list.\n\nIf you wish to delete a Search Attribute, please contact support\nat https://support.temporal.io."
} else {
s.Command.Long = "Create, list, or remove Search Attributes fields stored in a Workflow\nExecution's metadata:\n\n```\ntemporal operator search-attribute create \\\n --name YourAttributeName \\\n --type Keyword\n```\n\nSupported types include: Text, Keyword, Int, Double, Bool, Datetime, and\nKeywordList.\n\nIf you wish to delete a Search Attribute, please contact support\nat https://support.temporal.io."
s.Command.Long = "Create, list, or remove Search Attributes fields stored in a Workflow\nExecution's metadata:\n\n```\ntemporal operator search-attribute create \\\n --name YourAttributeName \\\n --type Keyword\n```\n\nSupported types include: text, keyword, int, double, bool, datetime, and\nkeyword-list.\n\nIf you wish to delete a Search Attribute, please contact support\nat https://support.temporal.io."
}
s.Command.Args = cobra.NoArgs
s.Command.AddCommand(&NewTemporalOperatorSearchAttributeCreateCommand(cctx, &s).Command)
Expand Down Expand Up @@ -1293,7 +1293,7 @@ func NewTemporalOperatorSearchAttributeCreateCommand(cctx *CommandContext, paren
s.Command.Args = cobra.NoArgs
s.Command.Flags().StringArrayVar(&s.Name, "name", nil, "Search Attribute name. Required.")
_ = cobra.MarkFlagRequired(s.Command.Flags(), "name")
s.Type = NewStringEnumArray([]string{"text", "keyword", "int", "double", "bool", "datetime", "keyword-list"}, []string{})
s.Type = NewStringEnumArray([]string{"text", "keyword", "int", "double", "bool", "datetime", "keyword-list", "KeywordList"}, []string{})
s.Command.Flags().Var(&s.Type, "type", "Search Attribute type. Accepted values: text, keyword, int, double, bool, datetime, keyword-list. Required.")
_ = cobra.MarkFlagRequired(s.Command.Flags(), "type")
s.Command.Run = func(c *cobra.Command, args []string) {
Expand Down Expand Up @@ -1714,7 +1714,7 @@ func NewTemporalServerStartDevCommand(cctx *CommandContext, parent *TemporalServ
s.Command.Flags().StringArrayVar(&s.SqlitePragma, "sqlite-pragma", nil, "SQLite pragma statements in \"PRAGMA=VALUE\" format.")
s.Command.Flags().StringArrayVar(&s.DynamicConfigValue, "dynamic-config-value", nil, "Dynamic configuration value using `KEY=VALUE` pairs. Keys must be identifiers, and values must be JSON values. For example: 'YourKey=\"YourString\"'. Can be passed multiple times.")
s.Command.Flags().BoolVar(&s.LogConfig, "log-config", false, "Log the server config to stderr.")
s.Command.Flags().StringArrayVar(&s.SearchAttribute, "search-attribute", nil, "Search attributes to register using `KEY=VALUE` pairs. Keys must be identifiers, and values must be the search attribute type, which is one of the following: Text, Keyword, Int, Double, Bool, Datetime, KeywordList.")
s.Command.Flags().StringArrayVar(&s.SearchAttribute, "search-attribute", nil, "Search attributes to register using `KEY=VALUE` pairs. Keys must be identifiers, and values must be the search attribute type, which is one of the following: text, keyword, int, double, bool, datetime, keyword-list.")
s.Command.Run = func(c *cobra.Command, args []string) {
if err := s.run(cctx, args); err != nil {
cctx.Options.Fail(err)
Expand Down
3 changes: 3 additions & 0 deletions temporalcli/commands.operator_search_attribute.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,9 @@ func (c *TemporalOperatorSearchAttributeCreateCommand) run(cctx *CommandContext,

searchAttributes := make(map[string]enums.IndexedValueType, len(c.Type.Values))
for i, saType := range c.Type.Values {
if strings.EqualFold(saType, "keyword-list") {
saType = "KeywordList"
}
saName := c.Name[i]
typeInt, err := searchAttributeTypeStringToEnum(saType)
if err != nil {
Expand Down
18 changes: 18 additions & 0 deletions temporalcli/commands.operator_search_attribute_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -98,3 +98,21 @@ func (s *SharedServerSuite) TestOperator_SearchAttribute() {
s.Equal(enums.INDEXED_VALUE_TYPE_DATETIME, jsonOut.SystemAttributes["StartTime"])
s.Equal(enums.INDEXED_VALUE_TYPE_KEYWORD, jsonOut.SystemAttributes["WorkflowId"])
}

func (s *SharedServerSuite) TestOperator_SearchAttribute_LegacyType() {
res := s.Execute(
"operator", "search-attribute", "create",
"--address", s.Address(),
"--name", "RandomKeywordField",
"--type", "keyword-list",
)
s.NoError(res.Err)

res = s.Execute(
"operator", "search-attribute", "create",
"--address", s.Address(),
"--name", "OtherRandomKeywordField",
"--type", "keywordlist",
)
s.NoError(res.Err)
}
43 changes: 39 additions & 4 deletions temporalcli/commands.schedule.go
Original file line number Diff line number Diff line change
Expand Up @@ -156,7 +156,11 @@ func (c *TemporalScheduleBackfillCommand) run(cctx *CommandContext, args []strin
defer cl.Close()
sch := cl.ScheduleClient().GetHandle(cctx, c.ScheduleId)

overlap, err := enumspb.ScheduleOverlapPolicyFromString(c.OverlapPolicy.Value)
overlapPolicy, err := mapLegacyOverlapPolicy(c.OverlapPolicy.Value)
if err != nil {
return err
}
overlap, err := enumspb.ScheduleOverlapPolicyFromString(overlapPolicy)
if err != nil {
return err
}
Expand Down Expand Up @@ -296,11 +300,15 @@ func (c *TemporalScheduleCreateCommand) run(cctx *CommandContext, args []string)
// ScheduleBackfill not supported
}

overlapPolicy, err := mapLegacyOverlapPolicy(c.OverlapPolicy.Value)
if err != nil {
return err
}
if err = c.toScheduleSpec(&opts.Spec); err != nil {
return err
} else if opts.Action, err = toScheduleAction(&c.SharedWorkflowStartOptions, &c.PayloadInputOptions); err != nil {
return err
} else if opts.Overlap, err = enumspb.ScheduleOverlapPolicyFromString(c.OverlapPolicy.Value); err != nil {
} else if opts.Overlap, err = enumspb.ScheduleOverlapPolicyFromString(overlapPolicy); err != nil {
return err
} else if opts.Memo, err = stringKeysJSONValues(c.ScheduleMemo, false); err != nil {
return fmt.Errorf("invalid memo values: %w", err)
Expand Down Expand Up @@ -496,7 +504,11 @@ func (c *TemporalScheduleTriggerCommand) run(cctx *CommandContext, args []string
defer cl.Close()
sch := cl.ScheduleClient().GetHandle(cctx, c.ScheduleId)

overlap, err := enumspb.ScheduleOverlapPolicyFromString(c.OverlapPolicy.Value)
overlapPolicy, err := mapLegacyOverlapPolicy(c.OverlapPolicy.Value)
if err != nil {
return err
}
overlap, err := enumspb.ScheduleOverlapPolicyFromString(overlapPolicy)
if err != nil {
return err
}
Expand Down Expand Up @@ -530,7 +542,11 @@ func (c *TemporalScheduleUpdateCommand) run(cctx *CommandContext, args []string)
},
}

if newSchedule.Policy.Overlap, err = enumspb.ScheduleOverlapPolicyFromString(c.OverlapPolicy.Value); err != nil {
overlapPolicy, err := mapLegacyOverlapPolicy(c.OverlapPolicy.Value)
if err != nil {
return err
}
if newSchedule.Policy.Overlap, err = enumspb.ScheduleOverlapPolicyFromString(overlapPolicy); err != nil {
return err
}

Expand Down Expand Up @@ -622,3 +638,22 @@ func encodeSearchAttributesToPayloads(in map[string]any) (map[string]*commonpb.P
}
return out, nil
}

func mapLegacyOverlapPolicy(in string) (string, error) {
switch strings.ToLower(in) {
case "skip":
return "Skip", nil
case "buffer-one", "bufferone":
return "BufferOne", nil
case "buffer-all", "bufferall":
return "BufferAll", nil
case "cancel-other", "cancelother":
return "CancelOther", nil
case "terminate-other", "terminateother":
return "TerminateOther", nil
case "allow-all", "allowall":
return "AllowAll", nil
default:
return "", fmt.Errorf("invalid overlap policy: %q", in)
}
}
27 changes: 27 additions & 0 deletions temporalcli/commands.schedule_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -439,6 +439,33 @@ func (s *SharedServerSuite) TestSchedule_Backfill() {
}, 10*time.Second, 100*time.Millisecond)
}

func (s *SharedServerSuite) TestSchedule_Backfill_New_OverlapPolicy() {
schedId, schedWfId, res := s.createSchedule("--interval", "10d/5h")
s.NoError(res.Err)

res = s.Execute(
"schedule", "backfill",
"--address", s.Address(),
"-s", schedId,
"--start-time", "2022-02-02T00:00:00Z",
"--end-time", "2022-02-28T00:00:00Z",
"--overlap-policy", "allow-all",
)
s.NoError(res.Err)

s.Eventually(func() bool {
res = s.Execute(
"workflow", "list",
"--address", s.Address(),
"-q", fmt.Sprintf(`TemporalScheduledById = "%s"`, schedId),
)
s.NoError(res.Err)
out := res.Stdout.String()
re := regexp.MustCompile(regexp.QuoteMeta(schedWfId + "-2022-02"))
return len(re.FindAllString(out, -1)) == 3
}, 10*time.Second, 100*time.Millisecond)
}

func (s *SharedServerSuite) TestSchedule_Update() {
schedId, schedWfId, res := s.createSchedule("--interval", "10d")
s.NoError(res.Err)
Expand Down
32 changes: 30 additions & 2 deletions temporalcli/commands.workflow_exec.go
Original file line number Diff line number Diff line change
Expand Up @@ -276,17 +276,19 @@ func buildStartOptions(sw *SharedWorkflowStartOptions, w *WorkflowStartOptions)
StartDelay: w.StartDelay.Duration(),
}
if w.IdReusePolicy.Value != "" {
idReusePolicy := convertReusePolicy(w.IdReusePolicy.Value)
var err error
o.WorkflowIDReusePolicy, err = stringToProtoEnum[enums.WorkflowIdReusePolicy](
w.IdReusePolicy.Value, enums.WorkflowIdReusePolicy_shorthandValue, enums.WorkflowIdReusePolicy_value)
idReusePolicy, enums.WorkflowIdReusePolicy_shorthandValue, enums.WorkflowIdReusePolicy_value)
if err != nil {
return o, fmt.Errorf("invalid workflow ID reuse policy: %w", err)
}
}
if w.IdConflictPolicy.Value != "" {
idConflictPolicy := convertConflictPolicy(w.IdConflictPolicy.Value)
var err error
o.WorkflowIDConflictPolicy, err = stringToProtoEnum[enums.WorkflowIdConflictPolicy](
w.IdConflictPolicy.Value, enums.WorkflowIdConflictPolicy_shorthandValue, enums.WorkflowIdConflictPolicy_value)
idConflictPolicy, enums.WorkflowIdConflictPolicy_shorthandValue, enums.WorkflowIdConflictPolicy_value)
if err != nil {
return o, fmt.Errorf("invalid workflow ID conflict policy: %w", err)
}
Expand Down Expand Up @@ -588,3 +590,29 @@ func isWorkflowTerminatingEvent(t enums.EventType) bool {
}
return false
}

func convertReusePolicy(s string) string {
switch strings.ToLower(s) {
case "allow-duplicate":
return "AllowDuplicate"
case "allow-duplicate-failed-only":
return "AllowDuplicateFailedOnly"
case "reject-duplicate":
return "RejectDuplicate"
case "terminate-if-running":
return "TerminateIfRunning"
}
return s
}

func convertConflictPolicy(s string) string {
switch strings.ToLower(s) {
case "fail":
return "Fail"
case "use-existing":
return "UseExisting"
case "terminate-existing":
return "TerminateExisting"
}
return s
}
19 changes: 10 additions & 9 deletions temporalcli/commands.workflow_reset.go
Original file line number Diff line number Diff line change
Expand Up @@ -96,7 +96,7 @@ func (c *TemporalWorkflowResetCommand) doWorkflowReset(cctx *CommandContext, cl
}

reapplyType := enums.RESET_REAPPLY_TYPE_ALL_ELIGIBLE
if c.ReapplyType.Value != "All" {
if strings.ToLower(c.ReapplyType.Value) != "all" {
if len(c.ReapplyExclude.Values) > 0 {
return errors.New("--reapply-type cannot be used with --reapply-exclude. Use --reapply-exclude.")
}
Expand Down Expand Up @@ -161,16 +161,17 @@ func (c *TemporalWorkflowResetCommand) runBatchReset(cctx *CommandContext, cl cl
}

func (c *TemporalWorkflowResetCommand) batchResetOptions(resetType string) *common.ResetOptions {
switch resetType {
case "FirstWorkflowTask":

switch strings.ToLower(resetType) {
case "firstworkflowtask", "first-workflow-task":
return &common.ResetOptions{
Target: &common.ResetOptions_FirstWorkflowTask{},
}
case "LastWorkflowTask":
case "lastworkflowtask", "last-workflow-task":
return &common.ResetOptions{
Target: &common.ResetOptions_LastWorkflowTask{},
}
case "BuildId":
case "buildid", "build-id":
return &common.ResetOptions{
Target: &common.ResetOptions_BuildId{
BuildId: c.BuildId,
Expand All @@ -184,12 +185,12 @@ func (c *TemporalWorkflowResetCommand) batchResetOptions(resetType string) *comm
func (c *TemporalWorkflowResetCommand) getResetEventIDByType(ctx context.Context, cl client.Client) (string, int64, error) {
resetType, namespace, wid, rid := c.Type.Value, c.Parent.Namespace, c.WorkflowId, c.RunId
wfsvc := cl.WorkflowService()
switch resetType {
case "LastWorkflowTask":
switch strings.ToLower(resetType) {
case "lastworkflowtask", "last-workflow-task":
return getLastWorkflowTaskEventID(ctx, namespace, wid, rid, wfsvc)
case "LastContinuedAsNew":
case "lastcontinuedasnew", "last-continued-as-new":
return getLastContinueAsNewID(ctx, namespace, wid, rid, wfsvc)
case "FirstWorkflowTask":
case "firstworkflowtask", "first-workflow-task":
return getFirstWorkflowTaskEventID(ctx, namespace, wid, rid, wfsvc)
default:
return "", -1, fmt.Errorf("invalid reset type: %s", resetType)
Expand Down
42 changes: 42 additions & 0 deletions temporalcli/commands.workflow_reset_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,48 @@ func (s *SharedServerSuite) TestWorkflow_Reset_ToFirstWorkflowTask() {
s.Greater(activityExecutions, 1, "Should have re-executed the workflow from the beginning")
}

func (s *SharedServerSuite) TestWorkflow_Reset_ToFirstWorkflowTask_New_Type() {
var wfExecutions, activityExecutions int
s.Worker().OnDevActivity(func(ctx context.Context, a any) (any, error) {
activityExecutions++
return nil, nil
})
s.Worker().OnDevWorkflow(func(ctx workflow.Context, a any) (any, error) {
workflow.ExecuteActivity(ctx, DevActivity, 1).Get(ctx, nil)
wfExecutions++
return nil, nil
})

// Start the workflow
searchAttr := "keyword-" + uuid.NewString()
run, err := s.Client.ExecuteWorkflow(
s.Context,
client.StartWorkflowOptions{
TaskQueue: s.Worker().Options.TaskQueue,
SearchAttributes: map[string]any{"CustomKeywordField": searchAttr},
},
DevWorkflow,
"ignored",
)
s.NoError(err)
var junk any
s.NoError(run.Get(s.Context, &junk))
s.Equal(1, wfExecutions)

// Reset to the first workflow task
res := s.Execute(
"workflow", "reset",
"--address", s.Address(),
"-w", run.GetID(),
"-t", "first-workflow-task",
"--reason", "test-reset-FirstWorkflowTask",
)
require.NoError(s.T(), res.Err)
s.awaitNextWorkflow(searchAttr)
s.Equal(2, wfExecutions, "Should have re-executed the workflow from the beginning")
s.Greater(activityExecutions, 1, "Should have re-executed the workflow from the beginning")
}

func (s *SharedServerSuite) TestWorkflow_Reset_ToLastWorkflowTask() {
var wfExecutions, activityExecutions int
s.Worker().OnDevActivity(func(ctx context.Context, a any) (any, error) {
Expand Down
8 changes: 5 additions & 3 deletions temporalcli/commandsgen/commands.yml
Original file line number Diff line number Diff line change
Expand Up @@ -1049,8 +1049,8 @@ commands:
--type Keyword
```
Supported types include: Text, Keyword, Int, Double, Bool, Datetime, and
KeywordList.
Supported types include: text, keyword, int, double, bool, datetime, and
keyword-list.
If you wish to delete a Search Attribute, please contact support
at https://support.temporal.io.
Expand Down Expand Up @@ -1081,6 +1081,8 @@ commands:
- bool
- datetime
- keyword-list
hidden-legacy-values:
- KeywordList
required: true

- name: temporal operator search-attribute list
Expand Down Expand Up @@ -1534,7 +1536,7 @@ commands:
Search attributes to register using `KEY=VALUE` pairs.
Keys must be identifiers, and values must be the search
attribute type, which is one of the following:
Text, Keyword, Int, Double, Bool, Datetime, KeywordList.
text, keyword, int, double, bool, datetime, keyword-list.
- name: temporal task-queue
summary: Manage Task Queues
Expand Down

0 comments on commit 64b9aa6

Please sign in to comment.