Files
httprunner/config.go

337 lines
11 KiB
Go

package hrp
import (
"reflect"
"github.com/httprunner/httprunner/v5/internal/builtin"
"github.com/httprunner/httprunner/v5/uixt/option"
)
type IConfig interface {
Get() *TConfig
}
// NewConfig returns a new constructed testcase config with specified testcase name.
func NewConfig(name string) *TConfig {
return &TConfig{
Name: name,
Environs: make(map[string]string),
Variables: make(map[string]interface{}),
OriginalVariables: make(map[string]interface{}),
}
}
// define struct for testcase config
type TConfig struct {
Name string `json:"name" yaml:"name"` // required
Verify bool `json:"verify,omitempty" yaml:"verify,omitempty"`
BaseURL string `json:"base_url,omitempty" yaml:"base_url,omitempty"` // deprecated in v4.1, moved to env
Headers map[string]string `json:"headers,omitempty" yaml:"headers,omitempty"` // public request headers
Environs map[string]string `json:"environs,omitempty" yaml:"environs,omitempty"` // environment variables
Variables map[string]interface{} `json:"variables,omitempty" yaml:"variables,omitempty"` // global variables
OriginalVariables map[string]interface{} `json:"-" yaml:"-"` // original user variables before env merge (not serialized)
Parameters map[string]interface{} `json:"parameters,omitempty" yaml:"parameters,omitempty"`
ParametersSetting *TParamsConfig `json:"parameters_setting,omitempty" yaml:"parameters_setting,omitempty"`
ThinkTimeSetting *ThinkTimeConfig `json:"think_time,omitempty" yaml:"think_time,omitempty"`
WebSocketSetting *WebSocketConfig `json:"websocket,omitempty" yaml:"websocket,omitempty"`
IOS []*option.IOSDeviceOptions `json:"ios,omitempty" yaml:"ios,omitempty"`
Android []*option.AndroidDeviceOptions `json:"android,omitempty" yaml:"android,omitempty"`
Harmony []*option.HarmonyDeviceOptions `json:"harmony,omitempty" yaml:"harmony,omitempty"`
Browser []*option.BrowserDeviceOptions `json:"browser,omitempty" yaml:"browser,omitempty"`
RequestTimeout float32 `json:"request_timeout,omitempty" yaml:"request_timeout,omitempty"` // request timeout in seconds
CaseTimeout float32 `json:"case_timeout,omitempty" yaml:"case_timeout,omitempty"` // testcase timeout in seconds
Export []string `json:"export,omitempty" yaml:"export,omitempty"`
Weight int `json:"weight,omitempty" yaml:"weight,omitempty"`
Path string `json:"path,omitempty" yaml:"path,omitempty"` // testcase file path
PluginSetting *PluginConfig `json:"plugin,omitempty" yaml:"plugin,omitempty"` // plugin config
MCPConfigPath string `json:"mcp_config_path,omitempty" yaml:"mcp_config_path,omitempty"`
AntiRisk bool `json:"anti_risk,omitempty" yaml:"anti_risk,omitempty"` // global anti-risk switch
AutoPopupHandler bool `json:"auto_popup_handler,omitempty" yaml:"auto_popup_handler,omitempty"` // enable auto popup handler
AIOptions *option.AIServiceOptions `json:"ai_options,omitempty" yaml:"ai_options,omitempty"`
}
func (c *TConfig) Get() *TConfig {
return c
}
// WithVariables sets variables for current testcase.
func (c *TConfig) WithVariables(variables map[string]interface{}) *TConfig {
c.Variables = variables
return c
}
// SetBaseURL sets base URL for current testcase.
func (c *TConfig) SetBaseURL(baseURL string) *TConfig {
c.BaseURL = baseURL
return c
}
// SetHeaders sets global headers for current testcase.
func (c *TConfig) SetHeaders(headers map[string]string) *TConfig {
c.Headers = headers
return c
}
// SetVerifySSL sets whether to verify SSL for current testcase.
func (c *TConfig) SetVerifySSL(verify bool) *TConfig {
c.Verify = verify
return c
}
// SetAntiRisk sets global anti-risk switch for current testcase.
func (c *TConfig) SetAntiRisk(antiRisk bool) *TConfig {
c.AntiRisk = antiRisk
return c
}
// WithParameters sets parameters for current testcase.
func (c *TConfig) WithParameters(parameters map[string]interface{}) *TConfig {
c.Parameters = parameters
return c
}
// WithParametersSetting sets parameters setting for current testcase.
func (c *TConfig) WithParametersSetting(options ...ParametersOption) *TConfig {
if c.ParametersSetting == nil {
c.ParametersSetting = &TParamsConfig{}
}
// apply all options
for _, option := range options {
option(c.ParametersSetting)
}
return c
}
// SetThinkTime sets think time config for current testcase.
func (c *TConfig) SetThinkTime(strategy ThinkTimeStrategy, cfg interface{}, limit float64) *TConfig {
c.ThinkTimeSetting = &ThinkTimeConfig{strategy, cfg, limit}
return c
}
// SetRequestTimeout sets request timeout in seconds.
func (c *TConfig) SetRequestTimeout(seconds float32) *TConfig {
c.RequestTimeout = seconds
return c
}
// SetCaseTimeout sets testcase timeout in seconds.
func (c *TConfig) SetCaseTimeout(seconds float32) *TConfig {
c.CaseTimeout = seconds
return c
}
// ExportVars specifies variable names to export for current testcase.
func (c *TConfig) ExportVars(vars ...string) *TConfig {
c.Export = vars
return c
}
// SetWeight sets weight for current testcase, which is used in load testing.
func (c *TConfig) SetWeight(weight int) *TConfig {
c.Weight = weight
return c
}
// SetAIOptions sets AI service options for current testcase.
func (c *TConfig) SetAIOptions(opts ...option.AIServiceOption) *TConfig {
c.AIOptions = option.NewAIServiceOptions(opts...)
return c
}
// SetLLMService sets LLM service for current testcase.
func (c *TConfig) SetLLMService(service option.LLMServiceType) *TConfig {
if c.AIOptions == nil {
c.AIOptions = option.NewAIServiceOptions()
}
c.AIOptions.LLMService = service
return c
}
// SetCVService sets CV service for current testcase.
func (c *TConfig) SetCVService(service option.CVServiceType) *TConfig {
if c.AIOptions == nil {
c.AIOptions = option.NewAIServiceOptions()
}
c.AIOptions.CVService = service
return c
}
func (c *TConfig) SetWebSocket(times, interval, timeout, size int64) *TConfig {
c.WebSocketSetting = &WebSocketConfig{
ReconnectionTimes: times,
ReconnectionInterval: interval,
MaxMessageSize: size,
}
return c
}
func (c *TConfig) SetIOS(opts ...option.IOSDeviceOption) *TConfig {
iosOptions := option.NewIOSDeviceOptions(opts...)
// each device can have its own settings
if iosOptions.UDID != "" {
c.IOS = append(c.IOS, iosOptions)
return c
}
// device UDID is not specified, settings will be shared
if len(c.IOS) == 0 {
c.IOS = append(c.IOS, iosOptions)
} else {
c.IOS[0] = iosOptions
}
return c
}
func (c *TConfig) SetHarmony(opts ...option.HarmonyDeviceOption) *TConfig {
harmonyOptions := option.NewHarmonyDeviceOptions(opts...)
// each device can have its own settings
if harmonyOptions.ConnectKey != "" {
c.Harmony = append(c.Harmony, harmonyOptions)
return c
}
// device UDID is not specified, settings will be shared
if len(c.Harmony) == 0 {
c.Harmony = append(c.Harmony, harmonyOptions)
} else {
c.Harmony[0] = harmonyOptions
}
return c
}
func (c *TConfig) SetAndroid(opts ...option.AndroidDeviceOption) *TConfig {
uiaOptions := option.NewAndroidDeviceOptions(opts...)
// each device can have its own settings
if uiaOptions.SerialNumber != "" {
c.Android = append(c.Android, uiaOptions)
return c
}
// device UDID is not specified, settings will be shared
if len(c.Android) == 0 {
c.Android = append(c.Android, uiaOptions)
} else {
c.Android[0] = uiaOptions
}
return c
}
func (c *TConfig) SetBrowser(opts ...option.BrowserDeviceOption) *TConfig {
browserOptions := option.NewBrowserDeviceOptions(opts...)
// each device can have its own settings
if browserOptions.BrowserID != "" {
c.Browser = append(c.Browser, browserOptions)
return c
}
// device UDID is not specified, settings will be shared
if len(c.Browser) == 0 {
c.Browser = append(c.Browser, browserOptions)
} else {
c.Browser[0] = browserOptions
}
return c
}
// EnablePlugin enables plugin for current testcase.
// default to disable plugin
func (c *TConfig) EnablePlugin() *TConfig {
c.PluginSetting = &PluginConfig{}
return c
}
// EnableAutoPopupHandler enables auto popup handler for current testcase.
// default to disable auto popup handler
func (c *TConfig) EnableAutoPopupHandler() *TConfig {
c.AutoPopupHandler = true
return c
}
type ThinkTimeConfig struct {
Strategy ThinkTimeStrategy `json:"strategy,omitempty" yaml:"strategy,omitempty"` // default、random、multiply、ignore
Setting interface{} `json:"setting,omitempty" yaml:"setting,omitempty"` // random(map): {"min_percentage": 0.5, "max_percentage": 1.5}; 10、multiply(float64): 1.5
Limit float64 `json:"limit,omitempty" yaml:"limit,omitempty"` // limit think time no more than specific time, ignore if value <= 0
}
func (ttc *ThinkTimeConfig) checkThinkTime() {
if ttc == nil {
return
}
// unset strategy, set default strategy
if ttc.Strategy == "" {
ttc.Strategy = ThinkTimeDefault
}
// check think time
if ttc.Strategy == ThinkTimeRandomPercentage {
if ttc.Setting == nil || reflect.TypeOf(ttc.Setting).Kind() != reflect.Map {
ttc.Setting = thinkTimeDefaultRandom
return
}
value, ok := ttc.Setting.(map[string]interface{})
if !ok {
ttc.Setting = thinkTimeDefaultRandom
return
}
if _, ok := value["min_percentage"]; !ok {
ttc.Setting = thinkTimeDefaultRandom
return
}
if _, ok := value["max_percentage"]; !ok {
ttc.Setting = thinkTimeDefaultRandom
return
}
left, err := builtin.Interface2Float64(value["min_percentage"])
if err != nil {
ttc.Setting = thinkTimeDefaultRandom
return
}
right, err := builtin.Interface2Float64(value["max_percentage"])
if err != nil {
ttc.Setting = thinkTimeDefaultRandom
return
}
ttc.Setting = map[string]float64{"min_percentage": left, "max_percentage": right}
} else if ttc.Strategy == ThinkTimeMultiply {
if ttc.Setting == nil {
ttc.Setting = float64(0) // default
return
}
value, err := builtin.Interface2Float64(ttc.Setting)
if err != nil {
ttc.Setting = float64(0) // default
return
}
ttc.Setting = value
} else if ttc.Strategy != ThinkTimeIgnore {
// unrecognized strategy, set default strategy
ttc.Strategy = ThinkTimeDefault
}
}
type ThinkTimeStrategy string
const (
ThinkTimeDefault ThinkTimeStrategy = "default" // as recorded
ThinkTimeRandomPercentage ThinkTimeStrategy = "random_percentage" // use random percentage of recorded think time
ThinkTimeMultiply ThinkTimeStrategy = "multiply" // multiply recorded think time
ThinkTimeIgnore ThinkTimeStrategy = "ignore" // ignore recorded think time
)
const (
thinkTimeDefaultMultiply = 1
)
var thinkTimeDefaultRandom = map[string]float64{"min_percentage": 0.5, "max_percentage": 1.5}
type PluginConfig struct {
Path string
Type string // bin、so、py
Content []byte
}