Skip to content

Commit

Permalink
Adding an endpoint to run WDA (#491)
Browse files Browse the repository at this point in the history
* basic wda endpoint working

* simplify api using post and delete

* add docs and change path to /wda/session/
  • Loading branch information
aluedeke authored Oct 16, 2024
1 parent 983f0eb commit 33c4935
Show file tree
Hide file tree
Showing 8 changed files with 272 additions and 32 deletions.
21 changes: 11 additions & 10 deletions ios/testmanagerd/xcuitestrunner.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import (
"errors"
"fmt"
"io"
"maps"
"path"
"strings"

Expand Down Expand Up @@ -219,7 +220,7 @@ const (

const testBundleSuffix = "UITests.xctrunner"

func RunXCUITest(bundleID string, testRunnerBundleID string, xctestConfigName string, device ios.DeviceEntry, env []string, testsToRun []string, testsToSkip []string, testListener *TestListener, isXCTest bool) ([]TestSuite, error) {
func RunXCUITest(bundleID string, testRunnerBundleID string, xctestConfigName string, device ios.DeviceEntry, env map[string]interface{}, testsToRun []string, testsToSkip []string, testListener *TestListener, isXCTest bool) ([]TestSuite, error) {
// FIXME: this is redundant code, getting the app list twice and creating the appinfos twice
// just to generate the xctestConfigFileName. Should be cleaned up at some point.
installationProxy, err := installationproxy.New(device)
Expand Down Expand Up @@ -256,7 +257,7 @@ func RunXCUIWithBundleIdsCtx(
xctestConfigFileName string,
device ios.DeviceEntry,
args []string,
env []string,
env map[string]interface{},
testsToRun []string,
testsToSkip []string,
testListener *TestListener,
Expand Down Expand Up @@ -288,7 +289,7 @@ func runXUITestWithBundleIdsXcode15Ctx(
xctestConfigFileName string,
device ios.DeviceEntry,
args []string,
env []string,
env map[string]interface{},
testsToRun []string,
testsToSkip []string,
testListener *TestListener,
Expand Down Expand Up @@ -443,7 +444,7 @@ func killTestRunner(killer processKiller, pid int) error {
return nil
}

func startTestRunner17(device ios.DeviceEntry, appserviceConn *appservice.Connection, xctestConfigPath string, bundleID string, sessionIdentifier string, testBundlePath string, testArgs []string, testEnv []string, isXCTest bool) (appservice.LaunchedAppWithStdIo, error) {
func startTestRunner17(device ios.DeviceEntry, appserviceConn *appservice.Connection, xctestConfigPath string, bundleID string, sessionIdentifier string, testBundlePath string, testArgs []string, testEnv map[string]interface{}, isXCTest bool) (appservice.LaunchedAppWithStdIo, error) {
args := []interface{}{}
for _, arg := range testArgs {
args = append(args, arg)
Expand Down Expand Up @@ -471,12 +472,12 @@ func startTestRunner17(device ios.DeviceEntry, appserviceConn *appservice.Connec
"XCTestSessionIdentifier": strings.ToUpper(sessionIdentifier),
}

for _, entrystring := range testEnv {
entry := strings.Split(entrystring, "=")
key := entry[0]
value := entry[1]
env[key] = value
log.Debugf("adding extra env %s=%s", key, value)
if len(testEnv) > 0 {
maps.Copy(env, testEnv)

for key, value := range testEnv {
log.Debugf("adding extra env %s=%s", key, value)
}
}

opts := map[string]interface{}{
Expand Down
18 changes: 9 additions & 9 deletions ios/testmanagerd/xcuitestrunner_11.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ package testmanagerd
import (
"context"
"fmt"
"strings"
"maps"

"github.com/danielpaulus/go-ios/ios"
dtx "github.com/danielpaulus/go-ios/ios/dtx_codec"
Expand All @@ -18,7 +18,7 @@ func runXCUIWithBundleIdsXcode11Ctx(
xctestConfigFileName string,
device ios.DeviceEntry,
args []string,
env []string,
env map[string]interface{},
testsToRun []string,
testsToSkip []string,
testListener *TestListener,
Expand Down Expand Up @@ -110,7 +110,7 @@ func runXCUIWithBundleIdsXcode11Ctx(
}

func startTestRunner11(pControl *instruments.ProcessControl, xctestConfigPath string, bundleID string,
sessionIdentifier string, testBundlePath string, wdaargs []string, wdaenv []string,
sessionIdentifier string, testBundlePath string, wdaargs []string, wdaenv map[string]interface{},
) (uint64, error) {
args := []interface{}{}
for _, arg := range wdaargs {
Expand All @@ -122,12 +122,12 @@ func startTestRunner11(pControl *instruments.ProcessControl, xctestConfigPath st
"XCTestSessionIdentifier": sessionIdentifier,
}

for _, entrystring := range wdaenv {
entry := strings.Split(entrystring, "=")
key := entry[0]
value := entry[1]
env[key] = value
log.Debugf("adding extra env %s=%s", key, value)
if len(wdaenv) > 0 {
maps.Copy(env, wdaenv)

for key, value := range wdaenv {
log.Debugf("adding extra env %s=%s", key, value)
}
}

opts := map[string]interface{}{
Expand Down
18 changes: 9 additions & 9 deletions ios/testmanagerd/xcuitestrunner_12.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ package testmanagerd
import (
"context"
"fmt"
"strings"
"maps"
"time"

"github.com/danielpaulus/go-ios/ios"
Expand All @@ -14,7 +14,7 @@ import (
)

func runXUITestWithBundleIdsXcode12Ctx(ctx context.Context, bundleID string, testRunnerBundleID string, xctestConfigFileName string,
device ios.DeviceEntry, args []string, env []string, testsToRun []string, testsToSkip []string, testListener *TestListener, isXCTest bool,
device ios.DeviceEntry, args []string, env map[string]interface{}, testsToRun []string, testsToSkip []string, testListener *TestListener, isXCTest bool,
) ([]TestSuite, error) {
conn, err := dtx.NewUsbmuxdConnection(device, testmanagerdiOS14)
if err != nil {
Expand Down Expand Up @@ -108,7 +108,7 @@ func runXUITestWithBundleIdsXcode12Ctx(ctx context.Context, bundleID string, tes
}

func startTestRunner12(pControl *instruments.ProcessControl, xctestConfigPath string, bundleID string,
sessionIdentifier string, testBundlePath string, wdaargs []string, wdaenv []string,
sessionIdentifier string, testBundlePath string, wdaargs []string, wdaenv map[string]interface{},
) (uint64, error) {
args := []interface{}{
"-NSTreatUnknownArgumentsAsOpen", "NO", "-ApplePersistenceIgnoreState", "YES",
Expand All @@ -130,12 +130,12 @@ func startTestRunner12(pControl *instruments.ProcessControl, xctestConfigPath st
"XCTestSessionIdentifier": sessionIdentifier,
}

for _, entrystring := range wdaenv {
entry := strings.Split(entrystring, "=")
key := entry[0]
value := entry[1]
env[key] = value
log.Debugf("adding extra env %s=%s", key, value)
if len(wdaenv) > 0 {
maps.Copy(env, wdaenv)

for key, value := range wdaenv {
log.Debugf("adding extra env %s=%s", key, value)
}
}

opts := map[string]interface{}{
Expand Down
2 changes: 1 addition & 1 deletion ios/testmanagerd/xcuitestrunner_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@ func TestXcuiTest(t *testing.T) {
ctx, stopWda := context.WithCancel(context.Background())
bundleID, testbundleID, xctestconfig := "com.facebook.WebDriverAgentRunner.xctrunner", "com.facebook.WebDriverAgentRunner.xctrunner", "WebDriverAgentRunner.xctest"
var wdaargs []string
var wdaenv []string
var wdaenv map[string]interface{}
go func() {
_, err := testmanagerd.RunXCUIWithBundleIdsCtx(ctx, bundleID, testbundleID, xctestconfig, device, wdaargs, wdaenv, nil, nil, testmanagerd.NewTestListener(os.Stdout, os.Stdout, os.TempDir()), false)
if err != nil {
Expand Down
16 changes: 13 additions & 3 deletions main.go
Original file line number Diff line number Diff line change
Expand Up @@ -913,8 +913,7 @@ The commands work as following:
}

rawTestlog, rawTestlogErr := arguments.String("--log-output")
env := arguments["--env"].([]string)

env := splitKeyValuePairs(arguments["--env"].([]string), "=")
isXCTest, _ := arguments.Bool("--xctest")

if rawTestlogErr == nil {
Expand Down Expand Up @@ -1191,7 +1190,7 @@ func runWdaCommand(device ios.DeviceEntry, arguments docopt.Opts) bool {
testbundleID, _ := arguments.String("--testrunnerbundleid")
xctestconfig, _ := arguments.String("--xctestconfig")
wdaargs := arguments["--arg"].([]string)
wdaenv := arguments["--env"].([]string)
wdaenv := splitKeyValuePairs(arguments["--env"].([]string), "=")

if bundleID == "" && testbundleID == "" && xctestconfig == "" {
log.Info("no bundle ids specified, falling back to defaults")
Expand Down Expand Up @@ -2186,3 +2185,14 @@ func exitIfError(msg string, err error) {
log.WithFields(log.Fields{"err": err}).Fatalf(msg)
}
}

func splitKeyValuePairs(envArgs []string, sep string) map[string]interface{} {
env := make(map[string]interface{})
for _, entrystring := range envArgs {
entry := strings.Split(entrystring, sep)
key := entry[0]
value := entry[1]
env[key] = value
}
return env
}
43 changes: 43 additions & 0 deletions restapi/api/middleware.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,9 @@ import (
"sync"

"github.com/danielpaulus/go-ios/ios"
"github.com/danielpaulus/go-ios/ios/tunnel"
"github.com/gin-gonic/gin"
log "github.com/sirupsen/logrus"
)

// DeviceMiddleware makes sure a udid was specified and that a device with that UDID
Expand All @@ -30,11 +32,52 @@ func DeviceMiddleware() gin.HandlerFunc {
c.AbortWithStatusJSON(http.StatusInternalServerError, gin.H{"error": err})
return
}

info, err := tunnel.TunnelInfoForDevice(device.Properties.SerialNumber, ios.HttpApiPort())
if err == nil {
log.WithField("udid", device.Properties.SerialNumber).Printf("Received tunnel info %v", info)

device.UserspaceTUNPort = info.UserspaceTUNPort
device.UserspaceTUN = info.UserspaceTUN

device, err = deviceWithRsdProvider(device, udid, info.Address, info.RsdPort)
if err != nil {
c.Error(err)
c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()}) // Return an error response
c.Next()
}
} else {
log.WithField("udid", device.Properties.SerialNumber).Warn("failed to get tunnel info")
}

c.Set(IOS_KEY, device)
c.Next()
}
}

func deviceWithRsdProvider(device ios.DeviceEntry, udid string, address string, rsdPort int) (ios.DeviceEntry, error) {
rsdService, err := ios.NewWithAddrPortDevice(address, rsdPort, device)
if err != nil {
return device, err
}

defer rsdService.Close()
rsdProvider, err := rsdService.Handshake()
if err != nil {
return device, err
}

device1, err := ios.GetDeviceWithAddress(udid, address, rsdProvider)
if err != nil {
return device, err
}

device1.UserspaceTUN = device.UserspaceTUN
device1.UserspaceTUNPort = device.UserspaceTUNPort

return device1, nil
}

const IOS_KEY = "go_ios_device"

// LimitNumClientsUDID limits clients to one concurrent connection per device UDID at a time
Expand Down
3 changes: 3 additions & 0 deletions restapi/api/routes.go
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,9 @@ func simpleDeviceRoutes(device *gin.RouterGroup) {
device.PUT("/setlocation", SetLocation)
device.GET("/syslog", streamingMiddleWare, Syslog)

device.POST("/wda/session", CreateWdaSession)
device.GET("/wda/session/:sessionId", ReadWdaSession)
device.DELETE("/wda/session/:sessionId", DeleteWdaSession)
}

func appRoutes(group *gin.RouterGroup) {
Expand Down
Loading

0 comments on commit 33c4935

Please sign in to comment.