Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: skip support at step level #592

Merged
merged 4 commits into from
Oct 18, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
32 changes: 30 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ Venom is a CLI (Command Line Interface) that aim to create, manage and run your
* [Export tests report](#export-tests-report)
* [Advanced usage](#advanced-usage)
* [Debug your testsuites](#debug-your-testsuites)
* [Skip testcase](#skip-testcase)
* [Skip testcase and teststeps](#skip-testcase-and-teststeps)
* [Iterating over data](#iterating-over-data)
* [FAQ](#faq)
* [Common errors with quotes](#common-errors-with-quotes)
Expand Down Expand Up @@ -774,7 +774,7 @@ $ venom run test.yml
[info] the value of result.systemoutjson is map[foo:bar] (exec.yml:34)
```

## Skip testcase
## Skip testcase and teststeps

It is possible to skip `testcase` according to some `assertions`. For instance, the following example will skip the last testcase.

Expand Down Expand Up @@ -810,6 +810,34 @@ testcases:

```

A `skip` statement may also be placed at steps level to partially execute a testcase.
If all steps from a testcase are skipped, the testcase itself will also be treated as "skipped" rather than "passed"/"failed".

```yaml
name: "Skip testsuite"
vars:
foo: bar

testcases:
- name: skip-one-of-these
steps:
- name: do-not-skip-this
type: exec
script: exit 0
assertions:
- result.code ShouldEqual 0
skip:
- foo ShouldNotBeEmpty
- name: skip-this
type: exec
script: exit 1
assertions:
- result.code ShouldEqual 0
skip:
- foo ShouldBeEmpty

```

## Iterating over data

It is possible to iterate over data using `range` attribute.
Expand Down
61 changes: 49 additions & 12 deletions process_testcase.go
Original file line number Diff line number Diff line change
Expand Up @@ -302,24 +302,31 @@ func (v *Venom) runTestSteps(ctx context.Context, tc *TestCase, tsIn *TestStepRe
printStepName := v.Verbose >= 1 && !fromUserExecutor
v.setTestStepName(tsResult, e, step, &ranged, &rangedData, rangedIndex, printStepName)

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Diff below looks complicated but it actually just move all the code related to v.RunTestStep to the else block of the if skip conditional

tsResult.Start = time.Now()

// ##### RUN Test Step Here
tsResult.Status = StatusRun
result := v.RunTestStep(ctx, e, tc, tsResult, stepNumber, rangedIndex, step)
if len(tsResult.Errors) > 0 || !tsResult.AssertionsApplied.OK {
skip, err := parseSkip(ctx, tc, tsResult, rawStep, stepNumber)
if err != nil {
tsResult.appendError(err)
tsResult.Status = StatusFail
} else if skip {
tsResult.Status = StatusSkip
} else {
tsResult.Status = StatusPass
}
tsResult.Start = time.Now()
tsResult.Status = StatusRun
result := v.RunTestStep(ctx, e, tc, tsResult, stepNumber, rangedIndex, step)
if len(tsResult.Errors) > 0 || !tsResult.AssertionsApplied.OK {
tsResult.Status = StatusFail
} else {
tsResult.Status = StatusPass
}

tsResult.End = time.Now()
tsResult.Duration = tsResult.End.Sub(tsResult.Start).Seconds()
tsResult.End = time.Now()
tsResult.Duration = tsResult.End.Sub(tsResult.Start).Seconds()

mapResult := GetExecutorResult(result)
previousStepVars.AddAll(H(mapResult))
mapResult := GetExecutorResult(result)
previousStepVars.AddAll(H(mapResult))

tc.testSteps = append(tc.testSteps, step)
tc.testSteps = append(tc.testSteps, step)
}

var isRequired bool

Expand Down Expand Up @@ -401,13 +408,43 @@ func (v *Venom) printTestStepResult(tc *TestCase, ts *TestStepResult, tsIn *Test
v.Println(" \t\t %s", Gray(fmt.Sprintf("%d other steps were skipped", skipped)))
}
}
} else if ts.Status == StatusSkip {
v.Println(" %s", Gray(StatusSkip))
} else {
v.Println(" %s", Green(StatusPass))
}
}
}
}

// Parse and format skip conditional
func parseSkip(ctx context.Context, tc *TestCase, ts *TestStepResult, rawStep []byte, stepNumber int) (bool, error) {
// Load "skip" attribute from step
var assertions struct {
Skip []string `yaml:"skip"`
}
if err := yaml.Unmarshal(rawStep, &assertions); err != nil {
return false, fmt.Errorf("unable to parse \"skip\" assertions: %v", err)
}

// Evaluate skip assertions
if len(assertions.Skip) > 0 {
results, err := testConditionalStatement(ctx, tc, assertions.Skip, tc.Vars, fmt.Sprintf("skipping testcase %%q step #%d: %%v", stepNumber))
if err != nil {
Error(ctx, "unable to evaluate \"skip\" assertions: %v", err)
return false, err
}
if len(results) > 0 {
for _, s := range results {
ts.Skipped = append(ts.Skipped, Skipped{Value: s})
Warn(ctx, s)
}
return true, nil
}
}
return false, nil
}

// Parse and format range data to allow iterations over user data
func parseRanged(ctx context.Context, rawStep []byte, stepVars H) (Range, error) {

Expand Down
20 changes: 16 additions & 4 deletions process_testsuite.go
Original file line number Diff line number Diff line change
Expand Up @@ -111,27 +111,33 @@ func (v *Venom) runTestCases(ctx context.Context, ts *TestSuite) {
start := time.Now()
tc.Start = start
ts.Status = StatusRun
if verboseReport || hasRanged {
v.Print("\n")
}
// ##### RUN Test Case Here
v.runTestCase(ctx, ts, tc)
tc.End = time.Now()
tc.Duration = tc.End.Sub(tc.Start).Seconds()
}

skippedSteps := 0
for _, testStepResult := range tc.TestStepResults {
if testStepResult.RangedEnable {
hasRanged = true
}
if testStepResult.Status == StatusFail {
hasFailure = true
}
}

if verboseReport || hasRanged {
v.Print("\n")
if testStepResult.Status == StatusSkip {
skippedSteps++
}
}

if hasFailure {
tc.Status = StatusFail
} else if skippedSteps == len(tc.TestStepResults) {
//If all test steps were skipped, consider the test case as skipped
tc.Status = StatusSkip
} else if tc.Status != StatusSkip {
tc.Status = StatusPass
}
Expand All @@ -140,6 +146,12 @@ func (v *Venom) runTestCases(ctx context.Context, ts *TestSuite) {
indent := ""
if hasRanged || verboseReport {
indent = "\t "
// If the testcase was entirely skipped, then the verbose mode will not have any output
// Print something to inform that the testcase was indeed processed although skipped
if len(tc.TestStepResults) == 0 {
v.Println("\t\t%s", Gray("• (all steps were skipped)"))
continue
}
} else {
if hasFailure {
v.Println(" %s", Red(StatusFail))
Expand Down
29 changes: 28 additions & 1 deletion tests/skip.yml
Original file line number Diff line number Diff line change
Expand Up @@ -25,4 +25,31 @@ testcases:
- type: exec
script: command_not_found
assertions:
- result.code ShouldEqual 0
- result.code ShouldEqual 0

- name: skip-one-of-these
steps:
- name: do-not-skip-this
type: exec
script: exit 0
assertions:
- result.code ShouldEqual 0
skip:
- foo ShouldNotBeEmpty
- name: skip-this
type: exec
script: exit 1
assertions:
- result.code ShouldEqual 0
skip:
- foo ShouldBeEmpty

- name: skip-all-of-steps
steps:
- name: skip-this
type: exec
script: exit 1
assertions:
- result.code ShouldEqual 0
skip:
- foo ShouldBeEmpty
1 change: 1 addition & 0 deletions types.go
Original file line number Diff line number Diff line change
Expand Up @@ -175,6 +175,7 @@ type TestCase struct {
type TestStepResult struct {
Name string `json:"name"`
Errors []Failure `json:"errors"`
Skipped []Skipped `json:"skipped" yaml:"skipped"`
Status string `json:"status" yaml:"status"`
Raw interface{} `json:"raw" yaml:"raw"`
Interpolated interface{} `json:"interpolated" yaml:"interpolated"`
Expand Down