feat: add Shell step type

This commit is contained in:
lilong.129
2024-01-18 23:35:35 +08:00
parent dce414e892
commit 70c91a9f5a
7 changed files with 229 additions and 43 deletions
+39
View File
@@ -155,6 +155,45 @@ func TestRunCaseWithThinkTime(t *testing.T) {
}
}
func TestRunCaseWithShell(t *testing.T) {
testcase1 := &TestCase{
Config: NewConfig("complex shell with multiple commands"),
TestSteps: []IStep{
NewStep("shell21").Shell("A=123; echo $A"),
NewStep("shell22").Shell("A=123 && echo $A"),
NewStep("shell23").Shell("export A=123 && echo $A"),
NewStep("shell24").Shell("for i in {1..5}; do echo $i; sleep 1; done"),
},
}
testcase2 := &TestCase{
Config: NewConfig("complex shell with environment variables"),
TestSteps: []IStep{
NewStep("shell3").Shell("A=123; echo $A"),
},
}
testcase3 := &TestCase{
Config: NewConfig("check shell exit code"),
TestSteps: []IStep{
NewStep("shell21").
Shell("ls -a; exit 3; exit 5").
Validate().
AssertExitCode(3),
NewStep("shell22").
Shell("ls -a; exit 3 && exit 5").
Validate().
AssertExitCode(3),
},
}
r := NewRunner(t)
err := r.Run(testcase1, testcase2, testcase3)
if err != nil {
t.Fatal()
}
}
func TestRunCaseWithPluginJSON(t *testing.T) {
buildHashicorpGoPlugin()
defer removeHashicorpGoPlugin()
+2
View File
@@ -12,6 +12,7 @@ const (
stepTypeWebSocket StepType = "websocket"
stepTypeAndroid StepType = "android"
stepTypeIOS StepType = "ios"
stepTypeShell StepType = "shell"
)
type StepResult struct {
@@ -40,6 +41,7 @@ type TStep struct {
WebSocket *WebSocketAction `json:"websocket,omitempty" yaml:"websocket,omitempty"`
Android *MobileStep `json:"android,omitempty" yaml:"android,omitempty"`
IOS *MobileStep `json:"ios,omitempty" yaml:"ios,omitempty"`
Shell *Shell `json:"shell,omitempty" yaml:"shell,omitempty"`
Variables map[string]interface{} `json:"variables,omitempty" yaml:"variables,omitempty"`
SetupHooks []string `json:"setup_hooks,omitempty" yaml:"setup_hooks,omitempty"`
TeardownHooks []string `json:"teardown_hooks,omitempty" yaml:"teardown_hooks,omitempty"`
+11
View File
@@ -769,6 +769,17 @@ func (s *StepRequest) IOS() *StepMobile {
}
}
// Shell creates a new shell action
func (s *StepRequest) Shell(content string) *StepShell {
s.step.Shell = &Shell{
String: content,
}
return &StepShell{
step: s.step,
}
}
// StepRequestWithOptionalArgs implements IStep interface.
type StepRequestWithOptionalArgs struct {
step *TStep
+119
View File
@@ -0,0 +1,119 @@
package hrp
import (
"fmt"
"time"
"github.com/httprunner/funplugin/myexec"
"github.com/pkg/errors"
"github.com/rs/zerolog/log"
)
type Shell struct {
String string `json:"string" yaml:"string"`
ExpectExitCode int `json:"expect_exit_code" yaml:"expect_exit_code"`
}
// StepShell implements IStep interface.
type StepShell struct {
step *TStep
}
func (s *StepShell) Name() string {
return s.step.Name
}
func (s *StepShell) Type() StepType {
return stepTypeShell
}
func (s *StepShell) Struct() *TStep {
return s.step
}
func (s *StepShell) Run(r *SessionRunner) (*StepResult, error) {
return runStepShell(r, s.step)
}
// Validate switches to step validation.
func (s *StepShell) Validate() *StepShellValidation {
return &StepShellValidation{
step: s.step,
}
}
// StepShellValidation implements IStep interface.
type StepShellValidation struct {
step *TStep
}
func (s *StepShellValidation) Name() string {
if s.step.Name != "" {
return s.step.Name
}
return fmt.Sprintf("%s %s", s.step.Request.Method, s.step.Request.URL)
}
func (s *StepShellValidation) Type() StepType {
if s.step.Request != nil {
return StepType(fmt.Sprintf("request-%v", s.step.Request.Method))
}
if s.step.WebSocket != nil {
return StepType(fmt.Sprintf("websocket-%v", s.step.WebSocket.Type))
}
return "validation"
}
func (s *StepShellValidation) Struct() *TStep {
return s.step
}
func (s *StepShellValidation) Run(r *SessionRunner) (*StepResult, error) {
return runStepShell(r, s.step)
}
func (s *StepShellValidation) AssertExitCode(expected int) *StepShellValidation {
s.step.Shell.ExpectExitCode = expected
return s
}
func runStepShell(r *SessionRunner, step *TStep) (stepResult *StepResult, err error) {
shell := step.Shell
log.Info().
Str("name", step.Name).
Str("type", string(stepTypeShell)).
Str("content", shell.String).
Msg("run shell string")
stepResult = &StepResult{
Name: step.Name,
StepType: stepTypeShell,
Success: false,
Elapsed: 0,
ContentSize: 0,
}
start := time.Now()
exitCode, err := myexec.RunShell(shell.String)
stepResult.Elapsed = time.Since(start).Milliseconds()
if err != nil {
if exitCode == shell.ExpectExitCode {
// get expected error
stepResult.Success = true
return stepResult, nil
}
err = errors.Wrap(err, "exec shell string failed")
return
}
// validate response
if exitCode != shell.ExpectExitCode {
err = fmt.Errorf("unexpected exit code %d, expect %d",
exitCode, shell.ExpectExitCode)
return
}
stepResult.Success = true
return stepResult, nil
}