Passed
Push — master ( d53f06...3b5095 )
by Stefano
02:29
created

cmd_test.TestScanWithCookies   A

Complexity

Conditions 3

Size

Total Lines 31
Code Lines 23

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 3
eloc 23
nop 1
dl 0
loc 31
rs 9.328
c 0
b 0
f 0
1
package cmd_test
2
3
import (
4
	"bytes"
5
	"io/ioutil"
6
	"net/http"
7
	"net/http/httptest"
8
	"os"
9
	"strings"
10
	"sync"
11
	"testing"
12
	"time"
13
14
	"github.com/pkg/errors"
15
	"github.com/sirupsen/logrus"
16
	"github.com/spf13/cobra"
17
	"github.com/stefanoj3/dirstalk/pkg/cmd"
18
	"github.com/stefanoj3/dirstalk/pkg/common/test"
19
	"github.com/stretchr/testify/assert"
20
)
21
22
func TestRootCommand(t *testing.T) {
23
	logger, _ := test.NewLogger()
24
25
	c, err := createCommand(logger)
26
	assert.NoError(t, err)
27
	assert.NotNil(t, c)
28
29
	_, out, err := executeCommand(c)
30
	assert.NoError(t, err)
31
32
	// ensure the summary is printed
33
	assert.Contains(t, out, "dirstalk is a tool that attempts")
34
	assert.Contains(t, out, "Usage")
35
	assert.Contains(t, out, "dictionary.generate")
36
	assert.Contains(t, out, "scan")
37
}
38
39
func TestScanCommand(t *testing.T) {
40
	logger, _ := test.NewLogger()
41
42
	c, err := createCommand(logger)
43
	assert.NoError(t, err)
44
	assert.NotNil(t, c)
45
46
	testServer, serverAssertion := test.NewServerWithAssertion(
47
		http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
48
			w.WriteHeader(http.StatusNotFound)
49
		}),
50
	)
51
	defer testServer.Close()
52
53
	_, _, err = executeCommand(c, "scan", testServer.URL, "--dictionary", "testdata/dict.txt", "-v")
54
	assert.NoError(t, err)
55
56
	assert.Equal(t, 3, serverAssertion.Len())
57
}
58
59
func TestScanWithRemoteDictionary(t *testing.T) {
60
	logger, _ := test.NewLogger()
61
62
	c, err := createCommand(logger)
63
	assert.NoError(t, err)
64
	assert.NotNil(t, c)
65
66
	dictionaryServer := httptest.NewServer(
67
		http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
68
			dict := `home
69
home/index.php
70
blabla
71
`
72
			w.WriteHeader(http.StatusOK)
73
			_, _ = w.Write([]byte(dict))
74
		}),
75
	)
76
	defer dictionaryServer.Close()
77
78
	testServer, serverAssertion := test.NewServerWithAssertion(
79
		http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
80
			w.WriteHeader(http.StatusNotFound)
81
		}),
82
	)
83
	defer testServer.Close()
84
85
	_, _, err = executeCommand(c, "scan", testServer.URL, "--dictionary", dictionaryServer.URL)
86
	assert.NoError(t, err)
87
88
	assert.Equal(t, 3, serverAssertion.Len())
89
}
90
91
func TestScanWithUserAgentFlag(t *testing.T) {
92
	const testUserAgent = "my_test_user_agent"
93
94
	logger, _ := test.NewLogger()
95
96
	c, err := createCommand(logger)
97
	assert.NoError(t, err)
98
	assert.NotNil(t, c)
99
100
	testServer, serverAssertion := test.NewServerWithAssertion(
101
		http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
102
			w.WriteHeader(http.StatusNotFound)
103
		}),
104
	)
105
	defer testServer.Close()
106
107
	_, _, err = executeCommand(
108
		c,
109
		"scan",
110
		testServer.URL,
111
		"--user-agent",
112
		testUserAgent,
113
		"--dictionary",
114
		"testdata/dict.txt",
115
	)
116
	assert.NoError(t, err)
117
118
	assert.Equal(t, 3, serverAssertion.Len())
119
	serverAssertion.Range(func(_ int, r http.Request) {
120
		assert.Equal(t, testUserAgent, r.Header.Get("User-Agent"))
121
	})
122
}
123
124
func TestScanWithCookies(t *testing.T) {
125
	logger, _ := test.NewLogger()
126
127
	c, err := createCommand(logger)
128
	assert.NoError(t, err)
129
	assert.NotNil(t, c)
130
131
	testServer, serverAssertion := test.NewServerWithAssertion(
132
		http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {}),
133
	)
134
	defer testServer.Close()
135
136
	_, _, err = executeCommand(
137
		c,
138
		"scan",
139
		testServer.URL,
140
		"--cookies",
141
		"name1=val1,name2=val2",
142
		"--dictionary",
143
		"testdata/dict.txt",
144
	)
145
	assert.NoError(t, err)
146
147
	serverAssertion.Range(func(_ int, r http.Request) {
148
		assert.Equal(t, 2, len(r.Cookies()))
149
150
		assert.Equal(t, r.Cookies()[0].Name, "name1")
151
		assert.Equal(t, r.Cookies()[0].Value, "val1")
152
153
		assert.Equal(t, r.Cookies()[1].Name, "name2")
154
		assert.Equal(t, r.Cookies()[1].Value, "val2")
155
	})
156
}
157
158
func TestWhenProvidingCookiesInWrongFormatShouldErr(t *testing.T) {
159
	const malformedCookie = "gibberish"
160
161
	logger, _ := test.NewLogger()
162
163
	c, err := createCommand(logger)
164
	assert.NoError(t, err)
165
	assert.NotNil(t, c)
166
167
	testServer, serverAssertion := test.NewServerWithAssertion(
168
		http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
169
			w.WriteHeader(http.StatusNotFound)
170
		}),
171
	)
172
	defer testServer.Close()
173
174
	_, _, err = executeCommand(
175
		c,
176
		"scan",
177
		testServer.URL,
178
		"--cookies",
179
		malformedCookie,
180
		"--dictionary",
181
		"testdata/dict.txt",
182
	)
183
	assert.Error(t, err)
184
	assert.Contains(t, err.Error(), "cookie format is invalid")
185
	assert.Contains(t, err.Error(), malformedCookie)
186
187
	assert.Equal(t, 0, serverAssertion.Len())
188
}
189
190
func TestScanWithCookieJar(t *testing.T) {
191
	const (
192
		serverCookieName  = "server_cookie_name"
193
		serverCookieValue = "server_cookie_value"
194
	)
195
196
	logger, _ := test.NewLogger()
197
198
	c, err := createCommand(logger)
199
	assert.NoError(t, err)
200
	assert.NotNil(t, c)
201
202
	once := sync.Once{}
203
	testServer, serverAssertion := test.NewServerWithAssertion(
204
		http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
205
			once.Do(func() {
206
				http.SetCookie(
207
					w,
208
					&http.Cookie{
209
						Name:    serverCookieName,
210
						Value:   serverCookieValue,
211
						Expires: time.Now().AddDate(0, 1, 0),
212
					},
213
				)
214
			})
215
		}),
216
	)
217
	defer testServer.Close()
218
219
	_, _, err = executeCommand(
220
		c,
221
		"scan",
222
		testServer.URL,
223
		"--use-cookie-jar",
224
		"--dictionary",
225
		"testdata/dict.txt",
226
		"-t",
227
		"1",
228
	)
229
	assert.NoError(t, err)
230
231
	serverAssertion.Range(func(index int, r http.Request) {
232
		if index == 0 { // first request should have no cookies
233
			assert.Equal(t, 0, len(r.Cookies()))
234
			return
235
		}
236
237
		assert.Equal(t, 1, len(r.Cookies()))
238
		assert.Equal(t, r.Cookies()[0].Name, serverCookieName)
239
		assert.Equal(t, r.Cookies()[0].Value, serverCookieValue)
240
	})
241
}
242
243
func TestDictionaryGenerateCommand(t *testing.T) {
244
	logger, _ := test.NewLogger()
245
246
	c, err := createCommand(logger)
247
	assert.NoError(t, err)
248
	assert.NotNil(t, c)
249
250
	testFilePath := "testdata/" + test.RandStringRunes(10)
251
	defer removeTestFile(testFilePath)
252
	_, _, err = executeCommand(c, "dictionary.generate", ".", "-o", testFilePath)
253
	assert.NoError(t, err)
254
255
	content, err := ioutil.ReadFile(testFilePath)
256
	assert.NoError(t, err)
257
258
	// Ensure the command ran and produced some of the expected output
259
	// it is not in the scope of this test to ensure the correct output
260
	assert.Contains(t, string(content), "root_integration_test.go")
261
}
262
263
func TestGenerateDictionaryWithoutOutputPath(t *testing.T) {
264
	logger, _ := test.NewLogger()
265
266
	c, err := createCommand(logger)
267
	assert.NoError(t, err)
268
	assert.NotNil(t, c)
269
270
	_, _, err = executeCommand(c, "dictionary.generate", ".")
271
	assert.NoError(t, err)
272
}
273
274
func TestGenerateDictionaryWithInvalidDirectory(t *testing.T) {
275
	logger, _ := test.NewLogger()
276
277
	fakePath := "./" + test.RandStringRunes(10)
278
	c, err := createCommand(logger)
279
	assert.NoError(t, err)
280
	assert.NotNil(t, c)
281
282
	_, _, err = executeCommand(c, "dictionary.generate", fakePath)
283
	assert.Error(t, err)
284
285
	assert.Contains(t, err.Error(), "unable to use the provided path")
286
	assert.Contains(t, err.Error(), fakePath)
287
}
288
289
func TestVersionCommand(t *testing.T) {
290
	logger, buf := test.NewLogger()
291
292
	c, err := createCommand(logger)
293
	assert.NoError(t, err)
294
	assert.NotNil(t, c)
295
296
	_, _, err = executeCommand(c, "version")
297
	assert.NoError(t, err)
298
299
	// Ensure the command ran and produced some of the expected output
300
	// it is not in the scope of this test to ensure the correct output
301
	assert.Contains(t, buf.String(), "Version: ")
302
}
303
304
func executeCommand(root *cobra.Command, args ...string) (c *cobra.Command, output string, err error) {
305
	buf := new(bytes.Buffer)
306
	root.SetOutput(buf)
307
308
	a := []string{""}
309
	os.Args = append(a, args...)
310
311
	c, err = root.ExecuteC()
312
313
	return c, buf.String(), err
314
}
315
316
func removeTestFile(path string) {
317
	if !strings.Contains(path, "testdata") {
318
		return
319
	}
320
321
	_ = os.Remove(path)
322
}
323
324
func createCommand(logger *logrus.Logger) (*cobra.Command, error) {
325
	dirStalkCmd, err := cmd.NewRootCommand(logger)
326
	if err != nil {
327
		return nil, err
328
	}
329
330
	scanCmd, err := cmd.NewScanCommand(logger)
331
	if err != nil {
332
		return nil, errors.Wrap(err, "failed to create scan command")
333
	}
334
335
	dirStalkCmd.AddCommand(scanCmd)
336
	dirStalkCmd.AddCommand(cmd.NewGenerateDictionaryCommand())
337
	dirStalkCmd.AddCommand(cmd.NewVersionCommand(logger.Out))
338
339
	return dirStalkCmd, nil
340
}
341