mirror of
https://github.com/httprunner/httprunner.git
synced 2026-05-13 17:29:56 +08:00
feat: add status code for mobile UI
This commit is contained in:
@@ -18,17 +18,33 @@ var (
|
||||
)
|
||||
|
||||
// parser: [40, 60)
|
||||
var (
|
||||
ParseError = errors.New("parse error") // 40
|
||||
ParseConfigError = errors.New("parse config error") // 41
|
||||
ParseStringError = errors.New("parse string failed") // 42
|
||||
ParseVariablesError = errors.New("parse variables failed") // 43
|
||||
)
|
||||
|
||||
// runner: [60, 100)
|
||||
|
||||
// ios related: [100, 130)
|
||||
var (
|
||||
IOSScreenShotError = errors.New("ios screenshot error") // 110
|
||||
IOSDeviceConnectionError = errors.New("ios device connection error") // 100
|
||||
IOSDeviceHTTPDriverError = errors.New("ios device HTTP driver error") // 101
|
||||
IOSDeviceUSBDriverError = errors.New("ios device USB driver error") // 102
|
||||
IOSScreenShotError = errors.New("ios screenshot error") // 110
|
||||
IOSCaptureLogError = errors.New("ios capture log error") // 111
|
||||
|
||||
MobileUIDriverError = errors.New("mobile UI driver error") // 120
|
||||
MobileUIValidationError = errors.New("mobile UI validation error") // 121
|
||||
)
|
||||
|
||||
// android related: [130, 160)
|
||||
var (
|
||||
AndroidScreenShotError = errors.New("android screenshot error") // 150
|
||||
AndroidDeviceConnectionError = errors.New("android device connection error") // 130
|
||||
AndroidDeviceDriverError = errors.New("android device driver error") // 131
|
||||
AndroidScreenShotError = errors.New("android screenshot error") // 150
|
||||
AndroidCaptureLogError = errors.New("android capture log error") // 151
|
||||
)
|
||||
|
||||
// OCR related: [160, 180)
|
||||
@@ -45,14 +61,28 @@ var (
|
||||
// report related: [200, 220)
|
||||
|
||||
var errorsMap = map[error]int{
|
||||
// loader
|
||||
LoadJSONError: 10,
|
||||
LoadYAMLError: 11,
|
||||
|
||||
// parser
|
||||
ParseError: 40,
|
||||
ParseConfigError: 41,
|
||||
ParseStringError: 42,
|
||||
ParseVariablesError: 43,
|
||||
|
||||
// ios related
|
||||
IOSScreenShotError: 110,
|
||||
IOSDeviceConnectionError: 100,
|
||||
IOSDeviceHTTPDriverError: 101,
|
||||
IOSDeviceUSBDriverError: 102,
|
||||
IOSScreenShotError: 110,
|
||||
IOSCaptureLogError: 111,
|
||||
|
||||
// android related
|
||||
AndroidScreenShotError: 130,
|
||||
AndroidDeviceConnectionError: 130,
|
||||
AndroidDeviceDriverError: 131,
|
||||
AndroidScreenShotError: 150,
|
||||
AndroidCaptureLogError: 151,
|
||||
|
||||
// OCR related
|
||||
OCREnvMissedError: 160,
|
||||
|
||||
@@ -1 +1 @@
|
||||
v4.3.0-beta-10172144
|
||||
v4.3.0-beta-10191154
|
||||
@@ -13,9 +13,11 @@ import (
|
||||
"github.com/httprunner/funplugin"
|
||||
"github.com/httprunner/funplugin/shared"
|
||||
"github.com/maja42/goval"
|
||||
"github.com/pkg/errors"
|
||||
"github.com/rs/zerolog/log"
|
||||
|
||||
"github.com/httprunner/httprunner/v4/hrp/internal/builtin"
|
||||
"github.com/httprunner/httprunner/v4/hrp/internal/code"
|
||||
)
|
||||
|
||||
func newParser() *Parser {
|
||||
@@ -183,18 +185,18 @@ func (p *Parser) ParseString(raw string, variablesMapping map[string]interface{}
|
||||
argsStr := funcMatched[2]
|
||||
arguments, err := parseFunctionArguments(argsStr)
|
||||
if err != nil {
|
||||
return raw, err
|
||||
return raw, errors.Wrap(code.ParseStringError, err.Error())
|
||||
}
|
||||
parsedArgs, err := p.Parse(arguments, variablesMapping)
|
||||
if err != nil {
|
||||
return raw, err
|
||||
return raw, errors.Wrap(code.ParseStringError, err.Error())
|
||||
}
|
||||
|
||||
result, err := p.callFunc(funcName, parsedArgs.([]interface{})...)
|
||||
if err != nil {
|
||||
log.Error().Str("funcName", funcName).Interface("arguments", arguments).
|
||||
Err(err).Msg("call function failed")
|
||||
return raw, err
|
||||
return raw, errors.Wrap(code.ParseStringError, err.Error())
|
||||
}
|
||||
log.Info().Str("funcName", funcName).Interface("arguments", arguments).
|
||||
Interface("output", result).Msg("call function success")
|
||||
@@ -226,7 +228,8 @@ func (p *Parser) ParseString(raw string, variablesMapping map[string]interface{}
|
||||
}
|
||||
varValue, ok := variablesMapping[varName]
|
||||
if !ok {
|
||||
return raw, fmt.Errorf("variable %s not found", varName)
|
||||
return raw, errors.Wrap(code.ParseStringError,
|
||||
fmt.Sprintf("variable %s not found", varName))
|
||||
}
|
||||
|
||||
if fmt.Sprintf("${%s}", varName) == raw || fmt.Sprintf("$%s", varName) == raw {
|
||||
@@ -428,7 +431,8 @@ func (p *Parser) ParseVariables(variables map[string]interface{}) (map[string]in
|
||||
// variables = {"key": ["$key", 2]}
|
||||
if _, ok := extractVarsSet[varName]; ok {
|
||||
log.Error().Interface("variables", variables).Msg("[parseVariables] variable self reference error")
|
||||
return variables, fmt.Errorf("variable self reference: %v", varName)
|
||||
return variables, errors.Wrap(code.ParseVariablesError,
|
||||
fmt.Sprintf("variable self reference: %v", varName))
|
||||
}
|
||||
|
||||
// check if reference variable not in variables mapping
|
||||
@@ -443,7 +447,8 @@ func (p *Parser) ParseVariables(variables map[string]interface{}) (map[string]in
|
||||
}
|
||||
if len(undefinedVars) > 0 {
|
||||
log.Error().Interface("undefinedVars", undefinedVars).Msg("[parseVariables] variable not defined error")
|
||||
return variables, fmt.Errorf("variable not defined: %v", undefinedVars)
|
||||
return variables, errors.Wrap(code.ParseVariablesError,
|
||||
fmt.Sprintf("variable not defined: %v", undefinedVars))
|
||||
}
|
||||
|
||||
parsedValue, err := p.Parse(varValue, parsedVariables)
|
||||
@@ -456,7 +461,7 @@ func (p *Parser) ParseVariables(variables map[string]interface{}) (map[string]in
|
||||
// check if circular reference exists
|
||||
if traverseRounds > len(variables) {
|
||||
log.Error().Msg("[parseVariables] circular reference error, break infinite loop!")
|
||||
return variables, fmt.Errorf("circular reference")
|
||||
return variables, errors.Wrap(code.ParseVariablesError, "circular reference")
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -13,6 +13,7 @@ import (
|
||||
"github.com/pkg/errors"
|
||||
"github.com/rs/zerolog/log"
|
||||
|
||||
"github.com/httprunner/httprunner/v4/hrp/internal/code"
|
||||
"github.com/httprunner/httprunner/v4/hrp/internal/json"
|
||||
"github.com/httprunner/httprunner/v4/hrp/internal/myexec"
|
||||
)
|
||||
@@ -71,7 +72,8 @@ func GetAndroidDeviceOptions(dev *AndroidDevice) (deviceOptions []AndroidDeviceO
|
||||
func NewAndroidDevice(options ...AndroidDeviceOption) (device *AndroidDevice, err error) {
|
||||
deviceList, err := DeviceList()
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("get attached devices failed: %v", err)
|
||||
return nil, errors.Wrap(code.AndroidDeviceConnectionError,
|
||||
fmt.Sprintf("get attached devices failed: %v", err))
|
||||
}
|
||||
|
||||
device = &AndroidDevice{
|
||||
@@ -95,13 +97,14 @@ func NewAndroidDevice(options ...AndroidDeviceOption) (device *AndroidDevice, er
|
||||
return device, nil
|
||||
}
|
||||
|
||||
return nil, fmt.Errorf("device %s not found", device.SerialNumber)
|
||||
return nil, errors.Wrap(code.AndroidDeviceConnectionError,
|
||||
fmt.Sprintf("device %s not found", device.SerialNumber))
|
||||
}
|
||||
|
||||
func DeviceList() (devices []gadb.Device, err error) {
|
||||
var adbClient gadb.Client
|
||||
if adbClient, err = gadb.NewClientWith(AdbServerHost, AdbServerPort); err != nil {
|
||||
return nil, err
|
||||
return nil, errors.Wrap(code.AndroidDeviceConnectionError, err.Error())
|
||||
}
|
||||
|
||||
return adbClient.DeviceList()
|
||||
|
||||
@@ -963,7 +963,12 @@ func (ud *uiaDriver) Wait(condition Condition) error {
|
||||
func (ud *uiaDriver) StartCaptureLog(identifier ...string) (err error) {
|
||||
log.Info().Msg("start adb log recording")
|
||||
err = ud.logcat.CatchLogcat()
|
||||
return
|
||||
if err != nil {
|
||||
err = errors.Wrap(code.IOSCaptureLogError,
|
||||
fmt.Sprintf("start adb log recording failed: %v", err))
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (ud *uiaDriver) StopCaptureLog() (result interface{}, err error) {
|
||||
@@ -971,6 +976,8 @@ func (ud *uiaDriver) StopCaptureLog() (result interface{}, err error) {
|
||||
err = ud.logcat.Stop()
|
||||
if err != nil {
|
||||
log.Error().Err(err).Msg("failed to get adb log recording")
|
||||
err = errors.Wrap(code.IOSCaptureLogError,
|
||||
fmt.Sprintf("get adb log recording failed: %v", err))
|
||||
return "", err
|
||||
}
|
||||
content := ud.logcat.logBuffer.String()
|
||||
|
||||
@@ -20,6 +20,7 @@ import (
|
||||
"github.com/pkg/errors"
|
||||
"github.com/rs/zerolog/log"
|
||||
|
||||
"github.com/httprunner/httprunner/v4/hrp/internal/code"
|
||||
"github.com/httprunner/httprunner/v4/hrp/internal/env"
|
||||
"github.com/httprunner/httprunner/v4/hrp/internal/json"
|
||||
)
|
||||
@@ -106,11 +107,13 @@ func WithPerfOptions(options ...giDevice.PerfOption) IOSDeviceOption {
|
||||
func IOSDevices(udid ...string) (devices []giDevice.Device, err error) {
|
||||
var usbmux giDevice.Usbmux
|
||||
if usbmux, err = giDevice.NewUsbmux(); err != nil {
|
||||
return nil, fmt.Errorf("init usbmux failed: %v", err)
|
||||
return nil, errors.Wrap(code.IOSDeviceConnectionError,
|
||||
fmt.Sprintf("init usbmux failed: %v", err))
|
||||
}
|
||||
|
||||
if devices, err = usbmux.Devices(); err != nil {
|
||||
return nil, fmt.Errorf("list ios devices failed: %v", err)
|
||||
return nil, errors.Wrap(code.IOSDeviceConnectionError,
|
||||
fmt.Sprintf("list ios devices failed: %v", err))
|
||||
}
|
||||
|
||||
// filter by udid
|
||||
@@ -185,7 +188,8 @@ func NewIOSDevice(options ...IOSDeviceOption) (device *IOSDevice, err error) {
|
||||
return device, nil
|
||||
}
|
||||
|
||||
return nil, fmt.Errorf("device %s not found", device.UDID)
|
||||
return nil, errors.Wrap(code.IOSDeviceConnectionError,
|
||||
fmt.Sprintf("device %s not found", device.UDID))
|
||||
}
|
||||
|
||||
type IOSDevice struct {
|
||||
@@ -230,13 +234,15 @@ func (dev *IOSDevice) NewDriver(capabilities Capabilities) (driverExt *DriverExt
|
||||
if dev.ResetHomeOnStartup {
|
||||
log.Info().Msg("go back to home screen")
|
||||
if err = driver.Homescreen(); err != nil {
|
||||
return nil, errors.Wrap(err, "failed to go back to home screen")
|
||||
return nil, errors.Wrap(code.MobileUIDriverError,
|
||||
fmt.Sprintf("go back to home screen failed: %v", err))
|
||||
}
|
||||
}
|
||||
|
||||
driverExt, err = Extend(driver)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "failed to extend WebDriver")
|
||||
return nil, errors.Wrap(code.MobileUIDriverError,
|
||||
fmt.Sprintf("extend WebDriver failed: %v", err))
|
||||
}
|
||||
settings, err := driverExt.Driver.SetAppiumSettings(map[string]interface{}{
|
||||
"snapshotMaxDepth": dev.SnapshotMaxDepth,
|
||||
@@ -380,17 +386,21 @@ func (dev *IOSDevice) perfOpitons() (perfOptions []giDevice.PerfOption) {
|
||||
func (dev *IOSDevice) NewHTTPDriver(capabilities Capabilities) (driver WebDriver, err error) {
|
||||
localPort, err := getFreePort()
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "get free port failed")
|
||||
return nil, errors.Wrap(code.IOSDeviceHTTPDriverError,
|
||||
fmt.Sprintf("get free port failed: %v", err))
|
||||
}
|
||||
if err = dev.forward(localPort, dev.Port); err != nil {
|
||||
return nil, errors.Wrap(err, "forward tcp port failed")
|
||||
return nil, errors.Wrap(code.IOSDeviceHTTPDriverError,
|
||||
fmt.Sprintf("forward tcp port failed: %v", err))
|
||||
}
|
||||
localMjpegPort, err := getFreePort()
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "get free port failed")
|
||||
return nil, errors.Wrap(code.IOSDeviceHTTPDriverError,
|
||||
fmt.Sprintf("get free port failed: %v", err))
|
||||
}
|
||||
if err = dev.forward(localMjpegPort, dev.MjpegPort); err != nil {
|
||||
return nil, errors.Wrap(err, "forward tcp port failed")
|
||||
return nil, errors.Wrap(code.IOSDeviceHTTPDriverError,
|
||||
fmt.Sprintf("forward tcp port failed: %v", err))
|
||||
}
|
||||
|
||||
log.Info().Interface("capabilities", capabilities).
|
||||
@@ -402,11 +412,11 @@ func (dev *IOSDevice) NewHTTPDriver(capabilities Capabilities) (driver WebDriver
|
||||
|
||||
host := "127.0.0.1"
|
||||
if wd.urlPrefix, err = url.Parse(fmt.Sprintf("http://%s:%d", host, localPort)); err != nil {
|
||||
return nil, err
|
||||
return nil, errors.Wrap(code.IOSDeviceHTTPDriverError, err.Error())
|
||||
}
|
||||
var sessionInfo SessionInfo
|
||||
if sessionInfo, err = wd.NewSession(capabilities); err != nil {
|
||||
return nil, err
|
||||
return nil, errors.Wrap(code.IOSDeviceHTTPDriverError, err.Error())
|
||||
}
|
||||
wd.sessionId = sessionInfo.SessionId
|
||||
|
||||
@@ -414,7 +424,7 @@ func (dev *IOSDevice) NewHTTPDriver(capabilities Capabilities) (driver WebDriver
|
||||
"tcp",
|
||||
fmt.Sprintf("%s:%d", host, localMjpegPort),
|
||||
); err != nil {
|
||||
return nil, err
|
||||
return nil, errors.Wrap(code.IOSDeviceHTTPDriverError, err.Error())
|
||||
}
|
||||
wd.mjpegClient = convertToHTTPClient(wd.mjpegHTTPConn)
|
||||
|
||||
@@ -428,23 +438,25 @@ func (dev *IOSDevice) NewUSBDriver(capabilities Capabilities) (driver WebDriver,
|
||||
|
||||
wd := new(wdaDriver)
|
||||
if wd.defaultConn, err = dev.d.NewConnect(dev.Port, 0); err != nil {
|
||||
return nil, fmt.Errorf("connect port %d failed: %w",
|
||||
dev.Port, err)
|
||||
return nil, errors.Wrap(code.IOSDeviceUSBDriverError,
|
||||
fmt.Sprintf("connect port %d failed: %v", dev.Port, err))
|
||||
}
|
||||
wd.client = convertToHTTPClient(wd.defaultConn.RawConn())
|
||||
|
||||
if wd.mjpegUSBConn, err = dev.d.NewConnect(dev.MjpegPort, 0); err != nil {
|
||||
return nil, fmt.Errorf("connect MJPEG port %d failed: %w",
|
||||
dev.MjpegPort, err)
|
||||
return nil, errors.Wrap(code.IOSDeviceUSBDriverError,
|
||||
fmt.Sprintf("connect MJPEG port %d failed: %v", dev.MjpegPort, err))
|
||||
}
|
||||
wd.mjpegClient = convertToHTTPClient(wd.mjpegUSBConn.RawConn())
|
||||
|
||||
if wd.urlPrefix, err = url.Parse("http://" + dev.UDID); err != nil {
|
||||
return nil, err
|
||||
return nil, errors.Wrap(code.IOSDeviceUSBDriverError, err.Error())
|
||||
}
|
||||
if _, err = wd.NewSession(capabilities); err != nil {
|
||||
return nil, errors.Wrap(code.IOSDeviceUSBDriverError, err.Error())
|
||||
}
|
||||
_, err = wd.NewSession(capabilities)
|
||||
|
||||
return wd, err
|
||||
return wd, nil
|
||||
}
|
||||
|
||||
func (dExt *DriverExt) ConnectMjpegStream(httpClient *http.Client) (err error) {
|
||||
|
||||
@@ -858,7 +858,8 @@ func (wd *wdaDriver) StartCaptureLog(identifier ...string) error {
|
||||
data := map[string]interface{}{"action": "start", "type": 2, "identifier": identifier[0]}
|
||||
_, err := wd.triggerWDALog(data)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "failed to start WDA log recording")
|
||||
return errors.Wrap(code.IOSCaptureLogError,
|
||||
fmt.Sprintf("start WDA log recording failed: %v", err))
|
||||
}
|
||||
|
||||
return nil
|
||||
@@ -875,12 +876,14 @@ func (wd *wdaDriver) StopCaptureLog() (result interface{}, err error) {
|
||||
rawResp, err := wd.triggerWDALog(data)
|
||||
if err != nil {
|
||||
log.Error().Err(err).Bytes("rawResp", rawResp).Msg("failed to get WDA logs")
|
||||
return "", errors.Wrap(err, "failed to get WDA logs")
|
||||
return "", errors.Wrap(code.IOSCaptureLogError,
|
||||
fmt.Sprintf("get WDA logs failed: %v", err))
|
||||
}
|
||||
reply := new(wdaResponse)
|
||||
if err = json.Unmarshal(rawResp, reply); err != nil {
|
||||
log.Error().Err(err).Bytes("rawResp", rawResp).Msg("failed to json.Unmarshal WDA logs")
|
||||
return reply, err
|
||||
return reply, errors.Wrap(code.IOSCaptureLogError,
|
||||
fmt.Sprintf("json.Unmarshal WDA logs failed: %v", err))
|
||||
}
|
||||
log.Info().Interface("value", reply.Value).Msg("get WDA log response")
|
||||
return reply.Value, nil
|
||||
|
||||
@@ -560,7 +560,7 @@ func (r *SessionRunner) ParseStepVariables(stepVariables map[string]interface{})
|
||||
if err != nil {
|
||||
log.Error().Interface("variables", r.caseRunner.parsedConfig.Variables).
|
||||
Err(err).Msg("parse step variables failed")
|
||||
return nil, err
|
||||
return nil, errors.Wrap(err, "parse step variables failed")
|
||||
}
|
||||
return parsedVariables, nil
|
||||
}
|
||||
|
||||
@@ -7,6 +7,7 @@ import (
|
||||
"github.com/pkg/errors"
|
||||
"github.com/rs/zerolog/log"
|
||||
|
||||
"github.com/httprunner/httprunner/v4/hrp/internal/code"
|
||||
"github.com/httprunner/httprunner/v4/hrp/pkg/uixt"
|
||||
)
|
||||
|
||||
@@ -609,10 +610,11 @@ func runStepMobileUI(s *SessionRunner, step *TStep) (stepResult *StepResult, err
|
||||
// run actions
|
||||
for _, action := range actions {
|
||||
if action.Params, err = s.caseRunner.parser.Parse(action.Params, stepVariables); err != nil {
|
||||
return stepResult, errors.Wrap(err, "parse action params failed")
|
||||
return stepResult, errors.Wrap(code.ParseError,
|
||||
fmt.Sprintf("parse action params failed: %v", err))
|
||||
}
|
||||
if err := uiDriver.DoAction(action); err != nil {
|
||||
return stepResult, err
|
||||
return stepResult, errors.Wrap(code.MobileUIDriverError, err.Error())
|
||||
}
|
||||
}
|
||||
|
||||
@@ -629,6 +631,7 @@ func runStepMobileUI(s *SessionRunner, step *TStep) (stepResult *StepResult, err
|
||||
// validate
|
||||
validateResults, err := validateUI(uiDriver, step.Validators)
|
||||
if err != nil {
|
||||
err = errors.Wrap(code.MobileUIValidationError, err.Error())
|
||||
return
|
||||
}
|
||||
sessionData := newSessionData()
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
__version__ = "v4.3.0-beta-10172144"
|
||||
__version__ = "v4.3.0-beta-10191154"
|
||||
__description__ = "One-stop solution for HTTP(S) testing."
|
||||
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
[tool.poetry]
|
||||
name = "httprunner"
|
||||
version = "v4.3.0-beta-10172144"
|
||||
version = "v4.3.0-beta-10191154"
|
||||
description = "One-stop solution for HTTP(S) testing."
|
||||
license = "Apache-2.0"
|
||||
readme = "README.md"
|
||||
|
||||
Reference in New Issue
Block a user