diff --git a/internal/version/VERSION b/internal/version/VERSION index e2cd73ae..acc1854a 100644 --- a/internal/version/VERSION +++ b/internal/version/VERSION @@ -1 +1 @@ -v5.0.0+2502182234 +v5.0.0+2502191537 diff --git a/pkg/uixt/android_driver_adb.go b/pkg/uixt/android_driver_adb.go index acd2cb48..7bb66216 100644 --- a/pkg/uixt/android_driver_adb.go +++ b/pkg/uixt/android_driver_adb.go @@ -298,6 +298,9 @@ func (ad *ADBDriver) TapXY(x, y float64, opts ...option.ActionOption) error { } func (ad *ADBDriver) TapAbsXY(x, y float64, opts ...option.ActionOption) error { + actionOptions := option.NewActionOptions(opts...) + x, y = actionOptions.ApplyOffset(x, y) + // adb shell input tap x y xStr := fmt.Sprintf("%.1f", x) yStr := fmt.Sprintf("%.1f", y) @@ -314,6 +317,9 @@ func (ad *ADBDriver) DoubleTapXY(x, y float64, opts ...option.ActionOption) erro if x, y, err = convertToAbsolutePoint(ad, x, y); err != nil { return err } + actionOptions := option.NewActionOptions(opts...) + x, y = actionOptions.ApplyOffset(x, y) + // adb shell input tap x y xStr := fmt.Sprintf("%.1f", x) yStr := fmt.Sprintf("%.1f", y) @@ -333,13 +339,7 @@ func (ad *ADBDriver) DoubleTapXY(x, y float64, opts ...option.ActionOption) erro func (ad *ADBDriver) TouchAndHold(x, y float64, opts ...option.ActionOption) (err error) { actionOptions := option.NewActionOptions(opts...) - - if len(actionOptions.Offset) == 2 { - x += float64(actionOptions.Offset[0]) - y += float64(actionOptions.Offset[1]) - } - x += actionOptions.GetRandomOffset() - y += actionOptions.GetRandomOffset() + x, y = actionOptions.ApplyOffset(x, y) duration := 1000.0 if actionOptions.Duration > 0 { duration = actionOptions.Duration * 1000 diff --git a/pkg/uixt/android_driver_uia2.go b/pkg/uixt/android_driver_uia2.go index 796dc6b8..c095801c 100644 --- a/pkg/uixt/android_driver_uia2.go +++ b/pkg/uixt/android_driver_uia2.go @@ -30,6 +30,10 @@ func NewUIA2Driver(device *AndroidDevice) (*UIA2Driver, error) { if err := driver.Setup(); err != nil { return nil, err } + + // register driver session reset handler + driver.Session.RegisterResetHandler(driver.Setup) + return driver, nil } @@ -246,6 +250,9 @@ func (ud *UIA2Driver) DoubleTapXY(x, y float64, opts ...option.ActionOption) err if x, y, err = convertToAbsolutePoint(ud, x, y); err != nil { return err } + actionOptions := option.NewActionOptions(opts...) + x, y = actionOptions.ApplyOffset(x, y) + data := map[string]interface{}{ "actions": []interface{}{ map[string]interface{}{ @@ -279,6 +286,7 @@ func (ud *UIA2Driver) TapXY(x, y float64, opts ...option.ActionOption) error { func (ud *UIA2Driver) TapAbsXY(x, y float64, opts ...option.ActionOption) error { // register(postHandler, new Tap("/wd/hub/session/:sessionId/appium/tap")) actionOptions := option.NewActionOptions(opts...) + x, y = actionOptions.ApplyOffset(x, y) duration := 100.0 if actionOptions.PressDuration > 0 { @@ -306,8 +314,9 @@ func (ud *UIA2Driver) TapAbsXY(x, y float64, opts ...option.ActionOption) error } func (ud *UIA2Driver) TouchAndHold(x, y float64, opts ...option.ActionOption) (err error) { - actionOpts := option.NewActionOptions(opts...) - duration := actionOpts.Duration + actionOptions := option.NewActionOptions(opts...) + x, y = actionOptions.ApplyOffset(x, y) + duration := actionOptions.Duration if duration == 0 { duration = 1.0 } diff --git a/pkg/uixt/driver_ext/android_stub_driver.go b/pkg/uixt/driver_ext/android_stub_driver.go index dfc2dd4f..aa1258a2 100644 --- a/pkg/uixt/driver_ext/android_stub_driver.go +++ b/pkg/uixt/driver_ext/android_stub_driver.go @@ -45,6 +45,14 @@ func NewStubAndroidDriver(dev *uixt.AndroidDevice) (*StubAndroidDriver, error) { ADBDriver: adbDriver, } + // setup driver + if err := driver.Setup(); err != nil { + return nil, err + } + + // register driver session reset handler + driver.Session.RegisterResetHandler(driver.Setup) + return driver, nil } @@ -268,11 +276,6 @@ func (sad *StubAndroidDriver) LogoutNoneUI(packageName string) error { log.Err(err).Msgf("%v", res) return err } - fmt.Printf("%v", resp) - if err != nil { - return err - } - time.Sleep(3 * time.Second) return nil } diff --git a/pkg/uixt/driver_ext/ios_stub_driver.go b/pkg/uixt/driver_ext/ios_stub_driver.go index f3cfb393..8738c0f6 100644 --- a/pkg/uixt/driver_ext/ios_stub_driver.go +++ b/pkg/uixt/driver_ext/ios_stub_driver.go @@ -44,6 +44,9 @@ func NewStubIOSDriver(dev *uixt.IOSDevice) (*StubIOSDriver, error) { return nil, err } + // register driver session reset handler + driver.Session.RegisterResetHandler(driver.Setup) + return driver, nil } @@ -114,13 +117,11 @@ func (s *StubIOSDriver) Source(srcOpt ...option.SourceOption) (string, error) { func (s *StubIOSDriver) OpenUrl(urlStr string, opts ...option.ActionOption) (err error) { targetUrl := fmt.Sprintf("/openURL?url=%s", url.QueryEscape(urlStr)) - fmt.Sprintln(targetUrl) - resp, err := s.Session.GET(targetUrl) + _, err = s.Session.GET(targetUrl) if err != nil { log.Error().Err(err).Msg("get source err") return nil } - fmt.Sprintln(resp) return nil } diff --git a/pkg/uixt/driver_session.go b/pkg/uixt/driver_session.go index b4d1ece0..031f3727 100644 --- a/pkg/uixt/driver_session.go +++ b/pkg/uixt/driver_session.go @@ -20,7 +20,6 @@ import ( "github.com/rs/zerolog/log" "github.com/httprunner/httprunner/v5/internal/json" - "github.com/httprunner/httprunner/v5/pkg/uixt/option" ) type Attachments map[string]interface{} @@ -61,38 +60,13 @@ type DriverSession struct { timeout time.Duration maxRetry int + // used to reset driver session when request failed + resetFn func() error + // cache driver request and response requests []*DriverRequests } -func (s *DriverSession) Init(capabilities option.Capabilities) (err error) { - data := make(map[string]interface{}) - if len(capabilities) == 0 { - data["capabilities"] = make(map[string]interface{}) - } else { - data["capabilities"] = map[string]interface{}{"alwaysMatch": capabilities} - } - var rawResp DriverRawResponse - if rawResp, err = s.POST(data, "/session"); err != nil { - return err - } - reply := new(struct{ Value struct{ SessionId string } }) - if err = json.Unmarshal(rawResp, reply); err != nil { - return err - } - s.ID = reply.Value.SessionId - - // WDA - // sessionInfo, err := rawResp.ValueConvertToSessionInfo() - // if err != nil { - // return err - // } - // // update session ID - // wd.Session.ID = sessionInfo.ID - - return nil -} - func (s *DriverSession) Reset() { s.requests = make([]*DriverRequests, 0) } @@ -101,6 +75,10 @@ func (s *DriverSession) SetBaseURL(baseUrl string) { s.baseUrl = baseUrl } +func (s *DriverSession) RegisterResetHandler(fn func() error) { + s.resetFn = fn +} + func (s *DriverSession) addRequestResult(driverResult *DriverRequests) { s.requests = append(s.requests, driverResult) } @@ -179,7 +157,7 @@ func (s *DriverSession) GET(pathElem ...string) (rawResp DriverRawResponse, err if err != nil { return nil, err } - return s.Request(http.MethodGet, urlStr, nil) + return s.RequestWithRetry(http.MethodGet, urlStr, nil) } func (s *DriverSession) POST(data interface{}, pathElem ...string) (rawResp DriverRawResponse, err error) { @@ -193,7 +171,7 @@ func (s *DriverSession) POST(data interface{}, pathElem ...string) (rawResp Driv return nil, err } } - return s.Request(http.MethodPost, urlStr, bsJSON) + return s.RequestWithRetry(http.MethodPost, urlStr, bsJSON) } func (s *DriverSession) DELETE(pathElem ...string) (rawResp DriverRawResponse, err error) { @@ -201,7 +179,30 @@ func (s *DriverSession) DELETE(pathElem ...string) (rawResp DriverRawResponse, e if err != nil { return nil, err } - return s.Request(http.MethodDelete, urlStr, nil) + return s.RequestWithRetry(http.MethodDelete, urlStr, nil) +} + +func (s *DriverSession) RequestWithRetry(method string, rawURL string, rawBody []byte) ( + rawResp DriverRawResponse, err error) { + for count := 1; count <= s.maxRetry; count++ { + rawResp, err = s.Request(method, rawURL, rawBody) + if err == nil { + return + } + time.Sleep(3 * time.Second) + + if s.resetFn != nil { + log.Warn().Msg("reset driver session") + if err2 := s.resetFn(); err2 != nil { + log.Error().Err(err2).Msgf( + "failed to reset session, try count %v", count) + } else { + log.Info().Msgf( + "reset session success, try count %v", count) + } + } + } + return } func (s *DriverSession) Request(method string, rawURL string, rawBody []byte) ( @@ -285,30 +286,6 @@ func (s *DriverSession) Request(method string, rawURL string, rawBody []byte) ( return } -// TODO: FIXME -func (s *DriverSession) RequestWithRetry(method string, rawURL string, rawBody []byte) ( - rawResp DriverRawResponse, err error) { - for count := 1; count <= s.maxRetry; count++ { - rawResp, err = s.Request(method, rawURL, rawBody) - if err == nil { - return - } - time.Sleep(3 * time.Second) - oldSessionID := s.ID - if err2 := s.Init(nil); err2 != nil { - log.Error().Err(err2).Msgf( - "failed to reset session, try count %v", count) - continue - } - log.Debug().Str("new session", s.ID).Str("old session", oldSessionID).Msgf( - "reset session successfully, try count %v", count) - if oldSessionID != "" { - rawURL = strings.Replace(rawURL, oldSessionID, s.ID, 1) - } - } - return -} - func (s *DriverSession) SetupPortForward(localPort int) error { conn, err := net.Dial("tcp", fmt.Sprintf("127.0.0.1:%d", localPort)) if err != nil { diff --git a/pkg/uixt/harmony_driver_hdc.go b/pkg/uixt/harmony_driver_hdc.go index e973accd..6be1fa98 100644 --- a/pkg/uixt/harmony_driver_hdc.go +++ b/pkg/uixt/harmony_driver_hdc.go @@ -151,6 +151,7 @@ func (hd *HDCDriver) TapXY(x, y float64, opts ...option.ActionOption) error { func (hd *HDCDriver) TapAbsXY(x, y float64, opts ...option.ActionOption) error { actionOptions := option.NewActionOptions(opts...) + x, y = actionOptions.ApplyOffset(x, y) if actionOptions.Identifier != "" { startTime := int(time.Now().UnixMilli()) diff --git a/pkg/uixt/ios_driver_wda.go b/pkg/uixt/ios_driver_wda.go index 1288d141..85cf4934 100644 --- a/pkg/uixt/ios_driver_wda.go +++ b/pkg/uixt/ios_driver_wda.go @@ -42,6 +42,9 @@ func NewWDADriver(device *IOSDevice) (*WDADriver, error) { return nil, err } + // register driver session reset handler + driver.Session.RegisterResetHandler(driver.Setup) + return driver, nil } @@ -566,6 +569,8 @@ func (wd *WDADriver) TapXY(x, y float64, opts ...option.ActionOption) error { func (wd *WDADriver) TapAbsXY(x, y float64, opts ...option.ActionOption) error { // [[FBRoute POST:@"/wda/tap/:uuid"] respondWithTarget:self action:@selector(handleTap:)] + actionOptions := option.NewActionOptions(opts...) + x, y = actionOptions.ApplyOffset(x, y) data := map[string]interface{}{ "x": wd.toScale(x), "y": wd.toScale(y), @@ -582,6 +587,8 @@ func (wd *WDADriver) DoubleTapXY(x, y float64, opts ...option.ActionOption) erro if x, y, err = convertToAbsolutePoint(wd, x, y); err != nil { return err } + actionOptions := option.NewActionOptions(opts...) + x, y = actionOptions.ApplyOffset(x, y) x = wd.toScale(x) y = wd.toScale(y) @@ -596,6 +603,7 @@ func (wd *WDADriver) DoubleTapXY(x, y float64, opts ...option.ActionOption) erro // FIXME: hold not work func (wd *WDADriver) TouchAndHold(x, y float64, opts ...option.ActionOption) (err error) { actionOptions := option.NewActionOptions(opts...) + x, y = actionOptions.ApplyOffset(x, y) if actionOptions.Duration == 0 { opts = append(opts, option.WithPressDuration(1)) } diff --git a/pkg/uixt/option/action.go b/pkg/uixt/option/action.go index 863f71e7..abd767f1 100644 --- a/pkg/uixt/option/action.go +++ b/pkg/uixt/option/action.go @@ -131,7 +131,17 @@ func (o *ActionOptions) GetScreenOptions() []ActionOption { return o.ScreenOptions.Options() } -func (o *ActionOptions) GetRandomOffset() float64 { +func (o *ActionOptions) ApplyOffset(absX, absY float64) (float64, float64) { + if len(o.Offset) == 2 { + absX += float64(o.Offset[0]) + absY += float64(o.Offset[1]) + } + absX += o.GenerateRandomOffset() + absY += o.GenerateRandomOffset() + return absX, absY +} + +func (o *ActionOptions) GenerateRandomOffset() float64 { if len(o.OffsetRandomRange) != 2 { // invalid offset random range, should be [min, max] return 0 diff --git a/pkg/uixt/option/ios.go b/pkg/uixt/option/ios.go index 34a36244..6fa60692 100644 --- a/pkg/uixt/option/ios.go +++ b/pkg/uixt/option/ios.go @@ -86,10 +86,6 @@ func NewIOSDeviceOptions(opts ...IOSDeviceOption) *IOSDeviceOptions { config.DismissAlertButtonSelector = dismissAlertButtonSelector } - // switch to iOS springboard before init WDA session - // avoid getting stuck when some super app is active such as douyin or wexin - config.ResetHomeOnStartup = true - return config }