feat: add status code for mobile UI

This commit is contained in:
debugtalk
2022-10-19 11:48:40 +08:00
parent a2f1f7ca0e
commit d8dc3c58c9
11 changed files with 106 additions and 43 deletions

View File

@@ -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,

View File

@@ -1 +1 @@
v4.3.0-beta-10172144
v4.3.0-beta-10191154

View File

@@ -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")
}
}

View File

@@ -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()

View File

@@ -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()

View File

@@ -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) {

View File

@@ -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

View File

@@ -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
}

View File

@@ -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()

View File

@@ -1,4 +1,4 @@
__version__ = "v4.3.0-beta-10172144"
__version__ = "v4.3.0-beta-10191154"
__description__ = "One-stop solution for HTTP(S) testing."

View File

@@ -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"