doze 0.0.11
Sign up to get free protection for your applications and to get access to all the features.
- 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
|