forked from commander-cli/commander
/
runtime.go
168 lines (144 loc) · 4.06 KB
/
runtime.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
package runtime
import (
"log"
"sort"
"time"
)
// Constants for defining the various tested properties
const (
ExitCode = "ExitCode"
Stdout = "Stdout"
Stderr = "Stderr"
LineCount = "LineCount"
)
type Filters []string
// NewRuntime creates a new runtime and inits default nodes
func NewRuntime(eh *EventHandler, nodes ...Node) Runtime {
local := Node{
Name: "local",
Type: "local",
Addr: "localhost",
}
nodes = append(nodes, local)
runner := Runner{
Nodes: nodes,
}
return Runtime{
Runner: &runner,
EventHandler: eh,
}
}
// Runtime represents the current runtime, please use NewRuntime() instead of creating an instance directly
type Runtime struct {
Runner *Runner
EventHandler *EventHandler
}
// EventHandler is a configurable event system that handles events such as test completion
type EventHandler struct {
TestFinished func(TestResult)
TestSkipped func(TestResult)
}
// TestCase represents a test case which will be executed by the runtime
type TestCase struct {
Title string
Command CommandUnderTest
Expected Expected
Result CommandResult
Nodes []string
FileName string
Skip bool
}
//GlobalTestConfig represents the configuration for a test
type GlobalTestConfig struct {
Env map[string]string
Dir string
Timeout string
Retries int
Interval string
InheritEnv bool
Nodes []string
}
// ResultStatus represents the status code of a test result
type ResultStatus int
// CommandResult holds the result for a specific test
type CommandResult struct {
Status ResultStatus
Stdout string
Stderr string
ExitCode int
FailureProperties []string
Error error
}
//Expected is the expected output of the command under test
type Expected struct {
Stdout ExpectedOut
Stderr ExpectedOut
LineCount int
ExitCode int
}
//ExpectedOut represents the assertions on stdout and stderr
type ExpectedOut struct {
Contains []string `yaml:"contains,omitempty"`
Lines map[int]string `yaml:"lines,omitempty"`
Exactly string `yaml:"exactly,omitempty"`
LineCount int `yaml:"line-count,omitempty"`
NotContains []string `yaml:"not-contains,omitempty"`
JSON map[string]string `yaml:"json,omitempty"`
XML map[string]string `yaml:"xml,omitempty"`
File string `yaml:"file,omitempty"`
}
// CommandUnderTest represents the command under test
type CommandUnderTest struct {
Cmd string
InheritEnv bool
Env map[string]string
Dir string
Timeout string
Retries int
Interval string
}
// TestResult represents the TestCase and the ValidationResult
type TestResult struct {
TestCase TestCase
ValidationResult ValidationResult
FailedProperty string
Tries int
Node string
Skipped bool
}
// Result respresents the aggregation of all TestResults/summary of a runtime
type Result struct {
TestResults []TestResult
Duration time.Duration
Failed int
Skipped int
}
// Start starts the given test suite and executes all tests
func (r *Runtime) Start(tests []TestCase) Result {
// Sort tests alphabetically to preserve a reproducible execution order
sort.SliceStable(tests, func(i, j int) bool {
return tests[i].Title < tests[j].Title
})
result := Result{}
testCh := r.Runner.Run(tests)
start := time.Now()
for tr := range testCh {
if tr.Skipped {
result.Skipped++
log.Println("title: '"+tr.TestCase.Title+"'", " was skipped")
log.Println("title: '"+tr.TestCase.Title+"'", " Command: ", tr.TestCase.Command.Cmd)
log.Println("title: '"+tr.TestCase.Title+"'", " Directory: ", tr.TestCase.Command.Dir)
log.Println("title: '"+tr.TestCase.Title+"'", " Env: ", tr.TestCase.Command.Env)
r.EventHandler.TestSkipped(tr)
result.TestResults = append(result.TestResults, tr)
continue
}
if !tr.ValidationResult.Success {
result.Failed++
}
r.EventHandler.TestFinished(tr)
result.TestResults = append(result.TestResults, tr)
}
result.Duration = time.Since(start)
return result
}