refactor: how to add a node type in workflow (#558)
This commit is contained in:
@@ -20,8 +20,11 @@ import (
|
||||
"context"
|
||||
"fmt"
|
||||
|
||||
"github.com/coze-dev/coze-studio/backend/domain/workflow/entity"
|
||||
"github.com/coze-dev/coze-studio/backend/domain/workflow/entity/vo"
|
||||
"github.com/coze-dev/coze-studio/backend/domain/workflow/internal/canvas/convert"
|
||||
"github.com/coze-dev/coze-studio/backend/domain/workflow/internal/nodes"
|
||||
"github.com/coze-dev/coze-studio/backend/domain/workflow/internal/schema"
|
||||
"github.com/coze-dev/coze-studio/backend/pkg/ctxcache"
|
||||
"github.com/coze-dev/coze-studio/backend/pkg/errorx"
|
||||
"github.com/coze-dev/coze-studio/backend/pkg/sonic"
|
||||
@@ -34,32 +37,42 @@ const (
|
||||
warningsKey = "deserialization_warnings"
|
||||
)
|
||||
|
||||
type DeserializationConfig struct {
|
||||
OutputFields map[string]*vo.TypeInfo `json:"outputFields,omitempty"`
|
||||
type DeserializationConfig struct{}
|
||||
|
||||
func (d *DeserializationConfig) Adapt(_ context.Context, n *vo.Node, _ ...nodes.AdaptOption) (
|
||||
*schema.NodeSchema, error) {
|
||||
ns := &schema.NodeSchema{
|
||||
Key: vo.NodeKey(n.ID),
|
||||
Type: entity.NodeTypeJsonDeserialization,
|
||||
Name: n.Data.Meta.Title,
|
||||
Configs: d,
|
||||
}
|
||||
|
||||
if err := convert.SetInputsForNodeSchema(n, ns); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if err := convert.SetOutputTypesForNodeSchema(n, ns); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return ns, nil
|
||||
}
|
||||
|
||||
type Deserializer struct {
|
||||
config *DeserializationConfig
|
||||
typeInfo *vo.TypeInfo
|
||||
}
|
||||
|
||||
func NewJsonDeserializer(_ context.Context, cfg *DeserializationConfig) (*Deserializer, error) {
|
||||
if cfg == nil {
|
||||
return nil, fmt.Errorf("config required")
|
||||
}
|
||||
if cfg.OutputFields == nil {
|
||||
return nil, fmt.Errorf("OutputFields is required for deserialization")
|
||||
}
|
||||
typeInfo := cfg.OutputFields[OutputKeyDeserialization]
|
||||
if typeInfo == nil {
|
||||
func (d *DeserializationConfig) Build(_ context.Context, ns *schema.NodeSchema, _ ...schema.BuildOption) (any, error) {
|
||||
typeInfo, ok := ns.OutputTypes[OutputKeyDeserialization]
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("no output field specified in deserialization config")
|
||||
}
|
||||
return &Deserializer{
|
||||
config: cfg,
|
||||
typeInfo: typeInfo,
|
||||
}, nil
|
||||
}
|
||||
|
||||
type Deserializer struct {
|
||||
typeInfo *vo.TypeInfo
|
||||
}
|
||||
|
||||
func (jd *Deserializer) Invoke(ctx context.Context, input map[string]any) (map[string]any, error) {
|
||||
jsonStrValue := input[InputKeyDeserialization]
|
||||
|
||||
|
||||
@@ -24,6 +24,7 @@ import (
|
||||
|
||||
"github.com/coze-dev/coze-studio/backend/domain/workflow/entity/vo"
|
||||
"github.com/coze-dev/coze-studio/backend/domain/workflow/internal/nodes"
|
||||
"github.com/coze-dev/coze-studio/backend/domain/workflow/internal/schema"
|
||||
"github.com/coze-dev/coze-studio/backend/pkg/ctxcache"
|
||||
"github.com/coze-dev/coze-studio/backend/pkg/sonic"
|
||||
)
|
||||
@@ -31,19 +32,9 @@ import (
|
||||
func TestNewJsonDeserializer(t *testing.T) {
|
||||
ctx := context.Background()
|
||||
|
||||
// Test with nil config
|
||||
_, err := NewJsonDeserializer(ctx, nil)
|
||||
assert.Error(t, err)
|
||||
assert.Contains(t, err.Error(), "config required")
|
||||
|
||||
// Test with missing OutputFields config
|
||||
_, err = NewJsonDeserializer(ctx, &DeserializationConfig{})
|
||||
assert.Error(t, err)
|
||||
assert.Contains(t, err.Error(), "OutputFields is required")
|
||||
|
||||
// Test with missing output key in OutputFields
|
||||
_, err = NewJsonDeserializer(ctx, &DeserializationConfig{
|
||||
OutputFields: map[string]*vo.TypeInfo{
|
||||
_, err := (&DeserializationConfig{}).Build(ctx, &schema.NodeSchema{
|
||||
OutputTypes: map[string]*vo.TypeInfo{
|
||||
"testKey": {Type: vo.DataTypeString},
|
||||
},
|
||||
})
|
||||
@@ -51,12 +42,12 @@ func TestNewJsonDeserializer(t *testing.T) {
|
||||
assert.Contains(t, err.Error(), "no output field specified in deserialization config")
|
||||
|
||||
// Test with valid config
|
||||
validConfig := &DeserializationConfig{
|
||||
OutputFields: map[string]*vo.TypeInfo{
|
||||
validConfig := &schema.NodeSchema{
|
||||
OutputTypes: map[string]*vo.TypeInfo{
|
||||
OutputKeyDeserialization: {Type: vo.DataTypeString},
|
||||
},
|
||||
}
|
||||
processor, err := NewJsonDeserializer(ctx, validConfig)
|
||||
processor, err := (&DeserializationConfig{}).Build(ctx, validConfig)
|
||||
assert.NoError(t, err)
|
||||
assert.NotNil(t, processor)
|
||||
}
|
||||
@@ -65,16 +56,16 @@ func TestJsonDeserializer_Invoke(t *testing.T) {
|
||||
ctx := context.Background()
|
||||
|
||||
// Base type test config
|
||||
baseTypeConfig := &DeserializationConfig{
|
||||
OutputFields: map[string]*vo.TypeInfo{
|
||||
"output": {Type: vo.DataTypeString},
|
||||
baseTypeConfig := &schema.NodeSchema{
|
||||
OutputTypes: map[string]*vo.TypeInfo{
|
||||
OutputKeyDeserialization: {Type: vo.DataTypeString},
|
||||
},
|
||||
}
|
||||
|
||||
// Object type test config
|
||||
objectTypeConfig := &DeserializationConfig{
|
||||
OutputFields: map[string]*vo.TypeInfo{
|
||||
"output": {
|
||||
objectTypeConfig := &schema.NodeSchema{
|
||||
OutputTypes: map[string]*vo.TypeInfo{
|
||||
OutputKeyDeserialization: {
|
||||
Type: vo.DataTypeObject,
|
||||
Properties: map[string]*vo.TypeInfo{
|
||||
"name": {Type: vo.DataTypeString, Required: true},
|
||||
@@ -85,9 +76,9 @@ func TestJsonDeserializer_Invoke(t *testing.T) {
|
||||
}
|
||||
|
||||
// Array type test config
|
||||
arrayTypeConfig := &DeserializationConfig{
|
||||
OutputFields: map[string]*vo.TypeInfo{
|
||||
"output": {
|
||||
arrayTypeConfig := &schema.NodeSchema{
|
||||
OutputTypes: map[string]*vo.TypeInfo{
|
||||
OutputKeyDeserialization: {
|
||||
Type: vo.DataTypeArray,
|
||||
ElemTypeInfo: &vo.TypeInfo{Type: vo.DataTypeInteger},
|
||||
},
|
||||
@@ -95,9 +86,9 @@ func TestJsonDeserializer_Invoke(t *testing.T) {
|
||||
}
|
||||
|
||||
// Nested array object test config
|
||||
nestedArrayConfig := &DeserializationConfig{
|
||||
OutputFields: map[string]*vo.TypeInfo{
|
||||
"output": {
|
||||
nestedArrayConfig := &schema.NodeSchema{
|
||||
OutputTypes: map[string]*vo.TypeInfo{
|
||||
OutputKeyDeserialization: {
|
||||
Type: vo.DataTypeArray,
|
||||
ElemTypeInfo: &vo.TypeInfo{
|
||||
Type: vo.DataTypeObject,
|
||||
@@ -113,7 +104,7 @@ func TestJsonDeserializer_Invoke(t *testing.T) {
|
||||
// Test cases
|
||||
tests := []struct {
|
||||
name string
|
||||
config *DeserializationConfig
|
||||
config *schema.NodeSchema
|
||||
inputJSON string
|
||||
expectedOutput any
|
||||
expectErr bool
|
||||
@@ -127,9 +118,9 @@ func TestJsonDeserializer_Invoke(t *testing.T) {
|
||||
expectWarnings: 0,
|
||||
}, {
|
||||
name: "Test integer deserialization",
|
||||
config: &DeserializationConfig{
|
||||
OutputFields: map[string]*vo.TypeInfo{
|
||||
"output": {Type: vo.DataTypeInteger},
|
||||
config: &schema.NodeSchema{
|
||||
OutputTypes: map[string]*vo.TypeInfo{
|
||||
OutputKeyDeserialization: {Type: vo.DataTypeInteger},
|
||||
},
|
||||
},
|
||||
inputJSON: `123`,
|
||||
@@ -138,9 +129,9 @@ func TestJsonDeserializer_Invoke(t *testing.T) {
|
||||
expectWarnings: 0,
|
||||
}, {
|
||||
name: "Test boolean deserialization",
|
||||
config: &DeserializationConfig{
|
||||
OutputFields: map[string]*vo.TypeInfo{
|
||||
"output": {Type: vo.DataTypeBoolean},
|
||||
config: &schema.NodeSchema{
|
||||
OutputTypes: map[string]*vo.TypeInfo{
|
||||
OutputKeyDeserialization: {Type: vo.DataTypeBoolean},
|
||||
},
|
||||
},
|
||||
inputJSON: `true`,
|
||||
@@ -180,9 +171,9 @@ func TestJsonDeserializer_Invoke(t *testing.T) {
|
||||
expectWarnings: 0,
|
||||
}, {
|
||||
name: "Test type mismatch warning",
|
||||
config: &DeserializationConfig{
|
||||
OutputFields: map[string]*vo.TypeInfo{
|
||||
"output": {Type: vo.DataTypeInteger},
|
||||
config: &schema.NodeSchema{
|
||||
OutputTypes: map[string]*vo.TypeInfo{
|
||||
OutputKeyDeserialization: {Type: vo.DataTypeInteger},
|
||||
},
|
||||
},
|
||||
inputJSON: `"not a number"`,
|
||||
@@ -198,9 +189,9 @@ func TestJsonDeserializer_Invoke(t *testing.T) {
|
||||
expectWarnings: 0,
|
||||
}, {
|
||||
name: "Test string to integer conversion",
|
||||
config: &DeserializationConfig{
|
||||
OutputFields: map[string]*vo.TypeInfo{
|
||||
"output": {Type: vo.DataTypeInteger},
|
||||
config: &schema.NodeSchema{
|
||||
OutputTypes: map[string]*vo.TypeInfo{
|
||||
OutputKeyDeserialization: {Type: vo.DataTypeInteger},
|
||||
},
|
||||
},
|
||||
inputJSON: `"123"`,
|
||||
@@ -209,9 +200,9 @@ func TestJsonDeserializer_Invoke(t *testing.T) {
|
||||
expectWarnings: 0,
|
||||
}, {
|
||||
name: "Test float to integer conversion (integer part)",
|
||||
config: &DeserializationConfig{
|
||||
OutputFields: map[string]*vo.TypeInfo{
|
||||
"output": {Type: vo.DataTypeInteger},
|
||||
config: &schema.NodeSchema{
|
||||
OutputTypes: map[string]*vo.TypeInfo{
|
||||
OutputKeyDeserialization: {Type: vo.DataTypeInteger},
|
||||
},
|
||||
},
|
||||
inputJSON: `123.0`,
|
||||
@@ -220,9 +211,9 @@ func TestJsonDeserializer_Invoke(t *testing.T) {
|
||||
expectWarnings: 0,
|
||||
}, {
|
||||
name: "Test float to integer conversion (non-integer part)",
|
||||
config: &DeserializationConfig{
|
||||
OutputFields: map[string]*vo.TypeInfo{
|
||||
"output": {Type: vo.DataTypeInteger},
|
||||
config: &schema.NodeSchema{
|
||||
OutputTypes: map[string]*vo.TypeInfo{
|
||||
OutputKeyDeserialization: {Type: vo.DataTypeInteger},
|
||||
},
|
||||
},
|
||||
inputJSON: `123.5`,
|
||||
@@ -231,9 +222,9 @@ func TestJsonDeserializer_Invoke(t *testing.T) {
|
||||
expectWarnings: 0,
|
||||
}, {
|
||||
name: "Test boolean to integer conversion",
|
||||
config: &DeserializationConfig{
|
||||
OutputFields: map[string]*vo.TypeInfo{
|
||||
"output": {Type: vo.DataTypeInteger},
|
||||
config: &schema.NodeSchema{
|
||||
OutputTypes: map[string]*vo.TypeInfo{
|
||||
OutputKeyDeserialization: {Type: vo.DataTypeInteger},
|
||||
},
|
||||
},
|
||||
inputJSON: `true`,
|
||||
@@ -242,9 +233,9 @@ func TestJsonDeserializer_Invoke(t *testing.T) {
|
||||
expectWarnings: 1,
|
||||
}, {
|
||||
name: "Test string to boolean conversion",
|
||||
config: &DeserializationConfig{
|
||||
OutputFields: map[string]*vo.TypeInfo{
|
||||
"output": {Type: vo.DataTypeBoolean},
|
||||
config: &schema.NodeSchema{
|
||||
OutputTypes: map[string]*vo.TypeInfo{
|
||||
OutputKeyDeserialization: {Type: vo.DataTypeBoolean},
|
||||
},
|
||||
},
|
||||
inputJSON: `"true"`,
|
||||
@@ -252,10 +243,11 @@ func TestJsonDeserializer_Invoke(t *testing.T) {
|
||||
expectErr: false,
|
||||
expectWarnings: 0,
|
||||
}, {
|
||||
name: "Test string to integer conversion in nested object",
|
||||
config: &DeserializationConfig{
|
||||
OutputFields: map[string]*vo.TypeInfo{
|
||||
"output": {
|
||||
name: "Test string to integer conversion in nested object",
|
||||
inputJSON: `{"age":"456"}`,
|
||||
config: &schema.NodeSchema{
|
||||
OutputTypes: map[string]*vo.TypeInfo{
|
||||
OutputKeyDeserialization: {
|
||||
Type: vo.DataTypeObject,
|
||||
Properties: map[string]*vo.TypeInfo{
|
||||
"age": {Type: vo.DataTypeInteger},
|
||||
@@ -263,15 +255,14 @@ func TestJsonDeserializer_Invoke(t *testing.T) {
|
||||
},
|
||||
},
|
||||
},
|
||||
inputJSON: `{"age":"456"}`,
|
||||
expectedOutput: map[string]any{"age": 456},
|
||||
expectErr: false,
|
||||
expectWarnings: 0,
|
||||
}, {
|
||||
name: "Test string to integer conversion for array elements",
|
||||
config: &DeserializationConfig{
|
||||
OutputFields: map[string]*vo.TypeInfo{
|
||||
"output": {
|
||||
config: &schema.NodeSchema{
|
||||
OutputTypes: map[string]*vo.TypeInfo{
|
||||
OutputKeyDeserialization: {
|
||||
Type: vo.DataTypeArray,
|
||||
ElemTypeInfo: &vo.TypeInfo{Type: vo.DataTypeInteger},
|
||||
},
|
||||
@@ -283,9 +274,9 @@ func TestJsonDeserializer_Invoke(t *testing.T) {
|
||||
expectWarnings: 0,
|
||||
}, {
|
||||
name: "Test string with non-numeric characters to integer conversion",
|
||||
config: &DeserializationConfig{
|
||||
OutputFields: map[string]*vo.TypeInfo{
|
||||
"output": {Type: vo.DataTypeInteger},
|
||||
config: &schema.NodeSchema{
|
||||
OutputTypes: map[string]*vo.TypeInfo{
|
||||
OutputKeyDeserialization: {Type: vo.DataTypeInteger},
|
||||
},
|
||||
},
|
||||
inputJSON: `"123abc"`,
|
||||
@@ -294,9 +285,9 @@ func TestJsonDeserializer_Invoke(t *testing.T) {
|
||||
expectWarnings: 1,
|
||||
}, {
|
||||
name: "Test type mismatch in nested object field",
|
||||
config: &DeserializationConfig{
|
||||
OutputFields: map[string]*vo.TypeInfo{
|
||||
"output": {
|
||||
config: &schema.NodeSchema{
|
||||
OutputTypes: map[string]*vo.TypeInfo{
|
||||
OutputKeyDeserialization: {
|
||||
Type: vo.DataTypeObject,
|
||||
Properties: map[string]*vo.TypeInfo{
|
||||
"score": {Type: vo.DataTypeInteger},
|
||||
@@ -310,9 +301,9 @@ func TestJsonDeserializer_Invoke(t *testing.T) {
|
||||
expectWarnings: 1,
|
||||
}, {
|
||||
name: "Test partial conversion failure in array elements",
|
||||
config: &DeserializationConfig{
|
||||
OutputFields: map[string]*vo.TypeInfo{
|
||||
"output": {
|
||||
config: &schema.NodeSchema{
|
||||
OutputTypes: map[string]*vo.TypeInfo{
|
||||
OutputKeyDeserialization: {
|
||||
Type: vo.DataTypeArray,
|
||||
ElemTypeInfo: &vo.TypeInfo{Type: vo.DataTypeInteger},
|
||||
},
|
||||
@@ -326,12 +317,12 @@ func TestJsonDeserializer_Invoke(t *testing.T) {
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
processor, err := NewJsonDeserializer(ctx, tt.config)
|
||||
processor, err := (&DeserializationConfig{}).Build(ctx, tt.config)
|
||||
assert.NoError(t, err)
|
||||
|
||||
ctxWithCache := ctxcache.Init(ctx)
|
||||
input := map[string]any{"input": tt.inputJSON}
|
||||
result, err := processor.Invoke(ctxWithCache, input)
|
||||
result, err := processor.(*Deserializer).Invoke(ctxWithCache, input)
|
||||
|
||||
if tt.expectErr {
|
||||
assert.Error(t, err)
|
||||
|
||||
@@ -20,7 +20,11 @@ import (
|
||||
"context"
|
||||
"fmt"
|
||||
|
||||
"github.com/coze-dev/coze-studio/backend/domain/workflow/entity"
|
||||
"github.com/coze-dev/coze-studio/backend/domain/workflow/entity/vo"
|
||||
"github.com/coze-dev/coze-studio/backend/domain/workflow/internal/canvas/convert"
|
||||
"github.com/coze-dev/coze-studio/backend/domain/workflow/internal/nodes"
|
||||
"github.com/coze-dev/coze-studio/backend/domain/workflow/internal/schema"
|
||||
"github.com/coze-dev/coze-studio/backend/pkg/sonic"
|
||||
)
|
||||
|
||||
@@ -29,28 +33,57 @@ const (
|
||||
OutputKeySerialization = "output"
|
||||
)
|
||||
|
||||
// SerializationConfig is the Config type for NodeTypeJsonSerialization.
|
||||
// Each Node Type should have its own designated Config type,
|
||||
// which should implement NodeAdaptor and NodeBuilder.
|
||||
// NOTE: we didn't define any fields for this type,
|
||||
// because this node is simple, we doesn't need to extract any SPECIFIC piece of info
|
||||
// from frontend Node. In other cases we would need to do it, such as LLM's model configs.
|
||||
type SerializationConfig struct {
|
||||
InputTypes map[string]*vo.TypeInfo
|
||||
// you can define ANY number of fields here,
|
||||
// as long as these fields are SERIALIZABLE and EXPORTED.
|
||||
// to store specific info extracted from frontend node.
|
||||
// e.g.
|
||||
// - LLM model configs
|
||||
// - conditional expressions
|
||||
// - fixed input fields such as MaxBatchSize
|
||||
}
|
||||
|
||||
type JsonSerializer struct {
|
||||
config *SerializationConfig
|
||||
}
|
||||
|
||||
func NewJsonSerializer(_ context.Context, cfg *SerializationConfig) (*JsonSerializer, error) {
|
||||
if cfg == nil {
|
||||
return nil, fmt.Errorf("config required")
|
||||
}
|
||||
if cfg.InputTypes == nil {
|
||||
return nil, fmt.Errorf("InputTypes is required for serialization")
|
||||
// Adapt provides conversion from Node to NodeSchema.
|
||||
// NOTE: in this specific case, we don't need AdaptOption.
|
||||
func (s *SerializationConfig) Adapt(_ context.Context, n *vo.Node, _ ...nodes.AdaptOption) (*schema.NodeSchema, error) {
|
||||
ns := &schema.NodeSchema{
|
||||
Key: vo.NodeKey(n.ID),
|
||||
Type: entity.NodeTypeJsonSerialization,
|
||||
Name: n.Data.Meta.Title,
|
||||
Configs: s, // remember to set the Node's Config Type to NodeSchema as well
|
||||
}
|
||||
|
||||
return &JsonSerializer{
|
||||
config: cfg,
|
||||
}, nil
|
||||
// this sets input fields' type and mapping info
|
||||
if err := convert.SetInputsForNodeSchema(n, ns); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// this set output fields' type info
|
||||
if err := convert.SetOutputTypesForNodeSchema(n, ns); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return ns, nil
|
||||
}
|
||||
|
||||
func (js *JsonSerializer) Invoke(_ context.Context, input map[string]any) (map[string]any, error) {
|
||||
func (s *SerializationConfig) Build(_ context.Context, _ *schema.NodeSchema, _ ...schema.BuildOption) (
|
||||
any, error) {
|
||||
return &Serializer{}, nil
|
||||
}
|
||||
|
||||
// Serializer is the actual node implementation.
|
||||
type Serializer struct {
|
||||
// here can holds ANY data required for node execution
|
||||
}
|
||||
|
||||
// Invoke implements the InvokableNode interface.
|
||||
func (js *Serializer) Invoke(_ context.Context, input map[string]any) (map[string]any, error) {
|
||||
// Directly use the input map for serialization
|
||||
if input == nil {
|
||||
return nil, fmt.Errorf("input data for serialization cannot be nil")
|
||||
|
||||
@@ -23,44 +23,34 @@ import (
|
||||
"github.com/stretchr/testify/assert"
|
||||
|
||||
"github.com/coze-dev/coze-studio/backend/domain/workflow/entity/vo"
|
||||
"github.com/coze-dev/coze-studio/backend/domain/workflow/internal/schema"
|
||||
)
|
||||
|
||||
func TestNewJsonSerialize(t *testing.T) {
|
||||
ctx := context.Background()
|
||||
|
||||
// Test with nil config
|
||||
_, err := NewJsonSerializer(ctx, nil)
|
||||
assert.Error(t, err)
|
||||
assert.Contains(t, err.Error(), "config required")
|
||||
|
||||
// Test with missing InputTypes config
|
||||
_, err = NewJsonSerializer(ctx, &SerializationConfig{})
|
||||
assert.Error(t, err)
|
||||
assert.Contains(t, err.Error(), "InputTypes is required")
|
||||
|
||||
// Test with valid config
|
||||
validConfig := &SerializationConfig{
|
||||
s, err := (&SerializationConfig{}).Build(ctx, &schema.NodeSchema{
|
||||
InputTypes: map[string]*vo.TypeInfo{
|
||||
"testKey": {Type: "string"},
|
||||
},
|
||||
}
|
||||
processor, err := NewJsonSerializer(ctx, validConfig)
|
||||
})
|
||||
|
||||
assert.NoError(t, err)
|
||||
assert.NotNil(t, processor)
|
||||
assert.NotNil(t, s)
|
||||
}
|
||||
|
||||
func TestJsonSerialize_Invoke(t *testing.T) {
|
||||
ctx := context.Background()
|
||||
config := &SerializationConfig{
|
||||
|
||||
processor, err := (&SerializationConfig{}).Build(ctx, &schema.NodeSchema{
|
||||
InputTypes: map[string]*vo.TypeInfo{
|
||||
"stringKey": {Type: "string"},
|
||||
"intKey": {Type: "integer"},
|
||||
"boolKey": {Type: "boolean"},
|
||||
"objKey": {Type: "object"},
|
||||
},
|
||||
}
|
||||
|
||||
processor, err := NewJsonSerializer(ctx, config)
|
||||
})
|
||||
assert.NoError(t, err)
|
||||
|
||||
// Test cases
|
||||
@@ -115,7 +105,7 @@ func TestJsonSerialize_Invoke(t *testing.T) {
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
result, err := processor.Invoke(ctx, tt.input)
|
||||
result, err := processor.(*Serializer).Invoke(ctx, tt.input)
|
||||
|
||||
if tt.expectErr {
|
||||
assert.Error(t, err)
|
||||
|
||||
Reference in New Issue
Block a user