@marcel91200 / caddy Mirror · read-only
Fork 0

Fast and extensible multi-platform HTTP/1-2-3 web server with automatic HTTPS

Mirrored from https://github.com/Slazee/caddy.git

Synced Nov 10, 23:45 UTC

master
go 353 lines 6.97 KB
Raw
1 package caddycmd
2
3 import (
4 "errors"
5 "net"
6 "reflect"
7 "strings"
8 "testing"
9 )
10
11 func TestParseEnvFile(t *testing.T) {
12 for i, tc := range []struct {
13 input string
14 expect map[string]string
15 shouldErr bool
16 }{
17 {
18 input: `KEY=value`,
19 expect: map[string]string{
20 "KEY": "value",
21 },
22 },
23 {
24 input: `
25 KEY=value
26 OTHER_KEY=Some Value
27 `,
28 expect: map[string]string{
29 "KEY": "value",
30 "OTHER_KEY": "Some Value",
31 },
32 },
33 {
34 input: `
35 KEY=value
36 INVALID KEY=asdf
37 OTHER_KEY=Some Value
38 `,
39 shouldErr: true,
40 },
41 {
42 input: `
43 KEY=value
44 SIMPLE_QUOTED="quoted value"
45 OTHER_KEY=Some Value
46 `,
47 expect: map[string]string{
48 "KEY": "value",
49 "SIMPLE_QUOTED": "quoted value",
50 "OTHER_KEY": "Some Value",
51 },
52 },
53 {
54 input: `
55 KEY=value
56 NEWLINES="foo
57 bar"
58 OTHER_KEY=Some Value
59 `,
60 expect: map[string]string{
61 "KEY": "value",
62 "NEWLINES": "foo\n\tbar",
63 "OTHER_KEY": "Some Value",
64 },
65 },
66 {
67 input: `
68 KEY=value
69 ESCAPED="\"escaped quotes\"
70 here"
71 OTHER_KEY=Some Value
72 `,
73 expect: map[string]string{
74 "KEY": "value",
75 "ESCAPED": "\"escaped quotes\"\nhere",
76 "OTHER_KEY": "Some Value",
77 },
78 },
79 {
80 input: `
81 export KEY=value
82 OTHER_KEY=Some Value
83 `,
84 expect: map[string]string{
85 "KEY": "value",
86 "OTHER_KEY": "Some Value",
87 },
88 },
89 {
90 input: `
91 =value
92 OTHER_KEY=Some Value
93 `,
94 shouldErr: true,
95 },
96 {
97 input: `
98 EMPTY=
99 OTHER_KEY=Some Value
100 `,
101 expect: map[string]string{
102 "EMPTY": "",
103 "OTHER_KEY": "Some Value",
104 },
105 },
106 {
107 input: `
108 EMPTY=""
109 OTHER_KEY=Some Value
110 `,
111 expect: map[string]string{
112 "EMPTY": "",
113 "OTHER_KEY": "Some Value",
114 },
115 },
116 {
117 input: `
118 KEY=value
119 #OTHER_KEY=Some Value
120 `,
121 expect: map[string]string{
122 "KEY": "value",
123 },
124 },
125 {
126 input: `
127 KEY=value
128 COMMENT=foo bar # some comment here
129 OTHER_KEY=Some Value
130 `,
131 expect: map[string]string{
132 "KEY": "value",
133 "COMMENT": "foo bar",
134 "OTHER_KEY": "Some Value",
135 },
136 },
137 {
138 input: `
139 KEY=value
140 WHITESPACE= foo
141 OTHER_KEY=Some Value
142 `,
143 shouldErr: true,
144 },
145 {
146 input: `
147 KEY=value
148 WHITESPACE=" foo bar "
149 OTHER_KEY=Some Value
150 `,
151 expect: map[string]string{
152 "KEY": "value",
153 "WHITESPACE": " foo bar ",
154 "OTHER_KEY": "Some Value",
155 },
156 },
157 } {
158 actual, err := parseEnvFile(strings.NewReader(tc.input))
159 if err != nil && !tc.shouldErr {
160 t.Errorf("Test %d: Got error but shouldn't have: %v", i, err)
161 }
162 if err == nil && tc.shouldErr {
163 t.Errorf("Test %d: Did not get error but should have", i)
164 }
165 if tc.shouldErr {
166 continue
167 }
168 if !reflect.DeepEqual(tc.expect, actual) {
169 t.Errorf("Test %d: Expected %v but got %v", i, tc.expect, actual)
170 }
171 }
172 }
173
174 func TestListenTCPForPingbackUsesIPv4Loopback(t *testing.T) {
175 var calls []string
176 expected := &stubListener{addr: &net.TCPAddr{IP: net.ParseIP("127.0.0.1"), Port: 1234}}
177
178 actual, err := listenTCPForPingback(func(network, address string) (net.Listener, error) {
179 calls = append(calls, network+" "+address)
180 return expected, nil
181 })
182 if err != nil {
183 t.Fatalf("listenTCPForPingback returned error: %v", err)
184 }
185 if actual != expected {
186 t.Fatalf("expected listener %p, got %p", expected, actual)
187 }
188
189 expectCalls := []string{"tcp4 127.0.0.1:0"}
190 if !reflect.DeepEqual(calls, expectCalls) {
191 t.Fatalf("expected calls %v, got %v", expectCalls, calls)
192 }
193 }
194
195 func TestListenTCPForPingbackFallsBackToIPv6Loopback(t *testing.T) {
196 var calls []string
197 expected := &stubListener{addr: &net.TCPAddr{IP: net.ParseIP("::1"), Port: 1234}}
198
199 actual, err := listenTCPForPingback(func(network, address string) (net.Listener, error) {
200 calls = append(calls, network+" "+address)
201 if len(calls) == 1 {
202 return nil, errors.New("ipv4 unavailable")
203 }
204 return expected, nil
205 })
206 if err != nil {
207 t.Fatalf("listenTCPForPingback returned error: %v", err)
208 }
209 if actual != expected {
210 t.Fatalf("expected listener %p, got %p", expected, actual)
211 }
212
213 expectCalls := []string{"tcp4 127.0.0.1:0", "tcp6 [::1]:0"}
214 if !reflect.DeepEqual(calls, expectCalls) {
215 t.Fatalf("expected calls %v, got %v", expectCalls, calls)
216 }
217 }
218
219 func TestListenTCPForPingbackReportsBothFailures(t *testing.T) {
220 _, err := listenTCPForPingback(func(network, address string) (net.Listener, error) {
221 return nil, errors.New(network + " failed")
222 })
223 if err == nil {
224 t.Fatal("expected error")
225 }
226 if !strings.Contains(err.Error(), "tcp4 failed") ||
227 !strings.Contains(err.Error(), "tcp6 failed") {
228 t.Fatalf("expected both listener errors, got: %v", err)
229 }
230 }
231
232 type stubListener struct {
233 addr net.Addr
234 }
235
236 func (sl *stubListener) Accept() (net.Conn, error) {
237 return nil, net.ErrClosed
238 }
239
240 func (sl *stubListener) Close() error {
241 return nil
242 }
243
244 func (sl *stubListener) Addr() net.Addr {
245 return sl.addr
246 }
247
248 func Test_isCaddyfile(t *testing.T) {
249 type args struct {
250 configFile string
251 adapterName string
252 }
253 tests := []struct {
254 name string
255 args args
256 want bool
257 wantErr bool
258 }{
259 {
260 name: "bare Caddyfile without adapter",
261 args: args{
262 configFile: "Caddyfile",
263 adapterName: "",
264 },
265 want: true,
266 wantErr: false,
267 },
268 {
269 name: "local Caddyfile without adapter",
270 args: args{
271 configFile: "./Caddyfile",
272 adapterName: "",
273 },
274 want: true,
275 wantErr: false,
276 },
277 {
278 name: "local caddyfile with adapter",
279 args: args{
280 configFile: "./Caddyfile",
281 adapterName: "caddyfile",
282 },
283 want: true,
284 wantErr: false,
285 },
286 {
287 name: "ends with .caddyfile with adapter",
288 args: args{
289 configFile: "./conf.caddyfile",
290 adapterName: "caddyfile",
291 },
292 want: true,
293 wantErr: false,
294 },
295 {
296 name: "ends with .caddyfile without adapter",
297 args: args{
298 configFile: "./conf.caddyfile",
299 adapterName: "",
300 },
301 want: true,
302 wantErr: false,
303 },
304 {
305 name: "config is Caddyfile.yaml with adapter",
306 args: args{
307 configFile: "./Caddyfile.yaml",
308 adapterName: "yaml",
309 },
310 want: false,
311 wantErr: false,
312 },
313 {
314 name: "json is not caddyfile but not error",
315 args: args{
316 configFile: "./Caddyfile.json",
317 adapterName: "",
318 },
319 want: false,
320 wantErr: false,
321 },
322 {
323 name: "prefix of Caddyfile and ./ with any extension is Caddyfile",
324 args: args{
325 configFile: "./Caddyfile.prd",
326 adapterName: "",
327 },
328 want: true,
329 wantErr: false,
330 },
331 {
332 name: "prefix of Caddyfile without ./ with any extension is Caddyfile",
333 args: args{
334 configFile: "Caddyfile.prd",
335 adapterName: "",
336 },
337 want: true,
338 wantErr: false,
339 },
340 }
341 for _, tt := range tests {
342 t.Run(tt.name, func(t *testing.T) {
343 got, err := isCaddyfile(tt.args.configFile, tt.args.adapterName)
344 if (err != nil) != tt.wantErr {
345 t.Errorf("isCaddyfile() error = %v, wantErr %v", err, tt.wantErr)
346 return
347 }
348 if got != tt.want {
349 t.Errorf("isCaddyfile() = %v, want %v", got, tt.want)
350 }
351 })
352 }
353 }