mirror of
https://github.com/httprunner/httprunner.git
synced 2026-05-06 20:32:44 +08:00
Merge branch 'fix-sleep' into 'master'
refactor: unify float64 conversion logic in ToolSleep and ToolSleepMS, enhance error logging See merge request iesqa/httprunner!152
This commit is contained in:
@@ -217,6 +217,8 @@ func Interface2Float64(i interface{}) (float64, error) {
|
||||
case string: // e.g. "1", "0.5"
|
||||
floatVar, err := strconv.ParseFloat(v, 64)
|
||||
if err != nil {
|
||||
log.Error().Err(err).Str("value", v).
|
||||
Msg("convert string to float64 failed")
|
||||
return 0, err
|
||||
}
|
||||
return floatVar, nil
|
||||
@@ -226,6 +228,10 @@ func Interface2Float64(i interface{}) (float64, error) {
|
||||
if ok {
|
||||
return value.Float64()
|
||||
}
|
||||
|
||||
// Log error for unsupported types
|
||||
log.Error().Interface("value", i).Type("type", i).
|
||||
Msg("convert float64 failed")
|
||||
return 0, errors.New("failed to convert interface to float64")
|
||||
}
|
||||
|
||||
@@ -334,29 +340,6 @@ func IsZeroFloat64(f float64) bool {
|
||||
return math.Abs(f) < threshold
|
||||
}
|
||||
|
||||
func ConvertToFloat64(val interface{}) (float64, error) {
|
||||
switch v := val.(type) {
|
||||
case float64:
|
||||
return v, nil
|
||||
case int:
|
||||
return float64(v), nil
|
||||
case int64:
|
||||
return float64(v), nil
|
||||
case string:
|
||||
f, err := strconv.ParseFloat(v, 64)
|
||||
if err != nil {
|
||||
log.Error().Err(err).Str("value", v).
|
||||
Msg("convert string to float64 failed")
|
||||
return 0, err
|
||||
}
|
||||
return f, nil
|
||||
default:
|
||||
log.Error().Interface("value", val).Type("type", val).
|
||||
Msg("convert float64 failed")
|
||||
return 0, errors.New("convert float64 error")
|
||||
}
|
||||
}
|
||||
|
||||
func ConvertToFloat64Slice(val interface{}) ([]float64, error) {
|
||||
if paramsSlice, ok := val.([]float64); ok {
|
||||
return paramsSlice, nil
|
||||
@@ -369,7 +352,7 @@ func ConvertToFloat64Slice(val interface{}) ([]float64, error) {
|
||||
var err error
|
||||
float64Slice := make([]float64, len(paramsSlice))
|
||||
for i, v := range paramsSlice {
|
||||
float64Slice[i], err = ConvertToFloat64(v)
|
||||
float64Slice[i], err = Interface2Float64(v)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
@@ -1 +1 @@
|
||||
v5.0.0-250811
|
||||
v5.0.0-250812
|
||||
|
||||
@@ -2,9 +2,7 @@ package uixt
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"strconv"
|
||||
"time"
|
||||
|
||||
"github.com/mark3labs/mcp-go/mcp"
|
||||
@@ -70,28 +68,12 @@ func (t *ToolSleep) Implement() server.ToolHandlerFunc {
|
||||
// Sleep action logic
|
||||
log.Info().Interface("seconds", seconds).Msg("sleeping")
|
||||
|
||||
var duration time.Duration
|
||||
var actualSeconds float64
|
||||
switch v := seconds.(type) {
|
||||
case float64:
|
||||
actualSeconds = v
|
||||
duration = time.Duration(v*1000) * time.Millisecond
|
||||
case int:
|
||||
actualSeconds = float64(v)
|
||||
duration = time.Duration(v) * time.Second
|
||||
case int64:
|
||||
actualSeconds = float64(v)
|
||||
duration = time.Duration(v) * time.Second
|
||||
case string:
|
||||
s, err := builtin.ConvertToFloat64(v)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("invalid sleep duration: %v", v)
|
||||
}
|
||||
actualSeconds = s
|
||||
duration = time.Duration(s*1000) * time.Millisecond
|
||||
default:
|
||||
return nil, fmt.Errorf("unsupported sleep duration type: %T", v)
|
||||
// Use Interface2Float64 for unified type conversion
|
||||
actualSeconds, err := builtin.Interface2Float64(seconds)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("invalid sleep duration: %v", seconds)
|
||||
}
|
||||
duration := time.Duration(actualSeconds) * time.Second
|
||||
|
||||
// Extract start_time_ms and use sleepStrict for unified sleep logic
|
||||
startTime, err := extractStartTimeMs(request)
|
||||
@@ -116,19 +98,19 @@ func (t *ToolSleep) ConvertActionToCallToolRequest(action option.MobileAction) (
|
||||
arguments := map[string]any{}
|
||||
|
||||
var seconds float64
|
||||
if param, ok := action.Params.(json.Number); ok {
|
||||
seconds, _ = param.Float64()
|
||||
arguments["seconds"] = seconds
|
||||
} else if param, ok := action.Params.(int64); ok {
|
||||
seconds = float64(param)
|
||||
arguments["seconds"] = seconds
|
||||
} else if sleepConfig, ok := action.Params.(SleepConfig); ok {
|
||||
if sleepConfig, ok := action.Params.(SleepConfig); ok {
|
||||
// When startTime is provided, pass both seconds and startTime
|
||||
seconds = sleepConfig.Seconds
|
||||
arguments["seconds"] = seconds
|
||||
arguments["start_time_ms"] = sleepConfig.StartTime.UnixMilli()
|
||||
} else {
|
||||
return mcp.CallToolRequest{}, fmt.Errorf("invalid sleep params: %v", action.Params)
|
||||
// Use builtin.Interface2Float64 for unified parameter handling
|
||||
var err error
|
||||
seconds, err = builtin.Interface2Float64(action.Params)
|
||||
if err != nil {
|
||||
return mcp.CallToolRequest{}, fmt.Errorf("invalid sleep params: %v", action.Params)
|
||||
}
|
||||
arguments["seconds"] = seconds
|
||||
}
|
||||
|
||||
return BuildMCPCallToolRequest(t.Name(), arguments, action), nil
|
||||
@@ -167,28 +149,13 @@ func (t *ToolSleepMS) Implement() server.ToolHandlerFunc {
|
||||
// Sleep MS action logic
|
||||
log.Info().Interface("milliseconds", milliseconds).Msg("sleeping in milliseconds")
|
||||
|
||||
var duration time.Duration
|
||||
var actualMilliseconds int64
|
||||
switch v := milliseconds.(type) {
|
||||
case float64:
|
||||
actualMilliseconds = int64(v)
|
||||
duration = time.Duration(v) * time.Millisecond
|
||||
case int:
|
||||
actualMilliseconds = int64(v)
|
||||
duration = time.Duration(v) * time.Millisecond
|
||||
case int64:
|
||||
actualMilliseconds = v
|
||||
duration = time.Duration(v) * time.Millisecond
|
||||
case string:
|
||||
ms, err := strconv.ParseInt(v, 10, 64)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("invalid sleep duration: %v", v)
|
||||
}
|
||||
actualMilliseconds = ms
|
||||
duration = time.Duration(ms) * time.Millisecond
|
||||
default:
|
||||
return nil, fmt.Errorf("unsupported sleep duration type: %T", v)
|
||||
// Use Interface2Float64 for unified type conversion, then convert to int64
|
||||
floatVal, err := builtin.Interface2Float64(milliseconds)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("invalid sleep duration: %v", milliseconds)
|
||||
}
|
||||
actualMilliseconds := int64(floatVal)
|
||||
duration := time.Duration(actualMilliseconds) * time.Millisecond
|
||||
|
||||
// Extract start_time_ms and use sleepStrict for unified sleep logic
|
||||
startTime, err := extractStartTimeMs(request)
|
||||
@@ -212,19 +179,19 @@ func (t *ToolSleepMS) ConvertActionToCallToolRequest(action option.MobileAction)
|
||||
arguments := map[string]any{}
|
||||
|
||||
var milliseconds int64
|
||||
if param, ok := action.Params.(json.Number); ok {
|
||||
milliseconds, _ = param.Int64()
|
||||
arguments["milliseconds"] = milliseconds
|
||||
} else if param, ok := action.Params.(int64); ok {
|
||||
milliseconds = param
|
||||
arguments["milliseconds"] = milliseconds
|
||||
} else if sleepConfig, ok := action.Params.(SleepConfig); ok {
|
||||
if sleepConfig, ok := action.Params.(SleepConfig); ok {
|
||||
// When startTime is provided, pass both milliseconds and startTime
|
||||
milliseconds = sleepConfig.Milliseconds
|
||||
arguments["milliseconds"] = milliseconds
|
||||
arguments["start_time_ms"] = sleepConfig.StartTime.UnixMilli()
|
||||
} else {
|
||||
return mcp.CallToolRequest{}, fmt.Errorf("invalid sleep ms params: %v", action.Params)
|
||||
// Use builtin.Interface2Float64 for unified parameter handling, then convert to int64
|
||||
floatVal, err := builtin.Interface2Float64(action.Params)
|
||||
if err != nil {
|
||||
return mcp.CallToolRequest{}, fmt.Errorf("invalid sleep ms params: %v", action.Params)
|
||||
}
|
||||
milliseconds = int64(floatVal)
|
||||
arguments["milliseconds"] = milliseconds
|
||||
}
|
||||
|
||||
return BuildMCPCallToolRequest(t.Name(), arguments, action), nil
|
||||
|
||||
@@ -30,6 +30,15 @@ func TestToolSleep_ConvertActionToCallToolRequest(t *testing.T) {
|
||||
expectedArgs: map[string]any{"seconds": float64(3.5)},
|
||||
shouldError: false,
|
||||
},
|
||||
{
|
||||
name: "float64 parameter",
|
||||
action: option.MobileAction{
|
||||
Method: option.ACTION_Sleep,
|
||||
Params: float64(5.2),
|
||||
},
|
||||
expectedArgs: map[string]any{"seconds": float64(5.2)},
|
||||
shouldError: false,
|
||||
},
|
||||
{
|
||||
name: "int64 parameter",
|
||||
action: option.MobileAction{
|
||||
@@ -63,6 +72,24 @@ func TestToolSleep_ConvertActionToCallToolRequest(t *testing.T) {
|
||||
expectedArgs: nil,
|
||||
shouldError: true,
|
||||
},
|
||||
{
|
||||
name: "json.Number with integer value",
|
||||
action: option.MobileAction{
|
||||
Method: option.ACTION_Sleep,
|
||||
Params: json.Number("10"),
|
||||
},
|
||||
expectedArgs: map[string]any{"seconds": float64(10)},
|
||||
shouldError: false,
|
||||
},
|
||||
{
|
||||
name: "json.Number with decimal value",
|
||||
action: option.MobileAction{
|
||||
Method: option.ACTION_Sleep,
|
||||
Params: json.Number("1.25"),
|
||||
},
|
||||
expectedArgs: map[string]any{"seconds": float64(1.25)},
|
||||
shouldError: false,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
@@ -109,6 +136,15 @@ func TestToolSleepMS_ConvertActionToCallToolRequest(t *testing.T) {
|
||||
expectedArgs: map[string]any{"milliseconds": int64(2000)},
|
||||
shouldError: false,
|
||||
},
|
||||
{
|
||||
name: "float64 parameter",
|
||||
action: option.MobileAction{
|
||||
Method: option.ACTION_SleepMS,
|
||||
Params: float64(2500.7),
|
||||
},
|
||||
expectedArgs: map[string]any{"milliseconds": int64(2500)},
|
||||
shouldError: false,
|
||||
},
|
||||
{
|
||||
name: "SleepConfig with startTime",
|
||||
action: option.MobileAction{
|
||||
@@ -124,6 +160,15 @@ func TestToolSleepMS_ConvertActionToCallToolRequest(t *testing.T) {
|
||||
},
|
||||
shouldError: false,
|
||||
},
|
||||
{
|
||||
name: "json.Number with decimal value",
|
||||
action: option.MobileAction{
|
||||
Method: option.ACTION_SleepMS,
|
||||
Params: json.Number("1234.56"),
|
||||
},
|
||||
expectedArgs: map[string]any{"milliseconds": int64(1234)},
|
||||
shouldError: false,
|
||||
},
|
||||
{
|
||||
name: "invalid parameter type",
|
||||
action: option.MobileAction{
|
||||
|
||||
Reference in New Issue
Block a user