Browse code

Engine: better testing of streams and of basic engine primitives. Coverage=81.2%

Solomon Hykes authored on 2013/11/20 16:38:59
Showing 3 changed files
... ...
@@ -1,6 +1,9 @@
1 1
 package engine
2 2
 
3 3
 import (
4
+	"io/ioutil"
5
+	"os"
6
+	"path"
4 7
 	"testing"
5 8
 )
6 9
 
... ...
@@ -54,3 +57,47 @@ func TestJob(t *testing.T) {
54 54
 		t.Fatalf("handler dummy2 was not found in job2")
55 55
 	}
56 56
 }
57
+
58
+func TestEngineRoot(t *testing.T) {
59
+	tmp, err := ioutil.TempDir("", "docker-test-TestEngineCreateDir")
60
+	if err != nil {
61
+		t.Fatal(err)
62
+	}
63
+	defer os.RemoveAll(tmp)
64
+	dir := path.Join(tmp, "dir")
65
+	eng, err := New(dir)
66
+	if err != nil {
67
+		t.Fatal(err)
68
+	}
69
+	if st, err := os.Stat(dir); err != nil {
70
+		t.Fatal(err)
71
+	} else if !st.IsDir() {
72
+		t.Fatalf("engine.New() created something other than a directory at %s", dir)
73
+	}
74
+	if r := eng.Root(); r != dir {
75
+		t.Fatalf("Expected: %v\nReceived: %v", dir, r)
76
+	}
77
+}
78
+
79
+func TestEngineString(t *testing.T) {
80
+	eng1 := newTestEngine(t)
81
+	defer os.RemoveAll(eng1.Root())
82
+	eng2 := newTestEngine(t)
83
+	defer os.RemoveAll(eng2.Root())
84
+	s1 := eng1.String()
85
+	s2 := eng2.String()
86
+	if eng1 == eng2 {
87
+		t.Fatalf("Different engines should have different names (%v == %v)", s1, s2)
88
+	}
89
+}
90
+
91
+func TestEngineLogf(t *testing.T) {
92
+	eng := newTestEngine(t)
93
+	defer os.RemoveAll(eng.Root())
94
+	input := "Test log line"
95
+	if n, err := eng.Logf("%s\n", input); err != nil {
96
+		t.Fatal(err)
97
+	} else if n < len(input) {
98
+		t.Fatalf("Test: Logf() should print at least as much as the input\ninput=%d\nprinted=%d", len(input), n)
99
+	}
100
+}
57 101
new file mode 100644
... ...
@@ -0,0 +1,80 @@
0
+package engine
1
+
2
+import (
3
+	"os"
4
+	"testing"
5
+)
6
+
7
+func TestJobStatusOK(t *testing.T) {
8
+	eng := newTestEngine(t)
9
+	defer os.RemoveAll(eng.Root())
10
+	eng.Register("return_ok", func(job *Job) Status { return StatusOK })
11
+	err := eng.Job("return_ok").Run()
12
+	if err != nil {
13
+		t.Fatalf("Expected: err=%v\nReceived: err=%v", nil, err)
14
+	}
15
+}
16
+
17
+func TestJobStatusErr(t *testing.T) {
18
+	eng := newTestEngine(t)
19
+	defer os.RemoveAll(eng.Root())
20
+	eng.Register("return_err", func(job *Job) Status { return StatusErr })
21
+	err := eng.Job("return_err").Run()
22
+	if err == nil {
23
+		t.Fatalf("When a job returns StatusErr, Run() should return an error")
24
+	}
25
+}
26
+
27
+func TestJobStatusNotFound(t *testing.T) {
28
+	eng := newTestEngine(t)
29
+	defer os.RemoveAll(eng.Root())
30
+	eng.Register("return_not_found", func(job *Job) Status { return StatusNotFound })
31
+	err := eng.Job("return_not_found").Run()
32
+	if err == nil {
33
+		t.Fatalf("When a job returns StatusNotFound, Run() should return an error")
34
+	}
35
+}
36
+
37
+func TestJobStdoutString(t *testing.T) {
38
+	eng := newTestEngine(t)
39
+	defer os.RemoveAll(eng.Root())
40
+	// FIXME: test multiple combinations of output and status
41
+	eng.Register("say_something_in_stdout", func(job *Job) Status {
42
+		job.Printf("Hello world\n")
43
+		return StatusOK
44
+	})
45
+
46
+	job := eng.Job("say_something_in_stdout")
47
+	var output string
48
+	if err := job.Stdout.AddString(&output); err != nil {
49
+		t.Fatal(err)
50
+	}
51
+	if err := job.Run(); err != nil {
52
+		t.Fatal(err)
53
+	}
54
+	if expectedOutput := "Hello world"; output != expectedOutput {
55
+		t.Fatalf("Stdout last line:\nExpected: %v\nReceived: %v", expectedOutput, output)
56
+	}
57
+}
58
+
59
+func TestJobStderrString(t *testing.T) {
60
+	eng := newTestEngine(t)
61
+	defer os.RemoveAll(eng.Root())
62
+	// FIXME: test multiple combinations of output and status
63
+	eng.Register("say_something_in_stderr", func(job *Job) Status {
64
+		job.Errorf("Warning, something might happen\nHere it comes!\nOh no...\nSomething happened\n")
65
+		return StatusOK
66
+	})
67
+
68
+	job := eng.Job("say_something_in_stderr")
69
+	var output string
70
+	if err := job.Stderr.AddString(&output); err != nil {
71
+		t.Fatal(err)
72
+	}
73
+	if err := job.Run(); err != nil {
74
+		t.Fatal(err)
75
+	}
76
+	if expectedOutput := "Something happened"; output != expectedOutput {
77
+		t.Fatalf("Stderr last line:\nExpected: %v\nReceived: %v", expectedOutput, output)
78
+	}
79
+}
0 80
new file mode 100644
... ...
@@ -0,0 +1,252 @@
0
+package engine
1
+
2
+import (
3
+	"bufio"
4
+	"bytes"
5
+	"fmt"
6
+	"io/ioutil"
7
+	"strings"
8
+	"testing"
9
+)
10
+
11
+func TestOutputAddString(t *testing.T) {
12
+	var testInputs = [][2]string{
13
+		{
14
+			"hello, world!",
15
+			"hello, world!",
16
+		},
17
+
18
+		{
19
+			"One\nTwo\nThree",
20
+			"Three",
21
+		},
22
+
23
+		{
24
+			"",
25
+			"",
26
+		},
27
+
28
+		{
29
+			"A line\nThen another nl-terminated line\n",
30
+			"Then another nl-terminated line",
31
+		},
32
+
33
+		{
34
+			"A line followed by an empty line\n\n",
35
+			"",
36
+		},
37
+	}
38
+	for _, testData := range testInputs {
39
+		input := testData[0]
40
+		expectedOutput := testData[1]
41
+		o := NewOutput()
42
+		var output string
43
+		if err := o.AddString(&output); err != nil {
44
+			t.Error(err)
45
+		}
46
+		if n, err := o.Write([]byte(input)); err != nil {
47
+			t.Error(err)
48
+		} else if n != len(input) {
49
+			t.Errorf("Expected %d, got %d", len(input), n)
50
+		}
51
+		o.Close()
52
+		if output != expectedOutput {
53
+			t.Errorf("Last line is not stored as return string.\nInput:   '%s'\nExpected: '%s'\nGot:       '%s'", input, expectedOutput, output)
54
+		}
55
+	}
56
+}
57
+
58
+type sentinelWriteCloser struct {
59
+	calledWrite bool
60
+	calledClose bool
61
+}
62
+
63
+func (w *sentinelWriteCloser) Write(p []byte) (int, error) {
64
+	w.calledWrite = true
65
+	return len(p), nil
66
+}
67
+
68
+func (w *sentinelWriteCloser) Close() error {
69
+	w.calledClose = true
70
+	return nil
71
+}
72
+
73
+func TestOutputAddClose(t *testing.T) {
74
+	o := NewOutput()
75
+	var s sentinelWriteCloser
76
+	if err := o.Add(&s); err != nil {
77
+		t.Fatal(err)
78
+	}
79
+	if err := o.Close(); err != nil {
80
+		t.Fatal(err)
81
+	}
82
+	// Write data after the output is closed.
83
+	// Write should succeed, but no destination should receive it.
84
+	if _, err := o.Write([]byte("foo bar")); err != nil {
85
+		t.Fatal(err)
86
+	}
87
+	if !s.calledClose {
88
+		t.Fatal("Output.Close() didn't close the destination")
89
+	}
90
+}
91
+
92
+func TestOutputAddPipe(t *testing.T) {
93
+	var testInputs = []string{
94
+		"hello, world!",
95
+		"One\nTwo\nThree",
96
+		"",
97
+		"A line\nThen another nl-terminated line\n",
98
+		"A line followed by an empty line\n\n",
99
+	}
100
+	for _, input := range testInputs {
101
+		expectedOutput := input
102
+		o := NewOutput()
103
+		r, err := o.AddPipe()
104
+		if err != nil {
105
+			t.Fatal(err)
106
+		}
107
+		go func(o *Output) {
108
+			if n, err := o.Write([]byte(input)); err != nil {
109
+				t.Error(err)
110
+			} else if n != len(input) {
111
+				t.Errorf("Expected %d, got %d", len(input), n)
112
+			}
113
+			if err := o.Close(); err != nil {
114
+				t.Error(err)
115
+			}
116
+		}(o)
117
+		output, err := ioutil.ReadAll(r)
118
+		if err != nil {
119
+			t.Fatal(err)
120
+		}
121
+		if string(output) != expectedOutput {
122
+			t.Errorf("Last line is not stored as return string.\nExpected: '%s'\nGot:       '%s'", expectedOutput, output)
123
+		}
124
+	}
125
+}
126
+
127
+func TestTail(t *testing.T) {
128
+	var tests = make(map[string][][]string)
129
+	tests["hello, world!"] = [][]string{
130
+		{},
131
+		{"hello, world!"},
132
+		{"hello, world!"},
133
+		{"hello, world!"},
134
+	}
135
+	tests["One\nTwo\nThree"] = [][]string{
136
+		{},
137
+		{"Three"},
138
+		{"Two", "Three"},
139
+		{"One", "Two", "Three"},
140
+	}
141
+	for input, outputs := range tests {
142
+		for n, expectedOutput := range outputs {
143
+			var output []string
144
+			Tail(strings.NewReader(input), n, &output)
145
+			if fmt.Sprintf("%v", output) != fmt.Sprintf("%v", expectedOutput) {
146
+				t.Errorf("Tail n=%d returned wrong result.\nExpected: '%s'\nGot     : '%s'", expectedOutput, output)
147
+			}
148
+		}
149
+	}
150
+}
151
+
152
+func TestOutputAddTail(t *testing.T) {
153
+	var tests = make(map[string][][]string)
154
+	tests["hello, world!"] = [][]string{
155
+		{},
156
+		{"hello, world!"},
157
+		{"hello, world!"},
158
+		{"hello, world!"},
159
+	}
160
+	tests["One\nTwo\nThree"] = [][]string{
161
+		{},
162
+		{"Three"},
163
+		{"Two", "Three"},
164
+		{"One", "Two", "Three"},
165
+	}
166
+	for input, outputs := range tests {
167
+		for n, expectedOutput := range outputs {
168
+			o := NewOutput()
169
+			var output []string
170
+			if err := o.AddTail(&output, n); err != nil {
171
+				t.Error(err)
172
+			}
173
+			if n, err := o.Write([]byte(input)); err != nil {
174
+				t.Error(err)
175
+			} else if n != len(input) {
176
+				t.Errorf("Expected %d, got %d", len(input), n)
177
+			}
178
+			o.Close()
179
+			if fmt.Sprintf("%v", output) != fmt.Sprintf("%v", expectedOutput) {
180
+				t.Errorf("Tail(%d) returned wrong result.\nExpected: %v\nGot:      %v", n, expectedOutput, output)
181
+			}
182
+		}
183
+	}
184
+}
185
+
186
+func lastLine(txt string) string {
187
+	scanner := bufio.NewScanner(strings.NewReader(txt))
188
+	var lastLine string
189
+	for scanner.Scan() {
190
+		lastLine = scanner.Text()
191
+	}
192
+	return lastLine
193
+}
194
+
195
+func TestOutputAdd(t *testing.T) {
196
+	o := NewOutput()
197
+	b := &bytes.Buffer{}
198
+	o.Add(b)
199
+	input := "hello, world!"
200
+	if n, err := o.Write([]byte(input)); err != nil {
201
+		t.Fatal(err)
202
+	} else if n != len(input) {
203
+		t.Fatalf("Expected %d, got %d", len(input), n)
204
+	}
205
+	if output := b.String(); output != input {
206
+		t.Fatal("Received wrong data from Add.\nExpected: '%s'\nGot:     '%s'", input, output)
207
+	}
208
+}
209
+
210
+func TestInputAddEmpty(t *testing.T) {
211
+	i := NewInput()
212
+	var b bytes.Buffer
213
+	if err := i.Add(&b); err != nil {
214
+		t.Fatal(err)
215
+	}
216
+	data, err := ioutil.ReadAll(i)
217
+	if err != nil {
218
+		t.Fatal(err)
219
+	}
220
+	if len(data) > 0 {
221
+		t.Fatalf("Read from empty input shoul yield no data")
222
+	}
223
+}
224
+
225
+func TestInputAddTwo(t *testing.T) {
226
+	i := NewInput()
227
+	var b1 bytes.Buffer
228
+	// First add should succeed
229
+	if err := i.Add(&b1); err != nil {
230
+		t.Fatal(err)
231
+	}
232
+	var b2 bytes.Buffer
233
+	// Second add should fail
234
+	if err := i.Add(&b2); err == nil {
235
+		t.Fatalf("Adding a second source should return an error")
236
+	}
237
+}
238
+
239
+func TestInputAddNotEmpty(t *testing.T) {
240
+	i := NewInput()
241
+	b := bytes.NewBufferString("hello world\nabc")
242
+	expectedResult := b.String()
243
+	i.Add(b)
244
+	result, err := ioutil.ReadAll(i)
245
+	if err != nil {
246
+		t.Fatal(err)
247
+	}
248
+	if string(result) != expectedResult {
249
+		t.Fatalf("Expected: %v\nReceived: %v", expectedResult, result)
250
+	}
251
+}