mirror of
https://github.com/httprunner/httprunner.git
synced 2026-05-12 02:21:29 +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,11 +61,12 @@ var (
|
||||
|
||||
// android device related: [60, 70)
|
||||
var (
|
||||
AndroidDeviceConnectionError = errors.New("android device connection error") // 60
|
||||
AndroidDeviceUSBDriverError = errors.New("android device USB driver error") // 61
|
||||
AndroidShellExecError = errors.New("android adb shell exec error") // 62
|
||||
AndroidScreenShotError = errors.New("android screenshot error") // 65
|
||||
AndroidCaptureLogError = errors.New("android capture log error") // 66
|
||||
AndroidDeviceConnectionError = errors.New("android device general connection error") // 60
|
||||
AndroidDeviceConnectionRefusedError = errors.New("android device connection refused") // 61
|
||||
AndroidShellExecError = errors.New("android adb shell exec error") // 62
|
||||
AndroidDeviceOfflineError = errors.New("android device offline") // 63
|
||||
AndroidScreenShotError = errors.New("android screenshot error") // 65
|
||||
AndroidCaptureLogError = errors.New("android capture log error") // 66
|
||||
)
|
||||
|
||||
// UI automation related: [70, 80)
|
||||
@@ -127,11 +128,12 @@ var errorsMap = map[error]int{
|
||||
IOSCaptureLogError: 56,
|
||||
|
||||
// android related
|
||||
AndroidDeviceConnectionError: 60,
|
||||
AndroidDeviceUSBDriverError: 61,
|
||||
AndroidShellExecError: 62,
|
||||
AndroidScreenShotError: 65,
|
||||
AndroidCaptureLogError: 66,
|
||||
AndroidDeviceConnectionError: 60,
|
||||
AndroidDeviceConnectionRefusedError: 61,
|
||||
AndroidShellExecError: 62,
|
||||
AndroidDeviceOfflineError: 63,
|
||||
AndroidScreenShotError: 65,
|
||||
AndroidCaptureLogError: 66,
|
||||
|
||||
// UI automation related
|
||||
MobileUIDriverError: 70,
|
||||
|
||||
@@ -1 +1 @@
|
||||
v4.3.4-beta-2306212230
|
||||
v4.3.4-beta-2306282100
|
||||
@@ -5,7 +5,10 @@ import (
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
"github.com/rs/zerolog/log"
|
||||
|
||||
"github.com/httprunner/httprunner/v4/hrp/internal/code"
|
||||
)
|
||||
|
||||
const (
|
||||
@@ -84,6 +87,12 @@ func (c Client) DeviceSerialList() (serials []string, 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
|
||||
if resp, err = c.executeCommand("host:devices-l"); err != nil {
|
||||
return
|
||||
@@ -212,10 +221,7 @@ func (c Client) executeCommand(command string, onlyVerifyResponse ...bool) (resp
|
||||
}
|
||||
defer func() { _ = tp.Close() }()
|
||||
|
||||
if err = tp.Send(command); err != nil {
|
||||
return "", err
|
||||
}
|
||||
if err = tp.VerifyResponse(); err != nil {
|
||||
if err = tp.SendWithCheck(command); err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
|
||||
@@ -7,11 +7,18 @@ import (
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestClient_ServerVersion(t *testing.T) {
|
||||
adbClient, err := NewClient()
|
||||
var adbClient Client
|
||||
|
||||
func setupClient(t *testing.T) {
|
||||
var err error
|
||||
adbClient, err = NewClient()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestClient_ServerVersion(t *testing.T) {
|
||||
setupClient(t)
|
||||
|
||||
adbServerVersion, err := adbClient.ServerVersion()
|
||||
if err != nil {
|
||||
@@ -22,10 +29,7 @@ func TestClient_ServerVersion(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestClient_DeviceSerialList(t *testing.T) {
|
||||
adbClient, err := NewClient()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
setupClient(t)
|
||||
|
||||
serials, err := adbClient.DeviceSerialList()
|
||||
if err != nil {
|
||||
@@ -38,15 +42,7 @@ func TestClient_DeviceSerialList(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestClient_DeviceList(t *testing.T) {
|
||||
adbClient, err := NewClient()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
devices, err := adbClient.DeviceList()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
setupDevices(t)
|
||||
|
||||
for i := range devices {
|
||||
t.Log(devices[i].serial, devices[i].DeviceInfo())
|
||||
@@ -54,10 +50,7 @@ func TestClient_DeviceList(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestClient_ForwardList(t *testing.T) {
|
||||
adbClient, err := NewClient()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
setupClient(t)
|
||||
|
||||
deviceForwardList, err := adbClient.ForwardList()
|
||||
if err != nil {
|
||||
@@ -70,80 +63,59 @@ func TestClient_ForwardList(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestClient_ForwardKillAll(t *testing.T) {
|
||||
adbClient, err := NewClient()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
setupClient(t)
|
||||
|
||||
err = adbClient.ForwardKillAll()
|
||||
err := adbClient.ForwardKillAll()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestClient_Connect(t *testing.T) {
|
||||
adbClient, err := NewClient()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
setupClient(t)
|
||||
|
||||
err = adbClient.Connect("192.168.1.28")
|
||||
err := adbClient.Connect("192.168.1.28")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestClient_Disconnect(t *testing.T) {
|
||||
adbClient, err := NewClient()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
setupClient(t)
|
||||
|
||||
err = adbClient.Disconnect("192.168.1.28")
|
||||
err := adbClient.Disconnect("192.168.1.28")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestClient_DisconnectAll(t *testing.T) {
|
||||
adbClient, err := NewClient()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
setupClient(t)
|
||||
|
||||
err = adbClient.DisconnectAll()
|
||||
err := adbClient.DisconnectAll()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestClient_KillServer(t *testing.T) {
|
||||
adbClient, err := NewClient()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
setupClient(t)
|
||||
|
||||
err = adbClient.KillServer()
|
||||
err := adbClient.KillServer()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestScreenCap(t *testing.T) {
|
||||
adbClient, err := NewClient()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
setupDevices(t)
|
||||
|
||||
dl, err := adbClient.DeviceList()
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
for _, d := range devices {
|
||||
res, err := d.ScreenCap()
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
t.Log(len(res))
|
||||
ioutil.WriteFile("/tmp/1.png", res, 0o644)
|
||||
}
|
||||
d := dl[0]
|
||||
res, err := d.ScreenCap()
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
t.Log(len(res))
|
||||
ioutil.WriteFile("/tmp/1.png", res, 0o644)
|
||||
}
|
||||
|
||||
@@ -36,12 +36,18 @@ const (
|
||||
StateOnline DeviceState = "online"
|
||||
StateOffline DeviceState = "offline"
|
||||
StateDisconnected DeviceState = "disconnected"
|
||||
StateBootloader DeviceState = "bootloader"
|
||||
StateRecovery DeviceState = "recovery"
|
||||
StateUnauthorized DeviceState = "unauthorized"
|
||||
)
|
||||
|
||||
var deviceStateStrings = map[string]DeviceState{
|
||||
"": StateDisconnected,
|
||||
"offline": StateOffline,
|
||||
"device": StateOnline,
|
||||
"": StateDisconnected, // no devices/emulators found
|
||||
"offline": StateOffline,
|
||||
"bootloader": StateBootloader,
|
||||
"recovery": StateRecovery,
|
||||
"unauthorized": StateUnauthorized,
|
||||
"device": StateOnline,
|
||||
}
|
||||
|
||||
func deviceStateConv(k string) (deviceState DeviceState) {
|
||||
@@ -245,13 +251,10 @@ func (d *Device) ReverseForwardKillAll() error {
|
||||
|
||||
func (d *Device) RunShellCommand(cmd string, args ...string) (string, error) {
|
||||
raw, err := d.RunShellCommandWithBytes(cmd, args...)
|
||||
if err != nil {
|
||||
if errors.Is(err, code.AndroidDeviceConnectionError) {
|
||||
return "", err
|
||||
}
|
||||
return "", errors.Wrap(code.AndroidShellExecError, err.Error())
|
||||
if err != nil && errors.Cause(err) == nil {
|
||||
err = errors.Wrap(code.AndroidShellExecError, err.Error())
|
||||
}
|
||||
return string(raw), nil
|
||||
return string(raw), err
|
||||
}
|
||||
|
||||
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) == "" {
|
||||
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))
|
||||
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, 支持后台运行而不会阻断
|
||||
func (d *Device) RunShellCommandV2WithBytes(cmd string, args ...string) ([]byte, error) {
|
||||
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")
|
||||
}
|
||||
|
||||
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))
|
||||
if err != nil {
|
||||
return raw, err
|
||||
@@ -359,39 +376,11 @@ func (d *Device) createDeviceTransport() (tp transport, err error) {
|
||||
return transport{}, err
|
||||
}
|
||||
|
||||
if err = tp.Send(fmt.Sprintf("host:transport:%s", d.serial)); err != nil {
|
||||
return transport{}, err
|
||||
}
|
||||
err = tp.VerifyResponse()
|
||||
err = tp.SendWithCheck(fmt.Sprintf("host:transport:%s", d.serial))
|
||||
return
|
||||
}
|
||||
|
||||
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 {
|
||||
onlyVerifyResponse = []bool{false}
|
||||
}
|
||||
@@ -402,11 +391,7 @@ func (d *Device) executeCommand(command string, onlyVerifyResponse ...bool) (raw
|
||||
}
|
||||
defer func() { _ = tp.Close() }()
|
||||
|
||||
if err = tp.Send(command); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if err = tp.VerifyResponse(); err != nil {
|
||||
if err = tp.SendWithCheck(command); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
@@ -530,13 +515,12 @@ func (d *Device) installViaABBExec(apk io.ReadSeeker) (raw []byte, err error) {
|
||||
return nil, err
|
||||
}
|
||||
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
|
||||
}
|
||||
|
||||
if err = tp.VerifyResponse(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
_, err = apk.Seek(0, io.SeekStart)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@@ -594,7 +578,7 @@ func (d *Device) Uninstall(packageName string, keepData ...bool) (string, error)
|
||||
args = append(args, "-k")
|
||||
}
|
||||
args = append(args, packageName)
|
||||
return d.RunShellCommandV2("pm", args...)
|
||||
return d.RunShellCommand("pm", args...)
|
||||
}
|
||||
|
||||
func (d *Device) ScreenCap() ([]byte, error) {
|
||||
|
||||
@@ -12,16 +12,19 @@ import (
|
||||
"time"
|
||||
)
|
||||
|
||||
func TestDevice_State(t *testing.T) {
|
||||
adbClient, err := NewClient()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
var devices []*Device
|
||||
|
||||
devices, err := adbClient.DeviceList()
|
||||
func setupDevices(t *testing.T) {
|
||||
var err error
|
||||
setupClient(t)
|
||||
devices, err = adbClient.DeviceList()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestDevice_State(t *testing.T) {
|
||||
setupDevices(t)
|
||||
|
||||
for i := range devices {
|
||||
dev := devices[i]
|
||||
@@ -30,19 +33,17 @@ func TestDevice_State(t *testing.T) {
|
||||
t.Fatal(err)
|
||||
}
|
||||
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) {
|
||||
adbClient, err := NewClient()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
devices, err := adbClient.DeviceList()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
setupDevices(t)
|
||||
|
||||
for i := range devices {
|
||||
dev := devices[i]
|
||||
@@ -55,15 +56,7 @@ func TestDevice_DevicePath(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestDevice_Product(t *testing.T) {
|
||||
adbClient, err := NewClient()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
devices, err := adbClient.DeviceList()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
setupDevices(t)
|
||||
|
||||
for i := range devices {
|
||||
dev := devices[i]
|
||||
@@ -73,15 +66,7 @@ func TestDevice_Product(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestDevice_Model(t *testing.T) {
|
||||
adbClient, err := NewClient()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
devices, err := adbClient.DeviceList()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
setupDevices(t)
|
||||
|
||||
for i := range devices {
|
||||
dev := devices[i]
|
||||
@@ -90,15 +75,7 @@ func TestDevice_Model(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestDevice_Usb(t *testing.T) {
|
||||
adbClient, err := NewClient()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
devices, err := adbClient.DeviceList()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
setupDevices(t)
|
||||
|
||||
for i := range devices {
|
||||
dev := devices[i]
|
||||
@@ -107,15 +84,7 @@ func TestDevice_Usb(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestDevice_DeviceInfo(t *testing.T) {
|
||||
adbClient, err := NewClient()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
devices, err := adbClient.DeviceList()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
setupDevices(t)
|
||||
|
||||
for i := range devices {
|
||||
dev := devices[i]
|
||||
@@ -124,74 +93,54 @@ func TestDevice_DeviceInfo(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestDevice_Forward(t *testing.T) {
|
||||
adbClient, err := NewClient()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
setupDevices(t)
|
||||
|
||||
devices, err := adbClient.DeviceList()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
for _, device := range devices {
|
||||
localPort := 61000
|
||||
err := device.Forward(localPort, 6790)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
localPort := 61000
|
||||
err = devices[0].Forward(localPort, 6790)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
err = devices[0].ForwardKill(localPort)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
err = device.ForwardKill(localPort)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestDevice_ReverseForward(t *testing.T) {
|
||||
adbClient, err := NewClient()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
setupDevices(t)
|
||||
|
||||
devices, err := adbClient.DeviceList()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
for _, device := range devices {
|
||||
localPort := 5005
|
||||
err := device.ReverseForward(localPort, "localabstract:scrcpy")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
err = device.ReverseForward(localPort, "localabstract:scrcpy1")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
localPort := 5005
|
||||
err = devices[0].ReverseForward(localPort, "localabstract:scrcpy")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
err = devices[0].ReverseForward(localPort, "localabstract:scrcpy1")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
_, err = device.ReverseForwardList()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
_, err = devices[0].ReverseForwardList()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
err = devices[0].ReverseForwardKill("localabstract:scrcpy1")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
err = devices[0].ReverseForwardKillAll()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
err = device.ReverseForwardKill("localabstract:scrcpy1")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
err = device.ReverseForwardKillAll()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestDevice_ForwardList(t *testing.T) {
|
||||
adbClient, err := NewClient()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
devices, err := adbClient.DeviceList()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
setupDevices(t)
|
||||
|
||||
for i := range devices {
|
||||
dev := devices[i]
|
||||
@@ -204,32 +153,18 @@ func TestDevice_ForwardList(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestDevice_ForwardKill(t *testing.T) {
|
||||
adbClient, err := NewClient()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
setupDevices(t)
|
||||
|
||||
devices, err := adbClient.DeviceList()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
err = devices[0].ForwardKill(6790)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
for _, device := range devices {
|
||||
err := device.ForwardKill(6790)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestDevice_RunShellCommand(t *testing.T) {
|
||||
adbClient, err := NewClient()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
devices, err := adbClient.DeviceList()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
setupDevices(t)
|
||||
|
||||
// for i := range devices {
|
||||
// dev := devices[i]
|
||||
@@ -243,112 +178,75 @@ func TestDevice_RunShellCommand(t *testing.T) {
|
||||
// t.Log("\n"+dev.serial, cmdOutput)
|
||||
// }
|
||||
|
||||
dev := devices[len(devices)-1]
|
||||
dev = devices[0]
|
||||
|
||||
// cmdOutput, err := dev.RunShellCommand("monkey", "-p", "tv.danmaku.bili", "-c", "android.intent.category.LAUNCHER", "1")
|
||||
cmdOutput, err := dev.RunShellCommand("ls /sdcard")
|
||||
// cmdOutput, err := dev.RunShellCommandWithBytes("screencap -p")
|
||||
if err != nil {
|
||||
t.Fatal(dev.serial, err)
|
||||
for _, dev := range devices {
|
||||
// cmdOutput, err := dev.RunShellCommand("monkey", "-p", "tv.danmaku.bili", "-c", "android.intent.category.LAUNCHER", "1")
|
||||
cmdOutput, err := dev.RunShellCommand("ls /sdcard")
|
||||
// cmdOutput, err := dev.RunShellCommandWithBytes("screencap -p")
|
||||
if err != nil {
|
||||
t.Fatal(dev.serial, err)
|
||||
}
|
||||
t.Log("\n⬇️"+dev.serial+"⬇️\n", cmdOutput)
|
||||
}
|
||||
t.Log("\n⬇️"+dev.serial+"⬇️\n", cmdOutput)
|
||||
}
|
||||
|
||||
func TestDevice_EnableAdbOverTCP(t *testing.T) {
|
||||
adbClient, err := NewClient()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
setupDevices(t)
|
||||
|
||||
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)
|
||||
for _, dev := range devices {
|
||||
err := dev.EnableAdbOverTCP()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestDevice_List(t *testing.T) {
|
||||
adbClient, err := NewClient()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
setupDevices(t)
|
||||
|
||||
devices, err := adbClient.DeviceList()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
for _, dev := range devices {
|
||||
// fileEntries, err := dev.List("/sdcard")
|
||||
fileEntries, err := dev.List("/sdcard/Download")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
dev := devices[len(devices)-1]
|
||||
dev = devices[0]
|
||||
|
||||
// fileEntries, err := dev.List("/sdcard")
|
||||
fileEntries, err := dev.List("/sdcard/Download")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
for i := range fileEntries {
|
||||
t.Log(fileEntries[i].Name, "\t", fileEntries[i].IsDir())
|
||||
for i := range fileEntries {
|
||||
t.Log(fileEntries[i].Name, "\t", fileEntries[i].IsDir())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestDevice_Push(t *testing.T) {
|
||||
adbClient, err := NewClient()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
setupDevices(t)
|
||||
|
||||
devices, err := adbClient.DeviceList()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
for _, dev := range devices {
|
||||
file, _ := os.Open("/Users/hero/Documents/temp/MuMu共享文件夹/test.txt")
|
||||
err := dev.PushFile(file, "/sdcard/Download/push.txt", time.Now())
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
dev := devices[len(devices)-1]
|
||||
dev = devices[0]
|
||||
|
||||
file, _ := os.Open("/Users/hero/Documents/temp/MuMu共享文件夹/test.txt")
|
||||
err = dev.PushFile(file, "/sdcard/Download/push.txt", time.Now())
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
err = dev.Push(strings.NewReader("world"), "/sdcard/Download/hello.txt", time.Now())
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
err = dev.Push(strings.NewReader("world"), "/sdcard/Download/hello.txt", time.Now())
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestDevice_Pull(t *testing.T) {
|
||||
adbClient, err := NewClient()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
setupDevices(t)
|
||||
|
||||
devices, err := adbClient.DeviceList()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
for _, dev := range devices {
|
||||
buffer := bytes.NewBufferString("")
|
||||
err := dev.Pull("/sdcard/Download/hello.txt", buffer)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
dev := devices[len(devices)-1]
|
||||
dev = devices[0]
|
||||
|
||||
buffer := bytes.NewBufferString("")
|
||||
err = dev.Pull("/sdcard/Download/hello.txt", buffer)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
userHomeDir, _ := os.UserHomeDir()
|
||||
if err = ioutil.WriteFile(userHomeDir+"/Desktop/hello.txt", buffer.Bytes(), DefaultFileMode); err != nil {
|
||||
t.Fatal(err)
|
||||
userHomeDir, _ := os.UserHomeDir()
|
||||
if err = ioutil.WriteFile(userHomeDir+"/Desktop/hello.txt", buffer.Bytes(), DefaultFileMode); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -405,40 +303,22 @@ func TestDevice_RunShellCommandBackgroundWithBytes(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestDevice_InstallAPK(t *testing.T) {
|
||||
setupDevices(t)
|
||||
|
||||
apk, _ := os.Open("test.apk")
|
||||
adbClient, err := NewClient()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
for _, dev := range devices {
|
||||
res, err := dev.InstallAPK(apk)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
t.Log(res)
|
||||
}
|
||||
|
||||
devices, err := adbClient.DeviceList()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
dev := devices[len(devices)-1]
|
||||
dev = devices[0]
|
||||
|
||||
res, err := dev.InstallAPK(apk)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
t.Log(res)
|
||||
}
|
||||
|
||||
func TestDevice_HasFeature(t *testing.T) {
|
||||
adbClient, err := NewClient()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
setupDevices(t)
|
||||
|
||||
for _, dev := range devices {
|
||||
t.Log(dev.GetFeatures())
|
||||
}
|
||||
|
||||
devices, err := adbClient.DeviceList()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
dev := devices[len(devices)-1]
|
||||
dev = devices[0]
|
||||
|
||||
t.Log(dev.GetFeatures())
|
||||
}
|
||||
|
||||
@@ -17,6 +17,7 @@ type syncTransport struct {
|
||||
readTimeout time.Duration
|
||||
}
|
||||
|
||||
// newSyncTransport creates a new sync transport with existed tcp socket connection
|
||||
func newSyncTransport(sock net.Conn, readTimeout time.Duration) syncTransport {
|
||||
return syncTransport{sock: sock, readTimeout: readTimeout}
|
||||
}
|
||||
|
||||
@@ -7,6 +7,7 @@ import (
|
||||
"net"
|
||||
"regexp"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
@@ -19,19 +20,41 @@ var ErrConnBroken = errors.New("socket connection broken")
|
||||
|
||||
var DefaultAdbReadTimeout time.Duration = 60
|
||||
|
||||
var regexDeviceOffline = regexp.MustCompile("device .* not found")
|
||||
|
||||
type transport struct {
|
||||
sock net.Conn
|
||||
readTimeout time.Duration
|
||||
}
|
||||
|
||||
// newTransport creates a new tcp socket connection
|
||||
func newTransport(address string, readTimeout ...time.Duration) (tp transport, err error) {
|
||||
if len(readTimeout) == 0 {
|
||||
readTimeout = []time.Duration{DefaultAdbReadTimeout}
|
||||
}
|
||||
tp.readTimeout = readTimeout[0]
|
||||
if tp.sock, err = net.Dial("tcp", address); err != nil {
|
||||
err = fmt.Errorf("adb transport: %w", err)
|
||||
tp = transport{
|
||||
readTimeout: readTimeout[0],
|
||||
}
|
||||
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
|
||||
}
|
||||
|
||||
@@ -48,8 +71,6 @@ func (t transport) Conn() net.Conn {
|
||||
return t.sock
|
||||
}
|
||||
|
||||
var regexDeviceOffline = regexp.MustCompile("device .* not found")
|
||||
|
||||
func (t transport) VerifyResponse() (err error) {
|
||||
var status string
|
||||
if status, err = t.ReadStringN(4); err != nil {
|
||||
@@ -64,11 +85,6 @@ func (t transport) VerifyResponse() (err error) {
|
||||
return err
|
||||
}
|
||||
|
||||
if regexDeviceOffline.MatchString(sError) {
|
||||
// device offline
|
||||
return errors.Wrap(code.AndroidDeviceConnectionError, sError)
|
||||
}
|
||||
|
||||
log.Warn().Str("status", status).Str("err", sError).
|
||||
Msg("verify adb response failed")
|
||||
return errors.New(sError)
|
||||
@@ -126,11 +142,15 @@ func (t transport) Close() (err error) {
|
||||
return t.sock.Close()
|
||||
}
|
||||
|
||||
func (t transport) CreateSyncTransport() (sTp syncTransport, err error) {
|
||||
if err = t.Send("sync:"); err != nil {
|
||||
return syncTransport{}, err
|
||||
func (t transport) SendWithCheck(command string) (err error) {
|
||||
if err = t.Send(command); err != nil {
|
||||
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
|
||||
}
|
||||
sTp = newSyncTransport(t.sock, t.readTimeout)
|
||||
|
||||
@@ -377,7 +377,19 @@ func (dExt *DriverExt) GenAbsScope(x1, y1, x2, y2 float64) AbsScope {
|
||||
}
|
||||
|
||||
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 {
|
||||
case ACTION_AppInstall:
|
||||
@@ -506,7 +518,7 @@ func (dExt *DriverExt) DoAction(action MobileAction) error {
|
||||
case ACTION_ScreenShot:
|
||||
// take screenshot
|
||||
log.Info().Msg("take screenshot for current screen")
|
||||
_, _, err := dExt.TakeScreenShot(builtin.GenNameWithTimestamp("%d_screenshot"))
|
||||
_, _, err := dExt.takeScreenShot(builtin.GenNameWithTimestamp("%d_screenshot"))
|
||||
return err
|
||||
case ACTION_StartCamera:
|
||||
return dExt.Driver.StartCamera()
|
||||
|
||||
@@ -91,7 +91,7 @@ func NewAndroidDevice(options ...AndroidDeviceOption) (device *AndroidDevice, er
|
||||
|
||||
deviceList, err := GetAndroidDevices(device.SerialNumber)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(code.AndroidDeviceConnectionError, err.Error())
|
||||
return nil, err
|
||||
}
|
||||
|
||||
dev := deviceList[0]
|
||||
@@ -106,12 +106,11 @@ func NewAndroidDevice(options ...AndroidDeviceOption) (device *AndroidDevice, er
|
||||
func GetAndroidDevices(serial ...string) (devices []*gadb.Device, err error) {
|
||||
var adbClient gadb.Client
|
||||
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 {
|
||||
return nil, errors.Wrap(code.AndroidDeviceConnectionError,
|
||||
fmt.Sprintf("list android devices failed: %v", err))
|
||||
return nil, err
|
||||
}
|
||||
|
||||
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) {
|
||||
var localPort int
|
||||
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))
|
||||
}
|
||||
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",
|
||||
localPort, UIA2ServerPort, err))
|
||||
}
|
||||
@@ -204,7 +203,7 @@ func (dev *AndroidDevice) NewUSBDriver(capabilities Capabilities) (driver WebDri
|
||||
uiaDriver, err := NewUIADriver(capabilities, rawURL)
|
||||
if err != nil {
|
||||
_ = 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.logcat = dev.logcat
|
||||
|
||||
@@ -124,9 +124,8 @@ func NewDriverExt(device Device, driver WebDriver) (dExt *DriverExt, err error)
|
||||
return dExt, nil
|
||||
}
|
||||
|
||||
// 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) {
|
||||
// takeScreenShot takes screenshot and saves image file to $CWD/screenshots/ folder
|
||||
func (dExt *DriverExt) takeScreenShot(fileName string) (raw *bytes.Buffer, path string, err error) {
|
||||
// iOS 优先使用 MJPEG 流进行截图,性能最优
|
||||
// 如果 MJPEG 流未开启,则使用 WebDriver 的截图接口
|
||||
if dExt.frame != nil {
|
||||
@@ -145,17 +144,13 @@ func (dExt *DriverExt) TakeScreenShot(fileName ...string) (raw *bytes.Buffer, pa
|
||||
}
|
||||
|
||||
// save screenshot to file
|
||||
if len(fileName) > 0 && fileName[0] != "" {
|
||||
path := filepath.Join(env.ScreenShotsPath, fileName[0])
|
||||
path, err := dExt.saveScreenShot(compressed, path)
|
||||
if err != nil {
|
||||
log.Error().Err(err).Msg("save screenshot file failed")
|
||||
return nil, "", err
|
||||
}
|
||||
return compressed, path, nil
|
||||
path = filepath.Join(env.ScreenShotsPath, fileName)
|
||||
path, err = dExt.saveScreenShot(compressed, path)
|
||||
if err != nil {
|
||||
log.Error().Err(err).Msg("save screenshot file failed")
|
||||
return nil, "", err
|
||||
}
|
||||
|
||||
return compressed, "", nil
|
||||
return compressed, path, nil
|
||||
}
|
||||
|
||||
func compressImageBuffer(raw *bytes.Buffer) (compressed *bytes.Buffer, err error) {
|
||||
|
||||
@@ -59,7 +59,7 @@ type ImageResult struct {
|
||||
LiveType string `json:"liveType"` // 直播间类型
|
||||
}
|
||||
|
||||
type ImageResponse struct {
|
||||
type APIResponseImage struct {
|
||||
Code int `json:"code"`
|
||||
Message string `json:"message"`
|
||||
Result ImageResult `json:"result"`
|
||||
@@ -248,7 +248,7 @@ func (s *veDEMImageService) GetImage(imageBuf *bytes.Buffer) (
|
||||
log.Debug().
|
||||
Str("X-TT-LOGID", logID).
|
||||
Int("image_bytes", size).
|
||||
Float64("elapsed_seconds", elapsed.Seconds()).
|
||||
Float64("elapsed(s)", elapsed.Seconds()).
|
||||
Msg("request OCR service success")
|
||||
break
|
||||
}
|
||||
@@ -279,7 +279,7 @@ func (s *veDEMImageService) GetImage(imageBuf *bytes.Buffer) (
|
||||
return
|
||||
}
|
||||
|
||||
var imageResponse ImageResponse
|
||||
var imageResponse APIResponseImage
|
||||
err = json.Unmarshal(results, &imageResponse)
|
||||
if err != nil {
|
||||
log.Error().Err(err).
|
||||
@@ -334,19 +334,20 @@ type IImageService interface {
|
||||
}
|
||||
|
||||
// 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 imagePath string
|
||||
if bufSource, imagePath, err = dExt.TakeScreenShot(
|
||||
if bufSource, imagePath, err = dExt.takeScreenShot(
|
||||
builtin.GenNameWithTimestamp("%d_ocr")); err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
imageResult, err = dExt.ImageService.GetImage(bufSource)
|
||||
imageResult, err := dExt.ImageService.GetImage(bufSource)
|
||||
if err != nil {
|
||||
log.Error().Err(err).Msg("GetScreenResult failed")
|
||||
log.Error().Err(err).Msg("GetImage from ImageService failed")
|
||||
return
|
||||
}
|
||||
imageResult.imagePath = imagePath
|
||||
|
||||
imageUrl := imageResult.URL
|
||||
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")
|
||||
}
|
||||
|
||||
dExt.cacheStepData.screenResults[imagePath] = &ScreenResult{
|
||||
Texts: imageResult.OCRResult.ToOCRTexts(),
|
||||
screenResult = &ScreenResult{
|
||||
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 imageResult, nil
|
||||
return screenResult, nil
|
||||
}
|
||||
|
||||
func (dExt *DriverExt) GetScreenTexts() (ocrTexts OCRTexts, err error) {
|
||||
imageResult, err := dExt.GetScreenResult()
|
||||
screenResult, err := dExt.GetScreenResult()
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
return imageResult.OCRResult.ToOCRTexts(), nil
|
||||
return screenResult.Texts, nil
|
||||
}
|
||||
|
||||
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 {
|
||||
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
|
||||
}
|
||||
|
||||
|
||||
@@ -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 {
|
||||
if len(popup) != 2 {
|
||||
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 {
|
||||
log.Warn().Interface("popup", popup).
|
||||
Interface("texts", screenResult.Texts).Msg("text popup found")
|
||||
Interface("texts", screenTexts).Msg("text popup found")
|
||||
point := points[1].Center()
|
||||
log.Info().Str("text", points[1].Text).Msg("close popup")
|
||||
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
|
||||
findTexts := func(d *DriverExt) error {
|
||||
var err error
|
||||
ocrTexts, err := d.GetScreenTexts()
|
||||
screenTexts, err := d.GetScreenTexts()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
points, err := ocrTexts.FindTexts(texts, dExt.ParseActionOptions(options...)...)
|
||||
points, err := screenTexts.FindTexts(texts, dExt.ParseActionOptions(options...)...)
|
||||
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
|
||||
}
|
||||
|
||||
// target texts found, pick the first one
|
||||
point = points[0].Center() // FIXME
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -250,17 +250,13 @@ func (l *LiveCrawler) Run(driver *DriverExt, enterPoint PointF) error {
|
||||
}
|
||||
|
||||
// take screenshot and get screen texts by OCR
|
||||
imageResult, err := l.driver.GetScreenResult()
|
||||
screenResult, err := l.driver.GetScreenResult()
|
||||
if err != nil {
|
||||
log.Error().Err(err).Msg("OCR GetTexts failed")
|
||||
time.Sleep(3 * time.Second)
|
||||
continue
|
||||
}
|
||||
screenResult := l.driver.cacheStepData.screenResults[imageResult.imagePath]
|
||||
screenResult.Tags = []string{"live"}
|
||||
if imageResult.LiveType != "" {
|
||||
screenResult.Tags = append(screenResult.Tags, imageResult.LiveType)
|
||||
}
|
||||
screenResult.Tags = append([]string{"live"}, screenResult.Tags...)
|
||||
|
||||
// check live type and incr live count
|
||||
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")
|
||||
default:
|
||||
// take screenshot and get screen texts by OCR
|
||||
imageResult, err := dExt.GetScreenResult()
|
||||
screenResult, err := dExt.GetScreenResult()
|
||||
if err != nil {
|
||||
if strings.Contains(err.Error(), "connect: connection refused") {
|
||||
return err
|
||||
@@ -373,17 +369,15 @@ func (dExt *DriverExt) VideoCrawler(configs *VideoCrawlerConfigs) (err error) {
|
||||
time.Sleep(3 * time.Second)
|
||||
continue
|
||||
}
|
||||
screenResult := dExt.cacheStepData.screenResults[imageResult.imagePath]
|
||||
|
||||
// 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")
|
||||
return err
|
||||
}
|
||||
|
||||
// check if live video && run live crawler
|
||||
texts := imageResult.OCRResult.ToOCRTexts()
|
||||
if enterPoint, isLive := liveCrawler.checkLiveVideo(texts); isLive {
|
||||
if enterPoint, isLive := liveCrawler.checkLiveVideo(screenResult.Texts); isLive {
|
||||
log.Info().Msg("live video found")
|
||||
if !liveCrawler.currentStat.isLiveTargetAchieved() {
|
||||
if err := liveCrawler.Run(dExt, enterPoint); err != nil {
|
||||
|
||||
@@ -539,8 +539,9 @@ func (r *SessionRunner) Start(givenVars map[string]interface{}) error {
|
||||
parsedName = step.Name()
|
||||
}
|
||||
stepName := convertString(parsedName)
|
||||
log.Info().Str("step", stepName).
|
||||
Str("type", string(step.Type())).Msg("run step start")
|
||||
stepType := string(step.Type())
|
||||
log.Info().Str("step", stepName).Str("type", stepType).Msg("run step start")
|
||||
stepStartTime := time.Now()
|
||||
|
||||
// run times of step
|
||||
loopTimes := step.Struct().Loops
|
||||
@@ -563,10 +564,10 @@ func (r *SessionRunner) Start(givenVars map[string]interface{}) error {
|
||||
}
|
||||
|
||||
// run step
|
||||
stepStartTime := time.Now().Unix()
|
||||
startTime := time.Now().Unix()
|
||||
stepResult, err = step.Run(r)
|
||||
stepResult.Name = stepName + loopIndex
|
||||
stepResult.StartTime = stepStartTime
|
||||
stepResult.StartTime = startTime
|
||||
|
||||
r.updateSummary(stepResult)
|
||||
}
|
||||
@@ -576,19 +577,22 @@ func (r *SessionRunner) Start(givenVars map[string]interface{}) error {
|
||||
r.sessionVariables[k] = v
|
||||
}
|
||||
|
||||
stepElapsed := time.Since(stepStartTime).Seconds()
|
||||
if err == nil {
|
||||
log.Info().Str("step", stepResult.Name).
|
||||
Str("type", string(stepResult.StepType)).
|
||||
log.Info().Str("step", stepName).
|
||||
Str("type", stepType).
|
||||
Bool("success", true).
|
||||
Float64("elapsed(s)", stepElapsed).
|
||||
Interface("exportVars", stepResult.ExportVars).
|
||||
Msg("run step end")
|
||||
continue
|
||||
}
|
||||
|
||||
// failed
|
||||
log.Error().Err(err).Str("step", stepResult.Name).
|
||||
Str("type", string(stepResult.StepType)).
|
||||
log.Error().Err(err).Str("step", stepName).
|
||||
Str("type", stepType).
|
||||
Bool("success", false).
|
||||
Float64("elapsed(s)", stepElapsed).
|
||||
Msg("run step end")
|
||||
|
||||
// interrupted or timeout, abort running
|
||||
|
||||
@@ -6,7 +6,6 @@ import (
|
||||
"github.com/pkg/errors"
|
||||
"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/pkg/uixt"
|
||||
)
|
||||
@@ -598,10 +597,13 @@ func runStepMobileUI(s *SessionRunner, step *TStep) (stepResult *StepResult, err
|
||||
}
|
||||
}
|
||||
|
||||
// take screenshot after each step
|
||||
if _, _, err2 := uiDriver.TakeScreenShot(
|
||||
builtin.GenNameWithTimestamp("%d_step_") + step.Name); err2 != nil {
|
||||
// take screenshot and get screen texts by OCR
|
||||
screenTexts, err2 := uiDriver.GetScreenTexts()
|
||||
if err2 != nil {
|
||||
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
|
||||
|
||||
Reference in New Issue
Block a user