mirror of
https://github.com/httprunner/httprunner.git
synced 2026-05-14 01:49:41 +08:00
feat: add flag --log-plugin to turn on plugin logging
This commit is contained in:
12
boomer.go
12
boomer.go
@@ -16,7 +16,6 @@ func NewBoomer(spawnCount int, spawnRate float64) *HRPBoomer {
|
||||
b := &HRPBoomer{
|
||||
Boomer: boomer.NewStandaloneBoomer(spawnCount, spawnRate),
|
||||
pluginsMutex: new(sync.RWMutex),
|
||||
debug: false,
|
||||
}
|
||||
return b
|
||||
}
|
||||
@@ -25,13 +24,6 @@ type HRPBoomer struct {
|
||||
*boomer.Boomer
|
||||
plugins []common.Plugin // each task has its own plugin process
|
||||
pluginsMutex *sync.RWMutex // avoid data race
|
||||
debug bool
|
||||
}
|
||||
|
||||
// SetDebug configures whether to log HTTP request and response content.
|
||||
func (b *HRPBoomer) SetDebug(debug bool) *HRPBoomer {
|
||||
b.debug = debug
|
||||
return b
|
||||
}
|
||||
|
||||
// Run starts to run load test for one or multiple testcases.
|
||||
@@ -75,11 +67,11 @@ func (b *HRPBoomer) Quit() {
|
||||
}
|
||||
|
||||
func (b *HRPBoomer) convertBoomerTask(testcase *TestCase, rendezvousList []*Rendezvous) *boomer.Task {
|
||||
hrpRunner := NewRunner(nil).SetDebug(b.debug)
|
||||
hrpRunner := NewRunner(nil)
|
||||
config := testcase.Config
|
||||
|
||||
// each testcase has its own plugin process
|
||||
plugin, _ := initPlugin(config.Path)
|
||||
plugin, _ := initPlugin(config.Path, false)
|
||||
if plugin != nil {
|
||||
b.pluginsMutex.Lock()
|
||||
b.plugins = append(b.plugins, plugin)
|
||||
|
||||
@@ -26,12 +26,17 @@ var runCmd = &cobra.Command{
|
||||
paths = append(paths, &hrp.TestCasePath{Path: arg})
|
||||
}
|
||||
runner := hrp.NewRunner(nil).
|
||||
SetDebug(!silentFlag).
|
||||
SetFailfast(!continueOnFailure).
|
||||
SetSaveTests(saveTests)
|
||||
if genHTMLReport {
|
||||
runner.GenHTMLReport()
|
||||
}
|
||||
if !requestsLogOff {
|
||||
runner.SetRequestsLogOn()
|
||||
}
|
||||
if pluginLogOn {
|
||||
runner.SetPluginLogOn()
|
||||
}
|
||||
if proxyUrl != "" {
|
||||
runner.SetProxyUrl(proxyUrl)
|
||||
}
|
||||
@@ -44,7 +49,8 @@ var runCmd = &cobra.Command{
|
||||
|
||||
var (
|
||||
continueOnFailure bool
|
||||
silentFlag bool
|
||||
requestsLogOff bool
|
||||
pluginLogOn bool
|
||||
proxyUrl string
|
||||
saveTests bool
|
||||
genHTMLReport bool
|
||||
@@ -53,8 +59,9 @@ var (
|
||||
func init() {
|
||||
rootCmd.AddCommand(runCmd)
|
||||
runCmd.Flags().BoolVarP(&continueOnFailure, "continue-on-failure", "c", false, "continue running next step when failure occurs")
|
||||
runCmd.Flags().BoolVarP(&silentFlag, "silent", "s", false, "disable logging request & response details")
|
||||
runCmd.Flags().BoolVar(&requestsLogOff, "disable-log-requests", false, "turn off request & response details logging")
|
||||
runCmd.Flags().BoolVar(&pluginLogOn, "log-plugin", false, "turn on plugin logging")
|
||||
runCmd.Flags().StringVarP(&proxyUrl, "proxy-url", "p", "", "set proxy url")
|
||||
runCmd.Flags().BoolVar(&saveTests, "save-tests", false, "save tests summary")
|
||||
runCmd.Flags().BoolVarP(&genHTMLReport, "gen-html-report", "r", false, "generate html report")
|
||||
runCmd.Flags().BoolVarP(&saveTests, "save-tests", "s", false, "save tests summary")
|
||||
runCmd.Flags().BoolVarP(&genHTMLReport, "gen-html-report", "g", false, "generate html report")
|
||||
}
|
||||
|
||||
@@ -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 22-Feb-2022
|
||||
###### Auto generated by spf13/cobra on 25-Feb-2022
|
||||
|
||||
@@ -39,4 +39,4 @@ hrp boom [flags]
|
||||
|
||||
* [hrp](hrp.md) - One-stop solution for HTTP(S) testing.
|
||||
|
||||
###### Auto generated by spf13/cobra on 22-Feb-2022
|
||||
###### Auto generated by spf13/cobra on 25-Feb-2022
|
||||
|
||||
@@ -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 22-Feb-2022
|
||||
###### Auto generated by spf13/cobra on 25-Feb-2022
|
||||
|
||||
@@ -21,9 +21,10 @@ hrp run $path... [flags]
|
||||
### Options
|
||||
|
||||
```
|
||||
--continue-on-failure continue running next step when failure occurs
|
||||
-r, --gen-html-report generate html report
|
||||
-c, --continue-on-failure continue running next step when failure occurs
|
||||
-g, --gen-html-report generate html report
|
||||
-h, --help help for run
|
||||
--plugin-log turn on plugin logging
|
||||
-p, --proxy-url string set proxy url
|
||||
--save-tests save tests summary
|
||||
-s, --silent disable logging request & response details
|
||||
@@ -33,4 +34,4 @@ hrp run $path... [flags]
|
||||
|
||||
* [hrp](hrp.md) - One-stop solution for HTTP(S) testing.
|
||||
|
||||
###### Auto generated by spf13/cobra on 22-Feb-2022
|
||||
###### Auto generated by spf13/cobra on 25-Feb-2022
|
||||
|
||||
@@ -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 22-Feb-2022
|
||||
###### Auto generated by spf13/cobra on 25-Feb-2022
|
||||
|
||||
@@ -70,7 +70,7 @@ func TestCallPluginFunction(t *testing.T) {
|
||||
buildGoPlugin()
|
||||
defer removeGoPlugin()
|
||||
|
||||
plugin, err := Init("debugtalk.so")
|
||||
plugin, err := Init("debugtalk.so", false)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
@@ -1,25 +1,62 @@
|
||||
package common
|
||||
|
||||
import (
|
||||
pluginHost "github.com/httprunner/hrp/plugin/host"
|
||||
"os"
|
||||
"os/exec"
|
||||
|
||||
"github.com/hashicorp/go-hclog"
|
||||
"github.com/hashicorp/go-plugin"
|
||||
"github.com/httprunner/hrp/plugin/shared"
|
||||
pluginShared "github.com/httprunner/hrp/plugin/shared"
|
||||
"github.com/rs/zerolog/log"
|
||||
)
|
||||
|
||||
var client *plugin.Client
|
||||
|
||||
// HashicorpPlugin implements hashicorp/go-plugin
|
||||
type HashicorpPlugin struct {
|
||||
logOn bool // turn on plugin log
|
||||
pluginShared.FuncCaller
|
||||
cachedFunctions map[string]bool // cache loaded functions to improve performance
|
||||
}
|
||||
|
||||
func (p *HashicorpPlugin) Init(path string) error {
|
||||
loggerOptions := &hclog.LoggerOptions{
|
||||
Name: shared.Name,
|
||||
Output: os.Stdout,
|
||||
}
|
||||
if p.logOn {
|
||||
loggerOptions.Level = hclog.Debug
|
||||
} else {
|
||||
loggerOptions.Level = hclog.Info
|
||||
}
|
||||
// launch the plugin process
|
||||
client = plugin.NewClient(&plugin.ClientConfig{
|
||||
HandshakeConfig: shared.HandshakeConfig,
|
||||
Plugins: map[string]plugin.Plugin{
|
||||
shared.Name: &shared.HashicorpPlugin{},
|
||||
},
|
||||
Cmd: exec.Command(path),
|
||||
Logger: hclog.New(loggerOptions),
|
||||
})
|
||||
|
||||
f, err := pluginHost.Init(path)
|
||||
// Connect via RPC
|
||||
rpcClient, err := client.Client()
|
||||
if err != nil {
|
||||
log.Error().Err(err).Str("path", path).Msg("load go hashicorp plugin failed")
|
||||
log.Error().Err(err).Msg("connect plugin via RPC failed")
|
||||
return err
|
||||
}
|
||||
p.FuncCaller = f
|
||||
|
||||
// Request the plugin
|
||||
raw, err := rpcClient.Dispense(shared.Name)
|
||||
if err != nil {
|
||||
log.Error().Err(err).Msg("request plugin failed")
|
||||
return err
|
||||
}
|
||||
|
||||
// We should have a Function now! This feels like a normal interface
|
||||
// implementation but is in fact over an RPC connection.
|
||||
p.FuncCaller = raw.(shared.FuncCaller)
|
||||
|
||||
p.cachedFunctions = make(map[string]bool)
|
||||
log.Info().Str("path", path).Msg("load hashicorp go plugin success")
|
||||
@@ -55,6 +92,6 @@ func (p *HashicorpPlugin) Call(funcName string, args ...interface{}) (interface{
|
||||
func (p *HashicorpPlugin) Quit() error {
|
||||
// kill hashicorp plugin process
|
||||
log.Info().Msg("quit hashicorp plugin process")
|
||||
pluginHost.Quit()
|
||||
client.Kill()
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -28,7 +28,7 @@ func TestInitHashicorpPlugin(t *testing.T) {
|
||||
buildHashicorpPlugin()
|
||||
defer removeHashicorpPlugin()
|
||||
|
||||
plugin, err := Init("../../examples/debugtalk.bin")
|
||||
plugin, err := Init("../../examples/debugtalk.bin", false)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
@@ -23,7 +23,7 @@ type Plugin interface {
|
||||
Quit() error // quit plugin
|
||||
}
|
||||
|
||||
func Init(path string) (Plugin, error) {
|
||||
func Init(path string, logOn bool) (Plugin, error) {
|
||||
if path == "" {
|
||||
return nil, nil
|
||||
}
|
||||
@@ -34,7 +34,9 @@ func Init(path string) (Plugin, error) {
|
||||
pluginPath, err := locateFile(path, hashicorpGoPluginFile)
|
||||
if err == nil {
|
||||
// found hashicorp go plugin file
|
||||
plugin = &HashicorpPlugin{}
|
||||
plugin = &HashicorpPlugin{
|
||||
logOn: logOn,
|
||||
}
|
||||
err = plugin.Init(pluginPath)
|
||||
return plugin, err
|
||||
}
|
||||
|
||||
@@ -1,50 +0,0 @@
|
||||
package host
|
||||
|
||||
import (
|
||||
"os"
|
||||
"os/exec"
|
||||
|
||||
hclog "github.com/hashicorp/go-hclog"
|
||||
"github.com/hashicorp/go-plugin"
|
||||
|
||||
"github.com/httprunner/hrp/plugin/shared"
|
||||
)
|
||||
|
||||
var client *plugin.Client
|
||||
|
||||
func Init(path string) (shared.FuncCaller, error) {
|
||||
// launch the plugin process
|
||||
client = plugin.NewClient(&plugin.ClientConfig{
|
||||
HandshakeConfig: shared.HandshakeConfig,
|
||||
Plugins: map[string]plugin.Plugin{
|
||||
shared.Name: &shared.HashicorpPlugin{},
|
||||
},
|
||||
Cmd: exec.Command(path),
|
||||
Logger: hclog.New(&hclog.LoggerOptions{
|
||||
Name: shared.Name,
|
||||
Output: os.Stdout,
|
||||
Level: hclog.Info,
|
||||
}),
|
||||
})
|
||||
|
||||
// Connect via RPC
|
||||
rpcClient, err := client.Client()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Request the plugin
|
||||
raw, err := rpcClient.Dispense(shared.Name)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// We should have a Function now! This feels like a normal interface
|
||||
// implementation but is in fact over an RPC connection.
|
||||
function := raw.(shared.FuncCaller)
|
||||
return function, nil
|
||||
}
|
||||
|
||||
func Quit() {
|
||||
client.Kill()
|
||||
}
|
||||
37
runner.go
37
runner.go
@@ -43,7 +43,7 @@ const (
|
||||
// Run starts to run API test with default configs.
|
||||
func Run(testcases ...ITestCase) error {
|
||||
t := &testing.T{}
|
||||
return NewRunner(t).SetDebug(true).Run(testcases...)
|
||||
return NewRunner(t).SetRequestsLogOn().Run(testcases...)
|
||||
}
|
||||
|
||||
// NewRunner constructs a new runner instance.
|
||||
@@ -53,8 +53,7 @@ func NewRunner(t *testing.T) *HRPRunner {
|
||||
}
|
||||
return &HRPRunner{
|
||||
t: t,
|
||||
failfast: true, // default to failfast
|
||||
debug: false, // default to turn off debug
|
||||
failfast: true, // default to failfast
|
||||
genHTMLReport: false,
|
||||
client: &http.Client{
|
||||
Transport: &http.Transport{
|
||||
@@ -68,7 +67,8 @@ func NewRunner(t *testing.T) *HRPRunner {
|
||||
type HRPRunner struct {
|
||||
t *testing.T
|
||||
failfast bool
|
||||
debug bool
|
||||
requestsLogOn bool
|
||||
pluginLogOn bool
|
||||
saveTests bool
|
||||
genHTMLReport bool
|
||||
client *http.Client
|
||||
@@ -81,10 +81,17 @@ func (r *HRPRunner) SetFailfast(failfast bool) *HRPRunner {
|
||||
return r
|
||||
}
|
||||
|
||||
// SetDebug configures whether to log HTTP request and response content.
|
||||
func (r *HRPRunner) SetDebug(debug bool) *HRPRunner {
|
||||
log.Info().Bool("debug", debug).Msg("[init] SetDebug")
|
||||
r.debug = debug
|
||||
// SetRequestsLogOn turns on request & response details logging.
|
||||
func (r *HRPRunner) SetRequestsLogOn() *HRPRunner {
|
||||
log.Info().Msg("[init] SetRequestsLogOn")
|
||||
r.requestsLogOn = true
|
||||
return r
|
||||
}
|
||||
|
||||
// SetPluginLogOn turns on plugin logging.
|
||||
func (r *HRPRunner) SetPluginLogOn() *HRPRunner {
|
||||
log.Info().Msg("[init] SetPluginLogOn")
|
||||
r.pluginLogOn = true
|
||||
return r
|
||||
}
|
||||
|
||||
@@ -221,7 +228,7 @@ func (r *caseRunner) run() error {
|
||||
config := r.TestCase.Config
|
||||
// init plugin
|
||||
var err error
|
||||
if r.parser.plugin, err = initPlugin(config.Path); err != nil {
|
||||
if r.parser.plugin, err = initPlugin(config.Path, r.hrpRunner.pluginLogOn); err != nil {
|
||||
return err
|
||||
}
|
||||
defer func() {
|
||||
@@ -247,9 +254,7 @@ func (r *caseRunner) run() error {
|
||||
// merge test case if the step is test case
|
||||
summary, ok := stepDataObj.Data.(*testCaseSummary)
|
||||
if ok {
|
||||
for _, rc := range summary.Records {
|
||||
r.summary.Records = append(r.summary.Records, rc)
|
||||
}
|
||||
r.summary.Records = append(r.summary.Records, summary.Records...)
|
||||
r.summary.Stat.Total += summary.Stat.Total
|
||||
r.summary.Stat.Successes += summary.Stat.Successes
|
||||
r.summary.Stat.Failures += summary.Stat.Failures
|
||||
@@ -277,8 +282,8 @@ func (r *caseRunner) run() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func initPlugin(path string) (plugin common.Plugin, err error) {
|
||||
plugin, err = common.Init(path)
|
||||
func initPlugin(path string, logOn bool) (plugin common.Plugin, err error) {
|
||||
plugin, err = common.Init(path, logOn)
|
||||
if plugin == nil {
|
||||
return
|
||||
}
|
||||
@@ -836,7 +841,7 @@ func (r *caseRunner) runStepRequest(step *TStep) (stepResult *stepData, err erro
|
||||
}
|
||||
|
||||
func (r *caseRunner) printRequest(req *http.Request) error {
|
||||
if !r.hrpRunner.debug {
|
||||
if !r.hrpRunner.requestsLogOn {
|
||||
return nil
|
||||
}
|
||||
reqContentType := req.Header.Get("Content-Type")
|
||||
@@ -855,7 +860,7 @@ func (r *caseRunner) printRequest(req *http.Request) error {
|
||||
}
|
||||
|
||||
func (r *caseRunner) printResponse(resp *http.Response) error {
|
||||
if !r.hrpRunner.debug {
|
||||
if !r.hrpRunner.requestsLogOn {
|
||||
return nil
|
||||
}
|
||||
fmt.Println("==================== response ===================")
|
||||
|
||||
@@ -77,7 +77,7 @@ func TestRunRequestRun(t *testing.T) {
|
||||
Config: NewConfig("test").SetBaseURL("https://postman-echo.com"),
|
||||
TestSteps: []IStep{stepGET, stepPOSTData},
|
||||
}
|
||||
runner := NewRunner(t).SetDebug(true).newCaseRunner(testcase)
|
||||
runner := NewRunner(t).SetRequestsLogOn().newCaseRunner(testcase)
|
||||
if _, err := runner.runStep(0, testcase.Config); err != nil {
|
||||
t.Fatalf("tStep.Run() error: %s", err)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user