Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions definitions.go
Original file line number Diff line number Diff line change
Expand Up @@ -1185,6 +1185,13 @@ var runTaskDefinition = &jsonschema.Schema{
"The value should be validated against the target workflow's input schema, if specified.",
AdditionalProperties: trueSchema(),
},
propTaskQueue: {
Type: typeString,
Title: "SubflowTaskQueue",
MinLength: utils.Ptr(1),
Description: "The Temporal task queue to start the child workflow on. " +
"If not set, the child workflow runs on the parent workflow's task queue.",
},
propType: {
Type: typeString,
Title: "SubflowType",
Expand Down
23 changes: 23 additions & 0 deletions definitions_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -265,6 +265,29 @@ func TestRunTaskDefinitionVariants(t *testing.T) {
}
}

func TestRunWorkflowTaskQueueProperty(t *testing.T) {
var workflow *jsonschema.Schema
for _, variant := range runTaskDefinition.AllOf[1].Properties["run"].OneOf {
if variant.Title != "RunWorkflow" {
continue
}
workflow = variant.Properties["workflow"]
break
}

require.NotNil(t, workflow, "RunWorkflow should define a workflow property")
require.Contains(t, workflow.Properties, propTaskQueue)
taskQueue := workflow.Properties[propTaskQueue]
require.NotNil(t, taskQueue)

assert.Equal(t, typeString, taskQueue.Type)
assert.Equal(t, "SubflowTaskQueue", taskQueue.Title)
require.NotNil(t, taskQueue.MinLength)
assert.Equal(t, 1, *taskQueue.MinLength)
assert.Empty(t, taskQueue.Pattern)
assert.Equal(t, []string{propType}, workflow.Required)
}

// TestSchemaDefinitionInlineOnly verifies that schemaDefinition supports only
// the inline document form and not the external resource form.
func TestSchemaDefinitionInlineOnly(t *testing.T) {
Expand Down
6 changes: 6 additions & 0 deletions schema.json
Original file line number Diff line number Diff line change
Expand Up @@ -1343,6 +1343,12 @@
"description": "The data, if any, to pass as input to the workflow to execute. The value should be validated against the target workflow's input schema, if specified.",
"additionalProperties": true
},
"taskQueue": {
"type": "string",
"title": "SubflowTaskQueue",
"description": "The Temporal task queue to start the child workflow on. If not set, the child workflow runs on the parent workflow's task queue.",
"minLength": 1
},
"type": {
"type": "string",
"title": "SubflowType",
Expand Down
7 changes: 7 additions & 0 deletions schema.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -903,6 +903,13 @@ $defs:
workflow's input schema, if specified.
title: SubflowInput
type: object
taskQueue:
description: The Temporal task queue to start the child workflow
on. If not set, the child workflow runs on the parent workflow's
task queue.
minLength: 1
title: SubflowTaskQueue
type: string
type:
description: The workflow type to run.
title: SubflowType
Expand Down
103 changes: 103 additions & 0 deletions schema_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,20 @@ func minimalWorkflow() map[string]any {
}
}

func runWorkflowDoc(workflow map[string]any) map[string]any {
doc := minimalWorkflow()
doc[propDo] = []any{
map[string]any{
"callChild": map[string]any{
"run": map[string]any{
"workflow": workflow,
},
},
},
}
return doc
}

// TestSchema_DocumentFields verifies that the document schema accepts the
// Zigflow-aligned field names and rejects the old Serverless Workflow names.
func TestSchema_DocumentFields(t *testing.T) {
Expand Down Expand Up @@ -139,3 +153,92 @@ func TestSchema_RejectsUnknownTopLevelProperties(t *testing.T) {
assert.NoError(t, err, "document with only known top-level properties should pass validation")
})
}

func TestSchema_RunWorkflowTaskQueue(t *testing.T) {
resolved := resolvedTestSchema(t)
tests := []struct {
name string
workflow map[string]any
awaitFalse bool
wantError bool
}{
{
name: "without taskQueue is accepted",
workflow: map[string]any{propType: testWorkflowType},
},
{
name: "with taskQueue is accepted",
workflow: map[string]any{propType: testWorkflowType, propTaskQueue: "other-queue"},
},
{
name: "orders.v2 is accepted",
workflow: map[string]any{propType: testWorkflowType, propTaskQueue: "orders.v2"},
},
{
name: "test_workflow is accepted",
workflow: map[string]any{propType: testWorkflowType, propTaskQueue: "test_workflow"},
},
{
name: "single-character name is accepted",
workflow: map[string]any{propType: testWorkflowType, propTaskQueue: "a"},
},
{
name: "taskQueue with input and await false is accepted",
workflow: map[string]any{
propType: testWorkflowType,
propTaskQueue: "other-queue",
propInput: map[string]any{"a": 1},
},
awaitFalse: true,
},
{
name: "empty taskQueue is rejected",
workflow: map[string]any{
propType: testWorkflowType,
propTaskQueue: "",
},
wantError: true,
},
{
name: "integer taskQueue is rejected",
workflow: map[string]any{
propType: testWorkflowType,
propTaskQueue: 123,
},
wantError: true,
},
{
name: "object taskQueue is rejected",
workflow: map[string]any{
propType: testWorkflowType,
propTaskQueue: map[string]any{},
},
wantError: true,
},
{
name: "unknown sibling property is rejected",
workflow: map[string]any{
propType: testWorkflowType,
"queue": "x",
},
wantError: true,
},
}

for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
doc := runWorkflowDoc(tt.workflow)
if tt.awaitFalse {
task := doc[propDo].([]any)[0].(map[string]any)["callChild"].(map[string]any)
task["run"].(map[string]any)["await"] = false
}

err := resolved.Validate(doc)
if tt.wantError {
assert.Error(t, err)
} else {
assert.NoError(t, err)
}
})
}
}
Loading