feat: support running load testing by loading profile

This commit is contained in:
xucong053
2022-05-20 14:53:23 +08:00
parent a283565d41
commit a25cae0aa9
5 changed files with 82 additions and 49 deletions
+55 -39
View File
@@ -1,12 +1,15 @@
package cmd package cmd
import ( import (
"os"
"time" "time"
"github.com/rs/zerolog/log"
"github.com/spf13/cobra" "github.com/spf13/cobra"
"github.com/httprunner/httprunner/v4/hrp" "github.com/httprunner/httprunner/v4/hrp"
"github.com/httprunner/httprunner/v4/hrp/internal/boomer" "github.com/httprunner/httprunner/v4/hrp/internal/boomer"
"github.com/httprunner/httprunner/v4/hrp/internal/builtin"
) )
// boomCmd represents the boom command // boomCmd represents the boom command
@@ -28,57 +31,70 @@ var boomCmd = &cobra.Command{
path := hrp.TestCasePath(arg) path := hrp.TestCasePath(arg)
paths = append(paths, &path) paths = append(paths, &path)
} }
hrpBoomer := hrp.NewBoomer(spawnCount, spawnRate) // if set profile, the priority is higher than the other commands
hrpBoomer.SetRateLimiter(maxRPS, requestIncreaseRate) if boomArgs.profile != "" {
if loopCount > 0 { err := builtin.LoadFile(boomArgs.profile, &boomArgs)
hrpBoomer.SetLoopCount(loopCount) if err != nil {
log.Error().Err(err).Msg("failed to load profile")
os.Exit(1)
}
} }
if !disableConsoleOutput {
hrpBoomer := hrp.NewBoomer(boomArgs.SpawnCount, boomArgs.SpawnRate)
hrpBoomer.SetRateLimiter(boomArgs.MaxRPS, boomArgs.RequestIncreaseRate)
if boomArgs.LoopCount > 0 {
hrpBoomer.SetLoopCount(boomArgs.LoopCount)
}
if !boomArgs.DisableConsoleOutput {
hrpBoomer.AddOutput(boomer.NewConsoleOutput()) hrpBoomer.AddOutput(boomer.NewConsoleOutput())
} }
if prometheusPushgatewayURL != "" { if boomArgs.PrometheusPushgatewayURL != "" {
hrpBoomer.AddOutput(boomer.NewPrometheusPusherOutput(prometheusPushgatewayURL, "hrp", hrpBoomer.GetMode())) hrpBoomer.AddOutput(boomer.NewPrometheusPusherOutput(boomArgs.PrometheusPushgatewayURL, "hrp", hrpBoomer.GetMode()))
} }
hrpBoomer.SetDisableKeepAlive(disableKeepalive) hrpBoomer.SetDisableKeepAlive(boomArgs.DisableKeepalive)
hrpBoomer.SetDisableCompression(disableCompression) hrpBoomer.SetDisableCompression(boomArgs.DisableCompression)
hrpBoomer.SetClientTransport() hrpBoomer.SetClientTransport()
hrpBoomer.EnableCPUProfile(cpuProfile, cpuProfileDuration) hrpBoomer.EnableCPUProfile(boomArgs.CPUProfile, boomArgs.CPUProfileDuration)
hrpBoomer.EnableMemoryProfile(memoryProfile, memoryProfileDuration) hrpBoomer.EnableMemoryProfile(boomArgs.MemoryProfile, boomArgs.MemoryProfileDuration)
hrpBoomer.EnableGracefulQuit() hrpBoomer.EnableGracefulQuit()
hrpBoomer.Run(paths...) hrpBoomer.Run(paths...)
}, },
} }
var ( type BoomArgs struct {
spawnCount int SpawnCount int `json:"spawn-count,omitempty" yaml:"spawn-count,omitempty"`
spawnRate float64 SpawnRate float64 `json:"spawn-rate,omitempty" yaml:"spawn-rate,omitempty"`
maxRPS int64 MaxRPS int64 `json:"max-rps,omitempty" yaml:"max-rps,omitempty"`
loopCount int64 LoopCount int64 `json:"loop-count,omitempty" yaml:"loop-count,omitempty"`
requestIncreaseRate string RequestIncreaseRate string `json:"request-increase-rate,omitempty" yaml:"request-increase-rate,omitempty"`
memoryProfile string MemoryProfile string `json:"memory-profile,omitempty" yaml:"memory-profile,omitempty"`
memoryProfileDuration time.Duration MemoryProfileDuration time.Duration `json:"memory-profile-duration" yaml:"memory-profile-duration"`
cpuProfile string CPUProfile string `json:"cpu-profile,omitempty" yaml:"cpu-profile,omitempty"`
cpuProfileDuration time.Duration CPUProfileDuration time.Duration `json:"cpu-profile-duration,omitempty" yaml:"cpu-profile-duration,omitempty"`
prometheusPushgatewayURL string PrometheusPushgatewayURL string `json:"prometheus-gateway,omitempty" yaml:"prometheus-gateway,omitempty"`
disableConsoleOutput bool DisableConsoleOutput bool `json:"disable-console-output,omitempty" yaml:"disable-console-output,omitempty"`
disableCompression bool DisableCompression bool `json:"disable-compression,omitempty" yaml:"disable-compression,omitempty"`
disableKeepalive bool DisableKeepalive bool `json:"disable-keepalive,omitempty" yaml:"disable-keepalive,omitempty"`
) profile string
}
var boomArgs BoomArgs
func init() { func init() {
rootCmd.AddCommand(boomCmd) rootCmd.AddCommand(boomCmd)
boomCmd.Flags().Int64Var(&maxRPS, "max-rps", 0, "Max RPS that boomer can generate, disabled by default.") boomCmd.Flags().Int64Var(&boomArgs.MaxRPS, "max-rps", 0, "Max RPS that boomer can generate, disabled by default.")
boomCmd.Flags().StringVar(&requestIncreaseRate, "request-increase-rate", "-1", "Request increase rate, disabled by default.") boomCmd.Flags().StringVar(&boomArgs.RequestIncreaseRate, "request-increase-rate", "-1", "Request increase rate, disabled by default.")
boomCmd.Flags().IntVar(&spawnCount, "spawn-count", 1, "The number of users to spawn for load testing") boomCmd.Flags().IntVar(&boomArgs.SpawnCount, "spawn-count", 1, "The number of users to spawn for load testing")
boomCmd.Flags().Float64Var(&spawnRate, "spawn-rate", 1, "The rate for spawning users") boomCmd.Flags().Float64Var(&boomArgs.SpawnRate, "spawn-rate", 1, "The rate for spawning users")
boomCmd.Flags().Int64Var(&loopCount, "loop-count", -1, "The specify running cycles for load testing") boomCmd.Flags().Int64Var(&boomArgs.LoopCount, "loop-count", -1, "The specify running cycles for load testing")
boomCmd.Flags().StringVar(&memoryProfile, "mem-profile", "", "Enable memory profiling.") boomCmd.Flags().StringVar(&boomArgs.MemoryProfile, "mem-profile", "", "Enable memory profiling.")
boomCmd.Flags().DurationVar(&memoryProfileDuration, "mem-profile-duration", 30*time.Second, "Memory profile duration.") boomCmd.Flags().DurationVar(&boomArgs.MemoryProfileDuration, "mem-profile-duration", 30*time.Second, "Memory profile duration.")
boomCmd.Flags().StringVar(&cpuProfile, "cpu-profile", "", "Enable CPU profiling.") boomCmd.Flags().StringVar(&boomArgs.CPUProfile, "cpu-profile", "", "Enable CPU profiling.")
boomCmd.Flags().DurationVar(&cpuProfileDuration, "cpu-profile-duration", 30*time.Second, "CPU profile duration.") boomCmd.Flags().DurationVar(&boomArgs.CPUProfileDuration, "cpu-profile-duration", 30*time.Second, "CPU profile duration.")
boomCmd.Flags().StringVar(&prometheusPushgatewayURL, "prometheus-gateway", "", "Prometheus Pushgateway url.") boomCmd.Flags().StringVar(&boomArgs.PrometheusPushgatewayURL, "prometheus-gateway", "", "Prometheus Pushgateway url.")
boomCmd.Flags().BoolVar(&disableConsoleOutput, "disable-console-output", false, "Disable console output.") boomCmd.Flags().BoolVar(&boomArgs.DisableConsoleOutput, "disable-console-output", false, "Disable console output.")
boomCmd.Flags().BoolVar(&disableCompression, "disable-compression", false, "Disable compression") boomCmd.Flags().BoolVar(&boomArgs.DisableCompression, "disable-compression", false, "Disable compression")
boomCmd.Flags().BoolVar(&disableKeepalive, "disable-keepalive", false, "Disable keepalive") boomCmd.Flags().BoolVar(&boomArgs.DisableKeepalive, "disable-keepalive", false, "Disable keepalive")
boomCmd.Flags().StringVar(&boomArgs.profile, "profile", "", "profile for load testing")
} }
+18 -1
View File
@@ -6,6 +6,7 @@ import (
"os" "os"
"os/exec" "os/exec"
"path/filepath" "path/filepath"
"time"
"github.com/httprunner/funplugin/shared" "github.com/httprunner/funplugin/shared"
"github.com/pkg/errors" "github.com/pkg/errors"
@@ -13,6 +14,7 @@ import (
"github.com/httprunner/httprunner/v4/hrp/internal/builtin" "github.com/httprunner/httprunner/v4/hrp/internal/builtin"
"github.com/httprunner/httprunner/v4/hrp/internal/sdk" "github.com/httprunner/httprunner/v4/hrp/internal/sdk"
"github.com/httprunner/httprunner/v4/hrp/internal/version"
) )
type PluginType string type PluginType string
@@ -23,6 +25,12 @@ const (
Go PluginType = "go" Go PluginType = "go"
) )
type ProjectInfo struct {
ProjectName string `json:"project_name,omitempty" yaml:"project_name,omitempty"`
CreateTime time.Time `json:"create_time,omitempty" yaml:"create_time,omitempty"`
Version string `json:"hrp_version,omitempty" yaml:"hrp_version,omitempty"`
}
//go:embed templates/* //go:embed templates/*
var templatesDir embed.FS var templatesDir embed.FS
@@ -88,8 +96,17 @@ func CreateScaffold(projectName string, pluginType PluginType, force bool) error
return err return err
} }
projectInfo := &ProjectInfo{
ProjectName: projectName,
CreateTime: time.Now(),
Version: version.VERSION,
}
// dump project information to file
err := builtin.Dump2JSON(projectInfo, filepath.Join(projectName, "proj.json"))
// create .gitignore // create .gitignore
err := CopyFile("templates/gitignore", filepath.Join(projectName, ".gitignore")) err = CopyFile("templates/gitignore", filepath.Join(projectName, ".gitignore"))
if err != nil { if err != nil {
return err return err
} }
+7 -7
View File
@@ -20,9 +20,9 @@ type TParamsConfig struct {
type iteratorPickOrder string type iteratorPickOrder string
const ( const (
strategySequential iteratorPickOrder = "sequential" pickOrderSequential iteratorPickOrder = "sequential"
strategyRandom iteratorPickOrder = "random" pickOrderRandom iteratorPickOrder = "random"
strategyUnique iteratorPickOrder = "unique" pickOrderUnique iteratorPickOrder = "unique"
) )
/* /*
@@ -67,15 +67,15 @@ func newParametersIterator(parameters map[string]Parameters, config *TParamsConf
parametersList := make([]Parameters, 0) parametersList := make([]Parameters, 0)
for paramName := range parameters { for paramName := range parameters {
// check parameter individual strategy // check parameter individual pick order strategy
strategy, ok := config.Strategies[paramName] strategy, ok := config.Strategies[paramName]
if !ok { if !ok {
// default to overall pick order // default to overall pick order strategy
strategy.PickOrder = config.PickOrder strategy.PickOrder = config.PickOrder
} }
// group parameters by strategy // group parameters by pick order strategy
if strategy.PickOrder == strategyRandom { if strategy.PickOrder == pickOrderRandom {
iterator.randomParameterNames = append(iterator.randomParameterNames, paramName) iterator.randomParameterNames = append(iterator.randomParameterNames, paramName)
} else { } else {
parametersList = append(parametersList, parameters[paramName]) parametersList = append(parametersList, parameters[paramName])
+1 -1
View File
@@ -118,7 +118,7 @@ func locateFile(startPath string, destFile string) (string, error) {
return locateFile(parentDir, destFile) return locateFile(parentDir, destFile)
} }
func getProjectRootDirPath(path string) (rootDir string, err error) { func GetProjectRootDirPath(path string) (rootDir string, err error) {
pluginPath, err := locatePlugin(path) pluginPath, err := locatePlugin(path)
if err == nil { if err == nil {
rootDir = filepath.Dir(pluginPath) rootDir = filepath.Dir(pluginPath)
+1 -1
View File
@@ -75,7 +75,7 @@ func (path *TestCasePath) ToTestCase() (*TestCase, error) {
} }
// locate project root dir by plugin path // locate project root dir by plugin path
projectRootDir, err := getProjectRootDirPath(casePath) projectRootDir, err := GetProjectRootDirPath(casePath)
if err != nil { if err != nil {
return nil, errors.Wrap(err, "failed to get project root dir") return nil, errors.Wrap(err, "failed to get project root dir")
} }