mirror of
https://github.com/httprunner/httprunner.git
synced 2026-09-05 15:37:35 +08:00
Merge pull request #1629 from httprunner/ios-pcap
- feat: log step elapsed in seconds - feat: log uixt action elapsed in seconds - change: log elapsed seconds for shell execution - refactor: raise adb error
This commit is contained in:
@@ -61,9 +61,10 @@ var (
|
|||||||
|
|
||||||
// android device related: [60, 70)
|
// android device related: [60, 70)
|
||||||
var (
|
var (
|
||||||
AndroidDeviceConnectionError = errors.New("android device connection error") // 60
|
AndroidDeviceConnectionError = errors.New("android device general connection error") // 60
|
||||||
AndroidDeviceUSBDriverError = errors.New("android device USB driver error") // 61
|
AndroidDeviceConnectionRefusedError = errors.New("android device connection refused") // 61
|
||||||
AndroidShellExecError = errors.New("android adb shell exec error") // 62
|
AndroidShellExecError = errors.New("android adb shell exec error") // 62
|
||||||
|
AndroidDeviceOfflineError = errors.New("android device offline") // 63
|
||||||
AndroidScreenShotError = errors.New("android screenshot error") // 65
|
AndroidScreenShotError = errors.New("android screenshot error") // 65
|
||||||
AndroidCaptureLogError = errors.New("android capture log error") // 66
|
AndroidCaptureLogError = errors.New("android capture log error") // 66
|
||||||
)
|
)
|
||||||
@@ -128,8 +129,9 @@ var errorsMap = map[error]int{
|
|||||||
|
|
||||||
// android related
|
// android related
|
||||||
AndroidDeviceConnectionError: 60,
|
AndroidDeviceConnectionError: 60,
|
||||||
AndroidDeviceUSBDriverError: 61,
|
AndroidDeviceConnectionRefusedError: 61,
|
||||||
AndroidShellExecError: 62,
|
AndroidShellExecError: 62,
|
||||||
|
AndroidDeviceOfflineError: 63,
|
||||||
AndroidScreenShotError: 65,
|
AndroidScreenShotError: 65,
|
||||||
AndroidCaptureLogError: 66,
|
AndroidCaptureLogError: 66,
|
||||||
|
|
||||||
|
|||||||
@@ -1 +1 @@
|
|||||||
v4.3.4-beta-2306212230
|
v4.3.4-beta-2306282100
|
||||||
+10
-4
@@ -5,7 +5,10 @@ import (
|
|||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
|
"github.com/pkg/errors"
|
||||||
"github.com/rs/zerolog/log"
|
"github.com/rs/zerolog/log"
|
||||||
|
|
||||||
|
"github.com/httprunner/httprunner/v4/hrp/internal/code"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
@@ -84,6 +87,12 @@ func (c Client) DeviceSerialList() (serials []string, err error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (c Client) DeviceList() (devices []*Device, err error) {
|
func (c Client) DeviceList() (devices []*Device, err error) {
|
||||||
|
defer func() {
|
||||||
|
if err != nil && errors.Cause(err) == nil {
|
||||||
|
err = errors.Wrap(code.AndroidDeviceConnectionError, err.Error())
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
|
||||||
var resp string
|
var resp string
|
||||||
if resp, err = c.executeCommand("host:devices-l"); err != nil {
|
if resp, err = c.executeCommand("host:devices-l"); err != nil {
|
||||||
return
|
return
|
||||||
@@ -212,10 +221,7 @@ func (c Client) executeCommand(command string, onlyVerifyResponse ...bool) (resp
|
|||||||
}
|
}
|
||||||
defer func() { _ = tp.Close() }()
|
defer func() { _ = tp.Close() }()
|
||||||
|
|
||||||
if err = tp.Send(command); err != nil {
|
if err = tp.SendWithCheck(command); err != nil {
|
||||||
return "", err
|
|
||||||
}
|
|
||||||
if err = tp.VerifyResponse(); err != nil {
|
|
||||||
return "", err
|
return "", err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+25
-53
@@ -7,11 +7,18 @@ import (
|
|||||||
"testing"
|
"testing"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestClient_ServerVersion(t *testing.T) {
|
var adbClient Client
|
||||||
adbClient, err := NewClient()
|
|
||||||
|
func setupClient(t *testing.T) {
|
||||||
|
var err error
|
||||||
|
adbClient, err = NewClient()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestClient_ServerVersion(t *testing.T) {
|
||||||
|
setupClient(t)
|
||||||
|
|
||||||
adbServerVersion, err := adbClient.ServerVersion()
|
adbServerVersion, err := adbClient.ServerVersion()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -22,10 +29,7 @@ func TestClient_ServerVersion(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestClient_DeviceSerialList(t *testing.T) {
|
func TestClient_DeviceSerialList(t *testing.T) {
|
||||||
adbClient, err := NewClient()
|
setupClient(t)
|
||||||
if err != nil {
|
|
||||||
t.Fatal(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
serials, err := adbClient.DeviceSerialList()
|
serials, err := adbClient.DeviceSerialList()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -38,15 +42,7 @@ func TestClient_DeviceSerialList(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestClient_DeviceList(t *testing.T) {
|
func TestClient_DeviceList(t *testing.T) {
|
||||||
adbClient, err := NewClient()
|
setupDevices(t)
|
||||||
if err != nil {
|
|
||||||
t.Fatal(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
devices, err := adbClient.DeviceList()
|
|
||||||
if err != nil {
|
|
||||||
t.Fatal(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
for i := range devices {
|
for i := range devices {
|
||||||
t.Log(devices[i].serial, devices[i].DeviceInfo())
|
t.Log(devices[i].serial, devices[i].DeviceInfo())
|
||||||
@@ -54,10 +50,7 @@ func TestClient_DeviceList(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestClient_ForwardList(t *testing.T) {
|
func TestClient_ForwardList(t *testing.T) {
|
||||||
adbClient, err := NewClient()
|
setupClient(t)
|
||||||
if err != nil {
|
|
||||||
t.Fatal(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
deviceForwardList, err := adbClient.ForwardList()
|
deviceForwardList, err := adbClient.ForwardList()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -70,76 +63,54 @@ func TestClient_ForwardList(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestClient_ForwardKillAll(t *testing.T) {
|
func TestClient_ForwardKillAll(t *testing.T) {
|
||||||
adbClient, err := NewClient()
|
setupClient(t)
|
||||||
if err != nil {
|
|
||||||
t.Fatal(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
err = adbClient.ForwardKillAll()
|
err := adbClient.ForwardKillAll()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestClient_Connect(t *testing.T) {
|
func TestClient_Connect(t *testing.T) {
|
||||||
adbClient, err := NewClient()
|
setupClient(t)
|
||||||
if err != nil {
|
|
||||||
t.Fatal(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
err = adbClient.Connect("192.168.1.28")
|
err := adbClient.Connect("192.168.1.28")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestClient_Disconnect(t *testing.T) {
|
func TestClient_Disconnect(t *testing.T) {
|
||||||
adbClient, err := NewClient()
|
setupClient(t)
|
||||||
if err != nil {
|
|
||||||
t.Fatal(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
err = adbClient.Disconnect("192.168.1.28")
|
err := adbClient.Disconnect("192.168.1.28")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestClient_DisconnectAll(t *testing.T) {
|
func TestClient_DisconnectAll(t *testing.T) {
|
||||||
adbClient, err := NewClient()
|
setupClient(t)
|
||||||
if err != nil {
|
|
||||||
t.Fatal(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
err = adbClient.DisconnectAll()
|
err := adbClient.DisconnectAll()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestClient_KillServer(t *testing.T) {
|
func TestClient_KillServer(t *testing.T) {
|
||||||
adbClient, err := NewClient()
|
setupClient(t)
|
||||||
if err != nil {
|
|
||||||
t.Fatal(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
err = adbClient.KillServer()
|
err := adbClient.KillServer()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestScreenCap(t *testing.T) {
|
func TestScreenCap(t *testing.T) {
|
||||||
adbClient, err := NewClient()
|
setupDevices(t)
|
||||||
if err != nil {
|
|
||||||
t.Fatal(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
dl, err := adbClient.DeviceList()
|
for _, d := range devices {
|
||||||
if err != nil {
|
|
||||||
t.Error(err)
|
|
||||||
}
|
|
||||||
d := dl[0]
|
|
||||||
res, err := d.ScreenCap()
|
res, err := d.ScreenCap()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Error(err)
|
t.Error(err)
|
||||||
@@ -147,3 +118,4 @@ func TestScreenCap(t *testing.T) {
|
|||||||
t.Log(len(res))
|
t.Log(len(res))
|
||||||
ioutil.WriteFile("/tmp/1.png", res, 0o644)
|
ioutil.WriteFile("/tmp/1.png", res, 0o644)
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|||||||
+35
-51
@@ -36,11 +36,17 @@ const (
|
|||||||
StateOnline DeviceState = "online"
|
StateOnline DeviceState = "online"
|
||||||
StateOffline DeviceState = "offline"
|
StateOffline DeviceState = "offline"
|
||||||
StateDisconnected DeviceState = "disconnected"
|
StateDisconnected DeviceState = "disconnected"
|
||||||
|
StateBootloader DeviceState = "bootloader"
|
||||||
|
StateRecovery DeviceState = "recovery"
|
||||||
|
StateUnauthorized DeviceState = "unauthorized"
|
||||||
)
|
)
|
||||||
|
|
||||||
var deviceStateStrings = map[string]DeviceState{
|
var deviceStateStrings = map[string]DeviceState{
|
||||||
"": StateDisconnected,
|
"": StateDisconnected, // no devices/emulators found
|
||||||
"offline": StateOffline,
|
"offline": StateOffline,
|
||||||
|
"bootloader": StateBootloader,
|
||||||
|
"recovery": StateRecovery,
|
||||||
|
"unauthorized": StateUnauthorized,
|
||||||
"device": StateOnline,
|
"device": StateOnline,
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -245,13 +251,10 @@ func (d *Device) ReverseForwardKillAll() error {
|
|||||||
|
|
||||||
func (d *Device) RunShellCommand(cmd string, args ...string) (string, error) {
|
func (d *Device) RunShellCommand(cmd string, args ...string) (string, error) {
|
||||||
raw, err := d.RunShellCommandWithBytes(cmd, args...)
|
raw, err := d.RunShellCommandWithBytes(cmd, args...)
|
||||||
if err != nil {
|
if err != nil && errors.Cause(err) == nil {
|
||||||
if errors.Is(err, code.AndroidDeviceConnectionError) {
|
err = errors.Wrap(code.AndroidShellExecError, err.Error())
|
||||||
return "", err
|
|
||||||
}
|
}
|
||||||
return "", errors.Wrap(code.AndroidShellExecError, err.Error())
|
return string(raw), err
|
||||||
}
|
|
||||||
return string(raw), nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (d *Device) RunShellCommandWithBytes(cmd string, args ...string) ([]byte, error) {
|
func (d *Device) RunShellCommandWithBytes(cmd string, args ...string) ([]byte, error) {
|
||||||
@@ -264,15 +267,20 @@ func (d *Device) RunShellCommandWithBytes(cmd string, args ...string) ([]byte, e
|
|||||||
if strings.TrimSpace(cmd) == "" {
|
if strings.TrimSpace(cmd) == "" {
|
||||||
return nil, errors.New("adb shell: command cannot be empty")
|
return nil, errors.New("adb shell: command cannot be empty")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
startTime := time.Now()
|
||||||
|
defer func() {
|
||||||
|
// log elapsed seconds for shell execution
|
||||||
|
log.Debug().Str("cmd",
|
||||||
|
fmt.Sprintf("adb -s %s shell %s", d.serial, cmd)).
|
||||||
|
Float64("elapsed(s)", time.Since(startTime).Seconds()).
|
||||||
|
Msg("run adb shell")
|
||||||
|
}()
|
||||||
|
|
||||||
raw, err := d.executeCommand(fmt.Sprintf("shell:%s", cmd))
|
raw, err := d.executeCommand(fmt.Sprintf("shell:%s", cmd))
|
||||||
return raw, err
|
return raw, err
|
||||||
}
|
}
|
||||||
|
|
||||||
func (d *Device) RunShellCommandV2(cmd string, args ...string) (string, error) {
|
|
||||||
raw, err := d.RunShellCommandV2WithBytes(cmd, args...)
|
|
||||||
return string(raw), err
|
|
||||||
}
|
|
||||||
|
|
||||||
// RunShellCommandV2WithBytes shell v2, 支持后台运行而不会阻断
|
// RunShellCommandV2WithBytes shell v2, 支持后台运行而不会阻断
|
||||||
func (d *Device) RunShellCommandV2WithBytes(cmd string, args ...string) ([]byte, error) {
|
func (d *Device) RunShellCommandV2WithBytes(cmd string, args ...string) ([]byte, error) {
|
||||||
if len(args) > 0 {
|
if len(args) > 0 {
|
||||||
@@ -282,6 +290,15 @@ func (d *Device) RunShellCommandV2WithBytes(cmd string, args ...string) ([]byte,
|
|||||||
return nil, errors.New("adb shell: command cannot be empty")
|
return nil, errors.New("adb shell: command cannot be empty")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
startTime := time.Now()
|
||||||
|
defer func() {
|
||||||
|
// log elapsed seconds for shell execution
|
||||||
|
log.Debug().Str("cmd",
|
||||||
|
fmt.Sprintf("adb -s %s shell %s", d.serial, cmd)).
|
||||||
|
Float64("elapsed(s)", time.Since(startTime).Seconds()).
|
||||||
|
Msg("run adb shell in v2")
|
||||||
|
}()
|
||||||
|
|
||||||
raw, err := d.executeCommand(fmt.Sprintf("shell,v2,raw:%s", cmd))
|
raw, err := d.executeCommand(fmt.Sprintf("shell,v2,raw:%s", cmd))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return raw, err
|
return raw, err
|
||||||
@@ -359,39 +376,11 @@ func (d *Device) createDeviceTransport() (tp transport, err error) {
|
|||||||
return transport{}, err
|
return transport{}, err
|
||||||
}
|
}
|
||||||
|
|
||||||
if err = tp.Send(fmt.Sprintf("host:transport:%s", d.serial)); err != nil {
|
err = tp.SendWithCheck(fmt.Sprintf("host:transport:%s", d.serial))
|
||||||
return transport{}, err
|
|
||||||
}
|
|
||||||
err = tp.VerifyResponse()
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
func (d *Device) executeCommand(command string, onlyVerifyResponse ...bool) (raw []byte, err error) {
|
func (d *Device) executeCommand(command string, onlyVerifyResponse ...bool) (raw []byte, err error) {
|
||||||
startTime := time.Now()
|
|
||||||
defer func() {
|
|
||||||
// log elapsed seconds for shell execution
|
|
||||||
elapsed := time.Since(startTime).Seconds()
|
|
||||||
if strings.HasPrefix(command, "shell,v2,raw:") {
|
|
||||||
cmd := strings.TrimPrefix(command, "shell,v2,raw:")
|
|
||||||
log.Debug().Str("cmd",
|
|
||||||
fmt.Sprintf("adb -s %s shell %s", d.serial, cmd)).
|
|
||||||
Float64("elapsed(s)", elapsed).
|
|
||||||
Msg("run adb shell in v2")
|
|
||||||
} else if strings.HasPrefix(command, "shell:") {
|
|
||||||
cmd := strings.TrimPrefix(command, "shell:")
|
|
||||||
log.Debug().Str("cmd",
|
|
||||||
fmt.Sprintf("adb -s %s shell %s", d.serial, cmd)).
|
|
||||||
Float64("elapsed(s)", elapsed).
|
|
||||||
Msg("run adb shell")
|
|
||||||
} else {
|
|
||||||
cmd := strings.ReplaceAll(command, ":", " ")
|
|
||||||
log.Debug().Str("command",
|
|
||||||
fmt.Sprintf("adb -s %s %s", d.serial, cmd)).
|
|
||||||
Float64("elapsed(s)", elapsed).
|
|
||||||
Msg("run adb command")
|
|
||||||
}
|
|
||||||
}()
|
|
||||||
|
|
||||||
if len(onlyVerifyResponse) == 0 {
|
if len(onlyVerifyResponse) == 0 {
|
||||||
onlyVerifyResponse = []bool{false}
|
onlyVerifyResponse = []bool{false}
|
||||||
}
|
}
|
||||||
@@ -402,11 +391,7 @@ func (d *Device) executeCommand(command string, onlyVerifyResponse ...bool) (raw
|
|||||||
}
|
}
|
||||||
defer func() { _ = tp.Close() }()
|
defer func() { _ = tp.Close() }()
|
||||||
|
|
||||||
if err = tp.Send(command); err != nil {
|
if err = tp.SendWithCheck(command); err != nil {
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
if err = tp.VerifyResponse(); err != nil {
|
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -530,13 +515,12 @@ func (d *Device) installViaABBExec(apk io.ReadSeeker) (raw []byte, err error) {
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
defer func() { _ = tp.Close() }()
|
defer func() { _ = tp.Close() }()
|
||||||
if err = tp.Send(fmt.Sprintf("abb_exec:package\x00install\x00-t\x00-S\x00%d", filesize)); err != nil {
|
|
||||||
|
cmd := fmt.Sprintf("abb_exec:package\x00install\x00-t\x00-S\x00%d", filesize)
|
||||||
|
if err = tp.SendWithCheck(cmd); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
if err = tp.VerifyResponse(); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
_, err = apk.Seek(0, io.SeekStart)
|
_, err = apk.Seek(0, io.SeekStart)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
@@ -594,7 +578,7 @@ func (d *Device) Uninstall(packageName string, keepData ...bool) (string, error)
|
|||||||
args = append(args, "-k")
|
args = append(args, "-k")
|
||||||
}
|
}
|
||||||
args = append(args, packageName)
|
args = append(args, packageName)
|
||||||
return d.RunShellCommandV2("pm", args...)
|
return d.RunShellCommand("pm", args...)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (d *Device) ScreenCap() ([]byte, error) {
|
func (d *Device) ScreenCap() ([]byte, error) {
|
||||||
|
|||||||
+63
-183
@@ -12,16 +12,19 @@ import (
|
|||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestDevice_State(t *testing.T) {
|
var devices []*Device
|
||||||
adbClient, err := NewClient()
|
|
||||||
|
func setupDevices(t *testing.T) {
|
||||||
|
var err error
|
||||||
|
setupClient(t)
|
||||||
|
devices, err = adbClient.DeviceList()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
devices, err := adbClient.DeviceList()
|
func TestDevice_State(t *testing.T) {
|
||||||
if err != nil {
|
setupDevices(t)
|
||||||
t.Fatal(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
for i := range devices {
|
for i := range devices {
|
||||||
dev := devices[i]
|
dev := devices[i]
|
||||||
@@ -30,19 +33,17 @@ func TestDevice_State(t *testing.T) {
|
|||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
t.Log(dev.Serial(), state)
|
t.Log(dev.Serial(), state)
|
||||||
|
|
||||||
|
resp, err := dev.RunShellCommand("ls")
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
t.Log(string(resp))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestDevice_DevicePath(t *testing.T) {
|
func TestDevice_DevicePath(t *testing.T) {
|
||||||
adbClient, err := NewClient()
|
setupDevices(t)
|
||||||
if err != nil {
|
|
||||||
t.Fatal(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
devices, err := adbClient.DeviceList()
|
|
||||||
if err != nil {
|
|
||||||
t.Fatal(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
for i := range devices {
|
for i := range devices {
|
||||||
dev := devices[i]
|
dev := devices[i]
|
||||||
@@ -55,15 +56,7 @@ func TestDevice_DevicePath(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestDevice_Product(t *testing.T) {
|
func TestDevice_Product(t *testing.T) {
|
||||||
adbClient, err := NewClient()
|
setupDevices(t)
|
||||||
if err != nil {
|
|
||||||
t.Fatal(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
devices, err := adbClient.DeviceList()
|
|
||||||
if err != nil {
|
|
||||||
t.Fatal(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
for i := range devices {
|
for i := range devices {
|
||||||
dev := devices[i]
|
dev := devices[i]
|
||||||
@@ -73,15 +66,7 @@ func TestDevice_Product(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestDevice_Model(t *testing.T) {
|
func TestDevice_Model(t *testing.T) {
|
||||||
adbClient, err := NewClient()
|
setupDevices(t)
|
||||||
if err != nil {
|
|
||||||
t.Fatal(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
devices, err := adbClient.DeviceList()
|
|
||||||
if err != nil {
|
|
||||||
t.Fatal(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
for i := range devices {
|
for i := range devices {
|
||||||
dev := devices[i]
|
dev := devices[i]
|
||||||
@@ -90,15 +75,7 @@ func TestDevice_Model(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestDevice_Usb(t *testing.T) {
|
func TestDevice_Usb(t *testing.T) {
|
||||||
adbClient, err := NewClient()
|
setupDevices(t)
|
||||||
if err != nil {
|
|
||||||
t.Fatal(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
devices, err := adbClient.DeviceList()
|
|
||||||
if err != nil {
|
|
||||||
t.Fatal(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
for i := range devices {
|
for i := range devices {
|
||||||
dev := devices[i]
|
dev := devices[i]
|
||||||
@@ -107,15 +84,7 @@ func TestDevice_Usb(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestDevice_DeviceInfo(t *testing.T) {
|
func TestDevice_DeviceInfo(t *testing.T) {
|
||||||
adbClient, err := NewClient()
|
setupDevices(t)
|
||||||
if err != nil {
|
|
||||||
t.Fatal(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
devices, err := adbClient.DeviceList()
|
|
||||||
if err != nil {
|
|
||||||
t.Fatal(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
for i := range devices {
|
for i := range devices {
|
||||||
dev := devices[i]
|
dev := devices[i]
|
||||||
@@ -124,74 +93,54 @@ func TestDevice_DeviceInfo(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestDevice_Forward(t *testing.T) {
|
func TestDevice_Forward(t *testing.T) {
|
||||||
adbClient, err := NewClient()
|
setupDevices(t)
|
||||||
if err != nil {
|
|
||||||
t.Fatal(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
devices, err := adbClient.DeviceList()
|
|
||||||
if err != nil {
|
|
||||||
t.Fatal(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
|
for _, device := range devices {
|
||||||
localPort := 61000
|
localPort := 61000
|
||||||
err = devices[0].Forward(localPort, 6790)
|
err := device.Forward(localPort, 6790)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
err = devices[0].ForwardKill(localPort)
|
err = device.ForwardKill(localPort)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func TestDevice_ReverseForward(t *testing.T) {
|
func TestDevice_ReverseForward(t *testing.T) {
|
||||||
adbClient, err := NewClient()
|
setupDevices(t)
|
||||||
if err != nil {
|
|
||||||
t.Fatal(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
devices, err := adbClient.DeviceList()
|
|
||||||
if err != nil {
|
|
||||||
t.Fatal(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
|
for _, device := range devices {
|
||||||
localPort := 5005
|
localPort := 5005
|
||||||
err = devices[0].ReverseForward(localPort, "localabstract:scrcpy")
|
err := device.ReverseForward(localPort, "localabstract:scrcpy")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
err = devices[0].ReverseForward(localPort, "localabstract:scrcpy1")
|
err = device.ReverseForward(localPort, "localabstract:scrcpy1")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
_, err = devices[0].ReverseForwardList()
|
_, err = device.ReverseForwardList()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
err = devices[0].ReverseForwardKill("localabstract:scrcpy1")
|
err = device.ReverseForwardKill("localabstract:scrcpy1")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
err = devices[0].ReverseForwardKillAll()
|
err = device.ReverseForwardKillAll()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func TestDevice_ForwardList(t *testing.T) {
|
func TestDevice_ForwardList(t *testing.T) {
|
||||||
adbClient, err := NewClient()
|
setupDevices(t)
|
||||||
if err != nil {
|
|
||||||
t.Fatal(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
devices, err := adbClient.DeviceList()
|
|
||||||
if err != nil {
|
|
||||||
t.Fatal(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
for i := range devices {
|
for i := range devices {
|
||||||
dev := devices[i]
|
dev := devices[i]
|
||||||
@@ -204,32 +153,18 @@ func TestDevice_ForwardList(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestDevice_ForwardKill(t *testing.T) {
|
func TestDevice_ForwardKill(t *testing.T) {
|
||||||
adbClient, err := NewClient()
|
setupDevices(t)
|
||||||
|
|
||||||
|
for _, device := range devices {
|
||||||
|
err := device.ForwardKill(6790)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
devices, err := adbClient.DeviceList()
|
|
||||||
if err != nil {
|
|
||||||
t.Fatal(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
err = devices[0].ForwardKill(6790)
|
|
||||||
if err != nil {
|
|
||||||
t.Fatal(err)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestDevice_RunShellCommand(t *testing.T) {
|
func TestDevice_RunShellCommand(t *testing.T) {
|
||||||
adbClient, err := NewClient()
|
setupDevices(t)
|
||||||
if err != nil {
|
|
||||||
t.Fatal(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
devices, err := adbClient.DeviceList()
|
|
||||||
if err != nil {
|
|
||||||
t.Fatal(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
// for i := range devices {
|
// for i := range devices {
|
||||||
// dev := devices[i]
|
// dev := devices[i]
|
||||||
@@ -243,9 +178,7 @@ func TestDevice_RunShellCommand(t *testing.T) {
|
|||||||
// t.Log("\n"+dev.serial, cmdOutput)
|
// t.Log("\n"+dev.serial, cmdOutput)
|
||||||
// }
|
// }
|
||||||
|
|
||||||
dev := devices[len(devices)-1]
|
for _, dev := range devices {
|
||||||
dev = devices[0]
|
|
||||||
|
|
||||||
// cmdOutput, err := dev.RunShellCommand("monkey", "-p", "tv.danmaku.bili", "-c", "android.intent.category.LAUNCHER", "1")
|
// cmdOutput, err := dev.RunShellCommand("monkey", "-p", "tv.danmaku.bili", "-c", "android.intent.category.LAUNCHER", "1")
|
||||||
cmdOutput, err := dev.RunShellCommand("ls /sdcard")
|
cmdOutput, err := dev.RunShellCommand("ls /sdcard")
|
||||||
// cmdOutput, err := dev.RunShellCommandWithBytes("screencap -p")
|
// cmdOutput, err := dev.RunShellCommandWithBytes("screencap -p")
|
||||||
@@ -254,41 +187,23 @@ func TestDevice_RunShellCommand(t *testing.T) {
|
|||||||
}
|
}
|
||||||
t.Log("\n⬇️"+dev.serial+"⬇️\n", cmdOutput)
|
t.Log("\n⬇️"+dev.serial+"⬇️\n", cmdOutput)
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func TestDevice_EnableAdbOverTCP(t *testing.T) {
|
func TestDevice_EnableAdbOverTCP(t *testing.T) {
|
||||||
adbClient, err := NewClient()
|
setupDevices(t)
|
||||||
|
|
||||||
|
for _, dev := range devices {
|
||||||
|
err := dev.EnableAdbOverTCP()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
devices, err := adbClient.DeviceList()
|
|
||||||
if err != nil {
|
|
||||||
t.Fatal(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
dev := devices[len(devices)-1]
|
|
||||||
dev = devices[0]
|
|
||||||
|
|
||||||
err = dev.EnableAdbOverTCP()
|
|
||||||
if err != nil {
|
|
||||||
t.Fatal(err)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestDevice_List(t *testing.T) {
|
func TestDevice_List(t *testing.T) {
|
||||||
adbClient, err := NewClient()
|
setupDevices(t)
|
||||||
if err != nil {
|
|
||||||
t.Fatal(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
devices, err := adbClient.DeviceList()
|
|
||||||
if err != nil {
|
|
||||||
t.Fatal(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
dev := devices[len(devices)-1]
|
|
||||||
dev = devices[0]
|
|
||||||
|
|
||||||
|
for _, dev := range devices {
|
||||||
// fileEntries, err := dev.List("/sdcard")
|
// fileEntries, err := dev.List("/sdcard")
|
||||||
fileEntries, err := dev.List("/sdcard/Download")
|
fileEntries, err := dev.List("/sdcard/Download")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -299,23 +214,14 @@ func TestDevice_List(t *testing.T) {
|
|||||||
t.Log(fileEntries[i].Name, "\t", fileEntries[i].IsDir())
|
t.Log(fileEntries[i].Name, "\t", fileEntries[i].IsDir())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func TestDevice_Push(t *testing.T) {
|
func TestDevice_Push(t *testing.T) {
|
||||||
adbClient, err := NewClient()
|
setupDevices(t)
|
||||||
if err != nil {
|
|
||||||
t.Fatal(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
devices, err := adbClient.DeviceList()
|
|
||||||
if err != nil {
|
|
||||||
t.Fatal(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
dev := devices[len(devices)-1]
|
|
||||||
dev = devices[0]
|
|
||||||
|
|
||||||
|
for _, dev := range devices {
|
||||||
file, _ := os.Open("/Users/hero/Documents/temp/MuMu共享文件夹/test.txt")
|
file, _ := os.Open("/Users/hero/Documents/temp/MuMu共享文件夹/test.txt")
|
||||||
err = dev.PushFile(file, "/sdcard/Download/push.txt", time.Now())
|
err := dev.PushFile(file, "/sdcard/Download/push.txt", time.Now())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
@@ -325,23 +231,14 @@ func TestDevice_Push(t *testing.T) {
|
|||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func TestDevice_Pull(t *testing.T) {
|
func TestDevice_Pull(t *testing.T) {
|
||||||
adbClient, err := NewClient()
|
setupDevices(t)
|
||||||
if err != nil {
|
|
||||||
t.Fatal(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
devices, err := adbClient.DeviceList()
|
|
||||||
if err != nil {
|
|
||||||
t.Fatal(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
dev := devices[len(devices)-1]
|
|
||||||
dev = devices[0]
|
|
||||||
|
|
||||||
|
for _, dev := range devices {
|
||||||
buffer := bytes.NewBufferString("")
|
buffer := bytes.NewBufferString("")
|
||||||
err = dev.Pull("/sdcard/Download/hello.txt", buffer)
|
err := dev.Pull("/sdcard/Download/hello.txt", buffer)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
@@ -351,6 +248,7 @@ func TestDevice_Pull(t *testing.T) {
|
|||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func TestDevice_RunShellCommandBackgroundWithBytes(t *testing.T) {
|
func TestDevice_RunShellCommandBackgroundWithBytes(t *testing.T) {
|
||||||
type fields struct {
|
type fields struct {
|
||||||
@@ -405,40 +303,22 @@ func TestDevice_RunShellCommandBackgroundWithBytes(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestDevice_InstallAPK(t *testing.T) {
|
func TestDevice_InstallAPK(t *testing.T) {
|
||||||
|
setupDevices(t)
|
||||||
|
|
||||||
apk, _ := os.Open("test.apk")
|
apk, _ := os.Open("test.apk")
|
||||||
adbClient, err := NewClient()
|
for _, dev := range devices {
|
||||||
if err != nil {
|
|
||||||
t.Fatal(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
devices, err := adbClient.DeviceList()
|
|
||||||
if err != nil {
|
|
||||||
t.Fatal(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
dev := devices[len(devices)-1]
|
|
||||||
dev = devices[0]
|
|
||||||
|
|
||||||
res, err := dev.InstallAPK(apk)
|
res, err := dev.InstallAPK(apk)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
t.Log(res)
|
t.Log(res)
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func TestDevice_HasFeature(t *testing.T) {
|
func TestDevice_HasFeature(t *testing.T) {
|
||||||
adbClient, err := NewClient()
|
setupDevices(t)
|
||||||
if err != nil {
|
|
||||||
t.Fatal(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
devices, err := adbClient.DeviceList()
|
|
||||||
if err != nil {
|
|
||||||
t.Fatal(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
dev := devices[len(devices)-1]
|
|
||||||
dev = devices[0]
|
|
||||||
|
|
||||||
|
for _, dev := range devices {
|
||||||
t.Log(dev.GetFeatures())
|
t.Log(dev.GetFeatures())
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -17,6 +17,7 @@ type syncTransport struct {
|
|||||||
readTimeout time.Duration
|
readTimeout time.Duration
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// newSyncTransport creates a new sync transport with existed tcp socket connection
|
||||||
func newSyncTransport(sock net.Conn, readTimeout time.Duration) syncTransport {
|
func newSyncTransport(sock net.Conn, readTimeout time.Duration) syncTransport {
|
||||||
return syncTransport{sock: sock, readTimeout: readTimeout}
|
return syncTransport{sock: sock, readTimeout: readTimeout}
|
||||||
}
|
}
|
||||||
|
|||||||
+34
-14
@@ -7,6 +7,7 @@ import (
|
|||||||
"net"
|
"net"
|
||||||
"regexp"
|
"regexp"
|
||||||
"strconv"
|
"strconv"
|
||||||
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/pkg/errors"
|
"github.com/pkg/errors"
|
||||||
@@ -19,19 +20,41 @@ var ErrConnBroken = errors.New("socket connection broken")
|
|||||||
|
|
||||||
var DefaultAdbReadTimeout time.Duration = 60
|
var DefaultAdbReadTimeout time.Duration = 60
|
||||||
|
|
||||||
|
var regexDeviceOffline = regexp.MustCompile("device .* not found")
|
||||||
|
|
||||||
type transport struct {
|
type transport struct {
|
||||||
sock net.Conn
|
sock net.Conn
|
||||||
readTimeout time.Duration
|
readTimeout time.Duration
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// newTransport creates a new tcp socket connection
|
||||||
func newTransport(address string, readTimeout ...time.Duration) (tp transport, err error) {
|
func newTransport(address string, readTimeout ...time.Duration) (tp transport, err error) {
|
||||||
if len(readTimeout) == 0 {
|
if len(readTimeout) == 0 {
|
||||||
readTimeout = []time.Duration{DefaultAdbReadTimeout}
|
readTimeout = []time.Duration{DefaultAdbReadTimeout}
|
||||||
}
|
}
|
||||||
tp.readTimeout = readTimeout[0]
|
tp = transport{
|
||||||
if tp.sock, err = net.Dial("tcp", address); err != nil {
|
readTimeout: readTimeout[0],
|
||||||
err = fmt.Errorf("adb transport: %w", err)
|
|
||||||
}
|
}
|
||||||
|
tp.sock, err = net.Dial("tcp", address)
|
||||||
|
if err == nil {
|
||||||
|
// dial success
|
||||||
|
return tp, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// connection refused
|
||||||
|
if strings.Contains(err.Error(), "connect: connection refused") {
|
||||||
|
err = errors.Wrap(code.AndroidDeviceConnectionRefusedError, err.Error())
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// device offline
|
||||||
|
if regexDeviceOffline.MatchString(err.Error()) {
|
||||||
|
err = errors.Wrap(code.AndroidDeviceOfflineError, err.Error())
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// other connection errors
|
||||||
|
err = errors.Wrap(code.AndroidDeviceConnectionError, err.Error())
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -48,8 +71,6 @@ func (t transport) Conn() net.Conn {
|
|||||||
return t.sock
|
return t.sock
|
||||||
}
|
}
|
||||||
|
|
||||||
var regexDeviceOffline = regexp.MustCompile("device .* not found")
|
|
||||||
|
|
||||||
func (t transport) VerifyResponse() (err error) {
|
func (t transport) VerifyResponse() (err error) {
|
||||||
var status string
|
var status string
|
||||||
if status, err = t.ReadStringN(4); err != nil {
|
if status, err = t.ReadStringN(4); err != nil {
|
||||||
@@ -64,11 +85,6 @@ func (t transport) VerifyResponse() (err error) {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
if regexDeviceOffline.MatchString(sError) {
|
|
||||||
// device offline
|
|
||||||
return errors.Wrap(code.AndroidDeviceConnectionError, sError)
|
|
||||||
}
|
|
||||||
|
|
||||||
log.Warn().Str("status", status).Str("err", sError).
|
log.Warn().Str("status", status).Str("err", sError).
|
||||||
Msg("verify adb response failed")
|
Msg("verify adb response failed")
|
||||||
return errors.New(sError)
|
return errors.New(sError)
|
||||||
@@ -126,11 +142,15 @@ func (t transport) Close() (err error) {
|
|||||||
return t.sock.Close()
|
return t.sock.Close()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t transport) CreateSyncTransport() (sTp syncTransport, err error) {
|
func (t transport) SendWithCheck(command string) (err error) {
|
||||||
if err = t.Send("sync:"); err != nil {
|
if err = t.Send(command); err != nil {
|
||||||
return syncTransport{}, err
|
return err
|
||||||
}
|
}
|
||||||
if err = t.VerifyResponse(); err != nil {
|
return t.VerifyResponse()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t transport) CreateSyncTransport() (sTp syncTransport, err error) {
|
||||||
|
if err = t.SendWithCheck("sync:"); err != nil {
|
||||||
return syncTransport{}, err
|
return syncTransport{}, err
|
||||||
}
|
}
|
||||||
sTp = newSyncTransport(t.sock, t.readTimeout)
|
sTp = newSyncTransport(t.sock, t.readTimeout)
|
||||||
|
|||||||
+14
-2
@@ -377,7 +377,19 @@ func (dExt *DriverExt) GenAbsScope(x1, y1, x2, y2 float64) AbsScope {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (dExt *DriverExt) DoAction(action MobileAction) error {
|
func (dExt *DriverExt) DoAction(action MobileAction) error {
|
||||||
log.Info().Str("method", string(action.Method)).Interface("params", action.Params).Msg("start UI action")
|
log.Debug().
|
||||||
|
Str("method", string(action.Method)).
|
||||||
|
Interface("params", action.Params).
|
||||||
|
Msg("uixt action start")
|
||||||
|
actionStartTime := time.Now()
|
||||||
|
|
||||||
|
defer func() {
|
||||||
|
log.Debug().
|
||||||
|
Str("method", string(action.Method)).
|
||||||
|
Interface("params", action.Params).
|
||||||
|
Float64("elapsed(s)", time.Since(actionStartTime).Seconds()).
|
||||||
|
Msg("uixt action end")
|
||||||
|
}()
|
||||||
|
|
||||||
switch action.Method {
|
switch action.Method {
|
||||||
case ACTION_AppInstall:
|
case ACTION_AppInstall:
|
||||||
@@ -506,7 +518,7 @@ func (dExt *DriverExt) DoAction(action MobileAction) error {
|
|||||||
case ACTION_ScreenShot:
|
case ACTION_ScreenShot:
|
||||||
// take screenshot
|
// take screenshot
|
||||||
log.Info().Msg("take screenshot for current screen")
|
log.Info().Msg("take screenshot for current screen")
|
||||||
_, _, err := dExt.TakeScreenShot(builtin.GenNameWithTimestamp("%d_screenshot"))
|
_, _, err := dExt.takeScreenShot(builtin.GenNameWithTimestamp("%d_screenshot"))
|
||||||
return err
|
return err
|
||||||
case ACTION_StartCamera:
|
case ACTION_StartCamera:
|
||||||
return dExt.Driver.StartCamera()
|
return dExt.Driver.StartCamera()
|
||||||
|
|||||||
@@ -91,7 +91,7 @@ func NewAndroidDevice(options ...AndroidDeviceOption) (device *AndroidDevice, er
|
|||||||
|
|
||||||
deviceList, err := GetAndroidDevices(device.SerialNumber)
|
deviceList, err := GetAndroidDevices(device.SerialNumber)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, errors.Wrap(code.AndroidDeviceConnectionError, err.Error())
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
dev := deviceList[0]
|
dev := deviceList[0]
|
||||||
@@ -106,12 +106,11 @@ func NewAndroidDevice(options ...AndroidDeviceOption) (device *AndroidDevice, er
|
|||||||
func GetAndroidDevices(serial ...string) (devices []*gadb.Device, err error) {
|
func GetAndroidDevices(serial ...string) (devices []*gadb.Device, err error) {
|
||||||
var adbClient gadb.Client
|
var adbClient gadb.Client
|
||||||
if adbClient, err = gadb.NewClientWith(AdbServerHost, AdbServerPort); err != nil {
|
if adbClient, err = gadb.NewClientWith(AdbServerHost, AdbServerPort); err != nil {
|
||||||
return nil, errors.Wrap(code.AndroidDeviceConnectionError, err.Error())
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
if devices, err = adbClient.DeviceList(); err != nil {
|
if devices, err = adbClient.DeviceList(); err != nil {
|
||||||
return nil, errors.Wrap(code.AndroidDeviceConnectionError,
|
return nil, err
|
||||||
fmt.Sprintf("list android devices failed: %v", err))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
var deviceList []*gadb.Device
|
var deviceList []*gadb.Device
|
||||||
@@ -190,11 +189,11 @@ func (dev *AndroidDevice) NewDriver(capabilities Capabilities) (driverExt *Drive
|
|||||||
func (dev *AndroidDevice) NewUSBDriver(capabilities Capabilities) (driver WebDriver, err error) {
|
func (dev *AndroidDevice) NewUSBDriver(capabilities Capabilities) (driver WebDriver, err error) {
|
||||||
var localPort int
|
var localPort int
|
||||||
if localPort, err = getFreePort(); err != nil {
|
if localPort, err = getFreePort(); err != nil {
|
||||||
return nil, errors.Wrap(code.AndroidDeviceUSBDriverError,
|
return nil, errors.Wrap(code.AndroidDeviceConnectionError,
|
||||||
fmt.Sprintf("get free port failed: %v", err))
|
fmt.Sprintf("get free port failed: %v", err))
|
||||||
}
|
}
|
||||||
if err = dev.d.Forward(localPort, UIA2ServerPort); err != nil {
|
if err = dev.d.Forward(localPort, UIA2ServerPort); err != nil {
|
||||||
return nil, errors.Wrap(code.AndroidDeviceUSBDriverError,
|
return nil, errors.Wrap(code.AndroidDeviceConnectionError,
|
||||||
fmt.Sprintf("forward port %d->%d failed: %v",
|
fmt.Sprintf("forward port %d->%d failed: %v",
|
||||||
localPort, UIA2ServerPort, err))
|
localPort, UIA2ServerPort, err))
|
||||||
}
|
}
|
||||||
@@ -204,7 +203,7 @@ func (dev *AndroidDevice) NewUSBDriver(capabilities Capabilities) (driver WebDri
|
|||||||
uiaDriver, err := NewUIADriver(capabilities, rawURL)
|
uiaDriver, err := NewUIADriver(capabilities, rawURL)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
_ = dev.d.ForwardKill(localPort)
|
_ = dev.d.ForwardKill(localPort)
|
||||||
return nil, errors.Wrap(code.AndroidDeviceUSBDriverError, err.Error())
|
return nil, errors.Wrap(code.AndroidDeviceConnectionError, err.Error())
|
||||||
}
|
}
|
||||||
uiaDriver.adbClient = dev.d
|
uiaDriver.adbClient = dev.d
|
||||||
uiaDriver.logcat = dev.logcat
|
uiaDriver.logcat = dev.logcat
|
||||||
|
|||||||
+4
-9
@@ -124,9 +124,8 @@ func NewDriverExt(device Device, driver WebDriver) (dExt *DriverExt, err error)
|
|||||||
return dExt, nil
|
return dExt, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// TakeScreenShot takes screenshot and saves image file to $CWD/screenshots/ folder
|
// takeScreenShot takes screenshot and saves image file to $CWD/screenshots/ folder
|
||||||
// if fileName is empty, it will not save image file and only return raw image data
|
func (dExt *DriverExt) takeScreenShot(fileName string) (raw *bytes.Buffer, path string, err error) {
|
||||||
func (dExt *DriverExt) TakeScreenShot(fileName ...string) (raw *bytes.Buffer, path string, err error) {
|
|
||||||
// iOS 优先使用 MJPEG 流进行截图,性能最优
|
// iOS 优先使用 MJPEG 流进行截图,性能最优
|
||||||
// 如果 MJPEG 流未开启,则使用 WebDriver 的截图接口
|
// 如果 MJPEG 流未开启,则使用 WebDriver 的截图接口
|
||||||
if dExt.frame != nil {
|
if dExt.frame != nil {
|
||||||
@@ -145,9 +144,8 @@ func (dExt *DriverExt) TakeScreenShot(fileName ...string) (raw *bytes.Buffer, pa
|
|||||||
}
|
}
|
||||||
|
|
||||||
// save screenshot to file
|
// save screenshot to file
|
||||||
if len(fileName) > 0 && fileName[0] != "" {
|
path = filepath.Join(env.ScreenShotsPath, fileName)
|
||||||
path := filepath.Join(env.ScreenShotsPath, fileName[0])
|
path, err = dExt.saveScreenShot(compressed, path)
|
||||||
path, err := dExt.saveScreenShot(compressed, path)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Error().Err(err).Msg("save screenshot file failed")
|
log.Error().Err(err).Msg("save screenshot file failed")
|
||||||
return nil, "", err
|
return nil, "", err
|
||||||
@@ -155,9 +153,6 @@ func (dExt *DriverExt) TakeScreenShot(fileName ...string) (raw *bytes.Buffer, pa
|
|||||||
return compressed, path, nil
|
return compressed, path, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
return compressed, "", nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func compressImageBuffer(raw *bytes.Buffer) (compressed *bytes.Buffer, err error) {
|
func compressImageBuffer(raw *bytes.Buffer) (compressed *bytes.Buffer, err error) {
|
||||||
// TODO: compress image data
|
// TODO: compress image data
|
||||||
return raw, nil
|
return raw, nil
|
||||||
|
|||||||
+18
-12
@@ -59,7 +59,7 @@ type ImageResult struct {
|
|||||||
LiveType string `json:"liveType"` // 直播间类型
|
LiveType string `json:"liveType"` // 直播间类型
|
||||||
}
|
}
|
||||||
|
|
||||||
type ImageResponse struct {
|
type APIResponseImage struct {
|
||||||
Code int `json:"code"`
|
Code int `json:"code"`
|
||||||
Message string `json:"message"`
|
Message string `json:"message"`
|
||||||
Result ImageResult `json:"result"`
|
Result ImageResult `json:"result"`
|
||||||
@@ -248,7 +248,7 @@ func (s *veDEMImageService) GetImage(imageBuf *bytes.Buffer) (
|
|||||||
log.Debug().
|
log.Debug().
|
||||||
Str("X-TT-LOGID", logID).
|
Str("X-TT-LOGID", logID).
|
||||||
Int("image_bytes", size).
|
Int("image_bytes", size).
|
||||||
Float64("elapsed_seconds", elapsed.Seconds()).
|
Float64("elapsed(s)", elapsed.Seconds()).
|
||||||
Msg("request OCR service success")
|
Msg("request OCR service success")
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
@@ -279,7 +279,7 @@ func (s *veDEMImageService) GetImage(imageBuf *bytes.Buffer) (
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
var imageResponse ImageResponse
|
var imageResponse APIResponseImage
|
||||||
err = json.Unmarshal(results, &imageResponse)
|
err = json.Unmarshal(results, &imageResponse)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Error().Err(err).
|
log.Error().Err(err).
|
||||||
@@ -334,19 +334,20 @@ type IImageService interface {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// GetScreenResult takes a screenshot, returns the image recognization result
|
// GetScreenResult takes a screenshot, returns the image recognization result
|
||||||
func (dExt *DriverExt) GetScreenResult() (imageResult ImageResult, err error) {
|
func (dExt *DriverExt) GetScreenResult() (screenResult *ScreenResult, err error) {
|
||||||
var bufSource *bytes.Buffer
|
var bufSource *bytes.Buffer
|
||||||
var imagePath string
|
var imagePath string
|
||||||
if bufSource, imagePath, err = dExt.TakeScreenShot(
|
if bufSource, imagePath, err = dExt.takeScreenShot(
|
||||||
builtin.GenNameWithTimestamp("%d_ocr")); err != nil {
|
builtin.GenNameWithTimestamp("%d_ocr")); err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
imageResult, err = dExt.ImageService.GetImage(bufSource)
|
imageResult, err := dExt.ImageService.GetImage(bufSource)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Error().Err(err).Msg("GetScreenResult failed")
|
log.Error().Err(err).Msg("GetImage from ImageService failed")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
imageResult.imagePath = imagePath
|
||||||
|
|
||||||
imageUrl := imageResult.URL
|
imageUrl := imageResult.URL
|
||||||
if imageUrl != "" {
|
if imageUrl != "" {
|
||||||
@@ -354,20 +355,25 @@ func (dExt *DriverExt) GetScreenResult() (imageResult ImageResult, err error) {
|
|||||||
log.Debug().Str("imagePath", imagePath).Str("imageUrl", imageUrl).Msg("log screenshot")
|
log.Debug().Str("imagePath", imagePath).Str("imageUrl", imageUrl).Msg("log screenshot")
|
||||||
}
|
}
|
||||||
|
|
||||||
dExt.cacheStepData.screenResults[imagePath] = &ScreenResult{
|
screenResult = &ScreenResult{
|
||||||
Texts: imageResult.OCRResult.ToOCRTexts(),
|
Texts: imageResult.OCRResult.ToOCRTexts(),
|
||||||
|
Tags: nil,
|
||||||
|
Popularity: Popularity{},
|
||||||
}
|
}
|
||||||
|
if imageResult.LiveType != "" {
|
||||||
|
screenResult.Tags = []string{imageResult.LiveType}
|
||||||
|
}
|
||||||
|
dExt.cacheStepData.screenResults[imagePath] = screenResult
|
||||||
|
|
||||||
imageResult.imagePath = imagePath
|
return screenResult, nil
|
||||||
return imageResult, nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (dExt *DriverExt) GetScreenTexts() (ocrTexts OCRTexts, err error) {
|
func (dExt *DriverExt) GetScreenTexts() (ocrTexts OCRTexts, err error) {
|
||||||
imageResult, err := dExt.GetScreenResult()
|
screenResult, err := dExt.GetScreenResult()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
return imageResult.OCRResult.ToOCRTexts(), nil
|
return screenResult.Texts, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (dExt *DriverExt) FindScreenText(text string, options ...ActionOption) (point PointF, err error) {
|
func (dExt *DriverExt) FindScreenText(text string, options ...ActionOption) (point PointF, err error) {
|
||||||
|
|||||||
@@ -101,7 +101,7 @@ func (dExt *DriverExt) FindAllImageRect(search string) (rects []image.Rectangle,
|
|||||||
if bufSearch, err = getBufFromDisk(search); err != nil {
|
if bufSearch, err = getBufFromDisk(search); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
if bufSource, _, err = dExt.TakeScreenShot(builtin.GenNameWithTimestamp("%d_cv")); err != nil {
|
if bufSource, _, err = dExt.takeScreenShot(builtin.GenNameWithTimestamp("%d_cv")); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -12,8 +12,8 @@ var popups = [][]string{
|
|||||||
{".*青少年.*", "我知道了"}, // 青少年弹窗
|
{".*青少年.*", "我知道了"}, // 青少年弹窗
|
||||||
{".*个人信息保护.*", "同意"},
|
{".*个人信息保护.*", "同意"},
|
||||||
{".*通讯录.*", "拒绝"},
|
{".*通讯录.*", "拒绝"},
|
||||||
{".*更新.*", "以后再说|稍后"},
|
{".*更新.*", "以后再说|稍后|取消"},
|
||||||
{".*升级.*", "以后再说|稍后"},
|
{".*升级.*", "以后再说|稍后|取消"},
|
||||||
{".*定位.*", "仅.*允许"},
|
{".*定位.*", "仅.*允许"},
|
||||||
{".*拍照.*", "仅.*允许"},
|
{".*拍照.*", "仅.*允许"},
|
||||||
{".*录音.*", "仅.*允许"},
|
{".*录音.*", "仅.*允许"},
|
||||||
@@ -24,16 +24,16 @@ var popups = [][]string{
|
|||||||
{"管理使用时间", ".*忽略.*"},
|
{"管理使用时间", ".*忽略.*"},
|
||||||
}
|
}
|
||||||
|
|
||||||
func (dExt *DriverExt) autoPopupHandler(screenResult *ScreenResult) error {
|
func (dExt *DriverExt) AutoPopupHandler(screenTexts OCRTexts) error {
|
||||||
for _, popup := range popups {
|
for _, popup := range popups {
|
||||||
if len(popup) != 2 {
|
if len(popup) != 2 {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
points, err := screenResult.Texts.FindTexts([]string{popup[0], popup[1]}, WithRegex(true))
|
points, err := screenTexts.FindTexts([]string{popup[0], popup[1]}, WithRegex(true))
|
||||||
if err == nil {
|
if err == nil {
|
||||||
log.Warn().Interface("popup", popup).
|
log.Warn().Interface("popup", popup).
|
||||||
Interface("texts", screenResult.Texts).Msg("text popup found")
|
Interface("texts", screenTexts).Msg("text popup found")
|
||||||
point := points[1].Center()
|
point := points[1].Center()
|
||||||
log.Info().Str("text", points[1].Text).Msg("close popup")
|
log.Info().Str("text", points[1].Text).Msg("close popup")
|
||||||
if err := dExt.TapAbsXY(point.X, point.Y); err != nil {
|
if err := dExt.TapAbsXY(point.X, point.Y); err != nil {
|
||||||
|
|||||||
@@ -135,14 +135,20 @@ func (dExt *DriverExt) swipeToTapTexts(texts []string, options ...ActionOption)
|
|||||||
var point PointF
|
var point PointF
|
||||||
findTexts := func(d *DriverExt) error {
|
findTexts := func(d *DriverExt) error {
|
||||||
var err error
|
var err error
|
||||||
ocrTexts, err := d.GetScreenTexts()
|
screenTexts, err := d.GetScreenTexts()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
points, err := ocrTexts.FindTexts(texts, dExt.ParseActionOptions(options...)...)
|
points, err := screenTexts.FindTexts(texts, dExt.ParseActionOptions(options...)...)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
// target texts not found, try to auto handle popup
|
||||||
|
if e := dExt.AutoPopupHandler(screenTexts); e != nil {
|
||||||
|
log.Error().Err(e).Msg("auto handle popup failed")
|
||||||
|
}
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// target texts found, pick the first one
|
||||||
point = points[0].Center() // FIXME
|
point = points[0].Center() // FIXME
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -250,17 +250,13 @@ func (l *LiveCrawler) Run(driver *DriverExt, enterPoint PointF) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// take screenshot and get screen texts by OCR
|
// take screenshot and get screen texts by OCR
|
||||||
imageResult, err := l.driver.GetScreenResult()
|
screenResult, err := l.driver.GetScreenResult()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Error().Err(err).Msg("OCR GetTexts failed")
|
log.Error().Err(err).Msg("OCR GetTexts failed")
|
||||||
time.Sleep(3 * time.Second)
|
time.Sleep(3 * time.Second)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
screenResult := l.driver.cacheStepData.screenResults[imageResult.imagePath]
|
screenResult.Tags = append([]string{"live"}, screenResult.Tags...)
|
||||||
screenResult.Tags = []string{"live"}
|
|
||||||
if imageResult.LiveType != "" {
|
|
||||||
screenResult.Tags = append(screenResult.Tags, imageResult.LiveType)
|
|
||||||
}
|
|
||||||
|
|
||||||
// check live type and incr live count
|
// check live type and incr live count
|
||||||
if err := l.currentStat.incrLive(screenResult, l.driver); err != nil {
|
if err := l.currentStat.incrLive(screenResult, l.driver); err != nil {
|
||||||
@@ -364,7 +360,7 @@ func (dExt *DriverExt) VideoCrawler(configs *VideoCrawlerConfigs) (err error) {
|
|||||||
return errors.Wrap(code.InterruptError, "feed crawler interrupted")
|
return errors.Wrap(code.InterruptError, "feed crawler interrupted")
|
||||||
default:
|
default:
|
||||||
// take screenshot and get screen texts by OCR
|
// take screenshot and get screen texts by OCR
|
||||||
imageResult, err := dExt.GetScreenResult()
|
screenResult, err := dExt.GetScreenResult()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if strings.Contains(err.Error(), "connect: connection refused") {
|
if strings.Contains(err.Error(), "connect: connection refused") {
|
||||||
return err
|
return err
|
||||||
@@ -373,17 +369,15 @@ func (dExt *DriverExt) VideoCrawler(configs *VideoCrawlerConfigs) (err error) {
|
|||||||
time.Sleep(3 * time.Second)
|
time.Sleep(3 * time.Second)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
screenResult := dExt.cacheStepData.screenResults[imageResult.imagePath]
|
|
||||||
|
|
||||||
// automatic handling of pop-up windows
|
// automatic handling of pop-up windows
|
||||||
if err := dExt.autoPopupHandler(screenResult); err != nil {
|
if err := dExt.AutoPopupHandler(screenResult.Texts); err != nil {
|
||||||
log.Error().Err(err).Msg("auto handle popup failed")
|
log.Error().Err(err).Msg("auto handle popup failed")
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
// check if live video && run live crawler
|
// check if live video && run live crawler
|
||||||
texts := imageResult.OCRResult.ToOCRTexts()
|
if enterPoint, isLive := liveCrawler.checkLiveVideo(screenResult.Texts); isLive {
|
||||||
if enterPoint, isLive := liveCrawler.checkLiveVideo(texts); isLive {
|
|
||||||
log.Info().Msg("live video found")
|
log.Info().Msg("live video found")
|
||||||
if !liveCrawler.currentStat.isLiveTargetAchieved() {
|
if !liveCrawler.currentStat.isLiveTargetAchieved() {
|
||||||
if err := liveCrawler.Run(dExt, enterPoint); err != nil {
|
if err := liveCrawler.Run(dExt, enterPoint); err != nil {
|
||||||
|
|||||||
+12
-8
@@ -539,8 +539,9 @@ func (r *SessionRunner) Start(givenVars map[string]interface{}) error {
|
|||||||
parsedName = step.Name()
|
parsedName = step.Name()
|
||||||
}
|
}
|
||||||
stepName := convertString(parsedName)
|
stepName := convertString(parsedName)
|
||||||
log.Info().Str("step", stepName).
|
stepType := string(step.Type())
|
||||||
Str("type", string(step.Type())).Msg("run step start")
|
log.Info().Str("step", stepName).Str("type", stepType).Msg("run step start")
|
||||||
|
stepStartTime := time.Now()
|
||||||
|
|
||||||
// run times of step
|
// run times of step
|
||||||
loopTimes := step.Struct().Loops
|
loopTimes := step.Struct().Loops
|
||||||
@@ -563,10 +564,10 @@ func (r *SessionRunner) Start(givenVars map[string]interface{}) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// run step
|
// run step
|
||||||
stepStartTime := time.Now().Unix()
|
startTime := time.Now().Unix()
|
||||||
stepResult, err = step.Run(r)
|
stepResult, err = step.Run(r)
|
||||||
stepResult.Name = stepName + loopIndex
|
stepResult.Name = stepName + loopIndex
|
||||||
stepResult.StartTime = stepStartTime
|
stepResult.StartTime = startTime
|
||||||
|
|
||||||
r.updateSummary(stepResult)
|
r.updateSummary(stepResult)
|
||||||
}
|
}
|
||||||
@@ -576,19 +577,22 @@ func (r *SessionRunner) Start(givenVars map[string]interface{}) error {
|
|||||||
r.sessionVariables[k] = v
|
r.sessionVariables[k] = v
|
||||||
}
|
}
|
||||||
|
|
||||||
|
stepElapsed := time.Since(stepStartTime).Seconds()
|
||||||
if err == nil {
|
if err == nil {
|
||||||
log.Info().Str("step", stepResult.Name).
|
log.Info().Str("step", stepName).
|
||||||
Str("type", string(stepResult.StepType)).
|
Str("type", stepType).
|
||||||
Bool("success", true).
|
Bool("success", true).
|
||||||
|
Float64("elapsed(s)", stepElapsed).
|
||||||
Interface("exportVars", stepResult.ExportVars).
|
Interface("exportVars", stepResult.ExportVars).
|
||||||
Msg("run step end")
|
Msg("run step end")
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
// failed
|
// failed
|
||||||
log.Error().Err(err).Str("step", stepResult.Name).
|
log.Error().Err(err).Str("step", stepName).
|
||||||
Str("type", string(stepResult.StepType)).
|
Str("type", stepType).
|
||||||
Bool("success", false).
|
Bool("success", false).
|
||||||
|
Float64("elapsed(s)", stepElapsed).
|
||||||
Msg("run step end")
|
Msg("run step end")
|
||||||
|
|
||||||
// interrupted or timeout, abort running
|
// interrupted or timeout, abort running
|
||||||
|
|||||||
@@ -6,7 +6,6 @@ import (
|
|||||||
"github.com/pkg/errors"
|
"github.com/pkg/errors"
|
||||||
"github.com/rs/zerolog/log"
|
"github.com/rs/zerolog/log"
|
||||||
|
|
||||||
"github.com/httprunner/httprunner/v4/hrp/internal/builtin"
|
|
||||||
"github.com/httprunner/httprunner/v4/hrp/internal/code"
|
"github.com/httprunner/httprunner/v4/hrp/internal/code"
|
||||||
"github.com/httprunner/httprunner/v4/hrp/pkg/uixt"
|
"github.com/httprunner/httprunner/v4/hrp/pkg/uixt"
|
||||||
)
|
)
|
||||||
@@ -598,10 +597,13 @@ func runStepMobileUI(s *SessionRunner, step *TStep) (stepResult *StepResult, err
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// take screenshot after each step
|
// take screenshot and get screen texts by OCR
|
||||||
if _, _, err2 := uiDriver.TakeScreenShot(
|
screenTexts, err2 := uiDriver.GetScreenTexts()
|
||||||
builtin.GenNameWithTimestamp("%d_step_") + step.Name); err2 != nil {
|
if err2 != nil {
|
||||||
log.Error().Err(err2).Str("step", step.Name).Msg("take screenshot failed on step finished")
|
log.Error().Err(err2).Str("step", step.Name).Msg("take screenshot failed on step finished")
|
||||||
|
} else if err3 := uiDriver.AutoPopupHandler(screenTexts); err3 != nil {
|
||||||
|
// automatic handling of pop-up windows on each step finished
|
||||||
|
log.Error().Err(err3).Msg("auto handle popup failed")
|
||||||
}
|
}
|
||||||
|
|
||||||
// save attachments
|
// save attachments
|
||||||
|
|||||||
Reference in New Issue
Block a user