From 878b626971b8ba5ef2be123b623fa691f53ee37f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E4=BD=99=E6=B3=93=E9=93=AE?= Date: Wed, 18 Sep 2024 13:44:54 +0800 Subject: [PATCH 1/5] =?UTF-8?q?feat:=20=E6=96=B0=E5=A2=9E=E9=B8=BF?= =?UTF-8?q?=E8=92=99=E6=94=AF=E6=8C=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- go.mod | 5 +- go.sum | 2 + hrp/pkg/uixt/harmony_device.go | 158 ++++++++++++++ hrp/pkg/uixt/harmony_hdc_driver.go | 317 +++++++++++++++++++++++++++++ hrp/pkg/uixt/harmony_test.go | 109 ++++++++++ hrp/step_mobile_ui.go | 2 + 6 files changed, 592 insertions(+), 1 deletion(-) create mode 100644 hrp/pkg/uixt/harmony_device.go create mode 100644 hrp/pkg/uixt/harmony_hdc_driver.go create mode 100644 hrp/pkg/uixt/harmony_test.go diff --git a/go.mod b/go.mod index 63cc82fd..da91ad5c 100644 --- a/go.mod +++ b/go.mod @@ -1,6 +1,8 @@ module github.com/httprunner/httprunner/v4 -go 1.18 +go 1.22 + +toolchain go1.22.0 require ( github.com/andybalholm/brotli v1.0.4 @@ -39,6 +41,7 @@ require ( require ( cloud.google.com/go/compute v1.23.0 // indirect cloud.google.com/go/compute/metadata v0.2.3 // indirect + code.byted.org/iesqa/ghdc v0.0.0-20240911080657-3fe04d3190a5 // indirect github.com/beorn7/perks v1.0.1 // indirect github.com/bytedance/sonic v1.11.6 // indirect github.com/bytedance/sonic/loader v0.1.1 // indirect diff --git a/go.sum b/go.sum index 270107b7..5c675132 100644 --- a/go.sum +++ b/go.sum @@ -34,6 +34,8 @@ cloud.google.com/go/storage v1.5.0/go.mod h1:tpKbwo567HUNpVclU5sGELwQWBDZ8gh0Zeo cloud.google.com/go/storage v1.6.0/go.mod h1:N7U0C8pVQ/+NIKOBQyamJIeKQKkZ+mxpohlUTyfDhBk= cloud.google.com/go/storage v1.8.0/go.mod h1:Wv1Oy7z6Yz3DshWRJFhqM/UCfaWIRTdp0RXyy7KQOVs= cloud.google.com/go/storage v1.10.0/go.mod h1:FLPqc6j+Ki4BU591ie1oL6qBQGu2Bl/tZ9ullr3+Kg0= +code.byted.org/iesqa/ghdc v0.0.0-20240911080657-3fe04d3190a5 h1:9H06vi9l4K8xjhQg5Lsu4lbtB2NBKUG/l4XyRGhLuAk= +code.byted.org/iesqa/ghdc v0.0.0-20240911080657-3fe04d3190a5/go.mod h1:0IrKgKT75jmlpi9N0Mi5xWKctJuKHFM6f+ZMQe5vnNs= dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= diff --git a/hrp/pkg/uixt/harmony_device.go b/hrp/pkg/uixt/harmony_device.go new file mode 100644 index 00000000..fc333c77 --- /dev/null +++ b/hrp/pkg/uixt/harmony_device.go @@ -0,0 +1,158 @@ +package uixt + +import ( + "fmt" + + "code.byted.org/iesqa/ghdc" + "github.com/pkg/errors" + "github.com/rs/zerolog/log" + + "github.com/httprunner/httprunner/v4/hrp/code" +) + +var ( + HdcServerHost = "localhost" + HdcServerPort = ghdc.HdcServerPort // 5037 +) + +type HarmonyDevice struct { + d *ghdc.Device + ConnectKey string `json:"connect_key,omitempty" yaml:"connect_key,omitempty"` + IgnorePopup bool `json:"ignore_popup,omitempty" yaml:"ignore_popup,omitempty"` +} + +type HarmonyDeviceOption func(*HarmonyDevice) + +func WithConnectKey(connectKey string) HarmonyDeviceOption { + return func(device *HarmonyDevice) { + device.ConnectKey = connectKey + } +} + +func NewHarmonyDevice(options ...HarmonyDeviceOption) (device *HarmonyDevice, err error) { + device = &HarmonyDevice{} + for _, option := range options { + option(device) + } + + deviceList, err := GetHarmonyDevices(device.ConnectKey) + if err != nil { + return nil, errors.Wrap(code.DeviceConnectionError, err.Error()) + } + + if device.ConnectKey == "" && len(deviceList) > 1 { + return nil, errors.Wrap(code.DeviceConnectionError, "more than one device connected, please specify the serial") + } + + dev := deviceList[0] + + if device.ConnectKey == "" { + selectSerial := dev.Serial() + device.ConnectKey = selectSerial + log.Warn(). + Str("connectKey", device.ConnectKey). + Msg("harmony ConnectKey is not specified, select the first one") + } + + device.d = dev + log.Info().Str("connectKey", device.ConnectKey).Msg("init harmony device") + return device, nil +} + +func GetHarmonyDevices(serial ...string) (devices []*ghdc.Device, err error) { + var hdcClient ghdc.Client + if hdcClient, err = ghdc.NewClientWith(HdcServerHost, HdcServerPort); err != nil { + return nil, err + } + var deviceList []ghdc.Device + + if deviceList, err = hdcClient.DeviceList(); err != nil { + return nil, err + } + + // filter by serial + for _, d := range deviceList { + for _, s := range serial { + if s != "" && s != d.Serial() { + continue + } + devices = append(devices, &d) + } + } + + if len(devices) == 0 { + var err error + if serial == nil || (len(serial) == 1 && serial[0] == "") { + err = fmt.Errorf("no harmony device found") + } else { + err = fmt.Errorf("no harmony device found for serial %v", serial) + } + return nil, err + } + return devices, nil +} + +func (dev *HarmonyDevice) Init() error { + return nil +} + +func (dev *HarmonyDevice) UUID() string { + return dev.ConnectKey +} + +func (dev *HarmonyDevice) LogEnabled() bool { + return false +} + +func (dev *HarmonyDevice) NewDriver(options ...DriverOption) (driverExt *DriverExt, err error) { + driver, err := newHarmonyDriver(dev.d) + if err != nil { + log.Error().Err(err).Msg("failed to new harmony driver") + return nil, err + } + + driverExt, err = newDriverExt(dev, driver, options...) + if err != nil { + return nil, err + } + + return driverExt, nil +} + +func (dev *HarmonyDevice) NewUSBDriver(options ...DriverOption) (driver IWebDriver, err error) { + harmonyDriver, err := newHarmonyDriver(dev.d) + if err != nil { + log.Error().Err(err).Msg("failed to new harmony driver") + return nil, err + } + + return harmonyDriver, nil +} + +func (dev *HarmonyDevice) StartPerf() error { + return nil +} + +func (dev *HarmonyDevice) StopPerf() string { + return "" +} + +func (dev *HarmonyDevice) StartPcap() error { + return nil +} + +func (dev *HarmonyDevice) StopPcap() string { + return "" +} + +func (dev *HarmonyDevice) Install(appPath string, opts *InstallOptions) error { + return nil +} + +func (dev *HarmonyDevice) Uninstall(packageName string) error { + return nil +} + +func (dev *HarmonyDevice) GetPackageInfo(packageName string) (AppInfo, error) { + return AppInfo{}, nil +} diff --git a/hrp/pkg/uixt/harmony_hdc_driver.go b/hrp/pkg/uixt/harmony_hdc_driver.go new file mode 100644 index 00000000..0968d2c4 --- /dev/null +++ b/hrp/pkg/uixt/harmony_hdc_driver.go @@ -0,0 +1,317 @@ +package uixt + +import ( + "bytes" + "fmt" + "os" + "regexp" + "strconv" + "time" + + "code.byted.org/iesqa/ghdc" + "github.com/rs/zerolog/log" +) + +type hdcDriver struct { + Driver + device *ghdc.Device + uiDriver *ghdc.UIDriver +} + +func newHarmonyDriver(device *ghdc.Device) (driver *hdcDriver, err error) { + driver = new(hdcDriver) + driver.device = device + uiDriver, err := ghdc.NewUIDriver(*device) + if err != nil { + log.Error().Err(err).Msg("failed to new harmony ui driver") + return nil, err + } + driver.uiDriver = uiDriver + return +} + +func (hd *hdcDriver) NewSession(capabilities Capabilities) (SessionInfo, error) { + return SessionInfo{}, errDriverNotImplemented +} + +func (hd *hdcDriver) DeleteSession() error { + return errDriverNotImplemented +} + +func (hd *hdcDriver) GetSession() *DriverSession { + return nil +} + +func (hd *hdcDriver) Status() (DeviceStatus, error) { + return DeviceStatus{}, errDriverNotImplemented +} + +func (hd *hdcDriver) DeviceInfo() (DeviceInfo, error) { + return DeviceInfo{}, errDriverNotImplemented +} + +func (hd *hdcDriver) Location() (Location, error) { + return Location{}, errDriverNotImplemented +} + +func (hd *hdcDriver) BatteryInfo() (BatteryInfo, error) { + return BatteryInfo{}, errDriverNotImplemented +} + +func (hd *hdcDriver) WindowSize() (size Size, err error) { + res, err := hd.device.RunShellCommand("hidumper", "-s", "RenderService", "-a", "screen") + if err != nil { + log.Error().Err(err).Msg("failed to get window size") + return size, err + } + re := regexp.MustCompile(`activeMode:\s*(\d+)x(\d+)`) + matches := re.FindStringSubmatch(res) + + if len(matches) > 2 { + fmt.Printf("Width: %s, Height: %s\n", matches[1], matches[2]) + width, err := strconv.Atoi(matches[1]) + if err != nil { + log.Error().Err(err).Str("width", matches[1]).Msg("failed to get window size") + return size, err + } + size.Width = width + height, err := strconv.Atoi(matches[2]) + if err != nil { + log.Error().Err(err).Str("height", matches[2]).Msg("failed to get window size") + return size, err + } + size.Height = height + return size, nil + } + err = fmt.Errorf("failed to find window size in dump result") + log.Error().Err(err).Str("result", res).Msg("failed to get window size") + return size, err +} + +func (hd *hdcDriver) Screen() (Screen, error) { + return Screen{}, errDriverNotImplemented +} + +func (hd *hdcDriver) Scale() (float64, error) { + return 1, nil +} + +func (hd *hdcDriver) GetTimestamp() (timestamp int64, err error) { + return 0, errDriverNotImplemented +} + +func (hd *hdcDriver) Homescreen() error { + return hd.uiDriver.PressKey(ghdc.KEYCODE_HOME) +} + +func (hd *hdcDriver) Unlock() (err error) { + return hd.uiDriver.PressKey(ghdc.KEYCODE_HOME) +} + +func (hd *hdcDriver) AppLaunch(packageName string) error { + // Todo + return errDriverNotImplemented +} + +func (hd *hdcDriver) AppTerminate(packageName string) (bool, error) { + // Todo + return false, errDriverNotImplemented +} + +func (hd *hdcDriver) GetForegroundApp() (app AppInfo, err error) { + // Todo + return AppInfo{}, errDriverNotImplemented +} + +func (hd *hdcDriver) AssertForegroundApp(packageName string, activityType ...string) error { + // Todo + return errDriverNotImplemented +} + +func (hd *hdcDriver) StartCamera() error { + return errDriverNotImplemented +} + +func (hd *hdcDriver) StopCamera() error { + return errDriverNotImplemented +} + +func (hd *hdcDriver) Orientation() (orientation Orientation, err error) { + return OrientationPortrait, nil +} + +func (hd *hdcDriver) Tap(x, y int, options ...ActionOption) error { + return hd.TapFloat(float64(x), float64(y), options...) +} + +func (hd *hdcDriver) TapFloat(x, y float64, options ...ActionOption) error { + actionOptions := NewActionOptions(options...) + + if len(actionOptions.Offset) == 2 { + x += float64(actionOptions.Offset[0]) + y += float64(actionOptions.Offset[1]) + } + + x += actionOptions.getRandomOffset() + y += actionOptions.getRandomOffset() + + return hd.uiDriver.Touch(int(x), int(y)) +} + +func (hd *hdcDriver) DoubleTap(x, y int, options ...ActionOption) error { + return errDriverNotImplemented +} + +func (hd *hdcDriver) DoubleTapFloat(x, y float64, options ...ActionOption) error { + return errDriverNotImplemented +} + +func (hd *hdcDriver) TouchAndHold(x, y int, second ...float64) error { + return errDriverNotImplemented +} + +func (hd *hdcDriver) TouchAndHoldFloat(x, y float64, second ...float64) error { + return errDriverNotImplemented +} + +func (hd *hdcDriver) Drag(fromX, fromY, toX, toY int, options ...ActionOption) error { + return errDriverNotImplemented +} + +func (hd *hdcDriver) DragFloat(fromX, fromY, toX, toY float64, options ...ActionOption) error { + return errDriverNotImplemented +} + +// Swipe works like Drag, but `pressForDuration` value is 0 +func (hd *hdcDriver) Swipe(fromX, fromY, toX, toY int, options ...ActionOption) error { + return hd.SwipeFloat(float64(fromX), float64(fromY), float64(toX), float64(toY), options...) +} + +func (hd *hdcDriver) SwipeFloat(fromX, fromY, toX, toY float64, options ...ActionOption) error { + actionOptions := NewActionOptions(options...) + if len(actionOptions.Offset) == 4 { + fromX += float64(actionOptions.Offset[0]) + fromY += float64(actionOptions.Offset[1]) + toX += float64(actionOptions.Offset[2]) + toY += float64(actionOptions.Offset[3]) + } + fromX += actionOptions.getRandomOffset() + fromY += actionOptions.getRandomOffset() + toX += actionOptions.getRandomOffset() + toY += actionOptions.getRandomOffset() + + duration := 0.2 + if actionOptions.PressDuration > 0 { + duration = actionOptions.PressDuration + } + + return hd.uiDriver.Drag(int(fromX), int(fromY), int(toX), int(toY), duration) +} + +func (hd *hdcDriver) SetPasteboard(contentType PasteboardType, content string) error { + return errDriverNotImplemented +} + +func (hd *hdcDriver) GetPasteboard(contentType PasteboardType) (raw *bytes.Buffer, err error) { + return nil, errDriverNotImplemented +} + +func (hd *hdcDriver) SetIme(ime string) error { + return errDriverNotImplemented +} + +func (hd *hdcDriver) SendKeys(text string, options ...ActionOption) error { + return hd.uiDriver.InputText(text) +} + +func (hd *hdcDriver) Input(text string, options ...ActionOption) error { + return hd.uiDriver.InputText(text) +} + +func (hd *hdcDriver) Clear(packageName string) error { + return errDriverNotImplemented +} + +func (hd *hdcDriver) PressButton(devBtn DeviceButton) error { + return errDriverNotImplemented +} + +func (hd *hdcDriver) PressBack(options ...ActionOption) error { + return hd.uiDriver.PressBack() +} + +func (hd *hdcDriver) PressKeyCode(keyCode KeyCode) (err error) { + return errDriverNotImplemented +} + +func (hd *hdcDriver) PressHarmonyKeyCode(keyCode ghdc.KeyCode) (err error) { + return hd.uiDriver.PressKey(keyCode) +} + +func (hd *hdcDriver) Screenshot() (*bytes.Buffer, error) { + tempDir := os.TempDir() + screenshotPath := fmt.Sprintf("%s/screenshot_%d.png", tempDir, time.Now().Unix()) + err := hd.uiDriver.Screenshot(screenshotPath) + if err != nil { + log.Error().Err(err).Msg("failed to screenshot") + return nil, err + } + defer func() { + _ = os.Remove(screenshotPath) + }() + + raw, err := os.ReadFile(screenshotPath) + if err != nil { + log.Error().Err(err).Msg("failed to screenshot") + return nil, err + } + return bytes.NewBuffer(raw), nil +} + +func (hd *hdcDriver) Source(srcOpt ...SourceOption) (string, error) { + return "", nil +} + +func (hd *hdcDriver) LoginNoneUI(packageName, phoneNumber string, captcha string) error { + return errDriverNotImplemented +} + +func (hd *hdcDriver) LogoutNoneUI(packageName string) error { + return errDriverNotImplemented +} + +func (hd *hdcDriver) TapByText(text string, options ...ActionOption) error { + return errDriverNotImplemented +} + +func (hd *hdcDriver) TapByTexts(actions ...TapTextAction) error { + return errDriverNotImplemented +} + +func (hd *hdcDriver) AccessibleSource() (string, error) { + return "", errDriverNotImplemented +} + +func (hd *hdcDriver) HealthCheck() error { + return errDriverNotImplemented +} + +func (hd *hdcDriver) GetAppiumSettings() (map[string]interface{}, error) { + return nil, errDriverNotImplemented +} + +func (hd *hdcDriver) SetAppiumSettings(settings map[string]interface{}) (map[string]interface{}, error) { + return nil, errDriverNotImplemented +} + +func (hd *hdcDriver) IsHealthy() (bool, error) { + return false, errDriverNotImplemented +} + +func (hd *hdcDriver) StartCaptureLog(identifier ...string) (err error) { + return errDriverNotImplemented +} + +func (hd *hdcDriver) StopCaptureLog() (result interface{}, err error) { + return nil, errDriverNotImplemented +} diff --git a/hrp/pkg/uixt/harmony_test.go b/hrp/pkg/uixt/harmony_test.go new file mode 100644 index 00000000..dbb82134 --- /dev/null +++ b/hrp/pkg/uixt/harmony_test.go @@ -0,0 +1,109 @@ +package uixt + +import ( + "fmt" + "testing" +) + +var ( + driver IWebDriver + harmonyDriverExt *DriverExt +) + +func setup(t *testing.T) { + device, err := NewHarmonyDevice() + if err != nil { + t.Fatal(err) + } + driver, err = device.NewUSBDriver() + if err != nil { + t.Fatal(err) + } + harmonyDriverExt, err = newDriverExt(device, driver) + if err != nil { + t.Fatal(err) + } +} + +func TestWindowSize(t *testing.T) { + setup(t) + size, err := driver.WindowSize() + if err != nil { + t.Fatal(err) + } + t.Log(fmt.Sprintf("width: %d, height: %d", size.Width, size.Height)) +} + +func TestTap(t *testing.T) { + setup(t) + err := harmonyDriverExt.TapAbsXY(200, 2000) + if err != nil { + t.Fatal(err) + } +} + +func TestSwipe(t *testing.T) { + setup(t) + err := harmonyDriverExt.SwipeLeft() + if err != nil { + t.Fatal(err) + } +} + +func TestInput(t *testing.T) { + setup(t) + err := harmonyDriverExt.Input("test测试123!@#") + if err != nil { + t.Fatal(err) + } +} + +func TestHomeScreen(t *testing.T) { + setup(t) + err := driver.Homescreen() + if err != nil { + t.Fatal(err) + } +} + +func TestUnlock(t *testing.T) { + setup(t) + err := driver.Unlock() + if err != nil { + t.Fatal(err) + } +} + +func TestPressBack(t *testing.T) { + setup(t) + err := driver.PressBack() + if err != nil { + t.Fatal(err) + } +} + +func TestScreenshot(t *testing.T) { + setup(t) + screenshot, err := driver.Screenshot() + if err != nil { + t.Fatal(err) + } + t.Log(screenshot) +} + +func TestLaunch(t *testing.T) { + setup(t) + err := driver.AppLaunch("") + if err != nil { + t.Fatal(err) + } +} + +func TestForegroundApp(t *testing.T) { + setup(t) + appInfo, err := driver.GetForegroundApp() + if err != nil { + t.Fatal(err) + } + t.Log(appInfo) +} diff --git a/hrp/step_mobile_ui.go b/hrp/step_mobile_ui.go index 8c22570d..2b611c7b 100644 --- a/hrp/step_mobile_ui.go +++ b/hrp/step_mobile_ui.go @@ -35,6 +35,8 @@ func initUIClient(serial, osType string) (client *uixt.DriverExt, err error) { var device uixt.IDevice if osType == "ios" { device, err = uixt.NewIOSDevice(uixt.WithUDID(serial)) + } else if osType == "harmony" { + device, err = uixt.NewHarmonyDevice(uixt.WithConnectKey(serial)) } else { device, err = uixt.NewAndroidDevice(uixt.WithSerialNumber(serial)) } From ac6940b2832d5b3598ce3de8df5557be5b8786f5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E4=BD=99=E6=B3=93=E9=93=AE?= Date: Wed, 18 Sep 2024 21:50:05 +0800 Subject: [PATCH 2/5] =?UTF-8?q?feat:=20=E6=94=AF=E6=8C=81=E6=89=93?= =?UTF-8?q?=E5=BC=80=E9=94=81=E5=B1=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- go.mod | 2 +- go.sum | 6 ++++ hrp/pkg/uixt/harmony_hdc_driver.go | 52 ++++++++++++------------------ hrp/pkg/uixt/harmony_test.go | 4 +-- 4 files changed, 29 insertions(+), 35 deletions(-) diff --git a/go.mod b/go.mod index da91ad5c..60df183a 100644 --- a/go.mod +++ b/go.mod @@ -41,7 +41,7 @@ require ( require ( cloud.google.com/go/compute v1.23.0 // indirect cloud.google.com/go/compute/metadata v0.2.3 // indirect - code.byted.org/iesqa/ghdc v0.0.0-20240911080657-3fe04d3190a5 // indirect + code.byted.org/iesqa/ghdc v0.0.0-20240918093157-b4feef0e5af0 // indirect github.com/beorn7/perks v1.0.1 // indirect github.com/bytedance/sonic v1.11.6 // indirect github.com/bytedance/sonic/loader v0.1.1 // indirect diff --git a/go.sum b/go.sum index 5c675132..4a624d15 100644 --- a/go.sum +++ b/go.sum @@ -36,6 +36,12 @@ cloud.google.com/go/storage v1.8.0/go.mod h1:Wv1Oy7z6Yz3DshWRJFhqM/UCfaWIRTdp0RX cloud.google.com/go/storage v1.10.0/go.mod h1:FLPqc6j+Ki4BU591ie1oL6qBQGu2Bl/tZ9ullr3+Kg0= code.byted.org/iesqa/ghdc v0.0.0-20240911080657-3fe04d3190a5 h1:9H06vi9l4K8xjhQg5Lsu4lbtB2NBKUG/l4XyRGhLuAk= code.byted.org/iesqa/ghdc v0.0.0-20240911080657-3fe04d3190a5/go.mod h1:0IrKgKT75jmlpi9N0Mi5xWKctJuKHFM6f+ZMQe5vnNs= +code.byted.org/iesqa/ghdc v0.0.0-20240918062858-e57e2d72ed7b h1:pbIbB1S+vhIgEeaDoIqM5GtsCtlGXYaO7VZBYbVGYZU= +code.byted.org/iesqa/ghdc v0.0.0-20240918062858-e57e2d72ed7b/go.mod h1:0IrKgKT75jmlpi9N0Mi5xWKctJuKHFM6f+ZMQe5vnNs= +code.byted.org/iesqa/ghdc v0.0.0-20240918083005-02dc9c3eed10 h1:QwIVe4NaY3i3u0sN3JGczfrtAlI0FnPQSfOCfojudoc= +code.byted.org/iesqa/ghdc v0.0.0-20240918083005-02dc9c3eed10/go.mod h1:0IrKgKT75jmlpi9N0Mi5xWKctJuKHFM6f+ZMQe5vnNs= +code.byted.org/iesqa/ghdc v0.0.0-20240918093157-b4feef0e5af0 h1:qsKGQS3A530QpOXY80ogzzhVpf25Q4WfHusSlRyNvLU= +code.byted.org/iesqa/ghdc v0.0.0-20240918093157-b4feef0e5af0/go.mod h1:0IrKgKT75jmlpi9N0Mi5xWKctJuKHFM6f+ZMQe5vnNs= dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= diff --git a/hrp/pkg/uixt/harmony_hdc_driver.go b/hrp/pkg/uixt/harmony_hdc_driver.go index 0968d2c4..bffd400b 100644 --- a/hrp/pkg/uixt/harmony_hdc_driver.go +++ b/hrp/pkg/uixt/harmony_hdc_driver.go @@ -4,8 +4,6 @@ import ( "bytes" "fmt" "os" - "regexp" - "strconv" "time" "code.byted.org/iesqa/ghdc" @@ -59,32 +57,13 @@ func (hd *hdcDriver) BatteryInfo() (BatteryInfo, error) { } func (hd *hdcDriver) WindowSize() (size Size, err error) { - res, err := hd.device.RunShellCommand("hidumper", "-s", "RenderService", "-a", "screen") + display, err := hd.uiDriver.GetDisplaySize() if err != nil { log.Error().Err(err).Msg("failed to get window size") - return size, err + return Size{}, err } - re := regexp.MustCompile(`activeMode:\s*(\d+)x(\d+)`) - matches := re.FindStringSubmatch(res) - - if len(matches) > 2 { - fmt.Printf("Width: %s, Height: %s\n", matches[1], matches[2]) - width, err := strconv.Atoi(matches[1]) - if err != nil { - log.Error().Err(err).Str("width", matches[1]).Msg("failed to get window size") - return size, err - } - size.Width = width - height, err := strconv.Atoi(matches[2]) - if err != nil { - log.Error().Err(err).Str("height", matches[2]).Msg("failed to get window size") - return size, err - } - size.Height = height - return size, nil - } - err = fmt.Errorf("failed to find window size in dump result") - log.Error().Err(err).Str("result", res).Msg("failed to get window size") + size.Width = display.Width + size.Height = display.Height return size, err } @@ -105,7 +84,12 @@ func (hd *hdcDriver) Homescreen() error { } func (hd *hdcDriver) Unlock() (err error) { - return hd.uiDriver.PressKey(ghdc.KEYCODE_HOME) + // Todo 检查是否锁屏 hdc shell hidumper -s RenderService -a screen + err = hd.uiDriver.PressPowerKey() + if err != nil { + return err + } + return hd.Swipe(500, 2000, 500, 500) } func (hd *hdcDriver) AppLaunch(packageName string) error { @@ -114,8 +98,12 @@ func (hd *hdcDriver) AppLaunch(packageName string) error { } func (hd *hdcDriver) AppTerminate(packageName string) (bool, error) { - // Todo - return false, errDriverNotImplemented + _, err := hd.device.RunShellCommand("aa", "force-stop", packageName) + if err != nil { + log.Error().Err(err).Msg("failed to terminal app") + return false, err + } + return true, nil } func (hd *hdcDriver) GetForegroundApp() (app AppInfo, err error) { @@ -155,7 +143,7 @@ func (hd *hdcDriver) TapFloat(x, y float64, options ...ActionOption) error { x += actionOptions.getRandomOffset() y += actionOptions.getRandomOffset() - return hd.uiDriver.Touch(int(x), int(y)) + return hd.uiDriver.InjectGesture(ghdc.NewGesture().Start(ghdc.Point{X: int(x), Y: int(y)}).Pause(100)) } func (hd *hdcDriver) DoubleTap(x, y int, options ...ActionOption) error { @@ -200,12 +188,12 @@ func (hd *hdcDriver) SwipeFloat(fromX, fromY, toX, toY float64, options ...Actio toX += actionOptions.getRandomOffset() toY += actionOptions.getRandomOffset() - duration := 0.2 + duration := 200 if actionOptions.PressDuration > 0 { - duration = actionOptions.PressDuration + duration = int(actionOptions.PressDuration * 1000) } - return hd.uiDriver.Drag(int(fromX), int(fromY), int(toX), int(toY), duration) + return hd.uiDriver.InjectGesture(ghdc.NewGesture().Start(ghdc.Point{X: int(fromX), Y: int(fromY)}).MoveTo(ghdc.Point{X: int(toX), Y: int(toY)}, duration)) } func (hd *hdcDriver) SetPasteboard(contentType PasteboardType, content string) error { diff --git a/hrp/pkg/uixt/harmony_test.go b/hrp/pkg/uixt/harmony_test.go index dbb82134..c277d7df 100644 --- a/hrp/pkg/uixt/harmony_test.go +++ b/hrp/pkg/uixt/harmony_test.go @@ -34,7 +34,7 @@ func TestWindowSize(t *testing.T) { t.Log(fmt.Sprintf("width: %d, height: %d", size.Width, size.Height)) } -func TestTap(t *testing.T) { +func TestHarmonyTap(t *testing.T) { setup(t) err := harmonyDriverExt.TapAbsXY(200, 2000) if err != nil { @@ -52,7 +52,7 @@ func TestSwipe(t *testing.T) { func TestInput(t *testing.T) { setup(t) - err := harmonyDriverExt.Input("test测试123!@#") + err := harmonyDriverExt.Input("test") if err != nil { t.Fatal(err) } From 4fb9baf5a84e50ba7213904baaa035333dc0bbee Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E4=BD=99=E6=B3=93=E9=93=AE?= Date: Thu, 19 Sep 2024 22:51:10 +0800 Subject: [PATCH 3/5] =?UTF-8?q?fix:=20=E6=94=AF=E6=8C=81=E9=B8=BF=E8=92=99?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- hrp/pkg/uixt/harmony_hdc_driver.go | 5 ++++- hrp/step.go | 2 ++ hrp/step_mobile_ui.go | 7 ++++++- hrp/testcase.go | 4 ++++ 4 files changed, 16 insertions(+), 2 deletions(-) diff --git a/hrp/pkg/uixt/harmony_hdc_driver.go b/hrp/pkg/uixt/harmony_hdc_driver.go index bffd400b..456f7173 100644 --- a/hrp/pkg/uixt/harmony_hdc_driver.go +++ b/hrp/pkg/uixt/harmony_hdc_driver.go @@ -11,6 +11,7 @@ import ( ) type hdcDriver struct { + points []ExportPoint Driver device *ghdc.Device uiDriver *ghdc.UIDriver @@ -25,10 +26,12 @@ func newHarmonyDriver(device *ghdc.Device) (driver *hdcDriver, err error) { return nil, err } driver.uiDriver = uiDriver + driver.NewSession(nil) return } func (hd *hdcDriver) NewSession(capabilities Capabilities) (SessionInfo, error) { + hd.Driver.session.Init() return SessionInfo{}, errDriverNotImplemented } @@ -37,7 +40,7 @@ func (hd *hdcDriver) DeleteSession() error { } func (hd *hdcDriver) GetSession() *DriverSession { - return nil + return &hd.Driver.session } func (hd *hdcDriver) Status() (DeviceStatus, error) { diff --git a/hrp/step.go b/hrp/step.go index 328f8343..f0c69f35 100644 --- a/hrp/step.go +++ b/hrp/step.go @@ -11,6 +11,7 @@ const ( stepTypeThinkTime StepType = "thinktime" stepTypeWebSocket StepType = "websocket" stepTypeAndroid StepType = "android" + stepTypeHarmony StepType = "harmony" stepTypeIOS StepType = "ios" stepTypeShell StepType = "shell" @@ -54,6 +55,7 @@ type TStep struct { ThinkTime *ThinkTime `json:"think_time,omitempty" yaml:"think_time,omitempty"` WebSocket *WebSocketAction `json:"websocket,omitempty" yaml:"websocket,omitempty"` Android *MobileUI `json:"android,omitempty" yaml:"android,omitempty"` + Harmony *MobileUI `json:"harmony,omitempty" yaml:"harmony,omitempty"` IOS *MobileUI `json:"ios,omitempty" yaml:"ios,omitempty"` Shell *Shell `json:"shell,omitempty" yaml:"shell,omitempty"` Variables map[string]interface{} `json:"variables,omitempty" yaml:"variables,omitempty"` diff --git a/hrp/step_mobile_ui.go b/hrp/step_mobile_ui.go index 2b611c7b..1930b71c 100644 --- a/hrp/step_mobile_ui.go +++ b/hrp/step_mobile_ui.go @@ -398,6 +398,8 @@ func (s *StepMobile) Name() string { func (s *StepMobile) Type() StepType { if s.step.Android != nil { return stepTypeAndroid + } else if s.step.Harmony != nil { + return stepTypeHarmony } return stepTypeIOS } @@ -591,10 +593,13 @@ func runStepMobileUI(s *SessionRunner, step *TStep) (stepResult *StepResult, err // ios step osType = "ios" mobileStep = step.IOS - } else { + } else if step.Android != nil { // android step osType = "android" mobileStep = step.Android + } else { + osType = "harmony" + mobileStep = step.Harmony } // report GA event diff --git a/hrp/testcase.go b/hrp/testcase.go index 42dae8fc..03a16fc0 100644 --- a/hrp/testcase.go +++ b/hrp/testcase.go @@ -257,6 +257,10 @@ func (tc *TestCase) loadISteps() (*TestCase, error) { testCase.TestSteps = append(testCase.TestSteps, &StepMobile{ step: step, }) + } else if step.Harmony != nil { + testCase.TestSteps = append(testCase.TestSteps, &StepMobile{ + step: step, + }) } else if step.Android != nil { testCase.TestSteps = append(testCase.TestSteps, &StepMobile{ step: step, From 029bfa05b4033fbb350aa283069eca7ea8737ed9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E4=BD=99=E6=B3=93=E9=93=AE?= Date: Fri, 20 Sep 2024 10:49:38 +0800 Subject: [PATCH 4/5] =?UTF-8?q?feat:=20=E5=8A=A0=E5=85=A5=E6=89=93?= =?UTF-8?q?=E7=82=B9=E6=94=AF=E6=8C=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- hrp/internal/version/VERSION | 2 +- hrp/pkg/uixt/harmony_device.go | 15 ++++++++++++++- hrp/pkg/uixt/harmony_hdc_driver.go | 13 ++++++++++--- 3 files changed, 25 insertions(+), 5 deletions(-) diff --git a/hrp/internal/version/VERSION b/hrp/internal/version/VERSION index 7378a3bb..899d8138 100644 --- a/hrp/internal/version/VERSION +++ b/hrp/internal/version/VERSION @@ -1 +1 @@ -v4.6.5 +v4.6.6 \ No newline at end of file diff --git a/hrp/pkg/uixt/harmony_device.go b/hrp/pkg/uixt/harmony_device.go index fc333c77..8820c962 100644 --- a/hrp/pkg/uixt/harmony_device.go +++ b/hrp/pkg/uixt/harmony_device.go @@ -19,6 +19,7 @@ type HarmonyDevice struct { d *ghdc.Device ConnectKey string `json:"connect_key,omitempty" yaml:"connect_key,omitempty"` IgnorePopup bool `json:"ignore_popup,omitempty" yaml:"ignore_popup,omitempty"` + LogOn bool `json:"log_on,omitempty" yaml:"log_on,omitempty"` } type HarmonyDeviceOption func(*HarmonyDevice) @@ -29,6 +30,18 @@ func WithConnectKey(connectKey string) HarmonyDeviceOption { } } +func WithIgnorePopup(ignorePopup bool) HarmonyDeviceOption { + return func(device *HarmonyDevice) { + device.IgnorePopup = ignorePopup + } +} + +func WithLogOn(logOn bool) HarmonyDeviceOption { + return func(device *HarmonyDevice) { + device.LogOn = logOn + } +} + func NewHarmonyDevice(options ...HarmonyDeviceOption) (device *HarmonyDevice, err error) { device = &HarmonyDevice{} for _, option := range options { @@ -101,7 +114,7 @@ func (dev *HarmonyDevice) UUID() string { } func (dev *HarmonyDevice) LogEnabled() bool { - return false + return dev.LogOn } func (dev *HarmonyDevice) NewDriver(options ...DriverOption) (driverExt *DriverExt, err error) { diff --git a/hrp/pkg/uixt/harmony_hdc_driver.go b/hrp/pkg/uixt/harmony_hdc_driver.go index 456f7173..7aa89d8f 100644 --- a/hrp/pkg/uixt/harmony_hdc_driver.go +++ b/hrp/pkg/uixt/harmony_hdc_driver.go @@ -145,7 +145,10 @@ func (hd *hdcDriver) TapFloat(x, y float64, options ...ActionOption) error { x += actionOptions.getRandomOffset() y += actionOptions.getRandomOffset() - + if actionOptions.Identifier != "" { + startTime := int(time.Now().UnixMilli()) + hd.points = append(hd.points, ExportPoint{Start: startTime, End: startTime + 100, Ext: actionOptions.Identifier, RunTime: 100}) + } return hd.uiDriver.InjectGesture(ghdc.NewGesture().Start(ghdc.Point{X: int(x), Y: int(y)}).Pause(100)) } @@ -195,7 +198,10 @@ func (hd *hdcDriver) SwipeFloat(fromX, fromY, toX, toY float64, options ...Actio if actionOptions.PressDuration > 0 { duration = int(actionOptions.PressDuration * 1000) } - + if actionOptions.Identifier != "" { + startTime := int(time.Now().UnixMilli()) + hd.points = append(hd.points, ExportPoint{Start: startTime, End: startTime + 100, Ext: actionOptions.Identifier, RunTime: 100}) + } return hd.uiDriver.InjectGesture(ghdc.NewGesture().Start(ghdc.Point{X: int(fromX), Y: int(fromY)}).MoveTo(ghdc.Point{X: int(toX), Y: int(toY)}, duration)) } @@ -304,5 +310,6 @@ func (hd *hdcDriver) StartCaptureLog(identifier ...string) (err error) { } func (hd *hdcDriver) StopCaptureLog() (result interface{}, err error) { - return nil, errDriverNotImplemented + // defer clear(hd.points) + return hd.points, nil } From a63a575c37d5ca7003eb2503a8e3d3e2889b7a7d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E4=BD=99=E6=B3=93=E9=93=AE?= Date: Fri, 20 Sep 2024 15:05:06 +0800 Subject: [PATCH 5/5] =?UTF-8?q?fix:=20=E5=9B=9E=E6=BB=9Ago=E7=89=88?= =?UTF-8?q?=E6=9C=AC=EF=BC=8C=E6=B5=8B=E8=AF=95=E5=8A=A0=E5=85=A5localhost?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- go.mod | 4 +--- hrp/pkg/uixt/harmony_test.go | 2 ++ 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/go.mod b/go.mod index 60df183a..f3b87bfb 100644 --- a/go.mod +++ b/go.mod @@ -1,8 +1,6 @@ module github.com/httprunner/httprunner/v4 -go 1.22 - -toolchain go1.22.0 +go 1.18 require ( github.com/andybalholm/brotli v1.0.4 diff --git a/hrp/pkg/uixt/harmony_test.go b/hrp/pkg/uixt/harmony_test.go index c277d7df..b47eb9c4 100644 --- a/hrp/pkg/uixt/harmony_test.go +++ b/hrp/pkg/uixt/harmony_test.go @@ -1,3 +1,5 @@ +//go:build localtest + package uixt import (