Publish Claude Code Binaries / Stage and publish binaries (push) Canceled after 0s
Publish Tutti App Runtime / Build darwin-arm64 (push) Canceled after 0s
Publish Tutti App Runtime / Build darwin-amd64 (push) Canceled after 0s
Publish Tutti App Runtime / Build linux-amd64 (push) Canceled after 0s
Publish Tutti App Runtime / Build windows-amd64 (push) Canceled after 0s
Sync Tutti Agent Skills / sync (push) Canceled after 0s
Windows Agent Adapters / Test Windows agent adapters (push) Canceled after 0s
Windows Daemon Adapters / Test Windows daemon adapters (push) Canceled after 0s
Publish Tutti App Runtime / Publish runtime catalog (push) Canceled after 0s
205 lines
6.7 KiB
Go
205 lines
6.7 KiB
Go
package core
|
|
|
|
import (
|
|
"strings"
|
|
"testing"
|
|
)
|
|
|
|
func TestValidateManifestRejectsReservedHandlerPath(t *testing.T) {
|
|
err := ValidateManifest(Manifest{
|
|
SchemaVersion: ManifestSchemaVersion,
|
|
Scope: "automation",
|
|
Commands: []ManifestCommand{{
|
|
Path: []string{"run"},
|
|
Summary: "Run automation",
|
|
Output: ManifestCommandOutput{DefaultMode: OutputModeJSON, JSON: true},
|
|
Handler: ManifestCommandHandler{Kind: "http", Method: "POST", Path: "/run"},
|
|
}},
|
|
})
|
|
if err == nil {
|
|
t.Fatal("ValidateManifest() error = nil, want handler path error")
|
|
}
|
|
}
|
|
|
|
func TestValidateManifestRejectsUnknownVisibility(t *testing.T) {
|
|
err := ValidateManifest(Manifest{
|
|
SchemaVersion: ManifestSchemaVersion,
|
|
Scope: "automation",
|
|
Commands: []ManifestCommand{{
|
|
Path: []string{"run"},
|
|
Summary: "Run automation",
|
|
Visibility: "private",
|
|
Output: ManifestCommandOutput{DefaultMode: OutputModeJSON, JSON: true},
|
|
Handler: ManifestCommandHandler{Kind: "http", Method: "POST", Path: "/tutti/cli/run"},
|
|
}},
|
|
})
|
|
if err == nil {
|
|
t.Fatal("ValidateManifest() error = nil, want visibility error")
|
|
}
|
|
}
|
|
|
|
func TestValidateManifestAcceptsEnumAndDefaultInputAnnotations(t *testing.T) {
|
|
err := ValidateManifest(Manifest{
|
|
SchemaVersion: ManifestSchemaVersion,
|
|
Scope: "automation",
|
|
Commands: []ManifestCommand{{
|
|
Path: []string{"create"},
|
|
Summary: "Create automation",
|
|
InputSchema: map[string]any{
|
|
"type": "object",
|
|
"properties": map[string]any{
|
|
"schedule-type": map[string]any{
|
|
"type": "string",
|
|
"description": "Schedule type.",
|
|
"enum": []any{"manual", "interval", "daily", "weekly", "cron"},
|
|
"default": "manual",
|
|
},
|
|
"enabled": map[string]any{
|
|
"type": "boolean",
|
|
"default": true,
|
|
},
|
|
"interval-minutes": map[string]any{
|
|
"type": "integer",
|
|
"default": 60,
|
|
},
|
|
},
|
|
},
|
|
Output: ManifestCommandOutput{DefaultMode: OutputModeJSON, JSON: true},
|
|
Handler: ManifestCommandHandler{Kind: "http", Method: "POST", Path: "/tutti/cli/create"},
|
|
}},
|
|
})
|
|
if err != nil {
|
|
t.Fatalf("ValidateManifest() error = %v", err)
|
|
}
|
|
}
|
|
|
|
func TestValidateManifestRejectsEnumValuesWithWrongType(t *testing.T) {
|
|
err := ValidateManifest(Manifest{
|
|
SchemaVersion: ManifestSchemaVersion,
|
|
Scope: "automation",
|
|
Commands: []ManifestCommand{{
|
|
Path: []string{"create"},
|
|
Summary: "Create automation",
|
|
InputSchema: map[string]any{
|
|
"type": "object",
|
|
"properties": map[string]any{
|
|
"schedule-type": map[string]any{
|
|
"type": "string",
|
|
"enum": []any{"manual", 1},
|
|
},
|
|
},
|
|
},
|
|
Output: ManifestCommandOutput{DefaultMode: OutputModeJSON, JSON: true},
|
|
Handler: ManifestCommandHandler{Kind: "http", Method: "POST", Path: "/tutti/cli/create"},
|
|
}},
|
|
})
|
|
if err == nil {
|
|
t.Fatal("ValidateManifest() error = nil, want enum type error")
|
|
}
|
|
}
|
|
|
|
func TestBuildCommandsBuildsAppCapability(t *testing.T) {
|
|
manifest := Manifest{
|
|
SchemaVersion: ManifestSchemaVersion,
|
|
Scope: "automation",
|
|
Description: "Automation commands",
|
|
Commands: []ManifestCommand{{
|
|
Path: []string{"run"},
|
|
Summary: "Run automation",
|
|
Description: "Runs a job",
|
|
Visibility: CommandVisibilityIntegration,
|
|
InputSchema: map[string]any{"type": "object", "properties": map[string]any{"name": map[string]any{"type": "string"}}},
|
|
Output: ManifestCommandOutput{DefaultMode: OutputModeJSON, JSON: true},
|
|
Handler: ManifestCommandHandler{Kind: "http", Method: "POST", Path: "/tutti/cli/run"},
|
|
}},
|
|
}
|
|
|
|
commands := BuildCommands(manifest, CommandBuildOptions{
|
|
AppID: "automation-app",
|
|
AppName: "Automation",
|
|
IconURL: "data:image/png;base64,abc",
|
|
AppDescription: "Test app",
|
|
DocumentationFile: "COMMANDS.md",
|
|
DocumentationPath: "/tmp/COMMANDS.md",
|
|
})
|
|
|
|
if len(commands) != 1 {
|
|
t.Fatalf("commands = %#v", commands)
|
|
}
|
|
capability := commands[0].Capability
|
|
if capability.ID != "app.automation-app.automation.run" || capability.Path[0] != "automation" {
|
|
t.Fatalf("capability = %#v", capability)
|
|
}
|
|
if capability.Source.AppID != "automation-app" || capability.Source.CLIDescription != "Automation commands" {
|
|
t.Fatalf("capability source = %#v", capability.Source)
|
|
}
|
|
if capability.Visibility != CommandVisibilityIntegration {
|
|
t.Fatalf("capability visibility = %q", capability.Visibility)
|
|
}
|
|
}
|
|
|
|
func TestBuildCommandsDefaultsVisibilityToPublic(t *testing.T) {
|
|
commands := BuildCommands(Manifest{
|
|
SchemaVersion: ManifestSchemaVersion,
|
|
Scope: "automation",
|
|
Commands: []ManifestCommand{{
|
|
Path: []string{"run"},
|
|
Summary: "Run automation",
|
|
Output: ManifestCommandOutput{DefaultMode: OutputModeJSON, JSON: true},
|
|
Handler: ManifestCommandHandler{Kind: "http", Method: "POST", Path: "/tutti/cli/run"},
|
|
}},
|
|
}, CommandBuildOptions{AppID: "automation-app"})
|
|
|
|
if len(commands) != 1 || commands[0].Capability.Visibility != CommandVisibilityPublic {
|
|
t.Fatalf("commands = %#v", commands)
|
|
}
|
|
}
|
|
|
|
func TestValidateManifestAcceptsWaitExecutionAndBuildsCapabilityMetadata(t *testing.T) {
|
|
manifest := Manifest{
|
|
SchemaVersion: ManifestSchemaVersion,
|
|
Scope: "automation",
|
|
Commands: []ManifestCommand{{
|
|
Path: []string{"runs", "wait"},
|
|
Summary: "Wait for a run",
|
|
Execution: &ManifestCommandExecution{Mode: CommandExecutionModeWait},
|
|
Output: ManifestCommandOutput{DefaultMode: OutputModeJSON, JSON: true},
|
|
Handler: ManifestCommandHandler{
|
|
Kind: "http", Method: "POST", Path: "/tutti/cli/runs/wait", TimeoutMs: 45000,
|
|
},
|
|
}},
|
|
}
|
|
if err := ValidateManifest(manifest); err != nil {
|
|
t.Fatalf("ValidateManifest() error = %v", err)
|
|
}
|
|
commands := BuildCommands(manifest, CommandBuildOptions{AppID: "automation-app"})
|
|
if len(commands) != 1 || commands[0].Capability.Execution == nil ||
|
|
commands[0].Capability.Execution.Mode != CommandExecutionModeWait ||
|
|
commands[0].Capability.HandlerTimeoutMs != 45000 {
|
|
t.Fatalf("commands = %#v", commands)
|
|
}
|
|
}
|
|
|
|
func TestValidateManifestRejectsWaitExecutionTimeoutInput(t *testing.T) {
|
|
err := ValidateManifest(Manifest{
|
|
SchemaVersion: ManifestSchemaVersion,
|
|
Scope: "automation",
|
|
Commands: []ManifestCommand{{
|
|
Path: []string{"runs", "wait"},
|
|
Summary: "Wait for a run",
|
|
Execution: &ManifestCommandExecution{Mode: CommandExecutionModeWait},
|
|
InputSchema: map[string]any{
|
|
"type": "object",
|
|
"properties": map[string]any{
|
|
"timeout-ms": map[string]any{"type": "integer"},
|
|
},
|
|
},
|
|
Output: ManifestCommandOutput{DefaultMode: OutputModeJSON, JSON: true},
|
|
Handler: ManifestCommandHandler{Kind: "http", Method: "POST", Path: "/tutti/cli/runs/wait"},
|
|
}},
|
|
})
|
|
if err == nil || !strings.Contains(err.Error(), "reserves --timeout-ms") {
|
|
t.Fatalf("ValidateManifest() error = %v", err)
|
|
}
|
|
}
|