Test Failed
Push — master ( d4cdd3...569253 )
by Vyacheslav
03:17 queued 01:50
created

goagi.TestNewFastAGI   A

Complexity

Conditions 1

Size

Total Lines 42
Code Lines 34

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
eloc 34
dl 0
loc 42
rs 9.064
c 0
b 0
f 0
nop 1

1 Method

Rating   Name   Duplication   Size   Complexity  
A goagi.TestNew 0 16 1
1
package goagi
2
3
import (
4
	"bytes"
5
	"io"
6
	"io/ioutil"
7
	"log"
8
	"net"
9
	"os"
10
	"strings"
11
	"testing"
12
	"time"
13
14
	"github.com/stretchr/testify/assert"
15
)
16
17
type stubReader struct {
18
	io.Reader
19
	tout int64
20
}
21
22
func (r *stubReader) SetReadDeadline(t time.Time) error {
23
	r.tout = t.Sub(time.Now()).Milliseconds()
24
	return nil
25
}
26
27
type stubWriter struct {
28
	io.Writer
29
	tout int64
30
}
31
32
func (w *stubWriter) SetWriteDeadline(t time.Time) error {
33
	w.tout = t.Sub(time.Now()).Milliseconds()
34
	return nil
35
}
36
37
var agiSetupInput = []string{
38
	"agi_network: yes",
39
	"agi_network_script: foo?",
40
	"agi_request: agi://127.0.0.1/foo?",
41
	"agi_channel: SIP/2222@default-00000023",
42
	"agi_language: en",
43
	"agi_type: SIP",
44
	"agi_uniqueid: 1397044468.0",
45
	"agi_version: 0.1",
46
	"agi_callerid: 5001",
47
	"agi_calleridname: Alice",
48
	"agi_callingpres: 67",
49
	"agi_callingani2: 0",
50
	"agi_callington: 0",
51
	"agi_callingtns: 0",
52
	"agi_dnid: 123456",
53
	"agi_rdnis: unknown",
54
	"agi_context: default",
55
	"agi_extension: 2222",
56
	"agi_priority: 1",
57
	"agi_enhanced: 0.0",
58
	"agi_accountcode: 0",
59
	"agi_threadid: 140536028174080",
60
	"agi_arg_1: argument1",
61
	"agi_arg_2: argument2",
62
}
63
64
func TestNew(t *testing.T) {
65
	input := strings.Join(agiSetupInput, "\n")
66
	input += "\n\n"
67
	logBuffer := new(bytes.Buffer)
68
	logger := log.New(logBuffer, "agi: ", log.Lmicroseconds)
69
	reader := &stubReader{strings.NewReader(input), 0}
70
	writer := &stubWriter{ioutil.Discard, 0}
71
72
	agi, err := New(reader, writer, logger)
73
	assert.Nil(t, err)
74
	assert.Equal(t, "SIP/2222@default-00000023", agi.Env("channel"))
75
	assert.Equal(t, "2222", agi.Env("extension"))
76
	assert.Empty(t, agi.Env("invalid_name"))
77
	assert.Equal(t, 2, len(agi.EnvArgs()))
78
	assert.Contains(t, logBuffer.String(), "agi_network: yes")
79
	assert.Contains(t, logBuffer.String(), "agi_threadid: 140536028174080")
80
}
81
82
func TestNewFail(t *testing.T) {
83
	reader, writer, err := os.Pipe()
84
	assert.Nil(t, err)
85
86
	reader.Close()
87
	agi, err := New(reader, writer, nil)
88
	assert.Nil(t, agi)
89
	assert.NotNil(t, err)
90
	assert.Contains(t, err.Error(), "closed")
91
}
92
93
func TestNewIOPipe(t *testing.T) {
94
	reader, writer, err := os.Pipe()
95
	assert.Nil(t, err)
96
	input := strings.Join(agiSetupInput, "\n")
97
	input += "\n\n"
98
99
	writer.WriteString(input)
100
	agi, err := New(reader, writer, nil)
101
	assert.Nil(t, err)
102
	assert.Equal(t, "2222", agi.Env("extension"))
103
	assert.Equal(t, 2, len(agi.EnvArgs()))
104
}
105
106
func TestNewNetPipe(t *testing.T) {
107
	reader, writer := net.Pipe()
108
	input := strings.Join(agiSetupInput, "\n")
109
	input += "\n\n"
110
111
	go writer.Write([]byte(input))
112
	agi, err := New(reader, writer, nil)
113
	assert.Nil(t, err)
114
	assert.Equal(t, "2222", agi.Env("extension"))
115
	assert.Equal(t, 2, len(agi.EnvArgs()))
116
}
117
118
func TestSessionInitTimeout(t *testing.T) {
119
	stdin, writer, err := os.Pipe()
120
	assert.Nil(t, err)
121
	agi := &AGI{reader: stdin}
122
	input := strings.Join(agiSetupInput, "\n")
123
124
	// write without terminating \n to simulate timeout
125
	writer.WriteString(input)
126
	_, err = agi.sessionInit()
127
	assert.NotNil(t, err)
128
	assert.Contains(t, err.Error(), "timeout")
129
}
130
131
func TestSessionInitDeviceFail(t *testing.T) {
132
	stdin, _, err := os.Pipe()
133
	assert.Nil(t, err)
134
	agi := &AGI{reader: stdin}
135
	stdin.Close()
136
	_, err = agi.sessionInit()
137
	assert.NotNil(t, err)
138
	assert.Contains(t, err.Error(), "closed")
139
}
140
141
func TestReadResponse(t *testing.T) {
142
	tests := []struct {
143
		input string
144
		code  int
145
		ishup bool
146
	}{
147
		{"100 result=0 Trying...\n", codeEarly, false},
148
		{"200 result=1\n", codeSucc, false},
149
		{"503 result=-2 Memory allocation failure\n", codeE503, false},
150
		{"510 Invalid or unknown command\n", codeE510, false},
151
		{"511 Command Not Premitted\n", codeE511, false},
152
		{"520 Invalid command syntax.\n", codeE520, false},
153
	}
154
155
	// run tests
156
	for _, test := range tests {
157
		reader := &stubReader{strings.NewReader(test.input), 0}
158
		agi := &AGI{reader: reader}
159
160
		res, code, err := agi.read(0)
161
		assert.Nil(t, err, test.input)
162
		assert.Equal(t, test.input, res)
163
		assert.Equal(t, test.code, code, test.input)
164
		assert.Equal(t, test.ishup, agi.isHUP, test.input)
165
	}
166
}
167
168
func TestReadResponseWithHangup(t *testing.T) {
169
	reader := &stubReader{strings.NewReader("HANGUP\n200 result=1\n"), 0}
170
	agi := &AGI{reader: reader}
171
	res, code, err := agi.read(0)
172
	assert.Nil(t, err)
173
	assert.Equal(t, "200 result=1\n", res)
174
	assert.Equal(t, codeSucc, code)
175
	assert.True(t, agi.isHUP)
176
}
177
178
func TestReadResponseLongError520(t *testing.T) {
179
	input := "HANGUP\n520-Invalid command syntax.  Proper usage follows:\n" +
180
		"Usage: DATABASE GET\n" +
181
		"Retrieves an entry in the Asterisk database for a\n" +
182
		"given family and key.\n" +
183
		"Returns 0 if is not set. Returns 1 if \n" +
184
		"is set and returns the variable in parentheses.\n" +
185
		"Example return code: 200 result=1 (testvariable)\n" +
186
		"520 End of proper usage.\n"
187
	reader := &stubReader{strings.NewReader(input), 0}
188
	agi := &AGI{reader: reader}
189
	res, code, err := agi.read(0)
190
	assert.Nil(t, err)
191
	assert.Equal(t, input[7:], res)
192
	assert.Equal(t, codeE520, code)
193
	assert.True(t, agi.isHUP)
194
}
195
196
func TestReadResponseGarbage(t *testing.T) {
197
	tests := []string{
198
		"Usage: DATABASE GET\n" +
199
			"Retrieves an entry in the Asterisk database for a\n" +
200
			"given family and key.\n" +
201
			"Returns 0 if is not set. Returns 1 if \n" +
202
			"is set and returns the variable in parentheses.\n" +
203
			"Example return code: 200 result=1 (testvariable)\n" +
204
			"520 End of proper usage.\n",
205
		"\n", // empty string
206
		"2222222\n",
207
		"-1 result=4\n",
208
		"780 result=0\n",
209
	}
210
211
	for _, input := range tests {
212
		reader := &stubReader{strings.NewReader(input), 0}
213
		agi := &AGI{reader: reader}
214
		_, code, err := agi.read(0)
215
		assert.NotNil(t, err)
216
		assert.Contains(t, err.Error(), "Invalid input")
217
		assert.Zero(t, code)
218
	}
219
}
220
221
func TestReadResponseFail(t *testing.T) {
222
	stdin, _, err := os.Pipe()
223
	assert.Nil(t, err)
224
	agi := &AGI{reader: stdin}
225
	stdin.Close()
226
	_, _, err = agi.read(0)
227
	assert.NotNil(t, err)
228
	assert.Contains(t, err.Error(), "closed")
229
}
230
231
func TestReadResponseTimeout(t *testing.T) {
232
	stdin, writer, err := os.Pipe()
233
	assert.Nil(t, err)
234
	agi := &AGI{reader: stdin}
235
236
	// write without terminating \n to simulate timeout
237
	writer.WriteString("foo bar")
238
	_, _, err = agi.read(time.Millisecond * 100)
239
	assert.NotNil(t, err)
240
	assert.Contains(t, err.Error(), "timeout")
241
242
	writer.WriteString("HANGUP\nfoo bar")
243
	_, _, err = agi.read(time.Millisecond * 100)
244
	assert.NotNil(t, err)
245
	assert.Contains(t, err.Error(), "timeout")
246
247
	stdin.Close()
248
	_, _, err = agi.read(time.Millisecond * 100)
249
	assert.NotNil(t, err)
250
	assert.Contains(t, err.Error(), "closed")
251
}
252
253
func TestWriteStdIO(t *testing.T) {
254
	reader, writer, err := os.Pipe()
255
	assert.Nil(t, err)
256
	agi := &AGI{writer: writer}
257
258
	err = agi.write([]byte("NOOP\n"))
259
	assert.Nil(t, err)
260
261
	buf := make([]byte, 32)
262
	n, _ := reader.Read(buf)
263
	assert.Equal(t, "NOOP\n", string(buf[:n]))
264
}
265
266
func TestWriteNetConn(t *testing.T) {
267
	reader, writer := net.Pipe()
268
269
	agi := &AGI{writer: writer}
270
271
	go func() {
272
		agi.write([]byte("ANSWER\n"))
273
		writer.Close()
274
	}()
275
276
	buf, _ := ioutil.ReadAll(reader)
277
	assert.Equal(t, "ANSWER\n", string(buf))
278
}
279
280
func TestWriteTimeout(t *testing.T) {
281
	_, writer := net.Pipe()
282
	agi := &AGI{writer: writer, rwtout: time.Millisecond * 100}
283
284
	err := agi.write([]byte("NOOP\n"))
285
	assert.NotNil(t, err)
286
	assert.Contains(t, err.Error(), "timeout")
287
}
288
289
func TestWriteFailSetTimeout(t *testing.T) {
290
	_, writer := net.Pipe()
291
	agi := &AGI{writer: writer, rwtout: time.Millisecond * 100}
292
293
	writer.Close()
294
	err := agi.write([]byte("NOOP\n"))
295
	assert.NotNil(t, err)
296
	assert.Contains(t, err.Error(), "closed")
297
}
298
299
func TestWriteFail(t *testing.T) {
300
	reader, writer, err := os.Pipe()
301
	assert.Nil(t, err)
302
	agi := &AGI{writer: writer}
303
304
	reader.Close()
305
	err = agi.write([]byte("HANGUP\n"))
306
	assert.NotNil(t, err)
307
	assert.Contains(t, err.Error(), "broken pipe")
308
}
309
310
func TestExecute(t *testing.T) {
311
	buf, reader, writer := stubReaderWriter("200 result=1")
312
	agi := &AGI{reader: reader, writer: writer, rwtout: rwDefaultTimeout * 5}
313
	resp, err := agi.execute("NOOP\n", true)
314
	assert.Nil(t, err)
315
	assert.Equal(t, "NOOP\n", buf.String())
316
	assert.Equal(t, 200, resp.Code())
317
	assert.Equal(t, 1, resp.Result())
318
	assert.True(t, reader.tout > 4000)
319
	assert.True(t, writer.tout > 4000)
320
321
	resp, err = agi.execute("HANGUP\n", false)
322
	assert.NotNil(t, err)
323
	assert.Nil(t, resp)
324
325
	_, wr := net.Pipe()
326
	agi.writer = wr
327
	wr.Close()
328
	resp, err = agi.execute("HANGUP\n", false)
329
	assert.NotNil(t, err)
330
	assert.Contains(t, err.Error(), "closed")
331
}
332
333
func TestAGI(t *testing.T) {
334
}
335