mirror of
https://github.com/httprunner/httprunner.git
synced 2026-05-13 17:19:54 +08:00
feat: init device with optional serial, port, mjpeg port
This commit is contained in:
@@ -1,5 +1,9 @@
|
||||
# Release History
|
||||
|
||||
## v4.2.1 (2022-08-23)
|
||||
|
||||
- feat: support iOS UI automation with WebDriverAgent
|
||||
|
||||
## v4.2.0 (2022-08-21)
|
||||
|
||||
**go version**
|
||||
|
||||
1
go.mod
1
go.mod
@@ -38,3 +38,4 @@ require (
|
||||
)
|
||||
|
||||
// replace github.com/httprunner/funplugin => ../funplugin
|
||||
replace github.com/electricbubble/gwda => github.com/debugtalk/gwda v0.0.0-20220823102718-fae698f66992
|
||||
|
||||
4
go.sum
4
go.sum
@@ -93,6 +93,8 @@ github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ3
|
||||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/debugtalk/gwda v0.0.0-20220823102718-fae698f66992 h1:z5dL+1EechBejcrY+zpeGUTuvUDnP6bTWroyhdqwzas=
|
||||
github.com/debugtalk/gwda v0.0.0-20220823102718-fae698f66992/go.mod h1:0kmE3KaUs6RECo+wkeSbmfJjQb/anVphrf3mvFvssJ0=
|
||||
github.com/denisbrodbeck/machineid v1.0.1 h1:geKr9qtkB876mXguW2X6TU4ZynleN6ezuMSRhl4D7AQ=
|
||||
github.com/denisbrodbeck/machineid v1.0.1/go.mod h1:dJUwb7PTidGDeYyUBmXZ2GphQBbjJCrnectwCyxcUSI=
|
||||
github.com/dgraph-io/badger v1.6.0/go.mod h1:zwt7syl517jmP8s94KqSxTlM6IMsdhYy6psNgSztDR4=
|
||||
@@ -101,8 +103,6 @@ github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25Kn
|
||||
github.com/eknkc/amber v0.0.0-20171010120322-cdade1c07385/go.mod h1:0vRUJqYpeSZifjYj7uP3BG/gKcuzL9xWVV/Y+cK33KM=
|
||||
github.com/electricbubble/gidevice v0.6.2 h1:eIeCHH7Xn5fTwnUv3qL8c7L4anKIHtjlTBkgr1LDVTc=
|
||||
github.com/electricbubble/gidevice v0.6.2/go.mod h1:bRHL2M9qgeEKju8KRvKMZUVEg7t5zMnTiG3SJ3QDH5o=
|
||||
github.com/electricbubble/gwda v0.4.0 h1:+Sbi8WRM8sXh0cXpmY97GiWuR1CNQ/v2tsMUyWxlnV4=
|
||||
github.com/electricbubble/gwda v0.4.0/go.mod h1:kyzKpP1/iKJ2i4AxmT8sEmSvB8Pz5NcDVwc/m/Jsg6k=
|
||||
github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
|
||||
github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
|
||||
github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98=
|
||||
|
||||
@@ -29,6 +29,7 @@ type TConfig struct {
|
||||
ParametersSetting *TParamsConfig `json:"parameters_setting,omitempty" yaml:"parameters_setting,omitempty"`
|
||||
ThinkTimeSetting *ThinkTimeConfig `json:"think_time,omitempty" yaml:"think_time,omitempty"`
|
||||
WebSocketSetting *WebSocketConfig `json:"websocket,omitempty" yaml:"websocket,omitempty"`
|
||||
IOS []*IOSConfig `json:"ios,omitempty" yaml:"ios,omitempty"`
|
||||
Timeout float64 `json:"timeout,omitempty" yaml:"timeout,omitempty"` // global timeout in seconds
|
||||
Export []string `json:"export,omitempty" yaml:"export,omitempty"`
|
||||
Weight int `json:"weight,omitempty" yaml:"weight,omitempty"`
|
||||
@@ -90,12 +91,34 @@ func (c *TConfig) SetWeight(weight int) *TConfig {
|
||||
return c
|
||||
}
|
||||
|
||||
func (c *TConfig) SetWebSocket(times, interval, timeout, size int64) {
|
||||
func (c *TConfig) SetWebSocket(times, interval, timeout, size int64) *TConfig {
|
||||
c.WebSocketSetting = &WebSocketConfig{
|
||||
ReconnectionTimes: times,
|
||||
ReconnectionInterval: interval,
|
||||
MaxMessageSize: size,
|
||||
}
|
||||
return c
|
||||
}
|
||||
|
||||
func (c *TConfig) SetIOS(device WDADevice) *TConfig {
|
||||
// each device can have its own settings
|
||||
if device.UDID != "" {
|
||||
c.IOS = append(c.IOS, &IOSConfig{
|
||||
WDADevice: device,
|
||||
})
|
||||
return c
|
||||
}
|
||||
|
||||
// device UDID is not specified ,settings will be shared
|
||||
iosConfig := &IOSConfig{
|
||||
WDADevice: device,
|
||||
}
|
||||
if len(c.IOS) == 0 {
|
||||
c.IOS = append(c.IOS, iosConfig)
|
||||
} else {
|
||||
c.IOS[0] = iosConfig
|
||||
}
|
||||
return c
|
||||
}
|
||||
|
||||
type ThinkTimeConfig struct {
|
||||
|
||||
@@ -12,12 +12,12 @@ import (
|
||||
"time"
|
||||
|
||||
"github.com/gorilla/websocket"
|
||||
"github.com/httprunner/funplugin"
|
||||
"github.com/jinzhu/copier"
|
||||
"github.com/pkg/errors"
|
||||
"github.com/rs/zerolog/log"
|
||||
"golang.org/x/net/http2"
|
||||
|
||||
"github.com/httprunner/funplugin"
|
||||
"github.com/httprunner/httprunner/v4/hrp/internal/builtin"
|
||||
"github.com/httprunner/httprunner/v4/hrp/internal/sdk"
|
||||
)
|
||||
@@ -384,6 +384,14 @@ func (r *testCaseRunner) parseConfig() error {
|
||||
}
|
||||
r.parametersIterator = parametersIterator
|
||||
|
||||
// init iOS WDA clients
|
||||
for _, iosDeviceConfig := range r.parsedConfig.IOS {
|
||||
_, err := r.hrpRunner.InitWDAClient(iosDeviceConfig.WDADevice)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "init iOS WDA client failed")
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
|
||||
@@ -75,8 +75,8 @@ type TStep struct {
|
||||
Rendezvous *Rendezvous `json:"rendezvous,omitempty" yaml:"rendezvous,omitempty"`
|
||||
ThinkTime *ThinkTime `json:"think_time,omitempty" yaml:"think_time,omitempty"`
|
||||
WebSocket *WebSocketAction `json:"websocket,omitempty" yaml:"websocket,omitempty"`
|
||||
Android *AndroidAction `json:"android,omitempty" yaml:"android,omitempty"`
|
||||
IOS *IOSAction `json:"ios,omitempty" yaml:"ios,omitempty"`
|
||||
Android *AndroidStep `json:"android,omitempty" yaml:"android,omitempty"`
|
||||
IOS *IOSStep `json:"ios,omitempty" yaml:"ios,omitempty"`
|
||||
Variables map[string]interface{} `json:"variables,omitempty" yaml:"variables,omitempty"`
|
||||
SetupHooks []string `json:"setup_hooks,omitempty" yaml:"setup_hooks,omitempty"`
|
||||
TeardownHooks []string `json:"teardown_hooks,omitempty" yaml:"teardown_hooks,omitempty"`
|
||||
|
||||
@@ -2,7 +2,7 @@ package hrp
|
||||
|
||||
import "fmt"
|
||||
|
||||
type AndroidAction struct {
|
||||
type AndroidStep struct {
|
||||
MobileAction
|
||||
Serial string `json:"serial,omitempty" yaml:"serial,omitempty"`
|
||||
Actions []MobileAction `json:"actions,omitempty" yaml:"actions,omitempty"`
|
||||
|
||||
@@ -32,9 +32,19 @@ const (
|
||||
dismissAlertButtonSelector = "**/XCUIElementTypeButton[`label IN {'不允许','暂不'}`]"
|
||||
)
|
||||
|
||||
type IOSAction struct {
|
||||
type IOSConfig struct {
|
||||
WDADevice
|
||||
}
|
||||
|
||||
type WDADevice struct {
|
||||
UDID string `json:"udid,omitempty" yaml:"udid,omitempty"`
|
||||
Port int `json:"port,omitempty" yaml:"port,omitempty"`
|
||||
MjpegPort int `json:"mjpeg_port,omitempty" yaml:"mjpeg_port,omitempty"`
|
||||
}
|
||||
|
||||
type IOSStep struct {
|
||||
WDADevice
|
||||
MobileAction
|
||||
UDID string `json:"udid,omitempty" yaml:"udid,omitempty"`
|
||||
Actions []MobileAction `json:"actions,omitempty" yaml:"actions,omitempty"`
|
||||
}
|
||||
|
||||
@@ -318,7 +328,7 @@ func (s *StepIOSValidation) Run(r *SessionRunner) (*StepResult, error) {
|
||||
return runStepIOS(r, s.step)
|
||||
}
|
||||
|
||||
func (r *HRPRunner) InitWDAClient(udid string) (client *wdaClient, err error) {
|
||||
func (r *HRPRunner) InitWDAClient(device WDADevice) (client *wdaClient, err error) {
|
||||
defer func() {
|
||||
if err != nil {
|
||||
return
|
||||
@@ -336,13 +346,24 @@ func (r *HRPRunner) InitWDAClient(udid string) (client *wdaClient, err error) {
|
||||
}()
|
||||
|
||||
// avoid duplicate init
|
||||
if udid == "" && len(r.wdaClients) == 1 {
|
||||
if device.UDID == "" && len(r.wdaClients) == 1 {
|
||||
for _, v := range r.wdaClients {
|
||||
return v, nil
|
||||
}
|
||||
}
|
||||
|
||||
targetDevice, err := getAttachedIOSDevice(udid)
|
||||
// init wda device
|
||||
var options []gwda.DeviceOptions
|
||||
if device.UDID != "" {
|
||||
options = append(options, gwda.WithSerialNumber(device.UDID))
|
||||
}
|
||||
if device.Port != 0 {
|
||||
options = append(options, gwda.WithPort(device.Port))
|
||||
}
|
||||
if device.MjpegPort != 0 {
|
||||
options = append(options, gwda.WithMjpegPort(device.MjpegPort))
|
||||
}
|
||||
targetDevice, err := gwda.NewDevice(options...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -395,30 +416,6 @@ func (r *HRPRunner) InitWDAClient(udid string) (client *wdaClient, err error) {
|
||||
return client, nil
|
||||
}
|
||||
|
||||
func getAttachedIOSDevice(udid string) (*gwda.Device, error) {
|
||||
// get all attached deivces
|
||||
devices, err := gwda.DeviceList()
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "failed to get attached ios devices list")
|
||||
}
|
||||
if len(devices) == 0 {
|
||||
return nil, errors.New("no ios devices attached")
|
||||
}
|
||||
|
||||
if udid == "" {
|
||||
return &devices[0], nil
|
||||
}
|
||||
|
||||
// find device by udid
|
||||
for _, device := range devices {
|
||||
if device.SerialNumber() == udid {
|
||||
return &device, nil
|
||||
}
|
||||
}
|
||||
|
||||
return nil, fmt.Errorf("device %s is not attached", udid)
|
||||
}
|
||||
|
||||
func runStepIOS(r *SessionRunner, step *TStep) (stepResult *StepResult, err error) {
|
||||
stepResult = &StepResult{
|
||||
Name: step.Name,
|
||||
@@ -428,7 +425,7 @@ func runStepIOS(r *SessionRunner, step *TStep) (stepResult *StepResult, err erro
|
||||
}
|
||||
|
||||
// init wdaClient driver
|
||||
wdaClient, err := r.hrpRunner.InitWDAClient(step.IOS.UDID)
|
||||
wdaClient, err := r.hrpRunner.InitWDAClient(step.IOS.WDADevice)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
@@ -70,7 +70,8 @@ func TestIOSAppLaunch(t *testing.T) {
|
||||
|
||||
func TestIOSWeixinLive(t *testing.T) {
|
||||
testCase := &TestCase{
|
||||
Config: NewConfig("ios ui action on 微信直播"),
|
||||
Config: NewConfig("ios ui action on 微信直播").
|
||||
SetIOS(WDADevice{Port: 8700, MjpegPort: 8800}),
|
||||
TestSteps: []IStep{
|
||||
NewStep("启动微信").
|
||||
IOS().
|
||||
|
||||
@@ -764,7 +764,7 @@ func (s *StepRequest) WebSocket() *StepWebSocket {
|
||||
|
||||
// Android creates a new android action
|
||||
func (s *StepRequest) Android() *StepAndroid {
|
||||
s.step.Android = &AndroidAction{}
|
||||
s.step.Android = &AndroidStep{}
|
||||
return &StepAndroid{
|
||||
step: s.step,
|
||||
}
|
||||
@@ -772,7 +772,7 @@ func (s *StepRequest) Android() *StepAndroid {
|
||||
|
||||
// IOS creates a new ios action
|
||||
func (s *StepRequest) IOS() *StepIOS {
|
||||
s.step.IOS = &IOSAction{}
|
||||
s.step.IOS = &IOSStep{}
|
||||
return &StepIOS{
|
||||
step: s.step,
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user