diff --git a/hrp/boomer.go b/hrp/boomer.go index f66679d3..0e74fe5d 100644 --- a/hrp/boomer.go +++ b/hrp/boomer.go @@ -5,7 +5,6 @@ import ( "sync" "time" - "github.com/jinzhu/copier" "github.com/rs/zerolog/log" "github.com/httprunner/funplugin" @@ -98,27 +97,21 @@ func (b *HRPBoomer) convertBoomerTask(testcase *TestCase, rendezvousList []*Rend Name: config.Name, Weight: config.Weight, Fn: func() { - sessionTestCase := &TestCase{} - // copy testcase to avoid data racing - if err := copier.Copy(sessionTestCase, testcase); err != nil { - log.Error().Err(err).Msg("copy testcase data failed") - return - } - sessionRunner := hrpRunner.NewSessionRunner(sessionTestCase) + sessionRunner := hrpRunner.NewSessionRunner(testcase) sessionRunner.parser.plugin = plugin testcaseSuccess := true // flag whole testcase result var transactionSuccess = true // flag current transaction result - cfg := sessionTestCase.Config + var parameterVariables map[string]interface{} // iterate through all parameter iterators and update case variables - for _, it := range cfg.ParametersSetting.Iterators { + for _, it := range testcase.Config.ParametersSetting.Iterators { if it.HasNext() { - cfg.Variables = mergeVariables(it.Next(), cfg.Variables) + parameterVariables = it.Next() } } - if err := sessionRunner.parseConfig(cfg); err != nil { + if err := sessionRunner.parseConfig(parameterVariables); err != nil { log.Error().Err(err).Msg("parse config failed") return } diff --git a/hrp/session.go b/hrp/session.go index 05173830..f59e6d01 100644 --- a/hrp/session.go +++ b/hrp/session.go @@ -4,6 +4,7 @@ import ( _ "embed" "time" + "github.com/jinzhu/copier" "github.com/pkg/errors" "github.com/rs/zerolog/log" ) @@ -14,6 +15,7 @@ type SessionRunner struct { testCase *TestCase hrpRunner *HRPRunner parser *Parser + parsedConfig *TConfig sessionVariables map[string]interface{} // transactions stores transaction timing info. // key is transaction name, value is map of transaction type and time, e.g. start time and end time. @@ -24,10 +26,10 @@ type SessionRunner struct { func (r *SessionRunner) init() { log.Info().Msg("init session runner") + r.parsedConfig = &TConfig{} r.sessionVariables = make(map[string]interface{}) r.transactions = make(map[string]map[transactionType]time.Time) r.startTime = time.Now() - r.summary.Name = r.testCase.Config.Name } func (r *SessionRunner) GetParser() *Parser { @@ -35,7 +37,7 @@ func (r *SessionRunner) GetParser() *Parser { } func (r *SessionRunner) GetConfig() *TConfig { - return r.testCase.Config + return r.parsedConfig } func (r *SessionRunner) LogOn() bool { @@ -62,7 +64,7 @@ func (r *SessionRunner) Start() error { }() // parse config - if err := r.parseConfig(config); err != nil { + if err := r.parseConfig(nil); err != nil { return err } @@ -105,56 +107,67 @@ func (r *SessionRunner) MergeStepVariables(vars map[string]interface{}) (map[str // step variables > session variables (extracted variables from previous steps) overrideVars := mergeVariables(vars, r.sessionVariables) // step variables > testcase config variables - overrideVars = mergeVariables(overrideVars, r.testCase.Config.Variables) + overrideVars = mergeVariables(overrideVars, r.parsedConfig.Variables) // parse step variables parsedVariables, err := r.parser.ParseVariables(overrideVars) if err != nil { - log.Error().Interface("variables", r.testCase.Config.Variables). + log.Error().Interface("variables", r.parsedConfig.Variables). Err(err).Msg("parse step variables failed") return nil, err } return parsedVariables, nil } -func (r *SessionRunner) parseConfig(cfg *TConfig) error { +// parseConfig parses testcase config with given variables, stores to parsedConfig. +func (r *SessionRunner) parseConfig(variables map[string]interface{}) error { + cfg := r.testCase.Config + + // deep copy config to avoid data racing + if err := copier.Copy(r.parsedConfig, cfg); err != nil { + log.Error().Err(err).Msg("copy testcase config failed") + return err + } + // parse config variables - parsedVariables, err := r.parser.ParseVariables(cfg.Variables) + mergedVars := mergeVariables(variables, cfg.Variables) + parsedVariables, err := r.parser.ParseVariables(mergedVars) if err != nil { log.Error().Interface("variables", cfg.Variables).Err(err).Msg("parse config variables failed") return err } - cfg.Variables = parsedVariables + r.parsedConfig.Variables = parsedVariables // parse config name parsedName, err := r.parser.ParseString(cfg.Name, cfg.Variables) if err != nil { return err } - cfg.Name = convertString(parsedName) + r.parsedConfig.Name = convertString(parsedName) // parse config base url parsedBaseURL, err := r.parser.ParseString(cfg.BaseURL, cfg.Variables) if err != nil { return err } - cfg.BaseURL = convertString(parsedBaseURL) + r.parsedConfig.BaseURL = convertString(parsedBaseURL) // ensure correction of think time config - cfg.ThinkTimeSetting.checkThinkTime() + r.parsedConfig.ThinkTimeSetting.checkThinkTime() return nil } func (r *SessionRunner) GetSummary() *TestCaseSummary { caseSummary := r.summary + caseSummary.Name = r.parsedConfig.Name caseSummary.Time.StartAt = r.startTime caseSummary.Time.Duration = time.Since(r.startTime).Seconds() exportVars := make(map[string]interface{}) - for _, value := range r.testCase.Config.Export { + for _, value := range r.parsedConfig.Export { exportVars[value] = r.sessionVariables[value] } caseSummary.InOut.ExportVars = exportVars - caseSummary.InOut.ConfigVars = r.testCase.Config.Variables + caseSummary.InOut.ConfigVars = r.parsedConfig.Variables return caseSummary } diff --git a/hrp/step_request_test.go b/hrp/step_request_test.go index 50becbec..ae61fa2c 100644 --- a/hrp/step_request_test.go +++ b/hrp/step_request_test.go @@ -81,6 +81,7 @@ func TestRunRequestRun(t *testing.T) { } runner := NewRunner(t).SetRequestsLogOn() sessionRunner := runner.NewSessionRunner(testcase) + sessionRunner.parseConfig(nil) if _, err := stepGET.Run(sessionRunner); err != nil { t.Fatalf("stepGET.Run() error: %v", err) } diff --git a/hrp/step_testcase.go b/hrp/step_testcase.go index 031133a5..4692be58 100644 --- a/hrp/step_testcase.go +++ b/hrp/step_testcase.go @@ -55,18 +55,24 @@ func (s *StepTestCaseWithOptionalArgs) Run(r *SessionRunner) (*StepResult, error return stepResult, err } - // copy step to avoid data racing - copiedStep := &TStep{} - if err := copier.Copy(copiedStep, s.step); err != nil { - log.Error().Err(err).Msg("copy step failed") + stepTestCase := s.step.TestCase.(*TestCase) + + // copy testcase to avoid data racing + copiedTestCase := &TestCase{} + if err := copier.Copy(copiedTestCase, stepTestCase); err != nil { + log.Error().Err(err).Msg("copy step testcase failed") return stepResult, err } - copiedStep.Variables = stepVariables - copiedTestCase := copiedStep.TestCase.(*TestCase) - // override testcase config - extendWithTestCase(s.step, copiedTestCase) + // override testcase name + if s.step.Name != "" { + copiedTestCase.Config.Name = s.step.Name + } + // merge & override variables + copiedTestCase.Config.Variables = mergeVariables(stepVariables, copiedTestCase.Config.Variables) + // merge & override extractors + copiedTestCase.Config.Export = mergeSlices(s.step.Export, copiedTestCase.Config.Export) sessionRunner := r.hrpRunner.NewSessionRunner(copiedTestCase) @@ -84,11 +90,6 @@ func (s *StepTestCaseWithOptionalArgs) Run(r *SessionRunner) (*StepResult, error stepResult.ExportVars = summary.InOut.ExportVars stepResult.Success = true - // update extracted variables - for k, v := range stepResult.ExportVars { - r.sessionVariables[k] = v - } - // merge testcase summary r.summary.Records = append(r.summary.Records, summary.Records...) r.summary.Stat.Total += summary.Stat.Total @@ -97,15 +98,3 @@ func (s *StepTestCaseWithOptionalArgs) Run(r *SessionRunner) (*StepResult, error return stepResult, nil } - -// extend referenced testcase with teststep, teststep config merge and override referenced testcase config -func extendWithTestCase(testStep *TStep, overriddenTestCase *TestCase) { - // override testcase name - if testStep.Name != "" { - overriddenTestCase.Config.Name = testStep.Name - } - // merge & override variables - overriddenTestCase.Config.Variables = mergeVariables(testStep.Variables, overriddenTestCase.Config.Variables) - // merge & override extractors - overriddenTestCase.Config.Export = mergeSlices(testStep.Export, overriddenTestCase.Config.Export) -} diff --git a/hrp/step_thinktime.go b/hrp/step_thinktime.go index ad158061..9abb20d5 100644 --- a/hrp/step_thinktime.go +++ b/hrp/step_thinktime.go @@ -38,7 +38,7 @@ func (s *StepThinkTime) Run(r *SessionRunner) (*StepResult, error) { Success: true, } - cfg := r.testCase.Config.ThinkTimeSetting + cfg := r.parsedConfig.ThinkTimeSetting if cfg == nil { cfg = &ThinkTimeConfig{thinkTimeDefault, nil, 0} }