fixed apiconfig
This commit is contained in:
@@ -11,14 +11,18 @@ const (
|
||||
|
||||
type APIConfig struct {
|
||||
ID string `json:"id" yaml:"id"`
|
||||
ListenPath string `json:"listenPath" yaml:"listenPath"`
|
||||
Method string `json:"method" yaml:"method"`
|
||||
Request RequestConfig `json:"request" yaml:"request"`
|
||||
Actions map[string]Action `json:"actions" yaml:"actions"`
|
||||
Conditionals map[string]Conditional `json:"conditionals" yaml:"conditionals"`
|
||||
Responses map[string]ResponseConfig `json:"responses" yaml:"responses"`
|
||||
HttpConfig HttpConfig `json:"http" yaml:"http"`
|
||||
McpTool MCPToolConfig `json:"mcpTool" yaml:"mcpTool"`
|
||||
|
||||
// Deprecated: use HttpConfig.Listenpath
|
||||
ListenPath string `json:"listenPath" yaml:"listenPath"`
|
||||
// Deprecated: use HttpConfig.Method
|
||||
Method string `json:"method" yaml:"method"`
|
||||
// Deprecated: use HttpConfig
|
||||
Request RequestConfig `json:"request" yaml:"request"`
|
||||
}
|
||||
|
||||
type HttpConfig struct {
|
||||
@@ -33,6 +37,7 @@ type McpConfig struct {
|
||||
}
|
||||
|
||||
type MCPToolConfig struct {
|
||||
Enabled bool `json:"enabled" yaml:"enabled"`
|
||||
Name string `json:"name" yaml:"name"`
|
||||
Description string `json:"description" yaml:"description"`
|
||||
Args map[string]ArgType `json:"args" yaml:"args"`
|
||||
|
||||
@@ -0,0 +1,92 @@
|
||||
package apiconfig
|
||||
|
||||
import "git.servflow.io/servflow/definitions/proto"
|
||||
|
||||
func ProtoConfigToAPIConfig(configs []*proto.WorkflowConfig) []*APIConfig {
|
||||
cfgs := make([]*APIConfig, 0)
|
||||
for i := range configs {
|
||||
protoConfig := configs[i]
|
||||
if protoConfig == nil || protoConfig.Id == "" || protoConfig.Status == proto.Status_INACTIVE {
|
||||
continue
|
||||
}
|
||||
a := APIConfig{
|
||||
ID: protoConfig.Id,
|
||||
ListenPath: protoConfig.ListenPath,
|
||||
Method: protoConfig.Method,
|
||||
Request: RequestConfig{
|
||||
Next: protoConfig.Request.Next,
|
||||
},
|
||||
Actions: map[string]Action{},
|
||||
Conditionals: map[string]Conditional{},
|
||||
Responses: map[string]ResponseConfig{},
|
||||
McpTool: MCPToolConfig{
|
||||
Enabled: protoConfig.Mcp.Enabled,
|
||||
Name: protoConfig.Mcp.Name,
|
||||
Result: protoConfig.Mcp.Result,
|
||||
Description: protoConfig.Mcp.Description,
|
||||
Start: protoConfig.Mcp.Start,
|
||||
Args: make(map[string]ArgType),
|
||||
},
|
||||
HttpConfig: HttpConfig{
|
||||
Next: protoConfig.Request.Next,
|
||||
ListenPath: protoConfig.Request.ListenPath,
|
||||
Method: protoConfig.Request.Method,
|
||||
},
|
||||
}
|
||||
|
||||
for k := range protoConfig.Mcp.Args {
|
||||
a.McpTool.Args[k] = ArgType{
|
||||
Name: protoConfig.Mcp.Args[k].Name,
|
||||
Type: protoConfig.Mcp.Args[k].Type,
|
||||
}
|
||||
}
|
||||
|
||||
for key := range protoConfig.Actions {
|
||||
act := protoConfig.Actions[key]
|
||||
a.Actions[key] = Action{
|
||||
Type: act.Type,
|
||||
Config: act.Config,
|
||||
Next: act.Next,
|
||||
Fail: act.Fail,
|
||||
}
|
||||
}
|
||||
|
||||
for key := range protoConfig.Conditionals {
|
||||
cond := protoConfig.Conditionals[key]
|
||||
a.Conditionals[key] = Conditional{
|
||||
ValidPath: cond.ValidPath,
|
||||
InvalidPath: cond.InvalidPath,
|
||||
Expression: cond.Expression,
|
||||
}
|
||||
}
|
||||
|
||||
for key := range protoConfig.Responses {
|
||||
resp := protoConfig.Responses[key]
|
||||
a.Responses[key] = ResponseConfig{
|
||||
Code: int(resp.GetCode()),
|
||||
Type: resp.Type,
|
||||
Template: string(resp.Template),
|
||||
}
|
||||
}
|
||||
|
||||
a.Normalize()
|
||||
cfgs = append(cfgs, &a)
|
||||
}
|
||||
|
||||
return cfgs
|
||||
}
|
||||
|
||||
func (a *APIConfig) Normalize() {
|
||||
if a.HttpConfig.Method == "" {
|
||||
a.HttpConfig.Method = a.Method
|
||||
}
|
||||
if a.HttpConfig.Next == "" {
|
||||
a.HttpConfig.Next = a.Request.Next
|
||||
}
|
||||
if a.HttpConfig.ListenPath == "" {
|
||||
a.HttpConfig.ListenPath = a.ListenPath
|
||||
}
|
||||
if len(a.HttpConfig.CORSAllowedOrigins) < 1 {
|
||||
a.HttpConfig.CORSAllowedOrigins = a.Request.CORSAllowedOrigins
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,169 @@
|
||||
package apiconfig
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"git.servflow.io/servflow/definitions/proto"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestProtoConfigToAPIConfig(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
input []*proto.WorkflowConfig
|
||||
validate func(t *testing.T, result []*APIConfig)
|
||||
}{
|
||||
{
|
||||
name: "empty input slice",
|
||||
input: []*proto.WorkflowConfig{},
|
||||
validate: func(t *testing.T, result []*APIConfig) {
|
||||
assert.Empty(t, result)
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "nil config should be skipped",
|
||||
input: []*proto.WorkflowConfig{
|
||||
nil,
|
||||
},
|
||||
validate: func(t *testing.T, result []*APIConfig) {
|
||||
assert.Empty(t, result)
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "inactive config should be skipped",
|
||||
input: []*proto.WorkflowConfig{
|
||||
{
|
||||
Id: "test-id",
|
||||
Status: proto.Status_INACTIVE,
|
||||
},
|
||||
},
|
||||
validate: func(t *testing.T, result []*APIConfig) {
|
||||
assert.Empty(t, result)
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "empty ID should be skipped",
|
||||
input: []*proto.WorkflowConfig{
|
||||
{
|
||||
Status: proto.Status_ACTIVE,
|
||||
},
|
||||
},
|
||||
validate: func(t *testing.T, result []*APIConfig) {
|
||||
assert.Empty(t, result)
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "valid config should be converted",
|
||||
input: []*proto.WorkflowConfig{
|
||||
{
|
||||
Id: "test-id",
|
||||
Status: proto.Status_ACTIVE,
|
||||
ListenPath: "/test",
|
||||
Method: "POST",
|
||||
Request: &proto.Request{
|
||||
Next: "next-action",
|
||||
ListenPath: "/test",
|
||||
Method: "GET",
|
||||
},
|
||||
Actions: map[string]*proto.Action{
|
||||
"action1": {
|
||||
Type: "http",
|
||||
Config: json.RawMessage(`{"url": "http://example.com"}`),
|
||||
Next: "action2",
|
||||
Fail: "error",
|
||||
},
|
||||
},
|
||||
Mcp: &proto.MCPConfig{
|
||||
Enabled: true,
|
||||
Name: "test-tool",
|
||||
Args: map[string]*proto.MCPArgConfig{
|
||||
"arg1": {
|
||||
Name: "arg1",
|
||||
Type: "string",
|
||||
},
|
||||
},
|
||||
Description: "test description",
|
||||
Start: "start",
|
||||
Result: "result",
|
||||
},
|
||||
Conditionals: map[string]*proto.Conditional{
|
||||
"cond1": {
|
||||
ValidPath: "valid",
|
||||
InvalidPath: "invalid",
|
||||
Expression: "response.code == 200",
|
||||
},
|
||||
},
|
||||
Responses: map[string]*proto.Response{
|
||||
"success": {
|
||||
Code: 200,
|
||||
Type: "json",
|
||||
Template: []byte(`{"status": "ok"}`),
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
validate: func(t *testing.T, result []*APIConfig) {
|
||||
require.Len(t, result, 1)
|
||||
cfg := result[0]
|
||||
|
||||
// Verify basic fields
|
||||
assert.Equal(t, "test-id", cfg.ID)
|
||||
assert.Equal(t, "/test", cfg.ListenPath)
|
||||
assert.Equal(t, "POST", cfg.Method)
|
||||
|
||||
// Verify request config
|
||||
assert.Equal(t, "next-action", cfg.Request.Next)
|
||||
|
||||
// Verify actions
|
||||
require.Contains(t, cfg.Actions, "action1")
|
||||
action := cfg.Actions["action1"]
|
||||
assert.Equal(t, "http", action.Type)
|
||||
assert.JSONEq(t, `{"url": "http://example.com"}`, string(action.Config))
|
||||
assert.Equal(t, "action2", action.Next)
|
||||
assert.Equal(t, "error", action.Fail)
|
||||
|
||||
// Verify conditionals
|
||||
require.Contains(t, cfg.Conditionals, "cond1")
|
||||
cond := cfg.Conditionals["cond1"]
|
||||
assert.Equal(t, "valid", cond.ValidPath)
|
||||
assert.Equal(t, "invalid", cond.InvalidPath)
|
||||
assert.Equal(t, "response.code == 200", cond.Expression)
|
||||
|
||||
// Verify responses
|
||||
require.Contains(t, cfg.Responses, "success")
|
||||
resp := cfg.Responses["success"]
|
||||
assert.Equal(t, 200, resp.Code)
|
||||
assert.Equal(t, "json", resp.Type)
|
||||
assert.Equal(t, `{"status": "ok"}`, resp.Template)
|
||||
|
||||
assert.Equal(t, MCPToolConfig{
|
||||
Enabled: true,
|
||||
Name: "test-tool",
|
||||
Args: map[string]ArgType{
|
||||
"arg1": {
|
||||
Name: "arg1",
|
||||
Type: "string",
|
||||
},
|
||||
},
|
||||
Description: "test description",
|
||||
Start: "start",
|
||||
Result: "result",
|
||||
}, cfg.McpTool)
|
||||
|
||||
assert.Equal(t, HttpConfig{
|
||||
Next: "next-action",
|
||||
ListenPath: "/test",
|
||||
Method: "GET",
|
||||
}, cfg.HttpConfig)
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
result := ProtoConfigToAPIConfig(tt.input)
|
||||
tt.validate(t, result)
|
||||
})
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user