Passed
Push — master ( b9ce7a...fa5039 )
by Stefano
02:17
created

pkg/scan/scanner_integration_test.go   A

Size/Duplication

Total Lines 409
Duplicated Lines 0 %

Importance

Changes 0
Metric Value
cc 24
eloc 276
dl 0
loc 409
rs 10
c 0
b 0
f 0

7 Methods

Rating   Name   Duplication   Size   Complexity  
A scan_test.TestScanningWithEmptyProducerWillProduceNoResults 0 16 2
B scan_test.TestScannerWillNotRedirectIfStatusCodeIsInvalid 0 66 4
A scan_test.TestScannerWillLogAnErrorWithInvalidDictionary 0 41 3
B scan_test.TestScannerWhenOutOfDepthWillNotFollowRedirect 0 62 4
B scan_test.TestScannerWillSkipRedirectWhenLocationHostIsDifferent 0 68 4
B scan_test.TestScannerWillChangeMethodForRedirect 0 73 4
B scan_test.TestScannerWillIgnoreRequestRedundantError 0 56 3
1
package scan_test
2
3
import (
4
	"net/http"
5
	"testing"
6
	"time"
7
8
	"github.com/stefanoj3/dirstalk/pkg/common/test"
9
	"github.com/stefanoj3/dirstalk/pkg/scan"
10
	"github.com/stefanoj3/dirstalk/pkg/scan/client"
11
	"github.com/stefanoj3/dirstalk/pkg/scan/producer"
12
	"github.com/stretchr/testify/assert"
13
)
14
15
func TestScanningWithEmptyProducerWillProduceNoResults(t *testing.T) {
16
	logger, _ := test.NewLogger()
17
18
	prod := producer.NewDictionaryProducer([]string{}, []string{}, 1)
19
	c := &http.Client{Timeout: time.Microsecond}
20
	sut := scan.NewScanner(
21
		c,
22
		prod,
23
		producer.NewReProducer(prod, []int{http.StatusNotFound}),
24
		logger,
25
	)
26
27
	results := sut.Scan(test.MustParseUrl(t, "http://localhost/"), 10)
28
29
	for r := range results {
30
		t.Fatalf("No results expected, got %s", r.Target.Path)
31
	}
32
}
33
34
func TestScannerWillLogAnErrorWithInvalidDictionary(t *testing.T) {
35
	logger, loggerBuffer := test.NewLogger()
36
37
	prod := producer.NewDictionaryProducer(
38
		[]string{"\n"},
39
		[]string{"/home"},
40
		1,
41
	)
42
43
	testServer, serverAssertion := test.NewServerWithAssertion(
44
		http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {}),
45
	)
46
	defer testServer.Close()
47
48
	c, err := client.NewClientFromConfig(
49
		1000,
50
		nil,
51
		"",
52
		false,
53
		nil,
54
		nil,
55
		true,
56
		test.MustParseUrl(t, testServer.URL),
57
	)
58
	assert.NoError(t, err)
59
	sut := scan.NewScanner(
60
		c,
61
		prod,
62
		producer.NewReProducer(prod, []int{http.StatusNotFound}),
63
		logger,
64
	)
65
66
	results := sut.Scan(test.MustParseUrl(t, testServer.URL), 10)
67
68
	for r := range results {
69
		t.Fatalf("No results expected, got %s", r.Target.Path)
70
	}
71
72
	assert.Contains(t, loggerBuffer.String(), "failed to build request")
73
	assert.Contains(t, loggerBuffer.String(), "invalid method")
74
	assert.Equal(t, 0, serverAssertion.Len())
75
}
76
77
func TestScannerWillNotRedirectIfStatusCodeIsInvalid(t *testing.T) {
78
	logger, loggerBuffer := test.NewLogger()
79
80
	prod := producer.NewDictionaryProducer(
81
		[]string{http.MethodGet},
82
		[]string{"/home"},
83
		3,
84
	)
85
86
	testServer, serverAssertion := test.NewServerWithAssertion(
87
		http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
88
			w.Header().Add("location", "/potato")
89
			if r.URL.Path == "/home" {
90
				w.WriteHeader(http.StatusOK)
91
				return
92
			}
93
94
			w.WriteHeader(http.StatusNotFound)
95
		}),
96
	)
97
	defer testServer.Close()
98
99
	c, err := client.NewClientFromConfig(
100
		1000,
101
		nil,
102
		"",
103
		false,
104
		nil,
105
		nil,
106
		true,
107
		test.MustParseUrl(t, testServer.URL),
108
	)
109
	assert.NoError(t, err)
110
111
	sut := scan.NewScanner(
112
		c,
113
		prod,
114
		producer.NewReProducer(prod, []int{http.StatusNotFound}),
115
		logger,
116
	)
117
118
	results := make([]scan.Result, 0, 2)
119
	resultsChannel := sut.Scan(test.MustParseUrl(t, testServer.URL), 10)
120
121
	for r := range resultsChannel {
122
		results = append(results, r)
123
	}
124
125
	expectedsResults := []scan.Result{
126
		{
127
			Target:     scan.Target{Path: "/home", Method: http.MethodGet, Depth: 3},
128
			StatusCode: http.StatusOK,
129
			URL:        *test.MustParseUrl(t, testServer.URL+"/home"),
130
		},
131
		{
132
			Target:     scan.Target{Path: "/home/home", Method: http.MethodGet, Depth: 2},
133
			StatusCode: http.StatusNotFound,
134
			URL:        *test.MustParseUrl(t, testServer.URL+"/home/home"),
135
		},
136
	}
137
138
	assert.Equal(t, expectedsResults, results)
139
140
	assert.Contains(t, loggerBuffer.String(), "/home")
141
	assert.Contains(t, loggerBuffer.String(), "/home/home")
142
	assert.Equal(t, 2, serverAssertion.Len())
143
}
144
145
func TestScannerWillChangeMethodForRedirect(t *testing.T) {
146
	logger, loggerBuffer := test.NewLogger()
147
148
	prod := producer.NewDictionaryProducer(
149
		[]string{http.MethodPatch},
150
		[]string{"/home"},
151
		3,
152
	)
153
154
	testServer, serverAssertion := test.NewServerWithAssertion(
155
		http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
156
			if r.URL.Path == "/home" {
157
				http.Redirect(w, r, "/potato", http.StatusMovedPermanently)
158
				return
159
			}
160
161
			w.WriteHeader(http.StatusNotFound)
162
		}),
163
	)
164
	defer testServer.Close()
165
166
	c, err := client.NewClientFromConfig(
167
		1000,
168
		nil,
169
		"",
170
		false,
171
		nil,
172
		nil,
173
		true,
174
		test.MustParseUrl(t, testServer.URL),
175
	)
176
	assert.NoError(t, err)
177
178
	sut := scan.NewScanner(
179
		c,
180
		prod,
181
		producer.NewReProducer(prod, []int{http.StatusNotFound}),
182
		logger,
183
	)
184
185
	results := make([]scan.Result, 0, 3)
186
	resultsChannel := sut.Scan(test.MustParseUrl(t, testServer.URL), 1)
187
188
	for r := range resultsChannel {
189
		results = append(results, r)
190
	}
191
192
	expectedResults := []scan.Result{
193
		{
194
			Target:     scan.Target{Path: "/home", Method: http.MethodPatch, Depth: 3},
195
			StatusCode: http.StatusMovedPermanently,
196
			URL:        *test.MustParseUrl(t, testServer.URL+"/home"),
197
		},
198
		{
199
			Target:     scan.Target{Path: "/potato", Method: http.MethodGet, Depth: 2},
200
			StatusCode: http.StatusNotFound,
201
			URL:        *test.MustParseUrl(t, testServer.URL+"/potato"),
202
		},
203
		{
204
			Target:     scan.Target{Path: "/home/home", Method: http.MethodPatch, Depth: 2},
205
			StatusCode: http.StatusNotFound,
206
			URL:        *test.MustParseUrl(t, testServer.URL+"/home/home"),
207
		},
208
	}
209
210
	assert.Equal(t, expectedResults, results)
211
212
	loggerBufferAsString := loggerBuffer.String()
213
	assert.Contains(t, loggerBufferAsString, "/home")
214
	assert.Contains(t, loggerBufferAsString, "/potato")
215
	assert.Contains(t, loggerBufferAsString, "/home/home")
216
	assert.NotContains(t, loggerBufferAsString, "error")
217
	assert.Equal(t, 3, serverAssertion.Len())
218
}
219
220
func TestScannerWhenOutOfDepthWillNotFollowRedirect(t *testing.T) {
221
	logger, loggerBuffer := test.NewLogger()
222
223
	prod := producer.NewDictionaryProducer(
224
		[]string{http.MethodPatch},
225
		[]string{"/home"},
226
		0,
227
	)
228
229
	testServer, serverAssertion := test.NewServerWithAssertion(
230
		http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
231
			if r.URL.Path == "/home" {
232
				http.Redirect(w, r, "/potato", http.StatusMovedPermanently)
233
				return
234
			}
235
236
			w.WriteHeader(http.StatusNotFound)
237
		}),
238
	)
239
	defer testServer.Close()
240
241
	c, err := client.NewClientFromConfig(
242
		1000,
243
		nil,
244
		"",
245
		false,
246
		nil,
247
		nil,
248
		true,
249
		test.MustParseUrl(t, testServer.URL),
250
	)
251
	assert.NoError(t, err)
252
253
	sut := scan.NewScanner(
254
		c,
255
		prod,
256
		producer.NewReProducer(prod, []int{http.StatusNotFound}),
257
		logger,
258
	)
259
260
	results := make([]scan.Result, 0, 1)
261
	resultsChannel := sut.Scan(test.MustParseUrl(t, testServer.URL), 1)
262
263
	for r := range resultsChannel {
264
		results = append(results, r)
265
	}
266
267
	expectedResults := []scan.Result{
268
		{
269
			Target:     scan.Target{Path: "/home", Method: http.MethodPatch, Depth: 0},
270
			StatusCode: http.StatusMovedPermanently,
271
			URL:        *test.MustParseUrl(t, testServer.URL+"/home"),
272
		},
273
	}
274
275
	assert.Equal(t, expectedResults, results)
276
277
	loggerBufferAsString := loggerBuffer.String()
278
	assert.Contains(t, loggerBufferAsString, "/home")
279
	assert.Contains(t, loggerBufferAsString, "depth is 0, not following any redirect")
280
	assert.NotContains(t, loggerBufferAsString, "error")
281
	assert.Equal(t, 1, serverAssertion.Len())
282
}
283
284
func TestScannerWillSkipRedirectWhenLocationHostIsDifferent(t *testing.T) {
285
	logger, loggerBuffer := test.NewLogger()
286
287
	prod := producer.NewDictionaryProducer(
288
		[]string{http.MethodPatch},
289
		[]string{"/home"},
290
		3,
291
	)
292
293
	testServer, serverAssertion := test.NewServerWithAssertion(
294
		http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
295
			if r.URL.Path == "/home" {
296
				http.Redirect(w, r, "http://gibberish/potato", http.StatusMovedPermanently)
297
				return
298
			}
299
300
			w.WriteHeader(http.StatusNotFound)
301
		}),
302
	)
303
	defer testServer.Close()
304
305
	c, err := client.NewClientFromConfig(
306
		1000,
307
		nil,
308
		"",
309
		false,
310
		nil,
311
		nil,
312
		true,
313
		test.MustParseUrl(t, testServer.URL),
314
	)
315
	assert.NoError(t, err)
316
317
	sut := scan.NewScanner(
318
		c,
319
		prod,
320
		producer.NewReProducer(prod, []int{http.StatusNotFound}),
321
		logger,
322
	)
323
324
	results := make([]scan.Result, 0, 2)
325
	resultsChannel := sut.Scan(test.MustParseUrl(t, testServer.URL), 1)
326
327
	for r := range resultsChannel {
328
		results = append(results, r)
329
	}
330
331
	expectedResults := []scan.Result{
332
		{
333
			Target:     scan.Target{Path: "/home", Method: http.MethodPatch, Depth: 3},
334
			StatusCode: http.StatusMovedPermanently,
335
			URL:        *test.MustParseUrl(t, testServer.URL+"/home"),
336
		},
337
		{
338
			Target:     scan.Target{Path: "/home/home", Method: http.MethodPatch, Depth: 2},
339
			StatusCode: http.StatusNotFound,
340
			URL:        *test.MustParseUrl(t, testServer.URL+"/home/home"),
341
		},
342
	}
343
344
	assert.Equal(t, expectedResults, results)
345
346
	loggerBufferAsString := loggerBuffer.String()
347
	assert.Contains(t, loggerBufferAsString, "/home")
348
	assert.Contains(t, loggerBufferAsString, "/home/home")
349
	assert.Contains(t, loggerBufferAsString, "skipping redirect, pointing to a different host")
350
	assert.NotContains(t, loggerBufferAsString, "error")
351
	assert.Equal(t, 2, serverAssertion.Len())
352
}
353
354
func TestScannerWillIgnoreRequestRedundantError(t *testing.T) {
355
	logger, loggerBuffer := test.NewLogger()
356
357
	prod := producer.NewDictionaryProducer(
358
		[]string{http.MethodGet},
359
		[]string{"/home", "/home"}, // twice the same entry to trick the client into doing the same request twice
360
		3,
361
	)
362
363
	testServer, serverAssertion := test.NewServerWithAssertion(
364
		http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
365
			w.WriteHeader(http.StatusNotFound)
366
		}),
367
	)
368
	defer testServer.Close()
369
370
	c, err := client.NewClientFromConfig(
371
		1000,
372
		nil,
373
		"",
374
		false,
375
		nil,
376
		nil,
377
		true,
378
		test.MustParseUrl(t, testServer.URL),
379
	)
380
	assert.NoError(t, err)
381
382
	sut := scan.NewScanner(
383
		c,
384
		prod,
385
		producer.NewReProducer(prod, []int{http.StatusNotFound}),
386
		logger,
387
	)
388
389
	results := make([]scan.Result, 0, 1)
390
	resultsChannel := sut.Scan(test.MustParseUrl(t, testServer.URL), 1)
391
392
	for r := range resultsChannel {
393
		results = append(results, r)
394
	}
395
396
	expectedResults := []scan.Result{
397
		{
398
			Target:     scan.Target{Path: "/home", Method: http.MethodGet, Depth: 3},
399
			StatusCode: http.StatusNotFound,
400
			URL:        *test.MustParseUrl(t, testServer.URL+"/home"),
401
		},
402
	}
403
404
	assert.Equal(t, expectedResults, results)
405
406
	loggerBufferAsString := loggerBuffer.String()
407
	assert.Contains(t, loggerBufferAsString, "/home")
408
	assert.Contains(t, loggerBufferAsString, "/home: this request has been made already")
409
	assert.Equal(t, 1, serverAssertion.Len())
410
}
411