Passed
Push — master ( f028f1...4fb92b )
by Stefano
02:12
created

stRedundantError   A

Complexity

Conditions 3

Size

Total Lines 49
Code Lines 35

Duplication

Lines 0
Ratio 0 %

Importance

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