diff --git a/docs/CHANGELOG.md b/docs/CHANGELOG.md index ed37df31..c0ee2d8c 100644 --- a/docs/CHANGELOG.md +++ b/docs/CHANGELOG.md @@ -1,5 +1,9 @@ # Release History +## v4.3.8 (2024-01-18) + +- feat: add Shell step type + ## v4.3.7 (2023-09-19) **go version** diff --git a/examples/uitest/bili/bili_android.json b/examples/uitest/bili/bili_android.json new file mode 100644 index 00000000..51807a40 --- /dev/null +++ b/examples/uitest/bili/bili_android.json @@ -0,0 +1,18 @@ +{ + "config": { + "name": "run ui test on bili android", + "variables": { + "RunTimes": 3, + "SerialNumber": "${ENV(SerialNumber)}" + } + }, + "teststeps": [ + { + "name": "run bili android", + "shell": { + "string": "bili_android", + "expect_exit_code": 0 + } + } + ] +} diff --git a/examples/uitest/bili/cli.go b/examples/uitest/bili/cli.go new file mode 100644 index 00000000..9a000d8d --- /dev/null +++ b/examples/uitest/bili/cli.go @@ -0,0 +1,135 @@ +package main + +import ( + "fmt" + "os" + "strconv" + "time" + + "github.com/httprunner/httprunner/v4/hrp/pkg/uixt" +) + +var ( + serial string + runTimes int +) + +func init() { + serial = os.Getenv("SerialNumber") + numStr := os.Getenv("RunTimes") + defaultNum := 20 + + var err error + runTimes, err = strconv.Atoi(numStr) + if err != nil { + runTimes = defaultNum + } + fmt.Printf("=== start running cases, serial=%s, runTimes=%d ===\n", serial, runTimes) +} + +func launchAppDriver(pkgName string) (driver *uixt.DriverExt, err error) { + device, _ := uixt.NewAndroidDevice(uixt.WithSerialNumber(serial)) + driver, err = device.NewDriver() + if err != nil { + return nil, err + } + + _, err = driver.Driver.AppTerminate(pkgName) + if err != nil { + return nil, err + } + + err = driver.Driver.Homescreen() + if err != nil { + return nil, err + } + + err = driver.Driver.AppLaunch(pkgName) + if err != nil { + return nil, err + } + + time.Sleep(15 * time.Second) + + // 处理弹窗 + err = driver.ClosePopupsHandler() + if err != nil { + return nil, err + } + + // 进入推荐页 + err = driver.TapByOCR("推荐", uixt.WithScope(0, 0, 1, 0.3)) + if err != nil { + return nil, err + } + + return driver, nil +} + +func watchVideo(driver *uixt.DriverExt) (err error) { + err = driver.SwipeUp() + if err != nil { + return err + } + time.Sleep(1 * time.Second) + + // 点击进入某视频 + err = driver.TapXY(0.3, 0.5) + if err != nil { + return err + } + + time.Sleep(5 * time.Second) + + // 点击播放区域,展现横屏图标 + err = driver.TapXY(0.5, 0.1) + if err != nil { + return err + } + time.Sleep(500 * time.Millisecond) + + // 切换横屏 + err = driver.TapByUIDetection( + uixt.WithScreenShotUITypes("fullScreen")) + if err != nil { + // 未找到横屏图标,该页面可能不是横版视频(直播|广告|Feed) + // 退出回到推荐页 + driver.Driver.PressBack() + return nil + } + + // 观播 10s + time.Sleep(10 * time.Second) + + // 返回视频页面 + err = driver.Driver.PressBack() + if err != nil { + return err + } + + // 返回推荐页 + err = driver.Driver.PressBack() + if err != nil { + return err + } + time.Sleep(1 * time.Second) + + return nil +} + +// build shell command +// go build -o bili_android examples/uitest/bilibili/cli.go +func main() { + driver, err := launchAppDriver("tv.danmaku.bili") + if err != nil { + panic(err) + } + + // 重复采集 XX 次 + for i := 0; i < runTimes; i++ { + err = watchVideo(driver) + if err != nil { + panic(err) + } + } +} diff --git a/examples/uitest/bili/cli_test.go b/examples/uitest/bili/cli_test.go new file mode 100644 index 00000000..9bbd0e1e --- /dev/null +++ b/examples/uitest/bili/cli_test.go @@ -0,0 +1,35 @@ +//go:build localtest + +package main + +import ( + "testing" + + "github.com/httprunner/httprunner/v4/hrp" +) + +func TestMain(t *testing.T) { + main() +} + +func TestRunCaseWithShell(t *testing.T) { + testcase1 := &hrp.TestCase{ + Config: hrp.NewConfig("run ui test on bili android"). + WithVariables(map[string]interface{}{ + "SerialNumber": "${ENV(SerialNumber)}", + "RunTimes": 3, + }), + TestSteps: []hrp.IStep{ + hrp.NewStep("run bili android"). + Shell("bili_android"), + }, + } + + testcase1.Dump2JSON("bili_android.json") + + r := hrp.NewRunner(t) + err := r.Run(testcase1) + if err != nil { + t.Fatal() + } +} diff --git a/go.mod b/go.mod index 23cc3089..6cc068cb 100644 --- a/go.mod +++ b/go.mod @@ -5,12 +5,12 @@ go 1.18 require ( github.com/andybalholm/brotli v1.0.4 github.com/denisbrodbeck/machineid v1.0.1 - github.com/fatih/color v1.15.0 + github.com/fatih/color v1.16.0 github.com/getsentry/sentry-go v0.13.0 github.com/go-openapi/spec v0.20.7 github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 github.com/gorilla/websocket v1.5.0 - github.com/httprunner/funplugin v0.5.3 + github.com/httprunner/funplugin v0.5.4 github.com/jinzhu/copier v0.3.5 github.com/jmespath/go-jmespath v0.4.0 github.com/json-iterator/go v1.1.12 @@ -26,16 +26,16 @@ require ( github.com/spf13/cobra v1.5.0 github.com/stretchr/testify v1.8.4 gocv.io/x/gocv v0.32.1 - golang.org/x/net v0.14.0 + golang.org/x/net v0.17.0 golang.org/x/oauth2 v0.8.0 google.golang.org/grpc v1.57.0 - google.golang.org/protobuf v1.31.0 + google.golang.org/protobuf v1.32.0 gopkg.in/yaml.v3 v3.0.1 howett.net/plist v1.0.0 ) require ( - cloud.google.com/go/compute v1.20.1 // indirect + cloud.google.com/go/compute v1.23.0 // indirect cloud.google.com/go/compute/metadata v0.2.3 // indirect github.com/beorn7/perks v1.0.1 // indirect github.com/cespare/xxhash/v2 v2.2.0 // indirect @@ -47,15 +47,15 @@ require ( github.com/go-openapi/jsonreference v0.20.0 // indirect github.com/go-openapi/swag v0.22.3 // indirect github.com/golang/protobuf v1.5.3 // indirect - github.com/hashicorp/go-hclog v1.5.0 // indirect - github.com/hashicorp/go-plugin v1.4.10 // indirect + github.com/hashicorp/go-hclog v1.6.2 // indirect + github.com/hashicorp/go-plugin v1.6.0 // indirect github.com/hashicorp/yamux v0.1.1 // indirect github.com/inconshreveable/mousetrap v1.0.1 // indirect github.com/josharian/intern v1.0.0 // indirect github.com/kr/pretty v0.3.1 // indirect github.com/mailru/easyjson v0.7.7 // indirect github.com/mattn/go-colorable v0.1.13 // indirect - github.com/mattn/go-isatty v0.0.19 // indirect + github.com/mattn/go-isatty v0.0.20 // indirect github.com/mattn/go-runewidth v0.0.14 // indirect github.com/matttproud/golang_protobuf_extensions v1.0.1 // indirect github.com/mitchellh/go-testing-interface v1.14.1 // indirect @@ -73,10 +73,10 @@ require ( github.com/tklauser/go-sysconf v0.3.10 // indirect github.com/tklauser/numcpus v0.5.0 // indirect github.com/yusufpapurcu/wmi v1.2.2 // indirect - golang.org/x/sys v0.11.0 // indirect - golang.org/x/text v0.12.0 // indirect - google.golang.org/appengine v1.6.7 // indirect - google.golang.org/genproto/googleapis/rpc v0.0.0-20230815205213-6bfd019c3878 // indirect + golang.org/x/sys v0.16.0 // indirect + golang.org/x/text v0.14.0 // indirect + google.golang.org/appengine v1.6.8 // indirect + google.golang.org/genproto/googleapis/rpc v0.0.0-20240116215550-a9fa1716bcac // indirect gopkg.in/yaml.v2 v2.4.0 // indirect ) diff --git a/go.sum b/go.sum index 19e9da71..8d9bc726 100644 --- a/go.sum +++ b/go.sum @@ -19,8 +19,8 @@ cloud.google.com/go/bigquery v1.4.0/go.mod h1:S8dzgnTigyfTmLBfrtrhyYhwRxG72rYxvf cloud.google.com/go/bigquery v1.5.0/go.mod h1:snEHRnqQbz117VIFhE8bmtwIDY80NLUZUMb4Nv6dBIg= cloud.google.com/go/bigquery v1.7.0/go.mod h1://okPTzCYNXSlb24MZs83e2Do+h+VXtc4gLoIoXIAPc= cloud.google.com/go/bigquery v1.8.0/go.mod h1:J5hqkt3O0uAFnINi6JXValWIb1v0goeZM77hZzJN/fQ= -cloud.google.com/go/compute v1.20.1 h1:6aKEtlUiwEpJzM001l0yFkpXmUVXaN8W+fbkb2AZNbg= -cloud.google.com/go/compute v1.20.1/go.mod h1:4tCnrn48xsqlwSAiLf1HXMQk8CONslYbdiEZc9FEIbM= +cloud.google.com/go/compute v1.23.0 h1:tP41Zoavr8ptEqaW6j+LQOnyBBhO7OkOMAGrgLopTwY= +cloud.google.com/go/compute v1.23.0/go.mod h1:4tCnrn48xsqlwSAiLf1HXMQk8CONslYbdiEZc9FEIbM= cloud.google.com/go/compute/metadata v0.2.3 h1:mg4jlk7mCAj6xXp9UJ4fjI9VUI5rubuGBW5aJ7UnBMY= cloud.google.com/go/compute/metadata v0.2.3/go.mod h1:VAV5nSsACxMJvgaAuX6Pk2AawlZn8kiOGuCv6gTkwuA= cloud.google.com/go/datastore v1.0.0/go.mod h1:LXYbyblFSglQ5pkeyhO+Qmw7ukd3C+pD7TKLgZqpHYE= @@ -48,6 +48,7 @@ github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24 github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8= github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM= github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= +github.com/bufbuild/protocompile v0.4.0 h1:LbFKd2XowZvQ/kajzguUp2DC9UEIQhIq77fZZlaQsNA= github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= github.com/cespare/xxhash/v2 v2.1.2/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= @@ -72,8 +73,8 @@ github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.m github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98= github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= github.com/fatih/color v1.13.0/go.mod h1:kLAiJbzzSOZDVNGyDpeOxJ47H46qBXwg5ILebYFFOfk= -github.com/fatih/color v1.15.0 h1:kOqh6YHBtK8aywxGerMG2Eq3H6Qgoqeo13Bk2Mv/nBs= -github.com/fatih/color v1.15.0/go.mod h1:0h5ZqXfHYED7Bhv2ZJamyIOUej9KtShiJESRwBDUSsw= +github.com/fatih/color v1.16.0 h1:zmkK9Ngbjj+K0yRhTVONQh1p/HknKYSlNT+vZCzyokM= +github.com/fatih/color v1.16.0/go.mod h1:fL2Sau1YI5c0pdGEVCbKQbLXB6edEj1ZgiY4NijnWvE= github.com/getsentry/sentry-go v0.13.0 h1:20dgTiUSfxRB/EhMPtxcL9ZEbM1ZdR+W/7f7NWD+xWo= github.com/getsentry/sentry-go v0.13.0/go.mod h1:EOsfu5ZdvKPfeHYV6pTVQnsjfp30+XA7//UooKNumH0= github.com/go-errors/errors v1.4.2 h1:J6MZopCL4uSllY1OfXM374weqZFFItUbrImctkmUxIA= @@ -163,23 +164,23 @@ github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+ github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk= github.com/gorilla/websocket v1.5.0 h1:PPwGk2jz7EePpoHN/+ClbZu8SPxiqlu12wZP/3sWmnc= github.com/gorilla/websocket v1.5.0/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= -github.com/hashicorp/go-hclog v1.5.0 h1:bI2ocEMgcVlz55Oj1xZNBsVi900c7II+fWDyV9o+13c= -github.com/hashicorp/go-hclog v1.5.0/go.mod h1:W4Qnvbt70Wk/zYJryRzDRU/4r0kIg0PVHBcfoyhpF5M= -github.com/hashicorp/go-plugin v1.4.10 h1:xUbmA4jC6Dq163/fWcp8P3JuHilrHHMLNRxzGQJ9hNk= -github.com/hashicorp/go-plugin v1.4.10/go.mod h1:6/1TEzT0eQznvI/gV2CM29DLSkAK/e58mUWKVsPaph0= +github.com/hashicorp/go-hclog v1.6.2 h1:NOtoftovWkDheyUM/8JW3QMiXyxJK3uHRK7wV04nD2I= +github.com/hashicorp/go-hclog v1.6.2/go.mod h1:W4Qnvbt70Wk/zYJryRzDRU/4r0kIg0PVHBcfoyhpF5M= +github.com/hashicorp/go-plugin v1.6.0 h1:wgd4KxHJTVGGqWBq4QPB1i5BZNEx9BR8+OFmHDmTk8A= +github.com/hashicorp/go-plugin v1.6.0/go.mod h1:lBS5MtSSBZk0SHc66KACcjjlU6WzEVP/8pwz68aMkCI= github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= github.com/hashicorp/yamux v0.1.1 h1:yrQxtgseBDrq9Y652vSRDvsKCJKOUD+GzTS4Y0Y8pvE= github.com/hashicorp/yamux v0.1.1/go.mod h1:CtWFDAQgb7dxtzFs4tWbplKIe2jSi3+5vKbgIO0SLnQ= -github.com/httprunner/funplugin v0.5.3 h1:OHYXqq8fuO/qzT+TzXxhS3HVfKdb8kh+Q/0/S3n4afA= -github.com/httprunner/funplugin v0.5.3/go.mod h1:YZzBBSOSdLZEpHZz0P2E5SOQ+o1+Fbn30oWS4RGHBz0= +github.com/httprunner/funplugin v0.5.4 h1:hlfNGcYw2Rv2Mdp1l2S1R6ufwzKgpB9lheFvAxI0LfM= +github.com/httprunner/funplugin v0.5.4/go.mod h1:YZzBBSOSdLZEpHZz0P2E5SOQ+o1+Fbn30oWS4RGHBz0= github.com/hybridgroup/mjpeg v0.0.0-20140228234708-4680f319790e/go.mod h1:eagM805MRKrioHYuU7iKLUyFPVKqVV6um5DAvCkUtXs= github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8= github.com/inconshreveable/mousetrap v1.0.1 h1:U3uMjPSQEBMNp1lFxmllqCPM6P5u/Xq7Pgzkat/bFNc= github.com/inconshreveable/mousetrap v1.0.1/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw= github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI= -github.com/jhump/protoreflect v1.6.0 h1:h5jfMVslIg6l29nsMs0D8Wj17RDVdNYti0vDN/PZZoE= +github.com/jhump/protoreflect v1.15.1 h1:HUMERORf3I3ZdX05WaQ6MIpd/NJ434hTp5YiKgfCL6c= github.com/jinzhu/copier v0.3.5 h1:GlvfUwHk62RokgqVNvYsku0TATCF7bAHVwEXoBh3iJg= github.com/jinzhu/copier v0.3.5/go.mod h1:DfbEm0FYsaqBcKcFuvmOZb218JkPGtvSHsKg8S8hyyg= github.com/jmespath/go-jmespath v0.4.0 h1:BEgLn5cpjn8UN1mAw4NjwDrS35OdebyEtFe+9YPoQUg= @@ -225,8 +226,8 @@ github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovk github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94= github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= -github.com/mattn/go-isatty v0.0.19 h1:JITubQf0MOLdlGRuRq+jtsDlekdYPia9ZFsB8h/APPA= -github.com/mattn/go-isatty v0.0.19/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= +github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY= +github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= github.com/mattn/go-runewidth v0.0.9/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI= github.com/mattn/go-runewidth v0.0.14 h1:+xnbZSEeDbOIg5/mE6JF0w6n9duR1l3/WmbinWVwUuU= github.com/mattn/go-runewidth v0.0.14/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w= @@ -324,6 +325,7 @@ github.com/tklauser/numcpus v0.5.0/go.mod h1:OGzpTxpcIMNGYQdit2BYL1pvk/dSOaJWjKo github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= +github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= github.com/yusufpapurcu/wmi v1.2.2 h1:KBNDSne4vP5mbSWnJbO+51IMOXJB67QiYCSBrubbPRg= github.com/yusufpapurcu/wmi v1.2.2/go.mod h1:SBZ9tNy3G9/m5Oi98Zks0QjeHVDvuK0qfxQmPyzfmi0= go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU= @@ -339,6 +341,7 @@ golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8U golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8= @@ -369,6 +372,7 @@ golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzB golang.org/x/mod v0.1.1-0.20191107180719-034126e5016b/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= @@ -397,11 +401,13 @@ golang.org/x/net v0.0.0-20200520182314-0ba52f642ac2/go.mod h1:qpuaurCH72eLCgpAm/ golang.org/x/net v0.0.0-20200625001655-4c5254603344/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= golang.org/x/net v0.0.0-20200707034311-ab3426394381/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= +golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20210525063256-abc453219eb5/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= golang.org/x/net v0.0.0-20220225172249-27dd8689420f/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= -golang.org/x/net v0.14.0 h1:BONx9s002vGdD9umnlX1Po8vOZmrgH34qlHcD1MfK14= -golang.org/x/net v0.14.0/go.mod h1:PpSgVXXLK0OxS0F31C1/tv6XNguvCrnXIDrFMspZIUI= +golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= +golang.org/x/net v0.17.0 h1:pVaXccu2ozPjCXewfr1S7xza/zcXTity9cCdXQYSjIM= +golang.org/x/net v0.17.0/go.mod h1:NxSsAGuq816PNPmqtQdLE42eU2Fs7NoRIZrHJAlaCOE= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= @@ -420,6 +426,7 @@ golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJ golang.org/x/sync v0.0.0-20200317015054-43a5402ce75a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= @@ -464,10 +471,12 @@ golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20220114195835-da31bd327af9/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220128215802-99c3d69c2c27/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220503163025-988cb79eb6c6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.11.0 h1:eG7RXZHdqOJ1i+0lgLgCpSXAp6M3LYlAo6osgSi0xOM= -golang.org/x/sys v0.11.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.16.0 h1:xWw16ngr6ZMtmxDyKyIgsE93KNKz5HKmMa3b8ALHidU= +golang.org/x/sys v0.16.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= @@ -477,8 +486,9 @@ golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= -golang.org/x/text v0.12.0 h1:k+n5B8goJNdU7hSvEtMUz3d1Q6D/XW4COJSJR6fN0mc= -golang.org/x/text v0.12.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= +golang.org/x/text v0.3.8/go.mod h1:E6s5w1FMmriuDzIBO73fBruAKo1PCIq6d2Q6DHfQ8WQ= +golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ= +golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= @@ -522,6 +532,7 @@ golang.org/x/tools v0.0.0-20200618134242-20370b0cb4b2/go.mod h1:EkVYQZoAsY45+roY golang.org/x/tools v0.0.0-20200729194436-6467de6f59a7/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= golang.org/x/tools v0.0.0-20200804011535-6c149bb5ef0d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= golang.org/x/tools v0.0.0-20200825202427-b303f430e36d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= +golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= @@ -548,8 +559,8 @@ google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7 google.golang.org/appengine v1.6.1/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0= google.golang.org/appengine v1.6.5/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= google.golang.org/appengine v1.6.6/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= -google.golang.org/appengine v1.6.7 h1:FZR1q0exgwxzPzp/aF+VccGrSfxfPpkBqjIIEq3ru6c= -google.golang.org/appengine v1.6.7/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= +google.golang.org/appengine v1.6.8 h1:IhEN5q69dyKagZPYMSdIjS2HqprW324FRQZJcGqPAsM= +google.golang.org/appengine v1.6.8/go.mod h1:1jJ3jBArFh5pcgW8gCtRJnepW8FzD1V44FJffLiz/Ds= google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= google.golang.org/genproto v0.0.0-20190418145605-e7d98fc518a7/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= @@ -579,8 +590,8 @@ google.golang.org/genproto v0.0.0-20200618031413-b414f8b61790/go.mod h1:jDfRM7Fc google.golang.org/genproto v0.0.0-20200729003335-053ba62fc06f/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20200804131852-c06518451d9c/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20200825200019-8632dd797987/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= -google.golang.org/genproto/googleapis/rpc v0.0.0-20230815205213-6bfd019c3878 h1:lv6/DhyiFFGsmzxbsUUTOkN29II+zeWHxvT8Lpdxsv0= -google.golang.org/genproto/googleapis/rpc v0.0.0-20230815205213-6bfd019c3878/go.mod h1:+Bk1OCOj40wS2hwAMA+aCW9ypzm63QTBBHp6lQ3p+9M= +google.golang.org/genproto/googleapis/rpc v0.0.0-20240116215550-a9fa1716bcac h1:nUQEQmH/csSvFECKYRv6HWEyypysidKl2I6Qpsglq/0= +google.golang.org/genproto/googleapis/rpc v0.0.0-20240116215550-a9fa1716bcac/go.mod h1:daQN87bsDqDoe316QbbvX60nMoJQa4r6Ds0ZuoAe5yA= google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38= google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM= @@ -607,8 +618,8 @@ google.golang.org/protobuf v1.24.0/go.mod h1:r/3tXBNzIEhYS9I1OUVjXDlt8tc493IdKGj google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c= google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= -google.golang.org/protobuf v1.31.0 h1:g0LDEJHgrBl9N9r17Ru3sqWhkIx2NB67okBHPwC7hs8= -google.golang.org/protobuf v1.31.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= +google.golang.org/protobuf v1.32.0 h1:pPC6BG5ex8PDFnkbrGU3EixyhKcQ2aDuBS36lqK/C7I= +google.golang.org/protobuf v1.32.0/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos= gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= diff --git a/hrp/cmd/adb/screencap.go b/hrp/cmd/adb/screencap.go index d25352bf..e74b7a4e 100644 --- a/hrp/cmd/adb/screencap.go +++ b/hrp/cmd/adb/screencap.go @@ -2,7 +2,7 @@ package adb import ( "fmt" - "io/ioutil" + "os" "strings" "time" @@ -36,7 +36,7 @@ var screencapAndroidDevicesCmd = &cobra.Command{ } filepath := fmt.Sprintf("%s.png", builtin.GenNameWithTimestamp("screencap_%d")) - if err = ioutil.WriteFile(filepath, res, 0o644); err != nil { + if err = os.WriteFile(filepath, res, 0o644); err != nil { return err } fmt.Println("screencap saved to", filepath) diff --git a/hrp/internal/version/VERSION b/hrp/internal/version/VERSION index 471e7432..98b734ff 100644 --- a/hrp/internal/version/VERSION +++ b/hrp/internal/version/VERSION @@ -1 +1 @@ -v4.3.6 \ No newline at end of file +v4.3.8-202401091556 \ No newline at end of file diff --git a/hrp/pkg/gadb/client_test.go b/hrp/pkg/gadb/client_test.go index 028a3b59..1ce1f975 100644 --- a/hrp/pkg/gadb/client_test.go +++ b/hrp/pkg/gadb/client_test.go @@ -3,7 +3,7 @@ package gadb import ( - "io/ioutil" + "os" "testing" ) @@ -116,6 +116,6 @@ func TestScreenCap(t *testing.T) { t.Error(err) } t.Log(len(res)) - ioutil.WriteFile("/tmp/1.png", res, 0o644) + os.WriteFile("/tmp/1.png", res, 0o644) } } diff --git a/hrp/pkg/gadb/device_test.go b/hrp/pkg/gadb/device_test.go index 50b37175..7af949c2 100644 --- a/hrp/pkg/gadb/device_test.go +++ b/hrp/pkg/gadb/device_test.go @@ -4,7 +4,6 @@ package gadb import ( "bytes" - "io/ioutil" "os" "reflect" "strings" @@ -244,7 +243,7 @@ func TestDevice_Pull(t *testing.T) { } userHomeDir, _ := os.UserHomeDir() - if err = ioutil.WriteFile(userHomeDir+"/Desktop/hello.txt", buffer.Bytes(), DefaultFileMode); err != nil { + if err = os.WriteFile(userHomeDir+"/Desktop/hello.txt", buffer.Bytes(), DefaultFileMode); err != nil { t.Fatal(err) } } diff --git a/hrp/pkg/uixt/android_test.go b/hrp/pkg/uixt/android_test.go index ffed7d4e..d1b8706f 100644 --- a/hrp/pkg/uixt/android_test.go +++ b/hrp/pkg/uixt/android_test.go @@ -5,7 +5,7 @@ package uixt import ( "encoding/json" "fmt" - "io/ioutil" + "os" "testing" "time" ) @@ -87,7 +87,7 @@ func TestDriver_Screenshot(t *testing.T) { t.Fatal(err) } - t.Log(ioutil.WriteFile("/Users/hero/Desktop/s1.png", screenshot.Bytes(), 0o600)) + t.Log(os.WriteFile("/Users/hero/Desktop/s1.png", screenshot.Bytes(), 0o600)) } func TestDriver_Rotation(t *testing.T) { @@ -346,7 +346,7 @@ func TestDriver_AppLaunch(t *testing.T) { t.Fatal(err) } - t.Log(ioutil.WriteFile("s1.png", raw.Bytes(), 0o600)) + t.Log(os.WriteFile("s1.png", raw.Bytes(), 0o600)) } func TestDriver_IsAppInForeground(t *testing.T) { diff --git a/hrp/pkg/uixt/ios_test.go b/hrp/pkg/uixt/ios_test.go index 0e6a16f5..4b34d2f4 100644 --- a/hrp/pkg/uixt/ios_test.go +++ b/hrp/pkg/uixt/ios_test.go @@ -298,7 +298,7 @@ func Test_remoteWD_GetPasteboard(t *testing.T) { // t.Fatal(err) // } // userHomeDir, _ := os.UserHomeDir() - // if err = ioutil.WriteFile(userHomeDir+"/Desktop/p1.png", buffer.Bytes(), 0600); err != nil { + // if err = os.WriteFile(userHomeDir+"/Desktop/p1.png", buffer.Bytes(), 0600); err != nil { // t.Error(err) // } } diff --git a/hrp/runner_test.go b/hrp/runner_test.go index 01d84a88..b66c7748 100644 --- a/hrp/runner_test.go +++ b/hrp/runner_test.go @@ -1,7 +1,6 @@ package hrp import ( - "io/ioutil" "os" "path/filepath" "testing" @@ -31,8 +30,8 @@ func removeHashicorpGoPlugin() { func buildHashicorpPyPlugin() { log.Info().Msg("[init] prepare hashicorp python plugin") - src, _ := ioutil.ReadFile(tmpl("plugin/debugtalk.py")) - err := ioutil.WriteFile(tmpl("debugtalk.py"), src, 0o644) + src, _ := os.ReadFile(tmpl("plugin/debugtalk.py")) + err := os.WriteFile(tmpl("debugtalk.py"), src, 0o644) if err != nil { log.Error().Err(err).Msg("copy hashicorp python plugin failed") os.Exit(code.GetErrorCode(err)) @@ -156,6 +155,27 @@ func TestRunCaseWithThinkTime(t *testing.T) { } } +func TestRunCaseWithShell(t *testing.T) { + testcase1 := &TestCase{ + Config: NewConfig("complex shell with env variables"). + WithVariables(map[string]interface{}{ + "SS": "12345", + "ABC": "$SS", + }), + TestSteps: []IStep{ + NewStep("shell21").Shell("echo hello world"), + // NewStep("shell21").Shell("echo $ABC"), + // NewStep("shell21").Shell("which hrp"), + }, + } + + r := NewRunner(t) + err := r.Run(testcase1) + if err != nil { + t.Fatal() + } +} + func TestRunCaseWithPluginJSON(t *testing.T) { buildHashicorpGoPlugin() defer removeHashicorpGoPlugin() diff --git a/hrp/step.go b/hrp/step.go index 88641370..0c95988c 100644 --- a/hrp/step.go +++ b/hrp/step.go @@ -12,6 +12,10 @@ const ( stepTypeWebSocket StepType = "websocket" stepTypeAndroid StepType = "android" stepTypeIOS StepType = "ios" + stepTypeShell StepType = "shell" + + stepTypeSuffixExtraction StepType = "_extraction" + stepTypeSuffixValidation StepType = "_validation" ) type StepResult struct { @@ -40,6 +44,7 @@ type TStep struct { WebSocket *WebSocketAction `json:"websocket,omitempty" yaml:"websocket,omitempty"` Android *MobileStep `json:"android,omitempty" yaml:"android,omitempty"` IOS *MobileStep `json:"ios,omitempty" yaml:"ios,omitempty"` + Shell *Shell `json:"shell,omitempty" yaml:"shell,omitempty"` Variables map[string]interface{} `json:"variables,omitempty" yaml:"variables,omitempty"` SetupHooks []string `json:"setup_hooks,omitempty" yaml:"setup_hooks,omitempty"` TeardownHooks []string `json:"teardown_hooks,omitempty" yaml:"teardown_hooks,omitempty"` diff --git a/hrp/step_mobile_ui.go b/hrp/step_mobile_ui.go index f65a9d6a..efdc0dea 100644 --- a/hrp/step_mobile_ui.go +++ b/hrp/step_mobile_ui.go @@ -522,7 +522,10 @@ func (s *StepMobileUIValidation) Name() string { } func (s *StepMobileUIValidation) Type() StepType { - return stepTypeIOS + if s.step.Android != nil { + return stepTypeAndroid + stepTypeSuffixValidation + } + return stepTypeIOS + stepTypeSuffixValidation } func (s *StepMobileUIValidation) Struct() *TStep { diff --git a/hrp/step_request.go b/hrp/step_request.go index 6d672a3c..08574fd4 100644 --- a/hrp/step_request.go +++ b/hrp/step_request.go @@ -769,6 +769,18 @@ func (s *StepRequest) IOS() *StepMobile { } } +// Shell creates a new shell action +func (s *StepRequest) Shell(content string) *StepShell { + s.step.Shell = &Shell{ + String: content, + ExpectExitCode: 0, + } + + return &StepShell{ + step: s.step, + } +} + // StepRequestWithOptionalArgs implements IStep interface. type StepRequestWithOptionalArgs struct { step *TStep @@ -904,13 +916,13 @@ func (s *StepRequestExtraction) Name() string { } func (s *StepRequestExtraction) Type() StepType { - if s.step.Request != nil { - return StepType(fmt.Sprintf("request-%v", s.step.Request.Method)) - } + var stepType StepType if s.step.WebSocket != nil { - return StepType(fmt.Sprintf("websocket-%v", s.step.WebSocket.Type)) + stepType = StepType(fmt.Sprintf("websocket-%v", s.step.WebSocket.Type)) + } else { + stepType = StepType(fmt.Sprintf("request-%v", s.step.Request.Method)) } - return "extraction" + return stepType + stepTypeSuffixExtraction } func (s *StepRequestExtraction) Struct() *TStep { @@ -940,13 +952,13 @@ func (s *StepRequestValidation) Name() string { } func (s *StepRequestValidation) Type() StepType { - if s.step.Request != nil { - return StepType(fmt.Sprintf("request-%v", s.step.Request.Method)) - } + var stepType StepType if s.step.WebSocket != nil { - return StepType(fmt.Sprintf("websocket-%v", s.step.WebSocket.Type)) + stepType = StepType(fmt.Sprintf("websocket-%v", s.step.WebSocket.Type)) + } else { + stepType = StepType(fmt.Sprintf("request-%v", s.step.Request.Method)) } - return "validation" + return stepType + stepTypeSuffixValidation } func (s *StepRequestValidation) Struct() *TStep { diff --git a/hrp/step_shell.go b/hrp/step_shell.go new file mode 100644 index 00000000..d7ba2d37 --- /dev/null +++ b/hrp/step_shell.go @@ -0,0 +1,119 @@ +package hrp + +import ( + "fmt" + "os" + "time" + + "github.com/httprunner/funplugin/myexec" + "github.com/pkg/errors" + "github.com/rs/zerolog/log" +) + +type Shell struct { + String string `json:"string" yaml:"string"` + ExpectExitCode int `json:"expect_exit_code" yaml:"expect_exit_code"` +} + +// StepShell implements IStep interface. +type StepShell struct { + step *TStep +} + +func (s *StepShell) Name() string { + return s.step.Name +} + +func (s *StepShell) Type() StepType { + return stepTypeShell +} + +func (s *StepShell) Struct() *TStep { + return s.step +} + +func (s *StepShell) Run(r *SessionRunner) (*StepResult, error) { + return runStepShell(r, s.step) +} + +// Validate switches to step validation. +func (s *StepShell) Validate() *StepShellValidation { + return &StepShellValidation{ + step: s.step, + } +} + +// StepShellValidation implements IStep interface. +type StepShellValidation struct { + step *TStep +} + +func (s *StepShellValidation) Name() string { + return s.step.Name +} + +func (s *StepShellValidation) Type() StepType { + return stepTypeShell + stepTypeSuffixValidation +} + +func (s *StepShellValidation) Struct() *TStep { + return s.step +} + +func (s *StepShellValidation) Run(r *SessionRunner) (*StepResult, error) { + return runStepShell(r, s.step) +} + +func (s *StepShellValidation) AssertExitCode(expected int) *StepShellValidation { + s.step.Shell.ExpectExitCode = expected + return s +} + +func runStepShell(r *SessionRunner, step *TStep) (stepResult *StepResult, err error) { + shell := step.Shell + log.Info(). + Str("name", step.Name). + Str("type", string(stepTypeShell)). + Str("content", shell.String). + Msg("run shell string") + + stepResult = &StepResult{ + Name: step.Name, + StepType: stepTypeShell, + Success: false, + Elapsed: 0, + ContentSize: 0, + } + + vars := r.caseRunner.parsedConfig.Variables + for key, value := range vars { + os.Setenv(key, fmt.Sprintf("%v", value)) + } + + start := time.Now() + exitCode, err := myexec.RunShell(shell.String) + stepResult.Elapsed = time.Since(start).Milliseconds() + if err != nil { + if exitCode == shell.ExpectExitCode { + // get expected error + log.Warn().Err(err). + Int("exitCode", exitCode). + Msg("get expected error, ignore") + stepResult.Success = true + return stepResult, nil + } + + err = errors.Wrap(err, "exec shell string failed") + return + } + + // validate response + if exitCode != shell.ExpectExitCode { + err = fmt.Errorf("unexpected exit code %d, expect %d", + exitCode, shell.ExpectExitCode) + return + } + + stepResult.Success = true + return stepResult, nil +} diff --git a/hrp/testcase.go b/hrp/testcase.go index 3640f6f5..b0c9bedb 100644 --- a/hrp/testcase.go +++ b/hrp/testcase.go @@ -282,6 +282,10 @@ func (tc *TCase) toTestCase() (*TestCase, error) { testCase.TestSteps = append(testCase.TestSteps, &StepMobile{ step: step, }) + } else if step.Shell != nil { + testCase.TestSteps = append(testCase.TestSteps, &StepShell{ + step: step, + }) } else { log.Warn().Interface("step", step).Msg("[convertTestCase] unexpected step") }