From 1b18976620a541bb802a0a3735a38e20695cec0b Mon Sep 17 00:00:00 2001 From: "lilong.129" Date: Wed, 19 Feb 2025 10:55:56 +0800 Subject: [PATCH 1/3] feat: ApplyOffset for tap xy --- internal/version/VERSION | 2 +- pkg/uixt/android_driver_adb.go | 14 +++++++------- pkg/uixt/android_driver_uia2.go | 9 +++++++-- pkg/uixt/driver_ext/ios_stub_driver.go | 4 +--- pkg/uixt/harmony_driver_hdc.go | 1 + pkg/uixt/ios_driver_wda.go | 5 +++++ pkg/uixt/option/action.go | 12 +++++++++++- 7 files changed, 33 insertions(+), 14 deletions(-) diff --git a/internal/version/VERSION b/internal/version/VERSION index e2cd73ae..f678a59d 100644 --- a/internal/version/VERSION +++ b/internal/version/VERSION @@ -1 +1 @@ -v5.0.0+2502182234 +v5.0.0+2502191055 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..6b17ded1 100644 --- a/pkg/uixt/android_driver_uia2.go +++ b/pkg/uixt/android_driver_uia2.go @@ -246,6 +246,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 +282,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 +310,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/ios_stub_driver.go b/pkg/uixt/driver_ext/ios_stub_driver.go index c4d27e57..11f9f382 100644 --- a/pkg/uixt/driver_ext/ios_stub_driver.go +++ b/pkg/uixt/driver_ext/ios_stub_driver.go @@ -106,13 +106,11 @@ func (s *StubIOSDriver) Source(srcOpt ...option.SourceOption) (string, error) { func (s *StubIOSDriver) OpenUrl(urlStr string, options ...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/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..ffeb576d 100644 --- a/pkg/uixt/ios_driver_wda.go +++ b/pkg/uixt/ios_driver_wda.go @@ -566,6 +566,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 +584,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 +600,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 From 9f0319660143ef38dfe9b8cc5f13164d82d997a7 Mon Sep 17 00:00:00 2001 From: "lilong.129" Date: Wed, 19 Feb 2025 14:16:23 +0800 Subject: [PATCH 2/3] fix: remove ResetHomeOnStartup --- internal/version/VERSION | 2 +- pkg/uixt/option/ios.go | 4 ---- 2 files changed, 1 insertion(+), 5 deletions(-) diff --git a/internal/version/VERSION b/internal/version/VERSION index f678a59d..02a74b81 100644 --- a/internal/version/VERSION +++ b/internal/version/VERSION @@ -1 +1 @@ -v5.0.0+2502191055 +v5.0.0+2502191416 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 } From bf78e6702aa9411b1651613e2db58bec2075a352 Mon Sep 17 00:00:00 2001 From: "lilong.129" Date: Wed, 19 Feb 2025 15:37:52 +0800 Subject: [PATCH 3/3] feat: add RequestWithRetry for DriverSession --- internal/version/VERSION | 2 +- pkg/uixt/android_driver_uia2.go | 4 + pkg/uixt/driver_ext/android_stub_driver.go | 13 ++-- pkg/uixt/driver_ext/ios_stub_driver.go | 3 + pkg/uixt/driver_session.go | 89 ++++++++-------------- pkg/uixt/ios_driver_wda.go | 3 + 6 files changed, 52 insertions(+), 62 deletions(-) diff --git a/internal/version/VERSION b/internal/version/VERSION index 02a74b81..acc1854a 100644 --- a/internal/version/VERSION +++ b/internal/version/VERSION @@ -1 +1 @@ -v5.0.0+2502191416 +v5.0.0+2502191537 diff --git a/pkg/uixt/android_driver_uia2.go b/pkg/uixt/android_driver_uia2.go index 6b17ded1..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 } diff --git a/pkg/uixt/driver_ext/android_stub_driver.go b/pkg/uixt/driver_ext/android_stub_driver.go index dde8f912..5d13964d 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 } @@ -272,11 +280,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 11f9f382..2a330882 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 } 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/ios_driver_wda.go b/pkg/uixt/ios_driver_wda.go index ffeb576d..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 }