doze 0.0.11
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/README +6 -0
- data/lib/doze/application.rb +92 -0
- data/lib/doze/collection/object.rb +14 -0
- data/lib/doze/entity.rb +62 -0
- data/lib/doze/error.rb +75 -0
- data/lib/doze/media_type.rb +135 -0
- data/lib/doze/negotiator.rb +107 -0
- data/lib/doze/request.rb +119 -0
- data/lib/doze/resource/error.rb +21 -0
- data/lib/doze/resource/proxy.rb +81 -0
- data/lib/doze/resource.rb +193 -0
- data/lib/doze/responder/error.rb +34 -0
- data/lib/doze/responder/main.rb +41 -0
- data/lib/doze/responder/resource.rb +262 -0
- data/lib/doze/responder.rb +58 -0
- data/lib/doze/response.rb +78 -0
- data/lib/doze/router/anchored_route_set.rb +68 -0
- data/lib/doze/router/route.rb +88 -0
- data/lib/doze/router/route_set.rb +34 -0
- data/lib/doze/router.rb +100 -0
- data/lib/doze/serialization/entity.rb +34 -0
- data/lib/doze/serialization/form_data_helpers.rb +40 -0
- data/lib/doze/serialization/html.rb +116 -0
- data/lib/doze/serialization/json.rb +29 -0
- data/lib/doze/serialization/multipart_form_data.rb +162 -0
- data/lib/doze/serialization/resource.rb +30 -0
- data/lib/doze/serialization/resource_proxy.rb +14 -0
- data/lib/doze/serialization/www_form_encoded.rb +42 -0
- data/lib/doze/serialization/yaml.rb +25 -0
- data/lib/doze/uri_template.rb +220 -0
- data/lib/doze/utils.rb +53 -0
- data/lib/doze/version.rb +3 -0
- data/lib/doze.rb +5 -0
- data/test/functional/auth_test.rb +69 -0
- data/test/functional/base.rb +159 -0
- data/test/functional/cache_header_test.rb +76 -0
- data/test/functional/direct_response_test.rb +16 -0
- data/test/functional/error_handling_test.rb +131 -0
- data/test/functional/get_and_conneg_test.rb +182 -0
- data/test/functional/media_type_extensions_test.rb +102 -0
- data/test/functional/media_type_test.rb +40 -0
- data/test/functional/method_support_test.rb +49 -0
- data/test/functional/non_get_method_test.rb +173 -0
- data/test/functional/precondition_test.rb +84 -0
- data/test/functional/raw_path_info_test.rb +69 -0
- data/test/functional/resource_representation_test.rb +14 -0
- data/test/functional/router_test.rb +196 -0
- data/test/functional/serialization_test.rb +142 -0
- data/test/functional/uri_template_test.rb +51 -0
- metadata +221 -0
@@ -0,0 +1,40 @@
|
|
1
|
+
require 'functional/base'
|
2
|
+
|
3
|
+
require 'doze/media_type'
|
4
|
+
|
5
|
+
class MediaTypeTest < Test::Unit::TestCase
|
6
|
+
include Doze::Utils
|
7
|
+
include Doze::TestCase
|
8
|
+
include Doze::MediaTypeTestCase
|
9
|
+
|
10
|
+
def test_put_registered_media_type_same_instance
|
11
|
+
foobar = Doze::MediaType.register('application/x-foo-bar')
|
12
|
+
root.expects(:supports_put?).returns(true)
|
13
|
+
root.expects(:accepts_put_with_media_type?).returns(true)
|
14
|
+
root.expects(:put).with {|entity| entity.media_type.equal?(foobar)}.returns(nil).once
|
15
|
+
put('CONTENT_TYPE' => 'application/x-foo-bar', :input => 'foo')
|
16
|
+
assert_equal STATUS_NO_CONTENT, last_response.status
|
17
|
+
end
|
18
|
+
|
19
|
+
def test_put_unregistered_media_type_equal
|
20
|
+
boo = Doze::MediaType.new('application/x-boo')
|
21
|
+
root.expects(:supports_put?).returns(true)
|
22
|
+
root.expects(:accepts_put_with_media_type?).returns(true)
|
23
|
+
root.expects(:put).with {|entity| entity && entity.media_type == boo}.returns(nil).once
|
24
|
+
put('CONTENT_TYPE' => 'application/x-boo', :input => 'foo')
|
25
|
+
assert_equal STATUS_NO_CONTENT, last_response.status
|
26
|
+
end
|
27
|
+
|
28
|
+
|
29
|
+
|
30
|
+
def test_lookup_name
|
31
|
+
mt = Doze::MediaType.register("application/foo")
|
32
|
+
assert Doze::MediaType["application/foo"].equal?(mt)
|
33
|
+
end
|
34
|
+
|
35
|
+
def test_lookup_alias
|
36
|
+
mt = Doze::MediaType.register("application/foo", :aliases => ['bar/foo'])
|
37
|
+
assert_equal Doze::MediaType["bar/foo"], mt
|
38
|
+
assert_equal ['application/foo', 'bar/foo'], mt.names
|
39
|
+
end
|
40
|
+
end
|
@@ -0,0 +1,49 @@
|
|
1
|
+
require 'functional/base'
|
2
|
+
|
3
|
+
class MethodSupportTest < Test::Unit::TestCase
|
4
|
+
include Doze::Utils
|
5
|
+
include Doze::TestCase
|
6
|
+
|
7
|
+
def test_unrecognized_method
|
8
|
+
app(:recognized_methods => [:get,:put,:post,:delete])
|
9
|
+
root.expects(:supports_method?).never
|
10
|
+
assert_equal STATUS_NOT_IMPLEMENTED, other_request_method('FOO').status
|
11
|
+
end
|
12
|
+
|
13
|
+
def test_recognized_but_not_supported_method
|
14
|
+
app(:recognized_methods => [:foo,:bar])
|
15
|
+
|
16
|
+
seq = sequence('support_calls')
|
17
|
+
root.expects(:supports_method?).with(:foo).returns(false).at_least_once.in_sequence(seq)
|
18
|
+
root.expects(:supports_method?).with(:bar).returns(true).at_least_once.in_sequence(seq)
|
19
|
+
|
20
|
+
assert_equal STATUS_METHOD_NOT_ALLOWED, other_request_method('FOO').status
|
21
|
+
allow = last_response.headers['Allow'] and allow = allow.split(', ')
|
22
|
+
assert_equal ['BAR','OPTIONS'], allow.sort
|
23
|
+
end
|
24
|
+
|
25
|
+
def test_recognized_and_supported_method_via_supports_foo
|
26
|
+
app(:recognized_methods => [:foo,:bar])
|
27
|
+
|
28
|
+
root.expects(:supports_foo?).returns(true).at_least_once
|
29
|
+
root.expects(:accepts_method_with_media_type?).with(:foo, anything).returns(true).at_least_once
|
30
|
+
root.expects(:supports_bar?).never
|
31
|
+
root.expects(:other_method).with(:foo, anything).returns(nil).once
|
32
|
+
assert_equal STATUS_NO_CONTENT, other_request_method('FOO').status
|
33
|
+
end
|
34
|
+
|
35
|
+
def test_options_with_get_supported_with_head_and_options_handled_automatically
|
36
|
+
root.expects(:supports_get?).returns(true).once
|
37
|
+
assert_equal STATUS_NO_CONTENT, other_request_method('OPTIONS').status
|
38
|
+
|
39
|
+
allow = last_response.headers['Allow'] and allow = allow.split(', ')
|
40
|
+
assert_not_nil allow
|
41
|
+
assert_equal ['GET','HEAD','OPTIONS'], allow.sort
|
42
|
+
end
|
43
|
+
|
44
|
+
def test_options_on_missing_resource
|
45
|
+
assert_equal STATUS_NO_CONTENT, other_request_method('OPTIONS', '/blah').status
|
46
|
+
allow = last_response.headers['Allow'] and allow = allow.split(', ')
|
47
|
+
assert_equal ['OPTIONS'], allow
|
48
|
+
end
|
49
|
+
end
|
@@ -0,0 +1,173 @@
|
|
1
|
+
require 'functional/base'
|
2
|
+
|
3
|
+
class NonGetMethodTest < Test::Unit::TestCase
|
4
|
+
include Doze::Utils
|
5
|
+
include Doze::TestCase
|
6
|
+
include Doze::MediaTypeTestCase
|
7
|
+
|
8
|
+
def setup
|
9
|
+
super
|
10
|
+
@foo = Doze::MediaType.new('text/foo')
|
11
|
+
@bar = Doze::MediaType.new('text/bar')
|
12
|
+
end
|
13
|
+
|
14
|
+
def test_put_with_unacceptable_media_type
|
15
|
+
root.expects(:supports_put?).returns(true)
|
16
|
+
root.expects(:accepts_put_with_media_type?).with do |a|
|
17
|
+
a.is_a?(Doze::Entity) && a.media_type == @foo &&
|
18
|
+
a.binary_data_stream.respond_to?(:read) && a.binary_data_stream.read == 'foo' &&
|
19
|
+
a.binary_data == 'foo'
|
20
|
+
end.returns(false)
|
21
|
+
root.expects(:put).never
|
22
|
+
put('CONTENT_TYPE' => 'text/foo', :input => 'foo')
|
23
|
+
assert_equal STATUS_UNSUPPORTED_MEDIA_TYPE, last_response.status
|
24
|
+
end
|
25
|
+
|
26
|
+
def test_put
|
27
|
+
root.expects(:supports_put?).returns(true)
|
28
|
+
root.expects(:accepts_put_with_media_type?).with {|a| a.is_a?(Doze::Entity) && a.media_type == @foo}.returns(true)
|
29
|
+
root.expects(:put).with do |value|
|
30
|
+
value.is_a?(Doze::Entity) and
|
31
|
+
value.binary_data == 'foo' and value.media_type == @foo and value.encoding == 'foobar'
|
32
|
+
end.returns(nil).once
|
33
|
+
|
34
|
+
put('CONTENT_TYPE' => 'text/foo; charset=foobar', :input => 'foo')
|
35
|
+
assert_equal STATUS_NO_CONTENT, last_response.status
|
36
|
+
end
|
37
|
+
|
38
|
+
def test_put_where_not_exists
|
39
|
+
root.expects(:exists?).returns(false)
|
40
|
+
root.expects(:supports_put?).returns(true)
|
41
|
+
root.expects(:accepts_put_with_media_type?).with {|a| a.is_a?(Doze::Entity) && a.media_type == @foo}.returns(true)
|
42
|
+
root.expects(:put).returns(nil).once
|
43
|
+
|
44
|
+
put('CONTENT_TYPE' => 'text/foo; charset=foobar', :input => 'foo')
|
45
|
+
assert_equal STATUS_CREATED, last_response.status
|
46
|
+
end
|
47
|
+
|
48
|
+
def test_post_with_unacceptable_media_type
|
49
|
+
root.expects(:supports_post?).returns(true)
|
50
|
+
root.expects(:accepts_post_with_media_type?).with {|a| a.is_a?(Doze::Entity) && a.media_type == @foo}.returns(false)
|
51
|
+
root.expects(:post).never
|
52
|
+
post('CONTENT_TYPE' => 'text/foo', :input => 'foo')
|
53
|
+
assert_equal STATUS_UNSUPPORTED_MEDIA_TYPE, last_response.status
|
54
|
+
end
|
55
|
+
|
56
|
+
def test_post_returning_created_resource
|
57
|
+
root.expects(:supports_post?).returns(true)
|
58
|
+
root.expects(:accepts_post_with_media_type?).with {|a| a.is_a?(Doze::Entity) && a.media_type == @foo}.returns(true)
|
59
|
+
created = mock_resource('/uri', 'foo')
|
60
|
+
root.expects(:post).with do |value|
|
61
|
+
value.is_a?(Doze::Entity) and
|
62
|
+
value.binary_data == 'foob' and value.media_type == @foo and value.encoding == 'foobar'
|
63
|
+
end.returns(created).once
|
64
|
+
|
65
|
+
post('CONTENT_TYPE' => 'text/foo; charset=foobar', :input => 'foob')
|
66
|
+
assert_equal STATUS_CREATED, last_response.status
|
67
|
+
assert_response_header 'Location', 'http://example.org/uri'
|
68
|
+
assert_equal 'foo', last_response.body
|
69
|
+
end
|
70
|
+
|
71
|
+
def test_post_returning_nothing
|
72
|
+
root.expects(:supports_post?).returns(true)
|
73
|
+
root.expects(:accepts_post_with_media_type?).with {|a| a.is_a?(Doze::Entity) && a.media_type == @foo}.returns(true)
|
74
|
+
root.expects(:post).returns(nil).once
|
75
|
+
|
76
|
+
post('CONTENT_TYPE' => 'text/foo; charset=foobar', :input => 'foob')
|
77
|
+
assert_equal STATUS_NO_CONTENT, last_response.status
|
78
|
+
end
|
79
|
+
|
80
|
+
def test_post_with_extra_arity_gets_session
|
81
|
+
root.expects(:supports_post?).returns(true)
|
82
|
+
root.expects(:accepts_post_with_media_type?).with {|a| a.is_a?(Doze::Entity) && a.media_type == @foo}.returns(true)
|
83
|
+
|
84
|
+
# Because mocha doesn't set the arity right
|
85
|
+
def root.post(a, b)
|
86
|
+
post_actually_called(a, b)
|
87
|
+
end
|
88
|
+
root.expects(:post_actually_called).with(instance_of(Doze::Entity), "user").once
|
89
|
+
|
90
|
+
post('REMOTE_USER' => 'user', 'CONTENT_TYPE' => 'text/foo; charset=foobar', :input => 'foob')
|
91
|
+
assert_equal STATUS_NO_CONTENT, last_response.status
|
92
|
+
end
|
93
|
+
|
94
|
+
def test_post_returning_entity
|
95
|
+
root.expects(:supports_post?).returns(true)
|
96
|
+
root.expects(:accepts_post_with_media_type?).with {|a| a.is_a?(Doze::Entity) && a.media_type == @foo}.returns(true)
|
97
|
+
root.expects(:post).returns(mock_entity('bar', @bar)).once
|
98
|
+
|
99
|
+
post('CONTENT_TYPE' => 'text/foo; charset=foobar', :input => 'foob')
|
100
|
+
assert_equal STATUS_OK, last_response.status
|
101
|
+
assert_equal 'bar', last_response.body
|
102
|
+
assert_equal 'text/bar', last_response.media_type
|
103
|
+
end
|
104
|
+
|
105
|
+
def test_post_returning_anonymous_resource
|
106
|
+
root.expects(:supports_post?).returns(true)
|
107
|
+
root.expects(:accepts_post_with_media_type?).with {|a| a.is_a?(Doze::Entity) && a.media_type == @foo}.returns(true)
|
108
|
+
resource = mock_resource(nil)
|
109
|
+
resource.expects(:get).returns(mock_entity('bar', @bar))
|
110
|
+
root.expects(:post).returns(resource).once
|
111
|
+
|
112
|
+
post('CONTENT_TYPE' => 'text/foo; charset=foobar', :input => 'foob')
|
113
|
+
assert_equal STATUS_OK, last_response.status
|
114
|
+
assert_equal 'bar', last_response.body
|
115
|
+
assert_equal 'text/bar', last_response.media_type
|
116
|
+
end
|
117
|
+
|
118
|
+
def test_delete
|
119
|
+
root.expects(:supports_delete?).returns(true)
|
120
|
+
root.expects(:accepts_delete_with_media_type?).never
|
121
|
+
root.expects(:delete_resource).returns(nil).once
|
122
|
+
|
123
|
+
delete
|
124
|
+
assert_equal STATUS_NO_CONTENT, last_response.status
|
125
|
+
assert last_response.body.empty?
|
126
|
+
end
|
127
|
+
|
128
|
+
def test_other_method_with_no_response
|
129
|
+
# PATCH used as an example here
|
130
|
+
app(:recognized_methods => [:get,:post,:put,:delete,:patch])
|
131
|
+
|
132
|
+
root.expects(:supports_patch?).returns(true)
|
133
|
+
root.expects(:accepts_method_with_media_type?).with {|m,a| m == :patch && a.is_a?(Doze::Entity) && a.media_type == @foo}.returns(true)
|
134
|
+
root.expects(:patch).with do |value|
|
135
|
+
value.is_a?(Doze::Entity) and
|
136
|
+
value.binary_data == 'foob' and value.media_type == @foo and value.encoding == 'foobar'
|
137
|
+
end.returns(nil).once
|
138
|
+
|
139
|
+
other_request_method('PATCH', {'CONTENT_TYPE' => 'text/foo; charset=foobar', :input => 'foob'})
|
140
|
+
assert_equal STATUS_NO_CONTENT, last_response.status
|
141
|
+
end
|
142
|
+
|
143
|
+
def test_other_method_with_anonymous_resource_response
|
144
|
+
# PATCH used as an example here
|
145
|
+
app(:recognized_methods => [:get,:post,:put,:delete,:patch])
|
146
|
+
|
147
|
+
root.expects(:supports_patch?).returns(true)
|
148
|
+
root.expects(:accepts_method_with_media_type?).with {|m,a| m == :patch && a.is_a?(Doze::Entity) && a.media_type == @foo}.returns(true)
|
149
|
+
resource = mock_resource(nil)
|
150
|
+
resource.expects(:get).returns(mock_entity('bar', @bar))
|
151
|
+
root.expects(:patch).returns(resource).once
|
152
|
+
|
153
|
+
other_request_method('PATCH', {'CONTENT_TYPE' => 'text/foo; charset=foobar', :input => 'foob'})
|
154
|
+
assert_equal STATUS_OK, last_response.status
|
155
|
+
assert_equal 'bar', last_response.body
|
156
|
+
assert_equal 'text/bar', last_response.media_type
|
157
|
+
end
|
158
|
+
|
159
|
+
def test_other_method_with_resource_response
|
160
|
+
# PATCH used as an example here
|
161
|
+
app(:recognized_methods => [:get,:post,:put,:delete,:patch])
|
162
|
+
|
163
|
+
root.expects(:supports_patch?).returns(true)
|
164
|
+
root.expects(:accepts_method_with_media_type?).with {|m,a| m == :patch && a.is_a?(Doze::Entity) && a.media_type == @foo}.returns(true)
|
165
|
+
resource = mock_resource('/foo', 'bar')
|
166
|
+
root.expects(:patch).returns(resource).once
|
167
|
+
|
168
|
+
other_request_method('PATCH', {'CONTENT_TYPE' => 'text/foo; charset=foobar', :input => 'foob'})
|
169
|
+
assert_equal STATUS_CREATED, last_response.status
|
170
|
+
assert_response_header 'Location', 'http://example.org/foo'
|
171
|
+
assert_equal 'bar', last_response.body
|
172
|
+
end
|
173
|
+
end
|
@@ -0,0 +1,84 @@
|
|
1
|
+
require 'functional/base'
|
2
|
+
|
3
|
+
class PreconditionTest < Test::Unit::TestCase
|
4
|
+
include Doze::Utils
|
5
|
+
include Doze::TestCase
|
6
|
+
|
7
|
+
def setup
|
8
|
+
@last_modified = Time.now - 30
|
9
|
+
root.expects(:last_modified).returns(@last_modified).at_least_once
|
10
|
+
end
|
11
|
+
|
12
|
+
def test_if_modified_since
|
13
|
+
get('HTTP_IF_MODIFIED_SINCE' => (@last_modified-10).httpdate)
|
14
|
+
assert_equal STATUS_OK, last_response.status
|
15
|
+
get('HTTP_IF_MODIFIED_SINCE' => (@last_modified+10).httpdate)
|
16
|
+
assert_equal STATUS_NOT_MODIFIED, last_response.status
|
17
|
+
end
|
18
|
+
|
19
|
+
def test_if_unmodified_since
|
20
|
+
get('HTTP_IF_UNMODIFIED_SINCE' => (@last_modified+10).httpdate)
|
21
|
+
assert_equal STATUS_OK, last_response.status
|
22
|
+
get('HTTP_IF_UNMODIFIED_SINCE' => (@last_modified-10).httpdate)
|
23
|
+
assert_equal STATUS_PRECONDITION_FAILED, last_response.status
|
24
|
+
end
|
25
|
+
|
26
|
+
def test_status_for_non_get
|
27
|
+
root.expects(:supports_post?).returns(true).at_least_once
|
28
|
+
root.expects(:supports_put?).returns(true).at_least_once
|
29
|
+
root.expects(:supports_delete?).returns(true).at_least_once
|
30
|
+
root.expects(:accepts_method_with_media_type?).returns(true).at_least_once
|
31
|
+
root.expects(:post).never
|
32
|
+
root.expects(:put).never
|
33
|
+
root.expects(:delete).never
|
34
|
+
|
35
|
+
assert_equal STATUS_PRECONDITION_FAILED, post('HTTP_IF_UNMODIFIED_SINCE' => (@last_modified-10).httpdate).status
|
36
|
+
assert_equal STATUS_PRECONDITION_FAILED, put('HTTP_IF_UNMODIFIED_SINCE' => (@last_modified-10).httpdate).status
|
37
|
+
assert_equal STATUS_PRECONDITION_FAILED, delete('HTTP_IF_UNMODIFIED_SINCE' => (@last_modified-10).httpdate).status
|
38
|
+
assert_equal STATUS_PRECONDITION_FAILED, post('HTTP_IF_MODIFIED_SINCE' => (@last_modified+10).httpdate).status
|
39
|
+
assert_equal STATUS_PRECONDITION_FAILED, put('HTTP_IF_MODIFIED_SINCE' => (@last_modified+10).httpdate).status
|
40
|
+
assert_equal STATUS_PRECONDITION_FAILED, delete('HTTP_IF_MODIFIED_SINCE' => (@last_modified+10).httpdate).status
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
class EntityPreconditionTest < Test::Unit::TestCase
|
45
|
+
include Doze::Utils
|
46
|
+
include Doze::TestCase
|
47
|
+
|
48
|
+
def setup
|
49
|
+
@last_modified = Time.now - 30
|
50
|
+
root.expects(:last_modified).returns(@last_modified).at_least_once
|
51
|
+
|
52
|
+
@entity = mock_entity('foo')
|
53
|
+
@etag = '123abc'
|
54
|
+
@entity.expects(:etag).returns(@etag).at_least_once
|
55
|
+
root.expects(:get).returns(@entity).at_least_once
|
56
|
+
end
|
57
|
+
|
58
|
+
def test_if_match
|
59
|
+
get('HTTP_IF_MATCH' => quote(@etag))
|
60
|
+
assert_equal STATUS_OK, last_response.status
|
61
|
+
get('HTTP_IF_MATCH' => quote("not-the-etag"))
|
62
|
+
assert_equal STATUS_PRECONDITION_FAILED, last_response.status
|
63
|
+
end
|
64
|
+
|
65
|
+
def test_if_none_match
|
66
|
+
get('HTTP_IF_NONE_MATCH' => quote(@etag))
|
67
|
+
assert_equal STATUS_NOT_MODIFIED, last_response.status
|
68
|
+
get('HTTP_IF_NONE_MATCH' => quote("not-the-etag"))
|
69
|
+
assert_equal STATUS_OK, last_response.status
|
70
|
+
end
|
71
|
+
|
72
|
+
def test_non_get_method_not_called_when_precondition_fails
|
73
|
+
root.expects(:supports_post?).returns(true).once
|
74
|
+
root.expects(:supports_put?).returns(true).once
|
75
|
+
root.expects(:supports_delete?).returns(true).once
|
76
|
+
root.expects(:accepts_method_with_media_type?).returns(true).at_least_once
|
77
|
+
root.expects(:post).never
|
78
|
+
root.expects(:put).never
|
79
|
+
root.expects(:delete).never
|
80
|
+
assert_equal STATUS_PRECONDITION_FAILED, post('HTTP_IF_MATCH' => quote('not-the-etag')).status
|
81
|
+
assert_equal STATUS_PRECONDITION_FAILED, put('HTTP_IF_MATCH' => quote('not-the-etag')).status
|
82
|
+
assert_equal STATUS_PRECONDITION_FAILED, delete('HTTP_IF_MATCH' => quote('not-the-etag')).status
|
83
|
+
end
|
84
|
+
end
|
@@ -0,0 +1,69 @@
|
|
1
|
+
require "test/unit"
|
2
|
+
require 'mocha/setup'
|
3
|
+
require 'doze/request'
|
4
|
+
|
5
|
+
class RawPathInfoTest < Test::Unit::TestCase
|
6
|
+
include Doze::Utils
|
7
|
+
include Doze::TestCase
|
8
|
+
|
9
|
+
def mock_request(path, host="localhost", scheme="http", port=-1, context="")
|
10
|
+
|
11
|
+
port_str = if port == -1 then "" ; else ":#{port}" ; end
|
12
|
+
|
13
|
+
path_parts = ["/", context, path].join("")
|
14
|
+
if path_parts[0...2] == "//" then path_parts = path_parts[1..-1] end
|
15
|
+
|
16
|
+
url = stub()
|
17
|
+
url.stubs(:toString).returns("#{scheme}://#{host}#{port_str}#{path_parts}")
|
18
|
+
|
19
|
+
s_request = stub("")
|
20
|
+
s_request.stubs(:getRequestURL).returns(url)
|
21
|
+
s_request.stubs(:getContextPath).returns(context)
|
22
|
+
|
23
|
+
app = stub()
|
24
|
+
env = stub()
|
25
|
+
env.stubs(:[]).with('java.servlet_request').returns(s_request)
|
26
|
+
Doze::Request.new(app, env)
|
27
|
+
end
|
28
|
+
|
29
|
+
def test_bland_path
|
30
|
+
dr = mock_request("/path/is/good")
|
31
|
+
assert_equal dr.raw_path_info, "/path/is/good"
|
32
|
+
end
|
33
|
+
|
34
|
+
def test_path_with_host_and_port
|
35
|
+
dr = mock_request("/how/do", "x23.awesome-server.playlouder---com.com", 5432)
|
36
|
+
assert_equal dr.raw_path_info, "/how/do"
|
37
|
+
end
|
38
|
+
|
39
|
+
def test_path_with_naughty_chars
|
40
|
+
dr = mock_request("/how/do%20", "awesome-server", 5432)
|
41
|
+
assert_equal dr.raw_path_info, "/how/do%20"
|
42
|
+
end
|
43
|
+
|
44
|
+
def test_context_is_chomped
|
45
|
+
['bob', 'bob-y', 'the%20bobster'].each do |context|
|
46
|
+
dr = mock_request('/path-s/of/life', 'www.awesome.com', 'https', 8080, context)
|
47
|
+
assert_equal dr.raw_path_info, "/path-s/of/life"
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
def test_searchpart_excluded
|
52
|
+
{
|
53
|
+
'/path' => '/path', '?false=true' => '/', '/path?you=suck&bob&nick=awesome' => '/path'
|
54
|
+
}.each do |raw, exp_raw_path_info|
|
55
|
+
dr = mock_request(raw, 'some.host-rocks', 'http', 1234)
|
56
|
+
assert_equal dr.raw_path_info, exp_raw_path_info
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
def test_servlet_is_missing
|
61
|
+
app = stub()
|
62
|
+
env = stub()
|
63
|
+
env.stubs(:[]).with('java.servlet_request').returns(nil)
|
64
|
+
dr = Doze::Request.new(app, env)
|
65
|
+
dr.expects(:path_info).twice.returns("/omg/im/a/path")
|
66
|
+
assert_equal dr.raw_path_info, dr.path_info
|
67
|
+
end
|
68
|
+
|
69
|
+
end
|
@@ -0,0 +1,14 @@
|
|
1
|
+
require 'functional/base'
|
2
|
+
|
3
|
+
class ResourceRepresentationTest < Test::Unit::TestCase
|
4
|
+
include Doze::Utils
|
5
|
+
include Doze::TestCase
|
6
|
+
|
7
|
+
def test_get_with_resource_representation
|
8
|
+
resource = mock_resource('/foo/bar')
|
9
|
+
root.expects(:get).returns(resource)
|
10
|
+
get
|
11
|
+
assert_equal STATUS_SEE_OTHER, last_response.status
|
12
|
+
assert_response_header 'Location', 'http://example.org/foo/bar'
|
13
|
+
end
|
14
|
+
end
|
@@ -0,0 +1,196 @@
|
|
1
|
+
require 'functional/base'
|
2
|
+
|
3
|
+
class RouterInterfaceTest < Test::Unit::TestCase
|
4
|
+
include Doze::Utils
|
5
|
+
include Doze::TestCase
|
6
|
+
|
7
|
+
# tests how the basic Router interface is exposed by the framework
|
8
|
+
|
9
|
+
def test_router_no_match
|
10
|
+
root_router.expects(:perform_routing).with('/foo', nil, '').returns(nil).once
|
11
|
+
assert_equal STATUS_NOT_FOUND, get('/foo').status
|
12
|
+
end
|
13
|
+
|
14
|
+
def test_router_match_resource_with_no_trailing_path
|
15
|
+
resource = mock_resource('/foo')
|
16
|
+
root_router.expects(:perform_routing).with('/foo', nil, '').returns([resource, '/foo', nil]).once
|
17
|
+
resource.expects(:get).returns(mock_entity('foo', 'text/html')).once
|
18
|
+
assert_equal STATUS_OK, get('/foo').status
|
19
|
+
end
|
20
|
+
|
21
|
+
def test_router_match_resource_but_with_trailing
|
22
|
+
# here we route to a resource, but there is some trailing path which can't be routed any further
|
23
|
+
resource = mock_resource('/foo')
|
24
|
+
root_router.expects(:perform_routing).with('/foo/bar', nil, '').returns([resource, '/foo', '/bar']).once
|
25
|
+
resource.expects(:get).never
|
26
|
+
assert_equal STATUS_NOT_FOUND, get('/foo/bar').status
|
27
|
+
end
|
28
|
+
|
29
|
+
def test_router_match_router_with_trailing_then_resource
|
30
|
+
# here we route to another router which is matched but with some trailing path that's passed on to it.
|
31
|
+
|
32
|
+
second_router = mock_router
|
33
|
+
resource = mock_resource('/foo/bar')
|
34
|
+
|
35
|
+
root_router.expects(:perform_routing).with('/foo/bar', nil, '').returns([second_router, '/foo', '/bar']).once
|
36
|
+
second_router.expects(:perform_routing).with('/bar', nil, '/foo').returns([resource, '/foo/bar', nil]).once
|
37
|
+
|
38
|
+
resource.expects(:get).returns(mock_entity('foo', 'text/html')).once
|
39
|
+
assert_equal STATUS_OK, get('/foo/bar').status
|
40
|
+
end
|
41
|
+
|
42
|
+
def test_router_match_router_resource_with_trailing_then_resource
|
43
|
+
# as above but this time our second router is also a resource - check that it does actually act as a router
|
44
|
+
|
45
|
+
second_router = mock_router(Doze::MockResource)
|
46
|
+
resource = mock_resource('/foo/bar')
|
47
|
+
|
48
|
+
root_router.expects(:perform_routing).with('/foo/bar', nil, '').returns([second_router, '/foo', '/bar']).once
|
49
|
+
second_router.expects(:perform_routing).with('/bar', nil, '/foo').returns([resource, '/foo/bar', nil]).once
|
50
|
+
|
51
|
+
second_router.expects(:get).never
|
52
|
+
resource.expects(:get).returns(mock_entity('foo', 'text/html')).once
|
53
|
+
assert_equal STATUS_OK, get('/foo/bar').status
|
54
|
+
end
|
55
|
+
|
56
|
+
def test_router_match_router_resource_with_no_trailing
|
57
|
+
resource = mock_router(Doze::MockResource)
|
58
|
+
|
59
|
+
root_router.expects(:perform_routing).with('/foo', nil, '').returns([resource, '/foo', nil]).once
|
60
|
+
resource.expects(:perform_routing).never
|
61
|
+
resource.expects(:get).returns(mock_entity('foo', 'text/html')).once
|
62
|
+
|
63
|
+
assert_equal STATUS_OK, get('/foo').status
|
64
|
+
end
|
65
|
+
|
66
|
+
def test_router_gets_passed_user
|
67
|
+
root_router.expects(:perform_routing).with('/foo', 'Mack', '').returns(nil).once
|
68
|
+
assert_equal STATUS_NOT_FOUND, get('/foo', 'REMOTE_USER' => 'Mack').status
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
|
73
|
+
class RouterDefaultImplementationTest < Test::Unit::TestCase
|
74
|
+
include Doze::Utils
|
75
|
+
include Doze::TestCase
|
76
|
+
|
77
|
+
# tests the default implementation of Router based on routes defined in class method helpers
|
78
|
+
|
79
|
+
def test_route_fixed_uri_to_resource_class
|
80
|
+
resource = mock_resource('/foo')
|
81
|
+
resource.expects(:get).returns(mock_entity('foo', 'text/html')).once
|
82
|
+
klass = Class.new
|
83
|
+
klass.expects(:new).with("/foo").returns(resource)
|
84
|
+
|
85
|
+
root_router do
|
86
|
+
route '/foo', :to => klass
|
87
|
+
end
|
88
|
+
|
89
|
+
assert_equal STATUS_OK, get('/foo').status
|
90
|
+
end
|
91
|
+
|
92
|
+
def test_route_fixed_uri_to_resource_instance
|
93
|
+
resource = mock_resource('/foo')
|
94
|
+
resource.expects(:get).returns(mock_entity('foo', 'text/html')).once
|
95
|
+
|
96
|
+
root_router do
|
97
|
+
route '/foo', :to => resource
|
98
|
+
end
|
99
|
+
|
100
|
+
assert_equal STATUS_OK, get('/foo').status
|
101
|
+
end
|
102
|
+
|
103
|
+
def test_route_with_params_to_block_returning_resource
|
104
|
+
root_router do
|
105
|
+
route('/foo/{x}/{y}') do |router, uri, params|
|
106
|
+
Doze::MockResource.new(uri, [uri, params].inspect)
|
107
|
+
end
|
108
|
+
end
|
109
|
+
|
110
|
+
get('/foo/abc/123')
|
111
|
+
|
112
|
+
assert_equal STATUS_OK, last_response.status
|
113
|
+
assert_equal(['/foo/abc/123', {:x => 'abc', :y => '123'}].inspect, last_response.body)
|
114
|
+
end
|
115
|
+
|
116
|
+
# More complex two-level routing scenario with params at both levels
|
117
|
+
def test_route_with_params_to_block_returning_router_routing_to_resource_with_more_params
|
118
|
+
root_router do
|
119
|
+
route('/foo/{x}') do |router1, uri1, params1|
|
120
|
+
|
121
|
+
Class.new do
|
122
|
+
include Doze::Router
|
123
|
+
route("/{y}") do |router2, uri2, params2|
|
124
|
+
Doze::MockResource.new(uri2, [uri1, params1, uri2, params2].inspect)
|
125
|
+
end
|
126
|
+
end.new
|
127
|
+
end
|
128
|
+
end
|
129
|
+
|
130
|
+
get('/foo/abc/123')
|
131
|
+
|
132
|
+
assert_equal STATUS_OK, last_response.status
|
133
|
+
# bit of a messy way to test it but this was getting fiddly to mock nicely
|
134
|
+
# expecting [uri1, params1, uri2, params2].inspect from above
|
135
|
+
assert_equal(['/foo/abc', {:x => 'abc'}, '/foo/abc/123', {:y => '123'}].inspect, last_response.body)
|
136
|
+
end
|
137
|
+
|
138
|
+
def test_route_with_special_param_regexp
|
139
|
+
root_router do
|
140
|
+
route('/foo/{x}', :regexps => {:x => /\d+/}) do |router, uri, params|
|
141
|
+
Doze::MockResource.new(uri, params[:x])
|
142
|
+
end
|
143
|
+
end
|
144
|
+
|
145
|
+
assert_equal STATUS_NOT_FOUND, get('/foo/abc').status
|
146
|
+
assert_equal STATUS_OK, get('/foo/123').status
|
147
|
+
assert_equal "123", last_response.body
|
148
|
+
end
|
149
|
+
|
150
|
+
def test_route_with_uri_template_passed_directly
|
151
|
+
root_router do
|
152
|
+
route(Doze::URITemplate.compile('/foo/{x}', :x => /\d+/)) do |router, uri, params|
|
153
|
+
Doze::MockResource.new(uri, params[:x])
|
154
|
+
end
|
155
|
+
end
|
156
|
+
|
157
|
+
assert_equal STATUS_NOT_FOUND, get('/foo/abc').status
|
158
|
+
assert_equal STATUS_OK, get('/foo/123').status
|
159
|
+
assert_equal "123", last_response.body
|
160
|
+
end
|
161
|
+
|
162
|
+
def test_user_specific_route
|
163
|
+
root_router do
|
164
|
+
route('/foo/{x}/{y}', :session_specific => true) do |router, uri, params, user|
|
165
|
+
Doze::MockResource.new(uri, [uri, params, user].inspect)
|
166
|
+
end
|
167
|
+
end
|
168
|
+
|
169
|
+
get('/foo/abc/123', 'REMOTE_USER' => 'Mo')
|
170
|
+
|
171
|
+
assert_equal STATUS_OK, last_response.status
|
172
|
+
assert_equal(['/foo/abc/123', {:x => 'abc', :y => '123'}, 'Mo'].inspect, last_response.body)
|
173
|
+
end
|
174
|
+
|
175
|
+
def test_propagate_static_routes
|
176
|
+
klass = Class.new
|
177
|
+
klass.send(:include, Doze::Router)
|
178
|
+
router = mock_router
|
179
|
+
router2 = mock_router
|
180
|
+
|
181
|
+
root_router do
|
182
|
+
route "/bar", :uniquely_to => klass
|
183
|
+
route "/baz", :uniquely_to => router
|
184
|
+
route "/baz", :to => router2
|
185
|
+
end
|
186
|
+
|
187
|
+
root_router.propagate_static_routes("/foo")
|
188
|
+
|
189
|
+
assert_equal "/foo", root_router.router_uri_prefix
|
190
|
+
|
191
|
+
assert_equal "/foo/bar", klass.router_uri_prefix
|
192
|
+
assert_equal "/foo/bar", klass.new.router_uri_prefix
|
193
|
+
assert_equal "/foo/baz", router.router_uri_prefix
|
194
|
+
assert_equal nil, router2.router_uri_prefix
|
195
|
+
end
|
196
|
+
end
|