mirror of
https://github.com/httprunner/httprunner.git
synced 2026-05-20 15:50:47 +08:00
514 lines
14 KiB
Go
514 lines
14 KiB
Go
package driver_ext
|
|
|
|
import (
|
|
"bytes"
|
|
"encoding/json"
|
|
"fmt"
|
|
"github.com/httprunner/httprunner/v5/pkg/uixt/types"
|
|
"net/url"
|
|
"time"
|
|
|
|
"github.com/httprunner/httprunner/v5/code"
|
|
"github.com/httprunner/httprunner/v5/internal/builtin"
|
|
"github.com/httprunner/httprunner/v5/pkg/uixt"
|
|
"github.com/httprunner/httprunner/v5/pkg/uixt/option"
|
|
|
|
"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) 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 string, 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 string, 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 string, 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(duration time.Duration) (videoPath string, err error) {
|
|
if err := s.SetupWda(); err != nil {
|
|
return "", errors.Wrap(code.DeviceHTTPDriverError, err.Error())
|
|
}
|
|
return s.WDADriver.ScreenRecord(duration)
|
|
}
|
|
|
|
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()
|
|
}
|