From b412fa193b2fa198ada2b126536364490d0420ae Mon Sep 17 00:00:00 2001 From: "lilong.129" Date: Fri, 14 Mar 2025 10:55:46 +0800 Subject: [PATCH] refactor: move uixt ext to EvalTools --- cmd/server.go | 6 +- internal/version/VERSION | 2 +- server/ext/app.go | 62 --- server/ext/context.go | 44 -- server/ext/handler.go | 66 --- server/ext/main.go | 26 - server/ext/model.go | 25 - uixt/driver_ext/android_stub_driver.go | 341 ------------- uixt/driver_ext/android_stub_driver_test.go | 27 - uixt/driver_ext/browser_sub_driver.go | 71 --- uixt/driver_ext/ext.go | 81 --- uixt/driver_ext/ios_stub_driver.go | 518 -------------------- uixt/driver_ext/ios_stub_driver_test.go | 29 -- 13 files changed, 3 insertions(+), 1295 deletions(-) delete mode 100644 server/ext/app.go delete mode 100644 server/ext/context.go delete mode 100644 server/ext/handler.go delete mode 100644 server/ext/main.go delete mode 100644 server/ext/model.go delete mode 100644 uixt/driver_ext/android_stub_driver.go delete mode 100644 uixt/driver_ext/android_stub_driver_test.go delete mode 100644 uixt/driver_ext/browser_sub_driver.go delete mode 100644 uixt/driver_ext/ext.go delete mode 100644 uixt/driver_ext/ios_stub_driver.go delete mode 100644 uixt/driver_ext/ios_stub_driver_test.go diff --git a/cmd/server.go b/cmd/server.go index 052e3739..c3b17855 100644 --- a/cmd/server.go +++ b/cmd/server.go @@ -1,9 +1,8 @@ package cmd import ( + "github.com/httprunner/httprunner/v5/server" "github.com/spf13/cobra" - - server_ext "github.com/httprunner/httprunner/v5/server/ext" ) // serverCmd represents the server command @@ -13,8 +12,7 @@ var serverCmd = &cobra.Command{ Long: `start hrp server, call httprunner by HTTP`, Args: cobra.MinimumNArgs(1), RunE: func(cmd *cobra.Command, args []string) error { - return server_ext.NewExtRouter().Run(port) - // return server.NewRouter().Run(port) + return server.NewRouter().Run(port) }, } diff --git a/internal/version/VERSION b/internal/version/VERSION index 9a33e2ee..d9a653d2 100644 --- a/internal/version/VERSION +++ b/internal/version/VERSION @@ -1 +1 @@ -v5.0.0-beta-2503112242 +v5.0.0-beta-2503141055 diff --git a/server/ext/app.go b/server/ext/app.go deleted file mode 100644 index 233b7d9b..00000000 --- a/server/ext/app.go +++ /dev/null @@ -1,62 +0,0 @@ -package server_ext - -import ( - "fmt" - "os" - - "github.com/gin-gonic/gin" - - "github.com/httprunner/httprunner/v5/server" - "github.com/httprunner/httprunner/v5/uixt" -) - -func (r *RouterExt) installAppHandler(c *gin.Context) { - var appInstallReq AppInstallRequest - if err := c.ShouldBindJSON(&appInstallReq); err != nil { - server.RenderErrorValidateRequest(c, err) - return - } - driver, err := r.GetDriver(c) - if err != nil { - return - } - err = driver.InstallByUrl(appInstallReq.AppUrl) - if err != nil { - server.RenderError(c, err) - return - } - if androidDevice, ok := driver.GetDevice().(*uixt.AndroidDevice); ok { - _ = driver.Home() - if appInstallReq.MappingUrl == "" || appInstallReq.ResourceMappingUrl == "" { - server.RenderSuccess(c, true) - return - } - localMappingPath, err := uixt.DownloadFileByUrl(appInstallReq.MappingUrl) - if err != nil { - server.RenderError(c, err) - } - defer func() { - _ = os.Remove(localMappingPath) - }() - if err = androidDevice.PushFile( - localMappingPath, - fmt.Sprintf("/data/local/tmp/%s_map.txt", appInstallReq.PackageName)); err != nil { - server.RenderError(c, err) - return - } - localResourceMappingPath, err := uixt.DownloadFileByUrl( - appInstallReq.ResourceMappingUrl) - if err != nil { - server.RenderError(c, err) - } - defer func() { - _ = os.Remove(localResourceMappingPath) - }() - if err = androidDevice.PushFile(localResourceMappingPath, - fmt.Sprintf("/data/local/tmp/%s_resmap.txt", appInstallReq.PackageName)); err != nil { - server.RenderError(c, err) - return - } - } - server.RenderSuccess(c, true) -} diff --git a/server/ext/context.go b/server/ext/context.go deleted file mode 100644 index dbf84bb7..00000000 --- a/server/ext/context.go +++ /dev/null @@ -1,44 +0,0 @@ -package server_ext - -import ( - "strings" - - "github.com/gin-gonic/gin" - - "github.com/httprunner/httprunner/v5/server" - "github.com/httprunner/httprunner/v5/uixt" - "github.com/httprunner/httprunner/v5/uixt/ai" - "github.com/httprunner/httprunner/v5/uixt/driver_ext" -) - -func (r *RouterExt) GetDriver(c *gin.Context) (driverExt *driver_ext.StubXTDriver, err error) { - var device uixt.IDevice - var driver driver_ext.IStubDriver - deviceObj, exists := c.Get("device") - if !exists { - device, err = r.GetDevice(c) - if err != nil { - return nil, err - } - } else { - device = deviceObj.(uixt.IDevice) - } - platform := c.Param("platform") - switch strings.ToLower(platform) { - case "android": - driver, err = driver_ext.NewStubAndroidDriver(device.(*uixt.AndroidDevice)) - case "ios": - driver, err = driver_ext.NewStubIOSDriver(device.(*uixt.IOSDevice)) - case "browser": - driver, err = driver_ext.NewStubBrowserDriver(device.(*uixt.BrowserDevice)) - } - if err != nil { - server.RenderErrorInitDriver(c, err) - return - } - - driverExt = driver_ext.NewStubXTDriver(driver, - ai.WithCVService(ai.CVServiceTypeVEDEM)) - c.Set("driver", driverExt) - return driverExt, nil -} diff --git a/server/ext/handler.go b/server/ext/handler.go deleted file mode 100644 index 980b89ee..00000000 --- a/server/ext/handler.go +++ /dev/null @@ -1,66 +0,0 @@ -package server_ext - -import ( - "time" - - "github.com/gin-gonic/gin" - "github.com/rs/zerolog/log" - - "github.com/httprunner/httprunner/v5/server" -) - -func (r *RouterExt) loginHandler(c *gin.Context) { - var loginReq LoginRequest - if err := c.ShouldBindJSON(&loginReq); err != nil { - server.RenderErrorValidateRequest(c, err) - return - } - - driver, err := r.GetDriver(c) - if err != nil { - return - } - info, err := driver.LoginNoneUI( - loginReq.PackageName, loginReq.PhoneNumber, - loginReq.Captcha, loginReq.Password) - if err != nil { - server.RenderError(c, err) - return - } - server.RenderSuccess(c, info) -} - -func (r *RouterExt) logoutHandler(c *gin.Context) { - var logoutReq LogoutRequest - if err := c.ShouldBindJSON(&logoutReq); err != nil { - server.RenderErrorValidateRequest(c, err) - return - } - - driver, err := r.GetDriver(c) - if err != nil { - return - } - err = driver.LogoutNoneUI(logoutReq.PackageName) - if err != nil { - server.RenderError(c, err) - return - } - server.RenderSuccess(c, true) -} - -func (r *RouterExt) sourceHandler(c *gin.Context) { - driver, err := r.GetDriver(c) - if err != nil { - return - } - source, err := driver.Source() - if err != nil { - log.Warn().Err(err).Msg("get source failed") - } - if source == "{}" || source == "" { - time.Sleep(1 * time.Second) - source, err = driver.Source() - } - server.RenderSuccess(c, source) -} diff --git a/server/ext/main.go b/server/ext/main.go deleted file mode 100644 index e53c4cba..00000000 --- a/server/ext/main.go +++ /dev/null @@ -1,26 +0,0 @@ -package server_ext - -import ( - "github.com/httprunner/httprunner/v5/server" -) - -type RouterExt struct { - *server.Router -} - -func NewExtRouter() *RouterExt { - router := &RouterExt{ - Router: server.NewRouter(), - } - router.Init() - return router -} - -func (r *RouterExt) Init() { - apiV1PlatformSerial := r.Group("/api/v1").Group("/:platform").Group("/:serial") - - apiV1PlatformSerial.GET("/stub/source", r.sourceHandler) - apiV1PlatformSerial.POST("/stub/login", r.loginHandler) - apiV1PlatformSerial.POST("/stub/logout", r.logoutHandler) - apiV1PlatformSerial.POST("/app/install", r.installAppHandler) -} diff --git a/server/ext/model.go b/server/ext/model.go deleted file mode 100644 index dcd8adb6..00000000 --- a/server/ext/model.go +++ /dev/null @@ -1,25 +0,0 @@ -package server_ext - -type AppInstallRequest struct { - AppUrl string `json:"appUrl" binding:"required"` - MappingUrl string `json:"mappingUrl"` - ResourceMappingUrl string `json:"resourceMappingUrl"` - PackageName string `json:"packageName"` -} - -type LoginRequest struct { - PackageName string `json:"packageName"` - PhoneNumber string `json:"phoneNumber"` - Captcha string `json:"captcha" binding:"required_without=Password"` - Password string `json:"password" binding:"required_without=Captcha"` -} - -type LogoutRequest struct { - PackageName string `json:"packageName"` -} - -type HttpResponse struct { - Code int `json:"errorCode"` - Message string `json:"errorMsg"` - Result interface{} `json:"result,omitempty"` -} diff --git a/uixt/driver_ext/android_stub_driver.go b/uixt/driver_ext/android_stub_driver.go deleted file mode 100644 index bf838139..00000000 --- a/uixt/driver_ext/android_stub_driver.go +++ /dev/null @@ -1,341 +0,0 @@ -package driver_ext - -import ( - "fmt" - "time" - - "github.com/pkg/errors" - "github.com/rs/zerolog/log" - - "github.com/httprunner/httprunner/v5/code" - "github.com/httprunner/httprunner/v5/internal/json" - "github.com/httprunner/httprunner/v5/uixt" - "github.com/httprunner/httprunner/v5/uixt/option" - "github.com/httprunner/httprunner/v5/uixt/types" -) - -type StubAndroidDriver struct { - *uixt.ADBDriver - - seq int - timeout time.Duration - douyinUrlPrefix string - douyinLiteUrlPrefix string -} - -const ( - StubSocketName = "com.bytest.device" - AndroidDouyinPort = 32316 - AndroidDouyinLitePort = 32792 -) - -type AppLoginInfo struct { - Did string `json:"did,omitempty" yaml:"did,omitempty"` - Uid string `json:"uid,omitempty" yaml:"uid,omitempty"` - IsLogin bool `json:"is_login,omitempty" yaml:"is_login,omitempty"` -} - -func NewStubAndroidDriver(dev *uixt.AndroidDevice) (*StubAndroidDriver, error) { - adbDriver, err := uixt.NewADBDriver(dev) - if err != nil { - return nil, err - } - driver := &StubAndroidDriver{ - timeout: 10 * time.Second, - ADBDriver: adbDriver, - } - - // setup driver - if err = driver.Setup(); err != nil { - return nil, err - } - - return driver, nil -} - -func (sad *StubAndroidDriver) GetDriver() uixt.IDriver { - return sad.ADBDriver -} - -func (sad *StubAndroidDriver) Setup() error { - socketLocalPort, err := sad.Device.Forward(StubSocketName) - if err != nil { - return errors.Wrap(code.DeviceConnectionError, - fmt.Sprintf("forward port %d->%s failed: %v", - socketLocalPort, StubSocketName, err)) - } - - douyinLocalPort, err := sad.Device.Forward(AndroidDouyinPort) - if err != nil { - return errors.Wrap(code.DeviceConnectionError, - fmt.Sprintf("forward port %d->%d failed: %v", - douyinLocalPort, AndroidDouyinPort, err)) - } - sad.douyinUrlPrefix = fmt.Sprintf("http://127.0.0.1:%d", douyinLocalPort) - - douyinLiteLocalPort, err := sad.Device.Forward(AndroidDouyinLitePort) - if err != nil { - return errors.Wrap(code.DeviceConnectionError, - fmt.Sprintf("forward port %d->%d failed: %v", - douyinLiteLocalPort, AndroidDouyinLitePort, err)) - } - sad.douyinLiteUrlPrefix = fmt.Sprintf("http://127.0.0.1:%d", douyinLiteLocalPort) - - return nil -} - -func (sad *StubAndroidDriver) sendCommand(packageName string, cmdType string, params map[string]interface{}) ( - interface{}, error) { - sad.seq++ - packet := map[string]interface{}{ - "Seq": sad.seq, - "Cmd": cmdType, - "v": "", - } - for key, value := range params { - if key == "Cmd" || key == "Seq" { - return "", errors.New("params cannot be Cmd or Seq") - } - packet[key] = value - } - data, err := json.Marshal(packet) - if err != nil { - return nil, err - } - - res, err := sad.Device.RunStubCommand(append(data, '\n'), packageName) - if err != nil { - return nil, err - } - var resultMap map[string]interface{} - if err := json.Unmarshal([]byte(res), &resultMap); err != nil { - return nil, err - } - if resultMap["Error"] != nil { - return nil, fmt.Errorf("failed to call stub command: %s", resultMap["Error"].(string)) - } - - return resultMap["Result"], nil -} - -func (sad *StubAndroidDriver) AppLaunch(packageName string) (err error) { - _ = sad.EnableDevtool(packageName, true) - err = sad.ADBDriver.AppLaunch(packageName) - if err != nil { - return err - } - return nil -} - -func (sad *StubAndroidDriver) Status() (types.DeviceStatus, error) { - app, err := sad.ForegroundInfo() - if err != nil { - return types.DeviceStatus{}, err - } - res, err := sad.sendCommand(app.PackageName, "Hello", nil) - if err != nil { - return types.DeviceStatus{}, err - } - log.Info().Msg(fmt.Sprintf("ping stub result :%v", res)) - return types.DeviceStatus{}, nil -} - -func (sad *StubAndroidDriver) Source(srcOpt ...option.SourceOption) (source string, err error) { - app, err := sad.ForegroundInfo() - if err != nil { - return "", err - } - params := map[string]interface{}{ - "ClassName": "com.bytedance.byteinsight.MockOperator", - "Method": "getLayout", - "RetType": "", - "Args": []string{}, - } - res, err := sad.sendCommand(app.PackageName, "CallStaticMethod", params) - if err != nil { - if app.PackageName == "com.ss.android.ugc.aweme" { - log.Error().Err(err).Msg("failed to get source") - } - return "", nil - } - if res.(string) == "{}" { - res, err = sad.sendCommand(app.PackageName, "CallStaticMethod", params) - if err != nil { - if app.PackageName == "com.ss.android.ugc.aweme" { - log.Error().Err(err).Msg("failed to get source") - } - return "", nil - } - } - return res.(string), nil -} - -func (sad *StubAndroidDriver) LoginNoneUI(packageName, phoneNumber, captcha, password string) ( - info AppLoginInfo, err error) { - app, err := sad.ForegroundInfo() - if err != nil { - return info, err - } - // app.PackageName in ["com.ss.android.ugc.aweme", "com.ss.android.ugc.aweme.lite"] - if app.PackageName == "com.ss.android.ugc.aweme" || app.PackageName == "com.ss.android.ugc.aweme.lite" { - return sad.LoginDouyin(app.PackageName, phoneNumber, captcha, password) - } else if app.PackageName == "com.ss.android.article.video" { - return sad.LoginXigua(app.PackageName, phoneNumber, captcha, password) - } else { - return info, fmt.Errorf("not support app %s", app.PackageName) - } -} - -func (sad *StubAndroidDriver) LoginXigua(packageName, phoneNumber, captcha, password string) ( - info AppLoginInfo, err error) { - loginSchema := "" - if captcha != "" { - loginSchema = fmt.Sprintf("snssdk32://local_channel_autologin?login_type=1&account=%s&smscode=%s", - phoneNumber, captcha) - } else if password != "" { - loginSchema = fmt.Sprintf("snssdk32://local_channel_autologin?login_type=2&account=%s&password=%s", - phoneNumber, password) - } else { - return info, fmt.Errorf("password and capcha is empty") - } - info.IsLogin = true - return info, sad.OpenUrl(loginSchema) -} - -func (sad *StubAndroidDriver) LoginDouyin(packageName, phoneNumber, captcha, password string) ( - info AppLoginInfo, err error) { - - params := map[string]interface{}{ - "phone": phoneNumber, - } - if captcha != "" { - params["captcha"] = captcha - } else if password != "" { - params["password"] = password - } else { - return info, fmt.Errorf("password and capcha is empty") - } - - info, err = sad.getLoginAppInfo(packageName) - if err != nil { - log.Err(err).Msg("failed to get login info") - return info, err - } - if info.Did == "" { - _ = sad.Home() - _ = sad.AppLaunch(packageName) - time.Sleep(20 * time.Second) - } - if info.IsLogin { - _ = sad.LogoutNoneUI(packageName) - } - - urlPrefix, err := sad.getUrlPrefix(packageName) - if err != nil { - return info, err - } - fullUrl := urlPrefix + "/host/login/account/" - resp, err := sad.Session.POST(params, fullUrl) - if err != nil { - return info, err - } - res, err := resp.ValueConvertToJsonObject() - if err != nil { - return info, err - } - log.Info().Msgf("%v", res) - if res["isSuccess"] != true { - err = fmt.Errorf("falied to login %s", res["data"]) - log.Err(err).Msgf("%v", res) - return info, err - } - time.Sleep(20 * time.Second) - info, err = sad.getLoginAppInfo(packageName) - if err != nil || !info.IsLogin { - return info, fmt.Errorf("falied to login %v", info) - } - return info, nil -} - -func (sad *StubAndroidDriver) LogoutNoneUI(packageName string) error { - urlPrefix, err := sad.getUrlPrefix(packageName) - if err != nil { - return err - } - fullUrl := urlPrefix + "/host/logout" - resp, err := sad.Session.GET(fullUrl) - if err != nil { - return err - } - res, err := resp.ValueConvertToJsonObject() - if err != nil { - return err - } - log.Info().Msgf("%v", res) - if res["isSuccess"] != true { - err = fmt.Errorf("falied to logout %s", res["data"]) - log.Err(err).Msgf("%v", res) - return err - } - return nil -} - -func (sad *StubAndroidDriver) EnableDevtool(packageName string, enable bool) error { - urlPrefix, err := sad.getUrlPrefix(packageName) - if err != nil { - return err - } - fullUrl := urlPrefix + "/host/devtool/enable" - params := map[string]interface{}{ - "enable": enable, - } - resp, err := sad.Session.POST(params, fullUrl) - if err != nil { - return err - } - res, err := resp.ValueConvertToJsonObject() - if err != nil { - return err - } - log.Info().Msgf("%v", res) - return nil -} - -func (sad *StubAndroidDriver) getLoginAppInfo(packageName string) (info AppLoginInfo, err error) { - urlPrefix, err := sad.getUrlPrefix(packageName) - if err != nil { - return info, err - } - fullUrl := urlPrefix + "/host/app/info" - resp, err := sad.Session.GET(fullUrl) - if err != nil { - return info, err - } - res, err := resp.ValueConvertToJsonObject() - if err != nil { - return info, err - } - if res["isSuccess"] != true { - err = fmt.Errorf("falied to get app info %s", res["data"]) - log.Err(err).Msgf("%v", res) - return info, err - } - - err = json.Unmarshal([]byte(res["data"].(string)), &info) - if err != nil { - err = fmt.Errorf("falied to parse app info %s", res["data"]) - return - } - return info, nil -} - -func (sad *StubAndroidDriver) getUrlPrefix(packageName string) (urlPrefix string, err error) { - if packageName == "com.ss.android.ugc.aweme" { - urlPrefix = sad.douyinUrlPrefix - } else if packageName == "com.ss.android.ugc.aweme.lite" { - urlPrefix = sad.douyinLiteUrlPrefix - } else { - return "", fmt.Errorf("not support app %s", packageName) - } - return urlPrefix, nil -} diff --git a/uixt/driver_ext/android_stub_driver_test.go b/uixt/driver_ext/android_stub_driver_test.go deleted file mode 100644 index 4f88a8e3..00000000 --- a/uixt/driver_ext/android_stub_driver_test.go +++ /dev/null @@ -1,27 +0,0 @@ -package driver_ext - -import ( - "testing" - - "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/require" - - "github.com/httprunner/httprunner/v5/uixt" -) - -func setupAndroidStubDriver(t *testing.T) *StubAndroidDriver { - device, err := uixt.NewAndroidDevice() - require.Nil(t, err) - device.Options.UIA2 = false - device.Options.LogOn = false - driver, err := NewStubAndroidDriver(device) - require.Nil(t, err) - return driver -} - -func TestAndroidStubDriver_LoginNoneUI(t *testing.T) { - androidStubDriver := setupAndroidStubDriver(t) - info, err := androidStubDriver.LoginNoneUI("com.ss.android.ugc.aweme", "12343418541", "", "im112233") - assert.Nil(t, err) - t.Logf("login info: %+v", info) -} diff --git a/uixt/driver_ext/browser_sub_driver.go b/uixt/driver_ext/browser_sub_driver.go deleted file mode 100644 index c57c7e25..00000000 --- a/uixt/driver_ext/browser_sub_driver.go +++ /dev/null @@ -1,71 +0,0 @@ -package driver_ext - -import ( - "encoding/json" - "net/http" - - "github.com/pkg/errors" - - "github.com/httprunner/httprunner/v5/uixt" - "github.com/httprunner/httprunner/v5/uixt/option" -) - -type StubBrowserDriver struct { - *uixt.BrowserDriver - - sessionId string -} - -func NewStubBrowserDriver(device *uixt.BrowserDevice) (driver *StubBrowserDriver, err error) { - browserDriver, err := uixt.NewBrowserDriver(device) - if err != nil { - return nil, errors.Wrap(err, "create browser session failed") - } - driver = &StubBrowserDriver{ - BrowserDriver: browserDriver, - } - driver.sessionId = device.UUID() - return driver, nil -} - -func (wd *StubBrowserDriver) GetDriver() uixt.IDriver { - return wd.BrowserDriver -} - -// Source Return application elements tree -func (wd *StubBrowserDriver) Source(srcOpt ...option.SourceOption) (string, error) { - resp, err := wd.BrowserDriver.HttpGet(http.MethodGet, wd.sessionId, "stub/source") - if err != nil { - return "", err - } - - jsonData, err := json.Marshal(resp.Data) - if err != nil { - return "", err - } - - return string(jsonData), err -} - -func (wd *StubBrowserDriver) LoginNoneUI(packageName, phoneNumber, captcha, password string) ( - info AppLoginInfo, err error) { - data := map[string]interface{}{ - "url": packageName, - "web_cookie": password, - } - resp, err := wd.HttpPOST(data, wd.sessionId, "stub/login") - if err != nil { - return info, err - } - respdata := resp.Data.(map[string]interface{}) - loginSuccss := AppLoginInfo{ - IsLogin: true, - Uid: respdata["webid"].(string), - Did: password, - } - return loginSuccss, err -} - -func (wd *StubBrowserDriver) LogoutNoneUI(packageName string) error { - return errors.New("not implemented") -} diff --git a/uixt/driver_ext/ext.go b/uixt/driver_ext/ext.go deleted file mode 100644 index 45d525eb..00000000 --- a/uixt/driver_ext/ext.go +++ /dev/null @@ -1,81 +0,0 @@ -package driver_ext - -import ( - "time" - - "github.com/rs/zerolog/log" - - "github.com/httprunner/httprunner/v5/uixt" - "github.com/httprunner/httprunner/v5/uixt/ai" - "github.com/httprunner/httprunner/v5/uixt/option" -) - -var ( - _ IStubDriver = (*StubAndroidDriver)(nil) - _ IStubDriver = (*StubIOSDriver)(nil) - _ IStubDriver = (*StubBrowserDriver)(nil) -) - -type IStubDriver interface { - GetDriver() uixt.IDriver - LoginNoneUI(packageName, phoneNumber, captcha, password string) (info AppLoginInfo, err error) - LogoutNoneUI(packageName string) error -} - -func NewStubXTDriver(stubDriver IStubDriver, opts ...ai.AIServiceOption) *StubXTDriver { - services := ai.NewAIService(opts...) - driverExt := &StubXTDriver{ - XTDriver: &uixt.XTDriver{ - IDriver: stubDriver.GetDriver(), - CVService: services.ICVService, - LLMService: services.ILLMService, - }, - IStubDriver: stubDriver, - } - return driverExt -} - -type StubXTDriver struct { - *uixt.XTDriver - IStubDriver -} - -func (dExt *StubXTDriver) InstallByUrl(url string, opts ...option.InstallOption) error { - appPath, err := uixt.DownloadFileByUrl(url) - if err != nil { - return err - } - err = dExt.Install(appPath, opts...) - if err != nil { - return err - } - return nil -} - -func (dExt *StubXTDriver) Install(filePath string, opts ...option.InstallOption) error { - if _, ok := dExt.GetDevice().(*uixt.AndroidDevice); ok { - stopChan := make(chan struct{}) - go func() { - ticker := time.NewTicker(5 * time.Second) - defer ticker.Stop() - - for { - select { - case <-ticker.C: - go func() { - _ = dExt.TapByOCR("^(.*无视风险安装|正在扫描.*|我知道了|稍后继续|稍后提醒|继续安装|知道了|确定|继续|完成|点击继续安装|继续安装旧版本|替换|.*正在安装|安装|授权本次安装|重新安装|仍要安装|更多详情|我知道了|已了解此应用未经检测.)$", option.WithRegex(true), option.WithIgnoreNotFoundError(true)) - //_ = dExt.IDriver.TapByHierarchy("^(.*无视风险安装|正在扫描.*|我知道了|稍后继续|稍后提醒|继续安装|知道了|确定|继续|完成|点击继续安装|继续安装旧版本|替换|.*正在安装|安装|授权本次安装|重新安装|仍要安装|更多详情|我知道了|已了解此应用未经检测.)$", option.WithRegex(true), option.WithIgnoreNotFoundError(true)) - }() - case <-stopChan: - log.Info().Msg("install complete") - return - } - } - }() - defer func() { - close(stopChan) - }() - } - - return dExt.GetDevice().Install(filePath, opts...) -} diff --git a/uixt/driver_ext/ios_stub_driver.go b/uixt/driver_ext/ios_stub_driver.go deleted file mode 100644 index 6dd7a980..00000000 --- a/uixt/driver_ext/ios_stub_driver.go +++ /dev/null @@ -1,518 +0,0 @@ -package driver_ext - -import ( - "bytes" - "encoding/json" - "fmt" - "net/url" - "time" - - "github.com/httprunner/httprunner/v5/code" - "github.com/httprunner/httprunner/v5/internal/builtin" - "github.com/httprunner/httprunner/v5/uixt" - "github.com/httprunner/httprunner/v5/uixt/option" - "github.com/httprunner/httprunner/v5/uixt/types" - - "github.com/pkg/errors" - "github.com/rs/zerolog/log" -) - -type StubIOSDriver struct { - Device *uixt.IOSDevice - Session *uixt.DriverSession - WDADriver *uixt.WDADriver - timeout time.Duration - douyinUrlPrefix string - douyinLiteUrlPrefix string -} - -const ( - IOSDouyinPort = 32921 - IOSDouyinLitePort = 33461 - defaultBightInsightPort = 8000 -) - -func NewStubIOSDriver(dev *uixt.IOSDevice) (*StubIOSDriver, error) { - driver := &StubIOSDriver{ - Device: dev, - timeout: 10 * time.Second, - Session: uixt.NewDriverSession(), - } - - // setup driver - if err := driver.Setup(); err != nil { - return nil, err - } - - return driver, nil -} - -func (s *StubIOSDriver) SetupWda() (err error) { - if s.WDADriver != nil { - return nil - } - s.WDADriver, err = uixt.NewWDADriver(s.Device) - return err -} - -func (s *StubIOSDriver) GetDriver() uixt.IDriver { - return s.WDADriver -} - -func (s *StubIOSDriver) Setup() error { - localPort, err := s.getLocalPort() - if err != nil { - return err - } - s.Session.SetBaseURL(fmt.Sprintf("http://127.0.0.1:%d", localPort)) - - localDouyinPort, err := builtin.GetFreePort() - if err != nil { - return errors.Wrap(code.DeviceHTTPDriverError, - fmt.Sprintf("get free port failed: %v", err)) - } - if err = s.Device.Forward(localDouyinPort, IOSDouyinPort); err != nil { - return errors.Wrap(code.DeviceHTTPDriverError, - fmt.Sprintf("forward tcp port failed: %v", err)) - } - s.douyinUrlPrefix = fmt.Sprintf("http://127.0.0.1:%d", localDouyinPort) - - localDouyinLitePort, err := builtin.GetFreePort() - if err != nil { - return errors.Wrap(code.DeviceHTTPDriverError, - fmt.Sprintf("get free port failed: %v", err)) - } - if err = s.Device.Forward(localDouyinLitePort, IOSDouyinLitePort); err != nil { - return errors.Wrap(code.DeviceHTTPDriverError, - fmt.Sprintf("forward tcp port failed: %v", err)) - } - s.douyinLiteUrlPrefix = fmt.Sprintf("http://127.0.0.1:%d", localDouyinLitePort) - return nil -} - -func (s *StubIOSDriver) getLocalPort() (int, error) { - localStubPort, err := builtin.GetFreePort() - if err != nil { - return 0, errors.Wrap(code.DeviceHTTPDriverError, - fmt.Sprintf("get free port failed: %v", err)) - } - if err = s.Device.Forward(localStubPort, defaultBightInsightPort); err != nil { - return 0, errors.Wrap(code.DeviceHTTPDriverError, - fmt.Sprintf("forward tcp port failed: %v", err)) - } - return localStubPort, nil -} - -func (s *StubIOSDriver) Source(srcOpt ...option.SourceOption) (string, error) { - resp, err := s.Session.GET("/source?format=json&onlyWeb=false") - if err != nil { - log.Error().Err(err).Msg("get source err") - return "", nil - } - return string(resp), nil -} - -func (s *StubIOSDriver) OpenUrl(urlStr string, opts ...option.ActionOption) (err error) { - targetUrl := fmt.Sprintf("/openURL?url=%s", url.QueryEscape(urlStr)) - _, err = s.Session.GET(targetUrl) - if err != nil { - log.Error().Err(err).Msg("get source err") - return nil - } - return nil -} - -func (s *StubIOSDriver) LoginNoneUI(packageName, phoneNumber, captcha, password string) (info AppLoginInfo, err error) { - appInfo, err := s.ForegroundInfo() - if err != nil { - return info, err - } - if appInfo.BundleId == "com.ss.iphone.ugc.AwemeInhouse" || appInfo.BundleId == "com.ss.iphone.ugc.awemeinhouse.lite" { - return s.LoginDouyin(appInfo.BundleId, phoneNumber, captcha, password) - } else if appInfo.BundleId == "com.ss.iphone.InHouse.article.Video" { - return s.LoginXigua(appInfo.BundleId, phoneNumber, captcha, password) - } else { - return info, fmt.Errorf("not support app") - } -} - -func (s *StubIOSDriver) LoginXigua(packageName, phoneNumber, captcha, password string) (info AppLoginInfo, err error) { - loginSchema := "" - if captcha != "" { - loginSchema = fmt.Sprintf("snssdk32://local_channel_autologin?login_type=1&account=%s&smscode=%s", phoneNumber, captcha) - } else if password != "" { - loginSchema = fmt.Sprintf("snssdk32://local_channel_autologin?login_type=2&account=%s&password=%s", phoneNumber, password) - } else { - return info, fmt.Errorf("password and capcha is empty") - } - info.IsLogin = true - return info, s.OpenUrl(loginSchema) -} - -func (s *StubIOSDriver) LoginDouyin(packageName, phoneNumber, captcha, password string) (info AppLoginInfo, err error) { - params := map[string]interface{}{ - "phone": phoneNumber, - } - if captcha != "" { - params["captcha"] = captcha - } else if password != "" { - params["password"] = password - } else { - return info, fmt.Errorf("password and capcha is empty") - } - urlPrefix, err := s.getUrlPrefix(packageName) - if err != nil { - return info, err - } - fullUrl := urlPrefix + "/host/login/account/" - resp, err := s.Session.POST(params, fullUrl) - if err != nil { - return info, err - } - res, err := resp.ValueConvertToJsonObject() - if err != nil { - return info, err - } - log.Info().Msgf("%v", res) - // {'isSuccess': True, 'data': '登录成功', 'code': 0} - if res["isSuccess"] != true { - err = fmt.Errorf("falied to logout %s", res["data"]) - log.Err(err).Msgf("%v", res) - return info, err - } - time.Sleep(20 * time.Second) - info, err = s.getLoginAppInfo(packageName) - if err != nil || !info.IsLogin { - return info, fmt.Errorf("falied to login %v", info) - } - return info, nil -} - -func (s *StubIOSDriver) LogoutNoneUI(packageName string) error { - urlPrefix, err := s.getUrlPrefix(packageName) - if err != nil { - return err - } - fullUrl := urlPrefix + "/host/loginout/" - resp, err := s.Session.GET(fullUrl) - if err != nil { - return err - } - res, err := resp.ValueConvertToJsonObject() - if err != nil { - return err - } - log.Info().Msgf("%v", res) - if res["isSuccess"] != true { - err = fmt.Errorf("falied to logout %s", res["data"]) - log.Err(err).Msgf("%v", res) - return err - } - time.Sleep(10 * time.Second) - return nil -} - -func (s *StubIOSDriver) EnableDevtool(packageName string, enable bool) (err error) { - urlPrefix, err := s.getUrlPrefix(packageName) - if err != nil { - return err - } - fullUrl := urlPrefix + "/host/devtool/enable" - - params := map[string]interface{}{ - "enable": enable, - } - resp, err := s.Session.POST(params, fullUrl) - if err != nil { - return err - } - res, err := resp.ValueConvertToJsonObject() - if err != nil { - return err - } - log.Info().Msgf("%v", res) - if res["isSuccess"] != true { - err = fmt.Errorf("falied to enable devtool %s", res["data"]) - log.Err(err).Msgf("%v", res) - return err - } - return nil -} - -func (s *StubIOSDriver) getLoginAppInfo(packageName string) (info AppLoginInfo, err error) { - urlPrefix, err := s.getUrlPrefix(packageName) - if err != nil { - return info, err - } - fullUrl := urlPrefix + "/host/app/info/" - - resp, err := s.Session.GET(fullUrl) - if err != nil { - return info, err - } - res, err := resp.ValueConvertToJsonObject() - if err != nil { - return info, err - } - log.Info().Msgf("%v", res) - if res["isSuccess"] != true { - err = fmt.Errorf("falied to get is login %s", res["data"]) - log.Err(err).Msgf("%v", res) - return info, err - } - err = json.Unmarshal([]byte(res["data"].(string)), &info) - if err != nil { - return info, err - } - return info, nil -} - -func (s *StubIOSDriver) getUrlPrefix(packageName string) (urlPrefix string, err error) { - if packageName == "com.ss.iphone.ugc.AwemeInhouse" { - urlPrefix = s.douyinUrlPrefix - } else if packageName == "com.ss.iphone.ugc.awemeinhouse.lite" { - urlPrefix = s.douyinLiteUrlPrefix - } else { - return "", fmt.Errorf("not support app %s", packageName) - } - return urlPrefix, nil -} - -func (s *StubIOSDriver) ScreenShot(opts ...option.ActionOption) (*bytes.Buffer, error) { - if err := s.SetupWda(); err != nil { - return nil, errors.Wrap(code.DeviceHTTPDriverError, err.Error()) - } - return s.WDADriver.ScreenShot(opts...) -} - -func (s *StubIOSDriver) AppLaunch(packageName string) error { - if err := s.SetupWda(); err != nil { - return errors.Wrap(code.DeviceHTTPDriverError, err.Error()) - } - err := s.WDADriver.AppLaunch(packageName) - if err != nil { - return err - } - _ = s.EnableDevtool(packageName, true) - return nil -} - -func (s *StubIOSDriver) GetDevice() uixt.IDevice { - return s.Device -} - -func (s *StubIOSDriver) TearDown() error { - return nil -} - -// session -func (s *StubIOSDriver) InitSession(capabilities option.Capabilities) error { - if err := s.SetupWda(); err != nil { - return errors.Wrap(code.DeviceHTTPDriverError, err.Error()) - } - return s.WDADriver.InitSession(capabilities) -} - -func (s *StubIOSDriver) GetSession() *uixt.DriverSession { - if err := s.SetupWda(); err != nil { - _ = errors.Wrap(code.DeviceHTTPDriverError, err.Error()) - return nil - } - return s.WDADriver.GetSession() -} - -func (s *StubIOSDriver) DeleteSession() error { - if err := s.SetupWda(); err != nil { - return errors.Wrap(code.DeviceHTTPDriverError, err.Error()) - } - return s.WDADriver.DeleteSession() -} - -// device info and status -func (s *StubIOSDriver) Status() (types.DeviceStatus, error) { - if err := s.SetupWda(); err != nil { - return types.DeviceStatus{}, errors.Wrap(code.DeviceHTTPDriverError, err.Error()) - } - return s.WDADriver.Status() -} - -func (s *StubIOSDriver) DeviceInfo() (types.DeviceInfo, error) { - if err := s.SetupWda(); err != nil { - return types.DeviceInfo{}, errors.Wrap(code.DeviceHTTPDriverError, err.Error()) - } - return s.WDADriver.DeviceInfo() -} - -func (s *StubIOSDriver) BatteryInfo() (types.BatteryInfo, error) { - if err := s.SetupWda(); err != nil { - return types.BatteryInfo{}, errors.Wrap(code.DeviceHTTPDriverError, err.Error()) - } - return s.WDADriver.BatteryInfo() -} - -func (s *StubIOSDriver) ForegroundInfo() (types.AppInfo, error) { - if err := s.SetupWda(); err != nil { - return types.AppInfo{}, errors.Wrap(code.DeviceHTTPDriverError, err.Error()) - } - return s.WDADriver.ForegroundInfo() -} - -func (s *StubIOSDriver) WindowSize() (types.Size, error) { - if err := s.SetupWda(); err != nil { - return types.Size{}, errors.Wrap(code.DeviceHTTPDriverError, err.Error()) - } - return s.WDADriver.WindowSize() -} - -func (s *StubIOSDriver) ScreenRecord(opts ...option.ActionOption) (videoPath string, err error) { - if err := s.SetupWda(); err != nil { - return "", errors.Wrap(code.DeviceHTTPDriverError, err.Error()) - } - return s.WDADriver.ScreenRecord(opts...) -} - -func (s *StubIOSDriver) Orientation() (types.Orientation, error) { - if err := s.SetupWda(); err != nil { - return "", errors.Wrap(code.DeviceHTTPDriverError, err.Error()) - } - return s.WDADriver.Orientation() -} - -func (s *StubIOSDriver) Rotation() (types.Rotation, error) { - if err := s.SetupWda(); err != nil { - return types.Rotation{}, errors.Wrap(code.DeviceHTTPDriverError, err.Error()) - } - return s.WDADriver.Rotation() -} - -func (s *StubIOSDriver) SetRotation(rotation types.Rotation) error { - if err := s.SetupWda(); err != nil { - return errors.Wrap(code.DeviceHTTPDriverError, err.Error()) - } - return s.WDADriver.SetRotation(rotation) -} - -func (s *StubIOSDriver) SetIme(ime string) error { - return types.ErrDriverNotImplemented -} - -func (s *StubIOSDriver) Home() error { - if err := s.SetupWda(); err != nil { - return errors.Wrap(code.DeviceHTTPDriverError, err.Error()) - } - return s.WDADriver.Home() -} - -func (s *StubIOSDriver) Unlock() error { - if err := s.SetupWda(); err != nil { - return errors.Wrap(code.DeviceHTTPDriverError, err.Error()) - } - return s.WDADriver.Unlock() -} - -func (s *StubIOSDriver) Back() error { - if err := s.SetupWda(); err != nil { - return errors.Wrap(code.DeviceHTTPDriverError, err.Error()) - } - return s.WDADriver.Back() -} - -func (s *StubIOSDriver) TapXY(x, y float64, opts ...option.ActionOption) error { - if err := s.SetupWda(); err != nil { - return errors.Wrap(code.DeviceHTTPDriverError, err.Error()) - } - return s.WDADriver.TapXY(x, y, opts...) -} - -func (s *StubIOSDriver) TapAbsXY(x, y float64, opts ...option.ActionOption) error { - if err := s.SetupWda(); err != nil { - return errors.Wrap(code.DeviceHTTPDriverError, err.Error()) - } - return s.WDADriver.TapAbsXY(x, y, opts...) -} - -func (s *StubIOSDriver) DoubleTap(x, y float64, opts ...option.ActionOption) error { - if err := s.SetupWda(); err != nil { - return errors.Wrap(code.DeviceHTTPDriverError, err.Error()) - } - return s.WDADriver.DoubleTap(x, y, opts...) -} - -func (s *StubIOSDriver) TouchAndHold(x, y float64, opts ...option.ActionOption) error { - if err := s.SetupWda(); err != nil { - return errors.Wrap(code.DeviceHTTPDriverError, err.Error()) - } - return s.WDADriver.TouchAndHold(x, y, opts...) -} - -func (s *StubIOSDriver) Drag(fromX, fromY, toX, toY float64, opts ...option.ActionOption) error { - if err := s.SetupWda(); err != nil { - return errors.Wrap(code.DeviceHTTPDriverError, err.Error()) - } - return s.WDADriver.Drag(fromX, fromY, toX, toY, opts...) -} - -func (s *StubIOSDriver) Swipe(fromX, fromY, toX, toY float64, opts ...option.ActionOption) error { - if err := s.SetupWda(); err != nil { - return errors.Wrap(code.DeviceHTTPDriverError, err.Error()) - } - return s.WDADriver.Swipe(fromX, fromY, toX, toY, opts...) -} - -func (s *StubIOSDriver) Input(text string, opts ...option.ActionOption) error { - if err := s.SetupWda(); err != nil { - return errors.Wrap(code.DeviceHTTPDriverError, err.Error()) - } - return s.WDADriver.Input(text, opts...) -} - -func (s *StubIOSDriver) Backspace(count int, opts ...option.ActionOption) error { - if err := s.SetupWda(); err != nil { - return errors.Wrap(code.DeviceHTTPDriverError, err.Error()) - } - return s.WDADriver.Backspace(count, opts...) -} - -func (s *StubIOSDriver) AppTerminate(packageName string) (bool, error) { - if err := s.SetupWda(); err != nil { - return false, errors.Wrap(code.DeviceHTTPDriverError, err.Error()) - } - return s.WDADriver.AppTerminate(packageName) -} - -func (s *StubIOSDriver) AppClear(packageName string) error { - if err := s.SetupWda(); err != nil { - return errors.Wrap(code.DeviceHTTPDriverError, err.Error()) - } - return s.WDADriver.AppClear(packageName) -} - -// image related -func (s *StubIOSDriver) PushImage(localPath string) error { - if err := s.SetupWda(); err != nil { - return errors.Wrap(code.DeviceHTTPDriverError, err.Error()) - } - return s.WDADriver.PushImage(localPath) -} - -func (s *StubIOSDriver) ClearImages() error { - if err := s.SetupWda(); err != nil { - return errors.Wrap(code.DeviceHTTPDriverError, err.Error()) - } - return s.WDADriver.ClearImages() -} - -// triggers the log capture and returns the log entries -func (s *StubIOSDriver) StartCaptureLog(identifier ...string) error { - if err := s.SetupWda(); err != nil { - return errors.Wrap(code.DeviceHTTPDriverError, err.Error()) - } - return s.WDADriver.StartCaptureLog(identifier...) -} - -func (s *StubIOSDriver) StopCaptureLog() (interface{}, error) { - if err := s.SetupWda(); err != nil { - return nil, errors.Wrap(code.DeviceHTTPDriverError, err.Error()) - } - return s.WDADriver.StopCaptureLog() -} diff --git a/uixt/driver_ext/ios_stub_driver_test.go b/uixt/driver_ext/ios_stub_driver_test.go deleted file mode 100644 index abeac4c7..00000000 --- a/uixt/driver_ext/ios_stub_driver_test.go +++ /dev/null @@ -1,29 +0,0 @@ -package driver_ext - -import ( - "testing" - - "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/require" - - "github.com/httprunner/httprunner/v5/uixt" - "github.com/httprunner/httprunner/v5/uixt/option" -) - -func setupIOSStubDriver(t *testing.T) *StubIOSDriver { - iOSDevice, err := uixt.NewIOSDevice( - option.WithWDAPort(8700), - option.WithWDAMjpegPort(8800), - option.WithResetHomeOnStartup(false)) - require.Nil(t, err) - iOSStubDriver, err := NewStubIOSDriver(iOSDevice) - require.Nil(t, err) - return iOSStubDriver -} - -func TestIOSStubDriver_LoginNoneUI(t *testing.T) { - iOSStubDriver := setupIOSStubDriver(t) - info, err := iOSStubDriver.LoginNoneUI("com.ss.iphone.ugc.AwemeInhouse", "12343418541", "", "im112233") - assert.Nil(t, err) - t.Logf("login info: %+v", info) -}