mirror of
https://github.com/httprunner/httprunner.git
synced 2026-08-28 19:47:14 +08:00
change: add exit code
This commit is contained in:
+5
-4
@@ -14,6 +14,7 @@ import (
|
|||||||
"golang.org/x/net/context"
|
"golang.org/x/net/context"
|
||||||
|
|
||||||
"github.com/httprunner/httprunner/v4/hrp/internal/builtin"
|
"github.com/httprunner/httprunner/v4/hrp/internal/builtin"
|
||||||
|
"github.com/httprunner/httprunner/v4/hrp/internal/code"
|
||||||
"github.com/httprunner/httprunner/v4/hrp/internal/json"
|
"github.com/httprunner/httprunner/v4/hrp/internal/json"
|
||||||
"github.com/httprunner/httprunner/v4/hrp/internal/sdk"
|
"github.com/httprunner/httprunner/v4/hrp/internal/sdk"
|
||||||
"github.com/httprunner/httprunner/v4/hrp/pkg/boomer"
|
"github.com/httprunner/httprunner/v4/hrp/pkg/boomer"
|
||||||
@@ -121,7 +122,7 @@ func (b *HRPBoomer) ConvertTestCasesToBoomerTasks(testcases ...ITestCase) (taskS
|
|||||||
testCases, err := LoadTestCases(testcases...)
|
testCases, err := LoadTestCases(testcases...)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Error().Err(err).Msg("failed to load testcases")
|
log.Error().Err(err).Msg("failed to load testcases")
|
||||||
os.Exit(1)
|
os.Exit(code.GetErrorCode(err))
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, testcase := range testCases {
|
for _, testcase := range testCases {
|
||||||
@@ -139,7 +140,7 @@ func (b *HRPBoomer) ParseTestCases(testCases []*TestCase) []*TCase {
|
|||||||
caseRunner, err := b.hrpRunner.NewCaseRunner(tc)
|
caseRunner, err := b.hrpRunner.NewCaseRunner(tc)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Error().Err(err).Msg("failed to create runner")
|
log.Error().Err(err).Msg("failed to create runner")
|
||||||
os.Exit(1)
|
os.Exit(code.GetErrorCode(err))
|
||||||
}
|
}
|
||||||
caseRunner.parsedConfig.Parameters = caseRunner.parametersIterator.outParameters()
|
caseRunner.parsedConfig.Parameters = caseRunner.parametersIterator.outParameters()
|
||||||
parsedTestCases = append(parsedTestCases, &TCase{
|
parsedTestCases = append(parsedTestCases, &TCase{
|
||||||
@@ -155,7 +156,7 @@ func (b *HRPBoomer) TestCasesToBytes(testcases ...ITestCase) []byte {
|
|||||||
testCases, err := LoadTestCases(testcases...)
|
testCases, err := LoadTestCases(testcases...)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Error().Err(err).Msg("failed to load testcases")
|
log.Error().Err(err).Msg("failed to load testcases")
|
||||||
os.Exit(1)
|
os.Exit(code.GetErrorCode(err))
|
||||||
}
|
}
|
||||||
tcs := b.ParseTestCases(testCases)
|
tcs := b.ParseTestCases(testCases)
|
||||||
testCasesBytes, err := json.Marshal(tcs)
|
testCasesBytes, err := json.Marshal(tcs)
|
||||||
@@ -318,7 +319,7 @@ func (b *HRPBoomer) convertBoomerTask(testcase *TestCase, rendezvousList []*Rend
|
|||||||
caseRunner, err := b.hrpRunner.NewCaseRunner(testcase)
|
caseRunner, err := b.hrpRunner.NewCaseRunner(testcase)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Error().Err(err).Msg("failed to create runner")
|
log.Error().Err(err).Msg("failed to create runner")
|
||||||
os.Exit(1)
|
os.Exit(code.GetErrorCode(err))
|
||||||
}
|
}
|
||||||
if caseRunner.parser.plugin != nil {
|
if caseRunner.parser.plugin != nil {
|
||||||
b.pluginsMutex.Lock()
|
b.pluginsMutex.Lock()
|
||||||
|
|||||||
+20
-9
@@ -15,6 +15,7 @@ import (
|
|||||||
"github.com/rs/zerolog/log"
|
"github.com/rs/zerolog/log"
|
||||||
|
|
||||||
"github.com/httprunner/httprunner/v4/hrp/internal/builtin"
|
"github.com/httprunner/httprunner/v4/hrp/internal/builtin"
|
||||||
|
"github.com/httprunner/httprunner/v4/hrp/internal/code"
|
||||||
"github.com/httprunner/httprunner/v4/hrp/internal/myexec"
|
"github.com/httprunner/httprunner/v4/hrp/internal/myexec"
|
||||||
"github.com/httprunner/httprunner/v4/hrp/internal/version"
|
"github.com/httprunner/httprunner/v4/hrp/internal/version"
|
||||||
)
|
)
|
||||||
@@ -175,11 +176,11 @@ func buildGo(path string, output string) error {
|
|||||||
content, err := os.ReadFile(path)
|
content, err := os.ReadFile(path)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Error().Err(err).Msg("failed to read file")
|
log.Error().Err(err).Msg("failed to read file")
|
||||||
return errors.Wrap(err, "read file failed")
|
return errors.Wrap(code.LoadFileError, err.Error())
|
||||||
}
|
}
|
||||||
functionNames, err := regexGoFunctionName.findAllFunctionNames(string(content))
|
functionNames, err := regexGoFunctionName.findAllFunctionNames(string(content))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return errors.Wrap(code.InvalidPluginFile, err.Error())
|
||||||
}
|
}
|
||||||
|
|
||||||
templateContent := &pluginTemplate{
|
templateContent := &pluginTemplate{
|
||||||
@@ -187,7 +188,11 @@ func buildGo(path string, output string) error {
|
|||||||
Version: version.VERSION,
|
Version: version.VERSION,
|
||||||
FunctionNames: functionNames,
|
FunctionNames: functionNames,
|
||||||
}
|
}
|
||||||
return templateContent.generateGo(output)
|
err = templateContent.generateGo(output)
|
||||||
|
if err != nil {
|
||||||
|
return errors.Wrap(code.BuildGoPluginFailed, err.Error())
|
||||||
|
}
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// buildPy completes funppy information in debugtalk.py
|
// buildPy completes funppy information in debugtalk.py
|
||||||
@@ -196,17 +201,18 @@ func buildPy(path string, output string) error {
|
|||||||
// check the syntax of debugtalk.py
|
// check the syntax of debugtalk.py
|
||||||
err := myexec.ExecPython3Command("py_compile", path)
|
err := myexec.ExecPython3Command("py_compile", path)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return errors.Wrap(err, "python plugin syntax invalid")
|
return errors.Wrap(code.InvalidPluginFile,
|
||||||
|
fmt.Sprintf("python plugin syntax invalid: %s", err.Error()))
|
||||||
}
|
}
|
||||||
|
|
||||||
content, err := os.ReadFile(path)
|
content, err := os.ReadFile(path)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Error().Err(err).Msg("failed to read file")
|
log.Error().Err(err).Msg("failed to read file")
|
||||||
return errors.Wrap(err, "read file failed")
|
return errors.Wrap(code.LoadFileError, err.Error())
|
||||||
}
|
}
|
||||||
functionNames, err := regexPyFunctionName.findAllFunctionNames(string(content))
|
functionNames, err := regexPyFunctionName.findAllFunctionNames(string(content))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return errors.Wrap(code.InvalidPluginFile, err.Error())
|
||||||
}
|
}
|
||||||
|
|
||||||
templateContent := &pluginTemplate{
|
templateContent := &pluginTemplate{
|
||||||
@@ -214,7 +220,11 @@ func buildPy(path string, output string) error {
|
|||||||
Version: version.VERSION,
|
Version: version.VERSION,
|
||||||
FunctionNames: functionNames,
|
FunctionNames: functionNames,
|
||||||
}
|
}
|
||||||
return templateContent.generatePy(output)
|
err = templateContent.generatePy(output)
|
||||||
|
if err != nil {
|
||||||
|
return errors.Wrap(code.BuildPyPluginFailed, err.Error())
|
||||||
|
}
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func BuildPlugin(path string, output string) (err error) {
|
func BuildPlugin(path string, output string) (err error) {
|
||||||
@@ -225,11 +235,12 @@ func BuildPlugin(path string, output string) (err error) {
|
|||||||
case ".go":
|
case ".go":
|
||||||
err = buildGo(path, output)
|
err = buildGo(path, output)
|
||||||
default:
|
default:
|
||||||
return errors.New("type error, expected .py or .go")
|
return errors.Wrap(code.UnsupportedFileExtension,
|
||||||
|
"type error, expected .py or .go")
|
||||||
}
|
}
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Error().Err(err).Str("path", path).Msg("build plugin failed")
|
log.Error().Err(err).Str("path", path).Msg("build plugin failed")
|
||||||
os.Exit(1)
|
return err
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|||||||
+6
-6
@@ -1,7 +1,6 @@
|
|||||||
package cmd
|
package cmd
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"os"
|
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
@@ -30,7 +29,7 @@ var boomCmd = &cobra.Command{
|
|||||||
}
|
}
|
||||||
setLogLevel(logLevel)
|
setLogLevel(logLevel)
|
||||||
},
|
},
|
||||||
Run: func(cmd *cobra.Command, args []string) {
|
RunE: func(cmd *cobra.Command, args []string) error {
|
||||||
var paths []hrp.ITestCase
|
var paths []hrp.ITestCase
|
||||||
for _, arg := range args {
|
for _, arg := range args {
|
||||||
path := hrp.TestCasePath(arg)
|
path := hrp.TestCasePath(arg)
|
||||||
@@ -42,7 +41,7 @@ var boomCmd = &cobra.Command{
|
|||||||
err := builtin.LoadFile(boomArgs.profile, &boomArgs.Profile)
|
err := builtin.LoadFile(boomArgs.profile, &boomArgs.Profile)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Error().Err(err).Msg("failed to load profile")
|
log.Error().Err(err).Msg("failed to load profile")
|
||||||
os.Exit(1)
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -89,6 +88,7 @@ var boomCmd = &cobra.Command{
|
|||||||
hrpBoomer.InitBoomer()
|
hrpBoomer.InitBoomer()
|
||||||
hrpBoomer.Run(paths...)
|
hrpBoomer.Run(paths...)
|
||||||
}
|
}
|
||||||
|
return nil
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -141,13 +141,13 @@ func init() {
|
|||||||
boomCmd.Flags().IntVar(&boomArgs.expectWorkersMaxWait, "expect-workers-max-wait", 120, "How many workers master should expect to connect before starting the test (only when --autostart is used")
|
boomCmd.Flags().IntVar(&boomArgs.expectWorkersMaxWait, "expect-workers-max-wait", 120, "How many workers master should expect to connect before starting the test (only when --autostart is used")
|
||||||
}
|
}
|
||||||
|
|
||||||
func makeHRPBoomer() *hrp.HRPBoomer {
|
func makeHRPBoomer() (*hrp.HRPBoomer, error) {
|
||||||
// if set profile, the priority is higher than the other commands
|
// if set profile, the priority is higher than the other commands
|
||||||
if boomArgs.profile != "" {
|
if boomArgs.profile != "" {
|
||||||
err := builtin.LoadFile(boomArgs.profile, &boomArgs)
|
err := builtin.LoadFile(boomArgs.profile, &boomArgs)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Error().Err(err).Msg("failed to load profile")
|
log.Error().Err(err).Msg("failed to load profile")
|
||||||
os.Exit(1)
|
return nil, err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
hrpBoomer := hrp.NewStandaloneBoomer(boomArgs.SpawnCount, boomArgs.SpawnRate)
|
hrpBoomer := hrp.NewStandaloneBoomer(boomArgs.SpawnCount, boomArgs.SpawnRate)
|
||||||
@@ -157,5 +157,5 @@ func makeHRPBoomer() *hrp.HRPBoomer {
|
|||||||
hrpBoomer.SetProfile(&boomArgs.Profile)
|
hrpBoomer.SetProfile(&boomArgs.Profile)
|
||||||
hrpBoomer.EnableGracefulQuit(context.Background())
|
hrpBoomer.EnableGracefulQuit(context.Background())
|
||||||
hrpBoomer.InitBoomer()
|
hrpBoomer.InitBoomer()
|
||||||
return hrpBoomer
|
return hrpBoomer, nil
|
||||||
}
|
}
|
||||||
|
|||||||
+8
-6
@@ -21,11 +21,9 @@ var runCurlCmd = &cobra.Command{
|
|||||||
PreRun: func(cmd *cobra.Command, args []string) {
|
PreRun: func(cmd *cobra.Command, args []string) {
|
||||||
setLogLevel(logLevel)
|
setLogLevel(logLevel)
|
||||||
},
|
},
|
||||||
Run: func(cmd *cobra.Command, args []string) {
|
RunE: func(cmd *cobra.Command, args []string) error {
|
||||||
runner := makeHRPRunner()
|
runner := makeHRPRunner()
|
||||||
if runner.Run(makeCurlTestCase(args)) != nil {
|
return runner.Run(makeCurlTestCase(args))
|
||||||
os.Exit(1)
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -41,9 +39,13 @@ var boomCurlCmd = &cobra.Command{
|
|||||||
}
|
}
|
||||||
setLogLevel(logLevel)
|
setLogLevel(logLevel)
|
||||||
},
|
},
|
||||||
Run: func(cmd *cobra.Command, args []string) {
|
RunE: func(cmd *cobra.Command, args []string) error {
|
||||||
boomer := makeHRPBoomer()
|
boomer, err := makeHRPBoomer()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
boomer.Run(makeCurlTestCase(args))
|
boomer.Run(makeCurlTestCase(args))
|
||||||
|
return nil
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+1
-2
@@ -2,7 +2,6 @@ package cmd
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"errors"
|
"errors"
|
||||||
"os"
|
|
||||||
|
|
||||||
"github.com/rs/zerolog/log"
|
"github.com/rs/zerolog/log"
|
||||||
"github.com/spf13/cobra"
|
"github.com/spf13/cobra"
|
||||||
@@ -37,7 +36,7 @@ var scaffoldCmd = &cobra.Command{
|
|||||||
err := scaffold.CreateScaffold(args[0], pluginType, venv, force)
|
err := scaffold.CreateScaffold(args[0], pluginType, venv, force)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Error().Err(err).Msg("create scaffold project failed")
|
log.Error().Err(err).Msg("create scaffold project failed")
|
||||||
os.Exit(1)
|
return err
|
||||||
}
|
}
|
||||||
log.Info().Str("projectName", args[0]).Msg("create scaffold success")
|
log.Info().Str("projectName", args[0]).Msg("create scaffold success")
|
||||||
return nil
|
return nil
|
||||||
|
|||||||
@@ -22,6 +22,7 @@ import (
|
|||||||
"github.com/rs/zerolog/log"
|
"github.com/rs/zerolog/log"
|
||||||
"gopkg.in/yaml.v3"
|
"gopkg.in/yaml.v3"
|
||||||
|
|
||||||
|
"github.com/httprunner/httprunner/v4/hrp/internal/code"
|
||||||
"github.com/httprunner/httprunner/v4/hrp/internal/json"
|
"github.com/httprunner/httprunner/v4/hrp/internal/json"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -235,8 +236,6 @@ func InterfaceType(raw interface{}) string {
|
|||||||
return reflect.TypeOf(raw).String()
|
return reflect.TypeOf(raw).String()
|
||||||
}
|
}
|
||||||
|
|
||||||
var ErrUnsupportedFileExt = fmt.Errorf("unsupported file extension")
|
|
||||||
|
|
||||||
// LoadFile loads file content with file extension and assigns to structObj
|
// LoadFile loads file content with file extension and assigns to structObj
|
||||||
func LoadFile(path string, structObj interface{}) (err error) {
|
func LoadFile(path string, structObj interface{}) (err error) {
|
||||||
log.Info().Str("path", path).Msg("load file")
|
log.Info().Str("path", path).Msg("load file")
|
||||||
@@ -252,12 +251,15 @@ func LoadFile(path string, structObj interface{}) (err error) {
|
|||||||
decoder := json.NewDecoder(bytes.NewReader(file))
|
decoder := json.NewDecoder(bytes.NewReader(file))
|
||||||
decoder.UseNumber()
|
decoder.UseNumber()
|
||||||
err = decoder.Decode(structObj)
|
err = decoder.Decode(structObj)
|
||||||
|
err = errors.Wrap(code.LoadJSONError, err.Error())
|
||||||
case ".yaml", ".yml":
|
case ".yaml", ".yml":
|
||||||
err = yaml.Unmarshal(file, structObj)
|
err = yaml.Unmarshal(file, structObj)
|
||||||
|
err = errors.Wrap(code.LoadYAMLError, err.Error())
|
||||||
case ".env":
|
case ".env":
|
||||||
err = parseEnvContent(file, structObj)
|
err = parseEnvContent(file, structObj)
|
||||||
|
err = errors.Wrap(code.LoadEnvError, err.Error())
|
||||||
default:
|
default:
|
||||||
err = ErrUnsupportedFileExt
|
err = code.UnsupportedFileExtension
|
||||||
}
|
}
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@@ -297,14 +299,14 @@ func loadFromCSV(path string) []map[string]interface{} {
|
|||||||
file, err := ReadFile(path)
|
file, err := ReadFile(path)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Error().Err(err).Msg("read csv file failed")
|
log.Error().Err(err).Msg("read csv file failed")
|
||||||
os.Exit(1)
|
os.Exit(code.GetErrorCode(err))
|
||||||
}
|
}
|
||||||
|
|
||||||
r := csv.NewReader(strings.NewReader(string(file)))
|
r := csv.NewReader(strings.NewReader(string(file)))
|
||||||
content, err := r.ReadAll()
|
content, err := r.ReadAll()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Error().Err(err).Msg("parse csv file failed")
|
log.Error().Err(err).Msg("parse csv file failed")
|
||||||
os.Exit(1)
|
os.Exit(code.GetErrorCode(err))
|
||||||
}
|
}
|
||||||
firstLine := content[0] // parameter names
|
firstLine := content[0] // parameter names
|
||||||
var result []map[string]interface{}
|
var result []map[string]interface{}
|
||||||
@@ -323,7 +325,7 @@ func loadMessage(path string) []byte {
|
|||||||
file, err := ReadFile(path)
|
file, err := ReadFile(path)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Error().Err(err).Msg("read message file failed")
|
log.Error().Err(err).Msg("read message file failed")
|
||||||
os.Exit(1)
|
os.Exit(code.GetErrorCode(err))
|
||||||
}
|
}
|
||||||
return file
|
return file
|
||||||
}
|
}
|
||||||
@@ -333,13 +335,13 @@ func ReadFile(path string) ([]byte, error) {
|
|||||||
path, err = filepath.Abs(path)
|
path, err = filepath.Abs(path)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Error().Err(err).Str("path", path).Msg("convert absolute path failed")
|
log.Error().Err(err).Str("path", path).Msg("convert absolute path failed")
|
||||||
return nil, err
|
return nil, errors.Wrap(code.LoadFileError, err.Error())
|
||||||
}
|
}
|
||||||
|
|
||||||
file, err := os.ReadFile(path)
|
file, err := os.ReadFile(path)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Error().Err(err).Msg("read file failed")
|
log.Error().Err(err).Msg("read file failed")
|
||||||
return nil, err
|
return nil, errors.Wrap(code.LoadFileError, err.Error())
|
||||||
}
|
}
|
||||||
return file, nil
|
return file, nil
|
||||||
}
|
}
|
||||||
|
|||||||
+43
-13
@@ -12,24 +12,40 @@ const (
|
|||||||
)
|
)
|
||||||
|
|
||||||
// environment: [2, 10)
|
// environment: [2, 10)
|
||||||
|
var (
|
||||||
|
InvalidPython3Venv = errors.New("prepare python3 venv failed") // 9
|
||||||
|
)
|
||||||
|
|
||||||
// loader: [10, 20)
|
// loader: [10, 20)
|
||||||
var (
|
var (
|
||||||
LoadError = errors.New("load error") // 10
|
LoadFileError = errors.New("load file error") // 10
|
||||||
LoadJSONError = errors.New("load json error") // 11
|
LoadJSONError = errors.New("load json error") // 11
|
||||||
LoadYAMLError = errors.New("load yaml error") // 12
|
LoadYAMLError = errors.New("load yaml error") // 12
|
||||||
|
LoadEnvError = errors.New("load .env error") // 13
|
||||||
|
LoadCSVError = errors.New("load csv error") // 14
|
||||||
|
InvalidCaseFormat = errors.New("invalid case format") // 15
|
||||||
|
UnsupportedFileExtension = errors.New("unsupported file extension") // 16
|
||||||
|
ReferencedFileNotFound = errors.New("referenced file not found") // 17
|
||||||
|
InvalidPluginFile = errors.New("invalid plugin file") // 18
|
||||||
)
|
)
|
||||||
|
|
||||||
// parser: [20, 30)
|
// parser: [20, 30)
|
||||||
var (
|
var (
|
||||||
ParseError = errors.New("parse error") // 20
|
ParseError = errors.New("parse error") // 20
|
||||||
ParseStringError = errors.New("parse string failed") // 21
|
VariableNotFound = errors.New("variable not found") // 21
|
||||||
ParseVariablesError = errors.New("parse variables failed") // 22
|
ParseFunctionError = errors.New("parse function failed") // 22
|
||||||
ParseConfigError = errors.New("parse config error") // 25
|
CallFunctionError = errors.New("call function failed") // 23
|
||||||
|
ParseVariablesError = errors.New("parse variables failed") // 24
|
||||||
)
|
)
|
||||||
|
|
||||||
// runner: [30, 40)
|
// runner: [30, 40)
|
||||||
|
|
||||||
|
var (
|
||||||
|
InitPluginFailed = errors.New("init plugin failed") // 31
|
||||||
|
BuildGoPluginFailed = errors.New("build go plugin failed") // 32
|
||||||
|
BuildPyPluginFailed = errors.New("build py plugin failed") // 33
|
||||||
|
)
|
||||||
|
|
||||||
// summary: [40, 50)
|
// summary: [40, 50)
|
||||||
|
|
||||||
// ios device related: [50, 60)
|
// ios device related: [50, 60)
|
||||||
@@ -67,16 +83,31 @@ var (
|
|||||||
// CV related: [90, 100)
|
// CV related: [90, 100)
|
||||||
|
|
||||||
var errorsMap = map[error]int{
|
var errorsMap = map[error]int{
|
||||||
|
// environment
|
||||||
|
InvalidPython3Venv: 9,
|
||||||
|
|
||||||
// loader
|
// loader
|
||||||
LoadError: 10,
|
LoadFileError: 10,
|
||||||
LoadJSONError: 11,
|
LoadJSONError: 11,
|
||||||
LoadYAMLError: 12,
|
LoadYAMLError: 12,
|
||||||
|
LoadEnvError: 13,
|
||||||
|
LoadCSVError: 14,
|
||||||
|
InvalidCaseFormat: 15,
|
||||||
|
UnsupportedFileExtension: 16,
|
||||||
|
ReferencedFileNotFound: 17,
|
||||||
|
InvalidPluginFile: 18,
|
||||||
|
|
||||||
// parser
|
// parser
|
||||||
ParseError: 20,
|
ParseError: 20,
|
||||||
ParseStringError: 21,
|
VariableNotFound: 21,
|
||||||
ParseVariablesError: 22,
|
ParseFunctionError: 22,
|
||||||
ParseConfigError: 25,
|
CallFunctionError: 23,
|
||||||
|
ParseVariablesError: 24,
|
||||||
|
|
||||||
|
// runner
|
||||||
|
InitPluginFailed: 31,
|
||||||
|
BuildGoPluginFailed: 32,
|
||||||
|
BuildPyPluginFailed: 33,
|
||||||
|
|
||||||
// ios related
|
// ios related
|
||||||
IOSDeviceConnectionError: 50,
|
IOSDeviceConnectionError: 50,
|
||||||
@@ -105,7 +136,6 @@ var errorsMap = map[error]int{
|
|||||||
|
|
||||||
func GetErrorCode(err error) (exitCode int) {
|
func GetErrorCode(err error) (exitCode int) {
|
||||||
if err == nil {
|
if err == nil {
|
||||||
log.Info().Int("code", Success).Msg("hrp exit")
|
|
||||||
return Success
|
return Success
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -10,6 +10,7 @@ import (
|
|||||||
"github.com/pkg/errors"
|
"github.com/pkg/errors"
|
||||||
"github.com/rs/zerolog/log"
|
"github.com/rs/zerolog/log"
|
||||||
|
|
||||||
|
"github.com/httprunner/httprunner/v4/hrp/internal/code"
|
||||||
"github.com/httprunner/httprunner/v4/hrp/internal/env"
|
"github.com/httprunner/httprunner/v4/hrp/internal/env"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -39,7 +40,7 @@ func EnsurePython3Venv(venv string, packages ...string) (python3 string, err err
|
|||||||
}
|
}
|
||||||
python3, err = ensurePython3Venv(venv, packages...)
|
python3, err = ensurePython3Venv(venv, packages...)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", errors.Wrap(err, "prepare python3 venv failed")
|
return "", errors.Wrap(code.InvalidPython3Venv, err.Error())
|
||||||
}
|
}
|
||||||
python3Executable = python3
|
python3Executable = python3
|
||||||
log.Info().Str("Python3Executable", python3Executable).Msg("set python3 executable path")
|
log.Info().Str("Python3Executable", python3Executable).Msg("set python3 executable path")
|
||||||
|
|||||||
+1
-1
@@ -54,7 +54,7 @@ func LoadTestCases(iTestCases ...ITestCase) ([]*TestCase, error) {
|
|||||||
tc, err := testCasePath.ToTestCase()
|
tc, err := testCasePath.ToTestCase()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Warn().Err(err).Str("path", path).Msg("load testcase failed")
|
log.Warn().Err(err).Str("path", path).Msg("load testcase failed")
|
||||||
return nil
|
return err
|
||||||
}
|
}
|
||||||
testCases = append(testCases, tc)
|
testCases = append(testCases, tc)
|
||||||
return nil
|
return nil
|
||||||
|
|||||||
+12
-7
@@ -125,14 +125,19 @@ func (p *Parser) Parse(raw interface{}, variablesMapping map[string]interface{})
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func parseJSONNumber(raw builtinJSON.Number) (interface{}, error) {
|
func parseJSONNumber(raw builtinJSON.Number) (value interface{}, err error) {
|
||||||
if strings.Contains(raw.String(), ".") {
|
if strings.Contains(raw.String(), ".") {
|
||||||
// float64
|
// float64
|
||||||
return raw.Float64()
|
value, err = raw.Float64()
|
||||||
} else {
|
} else {
|
||||||
// int64
|
// int64
|
||||||
return raw.Int64()
|
value, err = raw.Int64()
|
||||||
}
|
}
|
||||||
|
if err != nil {
|
||||||
|
return nil, errors.Wrap(code.ParseError,
|
||||||
|
fmt.Sprintf("parse json number failed: %v", err))
|
||||||
|
}
|
||||||
|
return value, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
const (
|
const (
|
||||||
@@ -185,18 +190,18 @@ func (p *Parser) ParseString(raw string, variablesMapping map[string]interface{}
|
|||||||
argsStr := funcMatched[2]
|
argsStr := funcMatched[2]
|
||||||
arguments, err := parseFunctionArguments(argsStr)
|
arguments, err := parseFunctionArguments(argsStr)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return raw, errors.Wrap(code.ParseStringError, err.Error())
|
return raw, errors.Wrap(code.ParseFunctionError, err.Error())
|
||||||
}
|
}
|
||||||
parsedArgs, err := p.Parse(arguments, variablesMapping)
|
parsedArgs, err := p.Parse(arguments, variablesMapping)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return raw, errors.Wrap(code.ParseStringError, err.Error())
|
return raw, err
|
||||||
}
|
}
|
||||||
|
|
||||||
result, err := p.callFunc(funcName, parsedArgs.([]interface{})...)
|
result, err := p.callFunc(funcName, parsedArgs.([]interface{})...)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Error().Str("funcName", funcName).Interface("arguments", arguments).
|
log.Error().Str("funcName", funcName).Interface("arguments", arguments).
|
||||||
Err(err).Msg("call function failed")
|
Err(err).Msg("call function failed")
|
||||||
return raw, errors.Wrap(code.ParseStringError, err.Error())
|
return raw, errors.Wrap(code.CallFunctionError, err.Error())
|
||||||
}
|
}
|
||||||
log.Info().Str("funcName", funcName).Interface("arguments", arguments).
|
log.Info().Str("funcName", funcName).Interface("arguments", arguments).
|
||||||
Interface("output", result).Msg("call function success")
|
Interface("output", result).Msg("call function success")
|
||||||
@@ -228,7 +233,7 @@ func (p *Parser) ParseString(raw string, variablesMapping map[string]interface{}
|
|||||||
}
|
}
|
||||||
varValue, ok := variablesMapping[varName]
|
varValue, ok := variablesMapping[varName]
|
||||||
if !ok {
|
if !ok {
|
||||||
return raw, errors.Wrap(code.ParseStringError,
|
return raw, errors.Wrap(code.VariableNotFound,
|
||||||
fmt.Sprintf("variable %s not found", varName))
|
fmt.Sprintf("variable %s not found", varName))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+4
-1
@@ -9,8 +9,10 @@ import (
|
|||||||
|
|
||||||
"github.com/httprunner/funplugin"
|
"github.com/httprunner/funplugin"
|
||||||
"github.com/httprunner/funplugin/fungo"
|
"github.com/httprunner/funplugin/fungo"
|
||||||
|
"github.com/pkg/errors"
|
||||||
"github.com/rs/zerolog/log"
|
"github.com/rs/zerolog/log"
|
||||||
|
|
||||||
|
"github.com/httprunner/httprunner/v4/hrp/internal/code"
|
||||||
"github.com/httprunner/httprunner/v4/hrp/internal/myexec"
|
"github.com/httprunner/httprunner/v4/hrp/internal/myexec"
|
||||||
"github.com/httprunner/httprunner/v4/hrp/internal/sdk"
|
"github.com/httprunner/httprunner/v4/hrp/internal/sdk"
|
||||||
)
|
)
|
||||||
@@ -52,7 +54,7 @@ func initPlugin(path, venv string, logOn bool) (plugin funplugin.IPlugin, err er
|
|||||||
err = BuildPlugin(pluginPath, genPyPluginPath)
|
err = BuildPlugin(pluginPath, genPyPluginPath)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Error().Err(err).Str("path", pluginPath).Msg("build plugin failed")
|
log.Error().Err(err).Str("path", pluginPath).Msg("build plugin failed")
|
||||||
return nil, nil
|
return nil, err
|
||||||
}
|
}
|
||||||
pluginPath = genPyPluginPath
|
pluginPath = genPyPluginPath
|
||||||
|
|
||||||
@@ -73,6 +75,7 @@ func initPlugin(path, venv string, logOn bool) (plugin funplugin.IPlugin, err er
|
|||||||
plugin, err = funplugin.Init(pluginPath, pluginOptions...)
|
plugin, err = funplugin.Init(pluginPath, pluginOptions...)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Error().Err(err).Msgf("init plugin failed: %s", pluginPath)
|
log.Error().Err(err).Msgf("init plugin failed: %s", pluginPath)
|
||||||
|
err = errors.Wrap(code.InitPluginFailed, err.Error())
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+3
-2
@@ -7,6 +7,7 @@ import (
|
|||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"github.com/httprunner/httprunner/v4/hrp/internal/code"
|
||||||
"github.com/rs/zerolog/log"
|
"github.com/rs/zerolog/log"
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
)
|
)
|
||||||
@@ -16,7 +17,7 @@ func buildHashicorpGoPlugin() {
|
|||||||
err := BuildPlugin(tmpl("plugin/debugtalk.go"), tmpl("debugtalk.bin"))
|
err := BuildPlugin(tmpl("plugin/debugtalk.go"), tmpl("debugtalk.bin"))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Error().Err(err).Msg("build hashicorp go plugin failed")
|
log.Error().Err(err).Msg("build hashicorp go plugin failed")
|
||||||
os.Exit(1)
|
os.Exit(code.GetErrorCode(err))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -33,7 +34,7 @@ func buildHashicorpPyPlugin() {
|
|||||||
err := ioutil.WriteFile(tmpl("debugtalk.py"), src, 0o644)
|
err := ioutil.WriteFile(tmpl("debugtalk.py"), src, 0o644)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Error().Err(err).Msg("copy hashicorp python plugin failed")
|
log.Error().Err(err).Msg("copy hashicorp python plugin failed")
|
||||||
os.Exit(1)
|
os.Exit(code.GetErrorCode(err))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+3
-2
@@ -21,6 +21,7 @@ import (
|
|||||||
"github.com/rs/zerolog/log"
|
"github.com/rs/zerolog/log"
|
||||||
|
|
||||||
"github.com/httprunner/httprunner/v4/hrp/internal/builtin"
|
"github.com/httprunner/httprunner/v4/hrp/internal/builtin"
|
||||||
|
"github.com/httprunner/httprunner/v4/hrp/internal/code"
|
||||||
"github.com/httprunner/httprunner/v4/hrp/internal/json"
|
"github.com/httprunner/httprunner/v4/hrp/internal/json"
|
||||||
"github.com/httprunner/httprunner/v4/hrp/pkg/httpstat"
|
"github.com/httprunner/httprunner/v4/hrp/pkg/httpstat"
|
||||||
)
|
)
|
||||||
@@ -683,7 +684,7 @@ func (s *StepRequest) CallRefCase(tc ITestCase) *StepTestCaseWithOptionalArgs {
|
|||||||
s.step.TestCase, err = tc.ToTestCase()
|
s.step.TestCase, err = tc.ToTestCase()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Error().Err(err).Msg("failed to load testcase")
|
log.Error().Err(err).Msg("failed to load testcase")
|
||||||
os.Exit(1)
|
os.Exit(code.GetErrorCode(err))
|
||||||
}
|
}
|
||||||
return &StepTestCaseWithOptionalArgs{
|
return &StepTestCaseWithOptionalArgs{
|
||||||
step: s.step,
|
step: s.step,
|
||||||
@@ -696,7 +697,7 @@ func (s *StepRequest) CallRefAPI(api IAPI) *StepAPIWithOptionalArgs {
|
|||||||
s.step.API, err = api.ToAPI()
|
s.step.API, err = api.ToAPI()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Error().Err(err).Msg("failed to load api")
|
log.Error().Err(err).Msg("failed to load api")
|
||||||
os.Exit(1)
|
os.Exit(code.GetErrorCode(err))
|
||||||
}
|
}
|
||||||
return &StepAPIWithOptionalArgs{
|
return &StepAPIWithOptionalArgs{
|
||||||
step: s.step,
|
step: s.step,
|
||||||
|
|||||||
+19
-9
@@ -10,6 +10,7 @@ import (
|
|||||||
"github.com/rs/zerolog/log"
|
"github.com/rs/zerolog/log"
|
||||||
|
|
||||||
"github.com/httprunner/httprunner/v4/hrp/internal/builtin"
|
"github.com/httprunner/httprunner/v4/hrp/internal/builtin"
|
||||||
|
"github.com/httprunner/httprunner/v4/hrp/internal/code"
|
||||||
)
|
)
|
||||||
|
|
||||||
// ITestCase represents interface for testcases,
|
// ITestCase represents interface for testcases,
|
||||||
@@ -117,7 +118,8 @@ func (tc *TCase) MakeCompat() (err error) {
|
|||||||
|
|
||||||
func (tc *TCase) ToTestCase(casePath string) (*TestCase, error) {
|
func (tc *TCase) ToTestCase(casePath string) (*TestCase, error) {
|
||||||
if tc.TestSteps == nil {
|
if tc.TestSteps == nil {
|
||||||
return nil, errors.New("invalid testcase format, missing teststeps!")
|
return nil, errors.Wrap(code.InvalidCaseFormat,
|
||||||
|
"invalid testcase format, missing teststeps!")
|
||||||
}
|
}
|
||||||
|
|
||||||
if tc.Config == nil {
|
if tc.Config == nil {
|
||||||
@@ -169,7 +171,8 @@ func (tc *TCase) toTestCase() (*TestCase, error) {
|
|||||||
if ok {
|
if ok {
|
||||||
path := filepath.Join(projectRootDir, apiPath)
|
path := filepath.Join(projectRootDir, apiPath)
|
||||||
if !builtin.IsFilePathExists(path) {
|
if !builtin.IsFilePathExists(path) {
|
||||||
return nil, errors.New("referenced api file not found: " + path)
|
return nil, errors.Wrap(code.ReferencedFileNotFound,
|
||||||
|
fmt.Sprintf("referenced api file not found: %s", path))
|
||||||
}
|
}
|
||||||
|
|
||||||
refAPI := APIPath(path)
|
refAPI := APIPath(path)
|
||||||
@@ -181,7 +184,8 @@ func (tc *TCase) toTestCase() (*TestCase, error) {
|
|||||||
} else {
|
} else {
|
||||||
apiMap, ok := step.API.(map[string]interface{})
|
apiMap, ok := step.API.(map[string]interface{})
|
||||||
if !ok {
|
if !ok {
|
||||||
return nil, fmt.Errorf("referenced api should be map or path(string), got %v", step.API)
|
return nil, errors.Wrap(code.InvalidCaseFormat,
|
||||||
|
fmt.Sprintf("referenced api should be map or path(string), got %v", step.API))
|
||||||
}
|
}
|
||||||
api := &API{}
|
api := &API{}
|
||||||
err = mapstructure.Decode(apiMap, api)
|
err = mapstructure.Decode(apiMap, api)
|
||||||
@@ -192,7 +196,8 @@ func (tc *TCase) toTestCase() (*TestCase, error) {
|
|||||||
}
|
}
|
||||||
_, ok = step.API.(*API)
|
_, ok = step.API.(*API)
|
||||||
if !ok {
|
if !ok {
|
||||||
return nil, fmt.Errorf("failed to handle referenced API, got %v", step.TestCase)
|
return nil, errors.Wrap(code.InvalidCaseFormat,
|
||||||
|
fmt.Sprintf("failed to handle referenced API, got %v", step.TestCase))
|
||||||
}
|
}
|
||||||
testCase.TestSteps = append(testCase.TestSteps, &StepAPIWithOptionalArgs{
|
testCase.TestSteps = append(testCase.TestSteps, &StepAPIWithOptionalArgs{
|
||||||
step: step,
|
step: step,
|
||||||
@@ -202,7 +207,8 @@ func (tc *TCase) toTestCase() (*TestCase, error) {
|
|||||||
if ok {
|
if ok {
|
||||||
path := filepath.Join(projectRootDir, casePath)
|
path := filepath.Join(projectRootDir, casePath)
|
||||||
if !builtin.IsFilePathExists(path) {
|
if !builtin.IsFilePathExists(path) {
|
||||||
return nil, errors.New("referenced testcase file not found: " + path)
|
return nil, errors.Wrap(code.ReferencedFileNotFound,
|
||||||
|
fmt.Sprintf("referenced testcase file not found: %s", path))
|
||||||
}
|
}
|
||||||
|
|
||||||
refTestCase := TestCasePath(path)
|
refTestCase := TestCasePath(path)
|
||||||
@@ -214,7 +220,8 @@ func (tc *TCase) toTestCase() (*TestCase, error) {
|
|||||||
} else {
|
} else {
|
||||||
testCaseMap, ok := step.TestCase.(map[string]interface{})
|
testCaseMap, ok := step.TestCase.(map[string]interface{})
|
||||||
if !ok {
|
if !ok {
|
||||||
return nil, fmt.Errorf("referenced testcase should be map or path(string), got %v", step.TestCase)
|
return nil, errors.Wrap(code.InvalidCaseFormat,
|
||||||
|
fmt.Sprintf("referenced testcase should be map or path(string), got %v", step.TestCase))
|
||||||
}
|
}
|
||||||
tCase := &TCase{}
|
tCase := &TCase{}
|
||||||
err = mapstructure.Decode(testCaseMap, tCase)
|
err = mapstructure.Decode(testCaseMap, tCase)
|
||||||
@@ -229,7 +236,8 @@ func (tc *TCase) toTestCase() (*TestCase, error) {
|
|||||||
}
|
}
|
||||||
_, ok = step.TestCase.(*TestCase)
|
_, ok = step.TestCase.(*TestCase)
|
||||||
if !ok {
|
if !ok {
|
||||||
return nil, fmt.Errorf("failed to handle referenced testcase, got %v", step.TestCase)
|
return nil, errors.Wrap(code.InvalidCaseFormat,
|
||||||
|
fmt.Sprintf("failed to handle referenced testcase, got %v", step.TestCase))
|
||||||
}
|
}
|
||||||
testCase.TestSteps = append(testCase.TestSteps, &StepTestCaseWithOptionalArgs{
|
testCase.TestSteps = append(testCase.TestSteps, &StepTestCaseWithOptionalArgs{
|
||||||
step: step,
|
step: step,
|
||||||
@@ -317,7 +325,8 @@ func convertCompatValidator(Validators []interface{}) (err error) {
|
|||||||
for assertMethod, iValidatorContent := range validatorMap {
|
for assertMethod, iValidatorContent := range validatorMap {
|
||||||
validatorContent := iValidatorContent.([]interface{})
|
validatorContent := iValidatorContent.([]interface{})
|
||||||
if len(validatorContent) > 3 {
|
if len(validatorContent) > 3 {
|
||||||
return fmt.Errorf("unexpected validator format: %v", validatorMap)
|
return errors.Wrap(code.InvalidCaseFormat,
|
||||||
|
fmt.Sprintf("unexpected validator format: %v", validatorMap))
|
||||||
}
|
}
|
||||||
validator.Check = validatorContent[0].(string)
|
validator.Check = validatorContent[0].(string)
|
||||||
validator.Assert = assertMethod
|
validator.Assert = assertMethod
|
||||||
@@ -330,7 +339,8 @@ func convertCompatValidator(Validators []interface{}) (err error) {
|
|||||||
Validators[i] = validator
|
Validators[i] = validator
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
return fmt.Errorf("unexpected validator format: %v", validatorMap)
|
return errors.Wrap(code.InvalidCaseFormat,
|
||||||
|
fmt.Sprintf("unexpected validator format: %v", validatorMap))
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user