mirror of
https://github.com/httprunner/httprunner.git
synced 2026-05-11 18:11:21 +08:00
refactor: move gadb to hrp pkg
This commit is contained in:
@@ -5,10 +5,10 @@ import (
|
||||
"fmt"
|
||||
"os"
|
||||
|
||||
"github.com/electricbubble/gadb"
|
||||
"github.com/pkg/errors"
|
||||
"github.com/spf13/cobra"
|
||||
|
||||
"github.com/httprunner/httprunner/v4/hrp/pkg/gadb"
|
||||
"github.com/httprunner/httprunner/v4/hrp/pkg/uixt"
|
||||
)
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
# boomer
|
||||
|
||||
This module is initially forked from [myzhan/boomer] and made a lot of changes.
|
||||
This module is initially forked from [myzhan/boomer@v1.6.0] and made a lot of changes.
|
||||
|
||||
[myzhan/boomer]: https://github.com/myzhan/boomer
|
||||
[myzhan/boomer@v1.6.0]: https://github.com/myzhan/boomer/tree/v1.6.0
|
||||
|
||||
5
hrp/pkg/gadb/README.md
Normal file
5
hrp/pkg/gadb/README.md
Normal file
@@ -0,0 +1,5 @@
|
||||
# gadb
|
||||
|
||||
This module is initially forked from [electricbubble/gadb@v0.0.7].
|
||||
|
||||
[electricbubble/gadb@v0.0.7]: https://github.com/electricbubble/gadb/tree/v0.0.7
|
||||
216
hrp/pkg/gadb/client.go
Normal file
216
hrp/pkg/gadb/client.go
Normal file
@@ -0,0 +1,216 @@
|
||||
package gadb
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strconv"
|
||||
"strings"
|
||||
)
|
||||
|
||||
const AdbServerPort = 5037
|
||||
const AdbDaemonPort = 5555
|
||||
|
||||
type Client struct {
|
||||
host string
|
||||
port int
|
||||
}
|
||||
|
||||
func NewClient() (Client, error) {
|
||||
return NewClientWith("localhost")
|
||||
}
|
||||
|
||||
func NewClientWith(host string, port ...int) (adbClient Client, err error) {
|
||||
if len(port) == 0 {
|
||||
port = []int{AdbServerPort}
|
||||
}
|
||||
adbClient.host = host
|
||||
adbClient.port = port[0]
|
||||
|
||||
var tp transport
|
||||
if tp, err = adbClient.createTransport(); err != nil {
|
||||
return Client{}, err
|
||||
}
|
||||
defer func() { _ = tp.Close() }()
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
func (c Client) ServerVersion() (version int, err error) {
|
||||
var resp string
|
||||
if resp, err = c.executeCommand("host:version"); err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
var v int64
|
||||
if v, err = strconv.ParseInt(resp, 16, 64); err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
version = int(v)
|
||||
return
|
||||
}
|
||||
|
||||
func (c Client) DeviceSerialList() (serials []string, err error) {
|
||||
var resp string
|
||||
if resp, err = c.executeCommand("host:devices"); err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
lines := strings.Split(resp, "\n")
|
||||
serials = make([]string, 0, len(lines))
|
||||
|
||||
for i := range lines {
|
||||
fields := strings.Fields(lines[i])
|
||||
if len(fields) < 2 {
|
||||
continue
|
||||
}
|
||||
serials = append(serials, fields[0])
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
func (c Client) DeviceList() (devices []Device, err error) {
|
||||
var resp string
|
||||
if resp, err = c.executeCommand("host:devices-l"); err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
lines := strings.Split(resp, "\n")
|
||||
devices = make([]Device, 0, len(lines))
|
||||
|
||||
for i := range lines {
|
||||
line := strings.TrimSpace(lines[i])
|
||||
if line == "" {
|
||||
continue
|
||||
}
|
||||
|
||||
fields := strings.Fields(line)
|
||||
if len(fields) < 5 || len(fields[0]) == 0 {
|
||||
debugLog(fmt.Sprintf("can't parse: %s", line))
|
||||
continue
|
||||
}
|
||||
|
||||
sliceAttrs := fields[2:]
|
||||
mapAttrs := map[string]string{}
|
||||
for _, field := range sliceAttrs {
|
||||
split := strings.Split(field, ":")
|
||||
key, val := split[0], split[1]
|
||||
mapAttrs[key] = val
|
||||
}
|
||||
devices = append(devices, Device{adbClient: c, serial: fields[0], attrs: mapAttrs})
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
func (c Client) ForwardList() (deviceForward []DeviceForward, err error) {
|
||||
var resp string
|
||||
if resp, err = c.executeCommand("host:list-forward"); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
lines := strings.Split(resp, "\n")
|
||||
deviceForward = make([]DeviceForward, 0, len(lines))
|
||||
|
||||
for i := range lines {
|
||||
line := strings.TrimSpace(lines[i])
|
||||
if line == "" {
|
||||
continue
|
||||
}
|
||||
fields := strings.Fields(line)
|
||||
deviceForward = append(deviceForward, DeviceForward{Serial: fields[0], Local: fields[1], Remote: fields[2]})
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
func (c Client) ForwardKillAll() (err error) {
|
||||
_, err = c.executeCommand("host:killforward-all", true)
|
||||
return
|
||||
}
|
||||
|
||||
func (c Client) Connect(ip string, port ...int) (err error) {
|
||||
if len(port) == 0 {
|
||||
port = []int{AdbDaemonPort}
|
||||
}
|
||||
|
||||
var resp string
|
||||
if resp, err = c.executeCommand(fmt.Sprintf("host:connect:%s:%d", ip, port[0])); err != nil {
|
||||
return err
|
||||
}
|
||||
if !strings.HasPrefix(resp, "connected to") && !strings.HasPrefix(resp, "already connected to") {
|
||||
return fmt.Errorf("adb connect: %s", resp)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func (c Client) Disconnect(ip string, port ...int) (err error) {
|
||||
cmd := fmt.Sprintf("host:disconnect:%s", ip)
|
||||
if len(port) != 0 {
|
||||
cmd = fmt.Sprintf("host:disconnect:%s:%d", ip, port[0])
|
||||
}
|
||||
|
||||
var resp string
|
||||
if resp, err = c.executeCommand(cmd); err != nil {
|
||||
return err
|
||||
}
|
||||
if !strings.HasPrefix(resp, "disconnected") {
|
||||
return fmt.Errorf("adb disconnect: %s", resp)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func (c Client) DisconnectAll() (err error) {
|
||||
var resp string
|
||||
if resp, err = c.executeCommand("host:disconnect:"); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if !strings.HasPrefix(resp, "disconnected everything") {
|
||||
return fmt.Errorf("adb disconnect all: %s", resp)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func (c Client) KillServer() (err error) {
|
||||
var tp transport
|
||||
if tp, err = c.createTransport(); err != nil {
|
||||
return err
|
||||
}
|
||||
defer func() { _ = tp.Close() }()
|
||||
|
||||
err = tp.Send("host:kill")
|
||||
return
|
||||
}
|
||||
|
||||
func (c Client) createTransport() (tp transport, err error) {
|
||||
return newTransport(fmt.Sprintf("%s:%d", c.host, c.port))
|
||||
}
|
||||
|
||||
func (c Client) executeCommand(command string, onlyVerifyResponse ...bool) (resp string, err error) {
|
||||
if len(onlyVerifyResponse) == 0 {
|
||||
onlyVerifyResponse = []bool{false}
|
||||
}
|
||||
|
||||
var tp transport
|
||||
if tp, err = c.createTransport(); err != nil {
|
||||
return "", err
|
||||
}
|
||||
defer func() { _ = tp.Close() }()
|
||||
|
||||
if err = tp.Send(command); err != nil {
|
||||
return "", err
|
||||
}
|
||||
if err = tp.VerifyResponse(); err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
if onlyVerifyResponse[0] {
|
||||
return
|
||||
}
|
||||
|
||||
if resp, err = tp.UnpackString(); err != nil {
|
||||
return "", err
|
||||
}
|
||||
return
|
||||
}
|
||||
145
hrp/pkg/gadb/client_test.go
Normal file
145
hrp/pkg/gadb/client_test.go
Normal file
@@ -0,0 +1,145 @@
|
||||
package gadb
|
||||
|
||||
import (
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestClient_ServerVersion(t *testing.T) {
|
||||
SetDebug(true)
|
||||
|
||||
adbClient, err := NewClient()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
adbServerVersion, err := adbClient.ServerVersion()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
t.Log(adbServerVersion)
|
||||
}
|
||||
|
||||
func TestClient_DeviceSerialList(t *testing.T) {
|
||||
SetDebug(true)
|
||||
|
||||
adbClient, err := NewClient()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
serials, err := adbClient.DeviceSerialList()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
for i := range serials {
|
||||
t.Log(serials[i])
|
||||
}
|
||||
}
|
||||
|
||||
func TestClient_DeviceList(t *testing.T) {
|
||||
SetDebug(true)
|
||||
|
||||
adbClient, err := NewClient()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
devices, err := adbClient.DeviceList()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
for i := range devices {
|
||||
t.Log(devices[i].serial, devices[i].DeviceInfo())
|
||||
}
|
||||
}
|
||||
|
||||
func TestClient_ForwardList(t *testing.T) {
|
||||
SetDebug(true)
|
||||
|
||||
adbClient, err := NewClient()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
deviceForwardList, err := adbClient.ForwardList()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
for i := range deviceForwardList {
|
||||
t.Log(deviceForwardList[i])
|
||||
}
|
||||
}
|
||||
|
||||
func TestClient_ForwardKillAll(t *testing.T) {
|
||||
SetDebug(true)
|
||||
|
||||
adbClient, err := NewClient()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
err = adbClient.ForwardKillAll()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestClient_Connect(t *testing.T) {
|
||||
adbClient, err := NewClient()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
SetDebug(true)
|
||||
|
||||
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)
|
||||
}
|
||||
|
||||
SetDebug(true)
|
||||
|
||||
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)
|
||||
}
|
||||
|
||||
SetDebug(true)
|
||||
|
||||
err = adbClient.DisconnectAll()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestClient_KillServer(t *testing.T) {
|
||||
SetDebug(true)
|
||||
|
||||
adbClient, err := NewClient()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
err = adbClient.KillServer()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
299
hrp/pkg/gadb/device.go
Normal file
299
hrp/pkg/gadb/device.go
Normal file
@@ -0,0 +1,299 @@
|
||||
package gadb
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"os"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
type DeviceFileInfo struct {
|
||||
Name string
|
||||
Mode os.FileMode
|
||||
Size uint32
|
||||
LastModified time.Time
|
||||
}
|
||||
|
||||
func (info DeviceFileInfo) IsDir() bool {
|
||||
return (info.Mode & (1 << 14)) == (1 << 14)
|
||||
}
|
||||
|
||||
const DefaultFileMode = os.FileMode(0664)
|
||||
|
||||
type DeviceState string
|
||||
|
||||
const (
|
||||
StateUnknown DeviceState = "UNKNOWN"
|
||||
StateOnline DeviceState = "online"
|
||||
StateOffline DeviceState = "offline"
|
||||
StateDisconnected DeviceState = "disconnected"
|
||||
)
|
||||
|
||||
var deviceStateStrings = map[string]DeviceState{
|
||||
"": StateDisconnected,
|
||||
"offline": StateOffline,
|
||||
"device": StateOnline,
|
||||
}
|
||||
|
||||
func deviceStateConv(k string) (deviceState DeviceState) {
|
||||
var ok bool
|
||||
if deviceState, ok = deviceStateStrings[k]; !ok {
|
||||
return StateUnknown
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
type DeviceForward struct {
|
||||
Serial string
|
||||
Local string
|
||||
Remote string
|
||||
// LocalProtocol string
|
||||
// RemoteProtocol string
|
||||
}
|
||||
|
||||
type Device struct {
|
||||
adbClient Client
|
||||
serial string
|
||||
attrs map[string]string
|
||||
}
|
||||
|
||||
func (d Device) Product() string {
|
||||
return d.attrs["product"]
|
||||
}
|
||||
|
||||
func (d Device) Model() string {
|
||||
return d.attrs["model"]
|
||||
}
|
||||
|
||||
func (d Device) Usb() string {
|
||||
return d.attrs["usb"]
|
||||
}
|
||||
|
||||
func (d Device) transportId() string {
|
||||
return d.attrs["transport_id"]
|
||||
}
|
||||
|
||||
func (d Device) DeviceInfo() map[string]string {
|
||||
return d.attrs
|
||||
}
|
||||
|
||||
func (d Device) Serial() string {
|
||||
// resp, err := d.adbClient.executeCommand(fmt.Sprintf("host-serial:%s:get-serialno", d.serial))
|
||||
return d.serial
|
||||
}
|
||||
|
||||
func (d Device) IsUsb() bool {
|
||||
return d.Usb() != ""
|
||||
}
|
||||
|
||||
func (d Device) State() (DeviceState, error) {
|
||||
resp, err := d.adbClient.executeCommand(fmt.Sprintf("host-serial:%s:get-state", d.serial))
|
||||
return deviceStateConv(resp), err
|
||||
}
|
||||
|
||||
func (d Device) DevicePath() (string, error) {
|
||||
resp, err := d.adbClient.executeCommand(fmt.Sprintf("host-serial:%s:get-devpath", d.serial))
|
||||
return resp, err
|
||||
}
|
||||
|
||||
func (d Device) Forward(localPort, remotePort int, noRebind ...bool) (err error) {
|
||||
command := ""
|
||||
local := fmt.Sprintf("tcp:%d", localPort)
|
||||
remote := fmt.Sprintf("tcp:%d", remotePort)
|
||||
|
||||
if len(noRebind) != 0 && noRebind[0] {
|
||||
command = fmt.Sprintf("host-serial:%s:forward:norebind:%s;%s", d.serial, local, remote)
|
||||
} else {
|
||||
command = fmt.Sprintf("host-serial:%s:forward:%s;%s", d.serial, local, remote)
|
||||
}
|
||||
|
||||
_, err = d.adbClient.executeCommand(command, true)
|
||||
return
|
||||
}
|
||||
|
||||
func (d Device) ForwardList() (deviceForwardList []DeviceForward, err error) {
|
||||
var forwardList []DeviceForward
|
||||
if forwardList, err = d.adbClient.ForwardList(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
deviceForwardList = make([]DeviceForward, 0, len(deviceForwardList))
|
||||
for i := range forwardList {
|
||||
if forwardList[i].Serial == d.serial {
|
||||
deviceForwardList = append(deviceForwardList, forwardList[i])
|
||||
}
|
||||
}
|
||||
// resp, err := d.adbClient.executeCommand(fmt.Sprintf("host-serial:%s:list-forward", d.serial))
|
||||
return
|
||||
}
|
||||
|
||||
func (d Device) ForwardKill(localPort int) (err error) {
|
||||
local := fmt.Sprintf("tcp:%d", localPort)
|
||||
_, err = d.adbClient.executeCommand(fmt.Sprintf("host-serial:%s:killforward:%s", d.serial, local), true)
|
||||
return
|
||||
}
|
||||
|
||||
func (d Device) RunShellCommand(cmd string, args ...string) (string, error) {
|
||||
raw, err := d.RunShellCommandWithBytes(cmd, args...)
|
||||
return string(raw), err
|
||||
}
|
||||
|
||||
func (d Device) RunShellCommandWithBytes(cmd string, args ...string) ([]byte, error) {
|
||||
if len(args) > 0 {
|
||||
cmd = fmt.Sprintf("%s %s", cmd, strings.Join(args, " "))
|
||||
}
|
||||
if strings.TrimSpace(cmd) == "" {
|
||||
return nil, errors.New("adb shell: command cannot be empty")
|
||||
}
|
||||
raw, err := d.executeCommand(fmt.Sprintf("shell:%s", cmd))
|
||||
return raw, err
|
||||
}
|
||||
|
||||
func (d Device) EnableAdbOverTCP(port ...int) (err error) {
|
||||
if len(port) == 0 {
|
||||
port = []int{AdbDaemonPort}
|
||||
}
|
||||
|
||||
_, err = d.executeCommand(fmt.Sprintf("tcpip:%d", port[0]), true)
|
||||
return
|
||||
}
|
||||
|
||||
func (d Device) createDeviceTransport() (tp transport, err error) {
|
||||
if tp, err = newTransport(fmt.Sprintf("%s:%d", d.adbClient.host, d.adbClient.port)); err != nil {
|
||||
return transport{}, err
|
||||
}
|
||||
|
||||
if err = tp.Send(fmt.Sprintf("host:transport:%s", d.serial)); err != nil {
|
||||
return transport{}, err
|
||||
}
|
||||
err = tp.VerifyResponse()
|
||||
return
|
||||
}
|
||||
|
||||
func (d Device) executeCommand(command string, onlyVerifyResponse ...bool) (raw []byte, err error) {
|
||||
if len(onlyVerifyResponse) == 0 {
|
||||
onlyVerifyResponse = []bool{false}
|
||||
}
|
||||
|
||||
var tp transport
|
||||
if tp, err = d.createDeviceTransport(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer func() { _ = tp.Close() }()
|
||||
|
||||
if err = tp.Send(command); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if err = tp.VerifyResponse(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if onlyVerifyResponse[0] {
|
||||
return
|
||||
}
|
||||
|
||||
raw, err = tp.ReadBytesAll()
|
||||
return
|
||||
}
|
||||
|
||||
func (d Device) List(remotePath string) (devFileInfos []DeviceFileInfo, err error) {
|
||||
var tp transport
|
||||
if tp, err = d.createDeviceTransport(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer func() { _ = tp.Close() }()
|
||||
|
||||
var sync syncTransport
|
||||
if sync, err = tp.CreateSyncTransport(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer func() { _ = sync.Close() }()
|
||||
|
||||
if err = sync.Send("LIST", remotePath); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
devFileInfos = make([]DeviceFileInfo, 0)
|
||||
|
||||
var entry DeviceFileInfo
|
||||
for entry, err = sync.ReadDirectoryEntry(); err == nil; entry, err = sync.ReadDirectoryEntry() {
|
||||
if entry == (DeviceFileInfo{}) {
|
||||
break
|
||||
}
|
||||
devFileInfos = append(devFileInfos, entry)
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
func (d Device) PushFile(local *os.File, remotePath string, modification ...time.Time) (err error) {
|
||||
if len(modification) == 0 {
|
||||
var stat os.FileInfo
|
||||
if stat, err = local.Stat(); err != nil {
|
||||
return err
|
||||
}
|
||||
modification = []time.Time{stat.ModTime()}
|
||||
}
|
||||
|
||||
return d.Push(local, remotePath, modification[0], DefaultFileMode)
|
||||
}
|
||||
|
||||
func (d Device) Push(source io.Reader, remotePath string, modification time.Time, mode ...os.FileMode) (err error) {
|
||||
if len(mode) == 0 {
|
||||
mode = []os.FileMode{DefaultFileMode}
|
||||
}
|
||||
|
||||
var tp transport
|
||||
if tp, err = d.createDeviceTransport(); err != nil {
|
||||
return err
|
||||
}
|
||||
defer func() { _ = tp.Close() }()
|
||||
|
||||
var sync syncTransport
|
||||
if sync, err = tp.CreateSyncTransport(); err != nil {
|
||||
return err
|
||||
}
|
||||
defer func() { _ = sync.Close() }()
|
||||
|
||||
data := fmt.Sprintf("%s,%d", remotePath, mode[0])
|
||||
if err = sync.Send("SEND", data); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err = sync.SendStream(source); err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
if err = sync.SendStatus("DONE", uint32(modification.Unix())); err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
if err = sync.VerifyStatus(); err != nil {
|
||||
return
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func (d Device) Pull(remotePath string, dest io.Writer) (err error) {
|
||||
var tp transport
|
||||
if tp, err = d.createDeviceTransport(); err != nil {
|
||||
return err
|
||||
}
|
||||
defer func() { _ = tp.Close() }()
|
||||
|
||||
var sync syncTransport
|
||||
if sync, err = tp.CreateSyncTransport(); err != nil {
|
||||
return err
|
||||
}
|
||||
defer func() { _ = sync.Close() }()
|
||||
|
||||
if err = sync.Send("RECV", remotePath); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
err = sync.WriteStream(dest)
|
||||
return
|
||||
}
|
||||
332
hrp/pkg/gadb/device_test.go
Normal file
332
hrp/pkg/gadb/device_test.go
Normal file
@@ -0,0 +1,332 @@
|
||||
package gadb
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"strings"
|
||||
"testing"
|
||||
"time"
|
||||
)
|
||||
|
||||
func TestDevice_State(t *testing.T) {
|
||||
adbClient, err := NewClient()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
devices, err := adbClient.DeviceList()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
for i := range devices {
|
||||
dev := devices[i]
|
||||
state, err := dev.State()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
t.Log(dev.Serial(), state)
|
||||
}
|
||||
}
|
||||
|
||||
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)
|
||||
}
|
||||
|
||||
for i := range devices {
|
||||
dev := devices[i]
|
||||
devPath, err := dev.DevicePath()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
t.Log(dev.Serial(), devPath)
|
||||
}
|
||||
}
|
||||
|
||||
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)
|
||||
}
|
||||
|
||||
for i := range devices {
|
||||
dev := devices[i]
|
||||
product := dev.Product()
|
||||
t.Log(dev.Serial(), product)
|
||||
}
|
||||
}
|
||||
|
||||
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)
|
||||
}
|
||||
|
||||
for i := range devices {
|
||||
dev := devices[i]
|
||||
t.Log(dev.Serial(), dev.Model())
|
||||
}
|
||||
}
|
||||
|
||||
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)
|
||||
}
|
||||
|
||||
for i := range devices {
|
||||
dev := devices[i]
|
||||
t.Log(dev.Serial(), dev.Usb(), dev.IsUsb())
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
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)
|
||||
}
|
||||
|
||||
for i := range devices {
|
||||
dev := devices[i]
|
||||
t.Log(dev.DeviceInfo())
|
||||
}
|
||||
}
|
||||
|
||||
func TestDevice_Forward(t *testing.T) {
|
||||
adbClient, err := NewClient()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
devices, err := adbClient.DeviceList()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
SetDebug(true)
|
||||
|
||||
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)
|
||||
}
|
||||
}
|
||||
|
||||
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)
|
||||
}
|
||||
|
||||
SetDebug(true)
|
||||
|
||||
for i := range devices {
|
||||
dev := devices[i]
|
||||
forwardList, err := dev.ForwardList()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
t.Log(dev.serial, "->", forwardList)
|
||||
}
|
||||
}
|
||||
|
||||
func TestDevice_ForwardKill(t *testing.T) {
|
||||
adbClient, err := NewClient()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
devices, err := adbClient.DeviceList()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
SetDebug(true)
|
||||
|
||||
err = devices[0].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)
|
||||
}
|
||||
|
||||
// for i := range devices {
|
||||
// dev := devices[i]
|
||||
// // cmdOutput, err := dev.RunShellCommand(`pm list packages | grep "bili"`)
|
||||
// // cmdOutput, err := dev.RunShellCommand(`pm list packages`, `| grep "bili"`)
|
||||
// // cmdOutput, err := dev.RunShellCommand("dumpsys activity | grep mFocusedActivity")
|
||||
// cmdOutput, err := dev.RunShellCommand("monkey", "-p", "tv.danmaku.bili", "-c", "android.intent.category.LAUNCHER", "1")
|
||||
// if err != nil {
|
||||
// t.Fatal(dev.serial, err)
|
||||
// }
|
||||
// t.Log("\n"+dev.serial, cmdOutput)
|
||||
// }
|
||||
|
||||
// SetDebug(true)
|
||||
|
||||
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)
|
||||
}
|
||||
t.Log("\n⬇️"+dev.serial+"⬇️\n", cmdOutput)
|
||||
|
||||
}
|
||||
|
||||
func TestDevice_EnableAdbOverTCP(t *testing.T) {
|
||||
adbClient, err := NewClient()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
devices, err := adbClient.DeviceList()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
dev := devices[len(devices)-1]
|
||||
dev = devices[0]
|
||||
|
||||
SetDebug(true)
|
||||
|
||||
err = dev.EnableAdbOverTCP()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestDevice_List(t *testing.T) {
|
||||
adbClient, err := NewClient()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
devices, err := adbClient.DeviceList()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
dev := devices[len(devices)-1]
|
||||
dev = devices[0]
|
||||
|
||||
SetDebug(true)
|
||||
|
||||
// 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())
|
||||
}
|
||||
}
|
||||
|
||||
func TestDevice_Push(t *testing.T) {
|
||||
adbClient, err := NewClient()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
devices, err := adbClient.DeviceList()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
dev := devices[len(devices)-1]
|
||||
dev = devices[0]
|
||||
|
||||
SetDebug(true)
|
||||
|
||||
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)
|
||||
}
|
||||
}
|
||||
|
||||
func TestDevice_Pull(t *testing.T) {
|
||||
adbClient, err := NewClient()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
devices, err := adbClient.DeviceList()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
dev := devices[len(devices)-1]
|
||||
dev = devices[0]
|
||||
|
||||
SetDebug(true)
|
||||
|
||||
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)
|
||||
}
|
||||
}
|
||||
59
hrp/pkg/gadb/examples/main.go
Normal file
59
hrp/pkg/gadb/examples/main.go
Normal file
@@ -0,0 +1,59 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"log"
|
||||
"os"
|
||||
"strings"
|
||||
|
||||
"github.com/httprunner/httprunner/v4/hrp/pkg/gadb"
|
||||
)
|
||||
|
||||
func main() {
|
||||
adbClient, err := gadb.NewClient()
|
||||
checkErr(err, "fail to connect adb server")
|
||||
|
||||
devices, err := adbClient.DeviceList()
|
||||
checkErr(err)
|
||||
|
||||
if len(devices) == 0 {
|
||||
log.Fatalln("list of devices is empty")
|
||||
}
|
||||
|
||||
dev := devices[0]
|
||||
|
||||
userHomeDir, _ := os.UserHomeDir()
|
||||
apk, err := os.Open(userHomeDir + "/Desktop/xuexi_android_10002068.apk")
|
||||
checkErr(err)
|
||||
|
||||
log.Println("starting to push apk")
|
||||
|
||||
remotePath := "/data/local/tmp/xuexi_android_10002068.apk"
|
||||
err = dev.PushFile(apk, remotePath)
|
||||
checkErr(err, "adb push")
|
||||
|
||||
log.Println("push completed")
|
||||
|
||||
log.Println("starting to install apk")
|
||||
|
||||
shellOutput, err := dev.RunShellCommand("pm install", remotePath)
|
||||
checkErr(err, "pm install")
|
||||
if !strings.Contains(shellOutput, "Success") {
|
||||
log.Fatalln("fail to install: ", shellOutput)
|
||||
}
|
||||
|
||||
log.Println("install completed")
|
||||
|
||||
}
|
||||
|
||||
func checkErr(err error, msg ...string) {
|
||||
if err == nil {
|
||||
return
|
||||
}
|
||||
|
||||
var output string
|
||||
if len(msg) != 0 {
|
||||
output = msg[0] + " "
|
||||
}
|
||||
output += err.Error()
|
||||
log.Fatalln(output)
|
||||
}
|
||||
17
hrp/pkg/gadb/gadb.go
Normal file
17
hrp/pkg/gadb/gadb.go
Normal file
@@ -0,0 +1,17 @@
|
||||
package gadb
|
||||
|
||||
import "log"
|
||||
|
||||
var debugFlag = false
|
||||
|
||||
// SetDebug set debug mode
|
||||
func SetDebug(debug bool) {
|
||||
debugFlag = debug
|
||||
}
|
||||
|
||||
func debugLog(msg string) {
|
||||
if !debugFlag {
|
||||
return
|
||||
}
|
||||
log.Println("[DEBUG] [gadb] " + msg)
|
||||
}
|
||||
252
hrp/pkg/gadb/sync_transport.go
Normal file
252
hrp/pkg/gadb/sync_transport.go
Normal file
@@ -0,0 +1,252 @@
|
||||
package gadb
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/binary"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"net"
|
||||
"time"
|
||||
)
|
||||
|
||||
type syncTransport struct {
|
||||
sock net.Conn
|
||||
readTimeout time.Duration
|
||||
}
|
||||
|
||||
func newSyncTransport(sock net.Conn, readTimeout time.Duration) syncTransport {
|
||||
return syncTransport{sock: sock, readTimeout: readTimeout}
|
||||
}
|
||||
|
||||
func (sync syncTransport) Send(command, data string) (err error) {
|
||||
if len(command) != 4 {
|
||||
return errors.New("sync commands must have length 4")
|
||||
}
|
||||
msg := bytes.NewBufferString(command)
|
||||
if err = binary.Write(msg, binary.LittleEndian, int32(len(data))); err != nil {
|
||||
return fmt.Errorf("sync transport write: %w", err)
|
||||
}
|
||||
msg.WriteString(data)
|
||||
|
||||
debugLog(fmt.Sprintf("--> %s", msg.String()))
|
||||
return _send(sync.sock, msg.Bytes())
|
||||
}
|
||||
|
||||
func (sync syncTransport) SendStream(reader io.Reader) (err error) {
|
||||
syncMaxChunkSize := 64 * 1024
|
||||
for err == nil {
|
||||
tmp := make([]byte, syncMaxChunkSize)
|
||||
var n int
|
||||
n, err = reader.Read(tmp)
|
||||
if err == io.EOF {
|
||||
err = nil
|
||||
break
|
||||
}
|
||||
if err == nil {
|
||||
err = sync.sendChunk(tmp[:n])
|
||||
}
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
func (sync syncTransport) SendStatus(statusCode string, n uint32) (err error) {
|
||||
msg := bytes.NewBufferString(statusCode)
|
||||
if err = binary.Write(msg, binary.LittleEndian, n); err != nil {
|
||||
return fmt.Errorf("sync transport write: %w", err)
|
||||
}
|
||||
debugLog(fmt.Sprintf("--> %s", msg.String()))
|
||||
return _send(sync.sock, msg.Bytes())
|
||||
}
|
||||
|
||||
func (sync syncTransport) sendChunk(buffer []byte) (err error) {
|
||||
msg := bytes.NewBufferString("DATA")
|
||||
if err = binary.Write(msg, binary.LittleEndian, int32(len(buffer))); err != nil {
|
||||
return fmt.Errorf("sync transport write: %w", err)
|
||||
}
|
||||
debugLog(fmt.Sprintf("--> %s ......", msg.String()))
|
||||
msg.Write(buffer)
|
||||
return _send(sync.sock, msg.Bytes())
|
||||
}
|
||||
|
||||
func (sync syncTransport) VerifyStatus() (err error) {
|
||||
var status string
|
||||
if status, err = sync.ReadStringN(4); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
log := bytes.NewBufferString(fmt.Sprintf("<-- %s", status))
|
||||
defer func() {
|
||||
debugLog(log.String())
|
||||
}()
|
||||
|
||||
var tmpUint32 uint32
|
||||
if tmpUint32, err = sync.ReadUint32(); err != nil {
|
||||
return fmt.Errorf("sync transport read (status): %w", err)
|
||||
}
|
||||
log.WriteString(fmt.Sprintf(" %d\t", tmpUint32))
|
||||
|
||||
var msg string
|
||||
if msg, err = sync.ReadStringN(int(tmpUint32)); err != nil {
|
||||
return err
|
||||
}
|
||||
log.WriteString(msg)
|
||||
|
||||
if status == "FAIL" {
|
||||
err = fmt.Errorf("sync verify status (fail): %s", msg)
|
||||
return
|
||||
}
|
||||
|
||||
if status != "OKAY" {
|
||||
err = fmt.Errorf("sync verify status: Unknown error: %s", msg)
|
||||
return
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
var syncReadChunkDone = errors.New("sync read chunk done")
|
||||
|
||||
func (sync syncTransport) WriteStream(dest io.Writer) (err error) {
|
||||
var chunk []byte
|
||||
save := func() error {
|
||||
if chunk, err = sync.readChunk(); err != nil && err != syncReadChunkDone {
|
||||
return fmt.Errorf("sync read chunk: %w", err)
|
||||
}
|
||||
if err == syncReadChunkDone {
|
||||
return err
|
||||
}
|
||||
if err = _send(dest, chunk); err != nil {
|
||||
return fmt.Errorf("sync write stream: %w", err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
for err == nil {
|
||||
err = save()
|
||||
}
|
||||
|
||||
if err == syncReadChunkDone {
|
||||
err = nil
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func (sync syncTransport) readChunk() (chunk []byte, err error) {
|
||||
var status string
|
||||
if status, err = sync.ReadStringN(4); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
log := bytes.NewBufferString("")
|
||||
defer func() { debugLog(log.String()) }()
|
||||
|
||||
var tmpUint32 uint32
|
||||
if tmpUint32, err = sync.ReadUint32(); err != nil {
|
||||
return nil, fmt.Errorf("read chunk (length): %w", err)
|
||||
}
|
||||
|
||||
if status == "FAIL" {
|
||||
log.WriteString(fmt.Sprintf("<-- %s\t%d\t", status, tmpUint32))
|
||||
var sError string
|
||||
if sError, err = sync.ReadStringN(int(tmpUint32)); err != nil {
|
||||
return nil, fmt.Errorf("read chunk (error message): %w", err)
|
||||
}
|
||||
err = fmt.Errorf("status (fail): %s", sError)
|
||||
log.WriteString(sError)
|
||||
return
|
||||
}
|
||||
|
||||
switch status {
|
||||
case "DONE":
|
||||
log.WriteString(fmt.Sprintf("<-- %s", status))
|
||||
err = syncReadChunkDone
|
||||
return
|
||||
case "DATA":
|
||||
log.WriteString(fmt.Sprintf("<-- %s\t%d\t", status, tmpUint32))
|
||||
if chunk, err = sync.ReadBytesN(int(tmpUint32)); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
default:
|
||||
log.WriteString(fmt.Sprintf("<-- %s\t%d\t", status, tmpUint32))
|
||||
err = errors.New("unknown error")
|
||||
}
|
||||
|
||||
log.WriteString("......")
|
||||
|
||||
return
|
||||
|
||||
}
|
||||
|
||||
func (sync syncTransport) ReadDirectoryEntry() (entry DeviceFileInfo, err error) {
|
||||
var status string
|
||||
if status, err = sync.ReadStringN(4); err != nil {
|
||||
return DeviceFileInfo{}, err
|
||||
}
|
||||
|
||||
log := bytes.NewBufferString(fmt.Sprintf("<-- %s", status))
|
||||
defer func() {
|
||||
debugLog(log.String())
|
||||
}()
|
||||
|
||||
if status == "DONE" {
|
||||
return
|
||||
}
|
||||
|
||||
log = bytes.NewBufferString(fmt.Sprintf("<-- %s\t", status))
|
||||
|
||||
if err = binary.Read(sync.sock, binary.LittleEndian, &entry.Mode); err != nil {
|
||||
return DeviceFileInfo{}, fmt.Errorf("sync transport read (mode): %w", err)
|
||||
}
|
||||
log.WriteString(entry.Mode.String() + "\t")
|
||||
|
||||
if entry.Size, err = sync.ReadUint32(); err != nil {
|
||||
return DeviceFileInfo{}, fmt.Errorf("sync transport read (size): %w", err)
|
||||
}
|
||||
log.WriteString(fmt.Sprintf("%10d", entry.Size) + "\t")
|
||||
|
||||
var tmpUint32 uint32
|
||||
if tmpUint32, err = sync.ReadUint32(); err != nil {
|
||||
return DeviceFileInfo{}, fmt.Errorf("sync transport read (time): %w", err)
|
||||
}
|
||||
entry.LastModified = time.Unix(int64(tmpUint32), 0)
|
||||
log.WriteString(entry.LastModified.String() + "\t")
|
||||
|
||||
if tmpUint32, err = sync.ReadUint32(); err != nil {
|
||||
return DeviceFileInfo{}, fmt.Errorf("sync transport read (file name length): %w", err)
|
||||
}
|
||||
log.WriteString(fmt.Sprintf("%d\t", tmpUint32))
|
||||
|
||||
if entry.Name, err = sync.ReadStringN(int(tmpUint32)); err != nil {
|
||||
return DeviceFileInfo{}, fmt.Errorf("sync transport read (file name): %w", err)
|
||||
}
|
||||
log.WriteString(entry.Name + "\t")
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
func (sync syncTransport) ReadUint32() (n uint32, err error) {
|
||||
err = binary.Read(sync.sock, binary.LittleEndian, &n)
|
||||
return
|
||||
}
|
||||
|
||||
func (sync syncTransport) ReadStringN(size int) (s string, err error) {
|
||||
var raw []byte
|
||||
if raw, err = sync.ReadBytesN(size); err != nil {
|
||||
return "", err
|
||||
}
|
||||
return string(raw), nil
|
||||
}
|
||||
|
||||
func (sync syncTransport) ReadBytesN(size int) (raw []byte, err error) {
|
||||
_ = sync.sock.SetReadDeadline(time.Now().Add(time.Second * sync.readTimeout))
|
||||
return _readN(sync.sock, size)
|
||||
}
|
||||
|
||||
func (sync syncTransport) Close() (err error) {
|
||||
if sync.sock == nil {
|
||||
return nil
|
||||
}
|
||||
return sync.sock.Close()
|
||||
}
|
||||
150
hrp/pkg/gadb/transport.go
Normal file
150
hrp/pkg/gadb/transport.go
Normal file
@@ -0,0 +1,150 @@
|
||||
package gadb
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"net"
|
||||
"strconv"
|
||||
"time"
|
||||
)
|
||||
|
||||
var ErrConnBroken = errors.New("socket connection broken")
|
||||
|
||||
var DefaultAdbReadTimeout time.Duration = 60
|
||||
|
||||
type transport struct {
|
||||
sock net.Conn
|
||||
readTimeout time.Duration
|
||||
}
|
||||
|
||||
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)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func (t transport) Send(command string) (err error) {
|
||||
msg := fmt.Sprintf("%04x%s", len(command), command)
|
||||
debugLog(fmt.Sprintf("--> %s", command))
|
||||
return _send(t.sock, []byte(msg))
|
||||
}
|
||||
|
||||
func (t transport) VerifyResponse() (err error) {
|
||||
var status string
|
||||
if status, err = t.ReadStringN(4); err != nil {
|
||||
return err
|
||||
}
|
||||
if status == "OKAY" {
|
||||
debugLog(fmt.Sprintf("<-- %s", status))
|
||||
return nil
|
||||
}
|
||||
|
||||
var sError string
|
||||
if sError, err = t.UnpackString(); err != nil {
|
||||
return err
|
||||
}
|
||||
err = fmt.Errorf("command failed: %s", sError)
|
||||
debugLog(fmt.Sprintf("<-- %s %s", status, sError))
|
||||
return
|
||||
}
|
||||
|
||||
func (t transport) ReadStringAll() (s string, err error) {
|
||||
var raw []byte
|
||||
raw, err = t.ReadBytesAll()
|
||||
return string(raw), err
|
||||
}
|
||||
|
||||
func (t transport) ReadBytesAll() (raw []byte, err error) {
|
||||
raw, err = ioutil.ReadAll(t.sock)
|
||||
debugLog(fmt.Sprintf("\r%s", raw))
|
||||
return
|
||||
}
|
||||
|
||||
func (t transport) UnpackString() (s string, err error) {
|
||||
var raw []byte
|
||||
raw, err = t.UnpackBytes()
|
||||
return string(raw), err
|
||||
}
|
||||
|
||||
func (t transport) UnpackBytes() (raw []byte, err error) {
|
||||
var length string
|
||||
if length, err = t.ReadStringN(4); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
var size int64
|
||||
if size, err = strconv.ParseInt(length, 16, 64); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
raw, err = t.ReadBytesN(int(size))
|
||||
debugLog(fmt.Sprintf("\r%s", raw))
|
||||
return
|
||||
}
|
||||
|
||||
func (t transport) ReadStringN(size int) (s string, err error) {
|
||||
var raw []byte
|
||||
if raw, err = t.ReadBytesN(size); err != nil {
|
||||
return "", err
|
||||
}
|
||||
return string(raw), nil
|
||||
}
|
||||
|
||||
func (t transport) ReadBytesN(size int) (raw []byte, err error) {
|
||||
_ = t.sock.SetReadDeadline(time.Now().Add(time.Second * t.readTimeout))
|
||||
return _readN(t.sock, size)
|
||||
}
|
||||
|
||||
func (t transport) Close() (err error) {
|
||||
if t.sock == nil {
|
||||
return nil
|
||||
}
|
||||
return t.sock.Close()
|
||||
}
|
||||
|
||||
func (t transport) CreateSyncTransport() (sTp syncTransport, err error) {
|
||||
if err = t.Send("sync:"); err != nil {
|
||||
return syncTransport{}, err
|
||||
}
|
||||
if err = t.VerifyResponse(); err != nil {
|
||||
return syncTransport{}, err
|
||||
}
|
||||
sTp = newSyncTransport(t.sock, t.readTimeout)
|
||||
return
|
||||
}
|
||||
|
||||
func _send(writer io.Writer, msg []byte) (err error) {
|
||||
for totalSent := 0; totalSent < len(msg); {
|
||||
var sent int
|
||||
if sent, err = writer.Write(msg[totalSent:]); err != nil {
|
||||
return err
|
||||
}
|
||||
if sent == 0 {
|
||||
return ErrConnBroken
|
||||
}
|
||||
totalSent += sent
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func _readN(reader io.Reader, size int) (raw []byte, err error) {
|
||||
raw = make([]byte, 0, size)
|
||||
for len(raw) < size {
|
||||
buf := make([]byte, size-len(raw))
|
||||
var n int
|
||||
if n, err = io.ReadFull(reader, buf); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if n == 0 {
|
||||
return nil, ErrConnBroken
|
||||
}
|
||||
raw = append(raw, buf...)
|
||||
}
|
||||
return
|
||||
}
|
||||
26
hrp/pkg/gadb/transport_test.go
Normal file
26
hrp/pkg/gadb/transport_test.go
Normal file
@@ -0,0 +1,26 @@
|
||||
package gadb
|
||||
|
||||
import (
|
||||
"testing"
|
||||
)
|
||||
|
||||
func Test_transport_VerifyResponse(t *testing.T) {
|
||||
SetDebug(true)
|
||||
|
||||
transport, err := newTransport("localhost:5037")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer transport.Close()
|
||||
|
||||
// err = transport.Send("host:123version")
|
||||
err = transport.Send("host:version")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
err = transport.VerifyResponse()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
@@ -9,13 +9,13 @@ import (
|
||||
"reflect"
|
||||
"strings"
|
||||
|
||||
"github.com/electricbubble/gadb"
|
||||
"github.com/pkg/errors"
|
||||
"github.com/rs/zerolog/log"
|
||||
|
||||
"github.com/httprunner/httprunner/v4/hrp/internal/code"
|
||||
"github.com/httprunner/httprunner/v4/hrp/internal/json"
|
||||
"github.com/httprunner/httprunner/v4/hrp/internal/myexec"
|
||||
"github.com/httprunner/httprunner/v4/hrp/pkg/gadb"
|
||||
)
|
||||
|
||||
var (
|
||||
|
||||
@@ -11,11 +11,11 @@ import (
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/electricbubble/gadb"
|
||||
"github.com/pkg/errors"
|
||||
"github.com/rs/zerolog/log"
|
||||
|
||||
"github.com/httprunner/httprunner/v4/hrp/internal/code"
|
||||
"github.com/httprunner/httprunner/v4/hrp/pkg/gadb"
|
||||
)
|
||||
|
||||
var errDriverNotImplemented = errors.New("driver method not implemented")
|
||||
|
||||
Reference in New Issue
Block a user