Merge 'merge-wings' into 'master'

fix: create results dir

See merge request: !100
This commit is contained in:
李隆
2025-06-17 11:41:12 +00:00
7 changed files with 123 additions and 43 deletions

View File

@@ -8,6 +8,7 @@ import (
"github.com/spf13/cobra" "github.com/spf13/cobra"
hrp "github.com/httprunner/httprunner/v5" hrp "github.com/httprunner/httprunner/v5"
"github.com/httprunner/httprunner/v5/internal/config"
) )
var CmdReport = &cobra.Command{ var CmdReport = &cobra.Command{
@@ -24,9 +25,9 @@ Examples:
resultFolder := args[0] resultFolder := args[0]
// Construct file paths // Construct file paths
summaryFile := filepath.Join(resultFolder, "summary.json") summaryFile := filepath.Join(resultFolder, config.SummaryFileName)
logFile := filepath.Join(resultFolder, "hrp.log") logFile := filepath.Join(resultFolder, config.LogFileName)
reportFile := filepath.Join(resultFolder, "report.html") reportFile := filepath.Join(resultFolder, config.ReportFileName)
// Generate HTML report // Generate HTML report
if err := hrp.GenerateHTMLReportFromFiles(summaryFile, logFile, reportFile); err != nil { if err := hrp.GenerateHTMLReportFromFiles(summaryFile, logFile, reportFile); err != nil {

View File

@@ -12,21 +12,32 @@ import (
) )
const ( const (
ResultsDirName = "results" // results directory names
DownloadsDirName = "downloads" ResultsDirName = "results" // $PWD/results/
ScreenshotsDirName = "screenshots" DownloadsDirName = "downloads" // $PWD/results/20060102150405/downloads/
ActionLogDirName = "action_log" ScreenshotsDirName = "screenshots" // $PWD/results/20060102150405/screenshots/
ActionLogDirName = "action_log" // $PWD/results/20060102150405/action_log/
// results file names
SummaryFileName = "hrp_summary.json" // $PWD/results/20060102150405/hrp_summary.json
LogFileName = "hrp.log" // $PWD/results/20060102150405/hrp.log
ReportFileName = "report.html" // $PWD/results/20060102150405/report.html
// mobile device path
DeviceActionLogFilePath = "/sdcard/Android/data/io.appium.uiautomator2.server/files/hodor"
) )
type Config struct { type Config struct {
RootDir string StartTime time.Time
resultsPath string RootDir string
downloadsPath string resultsPath string
screenShotsPath string downloadsPath string
StartTime time.Time screenShotsPath string
ActionLogFilePath string summaryFilePath string
DeviceActionLogFilePath string logFilePath string
mu sync.Mutex reportFilePath string
actionLogDirPath string
mu sync.Mutex
} }
var ( var (
@@ -51,20 +62,15 @@ func GetConfig() *Config {
cfg.resultsPath = filepath.Join(cfg.RootDir, resultsDir) cfg.resultsPath = filepath.Join(cfg.RootDir, resultsDir)
cfg.downloadsPath = filepath.Join(cfg.RootDir, filepath.Join(DownloadsDirName, startTimeStr)) cfg.downloadsPath = filepath.Join(cfg.RootDir, filepath.Join(DownloadsDirName, startTimeStr))
cfg.screenShotsPath = filepath.Join(cfg.resultsPath, ScreenshotsDirName) cfg.screenShotsPath = filepath.Join(cfg.resultsPath, ScreenshotsDirName)
cfg.ActionLogFilePath = filepath.Join(resultsDir, ActionLogDirName) cfg.actionLogDirPath = filepath.Join(resultsDir, ActionLogDirName)
cfg.DeviceActionLogFilePath = "/sdcard/Android/data/io.appium.uiautomator2.server/files/hodor"
globalConfig = cfg globalConfig = cfg
}) })
return globalConfig return globalConfig
} }
// ResultsPath returns the results path and creates the directory if it doesn't exist // resultsPathUnlocked returns the results path and creates the directory if it doesn't exist (internal use, no lock)
func (c *Config) ResultsPath() string { func (c *Config) resultsPathUnlocked() string {
c.mu.Lock()
defer c.mu.Unlock()
// Check if directory exists, create if it doesn't // Check if directory exists, create if it doesn't
if _, err := os.Stat(c.resultsPath); os.IsNotExist(err) { if _, err := os.Stat(c.resultsPath); os.IsNotExist(err) {
if err := builtin.EnsureFolderExists(c.resultsPath); err != nil { if err := builtin.EnsureFolderExists(c.resultsPath); err != nil {
@@ -76,6 +82,14 @@ func (c *Config) ResultsPath() string {
return c.resultsPath return c.resultsPath
} }
// ResultsPath returns the results path and creates the directory if it doesn't exist
func (c *Config) ResultsPath() string {
c.mu.Lock()
defer c.mu.Unlock()
return c.resultsPathUnlocked()
}
// DownloadsPath returns the downloads path and creates the directory if it doesn't exist // DownloadsPath returns the downloads path and creates the directory if it doesn't exist
func (c *Config) DownloadsPath() string { func (c *Config) DownloadsPath() string {
c.mu.Lock() c.mu.Lock()
@@ -107,3 +121,61 @@ func (c *Config) ScreenShotsPath() string {
} }
return c.screenShotsPath return c.screenShotsPath
} }
// $PWD/results/20060102150405/action_log/
func (c *Config) ActionLogDirPath() string {
c.mu.Lock()
defer c.mu.Unlock()
// Check if directory exists, create if it doesn't
if _, err := os.Stat(c.actionLogDirPath); os.IsNotExist(err) {
if err := builtin.EnsureFolderExists(c.actionLogDirPath); err != nil {
log.Fatal().Err(err).Str("path", c.actionLogDirPath).Msg("failed to create action log directory")
} else {
log.Info().Str("path", c.actionLogDirPath).Msg("created action log folder")
}
}
return c.actionLogDirPath
}
// $PWD/results/20060102150405/hrp_summary.json
func (c *Config) SummaryFilePath() string {
c.mu.Lock()
defer c.mu.Unlock()
if c.summaryFilePath != "" {
return c.summaryFilePath
}
// Ensure directory creation and set cached path
c.summaryFilePath = filepath.Join(c.resultsPathUnlocked(), SummaryFileName)
return c.summaryFilePath
}
// $PWD/results/20060102150405/hrp.log
func (c *Config) LogFilePath() string {
c.mu.Lock()
defer c.mu.Unlock()
if c.logFilePath != "" {
return c.logFilePath
}
// Ensure directory creation and set cached path
c.logFilePath = filepath.Join(c.resultsPathUnlocked(), LogFileName)
return c.logFilePath
}
// $PWD/results/20060102150405/report.html
func (c *Config) ReportFilePath() string {
c.mu.Lock()
defer c.mu.Unlock()
if c.reportFilePath != "" {
return c.reportFilePath
}
// Ensure directory creation and set cached path
c.reportFilePath = filepath.Join(c.resultsPathUnlocked(), ReportFileName)
return c.reportFilePath
}

View File

@@ -1 +1 @@
v5.0.0-beta-2506150047 v5.0.0-beta-2506171409

View File

@@ -3,7 +3,6 @@ package hrp
import ( import (
"io" "io"
"os" "os"
"path/filepath"
"runtime" "runtime"
"strings" "strings"
"time" "time"
@@ -65,8 +64,7 @@ func InitLogger(logLevel string, logJSON bool, logFile bool) {
} }
// file writer - write to results/taskID/hrp.log // file writer - write to results/taskID/hrp.log
cfg := config.GetConfig() logFilePath := config.GetConfig().LogFilePath()
logFilePath := filepath.Join(cfg.ResultsPath(), "hrp.log")
// create or open log file // create or open log file
logFileWriter, err := os.OpenFile(logFilePath, os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0o666) logFileWriter, err := os.OpenFile(logFilePath, os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0o666)

View File

@@ -3,7 +3,6 @@ package hrp
import ( import (
_ "embed" _ "embed"
"fmt" "fmt"
"path/filepath"
"runtime" "runtime"
"time" "time"
@@ -76,17 +75,11 @@ func (s *Summary) AddCaseSummary(caseSummary *TestCaseSummary) {
} }
} }
func (s *Summary) GetResultsPath() string {
return config.GetConfig().ResultsPath()
}
func (s *Summary) GenHTMLReport() error { func (s *Summary) GenHTMLReport() error {
reportsDir := s.GetResultsPath()
// Find summary.json and hrp.log files // Find summary.json and hrp.log files
summaryPath := filepath.Join(reportsDir, "summary.json") summaryPath := config.GetConfig().SummaryFilePath()
logPath := filepath.Join(reportsDir, "hrp.log") logPath := config.GetConfig().LogFilePath()
reportPath := filepath.Join(reportsDir, "report.html") reportPath := config.GetConfig().ReportFilePath()
// Check if summary.json exists, if not create it first // Check if summary.json exists, if not create it first
if !builtin.FileExists(summaryPath) { if !builtin.FileExists(summaryPath) {
@@ -99,8 +92,7 @@ func (s *Summary) GenHTMLReport() error {
} }
func (s *Summary) GenSummary() (path string, err error) { func (s *Summary) GenSummary() (path string, err error) {
reportsDir := config.GetConfig().ResultsPath() path = config.GetConfig().SummaryFilePath()
path = filepath.Join(reportsDir, "summary.json")
err = builtin.Dump2JSON(s, path) err = builtin.Dump2JSON(s, path)
if err != nil { if err != nil {
return "", err return "", err
@@ -108,6 +100,22 @@ func (s *Summary) GenSummary() (path string, err error) {
return path, nil return path, nil
} }
func (s *Summary) GetResultsPath() string {
return config.GetConfig().ResultsPath()
}
func (s *Summary) GetSummaryFilePath() string {
return config.GetConfig().SummaryFilePath()
}
func (s *Summary) GetLogFilePath() string {
return config.GetConfig().LogFilePath()
}
func (s *Summary) GetReportFilePath() string {
return config.GetConfig().ReportFilePath()
}
type Stat struct { type Stat struct {
TestCases TestCaseStat `json:"testcases" yaml:"testcases"` TestCases TestCaseStat `json:"testcases" yaml:"testcases"`
TestSteps TestStepStat `json:"teststeps" yaml:"teststeps"` TestSteps TestStepStat `json:"teststeps" yaml:"teststeps"`

View File

@@ -100,7 +100,7 @@ type AndroidDevice struct {
func (dev *AndroidDevice) Setup() error { func (dev *AndroidDevice) Setup() error {
dev.Device.RunShellCommand("ime", "enable", option.UnicodeImePackageName) dev.Device.RunShellCommand("ime", "enable", option.UnicodeImePackageName)
dev.Device.RunShellCommand("rm", "-r", config.GetConfig().DeviceActionLogFilePath) dev.Device.RunShellCommand("rm", "-r", config.DeviceActionLogFilePath)
// setup evalite // setup evalite
evalToolRaw, err := evalite.ReadFile("evalite") evalToolRaw, err := evalite.ReadFile("evalite")

View File

@@ -676,10 +676,11 @@ func (ad *ADBDriver) StopCaptureLog() (result interface{}, err error) {
// 没有解析到打点日志,走兜底逻辑 // 没有解析到打点日志,走兜底逻辑
if len(pointRes) == 0 { if len(pointRes) == 0 {
log.Info().Msg("action log is null, use action file >>>") log.Info().Msg("action log is null, use action file >>>")
logFilePathPrefix := fmt.Sprintf("%v/data", config.GetConfig().ActionLogFilePath) actionLogDirPath := config.GetConfig().ActionLogDirPath()
logFilePathPrefix := fmt.Sprintf("%v/data", actionLogDirPath)
files := []string{} files := []string{}
ad.Device.RunShellCommand("pull", config.GetConfig().DeviceActionLogFilePath, config.GetConfig().ActionLogFilePath) ad.Device.RunShellCommand("pull", config.DeviceActionLogFilePath, actionLogDirPath)
err = filepath.Walk(config.GetConfig().ActionLogFilePath, func(path string, info fs.FileInfo, err error) error { err = filepath.Walk(actionLogDirPath, func(path string, info fs.FileInfo, err error) error {
// 只是需要日志文件 // 只是需要日志文件
if ok := strings.Contains(path, logFilePathPrefix); ok { if ok := strings.Contains(path, logFilePathPrefix); ok {
files = append(files, path) files = append(files, path)