mirror of
https://github.com/httprunner/httprunner.git
synced 2026-05-13 08:59:44 +08:00
fix: call referenced api/testcase with relative path
This commit is contained in:
16
.github/workflows/hrp-scaffold.yml
vendored
16
.github/workflows/hrp-scaffold.yml
vendored
@@ -25,8 +25,11 @@ jobs:
|
||||
run: make build
|
||||
- name: Run start project
|
||||
run: ./output/hrp startproject demo
|
||||
- name: Run demo tests
|
||||
- name: Run generated demo tests
|
||||
run: ./output/hrp run demo/testcases/demo_with_funplugin.json demo/testcases/demo_requests.yml demo/testcases/demo_ref_testcase.yml
|
||||
- name: Run demo in examples
|
||||
run: |
|
||||
./output/hrp run examples/demo-with-py-plugin/testcases/demo_with_funplugin.json
|
||||
|
||||
scaffold-with-go-plugin:
|
||||
strategy:
|
||||
@@ -47,8 +50,12 @@ jobs:
|
||||
run: make build
|
||||
- name: Run start project
|
||||
run: ./output/hrp startproject demo --go
|
||||
- name: Run demo tests
|
||||
- name: Run generated demo tests
|
||||
run: ./output/hrp run demo/testcases/demo_with_funplugin.json demo/testcases/demo_requests.yml demo/testcases/demo_ref_testcase.yml
|
||||
- name: Run demo in examples
|
||||
run: |
|
||||
go build -o examples/demo-with-go-plugin/debugtalk.bin examples/demo-with-go-plugin/plugin/debugtalk.go
|
||||
./output/hrp run examples/demo-with-go-plugin/testcases/demo_with_funplugin.json
|
||||
|
||||
scaffold-without-custom-plugin:
|
||||
strategy:
|
||||
@@ -69,5 +76,8 @@ jobs:
|
||||
run: make build
|
||||
- name: Run start project
|
||||
run: ./output/hrp startproject demo --ignore-plugin
|
||||
- name: Run demo tests
|
||||
- name: Run generated demo tests
|
||||
run: ./output/hrp run demo/testcases/demo_without_funplugin.json
|
||||
- name: Run demo in examples
|
||||
run: |
|
||||
./output/hrp run examples/demo-without-plugin/testcases/demo_without_funplugin.json
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# Release History
|
||||
|
||||
## 4.0.0
|
||||
## v4.0.0-alpha
|
||||
|
||||
- refactor: merge [hrp] into httprunner v4, which will include golang and python dual engine
|
||||
|
||||
|
||||
@@ -1,135 +0,0 @@
|
||||
{
|
||||
"config": {
|
||||
"name": "testcase description",
|
||||
"variables": {},
|
||||
"verify": false
|
||||
},
|
||||
"teststeps": [
|
||||
{
|
||||
"name": "/get",
|
||||
"request": {
|
||||
"url": "https://postman-echo.com/get",
|
||||
"params": {
|
||||
"foo1": "HDnY8",
|
||||
"foo2": "34.5"
|
||||
},
|
||||
"method": "GET",
|
||||
"headers": {
|
||||
"Host": "postman-echo.com",
|
||||
"User-Agent": "HttpRunnerPlus",
|
||||
"Accept-Encoding": "gzip"
|
||||
}
|
||||
},
|
||||
"validate": [
|
||||
{
|
||||
"eq": [
|
||||
"status_code",
|
||||
200
|
||||
]
|
||||
},
|
||||
{
|
||||
"eq": [
|
||||
"headers.Content-Type",
|
||||
"application/json; charset=utf-8"
|
||||
]
|
||||
},
|
||||
{
|
||||
"eq": [
|
||||
"body.url",
|
||||
"https://postman-echo.com/get?foo1=HDnY8&foo2=34.5"
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "/post",
|
||||
"request": {
|
||||
"url": "https://postman-echo.com/post",
|
||||
"method": "POST",
|
||||
"cookies": {
|
||||
"sails.sid": "s%3Az_LpglkKxTvJ_eHVUH6V67drKp0AGWW-.PidabaXOnatLRP47hVyqqepl6BdrpEQzRlJQXtbIiwk"
|
||||
},
|
||||
"headers": {
|
||||
"Host": "postman-echo.com",
|
||||
"User-Agent": "Go-http-client/1.1",
|
||||
"Content-Length": "28",
|
||||
"Content-Type": "application/json; charset=UTF-8",
|
||||
"Cookie": "sails.sid=s%3Az_LpglkKxTvJ_eHVUH6V67drKp0AGWW-.PidabaXOnatLRP47hVyqqepl6BdrpEQzRlJQXtbIiwk",
|
||||
"Accept-Encoding": "gzip"
|
||||
},
|
||||
"json": {
|
||||
"foo1": "HDnY8",
|
||||
"foo2": 12.3
|
||||
}
|
||||
},
|
||||
"validate": [
|
||||
{
|
||||
"eq": [
|
||||
"status_code",
|
||||
200
|
||||
]
|
||||
},
|
||||
{
|
||||
"eq": [
|
||||
"headers.Content-Type",
|
||||
"application/json; charset=utf-8"
|
||||
]
|
||||
},
|
||||
{
|
||||
"eq": [
|
||||
"body.url",
|
||||
"https://postman-echo.com/post"
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "/post",
|
||||
"request": {
|
||||
"url": "https://postman-echo.com/post",
|
||||
"method": "POST",
|
||||
"cookies": {
|
||||
"sails.sid": "s%3AS5e7w0zQ0xAsCwh9L8T6R7QLYCO7_gtD.r8%2B2w9IWqEIfuVkrZjnxzm2xADIk34zKAWXRPapr%2FAw"
|
||||
},
|
||||
"headers": {
|
||||
"Host": "postman-echo.com",
|
||||
"User-Agent": "Go-http-client/1.1",
|
||||
"Content-Length": "20",
|
||||
"Content-Type": "application/x-www-form-urlencoded; charset=UTF-8",
|
||||
"Cookie": "sails.sid=s%3AS5e7w0zQ0xAsCwh9L8T6R7QLYCO7_gtD.r8%2B2w9IWqEIfuVkrZjnxzm2xADIk34zKAWXRPapr%2FAw",
|
||||
"Accept-Encoding": "gzip"
|
||||
},
|
||||
"data": {
|
||||
"foo1": "HDnY8",
|
||||
"foo2": "12.3"
|
||||
}
|
||||
},
|
||||
"validate": [
|
||||
{
|
||||
"eq": [
|
||||
"status_code",
|
||||
200
|
||||
]
|
||||
},
|
||||
{
|
||||
"eq": [
|
||||
"headers.Content-Type",
|
||||
"application/json; charset=utf-8"
|
||||
]
|
||||
},
|
||||
{
|
||||
"eq": [
|
||||
"body.data",
|
||||
""
|
||||
]
|
||||
},
|
||||
{
|
||||
"eq": [
|
||||
"body.url",
|
||||
"https://postman-echo.com/post"
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -1,81 +0,0 @@
|
||||
config:
|
||||
name: testcase description
|
||||
variables: {}
|
||||
verify: false
|
||||
teststeps:
|
||||
- name: /get
|
||||
request:
|
||||
headers:
|
||||
Accept-Encoding: gzip
|
||||
Host: postman-echo.com
|
||||
User-Agent: HttpRunnerPlus
|
||||
method: GET
|
||||
params:
|
||||
foo1: HDnY8
|
||||
foo2: '34.5'
|
||||
url: https://postman-echo.com/get
|
||||
validate:
|
||||
- eq:
|
||||
- status_code
|
||||
- 200
|
||||
- eq:
|
||||
- headers.Content-Type
|
||||
- application/json; charset=utf-8
|
||||
- eq:
|
||||
- body.url
|
||||
- https://postman-echo.com/get?foo1=HDnY8&foo2=34.5
|
||||
- name: /post
|
||||
request:
|
||||
cookies:
|
||||
sails.sid: s%3Az_LpglkKxTvJ_eHVUH6V67drKp0AGWW-.PidabaXOnatLRP47hVyqqepl6BdrpEQzRlJQXtbIiwk
|
||||
headers:
|
||||
Accept-Encoding: gzip
|
||||
Content-Length: '28'
|
||||
Content-Type: application/json; charset=UTF-8
|
||||
Cookie: sails.sid=s%3Az_LpglkKxTvJ_eHVUH6V67drKp0AGWW-.PidabaXOnatLRP47hVyqqepl6BdrpEQzRlJQXtbIiwk
|
||||
Host: postman-echo.com
|
||||
User-Agent: Go-http-client/1.1
|
||||
json:
|
||||
foo1: HDnY8
|
||||
foo2: 12.3
|
||||
method: POST
|
||||
url: https://postman-echo.com/post
|
||||
validate:
|
||||
- eq:
|
||||
- status_code
|
||||
- 200
|
||||
- eq:
|
||||
- headers.Content-Type
|
||||
- application/json; charset=utf-8
|
||||
- eq:
|
||||
- body.url
|
||||
- https://postman-echo.com/post
|
||||
- name: /post
|
||||
request:
|
||||
cookies:
|
||||
sails.sid: s%3AS5e7w0zQ0xAsCwh9L8T6R7QLYCO7_gtD.r8%2B2w9IWqEIfuVkrZjnxzm2xADIk34zKAWXRPapr%2FAw
|
||||
data:
|
||||
foo1: HDnY8
|
||||
foo2: '12.3'
|
||||
headers:
|
||||
Accept-Encoding: gzip
|
||||
Content-Length: '20'
|
||||
Content-Type: application/x-www-form-urlencoded; charset=UTF-8
|
||||
Cookie: sails.sid=s%3AS5e7w0zQ0xAsCwh9L8T6R7QLYCO7_gtD.r8%2B2w9IWqEIfuVkrZjnxzm2xADIk34zKAWXRPapr%2FAw
|
||||
Host: postman-echo.com
|
||||
User-Agent: Go-http-client/1.1
|
||||
method: POST
|
||||
url: https://postman-echo.com/post
|
||||
validate:
|
||||
- eq:
|
||||
- status_code
|
||||
- 200
|
||||
- eq:
|
||||
- headers.Content-Type
|
||||
- application/json; charset=utf-8
|
||||
- eq:
|
||||
- body.data
|
||||
- ''
|
||||
- eq:
|
||||
- body.url
|
||||
- https://postman-echo.com/post
|
||||
@@ -1,47 +0,0 @@
|
||||
config:
|
||||
name: 'api test demo'
|
||||
variables:
|
||||
user_agent: iOS/10.3
|
||||
device_sn: TESTCASE_SETUP_XXX
|
||||
os_platform: ios
|
||||
app_version: 2.8.6
|
||||
base_url: 'https://postman-echo.com'
|
||||
herader:
|
||||
- Accept: '*/*'
|
||||
Accept-Encoding: 'gzip, deflate, br'
|
||||
Cache-Control: no-cache
|
||||
Connection: keep-alive
|
||||
Host: postman-echo.com
|
||||
User-Agent: PostmanRuntime/7.28.4
|
||||
verify: false
|
||||
export:
|
||||
- session_token
|
||||
teststeps:
|
||||
- name: 'test api /get'
|
||||
api: api/get.json
|
||||
variables:
|
||||
user_agent: iOS/10.4
|
||||
device_sn: $device_sn
|
||||
os_platform: ios
|
||||
app_version: 2.8.7
|
||||
extract:
|
||||
session_token: 'body.headers."postman-token"'
|
||||
- name: 'test api /post'
|
||||
api: api/post.json
|
||||
variables:
|
||||
user_agent: iOS/10.5
|
||||
device_sn: $device_sn
|
||||
os_platform: ios
|
||||
app_version: 2.8.9
|
||||
validate:
|
||||
- { eq: [ status_code, 200 ] }
|
||||
- { eq: [ body.headers.postman-token, ea19464c-ddd4-4724-abe9-5e2b254c2723 ] }
|
||||
- name: 'test api /put'
|
||||
api: api/put.json
|
||||
variables:
|
||||
user_agent: iOS/10.6
|
||||
device_sn: $device_sn
|
||||
os_platform: ios
|
||||
app_version: 2.8.10
|
||||
extract:
|
||||
session_token: 'body.headers."postman-token"'
|
||||
@@ -1,18 +0,0 @@
|
||||
{
|
||||
"config": {
|
||||
"name": "reference testcase test",
|
||||
"base_url": "https://postman-echo.com",
|
||||
"variables": {
|
||||
"os_platform": "ios"
|
||||
}
|
||||
},
|
||||
"teststeps": [
|
||||
{
|
||||
"name": "run demo_httprunner.json",
|
||||
"testcase": "demo_httprunner.json",
|
||||
"variables": {
|
||||
"os_platform": "$os_platform"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -1,11 +0,0 @@
|
||||
config:
|
||||
name: "reference testcase test"
|
||||
base_url: "https://postman-echo.com"
|
||||
variables:
|
||||
os_platform: 'ios'
|
||||
|
||||
teststeps:
|
||||
- name: run demo_httprunner.yaml
|
||||
testcase: demo_httprunner.yaml
|
||||
variables:
|
||||
os_platform: $os_platform
|
||||
@@ -1,40 +0,0 @@
|
||||
config:
|
||||
name: "think time test demo"
|
||||
variables:
|
||||
app_version: v1
|
||||
user_agent: iOS/10.3
|
||||
base_url: "https://postman-echo.com"
|
||||
think_time:
|
||||
strategy: random_percentage
|
||||
setting:
|
||||
min_percentage: 1.0
|
||||
max_percentage: 1.5
|
||||
limit: 4
|
||||
verify: False
|
||||
|
||||
teststeps:
|
||||
- name: get with params
|
||||
request:
|
||||
method: GET
|
||||
url: /get
|
||||
headers:
|
||||
User-Agent: $user_agent,$app_version
|
||||
validate:
|
||||
- check: status_code
|
||||
assert: equals
|
||||
expect: 200
|
||||
msg: check status code
|
||||
- name: think time 1
|
||||
think_time:
|
||||
time: 3
|
||||
- name: post with params
|
||||
request:
|
||||
method: POST
|
||||
url: /post
|
||||
headers:
|
||||
User-Agent: $user_agent,$app_version
|
||||
validate:
|
||||
- check: status_code
|
||||
assert: equals
|
||||
expect: 200
|
||||
msg: check status code
|
||||
@@ -2,9 +2,11 @@ package hrp
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
"github.com/rs/zerolog/log"
|
||||
|
||||
"github.com/httprunner/httprunner/hrp/internal/builtin"
|
||||
@@ -92,9 +94,21 @@ func (tc *TCase) ToTestCase() (*TestCase, error) {
|
||||
testCase := &TestCase{
|
||||
Config: tc.Config,
|
||||
}
|
||||
|
||||
// locate project root dir by plugin path
|
||||
projectRootDir, err := getProjectRootDirPath(testCase.Config.Path)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "failed to get project root dir")
|
||||
}
|
||||
log.Info().Str("dir", projectRootDir).Msg("located project root dir")
|
||||
|
||||
for _, step := range tc.TestSteps {
|
||||
if step.APIPath != "" {
|
||||
path := filepath.Join(filepath.Dir(testCase.Config.Path), step.APIPath)
|
||||
path := filepath.Join(projectRootDir, step.APIPath)
|
||||
if !builtin.IsFilePathExists(path) {
|
||||
return nil, errors.New("referenced api file not found: " + path)
|
||||
}
|
||||
|
||||
refAPI := APIPath(path)
|
||||
step.APIContent = &refAPI
|
||||
apiContent, err := step.APIContent.ToAPI()
|
||||
@@ -106,7 +120,11 @@ func (tc *TCase) ToTestCase() (*TestCase, error) {
|
||||
step: step,
|
||||
})
|
||||
} else if step.TestCasePath != "" {
|
||||
path := filepath.Join(filepath.Dir(testCase.Config.Path), step.TestCasePath)
|
||||
path := filepath.Join(projectRootDir, step.TestCasePath)
|
||||
if !builtin.IsFilePathExists(path) {
|
||||
return nil, errors.New("referenced testcase file not found: " + path)
|
||||
}
|
||||
|
||||
refTestCase := TestCasePath(path)
|
||||
step.TestCaseContent = &refTestCase
|
||||
tc, err := step.TestCaseContent.ToTestCase()
|
||||
@@ -140,16 +158,29 @@ func (tc *TCase) ToTestCase() (*TestCase, error) {
|
||||
return testCase, nil
|
||||
}
|
||||
|
||||
func getProjectRootDirPath(path string) (rootDir string, err error) {
|
||||
pluginPath, err := locatePlugin(path)
|
||||
if err == nil {
|
||||
rootDir = filepath.Dir(pluginPath)
|
||||
return
|
||||
}
|
||||
|
||||
// failed to locate project root dir
|
||||
// maybe project plugin debugtalk.xx is not exist
|
||||
// use current dir instead
|
||||
return os.Getwd()
|
||||
}
|
||||
|
||||
// APIPath implements IAPI interface.
|
||||
type APIPath string
|
||||
|
||||
func (path *APIPath) ToString() string {
|
||||
func (path *APIPath) GetPath() string {
|
||||
return fmt.Sprintf("%v", *path)
|
||||
}
|
||||
|
||||
func (path *APIPath) ToAPI() (*API, error) {
|
||||
api := &API{}
|
||||
apiPath := path.ToString()
|
||||
apiPath := path.GetPath()
|
||||
err := builtin.LoadFile(apiPath, api)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@@ -161,22 +192,23 @@ func (path *APIPath) ToAPI() (*API, error) {
|
||||
// TestCasePath implements ITestCase interface.
|
||||
type TestCasePath string
|
||||
|
||||
func (path *TestCasePath) ToString() string {
|
||||
func (path *TestCasePath) GetPath() string {
|
||||
return fmt.Sprintf("%v", *path)
|
||||
}
|
||||
|
||||
func (path *TestCasePath) ToTestCase() (*TestCase, error) {
|
||||
tc := &TCase{}
|
||||
casePath := path.ToString()
|
||||
casePath := path.GetPath()
|
||||
err := builtin.LoadFile(casePath, tc)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
err = convertCompatTestCase(tc)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
tc.Config.Path = path.ToString()
|
||||
tc.Config.Path = casePath
|
||||
testcase, err := tc.ToTestCase()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
||||
@@ -8,20 +8,22 @@ import (
|
||||
"github.com/httprunner/httprunner/hrp/internal/builtin"
|
||||
)
|
||||
|
||||
const templatesDir = "internal/scaffold/templates/"
|
||||
const (
|
||||
templatesDir = "internal/scaffold/templates/"
|
||||
hrpExamplesDir = "../examples/hrp"
|
||||
)
|
||||
|
||||
var (
|
||||
demoTestCaseWithPluginJSONPath TestCasePath = templatesDir + "testcases/demo_with_funplugin.json"
|
||||
demoTestCaseWithPluginYAMLPath TestCasePath = templatesDir + "testcases/demo_with_funplugin.yaml"
|
||||
demoTestCaseWithoutPluginJSONPath TestCasePath = templatesDir + "testcases/demo_without_funplugin.json"
|
||||
demoTestCaseWithoutPluginYAMLPath TestCasePath = templatesDir + "testcases/demo_without_funplugin.yaml"
|
||||
demoTestCaseWithRefAPIPath TestCasePath = templatesDir + "testcases/demo_ref_api.json"
|
||||
demoAPIGETPath APIPath = templatesDir + "/api/get.yml"
|
||||
)
|
||||
|
||||
var (
|
||||
demoRefAPIYAMLPath TestCasePath = "../examples/hrp/ref_api_test.yaml"
|
||||
demoRefTestCaseJSONPath TestCasePath = "../examples/hrp/ref_testcase_test.json"
|
||||
demoThinkTimeJsonPath TestCasePath = "../examples/hrp/think_time_test.json"
|
||||
demoAPIYAMLPath APIPath = "../examples/hrp/api/put.yml"
|
||||
demoTestCaseWithThinkTimePath TestCasePath = hrpExamplesDir + "/think_time_test.json"
|
||||
)
|
||||
|
||||
var demoTestCaseWithPlugin = &TestCase{
|
||||
@@ -152,41 +154,21 @@ var demoTestCaseWithoutPlugin = &TestCase{
|
||||
|
||||
func TestGenDemoTestCase(t *testing.T) {
|
||||
tCase, _ := demoTestCaseWithPlugin.ToTCase()
|
||||
err := builtin.Dump2JSON(tCase, demoTestCaseWithPluginJSONPath.ToString())
|
||||
err := builtin.Dump2JSON(tCase, demoTestCaseWithPluginJSONPath.GetPath())
|
||||
if err != nil {
|
||||
t.Fail()
|
||||
}
|
||||
err = builtin.Dump2YAML(tCase, demoTestCaseWithPluginYAMLPath.ToString())
|
||||
err = builtin.Dump2YAML(tCase, demoTestCaseWithPluginYAMLPath.GetPath())
|
||||
if err != nil {
|
||||
t.Fail()
|
||||
}
|
||||
|
||||
tCase, _ = demoTestCaseWithoutPlugin.ToTCase()
|
||||
err = builtin.Dump2JSON(tCase, demoTestCaseWithoutPluginJSONPath.ToString())
|
||||
err = builtin.Dump2JSON(tCase, demoTestCaseWithoutPluginJSONPath.GetPath())
|
||||
if err != nil {
|
||||
t.Fail()
|
||||
}
|
||||
err = builtin.Dump2YAML(tCase, demoTestCaseWithoutPluginYAMLPath.ToString())
|
||||
if err != nil {
|
||||
t.Fail()
|
||||
}
|
||||
}
|
||||
|
||||
func TestJsonDemoWithPlugin(t *testing.T) {
|
||||
buildHashicorpGoPlugin()
|
||||
defer removeHashicorpGoPlugin()
|
||||
|
||||
err := NewRunner(nil).Run(&demoTestCaseWithPluginJSONPath) // hrp.Run(testCase)
|
||||
if err != nil {
|
||||
t.Fail()
|
||||
}
|
||||
}
|
||||
|
||||
func TestYamlDemoWithPlugin(t *testing.T) {
|
||||
buildHashicorpGoPlugin()
|
||||
defer removeHashicorpGoPlugin()
|
||||
|
||||
err := NewRunner(nil).Run(&demoTestCaseWithPluginYAMLPath) // hrp.Run(testCase)
|
||||
err = builtin.Dump2YAML(tCase, demoTestCaseWithoutPluginYAMLPath.GetPath())
|
||||
if err != nil {
|
||||
t.Fail()
|
||||
}
|
||||
@@ -195,11 +177,11 @@ func TestYamlDemoWithPlugin(t *testing.T) {
|
||||
func TestLoadCase(t *testing.T) {
|
||||
tcJSON := &TCase{}
|
||||
tcYAML := &TCase{}
|
||||
err := builtin.LoadFile(demoTestCaseWithPluginJSONPath.ToString(), tcJSON)
|
||||
err := builtin.LoadFile(demoTestCaseWithPluginJSONPath.GetPath(), tcJSON)
|
||||
if !assert.NoError(t, err) {
|
||||
t.Fail()
|
||||
}
|
||||
err = builtin.LoadFile(demoTestCaseWithPluginYAMLPath.ToString(), tcYAML)
|
||||
err = builtin.LoadFile(demoTestCaseWithPluginYAMLPath.GetPath(), tcYAML)
|
||||
if !assert.NoError(t, err) {
|
||||
t.Fail()
|
||||
}
|
||||
@@ -218,7 +200,7 @@ func TestLoadCase(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func Test_convertCheckExpr(t *testing.T) {
|
||||
func TestConvertCheckExpr(t *testing.T) {
|
||||
exprs := []struct {
|
||||
before string
|
||||
after string
|
||||
|
||||
@@ -108,16 +108,16 @@ func CreateFile(filePath string, data string) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// isFilePathExists returns true if path exists, whether path is file or dir
|
||||
func isPathExists(path string) bool {
|
||||
// IsPathExists returns true if path exists, whether path is file or dir
|
||||
func IsPathExists(path string) bool {
|
||||
if _, err := os.Stat(path); os.IsNotExist(err) {
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
// isFilePathExists returns true if path exists and path is file
|
||||
func isFilePathExists(path string) bool {
|
||||
// IsFilePathExists returns true if path exists and path is file
|
||||
func IsFilePathExists(path string) bool {
|
||||
info, err := os.Stat(path)
|
||||
if err != nil {
|
||||
// path not exists
|
||||
@@ -133,10 +133,10 @@ func isFilePathExists(path string) bool {
|
||||
}
|
||||
|
||||
func EnsureFolderExists(folderPath string) error {
|
||||
if !isPathExists(folderPath) {
|
||||
if !IsPathExists(folderPath) {
|
||||
err := CreateFolder(folderPath)
|
||||
return err
|
||||
} else if isFilePathExists(folderPath) {
|
||||
} else if IsFilePathExists(folderPath) {
|
||||
return fmt.Errorf("path %v should be directory", folderPath)
|
||||
}
|
||||
return nil
|
||||
|
||||
@@ -193,6 +193,11 @@ type API struct {
|
||||
Extract map[string]string `json:"extract,omitempty" yaml:"extract,omitempty"`
|
||||
Validators []interface{} `json:"validate,omitempty" yaml:"validate,omitempty"`
|
||||
Export []string `json:"export,omitempty" yaml:"export,omitempty"`
|
||||
Path string
|
||||
}
|
||||
|
||||
func (api *API) GetPath() string {
|
||||
return api.Path
|
||||
}
|
||||
|
||||
func (api *API) ToAPI() (*API, error) {
|
||||
@@ -210,6 +215,7 @@ type Validator struct {
|
||||
// IAPI represents interface for api,
|
||||
// includes API and APIPath.
|
||||
type IAPI interface {
|
||||
GetPath() string
|
||||
ToAPI() (*API, error)
|
||||
}
|
||||
|
||||
@@ -219,8 +225,8 @@ type TStep struct {
|
||||
Name string `json:"name" yaml:"name"` // required
|
||||
Request *Request `json:"request,omitempty" yaml:"request,omitempty"`
|
||||
APIPath string `json:"api,omitempty" yaml:"api,omitempty"`
|
||||
TestCasePath string `json:"testcase,omitempty" yaml:"testcase,omitempty"`
|
||||
APIContent IAPI `json:"api_content,omitempty" yaml:"api_content,omitempty"`
|
||||
TestCasePath string `json:"testcase,omitempty" yaml:"testcase,omitempty"`
|
||||
TestCaseContent ITestCase `json:"testcase_content,omitempty" yaml:"testcase_content,omitempty"`
|
||||
Transaction *Transaction `json:"transaction,omitempty" yaml:"transaction,omitempty"`
|
||||
Rendezvous *Rendezvous `json:"rendezvous,omitempty" yaml:"rendezvous,omitempty"`
|
||||
@@ -287,6 +293,10 @@ type TCase struct {
|
||||
TestSteps []*TStep `json:"teststeps" yaml:"teststeps"`
|
||||
}
|
||||
|
||||
func (tc *TCase) Path() string {
|
||||
return tc.Config.Path
|
||||
}
|
||||
|
||||
// IStep represents interface for all types for teststeps, includes:
|
||||
// StepRequest, StepRequestWithOptionalArgs, StepRequestValidation, StepRequestExtraction,
|
||||
// StepTestCaseWithOptionalArgs,
|
||||
@@ -300,6 +310,7 @@ type IStep interface {
|
||||
// ITestCase represents interface for testcases,
|
||||
// includes TestCase and TestCasePath.
|
||||
type ITestCase interface {
|
||||
GetPath() string
|
||||
ToTestCase() (*TestCase, error)
|
||||
ToTCase() (*TCase, error)
|
||||
}
|
||||
@@ -311,6 +322,10 @@ type TestCase struct {
|
||||
TestSteps []IStep
|
||||
}
|
||||
|
||||
func (tc *TestCase) GetPath() string {
|
||||
return tc.Config.Path
|
||||
}
|
||||
|
||||
func (tc *TestCase) ToTestCase() (*TestCase, error) {
|
||||
return tc, nil
|
||||
}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package hrp
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"sort"
|
||||
"testing"
|
||||
"time"
|
||||
@@ -742,7 +743,7 @@ func TestParseParameters(t *testing.T) {
|
||||
}{
|
||||
{
|
||||
map[string]interface{}{
|
||||
"username-password": "${parameterize(../examples/hrp/account.csv)}",
|
||||
"username-password": fmt.Sprintf("${parameterize(%s/account.csv)}", hrpExamplesDir),
|
||||
"user_agent": []interface{}{"IOS/10.1", "IOS/10.2"}},
|
||||
6,
|
||||
},
|
||||
@@ -782,17 +783,17 @@ func TestParseParametersError(t *testing.T) {
|
||||
}{
|
||||
{
|
||||
map[string]interface{}{
|
||||
"username_password": "${parameterize(../examples/hrp/account.csv)}",
|
||||
"username_password": fmt.Sprintf("${parameterize(%s/account.csv)}", hrpExamplesDir),
|
||||
"user_agent": []interface{}{"IOS/10.1", "IOS/10.2"}},
|
||||
},
|
||||
{
|
||||
map[string]interface{}{
|
||||
"username-password": "${parameterize(../examples/hrp/account.csv)}",
|
||||
"username-password": fmt.Sprintf("${parameterize(%s/account.csv)}", hrpExamplesDir),
|
||||
"user-agent": []interface{}{"IOS/10.1", "IOS/10.2"}},
|
||||
},
|
||||
{
|
||||
map[string]interface{}{
|
||||
"username-password": "${param(../examples/hrp/account.csv)}",
|
||||
"username-password": fmt.Sprintf("${param(%s/account.csv)}", hrpExamplesDir),
|
||||
"user_agent": []interface{}{"IOS/10.1", "IOS/10.2"}},
|
||||
},
|
||||
}
|
||||
|
||||
@@ -40,14 +40,14 @@ func removeHashicorpPyPlugin() {
|
||||
os.Remove(templatesDir + "debugtalk.py")
|
||||
}
|
||||
|
||||
func TestHttpRunnerWithGoPlugin(t *testing.T) {
|
||||
func TestRunCaseWithGoPlugin(t *testing.T) {
|
||||
buildHashicorpGoPlugin()
|
||||
defer removeHashicorpGoPlugin()
|
||||
|
||||
assertRunTestCases(t)
|
||||
}
|
||||
|
||||
func TestHttpRunnerWithPythonPlugin(t *testing.T) {
|
||||
func TestRunCaseWithPythonPlugin(t *testing.T) {
|
||||
buildHashicorpPyPlugin()
|
||||
defer removeHashicorpPyPlugin()
|
||||
|
||||
@@ -59,19 +59,19 @@ func assertRunTestCases(t *testing.T) {
|
||||
Config: NewConfig("TestCase1").
|
||||
SetBaseURL("http://httpbin.org"),
|
||||
TestSteps: []IStep{
|
||||
NewStep("headers").
|
||||
NewStep("testcase1-step1").
|
||||
GET("/headers").
|
||||
Validate().
|
||||
AssertEqual("status_code", 200, "check status code").
|
||||
AssertEqual("headers.\"Content-Type\"", "application/json", "check http response Content-Type"),
|
||||
NewStep("user-agent").
|
||||
NewStep("testcase1-step2").
|
||||
GET("/user-agent").
|
||||
Validate().
|
||||
AssertEqual("status_code", 200, "check status code").
|
||||
AssertEqual("headers.\"Content-Type\"", "application/json", "check http response Content-Type"),
|
||||
NewStep("TestCase3").CallRefCase(
|
||||
NewStep("testcase1-step3").CallRefCase(
|
||||
&TestCase{
|
||||
Config: NewConfig("TestCase3").SetBaseURL("http://httpbin.org"),
|
||||
Config: NewConfig("testcase1-step3-ref-case").SetBaseURL("http://httpbin.org"),
|
||||
TestSteps: []IStep{
|
||||
NewStep("ip").
|
||||
GET("/ip").
|
||||
@@ -81,32 +81,23 @@ func assertRunTestCases(t *testing.T) {
|
||||
},
|
||||
},
|
||||
),
|
||||
NewStep("TestCase4").CallRefCase(&demoRefAPIYAMLPath),
|
||||
NewStep("TestCase5").CallRefCase(&demoTestCaseWithPluginJSONPath),
|
||||
NewStep("testcase1-step4").CallRefCase(&demoTestCaseWithPluginJSONPath),
|
||||
},
|
||||
}
|
||||
testcase2 := &TestCase{
|
||||
Config: NewConfig("TestCase2").SetWeight(3),
|
||||
}
|
||||
testcase3 := &TestCase{
|
||||
Config: NewConfig("TestCase1").
|
||||
SetBaseURL("https://postman-echo.com"),
|
||||
TestSteps: []IStep{
|
||||
NewStep("TestCase5").CallRefAPI(&demoAPIYAMLPath),
|
||||
},
|
||||
}
|
||||
testcase4 := &demoRefTestCaseJSONPath
|
||||
|
||||
r := NewRunner(t)
|
||||
r.SetPluginLogOn()
|
||||
err := r.Run(testcase1, testcase2, testcase3, testcase4)
|
||||
err := r.Run(testcase1, testcase2)
|
||||
if err != nil {
|
||||
t.Fatalf("run testcase error: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestInitRendezvous(t *testing.T) {
|
||||
rendezvousBonudaryTestcase := &TestCase{
|
||||
func TestRunCaseWithRendezvous(t *testing.T) {
|
||||
rendezvousBoundaryTestcase := &TestCase{
|
||||
Config: NewConfig("run request with functions").
|
||||
SetBaseURL("https://postman-echo.com").
|
||||
WithVariables(map[string]interface{}{
|
||||
@@ -155,7 +146,7 @@ func TestInitRendezvous(t *testing.T) {
|
||||
{number: 100, percent: 1, timeout: 5000},
|
||||
}
|
||||
|
||||
rendezvousList := initRendezvous(rendezvousBonudaryTestcase, 100)
|
||||
rendezvousList := initRendezvous(rendezvousBoundaryTestcase, 100)
|
||||
|
||||
for i, r := range rendezvousList {
|
||||
if r.Number != expectedRendezvousParams[i].number {
|
||||
@@ -170,7 +161,7 @@ func TestInitRendezvous(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestThinkTime(t *testing.T) {
|
||||
func TestRunCaseWithThinkTime(t *testing.T) {
|
||||
buildHashicorpGoPlugin()
|
||||
defer removeHashicorpGoPlugin()
|
||||
|
||||
@@ -205,7 +196,8 @@ func TestThinkTime(t *testing.T) {
|
||||
{
|
||||
Config: NewConfig("TestCase5"),
|
||||
TestSteps: []IStep{
|
||||
NewStep("thinkTime").CallRefCase(&demoThinkTimeJsonPath), // think time: 3s, random pct: {"min_percentage":1, "max_percentage":1.5}, limit: 4s
|
||||
// think time: 3s, random pct: {"min_percentage":1, "max_percentage":1.5}, limit: 4s
|
||||
NewStep("thinkTime").CallRefCase(&demoTestCaseWithThinkTimePath),
|
||||
},
|
||||
},
|
||||
}
|
||||
@@ -247,3 +239,47 @@ func TestGenHTMLReport(t *testing.T) {
|
||||
t.Error(err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestRunCaseWithPluginJSON(t *testing.T) {
|
||||
buildHashicorpGoPlugin()
|
||||
defer removeHashicorpGoPlugin()
|
||||
|
||||
err := NewRunner(nil).Run(&demoTestCaseWithPluginJSONPath) // hrp.Run(testCase)
|
||||
if err != nil {
|
||||
t.Fail()
|
||||
}
|
||||
}
|
||||
|
||||
func TestRunCaseWithPluginYAML(t *testing.T) {
|
||||
buildHashicorpGoPlugin()
|
||||
defer removeHashicorpGoPlugin()
|
||||
|
||||
err := NewRunner(nil).Run(&demoTestCaseWithPluginYAMLPath) // hrp.Run(testCase)
|
||||
if err != nil {
|
||||
t.Fail()
|
||||
}
|
||||
}
|
||||
|
||||
func TestRunCaseWithRefAPI(t *testing.T) {
|
||||
buildHashicorpGoPlugin()
|
||||
defer removeHashicorpGoPlugin()
|
||||
|
||||
err := NewRunner(nil).Run(&demoTestCaseWithRefAPIPath)
|
||||
if err != nil {
|
||||
t.Fail()
|
||||
}
|
||||
|
||||
testcase := &TestCase{
|
||||
Config: NewConfig("TestCase").
|
||||
SetBaseURL("https://postman-echo.com"),
|
||||
TestSteps: []IStep{
|
||||
NewStep("run referenced api").CallRefAPI(&demoAPIGETPath),
|
||||
},
|
||||
}
|
||||
|
||||
r := NewRunner(t)
|
||||
err = r.Run(testcase)
|
||||
if err != nil {
|
||||
t.Fail()
|
||||
}
|
||||
}
|
||||
|
||||
21
hrp/step.go
21
hrp/step.go
@@ -1,6 +1,11 @@
|
||||
package hrp
|
||||
|
||||
import "fmt"
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
|
||||
"github.com/rs/zerolog/log"
|
||||
)
|
||||
|
||||
// NewConfig returns a new constructed testcase config with specified testcase name.
|
||||
func NewConfig(name string) *TConfig {
|
||||
@@ -163,7 +168,12 @@ func (s *StepRequest) PATCH(url string) *StepRequestWithOptionalArgs {
|
||||
|
||||
// CallRefCase calls a referenced testcase.
|
||||
func (s *StepRequest) CallRefCase(tc ITestCase) *StepTestCaseWithOptionalArgs {
|
||||
s.step.TestCaseContent, _ = tc.ToTestCase()
|
||||
var err error
|
||||
s.step.TestCaseContent, err = tc.ToTestCase()
|
||||
if err != nil {
|
||||
log.Error().Err(err).Msg("failed to load testcase")
|
||||
os.Exit(1)
|
||||
}
|
||||
return &StepTestCaseWithOptionalArgs{
|
||||
step: s.step,
|
||||
}
|
||||
@@ -171,7 +181,12 @@ func (s *StepRequest) CallRefCase(tc ITestCase) *StepTestCaseWithOptionalArgs {
|
||||
|
||||
// CallRefAPI calls a referenced api.
|
||||
func (s *StepRequest) CallRefAPI(api IAPI) *StepAPIWithOptionalArgs {
|
||||
s.step.APIContent, _ = api.ToAPI()
|
||||
var err error
|
||||
s.step.APIContent, err = api.ToAPI()
|
||||
if err != nil {
|
||||
log.Error().Err(err).Msg("failed to load api")
|
||||
os.Exit(1)
|
||||
}
|
||||
return &StepAPIWithOptionalArgs{
|
||||
step: s.step,
|
||||
}
|
||||
|
||||
@@ -1,25 +0,0 @@
|
||||
package tests
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/httprunner/httprunner/hrp"
|
||||
)
|
||||
|
||||
// generated by examples/data/har/demo.har using HttpRunner v3.1.6
|
||||
var (
|
||||
demoHttpRunnerJSONPath hrp.TestCasePath = "../../examples/hrp/demo_httprunner.json"
|
||||
demoHttpRunnerYAMLPath hrp.TestCasePath = "../../examples/hrp/demo_httprunner.yaml"
|
||||
)
|
||||
|
||||
func TestCompatTestCase(t *testing.T) {
|
||||
err := hrp.NewRunner(t).Run(&demoHttpRunnerJSONPath)
|
||||
if err != nil {
|
||||
t.Fatalf("run testcase error: %v", err)
|
||||
}
|
||||
|
||||
err = hrp.NewRunner(t).Run(&demoHttpRunnerYAMLPath)
|
||||
if err != nil {
|
||||
t.Fatalf("run testcase error: %v", err)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user