Skip to content
This repository was archived by the owner on Aug 30, 2024. It is now read-only.

Commit 2932fe9

Browse files
committed
Add RunCmd manual command
1 parent 8e8b215 commit 2932fe9

File tree

2 files changed

+81
-20
lines changed

2 files changed

+81
-20
lines changed

Diff for: ci/integration/integration_test.go

+16-1
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@ package integration
22

33
import (
44
"context"
5+
"os/exec"
6+
"strings"
57
"testing"
68
"time"
79

@@ -12,7 +14,11 @@ import (
1214
func TestTCli(t *testing.T) {
1315
ctx := context.Background()
1416

15-
container, err := tcli.NewRunContainer(ctx, "ubuntu:latest", "test-container")
17+
container, err := tcli.NewRunContainer(ctx, &tcli.ContainerConfig{
18+
Image: "ubuntu:latest",
19+
Name: "test-container",
20+
})
21+
1622
assert.Success(t, "new run container", err)
1723
defer container.Close()
1824

@@ -28,4 +34,13 @@ func TestTCli(t *testing.T) {
2834
tcli.StderrMatches("message"),
2935
tcli.DurationGreaterThan(time.Second),
3036
)
37+
38+
cmd := exec.CommandContext(ctx, "cat")
39+
cmd.Stdin = strings.NewReader("testing")
40+
41+
container.RunCmd(cmd).Assert(t,
42+
tcli.Success(),
43+
tcli.StderrEmpty(),
44+
tcli.StdoutMatches("testing"),
45+
)
3146
}

Diff for: ci/tcli/tcli.go

+65-19
Original file line numberDiff line numberDiff line change
@@ -19,23 +19,51 @@ type RunContainer struct {
1919
ctx context.Context
2020
}
2121

22-
func NewRunContainer(ctx context.Context, image, name string) (*RunContainer, error) {
23-
cmd := exec.CommandContext(ctx,
24-
"docker", "run",
25-
"--name", name,
22+
type ContainerConfig struct {
23+
Name string
24+
Image string
25+
Mounts map[string]string
26+
}
27+
28+
func mountArgs(m map[string]string) (args []string) {
29+
for src, dest := range m {
30+
args = append(args, "--mount", fmt.Sprintf("source=%s,target=%s", src, dest))
31+
}
32+
return args
33+
}
34+
35+
func preflightChecks() error {
36+
_, err := exec.LookPath("docker")
37+
if err != nil {
38+
return xerrors.Errorf(`"docker" not found in $PATH`)
39+
}
40+
return nil
41+
}
42+
43+
func NewRunContainer(ctx context.Context, config *ContainerConfig) (*RunContainer, error) {
44+
if err := preflightChecks(); err != nil {
45+
return nil, err
46+
}
47+
48+
args := []string{
49+
"run",
50+
"--name", config.Name,
2651
"-it", "-d",
27-
image,
28-
)
52+
}
53+
args = append(args, mountArgs(config.Mounts)...)
54+
args = append(args, config.Image)
55+
56+
cmd := exec.CommandContext(ctx, "docker", args...)
2957

3058
out, err := cmd.CombinedOutput()
3159
if err != nil {
3260
return nil, xerrors.Errorf(
3361
"failed to start testing container %q, (%s): %w",
34-
name, string(out), err)
62+
config.Name, string(out), err)
3563
}
3664

3765
return &RunContainer{
38-
name: name,
66+
name: config.Name,
3967
ctx: ctx,
4068
}, nil
4169
}
@@ -57,36 +85,51 @@ func (r *RunContainer) Close() error {
5785
}
5886

5987
type Assertable struct {
60-
cmd string
88+
cmd *exec.Cmd
6189
ctx context.Context
6290
container *RunContainer
6391
}
6492

65-
func (r *RunContainer) Run(ctx context.Context, cmd string) *Assertable {
93+
// Run executes the given command in the runtime container with reasonable defaults
94+
func (r *RunContainer) Run(ctx context.Context, command string) *Assertable {
95+
cmd := exec.CommandContext(ctx,
96+
"docker", "exec", "-i", r.name,
97+
"sh", "-c", command,
98+
)
99+
66100
return &Assertable{
67101
cmd: cmd,
68102
ctx: ctx,
69103
container: r,
70104
}
71105
}
72106

107+
// RunCmd lifts the given *exec.Cmd into the runtime container
108+
func (r *RunContainer) RunCmd(cmd *exec.Cmd) *Assertable {
109+
path, _ := exec.LookPath("docker")
110+
cmd.Path = path
111+
command := strings.Join(cmd.Args, " ")
112+
cmd.Args = append([]string{"docker", "exec", "-i", r.name, "sh", "-c", command})
113+
114+
return &Assertable{
115+
cmd: cmd,
116+
container: r,
117+
}
118+
}
119+
73120
func (a Assertable) Assert(t *testing.T, option ...Assertion) {
74121
var cmdResult CommandResult
75122

76-
cmd := exec.CommandContext(a.ctx,
77-
"docker", "exec", a.container.name,
78-
"sh", "-c", a.cmd,
79-
)
80123
var (
81124
stdout bytes.Buffer
82125
stderr bytes.Buffer
83126
)
84127

85-
cmd.Stdout = &stdout
86-
cmd.Stderr = &stderr
128+
a.cmd.Stdout = &stdout
129+
a.cmd.Stderr = &stderr
87130

88131
start := time.Now()
89-
err := cmd.Run()
132+
err := a.cmd.Run()
90133
cmdResult.Duration = time.Since(start)
91134

92135
if exitErr, ok := err.(*exec.ExitError); ok {
@@ -147,7 +190,7 @@ func ExitCodeIs(code int) Assertion {
147190
return simpleFuncAssert{
148191
valid: func(r CommandResult) error {
149192
if r.ExitCode != code {
150-
return xerrors.Errorf("exit code of %s expected, got %v", code, r.ExitCode)
193+
return xerrors.Errorf("exit code of %v expected, got %v", code, r.ExitCode)
151194
}
152195
return nil
153196
},
@@ -209,7 +252,10 @@ func matches(name, pattern string, target []byte) error {
209252
return xerrors.Errorf("failed to attempt regexp match: %w", err)
210253
}
211254
if !ok {
212-
return xerrors.Errorf("expected to find pattern (%s) in %s, no match found", pattern, name)
255+
return xerrors.Errorf(
256+
"expected to find pattern (%s) in %s, no match found in (%v)",
257+
pattern, name, string(target),
258+
)
213259
}
214260
return nil
215261
}

0 commit comments

Comments
 (0)