mirror of
https://github.com/httprunner/httprunner.git
synced 2026-06-26 01:51:29 +08:00
Merge pull request #1653 from httprunner/auto-reset-session
feat: support to reset automatically when crashed
This commit is contained in:
@@ -1,5 +1,9 @@
|
||||
# Release History
|
||||
|
||||
## v4.3.6 (2023-07-24)
|
||||
|
||||
- feat: support to reset driver (or session only) automatically when UIA2 / WDA crashed or WebDriver request failed
|
||||
|
||||
## v4.3.5 (2023-07-23)
|
||||
|
||||
- refactor: send events to Google Analytics 4, replace GA v1
|
||||
|
||||
@@ -6,9 +6,11 @@ import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"net"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
"github.com/rs/zerolog/log"
|
||||
@@ -46,12 +48,10 @@ func NewUIADriver(capabilities Capabilities, urlPrefix string) (driver *uiaDrive
|
||||
driver.client = convertToHTTPClient(conn)
|
||||
|
||||
session, err := driver.NewSession(capabilities)
|
||||
if err == nil {
|
||||
driver.sessionId = session.SessionId
|
||||
} else {
|
||||
log.Warn().Msg(
|
||||
"create UIAutomator session failed, use adb driver instead")
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "create UIAutomator session failed")
|
||||
}
|
||||
driver.sessionId = session.SessionId
|
||||
return driver, nil
|
||||
}
|
||||
|
||||
@@ -83,11 +83,65 @@ func (bs BatteryStatus) String() string {
|
||||
}
|
||||
}
|
||||
|
||||
func (ud *uiaDriver) resetDriver() error {
|
||||
newUIADriver, err := NewUIADriver(NewCapabilities(), ud.urlPrefix.String())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
ud.client = newUIADriver.client
|
||||
ud.sessionId = newUIADriver.sessionId
|
||||
return nil
|
||||
}
|
||||
|
||||
func (ud *uiaDriver) httpRequest(method string, rawURL string, rawBody []byte, disableRetry ...bool) (rawResp rawResponse, err error) {
|
||||
disableRetryBool := len(disableRetry) > 0 && disableRetry[0]
|
||||
for retryCount := 1; retryCount <= 5; retryCount++ {
|
||||
rawResp, err = ud.Driver.httpRequest(method, rawURL, rawBody)
|
||||
if err == nil || disableRetryBool {
|
||||
return
|
||||
}
|
||||
// wait for UIA2 server to resume automatically
|
||||
time.Sleep(3 * time.Second)
|
||||
oldSessionID := ud.sessionId
|
||||
if err = ud.resetDriver(); err != nil {
|
||||
log.Err(err).Msgf("failed to reset uia2 driver, retry count: %v", retryCount)
|
||||
continue
|
||||
}
|
||||
log.Debug().Str("new session", ud.sessionId).Str("old session", oldSessionID).Msgf("successful to reset uia2 driver, retry count: %v", retryCount)
|
||||
if oldSessionID != "" {
|
||||
rawURL = strings.Replace(rawURL, oldSessionID, ud.sessionId, 1)
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func (ud *uiaDriver) httpGET(pathElem ...string) (rawResp rawResponse, err error) {
|
||||
return ud.httpRequest(http.MethodGet, ud.concatURL(nil, pathElem...), nil)
|
||||
}
|
||||
|
||||
func (ud *uiaDriver) httpGETWithRetry(pathElem ...string) (rawResp rawResponse, err error) {
|
||||
return ud.httpRequest(http.MethodGet, ud.concatURL(nil, pathElem...), nil, true)
|
||||
}
|
||||
|
||||
func (ud *uiaDriver) httpPOST(data interface{}, pathElem ...string) (rawResp rawResponse, err error) {
|
||||
var bsJSON []byte = nil
|
||||
if data != nil {
|
||||
if bsJSON, err = json.Marshal(data); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
return ud.httpRequest(http.MethodPost, ud.concatURL(nil, pathElem...), bsJSON)
|
||||
}
|
||||
|
||||
func (ud *uiaDriver) httpDELETE(pathElem ...string) (rawResp rawResponse, err error) {
|
||||
return ud.httpRequest(http.MethodDelete, ud.concatURL(nil, pathElem...), nil)
|
||||
}
|
||||
|
||||
func (ud *uiaDriver) NewSession(capabilities Capabilities) (sessionInfo SessionInfo, err error) {
|
||||
// register(postHandler, new NewSession("/wd/hub/session"))
|
||||
var rawResp rawResponse
|
||||
data := map[string]interface{}{"capabilities": capabilities}
|
||||
if rawResp, err = ud.httpPOST(data, "/session"); err != nil {
|
||||
if rawResp, err = ud.Driver.httpPOST(data, "/session"); err != nil {
|
||||
return SessionInfo{SessionId: ""}, err
|
||||
}
|
||||
reply := new(struct{ Value struct{ SessionId string } })
|
||||
|
||||
@@ -484,11 +484,15 @@ func (dev *IOSDevice) forward(localPort, remotePort int) error {
|
||||
go func(lConn, rConn net.Conn) {
|
||||
if _, err := io.Copy(lConn, rConn); err != nil {
|
||||
log.Error().Err(err).Msg("copy local -> remote")
|
||||
rConn.Close()
|
||||
accept.Close()
|
||||
}
|
||||
}(lConn, rConn)
|
||||
go func(lConn, rConn net.Conn) {
|
||||
if _, err := io.Copy(rConn, lConn); err != nil {
|
||||
log.Error().Err(err).Msg("copy local <- remote")
|
||||
rConn.Close()
|
||||
accept.Close()
|
||||
}
|
||||
}(lConn, rConn)
|
||||
}(accept)
|
||||
@@ -660,9 +664,11 @@ func (dev *IOSDevice) NewUSBDriver(capabilities Capabilities) (driver WebDriver,
|
||||
if wd.urlPrefix, err = url.Parse("http://" + dev.UDID); err != nil {
|
||||
return nil, errors.Wrap(code.IOSDeviceUSBDriverError, err.Error())
|
||||
}
|
||||
if _, err = wd.NewSession(capabilities); err != nil {
|
||||
var sessionInfo SessionInfo
|
||||
if sessionInfo, err = wd.NewSession(capabilities); err != nil {
|
||||
return nil, errors.Wrap(code.IOSDeviceUSBDriverError, err.Error())
|
||||
}
|
||||
wd.sessionId = sessionInfo.SessionId
|
||||
|
||||
// init WDA scale
|
||||
if wd.scale, err = wd.Scale(); err != nil {
|
||||
|
||||
@@ -10,6 +10,7 @@ import (
|
||||
"net/url"
|
||||
"regexp"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
"github.com/rs/zerolog/log"
|
||||
@@ -31,6 +32,62 @@ type wdaDriver struct {
|
||||
mjpegClient *http.Client
|
||||
}
|
||||
|
||||
func (wd *wdaDriver) resetSession() error {
|
||||
capabilities := NewCapabilities()
|
||||
capabilities.WithDefaultAlertAction(AlertActionAccept)
|
||||
|
||||
sessionInfo, err := wd.NewSession(capabilities)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
wd.sessionId = sessionInfo.SessionId
|
||||
return nil
|
||||
}
|
||||
|
||||
func (wd *wdaDriver) httpRequest(method string, rawURL string, rawBody []byte, disableRetry ...bool) (rawResp rawResponse, err error) {
|
||||
disableRetryBool := len(disableRetry) > 0 && disableRetry[0]
|
||||
for retryCount := 1; retryCount <= 5; retryCount++ {
|
||||
rawResp, err = wd.Driver.httpRequest(method, rawURL, rawBody)
|
||||
if err == nil || disableRetryBool {
|
||||
return
|
||||
}
|
||||
// TODO: polling WDA to check if resumed automatically
|
||||
time.Sleep(5 * time.Second)
|
||||
oldSessionID := wd.sessionId
|
||||
if err = wd.resetSession(); err != nil {
|
||||
log.Err(err).Msgf("failed to reset wda driver, retry count: %v", retryCount)
|
||||
continue
|
||||
}
|
||||
log.Debug().Str("new session", wd.sessionId).Str("old session", oldSessionID).Msgf("successful to reset wda driver, retry count: %v", retryCount)
|
||||
if oldSessionID != "" {
|
||||
rawURL = strings.Replace(rawURL, oldSessionID, wd.sessionId, 1)
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func (wd *wdaDriver) httpGET(pathElem ...string) (rawResp rawResponse, err error) {
|
||||
return wd.httpRequest(http.MethodGet, wd.concatURL(nil, pathElem...), nil)
|
||||
}
|
||||
|
||||
func (wd *wdaDriver) httpGETWithRetry(pathElem ...string) (rawResp rawResponse, err error) {
|
||||
return wd.httpRequest(http.MethodGet, wd.concatURL(nil, pathElem...), nil, true)
|
||||
}
|
||||
|
||||
func (wd *wdaDriver) httpPOST(data interface{}, pathElem ...string) (rawResp rawResponse, err error) {
|
||||
var bsJSON []byte = nil
|
||||
if data != nil {
|
||||
if bsJSON, err = json.Marshal(data); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
return wd.httpRequest(http.MethodPost, wd.concatURL(nil, pathElem...), bsJSON)
|
||||
}
|
||||
|
||||
func (wd *wdaDriver) httpDELETE(pathElem ...string) (rawResp rawResponse, err error) {
|
||||
return wd.httpRequest(http.MethodDelete, wd.concatURL(nil, pathElem...), nil)
|
||||
}
|
||||
|
||||
func (wd *wdaDriver) GetMjpegClient() *http.Client {
|
||||
return wd.mjpegClient
|
||||
}
|
||||
@@ -45,13 +102,12 @@ func (wd *wdaDriver) NewSession(capabilities Capabilities) (sessionInfo SessionI
|
||||
}
|
||||
|
||||
var rawResp rawResponse
|
||||
if rawResp, err = wd.httpPOST(data, "/session"); err != nil {
|
||||
if rawResp, err = wd.Driver.httpPOST(data, "/session"); err != nil {
|
||||
return SessionInfo{}, err
|
||||
}
|
||||
if sessionInfo, err = rawResp.valueConvertToSessionInfo(); err != nil {
|
||||
return SessionInfo{}, err
|
||||
}
|
||||
wd.sessionId = sessionInfo.SessionId
|
||||
return
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user