Skip to content

Commit 2299eae

Browse files
committed
shell: add exit code check functionality
1 parent 2036bd6 commit 2299eae

File tree

6 files changed

+106
-3
lines changed

6 files changed

+106
-3
lines changed

dictionary.yml

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -420,6 +420,26 @@ handlers:
420420
description: substring of the message
421421
type: string
422422

423+
- name: exit_code_equal
424+
description: check exit code is equal given value
425+
handle: checkExitCodeEqual
426+
expressions:
427+
- $resource exit code equal to $exit_code
428+
parameters:
429+
- name: exit_code
430+
description: exit code of the executed command
431+
type: number
432+
433+
- name: exit_code_not_equal
434+
description: check exit code is not equal given value
435+
handle: checkExitCodeNotEqual
436+
expressions:
437+
- $resource exit code not equal to $exit_code
438+
parameters:
439+
- name: exit_code
440+
description: exit code of the executed command
441+
type: number
442+
423443
- name: cache
424444
description: cache driver that interacts with a cache service
425445
resources:

docs/resources.md

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -338,6 +338,20 @@ Given $resource stderr should not contains $substring
338338
339339
```
340340

341+
#### **Exit Code Equal**
342+
check exit code is equal given value
343+
```gherkin
344+
Given $resource exit code equal to $exit_code
345+
346+
```
347+
348+
#### **Exit Code Not Equal**
349+
check exit code is not equal given value
350+
```gherkin
351+
Given $resource exit code not equal to $exit_code
352+
353+
```
354+
341355

342356

343357
## Cache

examples/features/shell.feature

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,9 @@ Feature: shell features example
22

33
Scenario: Create file and check if file exist
44
Given "shell-cli" execute "touch helloworld"
5+
Given "shell-cli" exit code equal to 0
6+
Given "shell-cli" execute "rm some-not-exist-file"
7+
Given "shell-cli" exit code not equal to 0
58
Then "shell-cli" execute "ls"
69
Then "shell-cli" stdout should contains "helloworld"
710
Then "shell-cli" execute "rm helloworld"

handler/shell/handler.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,4 +10,6 @@ func (h *Handler) Register(s *godog.Suite) {
1010
s.Step(`^"([^"]*)" stdout should not contains "([^"]*)"$`, h.checkStdoutNotContains)
1111
s.Step(`^"([^"]*)" stderr should contains "([^"]*)"$`, h.checkStderrContains)
1212
s.Step(`^"([^"]*)" stderr should not contains "([^"]*)"$`, h.checkStderrNotContains)
13+
s.Step(`^"([^"]*)" exit code equal to (\d+)$`, h.checkExitCodeEqual)
14+
s.Step(`^"([^"]*)" exit code not equal to (\d+)$`, h.checkExitCodeNotEqual)
1315
}

handler/shell/shell.go

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ type Resource interface {
1313
Exec(command string, arguments ...string) error
1414
Stdout() (string, error)
1515
Stderr() (string, error)
16+
ExitCode() (int, error)
1617
}
1718

1819
type Handler struct {
@@ -104,3 +105,39 @@ func (h *Handler) checkStderrNotContains(resourceName, message string) error {
104105

105106
return nil
106107
}
108+
109+
func (h *Handler) checkExitCodeEqual(resourceName string, expectedExitCode int) error {
110+
r, ok := h.r[resourceName]
111+
if !ok {
112+
return fmt.Errorf("%s not found", resourceName)
113+
}
114+
115+
exitCode, err := r.ExitCode()
116+
if err != nil {
117+
return err
118+
}
119+
120+
if exitCode != expectedExitCode {
121+
return fmt.Errorf("expecting exit code to be %d, got %d", expectedExitCode, exitCode)
122+
}
123+
124+
return nil
125+
}
126+
127+
func (h *Handler) checkExitCodeNotEqual(resourceName string, unexpectedExitCode int) error {
128+
r, ok := h.r[resourceName]
129+
if !ok {
130+
return fmt.Errorf("%s not found", resourceName)
131+
}
132+
133+
exitCode, err := r.ExitCode()
134+
if err != nil {
135+
return err
136+
}
137+
138+
if exitCode == unexpectedExitCode {
139+
return fmt.Errorf("expecting exit code not to be %d, got %d", unexpectedExitCode, exitCode)
140+
}
141+
142+
return nil
143+
}

resource/shell/shell.go

Lines changed: 30 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,18 +2,21 @@ package shell
22

33
import (
44
"errors"
5+
"fmt"
56
"os/exec"
67
"strings"
78
"sync"
9+
"syscall"
810

911
"github.com/tomatool/tomato/config"
1012
)
1113

1214
type Shell struct {
1315
prefix []string
1416

15-
stdout string
16-
stderr string
17+
stdout string
18+
stderr string
19+
exitCode int
1720
}
1821

1922
func New(cfg *config.Resource) (*Shell, error) {
@@ -48,9 +51,24 @@ func (s *Shell) Exec(command string, arguments ...string) error {
4851
}
4952

5053
cmd := exec.Command(arguments[0], arguments[1:]...)
54+
5155
cmd.Stdout = newWriter(&s.stdout)
5256
cmd.Stderr = newWriter(&s.stderr)
53-
return cmd.Run()
57+
58+
if err := cmd.Start(); err != nil {
59+
return fmt.Errorf("shell: %v\nstdout: %s\nstderr: %s", err, s.stdout, s.stderr)
60+
}
61+
62+
if err := cmd.Wait(); err != nil {
63+
if exiterr, ok := err.(*exec.ExitError); ok {
64+
if status, ok := exiterr.Sys().(syscall.WaitStatus); ok {
65+
s.exitCode = status.ExitStatus()
66+
}
67+
} else {
68+
return fmt.Errorf("shell: %v\nstdout: %s\nstderr: %s", err, s.stdout, s.stderr)
69+
}
70+
}
71+
return nil
5472
}
5573
func (s *Shell) Stdout() (string, error) {
5674
defer func() { s.stdout = "" }()
@@ -70,6 +88,15 @@ func (s *Shell) Stderr() (string, error) {
7088

7189
return s.stderr, nil
7290
}
91+
func (s *Shell) ExitCode() (int, error) {
92+
defer func() { s.exitCode = 0 }()
93+
94+
if s.exitCode == 0 {
95+
return s.exitCode, nil
96+
}
97+
98+
return s.exitCode, nil
99+
}
73100

74101
type writer struct {
75102
mtx sync.Mutex

0 commit comments

Comments
 (0)