refactor ios: replace gidevice with go-ios

This commit is contained in:
lilong.129
2024-11-23 14:12:07 +08:00
parent 8aac2181be
commit ef37d88e0b
118 changed files with 2202 additions and 11764 deletions

View File

@@ -9,7 +9,7 @@ import (
"github.com/spf13/cobra"
"github.com/httprunner/httprunner/v4/hrp/internal/sdk"
"github.com/httprunner/httprunner/v4/hrp/pkg/gidevice"
"github.com/httprunner/httprunner/v4/hrp/pkg/uixt"
)
type Application struct {
@@ -37,21 +37,20 @@ var listAppsCmd = &cobra.Command{
return err
}
var applicationType gidevice.ApplicationType
device.GetDeviceInfo()
var applicationType uixt.ApplicationType
switch appType {
case "user":
applicationType = gidevice.ApplicationTypeUser
applicationType = uixt.ApplicationTypeUser
case "system":
applicationType = gidevice.ApplicationTypeSystem
applicationType = uixt.ApplicationTypeSystem
case "internal":
applicationType = gidevice.ApplicationTypeInternal
applicationType = uixt.ApplicationTypeInternal
case "all":
applicationType = gidevice.ApplicationTypeAny
applicationType = uixt.ApplicationTypeAny
}
result, err := device.InstallationProxyBrowse(
gidevice.WithApplicationType(applicationType),
gidevice.WithReturnAttributes("CFBundleVersion", "CFBundleDisplayName", "CFBundleIdentifier"))
result, err := device.ListApps(applicationType)
if err != nil {
return fmt.Errorf("get app list failed %v", err)
}

View File

@@ -7,52 +7,20 @@ import (
"strings"
"time"
"github.com/pkg/errors"
"github.com/danielpaulus/go-ios/ios"
"github.com/spf13/cobra"
"github.com/httprunner/httprunner/v4/hrp/internal/sdk"
"github.com/httprunner/httprunner/v4/hrp/pkg/gidevice"
"github.com/httprunner/httprunner/v4/hrp/pkg/uixt"
)
type Device struct {
d gidevice.Device
UDID string `json:"UDID"`
Status string `json:"status"`
ConnectionType string `json:"connectionType"`
ConnectionSpeed int `json:"connectionSpeed"`
DeviceDetail *DeviceDetail `json:"deviceDetail,omitempty"`
}
type DeviceDetail struct {
DeviceName string `json:"deviceName,omitempty"`
DeviceClass string `json:"deviceClass,omitempty"`
ProductVersion string `json:"productVersion,omitempty"`
ProductType string `json:"productType,omitempty"`
ProductName string `json:"productName,omitempty"`
PasswordProtected bool `json:"passwordProtected,omitempty"`
ModelNumber string `json:"modelNumber,omitempty"`
SerialNumber string `json:"serialNumber,omitempty"`
SIMStatus string `json:"simStatus,omitempty"`
PhoneNumber string `json:"phoneNumber,omitempty"`
CPUArchitecture string `json:"cpuArchitecture,omitempty"`
ProtocolVersion string `json:"protocolVersion,omitempty"`
RegionInfo string `json:"regionInfo,omitempty"`
TimeZone string `json:"timeZone,omitempty"`
UniqueDeviceID string `json:"uniqueDeviceID,omitempty"`
WiFiAddress string `json:"wifiAddress,omitempty"`
BuildVersion string `json:"buildVersion,omitempty"`
}
func (device *Device) GetDetail() (*DeviceDetail, error) {
value, err := device.d.GetValue("", "")
if err != nil {
return nil, errors.Wrap(err, "get device detail failed")
}
detailByte, _ := json.Marshal(value)
detail := &DeviceDetail{}
json.Unmarshal(detailByte, detail)
return detail, nil
d ios.DeviceEntry
UDID string `json:"UDID"`
Status string `json:"status"`
ConnectionType string `json:"connectionType"`
ConnectionSpeed int `json:"connectionSpeed"`
DeviceDetail *uixt.DeviceDetail `json:"deviceDetail,omitempty"`
}
func (device *Device) GetStatus() string {
@@ -89,7 +57,7 @@ var listDevicesCmd = &cobra.Command{
}
for _, d := range devices {
deviceProperties := d.Properties()
deviceProperties := d.Properties
device := &Device{
d: d,
UDID: deviceProperties.SerialNumber,
@@ -98,27 +66,16 @@ var listDevicesCmd = &cobra.Command{
}
device.Status = device.GetStatus()
if isDetail {
device.DeviceDetail, err = device.GetDetail()
if err != nil {
return err
}
fmt.Println(device.ToFormat())
} else {
fmt.Println(device.UDID, device.ConnectionType, device.Status)
}
fmt.Println(device.UDID, device.ConnectionType, device.Status)
}
return nil
},
}
var (
udid string
isDetail bool
)
var udid string
func init() {
listDevicesCmd.Flags().StringVarP(&udid, "udid", "u", "", "filter by device's udid")
listDevicesCmd.Flags().BoolVarP(&isDetail, "detail", "d", false, "print device's detail")
iosRootCmd.AddCommand(listDevicesCmd)
}

View File

@@ -1,11 +1,8 @@
package ios
import (
"fmt"
"github.com/spf13/cobra"
"github.com/httprunner/httprunner/v4/hrp/pkg/gidevice"
"github.com/httprunner/httprunner/v4/hrp/pkg/uixt"
)
@@ -14,15 +11,12 @@ var iosRootCmd = &cobra.Command{
Short: "simple utils for ios device management",
}
func getDevice(udid string) (gidevice.Device, error) {
devices, err := uixt.GetIOSDevices(udid)
func getDevice(udid string) (*uixt.IOSDevice, error) {
device, err := uixt.NewIOSDevice(uixt.WithUDID(udid))
if err != nil {
return nil, err
}
if len(devices) > 1 {
return nil, fmt.Errorf("found multiple attached devices, please specify ios udid")
}
return devices[0], nil
return device, nil
}
func Init(rootCmd *cobra.Command) {

View File

@@ -34,13 +34,8 @@ var installCmd = &cobra.Command{
fmt.Println(err)
return err
}
driverExt, err := device.NewDriver()
if err != nil {
fmt.Println(err)
return err
}
err = driverExt.Install(args[0])
err = device.Install(args[0])
if err != nil {
fmt.Println(err)
return err
@@ -51,7 +46,7 @@ var installCmd = &cobra.Command{
}
func init() {
installCmd.Flags().StringVarP(&udid, "serial", "s", "", "filter by device's serial")
installCmd.Flags().StringVarP(&udid, "udid", "u", "", "filter by device's serial")
iosRootCmd.AddCommand(installCmd)
}

View File

@@ -1,9 +1,7 @@
package ios
import (
"encoding/base64"
"fmt"
"path/filepath"
"strings"
"time"
@@ -33,22 +31,18 @@ var mountCmd = &cobra.Command{
return err
}
value, err := device.GetValue("", "ProductVersion")
images, errImage := device.ListImage()
if err != nil {
return fmt.Errorf("get device ProductVersion failed: %v", err)
return fmt.Errorf("list device images failed: %v", err)
}
log.Info().Str("version", value.(string)).Msg("get device version")
imageSignatures, errImage := device.Images()
if listDeveloperDiskImage {
for i, imgSign := range imageSignatures {
fmt.Printf("[%d] %s\n", i+1, base64.StdEncoding.EncodeToString(imgSign))
for i, imgSign := range images {
fmt.Printf("[%d] %s\n", i+1, imgSign)
}
return nil
}
if errImage == nil && len(imageSignatures) > 0 {
if errImage == nil && len(images) > 0 {
log.Info().Msg("ios developer image is already mounted")
return nil
}
@@ -59,27 +53,8 @@ var mountCmd = &cobra.Command{
return fmt.Errorf("developer disk image directory not exist: %s", developerDiskImageDir)
}
ver := strings.Split(value.(string), ".")
if len(ver) < 2 {
return fmt.Errorf("got invalid device ProductVersion: %v", value)
}
version := ver[0] + "." + ver[1]
var dmgPath, signaturePath string
if builtin.IsFilePathExists(filepath.Join(developerDiskImageDir, "DeveloperDiskImage.dmg")) {
dmgPath = filepath.Join(developerDiskImageDir, "DeveloperDiskImage.dmg")
signaturePath = filepath.Join(developerDiskImageDir, "DeveloperDiskImage.dmg.signature")
} else if builtin.IsFilePathExists(filepath.Join(developerDiskImageDir, version, "DeveloperDiskImage.dmg")) {
dmgPath = filepath.Join(developerDiskImageDir, version, "DeveloperDiskImage.dmg")
signaturePath = filepath.Join(developerDiskImageDir, version, "DeveloperDiskImage.dmg.signature")
} else {
log.Error().Str("dir", developerDiskImageDir).Msgf(
"developer disk image %s not found in directory", version)
return fmt.Errorf("developer disk image %s not found", version)
}
if err = device.MountDeveloperDiskImage(dmgPath, signaturePath); err != nil {
return fmt.Errorf("mount developer disk image %s failed: %s", version, err)
if err = device.MountImage(developerDiskImageDir); err != nil {
return fmt.Errorf("mount developer disk image failed: %s", err)
}
log.Info().Msg("mount developer disk image successfully")

View File

@@ -1,92 +0,0 @@
package ios
import (
"os"
"os/signal"
"strings"
"syscall"
"time"
"github.com/rs/zerolog/log"
"github.com/spf13/cobra"
"github.com/httprunner/httprunner/v4/hrp/internal/builtin"
"github.com/httprunner/httprunner/v4/hrp/internal/config"
"github.com/httprunner/httprunner/v4/hrp/internal/sdk"
"github.com/httprunner/httprunner/v4/hrp/pkg/uixt"
)
var pcapCmd = &cobra.Command{
Use: "pcap",
Short: "capture ios network packets",
RunE: func(cmd *cobra.Command, args []string) (err error) {
startTime := time.Now()
defer func() {
sdk.SendGA4Event("hrp_ios_pcap", map[string]interface{}{
"args": strings.Join(args, "-"),
"success": err == nil,
"engagement_time_msec": time.Since(startTime).Milliseconds(),
})
}()
pcapOptions := []uixt.IOSPcapOption{}
if pid > 0 {
pcapOptions = append(pcapOptions, uixt.WithIOSPcapPID(pid))
}
if procName != "" {
pcapOptions = append(pcapOptions, uixt.WithIOSPcapProcName(procName))
}
if bundleID != "" {
pcapOptions = append(pcapOptions, uixt.WithIOSPcapBundleID(bundleID))
}
if len(pcapOptions) == 0 {
pcapOptions = append(pcapOptions, uixt.WithIOSPcapAll(true))
}
device, err := uixt.NewIOSDevice(
uixt.WithUDID(udid),
uixt.WithIOSPcapOptions(pcapOptions...),
)
if err != nil {
log.Fatal().Err(err).Msg("failed to init ios device")
}
err = builtin.EnsureFolderExists(config.ResultsPath)
if err != nil {
return err
}
if err = device.StartPcap(); err != nil {
return err
}
defer device.StopPcap()
c := make(chan os.Signal, 1)
signal.Notify(c, syscall.SIGTERM, syscall.SIGINT)
timer := time.NewTimer(time.Duration(timeDuration) * time.Second)
for {
select {
case <-timer.C:
return nil
case <-c:
log.Warn().Msg("received signal, stop pcap")
return nil
}
}
},
}
var (
timeDuration int
pid int
procName string
)
func init() {
pcapCmd.Flags().StringVarP(&udid, "udid", "u", "", "specify device by udid")
pcapCmd.Flags().IntVarP(&pid, "pid", "p", 0, "specify process ID")
pcapCmd.Flags().StringVarP(&procName, "procName", "n", "", "specify process name")
pcapCmd.Flags().StringVarP(&bundleID, "bundleID", "b", "", "specify bundle ID")
pcapCmd.Flags().IntVarP(&timeDuration, "duration", "t", 10, "specify time duraion in seconds")
iosRootCmd.AddCommand(pcapCmd)
}

View File

@@ -1,98 +0,0 @@
package ios
import (
"os"
"os/signal"
"strings"
"syscall"
"time"
"github.com/rs/zerolog/log"
"github.com/spf13/cobra"
"github.com/httprunner/httprunner/v4/hrp/internal/builtin"
"github.com/httprunner/httprunner/v4/hrp/internal/config"
"github.com/httprunner/httprunner/v4/hrp/internal/sdk"
"github.com/httprunner/httprunner/v4/hrp/pkg/uixt"
)
var perfCmd = &cobra.Command{
Use: "perf",
Short: "capture ios performance data (cpu,mem,disk,net,fps,etc.)",
RunE: func(cmd *cobra.Command, args []string) (err error) {
startTime := time.Now()
defer func() {
sdk.SendGA4Event("hrp_ios_perf", map[string]interface{}{
"args": strings.Join(args, "-"),
"success": err == nil,
"engagement_time_msec": time.Since(startTime).Milliseconds(),
})
}()
perfOptions := []uixt.IOSPerfOption{}
for _, p := range indicators {
switch p {
case "sys_cpu":
perfOptions = append(perfOptions, uixt.WithIOSPerfSystemCPU(true))
case "sys_mem":
perfOptions = append(perfOptions, uixt.WithIOSPerfSystemMem(true))
case "sys_net":
perfOptions = append(perfOptions, uixt.WithIOSPerfSystemNetwork(true))
case "sys_disk":
perfOptions = append(perfOptions, uixt.WithIOSPerfSystemDisk(true))
case "network":
perfOptions = append(perfOptions, uixt.WithIOSPerfNetwork(true))
case "fps":
perfOptions = append(perfOptions, uixt.WithIOSPerfFPS(true))
case "gpu":
perfOptions = append(perfOptions, uixt.WithIOSPerfGPU(true))
}
}
perfOptions = append(perfOptions, uixt.WithIOSPerfOutputInterval(interval*1000))
device, err := uixt.NewIOSDevice(
uixt.WithUDID(udid),
uixt.WithIOSPerfOptions(perfOptions...),
)
if err != nil {
log.Fatal().Err(err).Msg("failed to init ios device")
}
err = builtin.EnsureFolderExists(config.ResultsPath)
if err != nil {
return err
}
if err = device.StartPerf(); err != nil {
return err
}
defer device.StopPerf()
c := make(chan os.Signal, 1)
signal.Notify(c, syscall.SIGTERM, syscall.SIGINT)
timer := time.NewTimer(time.Duration(timeDuration) * time.Second)
for {
select {
case <-timer.C:
return nil
case <-c:
log.Warn().Msg("received signal, stop perf")
return nil
}
}
},
}
var (
interval int
indicators []string
)
func init() {
perfCmd.Flags().StringVarP(&udid, "udid", "u", "", "specify device by udid")
perfCmd.Flags().StringSliceVarP(&indicators, "indicators", "p", []string{"sys_cpu", "sys_mem"},
"specify performance monitor, e.g. sys_cpu,sys_mem,sys_net,sys_disk,fps,network,gpu")
perfCmd.Flags().IntVarP(&timeDuration, "duration", "t", 10, "specify time duraion in seconds")
perfCmd.Flags().IntVarP(&interval, "interval", "i", 3, "set interval in seconds")
iosRootCmd.AddCommand(perfCmd)
}

View File

@@ -5,7 +5,6 @@ import (
"strings"
"time"
"github.com/pkg/errors"
"github.com/spf13/cobra"
"github.com/httprunner/httprunner/v4/hrp/internal/sdk"
@@ -30,34 +29,12 @@ var psCmd = &cobra.Command{
return err
}
apps, err := device.AppList()
runningProcesses, err := device.ListProcess(!isAll)
if err != nil {
return errors.Wrap(err, "get ios apps failed")
}
maxNameLen := 0
mapper := make(map[string]interface{})
for _, app := range apps {
mapper[app.ExecutableName] = app.CFBundleIdentifier
if len(app.ExecutableName) > maxNameLen {
maxNameLen = len(app.ExecutableName)
}
}
runningProcesses, err := device.AppRunningProcesses()
if err != nil {
return errors.Wrap(err, "get running processes failed")
return err
}
for _, p := range runningProcesses {
if !isAll && !p.IsApplication {
continue
}
bundleID, ok := mapper[p.Name]
if !ok {
bundleID = ""
}
fmt.Printf("%4d %-"+fmt.Sprintf("%d", maxNameLen)+"s %20s %s\n",
fmt.Printf("%4d %-"+fmt.Sprintf("%d", len(runningProcesses))+"s %20s %s\n",
p.Pid, p.Name, time.Since(p.StartDate).String(), bundleID)
}
return nil

View File

@@ -12,7 +12,7 @@ import (
var rebootCmd = &cobra.Command{
Use: "reboot",
Short: "reboot or shutdown ios device",
Short: "reboot ios device",
PersistentPreRun: func(cmd *cobra.Command, args []string) {},
RunE: func(cmd *cobra.Command, args []string) (err error) {
startTime := time.Now()
@@ -29,23 +29,16 @@ var rebootCmd = &cobra.Command{
return err
}
if isShutdown {
err = device.Shutdown()
} else {
err = device.Reboot()
}
err = device.Reboot()
if err != nil {
return err
}
fmt.Printf("reboot %s success\n", device.Properties().UDID)
fmt.Printf("reboot %s success\n", device.UDID)
return nil
},
}
var isShutdown bool
func init() {
rebootCmd.Flags().StringVarP(&udid, "udid", "u", "", "specify device by udid")
rebootCmd.Flags().BoolVarP(&isShutdown, "shutdown", "s", false, "shutdown ios device")
iosRootCmd.AddCommand(rebootCmd)
}

59
hrp/cmd/ios/uninstall.go Normal file
View File

@@ -0,0 +1,59 @@
package ios
import (
"fmt"
"strings"
"time"
"github.com/spf13/cobra"
"github.com/httprunner/httprunner/v4/hrp/internal/sdk"
"github.com/httprunner/httprunner/v4/hrp/pkg/uixt"
)
var uninstallCmd = &cobra.Command{
Use: "uninstall [flags] PACKAGE",
Short: "uninstall Package atomically",
Args: cobra.MinimumNArgs(0),
RunE: func(cmd *cobra.Command, args []string) (err error) {
startTime := time.Now()
defer func() {
sdk.SendGA4Event("hrp_adb_devices", map[string]interface{}{
"args": strings.Join(args, "-"),
"success": err == nil,
"engagement_time_msec": time.Since(startTime).Milliseconds(),
})
}()
if len(bundleId) == 0 {
return fmt.Errorf("bundleId is empty")
}
_, err = getDevice(udid)
if err != nil {
return err
}
device, err := uixt.NewIOSDevice(uixt.WithUDID(udid))
if err != nil {
fmt.Println(err)
return err
}
err = device.Uninstall(bundleId)
if err != nil {
fmt.Println(err)
return err
}
fmt.Println("success")
return nil
},
}
var bundleId string
func init() {
uninstallCmd.Flags().StringVarP(&udid, "udid", "u", "", "filter by device's serial")
uninstallCmd.Flags().StringVarP(&bundleId, "bundleId", "b", "", "bundleId to uninstall")
iosRootCmd.AddCommand(uninstallCmd)
}

View File

@@ -2,10 +2,7 @@ package ios
import (
"fmt"
"os"
"os/signal"
"strings"
"syscall"
"time"
"github.com/pkg/errors"
@@ -37,33 +34,24 @@ var xctestCmd = &cobra.Command{
}
log.Info().Str("bundleID", bundleID).Msg("run xctest")
out, cancel, err := device.XCTest(bundleID)
err = device.RunXCTest(bundleID, testRunnerBundleID, xctestConfig)
if err != nil {
return errors.Wrap(err, "run xctest failed")
}
done := make(chan os.Signal, 1)
signal.Notify(done, syscall.SIGTERM, syscall.SIGINT)
// print xctest running logs
go func() {
for s := range out {
fmt.Print(s)
}
done <- os.Interrupt
}()
<-done
cancel()
return nil
},
}
var bundleID string
var (
bundleID string
testRunnerBundleID string
xctestConfig string
)
func init() {
xctestCmd.Flags().StringVarP(&udid, "udid", "u", "", "filter by device's udid")
xctestCmd.Flags().StringVarP(&bundleID, "bundleID", "b", "", "specify ios bundleID")
xctestCmd.Flags().StringVarP(&testRunnerBundleID, "testRunnerBundleID", "t", "", "specify ios testRunnerBundleID")
xctestCmd.Flags().StringVarP(&xctestConfig, "xctestConfig", "x", "", "specify ios xctestConfig")
iosRootCmd.AddCommand(xctestCmd)
}