Skip to content

Commit 4f559f9

Browse files
author
Christian Weichel
committed
[dazzle-util] Added support for running tests locally
1 parent a7a4433 commit 4f559f9

10 files changed

Lines changed: 553 additions & 87 deletions

File tree

cmd/core/test-add.go

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@ import (
3838
"github.com/32leaves/dazzle/pkg/dazzle"
3939
"github.com/32leaves/dazzle/pkg/fancylog"
4040
"github.com/32leaves/dazzle/pkg/test"
41+
containertest "github.com/32leaves/dazzle/pkg/test/container"
4142
)
4243

4344
var testAddCmd = &cobra.Command{
@@ -116,7 +117,11 @@ var testAddCmd = &cobra.Command{
116117
if err != nil {
117118
log.Fatal(err)
118119
}
119-
tr, err := spec.RunContainer(context.Background(), env.Client, imageRef)
120+
executor := containertest.DockerExecutor{
121+
Client: env.Client,
122+
ImageRef: imageRef,
123+
}
124+
tr, err := executor.Run(context.TODO(), spec)
120125
if err != nil {
121126
log.Fatal(err)
122127
}

cmd/core/test-run.go

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ import (
3333
"github.com/32leaves/dazzle/pkg/dazzle"
3434
"github.com/32leaves/dazzle/pkg/fancylog"
3535
"github.com/32leaves/dazzle/pkg/test"
36+
containertest "github.com/32leaves/dazzle/pkg/test/container"
3637
)
3738

3839
var testRunCmd = &cobra.Command{
@@ -64,7 +65,11 @@ var testRunCmd = &cobra.Command{
6465
tests = append(tests, t...)
6566
}
6667

67-
results, success := test.RunTests(context.Background(), env.Client, imageRef, tests)
68+
executor := containertest.DockerExecutor{
69+
Client: env.Client,
70+
ImageRef: imageRef,
71+
}
72+
results, success := test.RunTests(context.Background(), executor, tests)
6873

6974
xmlout, _ := cmd.Flags().GetString("output-test-xml")
7075
if xmlout != "" {

cmd/util/test-add.go

Lines changed: 215 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,215 @@
1+
// Copyright © 2019 Christian Weichel
2+
3+
// Permission is hereby granted, free of charge, to any person obtaining a copy
4+
// of this software and associated documentation files (the "Software"), to deal
5+
// in the Software without restriction, including without limitation the rights
6+
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7+
// copies of the Software, and to permit persons to whom the Software is
8+
// furnished to do so, subject to the following conditions:
9+
10+
// The above copyright notice and this permission notice shall be included in
11+
// all copies or substantial portions of the Software.
12+
13+
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14+
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15+
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16+
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17+
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18+
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
19+
// THE SOFTWARE.
20+
21+
package util
22+
23+
import (
24+
"context"
25+
"encoding/csv"
26+
"encoding/json"
27+
"fmt"
28+
"io/ioutil"
29+
"os"
30+
"strings"
31+
32+
"github.com/gookit/color"
33+
"github.com/manifoldco/promptui"
34+
log "github.com/sirupsen/logrus"
35+
"github.com/spf13/cobra"
36+
"gopkg.in/yaml.v2"
37+
38+
"github.com/32leaves/dazzle/pkg/fancylog"
39+
"github.com/32leaves/dazzle/pkg/test"
40+
)
41+
42+
var testAddCmd = &cobra.Command{
43+
Use: "add <suite.yaml>",
44+
Short: "Adds to a dazzle test suite",
45+
Args: cobra.MinimumNArgs(1),
46+
Run: func(cmd *cobra.Command, args []string) {
47+
log.SetFormatter(&fancylog.Formatter{})
48+
49+
fn := args[0]
50+
fc, err := ioutil.ReadFile(fn)
51+
if err != nil && !os.IsNotExist(err) {
52+
log.Fatal(err)
53+
}
54+
55+
var tests []*test.Spec
56+
err = yaml.Unmarshal(fc, &tests)
57+
if err != nil {
58+
log.Fatal(err)
59+
}
60+
61+
desc, _ := cmd.Flags().GetString("description")
62+
if desc == "" {
63+
p := promptui.Prompt{
64+
Label: "Description",
65+
Validate: required,
66+
}
67+
desc, err = p.Run()
68+
if err != nil {
69+
log.Fatal(err)
70+
}
71+
}
72+
command, _ := cmd.Flags().GetString("command")
73+
if command == "" {
74+
p := promptui.Prompt{
75+
Label: "Test command",
76+
Validate: func(s string) error {
77+
if err = required(s); err != nil {
78+
return err
79+
}
80+
if _, err = splitCommand(s); err != nil {
81+
return err
82+
}
83+
return nil
84+
},
85+
}
86+
command, err = p.Run()
87+
if err != nil {
88+
log.Fatal(err)
89+
}
90+
}
91+
commandsegs, err := splitCommand(command)
92+
if err != nil {
93+
log.Fatal(err)
94+
}
95+
user, _ := cmd.Flags().GetString("user")
96+
envvars, _ := cmd.Flags().GetStringArray("env")
97+
entrypoint, _ := cmd.Flags().GetString("entrypoint")
98+
var epsegs []string
99+
if entrypoint != "" {
100+
epsegs, err = splitCommand(entrypoint)
101+
if err != nil {
102+
log.Fatal(err)
103+
}
104+
}
105+
106+
spec := &test.Spec{
107+
Desc: desc,
108+
Command: commandsegs,
109+
User: user,
110+
Env: envvars,
111+
Entrypoint: epsegs,
112+
Skip: false,
113+
}
114+
executor := test.LocalExecutor{}
115+
tr, err := executor.Run(context.TODO(), spec)
116+
if err != nil {
117+
log.Fatal(err)
118+
}
119+
120+
err = addAssertions(spec, tr)
121+
if err != nil {
122+
log.Fatal(err)
123+
}
124+
125+
tests = append(tests, spec)
126+
fc, err = yaml.Marshal(tests)
127+
if err != nil {
128+
log.Fatal(err)
129+
}
130+
fmt.Println(string(fc))
131+
132+
err = ioutil.WriteFile(args[0], fc, 0644)
133+
if err != nil {
134+
log.Fatal(err)
135+
}
136+
},
137+
}
138+
139+
func init() {
140+
testCmd.AddCommand(testAddCmd)
141+
142+
testAddCmd.Flags().StringP("description", "d", "", "test description")
143+
testAddCmd.Flags().StringP("command", "c", "", "test command to execute")
144+
testAddCmd.Flags().StringP("user", "u", "", "user to execute the command as")
145+
testAddCmd.Flags().StringArrayP("env", "e", []string{}, "set environment variables (VAR=VALUE) for running the test command")
146+
testAddCmd.Flags().String("entrypoint", "", "container entrypoint")
147+
}
148+
149+
func required(s string) error {
150+
if len(strings.TrimSpace(s)) == 0 {
151+
return fmt.Errorf("required")
152+
}
153+
return nil
154+
}
155+
156+
func splitCommand(cmd string) ([]string, error) {
157+
r := csv.NewReader(strings.NewReader(cmd))
158+
r.Comma = ' '
159+
return r.Read()
160+
}
161+
162+
func addAssertions(spec *test.Spec, runres *test.RunResult) error {
163+
// don't let log messages interfere with prompt
164+
log.SetLevel(log.WarnLevel)
165+
166+
stdout, _ := json.Marshal(string(runres.Stdout))
167+
stderr, _ := json.Marshal(string(runres.Stderr))
168+
fmt.Println("Available variables are:")
169+
color.Info.Print("stdout: ")
170+
fmt.Println(string(stdout))
171+
color.Info.Print("stderr: ")
172+
fmt.Println(string(stderr))
173+
color.Info.Print("status: ")
174+
fmt.Println(runres.StatusCode)
175+
176+
for {
177+
p := promptui.Prompt{
178+
Label: "Assertion",
179+
AllowEdit: true,
180+
Validate: func(a string) error {
181+
var res test.Result
182+
err := test.ValidateAssertions(&res, []string{a}, runres)
183+
if err != nil {
184+
return err
185+
}
186+
187+
if res.Failure != nil {
188+
return fmt.Errorf(res.Failure.Message)
189+
}
190+
191+
return nil
192+
},
193+
}
194+
a, err := p.Run()
195+
if err != nil {
196+
return err
197+
}
198+
spec.Assertions = append(spec.Assertions, a)
199+
200+
p = promptui.Prompt{
201+
Label: "Add another assertion?",
202+
IsConfirm: true,
203+
Default: "y",
204+
}
205+
cont, err := p.Run()
206+
if err != nil && err != promptui.ErrAbort {
207+
return err
208+
}
209+
if strings.TrimSpace(cont) != "" && strings.ToLower(cont) != "y" {
210+
break
211+
}
212+
}
213+
214+
return nil
215+
}

cmd/util/test-run.go

Lines changed: 89 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,89 @@
1+
// Copyright © 2019 Christian Weichel
2+
3+
// Permission is hereby granted, free of charge, to any person obtaining a copy
4+
// of this software and associated documentation files (the "Software"), to deal
5+
// in the Software without restriction, including without limitation the rights
6+
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7+
// copies of the Software, and to permit persons to whom the Software is
8+
// furnished to do so, subject to the following conditions:
9+
10+
// The above copyright notice and this permission notice shall be included in
11+
// all copies or substantial portions of the Software.
12+
13+
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14+
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15+
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16+
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17+
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18+
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
19+
// THE SOFTWARE.
20+
21+
package util
22+
23+
import (
24+
"context"
25+
"encoding/xml"
26+
"io/ioutil"
27+
"os"
28+
29+
log "github.com/sirupsen/logrus"
30+
"github.com/spf13/cobra"
31+
"gopkg.in/yaml.v2"
32+
33+
"github.com/32leaves/dazzle/pkg/fancylog"
34+
"github.com/32leaves/dazzle/pkg/test"
35+
)
36+
37+
var testRunCmd = &cobra.Command{
38+
Use: "run <test00.yaml> ... <testN.yaml>",
39+
Short: "Runs a dazzle test suite",
40+
Args: cobra.MinimumNArgs(1),
41+
Run: func(cmd *cobra.Command, args []string) {
42+
log.SetFormatter(&fancylog.Formatter{})
43+
44+
testFiles := args
45+
var tests []*test.Spec
46+
47+
for _, fn := range testFiles {
48+
fc, err := ioutil.ReadFile(fn)
49+
if err != nil {
50+
log.Fatal(err)
51+
}
52+
53+
var t []*test.Spec
54+
err = yaml.Unmarshal(fc, &t)
55+
if err != nil {
56+
log.WithField("file", fn).Fatal(err)
57+
}
58+
59+
tests = append(tests, t...)
60+
}
61+
62+
results, success := test.RunTests(context.Background(), test.LocalExecutor{}, tests)
63+
64+
xmlout, _ := cmd.Flags().GetString("output-test-xml")
65+
if xmlout != "" {
66+
fc, err := xml.MarshalIndent(results, " ", " ")
67+
if err != nil {
68+
log.Fatal(err)
69+
}
70+
71+
err = ioutil.WriteFile(xmlout, fc, 0644)
72+
if err != nil {
73+
log.Fatal(err)
74+
}
75+
}
76+
77+
if !success {
78+
os.Exit(1)
79+
}
80+
81+
os.Exit(0)
82+
},
83+
}
84+
85+
func init() {
86+
testCmd.AddCommand(testRunCmd)
87+
88+
testRunCmd.Flags().String("output-test-xml", "", "save result as JUnit XML file")
89+
}

cmd/util/test.go

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
// Copyright © 2019 Christian Weichel
2+
3+
// Permission is hereby granted, free of charge, to any person obtaining a copy
4+
// of this software and associated documentation files (the "Software"), to deal
5+
// in the Software without restriction, including without limitation the rights
6+
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7+
// copies of the Software, and to permit persons to whom the Software is
8+
// furnished to do so, subject to the following conditions:
9+
10+
// The above copyright notice and this permission notice shall be included in
11+
// all copies or substantial portions of the Software.
12+
13+
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14+
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15+
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16+
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17+
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18+
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
19+
// THE SOFTWARE.
20+
21+
package util
22+
23+
import (
24+
"github.com/spf13/cobra"
25+
)
26+
27+
var testCmd = &cobra.Command{
28+
Use: "test <command>",
29+
Short: "works with image tests",
30+
Args: cobra.MinimumNArgs(1),
31+
}
32+
33+
func init() {
34+
rootCmd.AddCommand(testCmd)
35+
}

go.mod

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ require (
77
github.com/alecthomas/jsonschema v0.0.0-20191017121752-4bb6e3fae4f2
88
github.com/alecthomas/repr v0.0.0-20181024024818-d37bc2a10ba1
99
github.com/buildpack/imgutil v0.0.0-20191010153712-78959154ded1
10+
github.com/creack/pty v1.1.9
1011
github.com/docker/cli v0.0.0-20190321234815-f40f9c240ab0
1112
github.com/docker/distribution v2.7.1+incompatible
1213
github.com/docker/docker v1.14.0-0.20190319215453-e7b5f7dbe98c

0 commit comments

Comments
 (0)