mirror of
https://github.com/httprunner/httprunner.git
synced 2026-07-07 07:21:23 +08:00
fix: report transaction result
This commit is contained in:
@@ -18,7 +18,7 @@
|
|||||||
- [x] Supports `variables`/`extract`/`validate`/`hooks` mechanisms to create extremely complex test scenarios.
|
- [x] Supports `variables`/`extract`/`validate`/`hooks` mechanisms to create extremely complex test scenarios.
|
||||||
- [ ] Built-in integration of rich functions, and you can also use [`go plugin`][plugin] to create and call custom functions.
|
- [ ] Built-in integration of rich functions, and you can also use [`go plugin`][plugin] to create and call custom functions.
|
||||||
- [x] Inherit all powerful features of [`Boomer`][Boomer] and [`locust`][locust], you can run `load test` without extra work.
|
- [x] Inherit all powerful features of [`Boomer`][Boomer] and [`locust`][locust], you can run `load test` without extra work.
|
||||||
- [x] Use it as a `CLI tool` or as a `library` are both supported.
|
- [x] Using it as a `CLI tool` or a `library` are both supported.
|
||||||
|
|
||||||
See [CHANGELOG].
|
See [CHANGELOG].
|
||||||
|
|
||||||
|
|||||||
54
boomer.go
54
boomer.go
@@ -62,31 +62,47 @@ func (b *hrpBoomer) convertBoomerTask(testcase *TestCase) *boomer.Task {
|
|||||||
Weight: config.Weight,
|
Weight: config.Weight,
|
||||||
Fn: func() {
|
Fn: func() {
|
||||||
runner := NewRunner(nil).SetDebug(b.debug).Reset()
|
runner := NewRunner(nil).SetDebug(b.debug).Reset()
|
||||||
|
|
||||||
|
testcaseSuccess := true // flag whole testcase result
|
||||||
|
var transactionSuccess = true // flag current transaction result
|
||||||
|
|
||||||
startTime := time.Now()
|
startTime := time.Now()
|
||||||
for _, step := range testcase.TestSteps {
|
for _, step := range testcase.TestSteps {
|
||||||
stepData, err := runner.runStep(step, testcase.Config)
|
stepData, err := runner.runStep(step, testcase.Config)
|
||||||
|
if err != nil {
|
||||||
if stepData.stepType == stepTypeRendezvous {
|
// step failed
|
||||||
// TODO: implement rendezvous in boomer
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
// record transaction
|
|
||||||
if stepData.stepType == stepTypeTransaction {
|
|
||||||
if stepData.elapsed != 0 { // only record when transaction ends
|
|
||||||
b.RecordTransaction(stepData.name, stepData.elapsed, 0)
|
|
||||||
}
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
if err == nil {
|
|
||||||
b.RecordSuccess(step.Type(), step.Name(), stepData.elapsed, stepData.responseLength)
|
|
||||||
} else {
|
|
||||||
var elapsed int64
|
var elapsed int64
|
||||||
if stepData != nil {
|
if stepData != nil {
|
||||||
elapsed = stepData.elapsed
|
elapsed = stepData.elapsed
|
||||||
}
|
}
|
||||||
b.RecordFailure(step.Type(), step.Name(), elapsed, err.Error())
|
b.RecordFailure(step.Type(), step.Name(), elapsed, err.Error())
|
||||||
|
|
||||||
|
// update flag
|
||||||
|
testcaseSuccess = false
|
||||||
|
transactionSuccess = false
|
||||||
|
|
||||||
|
if runner.failfast {
|
||||||
|
log.Error().Err(err).Msg("abort running due to failfast setting")
|
||||||
|
break
|
||||||
|
}
|
||||||
|
log.Warn().Err(err).Msg("run step failed, continue next step")
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
// step success
|
||||||
|
if stepData.stepType == stepTypeTransaction {
|
||||||
|
// transaction
|
||||||
|
// FIXME: support nested transactions
|
||||||
|
if stepData.elapsed != 0 { // only record when transaction ends
|
||||||
|
b.RecordTransaction(stepData.name, transactionSuccess, stepData.elapsed, 0)
|
||||||
|
transactionSuccess = true // reset flag for next transaction
|
||||||
|
}
|
||||||
|
} else if stepData.stepType == stepTypeRendezvous {
|
||||||
|
// rendezvous
|
||||||
|
// TODO: implement rendezvous in boomer
|
||||||
|
} else {
|
||||||
|
// request or testcase step
|
||||||
|
b.RecordSuccess(step.Type(), step.Name(), stepData.elapsed, stepData.contentSize)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
endTime := time.Now()
|
endTime := time.Now()
|
||||||
@@ -96,12 +112,12 @@ func (b *hrpBoomer) convertBoomerTask(testcase *TestCase) *boomer.Task {
|
|||||||
if len(transaction) == 1 {
|
if len(transaction) == 1 {
|
||||||
// if transaction end time not exists, use testcase end time instead
|
// if transaction end time not exists, use testcase end time instead
|
||||||
duration := endTime.Sub(transaction[TransactionStart])
|
duration := endTime.Sub(transaction[TransactionStart])
|
||||||
b.RecordTransaction(name, duration.Milliseconds(), 0)
|
b.RecordTransaction(name, transactionSuccess, duration.Milliseconds(), 0)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// report testcase as a whole Action transaction, inspired by LoadRunner
|
// report testcase as a whole Action transaction, inspired by LoadRunner
|
||||||
b.RecordTransaction("Action", endTime.Sub(startTime).Milliseconds(), 0)
|
b.RecordTransaction("Action", testcaseSuccess, endTime.Sub(startTime).Milliseconds(), 0)
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,8 +1,9 @@
|
|||||||
# Release History
|
# Release History
|
||||||
|
|
||||||
## v0.3.0 (2021-12-13)
|
## v0.3.0 (2021-12-21)
|
||||||
|
|
||||||
- feat: implement transaction for load test
|
- feat: implement transaction mechanism for load test
|
||||||
|
- feat: support `--continue-on-failure` flag to continue running next step when failure occurs
|
||||||
|
|
||||||
## v0.2.2 (2021-12-07)
|
## v0.2.2 (2021-12-07)
|
||||||
|
|
||||||
|
|||||||
@@ -22,4 +22,4 @@ Copyright 2021 debugtalk
|
|||||||
* [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 run](hrp_run.md) - run API test
|
||||||
|
|
||||||
###### Auto generated by spf13/cobra on 20-Dec-2021
|
###### Auto generated by spf13/cobra on 21-Dec-2021
|
||||||
|
|||||||
@@ -39,4 +39,4 @@ hrp boom [flags]
|
|||||||
|
|
||||||
* [hrp](hrp.md) - One-stop solution for HTTP(S) testing.
|
* [hrp](hrp.md) - One-stop solution for HTTP(S) testing.
|
||||||
|
|
||||||
###### Auto generated by spf13/cobra on 20-Dec-2021
|
###### Auto generated by spf13/cobra on 21-Dec-2021
|
||||||
|
|||||||
@@ -23,4 +23,4 @@ hrp har2case harPath... [flags]
|
|||||||
|
|
||||||
* [hrp](hrp.md) - One-stop solution for HTTP(S) testing.
|
* [hrp](hrp.md) - One-stop solution for HTTP(S) testing.
|
||||||
|
|
||||||
###### Auto generated by spf13/cobra on 20-Dec-2021
|
###### Auto generated by spf13/cobra on 21-Dec-2021
|
||||||
|
|||||||
@@ -21,13 +21,14 @@ hrp run path... [flags]
|
|||||||
### Options
|
### Options
|
||||||
|
|
||||||
```
|
```
|
||||||
-h, --help help for run
|
--continue-on-failure continue running next step when failure occurs
|
||||||
-p, --proxy-url string set proxy url
|
-h, --help help for run
|
||||||
-s, --silent disable logging request & response details
|
-p, --proxy-url string set proxy url
|
||||||
|
-s, --silent disable logging request & response details
|
||||||
```
|
```
|
||||||
|
|
||||||
### SEE ALSO
|
### SEE ALSO
|
||||||
|
|
||||||
* [hrp](hrp.md) - One-stop solution for HTTP(S) testing.
|
* [hrp](hrp.md) - One-stop solution for HTTP(S) testing.
|
||||||
|
|
||||||
###### Auto generated by spf13/cobra on 20-Dec-2021
|
###### Auto generated by spf13/cobra on 21-Dec-2021
|
||||||
|
|||||||
@@ -20,7 +20,7 @@ var runCmd = &cobra.Command{
|
|||||||
for _, arg := range args {
|
for _, arg := range args {
|
||||||
paths = append(paths, &hrp.TestCasePath{Path: arg})
|
paths = append(paths, &hrp.TestCasePath{Path: arg})
|
||||||
}
|
}
|
||||||
runner := hrp.NewRunner(nil).SetDebug(!silentFlag)
|
runner := hrp.NewRunner(nil).SetDebug(!silentFlag).SetFailfast(!continueOnFailure)
|
||||||
if proxyUrl != "" {
|
if proxyUrl != "" {
|
||||||
runner.SetProxyUrl(proxyUrl)
|
runner.SetProxyUrl(proxyUrl)
|
||||||
}
|
}
|
||||||
@@ -29,12 +29,14 @@ var runCmd = &cobra.Command{
|
|||||||
}
|
}
|
||||||
|
|
||||||
var (
|
var (
|
||||||
silentFlag bool
|
continueOnFailure bool
|
||||||
proxyUrl string
|
silentFlag bool
|
||||||
|
proxyUrl string
|
||||||
)
|
)
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
RootCmd.AddCommand(runCmd)
|
RootCmd.AddCommand(runCmd)
|
||||||
|
runCmd.Flags().BoolVar(&continueOnFailure, "continue-on-failure", false, "continue running next step when failure occurs")
|
||||||
runCmd.Flags().BoolVarP(&silentFlag, "silent", "s", false, "disable logging request & response details")
|
runCmd.Flags().BoolVarP(&silentFlag, "silent", "s", false, "disable logging request & response details")
|
||||||
runCmd.Flags().StringVarP(&proxyUrl, "proxy-url", "p", "", "set proxy url")
|
runCmd.Flags().StringVarP(&proxyUrl, "proxy-url", "p", "", "set proxy url")
|
||||||
// runCmd.Flags().BoolP("gen-html-report", "r", false, "Generate HTML report")
|
// runCmd.Flags().BoolP("gen-html-report", "r", false, "Generate HTML report")
|
||||||
|
|||||||
12
models.go
12
models.go
@@ -142,10 +142,10 @@ func (tc *TestCase) ToTCase() (*TCase, error) {
|
|||||||
type testCaseSummary struct{}
|
type testCaseSummary struct{}
|
||||||
|
|
||||||
type stepData struct {
|
type stepData struct {
|
||||||
name string // step name
|
name string // step name
|
||||||
stepType stepType // step type, testcase/request/transaction/rendezvous
|
stepType stepType // step type, testcase/request/transaction/rendezvous
|
||||||
success bool // step execution result
|
success bool // step execution result
|
||||||
elapsed int64 // step execution time in millisecond(ms)
|
elapsed int64 // step execution time in millisecond(ms)
|
||||||
responseLength int64 // response body length
|
contentSize int64 // response body length
|
||||||
exportVars map[string]interface{} // extract variables
|
exportVars map[string]interface{} // extract variables
|
||||||
}
|
}
|
||||||
|
|||||||
40
runner.go
40
runner.go
@@ -32,8 +32,9 @@ func NewRunner(t *testing.T) *hrpRunner {
|
|||||||
t = &testing.T{}
|
t = &testing.T{}
|
||||||
}
|
}
|
||||||
return &hrpRunner{
|
return &hrpRunner{
|
||||||
t: t,
|
t: t,
|
||||||
debug: false, // default to turn off debug
|
failfast: true, // default to failfast
|
||||||
|
debug: false, // default to turn off debug
|
||||||
client: &http.Client{
|
client: &http.Client{
|
||||||
Transport: &http.Transport{
|
Transport: &http.Transport{
|
||||||
TLSClientConfig: &tls.Config{InsecureSkipVerify: true},
|
TLSClientConfig: &tls.Config{InsecureSkipVerify: true},
|
||||||
@@ -41,11 +42,13 @@ func NewRunner(t *testing.T) *hrpRunner {
|
|||||||
Timeout: 30 * time.Second,
|
Timeout: 30 * time.Second,
|
||||||
},
|
},
|
||||||
sessionVariables: make(map[string]interface{}),
|
sessionVariables: make(map[string]interface{}),
|
||||||
|
transactions: make(map[string]map[TransactionType]time.Time),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
type hrpRunner struct {
|
type hrpRunner struct {
|
||||||
t *testing.T
|
t *testing.T
|
||||||
|
failfast bool
|
||||||
debug bool
|
debug bool
|
||||||
client *http.Client
|
client *http.Client
|
||||||
sessionVariables map[string]interface{}
|
sessionVariables map[string]interface{}
|
||||||
@@ -64,6 +67,13 @@ func (r *hrpRunner) Reset() *hrpRunner {
|
|||||||
return r
|
return r
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// SetFailfast configures whether to stop running when one step fails.
|
||||||
|
func (r *hrpRunner) SetFailfast(failfast bool) *hrpRunner {
|
||||||
|
log.Info().Bool("failfast", failfast).Msg("[init] SetFailfast")
|
||||||
|
r.failfast = failfast
|
||||||
|
return r
|
||||||
|
}
|
||||||
|
|
||||||
// SetDebug configures whether to log HTTP request and response content.
|
// SetDebug configures whether to log HTTP request and response content.
|
||||||
func (r *hrpRunner) SetDebug(debug bool) *hrpRunner {
|
func (r *hrpRunner) SetDebug(debug bool) *hrpRunner {
|
||||||
log.Info().Bool("debug", debug).Msg("[init] SetDebug")
|
log.Info().Bool("debug", debug).Msg("[init] SetDebug")
|
||||||
@@ -123,7 +133,11 @@ func (r *hrpRunner) runCase(testcase *TestCase) error {
|
|||||||
for _, step := range testcase.TestSteps {
|
for _, step := range testcase.TestSteps {
|
||||||
_, err := r.runStep(step, config)
|
_, err := r.runStep(step, config)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
if r.failfast {
|
||||||
|
log.Error().Err(err).Msg("abort running due to failfast setting")
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
log.Warn().Err(err).Msg("run step failed, continue next step")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -206,11 +220,11 @@ func (r *hrpRunner) runStepTransaction(transaction *Transaction) (stepResult *st
|
|||||||
Msg("transaction")
|
Msg("transaction")
|
||||||
|
|
||||||
stepResult = &stepData{
|
stepResult = &stepData{
|
||||||
name: transaction.Name,
|
name: transaction.Name,
|
||||||
stepType: stepTypeTransaction,
|
stepType: stepTypeTransaction,
|
||||||
success: true,
|
success: true,
|
||||||
elapsed: 0,
|
elapsed: 0,
|
||||||
responseLength: 0, // TODO: record transaction total response length
|
contentSize: 0, // TODO: record transaction total response length
|
||||||
}
|
}
|
||||||
|
|
||||||
// create transaction if not exists
|
// create transaction if not exists
|
||||||
@@ -258,10 +272,10 @@ func (r *hrpRunner) runStepRendezvous(rend *Rendezvous) (stepResult *stepData, e
|
|||||||
|
|
||||||
func (r *hrpRunner) runStepRequest(step *TStep) (stepResult *stepData, err error) {
|
func (r *hrpRunner) runStepRequest(step *TStep) (stepResult *stepData, err error) {
|
||||||
stepResult = &stepData{
|
stepResult = &stepData{
|
||||||
name: step.Name,
|
name: step.Name,
|
||||||
stepType: stepTypeRequest,
|
stepType: stepTypeRequest,
|
||||||
success: false,
|
success: false,
|
||||||
responseLength: 0,
|
contentSize: 0,
|
||||||
}
|
}
|
||||||
|
|
||||||
rawUrl := step.Request.URL
|
rawUrl := step.Request.URL
|
||||||
@@ -420,7 +434,7 @@ func (r *hrpRunner) runStepRequest(step *TStep) (stepResult *stepData, err error
|
|||||||
}
|
}
|
||||||
|
|
||||||
stepResult.success = true
|
stepResult.success = true
|
||||||
stepResult.responseLength = resp.ContentLength
|
stepResult.contentSize = resp.ContentLength
|
||||||
return stepResult, nil
|
return stepResult, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user