253 lines
		
	
	
		
			6.4 KiB
		
	
	
	
		
			Go
		
	
	
	
			
		
		
	
	
			253 lines
		
	
	
		
			6.4 KiB
		
	
	
	
		
			Go
		
	
	
	
| /*
 | |
|  * Copyright 2025 coze-dev Authors
 | |
|  *
 | |
|  * Licensed under the Apache License, Version 2.0 (the "License");
 | |
|  * you may not use this file except in compliance with the License.
 | |
|  * You may obtain a copy of the License at
 | |
|  *
 | |
|  *     http://www.apache.org/licenses/LICENSE-2.0
 | |
|  *
 | |
|  * Unless required by applicable law or agreed to in writing, software
 | |
|  * distributed under the License is distributed on an "AS IS" BASIS,
 | |
|  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 | |
|  * See the License for the specific language governing permissions and
 | |
|  * limitations under the License.
 | |
|  */
 | |
| 
 | |
| package service
 | |
| 
 | |
| import (
 | |
| 	"bytes"
 | |
| 	"encoding/json"
 | |
| 	"errors"
 | |
| 	"testing"
 | |
| 
 | |
| 	"github.com/bytedance/mockey"
 | |
| 	"github.com/bytedance/sonic"
 | |
| 	"github.com/getkin/kin-openapi/openapi3"
 | |
| 	"github.com/stretchr/testify/assert"
 | |
| 
 | |
| 	"github.com/coze-dev/coze-studio/backend/pkg/errorx"
 | |
| 
 | |
| 	model "github.com/coze-dev/coze-studio/backend/api/model/crossdomain/plugin"
 | |
| )
 | |
| 
 | |
| func TestToolExecutorProcessWithInvalidRespProcessStrategyOfReturnDefault(t *testing.T) {
 | |
| 	executor := &toolExecutor{
 | |
| 		invalidRespProcessStrategy: model.InvalidResponseProcessStrategyOfReturnDefault,
 | |
| 	}
 | |
| 
 | |
| 	paramVal := `
 | |
| {
 | |
| 	"a1": 1,
 | |
| 	"b1": {
 | |
| 		"a2": 2.1
 | |
| 	},
 | |
| 	"c1": [
 | |
| 		{
 | |
| 			"a2": 3.1
 | |
| 		}
 | |
| 	],
 | |
| 	"d1": "hello",
 | |
| 	"f1": true
 | |
| }
 | |
| `
 | |
| 
 | |
| 	decoder := sonic.ConfigDefault.NewDecoder(bytes.NewBufferString(paramVal))
 | |
| 	decoder.UseNumber()
 | |
| 	paramValMap := map[string]any{}
 | |
| 	err := decoder.Decode(¶mValMap)
 | |
| 	assert.NoError(t, err)
 | |
| 
 | |
| 	paramSchema := &openapi3.Schema{
 | |
| 		Type: openapi3.TypeObject,
 | |
| 		Properties: map[string]*openapi3.SchemaRef{
 | |
| 			"a1": {
 | |
| 				Value: &openapi3.Schema{
 | |
| 					Type: openapi3.TypeInteger,
 | |
| 				},
 | |
| 			},
 | |
| 			"b1": {
 | |
| 				Value: &openapi3.Schema{
 | |
| 					Type: openapi3.TypeObject,
 | |
| 					Properties: map[string]*openapi3.SchemaRef{
 | |
| 						"a2": {
 | |
| 							Value: &openapi3.Schema{
 | |
| 								Type: openapi3.TypeNumber,
 | |
| 							},
 | |
| 						},
 | |
| 					},
 | |
| 				},
 | |
| 			},
 | |
| 			"c1": {
 | |
| 				Value: &openapi3.Schema{
 | |
| 					Type: openapi3.TypeArray,
 | |
| 					Items: &openapi3.SchemaRef{
 | |
| 						Value: &openapi3.Schema{
 | |
| 							Type: openapi3.TypeObject,
 | |
| 							Properties: map[string]*openapi3.SchemaRef{
 | |
| 								"a2": {
 | |
| 									Value: &openapi3.Schema{
 | |
| 										Type: openapi3.TypeNumber,
 | |
| 									},
 | |
| 								},
 | |
| 							},
 | |
| 						},
 | |
| 					},
 | |
| 				},
 | |
| 			},
 | |
| 			"d1": {
 | |
| 				Value: &openapi3.Schema{
 | |
| 					Type: openapi3.TypeString,
 | |
| 				},
 | |
| 			},
 | |
| 			"f1": {
 | |
| 				Value: &openapi3.Schema{
 | |
| 					Type: openapi3.TypeBoolean,
 | |
| 				},
 | |
| 			},
 | |
| 		},
 | |
| 	}
 | |
| 
 | |
| 	processedParamValMap, err := executor.processWithInvalidRespProcessStrategyOfReturnDefault(nil, paramValMap, paramSchema)
 | |
| 	assert.NoError(t, err)
 | |
| 	assert.NotNil(t, processedParamValMap)
 | |
| 	assert.Equal(t, int64(1), processedParamValMap["a1"])
 | |
| 	assert.Equal(t, json.Number("2.1"), processedParamValMap["b1"].(map[string]any)["a2"])
 | |
| 	assert.Equal(t, json.Number("3.1"), processedParamValMap["c1"].([]any)[0].(map[string]any)["a2"])
 | |
| 	assert.Equal(t, "hello", processedParamValMap["d1"])
 | |
| 	assert.Equal(t, true, processedParamValMap["f1"])
 | |
| }
 | |
| 
 | |
| func TestToolExecutorProcessWithInvalidRespProcessStrategyOfReturnErr(t *testing.T) {
 | |
| 	executor := &toolExecutor{
 | |
| 		invalidRespProcessStrategy: model.InvalidResponseProcessStrategyOfReturnErr,
 | |
| 	}
 | |
| 
 | |
| 	mockey.PatchConvey("integer", t, func() {
 | |
| 		paramVal := `
 | |
| {
 | |
| 	"a": 1
 | |
| }
 | |
| `
 | |
| 
 | |
| 		decoder := sonic.ConfigDefault.NewDecoder(bytes.NewBufferString(paramVal))
 | |
| 		decoder.UseNumber()
 | |
| 		paramValMap := map[string]any{}
 | |
| 		err := decoder.Decode(¶mValMap)
 | |
| 		assert.NoError(t, err)
 | |
| 
 | |
| 		paramSchema := &openapi3.Schema{
 | |
| 			Type: openapi3.TypeObject,
 | |
| 			Properties: map[string]*openapi3.SchemaRef{
 | |
| 				"a": {
 | |
| 					Value: &openapi3.Schema{
 | |
| 						Type: openapi3.TypeString,
 | |
| 					},
 | |
| 				},
 | |
| 			},
 | |
| 		}
 | |
| 		_, err = executor.processWithInvalidRespProcessStrategyOfReturnErr(nil, paramValMap, paramSchema)
 | |
| 		var customErr errorx.StatusError
 | |
| 		assert.True(t, errors.As(err, &customErr))
 | |
| 		assert.Equal(t, "execute tool failed : expected 'a' to be of type 'string', but got 'json.Number'", customErr.Msg())
 | |
| 
 | |
| 		paramSchema = &openapi3.Schema{
 | |
| 			Type: openapi3.TypeObject,
 | |
| 			Properties: map[string]*openapi3.SchemaRef{
 | |
| 				"a1": {
 | |
| 					Value: &openapi3.Schema{
 | |
| 						Type: openapi3.TypeInteger,
 | |
| 					},
 | |
| 				},
 | |
| 			},
 | |
| 		}
 | |
| 		_, err = executor.processWithInvalidRespProcessStrategyOfReturnErr(nil, paramValMap, paramSchema)
 | |
| 		assert.NoError(t, err)
 | |
| 	})
 | |
| 
 | |
| 	mockey.PatchConvey("string", t, func() {
 | |
| 		paramVal := `
 | |
| {
 | |
| 	"a": "1"
 | |
| }
 | |
| `
 | |
| 
 | |
| 		decoder := sonic.ConfigDefault.NewDecoder(bytes.NewBufferString(paramVal))
 | |
| 		decoder.UseNumber()
 | |
| 		paramValMap := map[string]any{}
 | |
| 		err := decoder.Decode(¶mValMap)
 | |
| 		assert.NoError(t, err)
 | |
| 
 | |
| 		paramSchema := &openapi3.Schema{
 | |
| 			Type: openapi3.TypeObject,
 | |
| 			Properties: map[string]*openapi3.SchemaRef{
 | |
| 				"a": {
 | |
| 					Value: &openapi3.Schema{
 | |
| 						Type: openapi3.TypeInteger,
 | |
| 					},
 | |
| 				},
 | |
| 			},
 | |
| 		}
 | |
| 		_, err = executor.processWithInvalidRespProcessStrategyOfReturnErr(nil, paramValMap, paramSchema)
 | |
| 		var customErr errorx.StatusError
 | |
| 		assert.True(t, errors.As(err, &customErr))
 | |
| 		assert.Equal(t, "execute tool failed : expected 'a' to be of type 'integer', but got 'string'", customErr.Msg())
 | |
| 
 | |
| 		paramSchema = &openapi3.Schema{
 | |
| 			Type: openapi3.TypeObject,
 | |
| 			Properties: map[string]*openapi3.SchemaRef{
 | |
| 				"a": {
 | |
| 					Value: &openapi3.Schema{
 | |
| 						Type: openapi3.TypeString,
 | |
| 					},
 | |
| 				},
 | |
| 			},
 | |
| 		}
 | |
| 		_, err = executor.processWithInvalidRespProcessStrategyOfReturnErr(nil, paramValMap, paramSchema)
 | |
| 		assert.NoError(t, err)
 | |
| 	})
 | |
| 
 | |
| 	mockey.PatchConvey("boolean", t, func() {
 | |
| 		paramVal := `
 | |
| {
 | |
| 	"a": false
 | |
| }
 | |
| `
 | |
| 
 | |
| 		decoder := sonic.ConfigDefault.NewDecoder(bytes.NewBufferString(paramVal))
 | |
| 		decoder.UseNumber()
 | |
| 		paramValMap := map[string]any{}
 | |
| 		err := decoder.Decode(¶mValMap)
 | |
| 		assert.NoError(t, err)
 | |
| 
 | |
| 		paramSchema := &openapi3.Schema{
 | |
| 			Type: openapi3.TypeObject,
 | |
| 			Properties: map[string]*openapi3.SchemaRef{
 | |
| 				"a": {
 | |
| 					Value: &openapi3.Schema{
 | |
| 						Type: openapi3.TypeString,
 | |
| 					},
 | |
| 				},
 | |
| 			},
 | |
| 		}
 | |
| 		_, err = executor.processWithInvalidRespProcessStrategyOfReturnErr(nil, paramValMap, paramSchema)
 | |
| 		var customErr errorx.StatusError
 | |
| 		assert.True(t, errors.As(err, &customErr))
 | |
| 		assert.Equal(t, "execute tool failed : expected 'a' to be of type 'string', but got 'bool'", customErr.Msg())
 | |
| 
 | |
| 		paramSchema = &openapi3.Schema{
 | |
| 			Type: openapi3.TypeObject,
 | |
| 			Properties: map[string]*openapi3.SchemaRef{
 | |
| 				"a": {
 | |
| 					Value: &openapi3.Schema{
 | |
| 						Type: openapi3.TypeBoolean,
 | |
| 					},
 | |
| 				},
 | |
| 			},
 | |
| 		}
 | |
| 		_, err = executor.processWithInvalidRespProcessStrategyOfReturnErr(nil, paramValMap, paramSchema)
 | |
| 		assert.NoError(t, err)
 | |
| 	})
 | |
| }
 |