4
4
"bytes"
5
5
"context"
6
6
"fmt"
7
+ "io"
7
8
"os/exec"
8
9
"regexp"
9
10
"strings"
@@ -14,13 +15,18 @@ import (
14
15
"golang.org/x/xerrors"
15
16
)
16
17
17
- // RunContainer specifies a runtime container for performing command tests
18
- type RunContainer struct {
19
- name string
20
- ctx context.Context
18
+ var (
19
+ _ runnable = & ContainerRunner {}
20
+ _ runnable = & HostRunner {}
21
+ )
22
+
23
+ type runnable interface {
24
+ Run (ctx context.Context , command string ) * Assertable
25
+ RunCmd (cmd * exec.Cmd ) * Assertable
26
+ io.Closer
21
27
}
22
28
23
- // ContainerConfig describes the RunContainer configuration schema for initializing a testing environment
29
+ // ContainerConfig describes the ContainerRunner configuration schema for initializing a testing environment
24
30
type ContainerConfig struct {
25
31
Name string
26
32
Image string
@@ -42,8 +48,14 @@ func preflightChecks() error {
42
48
return nil
43
49
}
44
50
45
- // NewRunContainer starts a new docker container for executing command tests
46
- func NewRunContainer (ctx context.Context , config * ContainerConfig ) (* RunContainer , error ) {
51
+ // ContainerRunner specifies a runtime container for performing command tests
52
+ type ContainerRunner struct {
53
+ name string
54
+ ctx context.Context
55
+ }
56
+
57
+ // NewContainerRunner starts a new docker container for executing command tests
58
+ func NewContainerRunner (ctx context.Context , config * ContainerConfig ) (* ContainerRunner , error ) {
47
59
if err := preflightChecks (); err != nil {
48
60
return nil , err
49
61
}
@@ -65,14 +77,14 @@ func NewRunContainer(ctx context.Context, config *ContainerConfig) (*RunContaine
65
77
config .Name , string (out ), err )
66
78
}
67
79
68
- return & RunContainer {
80
+ return & ContainerRunner {
69
81
name : config .Name ,
70
82
ctx : ctx ,
71
83
}, nil
72
84
}
73
85
74
86
// Close kills and removes the command execution testing container
75
- func (r * RunContainer ) Close () error {
87
+ func (r * ContainerRunner ) Close () error {
76
88
cmd := exec .CommandContext (r .ctx ,
77
89
"sh" , "-c" , strings .Join ([]string {
78
90
"docker" , "kill" , r .name , "&&" ,
@@ -88,43 +100,72 @@ func (r *RunContainer) Close() error {
88
100
return nil
89
101
}
90
102
103
+ type HostRunner struct {}
104
+
105
+ func (r * HostRunner ) Run (ctx context.Context , command string ) * Assertable {
106
+ var (
107
+ args []string
108
+ path string
109
+ parts = strings .Split (command , " " )
110
+ )
111
+ if len (parts ) > 0 {
112
+ path = parts [0 ]
113
+ }
114
+ if len (parts ) > 1 {
115
+ args = parts [1 :]
116
+ }
117
+ return & Assertable {
118
+ cmd : exec .CommandContext (ctx , path , args ... ),
119
+ tname : command ,
120
+ }
121
+ }
122
+
123
+ func (r * HostRunner ) RunCmd (cmd * exec.Cmd ) * Assertable {
124
+ return & Assertable {
125
+ cmd : cmd ,
126
+ tname : strings .Join (cmd .Args , " " ),
127
+ }
128
+ }
129
+
130
+ func (r * HostRunner ) Close () error {
131
+ return nil
132
+ }
133
+
91
134
// Assertable describes an initialized command ready to be run and asserted against
92
135
type Assertable struct {
93
- cmd * exec.Cmd
94
- ctx context.Context
95
- container * RunContainer
136
+ cmd * exec.Cmd
137
+ tname string
96
138
}
97
139
98
140
// Run executes the given command in the runtime container with reasonable defaults
99
- func (r * RunContainer ) Run (ctx context.Context , command string ) * Assertable {
141
+ func (r * ContainerRunner ) Run (ctx context.Context , command string ) * Assertable {
100
142
cmd := exec .CommandContext (ctx ,
101
143
"docker" , "exec" , "-i" , r .name ,
102
144
"sh" , "-c" , command ,
103
145
)
104
146
105
147
return & Assertable {
106
- cmd : cmd ,
107
- ctx : ctx ,
108
- container : r ,
148
+ cmd : cmd ,
149
+ tname : command ,
109
150
}
110
151
}
111
152
112
153
// RunCmd lifts the given *exec.Cmd into the runtime container
113
- func (r * RunContainer ) RunCmd (cmd * exec.Cmd ) * Assertable {
154
+ func (r * ContainerRunner ) RunCmd (cmd * exec.Cmd ) * Assertable {
114
155
path , _ := exec .LookPath ("docker" )
115
156
cmd .Path = path
116
157
command := strings .Join (cmd .Args , " " )
117
- cmd .Args = append ( []string {"docker" , "exec" , "-i" , r .name , "sh" , "-c" , command })
158
+ cmd .Args = []string {"docker" , "exec" , "-i" , r .name , "sh" , "-c" , command }
118
159
119
160
return & Assertable {
120
- cmd : cmd ,
121
- container : r ,
161
+ cmd : cmd ,
162
+ tname : command ,
122
163
}
123
164
}
124
165
125
166
// Assert runs the Assertable and
126
167
func (a Assertable ) Assert (t * testing.T , option ... Assertion ) {
127
- t .Run (strings . Join ( a . cmd . Args [ 6 :], " " ) , func (t * testing.T ) {
168
+ t .Run (a . tname , func (t * testing.T ) {
128
169
var cmdResult CommandResult
129
170
130
171
var (
@@ -225,7 +266,7 @@ func StdoutEmpty() Assertion {
225
266
}
226
267
227
268
// GetResult offers an escape hatch from tcli
228
- // The passed pointer will be assigned to the commands *CommandResult
269
+ // The pointer passed as "result" will be assigned to the command's *CommandResult
229
270
func GetResult (result * * CommandResult ) Assertion {
230
271
return simpleFuncAssert {
231
272
valid : func (r * CommandResult ) error {
0 commit comments