diff --git a/boomer.go b/boomer.go index 3236a007..0989ce40 100644 --- a/boomer.go +++ b/boomer.go @@ -8,6 +8,7 @@ import ( "github.com/httprunner/hrp/internal/boomer" "github.com/httprunner/hrp/internal/ga" + "github.com/httprunner/hrp/plugin/common" ) func NewBoomer(spawnCount int, spawnRate float64) *HRPBoomer { @@ -20,7 +21,8 @@ func NewBoomer(spawnCount int, spawnRate float64) *HRPBoomer { type HRPBoomer struct { *boomer.Boomer - debug bool + plugins []common.Plugin // each task has its own plugin process + debug bool } // SetDebug configures whether to log HTTP request and response content. @@ -57,14 +59,29 @@ func (b *HRPBoomer) Run(testcases ...ITestCase) { b.Boomer.Run(taskSlice...) } +func (b *HRPBoomer) Quit() { + for _, plugin := range b.plugins { + plugin.Quit() + } + b.Boomer.Quit() +} + func (b *HRPBoomer) convertBoomerTask(testcase *TestCase) *boomer.Task { hrpRunner := NewRunner(nil).SetDebug(b.debug) config := testcase.Config.ToStruct() + + // each testcase has its own plugin process + plugin, _ := initPlugin(config.Path) + if plugin != nil { + b.plugins = append(b.plugins, plugin) + } + return &boomer.Task{ Name: config.Name, Weight: config.Weight, Fn: func() { runner := hrpRunner.newCaseRunner(testcase) + runner.parser.plugin = plugin testcaseSuccess := true // flag whole testcase result var transactionSuccess = true // flag current transaction result @@ -74,6 +91,7 @@ func (b *HRPBoomer) convertBoomerTask(testcase *TestCase) *boomer.Task { // copy config to avoid data racing if err := copier.Copy(caseConfig, cfg); err != nil { log.Error().Err(err).Msg("copy config data failed") + return } // iterate through all parameter iterators and update case variables for _, it := range caseConfig.ParametersSetting.Iterators { @@ -81,6 +99,13 @@ func (b *HRPBoomer) convertBoomerTask(testcase *TestCase) *boomer.Task { caseConfig.Variables = mergeVariables(it.Next(), caseConfig.Variables) } } + + config := runner.TestCase.Config + if err := runner.parseConfig(config); err != nil { + log.Error().Err(err).Msg("parse config failed") + return + } + startTime := time.Now() for index, step := range testcase.TestSteps { stepData, err := runner.runStep(index, caseConfig) diff --git a/boomer_test.go b/boomer_test.go index b49e1069..ab61e62e 100644 --- a/boomer_test.go +++ b/boomer_test.go @@ -6,6 +6,9 @@ import ( ) func TestBoomerStandaloneRun(t *testing.T) { + buildHashicorpPlugin() + defer removeHashicorpPlugin() + testcase1 := &TestCase{ Config: NewConfig("TestCase1").SetBaseURL("http://httpbin.org"), TestSteps: []IStep{ diff --git a/docs/cmd/hrp.md b/docs/cmd/hrp.md index 14de4bca..0a64f28f 100644 --- a/docs/cmd/hrp.md +++ b/docs/cmd/hrp.md @@ -33,4 +33,4 @@ Copyright 2021 debugtalk * [hrp run](hrp_run.md) - run API test * [hrp startproject](hrp_startproject.md) - create a scaffold project -###### Auto generated by spf13/cobra on 17-Jan-2022 +###### Auto generated by spf13/cobra on 18-Jan-2022 diff --git a/docs/cmd/hrp_boom.md b/docs/cmd/hrp_boom.md index 9b274446..162ae0e3 100644 --- a/docs/cmd/hrp_boom.md +++ b/docs/cmd/hrp_boom.md @@ -39,4 +39,4 @@ hrp boom [flags] * [hrp](hrp.md) - One-stop solution for HTTP(S) testing. -###### Auto generated by spf13/cobra on 17-Jan-2022 +###### Auto generated by spf13/cobra on 18-Jan-2022 diff --git a/docs/cmd/hrp_har2case.md b/docs/cmd/hrp_har2case.md index 2fe2e4ae..2d575c70 100644 --- a/docs/cmd/hrp_har2case.md +++ b/docs/cmd/hrp_har2case.md @@ -23,4 +23,4 @@ hrp har2case $har_path... [flags] * [hrp](hrp.md) - One-stop solution for HTTP(S) testing. -###### Auto generated by spf13/cobra on 17-Jan-2022 +###### Auto generated by spf13/cobra on 18-Jan-2022 diff --git a/docs/cmd/hrp_run.md b/docs/cmd/hrp_run.md index 2abd2c76..5c1f1c40 100644 --- a/docs/cmd/hrp_run.md +++ b/docs/cmd/hrp_run.md @@ -31,4 +31,4 @@ hrp run $path... [flags] * [hrp](hrp.md) - One-stop solution for HTTP(S) testing. -###### Auto generated by spf13/cobra on 17-Jan-2022 +###### Auto generated by spf13/cobra on 18-Jan-2022 diff --git a/docs/cmd/hrp_startproject.md b/docs/cmd/hrp_startproject.md index 40b7807b..96485c09 100644 --- a/docs/cmd/hrp_startproject.md +++ b/docs/cmd/hrp_startproject.md @@ -16,4 +16,4 @@ hrp startproject $project_name [flags] * [hrp](hrp.md) - One-stop solution for HTTP(S) testing. -###### Auto generated by spf13/cobra on 17-Jan-2022 +###### Auto generated by spf13/cobra on 18-Jan-2022 diff --git a/internal/scaffold/demo_test.go b/internal/scaffold/demo_test.go index a78d3dcf..9f301c4a 100644 --- a/internal/scaffold/demo_test.go +++ b/internal/scaffold/demo_test.go @@ -2,8 +2,12 @@ package scaffold import ( "fmt" + "os" + "os/exec" "testing" + "github.com/rs/zerolog/log" + "github.com/httprunner/hrp" ) @@ -12,6 +16,21 @@ var ( demoTestCaseYAMLPath = "../../examples/demo.yaml" ) +func buildHashicorpPlugin() { + log.Info().Msg("[init] build hashicorp go plugin") + cmd := exec.Command("go", "build", + "-o", "../../examples/debugtalk.bin", + "../../examples/plugin/hashicorp.go", "../../examples/plugin/debugtalk.go") + if err := cmd.Run(); err != nil { + panic(err) + } +} + +func removeHashicorpPlugin() { + log.Info().Msg("[teardown] remove hashicorp plugin") + os.Remove("../../examples/debugtalk.bin") +} + func TestGenDemoTestCase(t *testing.T) { tCase, _ := demoTestCase.ToTCase() err := tCase.Dump2JSON(demoTestCaseJSONPath) @@ -25,6 +44,9 @@ func TestGenDemoTestCase(t *testing.T) { } func Example_demo() { + buildHashicorpPlugin() + defer removeHashicorpPlugin() + demoTestCase.Config.ToStruct().Path = "../../examples/debugtalk.bin" err := hrp.NewRunner(nil).Run(demoTestCase) // hrp.Run(demoTestCase) fmt.Println(err) @@ -33,6 +55,9 @@ func Example_demo() { } func Example_jsonDemo() { + buildHashicorpPlugin() + defer removeHashicorpPlugin() + testCase := &hrp.TestCasePath{Path: demoTestCaseJSONPath} err := hrp.NewRunner(nil).Run(testCase) // hrp.Run(testCase) fmt.Println(err) @@ -41,6 +66,9 @@ func Example_jsonDemo() { } func Example_yamlDemo() { + buildHashicorpPlugin() + defer removeHashicorpPlugin() + testCase := &hrp.TestCasePath{Path: demoTestCaseYAMLPath} err := hrp.NewRunner(nil).Run(testCase) // hrp.Run(testCase) fmt.Println(err) diff --git a/plugin/common/hashicorp_plugin_test.go b/plugin/common/hashicorp_plugin_test.go index 06713926..a0c6a806 100644 --- a/plugin/common/hashicorp_plugin_test.go +++ b/plugin/common/hashicorp_plugin_test.go @@ -1,18 +1,18 @@ package common import ( - "fmt" "os" "os/exec" "testing" + "github.com/rs/zerolog/log" "github.com/stretchr/testify/assert" ) func buildHashicorpPlugin() { - fmt.Println("[init] build hashicorp go plugin") + log.Info().Msg("[init] build hashicorp go plugin") cmd := exec.Command("go", "build", - "-o=debugtalk.bin", + "-o", "../../examples/debugtalk.bin", "../../examples/plugin/hashicorp.go", "../../examples/plugin/debugtalk.go") if err := cmd.Run(); err != nil { panic(err) @@ -20,15 +20,15 @@ func buildHashicorpPlugin() { } func removeHashicorpPlugin() { - fmt.Println("[teardown] remove hashicorp plugin") - os.Remove("debugtalk.bin") + log.Info().Msg("[teardown] remove hashicorp plugin") + os.Remove("../../examples/debugtalk.bin") } func TestInitHashicorpPlugin(t *testing.T) { buildHashicorpPlugin() defer removeHashicorpPlugin() - plugin, err := Init("debugtalk.bin") + plugin, err := Init("../../examples/debugtalk.bin") if err != nil { t.Fatal(err) } diff --git a/runner.go b/runner.go index fb2bedb4..f8f20899 100644 --- a/runner.go +++ b/runner.go @@ -156,12 +156,19 @@ func (r *caseRunner) reset() *caseRunner { } func (r *caseRunner) run() error { + config := r.TestCase.Config + + // init plugin + var err error + if r.parser.plugin, err = initPlugin(config.ToStruct().Path); err != nil { + return err + } defer func() { if r.parser.plugin != nil { r.parser.plugin.Quit() } }() - config := r.TestCase.Config + if err := r.parseConfig(config); err != nil { return err } @@ -182,6 +189,33 @@ func (r *caseRunner) run() error { return nil } +func initPlugin(path string) (plugin common.Plugin, err error) { + defer func() { + if plugin == nil { + return + } + + var pluginType string + if _, ok := plugin.(*common.GoPlugin); ok { + pluginType = "go" + } else { + pluginType = "hashicorp" + } + + // report event for initializing plugin + event := ga.EventTracking{ + Category: "InitPlugin", + Action: fmt.Sprintf("Init %s plugin", pluginType), + } + if err != nil { + event.Value = 1 // failed + } + go ga.SendEvent(event) + }() + plugin, err = common.Init(path) + return +} + func (r *caseRunner) runStep(index int, caseConfig *TConfig) (stepResult *stepData, err error) { step := r.TestCase.TestSteps[index] @@ -504,34 +538,6 @@ func (r *caseRunner) runStepTestCase(step *TStep) (stepResult *stepData, err err func (r *caseRunner) parseConfig(config IConfig) error { cfg := config.ToStruct() - // init plugin - var err error - defer func() { - if r.parser.plugin == nil { - return - } - var pluginType string - if _, ok := r.parser.plugin.(*common.GoPlugin); ok { - pluginType = "go" - } else { - pluginType = "hashicorp" - } - - // report event for initializing plugin - event := ga.EventTracking{ - Category: "InitPlugin", - Action: fmt.Sprintf("Init %s plugin", pluginType), - } - if err != nil { - event.Value = 1 // failed - } - go ga.SendEvent(event) - }() - r.parser.plugin, err = common.Init(cfg.Path) - if err != nil { - return err - } - // parse config variables parsedVariables, err := r.parser.parseVariables(cfg.Variables) if err != nil { diff --git a/runner_test.go b/runner_test.go index 686d67e1..2fb64fcf 100644 --- a/runner_test.go +++ b/runner_test.go @@ -1,10 +1,32 @@ package hrp import ( + "os" + "os/exec" "testing" + + "github.com/rs/zerolog/log" ) +func buildHashicorpPlugin() { + log.Info().Msg("[init] build hashicorp go plugin") + cmd := exec.Command("go", "build", + "-o", "examples/debugtalk.bin", + "examples/plugin/hashicorp.go", "examples/plugin/debugtalk.go") + if err := cmd.Run(); err != nil { + panic(err) + } +} + +func removeHashicorpPlugin() { + log.Info().Msg("[teardown] remove hashicorp plugin") + os.Remove("examples/debugtalk.bin") +} + func TestHttpRunner(t *testing.T) { + buildHashicorpPlugin() + defer removeHashicorpPlugin() + testcase1 := &TestCase{ Config: NewConfig("TestCase1"). SetBaseURL("http://httpbin.org"),