Merge pull request #10 from httprunner/main

new pull request 2022.1.12
This commit is contained in:
xucong053
2022-01-12 14:59:38 +08:00
committed by GitHub
9 changed files with 94 additions and 18 deletions

View File

@@ -29,6 +29,9 @@ var boomCmd = &cobra.Command{
}
hrpBoomer := hrp.NewBoomer(spawnCount, spawnRate)
hrpBoomer.SetRateLimiter(maxRPS, requestIncreaseRate)
if loopCount > 0 {
hrpBoomer.SetLoopCount(loopCount)
}
if !disableConsoleOutput {
hrpBoomer.AddOutput(boomer.NewConsoleOutput())
}
@@ -45,6 +48,7 @@ var (
spawnCount int
spawnRate float64
maxRPS int64
loopCount int64
requestIncreaseRate string
memoryProfile string
memoryProfileDuration time.Duration

View File

@@ -29,8 +29,8 @@ Copyright 2021 debugtalk
### SEE ALSO
* [hrp boom](hrp_boom.md) - run load test with boomer
* [hrp har2case](hrp_har2case.md) - Convert HAR to json/yaml testcase files
* [hrp har2case](hrp_har2case.md) - convert HAR to json/yaml testcase files
* [hrp run](hrp_run.md) - run API test
* [hrp startproject](hrp_startproject.md) - Create a scaffold project
* [hrp startproject](hrp_startproject.md) - create a scaffold project
###### Auto generated by spf13/cobra on 8-Jan-2022
###### Auto generated by spf13/cobra on 12-Jan-2022

View File

@@ -38,4 +38,4 @@ hrp boom [flags]
* [hrp](hrp.md) - One-stop solution for HTTP(S) testing.
###### Auto generated by spf13/cobra on 8-Jan-2022
###### Auto generated by spf13/cobra on 12-Jan-2022

View File

@@ -1,10 +1,10 @@
## hrp har2case
Convert HAR to json/yaml testcase files
convert HAR to json/yaml testcase files
### Synopsis
Convert HAR to json/yaml testcase files
convert HAR to json/yaml testcase files
```
hrp har2case $har_path... [flags]
@@ -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 8-Jan-2022
###### Auto generated by spf13/cobra on 12-Jan-2022

View File

@@ -31,4 +31,4 @@ hrp run $path... [flags]
* [hrp](hrp.md) - One-stop solution for HTTP(S) testing.
###### Auto generated by spf13/cobra on 8-Jan-2022
###### Auto generated by spf13/cobra on 12-Jan-2022

View File

@@ -1,6 +1,6 @@
## hrp startproject
Create a scaffold project
create a scaffold project
```
hrp startproject $project_name [flags]
@@ -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 8-Jan-2022
###### Auto generated by spf13/cobra on 12-Jan-2022

View File

@@ -52,6 +52,11 @@ func (b *Boomer) SetRateLimiter(maxRPS int64, requestIncreaseRate string) {
}
}
// SetLoopCount set loop count for test.
func (b *Boomer) SetLoopCount(loopCount int64) {
b.localRunner.loop = &Loop{loopCount: loopCount}
}
// AddOutput accepts outputs which implements the boomer.Output interface.
func (b *Boomer) AddOutput(o Output) {
b.localRunner.addOutput(o)

View File

@@ -24,6 +24,31 @@ const (
reportStatsInterval = 3 * time.Second
)
type Loop struct {
loopCount int64 // more than 0
acquiredCount int64 // count acquired of load testing
finishedCount int64 // count finished of load testing
}
func (l *Loop) isFinished() bool {
// return true when there are no remaining loop count to test
return atomic.LoadInt64(&l.finishedCount) == l.loopCount
}
func (l *Loop) acquire() bool {
// get one ticket when there are still remaining loop count to test
// return true when getting ticket successfully
if atomic.LoadInt64(&l.acquiredCount) < l.loopCount {
atomic.AddInt64(&l.acquiredCount, 1)
return true
}
return false
}
func (l *Loop) increaseFinishedCount() {
atomic.AddInt64(&l.finishedCount, 1)
}
type runner struct {
state int32
@@ -37,6 +62,7 @@ type runner struct {
currentClientsNum int32 // current clients count
spawnCount int // target clients to spawn
spawnRate float64
loop *Loop // specify running cycles
outputs []Output
}
@@ -78,7 +104,7 @@ func (r *runner) outputOnStart() {
wg.Wait()
}
func (r *runner) outputOnEevent(data map[string]interface{}) {
func (r *runner) outputOnEvent(data map[string]interface{}) {
size := len(r.outputs)
if size == 0 {
return
@@ -110,7 +136,14 @@ func (r *runner) outputOnStop() {
wg.Wait()
}
func (r *runner) spawnWorkers(spawnCount int, spawnRate float64, quit chan bool, spawnCompleteFunc func()) {
func (r *runner) reportStats() {
data := r.stats.collectReportData()
data["user_count"] = atomic.LoadInt32(&r.currentClientsNum)
data["state"] = atomic.LoadInt32(&r.state)
r.outputOnEvent(data)
}
func (r *localRunner) spawnWorkers(spawnCount int, spawnRate float64, quit chan bool, spawnCompleteFunc func()) {
log.Info().
Int("spawnCount", spawnCount).
Float64("spawnRate", spawnRate).
@@ -135,6 +168,9 @@ func (r *runner) spawnWorkers(spawnCount int, spawnRate float64, quit chan bool,
case <-quit:
return
default:
if r.loop != nil && !r.loop.acquire() {
return
}
if r.rateLimitEnabled {
blocked := r.rateLimiter.Acquire()
if !blocked {
@@ -145,6 +181,12 @@ func (r *runner) spawnWorkers(spawnCount int, spawnRate float64, quit chan bool,
task := r.getTask()
r.safeRun(task.Fn)
}
if r.loop != nil {
r.loop.increaseFinishedCount()
if r.loop.isFinished() {
r.stop()
}
}
}
}
}()
@@ -250,10 +292,7 @@ func (r *localRunner) start() {
r.stats.logError(n.requestType, n.name, n.errMsg)
// report stats
case <-ticker.C:
data := r.stats.collectReportData()
data["user_count"] = atomic.LoadInt32(&r.currentClientsNum)
data["state"] = atomic.LoadInt32(&r.state)
r.outputOnEevent(data)
r.reportStats()
// stop
case <-r.stopChan:
atomic.StoreInt32(&r.state, stateQuitting)
@@ -267,6 +306,10 @@ func (r *localRunner) start() {
r.rateLimiter.Stop()
}
// report last stats
<-ticker.C
r.reportStats()
// output teardown
r.outputOnStop()

View File

@@ -1,8 +1,11 @@
package boomer
import (
"sync/atomic"
"testing"
"time"
"github.com/stretchr/testify/assert"
)
type HitOutput struct {
@@ -45,13 +48,13 @@ func TestOutputOnStart(t *testing.T) {
}
}
func TestOutputOnEevent(t *testing.T) {
func TestOutputOnEvent(t *testing.T) {
hitOutput := &HitOutput{}
hitOutput2 := &HitOutput{}
runner := &runner{}
runner.addOutput(hitOutput)
runner.addOutput(hitOutput2)
runner.outputOnEevent(nil)
runner.outputOnEvent(nil)
if !hitOutput.onEvent {
t.Error("hitOutput's OnEvent has not been called")
}
@@ -90,3 +93,24 @@ func TestLocalRunner(t *testing.T) {
time.Sleep(4 * time.Second)
runner.stop()
}
func TestLoopCount(t *testing.T) {
taskA := &Task{
Weight: 10,
Fn: func() {
time.Sleep(time.Second)
},
Name: "TaskA",
}
tasks := []*Task{taskA}
runner := newLocalRunner(2, 2)
runner.loop = &Loop{loopCount: 4}
runner.setTasks(tasks)
go runner.start()
ticker := time.NewTicker(4 * time.Second)
defer ticker.Stop()
<-ticker.C
if !assert.Equal(t, runner.loop.loopCount, atomic.LoadInt64(&runner.loop.finishedCount)) {
t.Fail()
}
}