hurley 0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
data/test/test_test.rb ADDED
@@ -0,0 +1,38 @@
1
+ require File.expand_path("../helper", __FILE__)
2
+
3
+ module Hurley
4
+ class TestTest < TestCase
5
+
6
+ def setup
7
+ @stubs = Test.new do |stub|
8
+ stub.get "/a/verboten" do |req|
9
+ [403, {}, ""]
10
+ end
11
+ stub.get("/a") do |req|
12
+ output = %w(fee fi fo fum)
13
+ [200, {}, output.join("\n")]
14
+ end
15
+ end
16
+
17
+ @client = Client.new do |c|
18
+ c.connection = @stubs
19
+ end
20
+ end
21
+
22
+ def test_matches_most_specific_handler
23
+ res = @client.get("/a")
24
+ assert_equal 200, res.status_code
25
+
26
+ res = @client.get("/a/verboten")
27
+ assert_equal 403, res.status_code
28
+ end
29
+
30
+ def test_returns_404_if_no_handler_found
31
+ res = @client.get("/a")
32
+ assert_equal 200, res.status_code
33
+
34
+ res = @client.get("/b")
35
+ assert_equal 404, res.status_code
36
+ end
37
+ end
38
+ end
data/test/url_test.rb ADDED
@@ -0,0 +1,443 @@
1
+ require File.expand_path("../helper", __FILE__)
2
+
3
+ module Hurley
4
+ class UrlTest < TestCase
5
+ def test_integration_join
6
+ test = Test.new
7
+
8
+ ["/foo/bar", "/foo", "/baz"].each do |path|
9
+ test.get("http://example.com" + path) do |req|
10
+ [200, {}, "#{path} http #{req.url.raw_query}".strip]
11
+ end
12
+
13
+ test.get("https://sub.example.com" + path) do |req|
14
+ [200, {}, "#{path} sub #{req.url.raw_query}".strip]
15
+ end
16
+
17
+ test.get(path + "?v=1") do |req|
18
+ [200, {}, "#{path} v1 #{req.url.raw_query}".strip]
19
+ end
20
+
21
+ test.get(path + "?v=2") do |req|
22
+ [200, {}, "#{path} v2 #{req.url.raw_query}".strip]
23
+ end
24
+
25
+ test.get(path) do |req|
26
+ [200, {}, "#{path} #{req.url.raw_query}".strip]
27
+ end
28
+
29
+ test.get("https://example.com" + path) do |req|
30
+ [500, {}, "unreachable"]
31
+ end
32
+ end
33
+
34
+ errors = []
35
+
36
+ extra_tests = {
37
+ "http://example.com/foo" => "/foo http",
38
+ "http://example.com/foo/bar" => "/foo/bar http",
39
+ "http://example.com/baz" => "/baz http",
40
+
41
+ "https://sub.example.com/foo" => "/foo sub",
42
+ "https://sub.example.com/foo/bar" => "/foo/bar sub",
43
+ "https://sub.example.com/baz" => "/baz sub",
44
+ }
45
+
46
+ root_tests = extra_tests.merge(
47
+ "/foo" => "/foo",
48
+ "/foo/" => "/foo",
49
+ "/foo/bar" => "/foo/bar",
50
+ "/foo/bar/" => "/foo/bar",
51
+ "/baz" => "/baz",
52
+ "/baz/" => "/baz",
53
+ "foo" => "/foo",
54
+ "foo/" => "/foo",
55
+ "foo/bar" => "/foo/bar",
56
+ "foo/bar/" => "/foo/bar",
57
+ "baz" => "/baz",
58
+ "baz/" => "/baz",
59
+
60
+ # v1
61
+ "/foo?v=1" => "/foo v1 v=1",
62
+ "/foo/?v=1" => "/foo v1 v=1",
63
+ "/foo/bar?v=1" => "/foo/bar v1 v=1",
64
+ "/foo/bar/?v=1" => "/foo/bar v1 v=1",
65
+ "/baz?v=1" => "/baz v1 v=1",
66
+ "/baz/?v=1" => "/baz v1 v=1",
67
+ "foo?v=1" => "/foo v1 v=1",
68
+ "foo/?v=1" => "/foo v1 v=1",
69
+ "foo/bar?v=1" => "/foo/bar v1 v=1",
70
+ "foo/bar/?v=1" => "/foo/bar v1 v=1",
71
+ "baz?v=1" => "/baz v1 v=1",
72
+ "baz/?v=1" => "/baz v1 v=1",
73
+
74
+ # v2
75
+ "/foo?v=2" => "/foo v2 v=2",
76
+ "/foo/?v=2" => "/foo v2 v=2",
77
+ "/foo/bar?v=2" => "/foo/bar v2 v=2",
78
+ "/foo/bar/?v=2" => "/foo/bar v2 v=2",
79
+ "/baz?v=2" => "/baz v2 v=2",
80
+ "/baz/?v=2" => "/baz v2 v=2",
81
+ "foo?v=2" => "/foo v2 v=2",
82
+ "foo/?v=2" => "/foo v2 v=2",
83
+ "foo/bar?v=2" => "/foo/bar v2 v=2",
84
+ "foo/bar/?v=2" => "/foo/bar v2 v=2",
85
+ "baz?v=2" => "/baz v2 v=2",
86
+ "baz/?v=2" => "/baz v2 v=2",
87
+ )
88
+
89
+ foo_tests = extra_tests.merge(
90
+ "" => "/foo",
91
+ "bar" => "/foo/bar",
92
+ "bar/" => "/foo/bar",
93
+ "/foo" => "/foo",
94
+ "/foo/" => "/foo",
95
+ "/foo/bar" => "/foo/bar",
96
+ "/foo/bar/" => "/foo/bar",
97
+ "/baz" => "/baz",
98
+ "/baz/" => "/baz",
99
+ )
100
+
101
+ {
102
+ "https://example.com" => root_tests,
103
+ "https://example.com/" => root_tests,
104
+ "https://example.com/foo" => foo_tests,
105
+ "https://example.com/foo/" => foo_tests,
106
+ }.each do |endpoint, requests|
107
+ cli = Client.new(endpoint)
108
+ cli.connection = test
109
+
110
+ requests.each do |path, expected|
111
+ res = cli.get(path)
112
+ if res.body != expected
113
+ errors << "#{endpoint} + #{path} == #{res.request.url.inspect}"
114
+ errors << " #{expected.inspect} != #{res.body.inspect}"
115
+ end
116
+ end
117
+ end
118
+
119
+ if errors.any?
120
+ fail "\n" + errors.join("\n")
121
+ end
122
+ end
123
+
124
+ def test_integration_basic_auth
125
+ cli = Client.new "http://a:b@c.com/d"
126
+ cli.connection = Test.new do |t|
127
+ t.get "/d/e" do |req|
128
+ token = req.header[:authorization].split(" ").last
129
+ [200, {}, Base64.decode64(token)]
130
+ end
131
+ end
132
+
133
+ req = cli.request :get, "e"
134
+ res = cli.call req
135
+
136
+ assert_equal 200, res.status_code
137
+ assert_equal "a:b", res.body
138
+ end
139
+
140
+ def test_join
141
+ errors = []
142
+
143
+ {
144
+ "https://example.com?v=1" => {
145
+ "" => "https://example.com?v=1",
146
+ "/" => "https://example.com/?v=1",
147
+ "?a=1" => "https://example.com?a=1&v=1",
148
+ "/?a=1" => "https://example.com/?a=1&v=1",
149
+ "?v=2&a=1" => "https://example.com?v=2&a=1",
150
+ "/?v=2&a=1" => "https://example.com/?v=2&a=1",
151
+ "a" => "https://example.com/a?v=1",
152
+ "a/" => "https://example.com/a/?v=1",
153
+ "a?a=1" => "https://example.com/a?a=1&v=1",
154
+ "a/?a=1" => "https://example.com/a/?a=1&v=1",
155
+ "a?v=2&a=1" => "https://example.com/a?v=2&a=1",
156
+ "a/?v=2&a=1" => "https://example.com/a/?v=2&a=1",
157
+ "a/b" => "https://example.com/a/b?v=1",
158
+ "a/b/" => "https://example.com/a/b/?v=1",
159
+ "a/b?a=1" => "https://example.com/a/b?a=1&v=1",
160
+ "a/b/?a=1" => "https://example.com/a/b/?a=1&v=1",
161
+ "a/b?v=2&a=1" => "https://example.com/a/b?v=2&a=1",
162
+ "a/b/?v=2&a=1" => "https://example.com/a/b/?v=2&a=1",
163
+ },
164
+
165
+ "https://example.com/?v=1" => {
166
+ "" => "https://example.com/?v=1",
167
+ "/" => "https://example.com/?v=1",
168
+ "?a=1" => "https://example.com/?a=1&v=1",
169
+ "/?a=1" => "https://example.com/?a=1&v=1",
170
+ "?v=2&a=1" => "https://example.com/?v=2&a=1",
171
+ "/?v=2&a=1" => "https://example.com/?v=2&a=1",
172
+ "a" => "https://example.com/a?v=1",
173
+ "a/" => "https://example.com/a/?v=1",
174
+ "a?a=1" => "https://example.com/a?a=1&v=1",
175
+ "a/?a=1" => "https://example.com/a/?a=1&v=1",
176
+ "a?v=2&a=1" => "https://example.com/a?v=2&a=1",
177
+ "a/?v=2&a=1" => "https://example.com/a/?v=2&a=1",
178
+ "a/b" => "https://example.com/a/b?v=1",
179
+ "a/b/" => "https://example.com/a/b/?v=1",
180
+ "a/b?a=1" => "https://example.com/a/b?a=1&v=1",
181
+ "a/b/?a=1" => "https://example.com/a/b/?a=1&v=1",
182
+ "a/b?v=2&a=1" => "https://example.com/a/b?v=2&a=1",
183
+ "a/b/?v=2&a=1" => "https://example.com/a/b/?v=2&a=1",
184
+ },
185
+
186
+ "https://example.com/a?v=1" => {
187
+ "" => "https://example.com/a?v=1",
188
+ "/" => "https://example.com/?v=1",
189
+ "?a=1" => "https://example.com/a?a=1&v=1",
190
+ "/?a=1" => "https://example.com/?a=1&v=1",
191
+ "?v=2&a=1" => "https://example.com/a?v=2&a=1",
192
+ "/?v=2&a=1" => "https://example.com/?v=2&a=1",
193
+ "/a" => "https://example.com/a?v=1",
194
+ "/a/" => "https://example.com/a/?v=1",
195
+ "/a?a=1" => "https://example.com/a?a=1&v=1",
196
+ "/a/?a=1" => "https://example.com/a/?a=1&v=1",
197
+ "/a?v=2&a=1" => "https://example.com/a?v=2&a=1",
198
+ "/a/?v=2&a=1" => "https://example.com/a/?v=2&a=1",
199
+ "/a/b" => "https://example.com/a/b?v=1",
200
+ "/a/b/" => "https://example.com/a/b/?v=1",
201
+ "/a/b?a=1" => "https://example.com/a/b?a=1&v=1",
202
+ "/a/b/?a=1" => "https://example.com/a/b/?a=1&v=1",
203
+ "/a/b?v=2&a=1" => "https://example.com/a/b?v=2&a=1",
204
+ "/a/b/?v=2&a=1" => "https://example.com/a/b/?v=2&a=1",
205
+ "c" => "https://example.com/a/c?v=1",
206
+ "c/" => "https://example.com/a/c/?v=1",
207
+ "c?a=1" => "https://example.com/a/c?a=1&v=1",
208
+ "c/?a=1" => "https://example.com/a/c/?a=1&v=1",
209
+ "c?v=2&a=1" => "https://example.com/a/c?v=2&a=1",
210
+ "c/?v=2&a=1" => "https://example.com/a/c/?v=2&a=1",
211
+ "/c" => "https://example.com/c?v=1",
212
+ "/c/" => "https://example.com/c/?v=1",
213
+ "/c?a=1" => "https://example.com/c?a=1&v=1",
214
+ "/c/?a=1" => "https://example.com/c/?a=1&v=1",
215
+ "/c?v=2&a=1" => "https://example.com/c?v=2&a=1",
216
+ "/c/?v=2&a=1" => "https://example.com/c/?v=2&a=1",
217
+ },
218
+
219
+ "https://example.com/a/?v=1" => {
220
+ "" => "https://example.com/a/?v=1",
221
+ "/" => "https://example.com/?v=1",
222
+ "?a=1" => "https://example.com/a/?a=1&v=1",
223
+ "/?a=1" => "https://example.com/?a=1&v=1",
224
+ "?v=2&a=1" => "https://example.com/a/?v=2&a=1",
225
+ "/?v=2&a=1" => "https://example.com/?v=2&a=1",
226
+ "/a" => "https://example.com/a?v=1",
227
+ "/a/" => "https://example.com/a/?v=1",
228
+ "/a?a=1" => "https://example.com/a?a=1&v=1",
229
+ "/a/?a=1" => "https://example.com/a/?a=1&v=1",
230
+ "/a?v=2&a=1" => "https://example.com/a?v=2&a=1",
231
+ "/a/?v=2&a=1" => "https://example.com/a/?v=2&a=1",
232
+ "/a/b" => "https://example.com/a/b?v=1",
233
+ "/a/b/" => "https://example.com/a/b/?v=1",
234
+ "/a/b?a=1" => "https://example.com/a/b?a=1&v=1",
235
+ "/a/b/?a=1" => "https://example.com/a/b/?a=1&v=1",
236
+ "/a/b?v=2&a=1" => "https://example.com/a/b?v=2&a=1",
237
+ "/a/b/?v=2&a=1" => "https://example.com/a/b/?v=2&a=1",
238
+ "c" => "https://example.com/a/c?v=1",
239
+ "c/" => "https://example.com/a/c/?v=1",
240
+ "c?a=1" => "https://example.com/a/c?a=1&v=1",
241
+ "c/?a=1" => "https://example.com/a/c/?a=1&v=1",
242
+ "c?v=2&a=1" => "https://example.com/a/c?v=2&a=1",
243
+ "c/?v=2&a=1" => "https://example.com/a/c/?v=2&a=1",
244
+ "/c" => "https://example.com/c?v=1",
245
+ "/c/" => "https://example.com/c/?v=1",
246
+ "/c?a=1" => "https://example.com/c?a=1&v=1",
247
+ "/c/?a=1" => "https://example.com/c/?a=1&v=1",
248
+ "/c?v=2&a=1" => "https://example.com/c?v=2&a=1",
249
+ "/c/?v=2&a=1" => "https://example.com/c/?v=2&a=1",
250
+ },
251
+
252
+ "http://example.com" => {
253
+ "" => "http://example.com",
254
+ "/" => "http://example.com/",
255
+ "https://example.com" => "https://example.com",
256
+ "https://example.com:8080" => "https://example.com:8080",
257
+ },
258
+
259
+ "http://example.com:8080" => {
260
+ "" => "http://example.com:8080",
261
+ "/" => "http://example.com:8080/",
262
+ "https://example.com" => "https://example.com",
263
+ "https://example.com:8080" => "https://example.com:8080",
264
+ },
265
+ }.each do |endpoint, tests|
266
+ absolute = Url.parse(endpoint)
267
+ tests.each do |input, expected|
268
+ actual = Url.join(absolute, input).to_s
269
+ if actual != expected
270
+ errors << "#{endpoint.inspect} + #{input.inspect} = #{actual.inspect}, not #{expected.inspect}"
271
+ end
272
+ end
273
+ end
274
+
275
+ if errors.any?
276
+ fail "\n" + errors.join("\n")
277
+ end
278
+ end
279
+
280
+ def test_escape
281
+ {
282
+ "abc" => "abc",
283
+ "a/b" => "a%2Fb",
284
+ "a b" => "a%20b",
285
+ "a+b" => "a%2Bb",
286
+ "a +b" => "a%20%2Bb",
287
+ "a&b" => "a%26b",
288
+ "a=b" => "a%3Db",
289
+ "a;b" => "a%3Bb",
290
+ "a?b" => "a%3Fb",
291
+ }.each do |input, expected|
292
+ assert_equal expected, Url.escape_path(input)
293
+ end
294
+ end
295
+
296
+ def test_escape_paths
297
+ assert_equal "a%20%2B%201/b%3B1", Url.escape_paths("a + 1", "b;1")
298
+ end
299
+
300
+ def test_parse_empty
301
+ u = Url.parse(nil)
302
+ assert_nil u.scheme
303
+ assert_nil u.host
304
+ assert_nil u.port
305
+ assert_equal "", u.path
306
+ assert_equal "", u.to_s
307
+ assert_nil u.user
308
+ assert_nil u.password
309
+ end
310
+
311
+ def test_parse_only_path
312
+ u = Url.parse("/foo")
313
+ assert_nil u.scheme
314
+ assert_nil u.host
315
+ assert_nil u.port
316
+ assert_equal "/foo", u.path
317
+ assert_equal "/foo", u.to_s
318
+ assert_nil u.user
319
+ assert_nil u.password
320
+ end
321
+
322
+ def test_parse_url_with_host
323
+ u = Url.parse("https://example.com?a=1")
324
+ assert_equal "https", u.scheme
325
+ assert_equal "example.com", u.host
326
+ assert_equal 443, u.port
327
+ assert_equal "", u.path
328
+ assert_equal "a=1", u.raw_query
329
+ assert_equal %w(a), u.query.keys
330
+ assert_equal "1", u.query["a"]
331
+ assert_nil u.user
332
+ assert_nil u.password
333
+ assert_equal "https://example.com?a=1", u.to_s
334
+ end
335
+
336
+ def test_parse_url_with_slash
337
+ u = Url.parse("https://example.com/?a=1")
338
+ assert_equal "https", u.scheme
339
+ assert_equal "example.com", u.host
340
+ assert_equal 443, u.port
341
+ assert_equal "/", u.path
342
+ assert_equal "a=1", u.raw_query
343
+ assert_equal %w(a), u.query.keys
344
+ assert_equal "1", u.query["a"]
345
+ assert_nil u.user
346
+ assert_nil u.password
347
+ assert_equal "https://example.com/?a=1", u.to_s
348
+ end
349
+
350
+ def test_parse_url_with_path
351
+ u = Url.parse("https://example.com/foo?a=1")
352
+ assert_equal "https", u.scheme
353
+ assert_equal "example.com", u.host
354
+ assert_equal 443, u.port
355
+ assert_equal "/foo", u.path
356
+ assert_equal "a=1", u.raw_query
357
+ assert_equal %w(a), u.query.keys
358
+ assert_equal "1", u.query["a"]
359
+ assert_nil u.user
360
+ assert_nil u.password
361
+ assert_equal "https://example.com/foo?a=1", u.to_s
362
+ end
363
+
364
+ def test_parse_url_with_auth
365
+ u = Url.parse("https://a:b%20c@example.com")
366
+ assert_equal "https", u.scheme
367
+ assert_equal "example.com", u.host
368
+ assert_equal 443, u.port
369
+ assert_equal "", u.path
370
+ assert_equal "a", u.user
371
+ assert_equal "b c", u.password
372
+ assert_equal "https://example.com", u.to_s
373
+ end
374
+
375
+ def test_join_auth_url_with_url
376
+ u = Url.join("http://a:b@c.com", "/path")
377
+ assert_equal "a", u.user
378
+ assert_equal "b", u.password
379
+ assert_equal "http://c.com/path", u.to_s
380
+ end
381
+
382
+ def test_join_auth_url_with_url_of_same_host
383
+ u = Url.join("http://a:b@c.com", "http://c.com/path")
384
+ assert_equal "a", u.user
385
+ assert_equal "b", u.password
386
+ assert_equal "http://c.com/path", u.to_s
387
+ end
388
+
389
+ def test_join_auth_url_with_url_of_different_host
390
+ u = Url.join("http://a:b@c.com", "http://d.com/path")
391
+ assert_nil u.user
392
+ assert_nil u.password
393
+ assert_equal "http://d.com/path", u.to_s
394
+ end
395
+
396
+ def test_basic_auth_user_with_password
397
+ u = Url.parse("http://a%20b:1%20%2B%202@foo.com")
398
+ assert_equal "a b", u.user
399
+ assert_equal "1 + 2", u.password
400
+ assert_equal "Basic #{Base64.encode64("a b:1 + 2").rstrip}", u.basic_auth
401
+ end
402
+
403
+ def test_basic_auth_user_without_password
404
+ u = Url.parse("http://a%20b@foo.com")
405
+ assert_equal "a b", u.user
406
+ assert_nil u.password
407
+ assert_equal "Basic #{Base64.encode64("a b").rstrip}", u.basic_auth
408
+ end
409
+
410
+ def test_join_url_with_auth_url
411
+ u = Url.join("http://c.com/path", "http://a:b@c.com")
412
+ assert_equal "a", u.user
413
+ assert_equal "b", u.password
414
+ assert_equal "http://c.com/path", u.to_s
415
+ end
416
+
417
+ def test_change_query_class
418
+ u = Url.parse "http://a.com?b=c"
419
+ u.query_class = Query::Nested
420
+
421
+ assert_equal "b=c", u.raw_query
422
+ assert_kind_of Query::Nested, u.query
423
+
424
+ u.query["d"] = "f"
425
+ u.query["a"] = [1,2]
426
+ assert_equal "b=c&d=f&a%5B%5D=1&a%5B%5D=2", u.raw_query
427
+
428
+ u.query_class = Query::Flat
429
+ assert_kind_of Query::Flat, u.query
430
+ assert_equal "b=c&d=f&a=1&a=2", u.raw_query
431
+ end
432
+
433
+ def test_url_parser
434
+ expected = if ENV["HURLEY_ADDRESSABLE"]
435
+ "Addressable::URI"
436
+ else
437
+ "URI::HTTPS"
438
+ end
439
+
440
+ assert_equal expected, Url.parse("https://example.com").instance_variable_get(:@parsed).class.name
441
+ end
442
+ end
443
+ end