fix: gen html report path

This commit is contained in:
debugtalk
2022-04-17 10:41:31 +08:00
parent 19479ea4bd
commit 86e7da2aee
9 changed files with 45 additions and 34 deletions

View File

@@ -35,4 +35,4 @@ Copyright 2021 debugtalk
* [hrp run](hrp_run.md) - run API test with go engine * [hrp run](hrp_run.md) - run API test with go engine
* [hrp startproject](hrp_startproject.md) - create a scaffold project * [hrp startproject](hrp_startproject.md) - create a scaffold project
###### Auto generated by spf13/cobra on 16-Apr-2022 ###### Auto generated by spf13/cobra on 17-Apr-2022

View File

@@ -41,4 +41,4 @@ hrp boom [flags]
* [hrp](hrp.md) - Next-Generation API Testing Solution. * [hrp](hrp.md) - Next-Generation API Testing Solution.
###### Auto generated by spf13/cobra on 16-Apr-2022 ###### Auto generated by spf13/cobra on 17-Apr-2022

View File

@@ -24,4 +24,4 @@ hrp har2case $har_path... [flags]
* [hrp](hrp.md) - Next-Generation API Testing Solution. * [hrp](hrp.md) - Next-Generation API Testing Solution.
###### Auto generated by spf13/cobra on 16-Apr-2022 ###### Auto generated by spf13/cobra on 17-Apr-2022

View File

@@ -16,4 +16,4 @@ hrp pytest $path ... [flags]
* [hrp](hrp.md) - Next-Generation API Testing Solution. * [hrp](hrp.md) - Next-Generation API Testing Solution.
###### Auto generated by spf13/cobra on 16-Apr-2022 ###### Auto generated by spf13/cobra on 17-Apr-2022

View File

@@ -34,4 +34,4 @@ hrp run $path... [flags]
* [hrp](hrp.md) - Next-Generation API Testing Solution. * [hrp](hrp.md) - Next-Generation API Testing Solution.
###### Auto generated by spf13/cobra on 16-Apr-2022 ###### Auto generated by spf13/cobra on 17-Apr-2022

View File

@@ -19,4 +19,4 @@ hrp startproject $project_name [flags]
* [hrp](hrp.md) - Next-Generation API Testing Solution. * [hrp](hrp.md) - Next-Generation API Testing Solution.
###### Auto generated by spf13/cobra on 16-Apr-2022 ###### Auto generated by spf13/cobra on 17-Apr-2022

View File

@@ -19,15 +19,17 @@ const (
hashicorpPyPluginFile = "debugtalk.py" // used for hashicorp python plugin hashicorpPyPluginFile = "debugtalk.py" // used for hashicorp python plugin
) )
func initPlugin(path string, logOn bool) (plugin funplugin.IPlugin, err error) { func initPlugin(path string, logOn bool) (plugin funplugin.IPlugin, pluginDir string, err error) {
// plugin file not found // plugin file not found
if path == "" { if path == "" {
return nil, nil return nil, "", nil
} }
pluginPath, err := locatePlugin(path) pluginPath, err := locatePlugin(path)
if err != nil { if err != nil {
return nil, nil return nil, "", nil
} }
// TODO: move pluginDir to funplugin
pluginDir = filepath.Dir(pluginPath)
// found plugin file // found plugin file
plugin, err = funplugin.Init(pluginPath, funplugin.WithLogOn(logOn)) plugin, err = funplugin.Init(pluginPath, funplugin.WithLogOn(logOn))

View File

@@ -2,11 +2,9 @@ package hrp
import ( import (
"crypto/tls" "crypto/tls"
"fmt"
"net" "net"
"net/http" "net/http"
"net/url" "net/url"
"path/filepath"
"testing" "testing"
"time" "time"
@@ -15,7 +13,6 @@ import (
"github.com/rs/zerolog/log" "github.com/rs/zerolog/log"
"golang.org/x/net/http2" "golang.org/x/net/http2"
"github.com/httprunner/httprunner/hrp/internal/builtin"
"github.com/httprunner/httprunner/hrp/internal/sdk" "github.com/httprunner/httprunner/hrp/internal/sdk"
) )
@@ -175,22 +172,9 @@ func (r *HRPRunner) Run(testcases ...ITestCase) error {
} }
s.Time.Duration = time.Since(s.Time.StartAt).Seconds() s.Time.Duration = time.Since(s.Time.StartAt).Seconds()
// update the report output path
pluginPath, err := locatePlugin(testcases[0].GetPath())
if err == nil {
outputPath, _ := filepath.Split(pluginPath)
summaryPath = filepath.Join(outputPath, summaryPath)
reportPath = filepath.Join(outputPath, reportPath)
}
// save summary // save summary
if r.saveTests { if r.saveTests {
dir, _ := filepath.Split(summaryPath) err := s.genSummary()
err := builtin.EnsureFolderExists(dir)
if err != nil {
return err
}
err = builtin.Dump2JSON(s, fmt.Sprintf(summaryPath, s.Time.StartAt.Unix()))
if err != nil { if err != nil {
return err return err
} }
@@ -229,11 +213,12 @@ func (r *HRPRunner) newCaseRunner(testcase *TestCase) (*testCaseRunner, error) {
} }
// init parser plugin // init parser plugin
plugin, err := initPlugin(testcase.Config.Path, r.pluginLogOn) plugin, pluginDir, err := initPlugin(testcase.Config.Path, r.pluginLogOn)
if err != nil { if err != nil {
return nil, errors.Wrap(err, "init plugin failed") return nil, errors.Wrap(err, "init plugin failed")
} }
runner.parser.plugin = plugin runner.parser.plugin = plugin
runner.rootDir = pluginDir
// parse testcase config // parse testcase config
if err := runner.parseConfig(); err != nil { if err := runner.parseConfig(); err != nil {
@@ -249,6 +234,7 @@ type testCaseRunner struct {
parser *Parser parser *Parser
parsedConfig *TConfig parsedConfig *TConfig
parametersIterator *ParametersIterator parametersIterator *ParametersIterator
rootDir string // project root dir
} }
// parseConfig parses testcase config, stores to parsedConfig. // parseConfig parses testcase config, stores to parsedConfig.

View File

@@ -38,6 +38,7 @@ type Summary struct {
Time *TestCaseTime `json:"time" yaml:"time"` Time *TestCaseTime `json:"time" yaml:"time"`
Platform *Platform `json:"platform" yaml:"platform"` Platform *Platform `json:"platform" yaml:"platform"`
Details []*TestCaseSummary `json:"details" yaml:"details"` Details []*TestCaseSummary `json:"details" yaml:"details"`
rootDir string
} }
func (s *Summary) appendCaseSummary(caseSummary *TestCaseSummary) { func (s *Summary) appendCaseSummary(caseSummary *TestCaseSummary) {
@@ -53,15 +54,24 @@ func (s *Summary) appendCaseSummary(caseSummary *TestCaseSummary) {
s.Stat.TestSteps.Failures += caseSummary.Stat.Failures s.Stat.TestSteps.Failures += caseSummary.Stat.Failures
s.Details = append(s.Details, caseSummary) s.Details = append(s.Details, caseSummary)
s.Success = s.Success && caseSummary.Success s.Success = s.Success && caseSummary.Success
// specify output reports dir
if len(s.Details) == 1 {
s.rootDir = caseSummary.RootDir
} else if s.rootDir != caseSummary.RootDir {
// if multiple testcases have different root path, use current working dir
s.rootDir, _ = os.Getwd()
}
} }
func (s *Summary) genHTMLReport() error { func (s *Summary) genHTMLReport() error {
dir, _ := filepath.Split(reportPath) reportsDir := filepath.Join(s.rootDir, resultsDir)
err := builtin.EnsureFolderExists(dir) err := builtin.EnsureFolderExists(reportsDir)
if err != nil { if err != nil {
return err return err
} }
reportPath := fmt.Sprintf(reportPath, s.Time.StartAt.Unix())
reportPath := filepath.Join(reportsDir, fmt.Sprintf("report-%v.html", s.Time.StartAt.Unix()))
file, err := os.OpenFile(reportPath, os.O_WRONLY|os.O_CREATE, 0666) file, err := os.OpenFile(reportPath, os.O_WRONLY|os.O_CREATE, 0666)
if err != nil { if err != nil {
log.Error().Err(err).Msg("open file failed") log.Error().Err(err).Msg("open file failed")
@@ -84,13 +94,25 @@ func (s *Summary) genHTMLReport() error {
return err return err
} }
func (s *Summary) genSummary() error {
reportsDir := filepath.Join(s.rootDir, resultsDir)
err := builtin.EnsureFolderExists(reportsDir)
if err != nil {
return err
}
summaryPath := filepath.Join(reportsDir, fmt.Sprintf("summary-%v.json", s.Time.StartAt.Unix()))
err = builtin.Dump2JSON(s, summaryPath)
if err != nil {
return err
}
return nil
}
//go:embed internal/scaffold/templates/report/template.html //go:embed internal/scaffold/templates/report/template.html
var reportTemplate string var reportTemplate string
var ( const resultsDir = "reports"
reportPath = "reports/report-%v.html"
summaryPath = "reports/summary-%v.json"
)
type Stat struct { type Stat struct {
TestCases TestCaseStat `json:"testcases" yaml:"test_cases"` TestCases TestCaseStat `json:"testcases" yaml:"test_cases"`
@@ -130,6 +152,7 @@ type TestCaseSummary struct {
InOut *TestCaseInOut `json:"in_out" yaml:"in_out"` InOut *TestCaseInOut `json:"in_out" yaml:"in_out"`
Log string `json:"log,omitempty" yaml:"log,omitempty"` // TODO Log string `json:"log,omitempty" yaml:"log,omitempty"` // TODO
Records []*StepResult `json:"records" yaml:"records"` Records []*StepResult `json:"records" yaml:"records"`
RootDir string `json:"root_dir" yaml:"root_dir"`
} }
type TestCaseInOut struct { type TestCaseInOut struct {