rack-oauth2 0.5.1 → 0.6.0.alpha

Sign up to get free protection for your applications and to get access to all the features.
Files changed (40) hide show
  1. data/VERSION +1 -1
  2. data/lib/rack/oauth2.rb +2 -1
  3. data/lib/rack/oauth2/access_token.rb +30 -0
  4. data/lib/rack/oauth2/access_token/bearer.rb +29 -0
  5. data/lib/rack/oauth2/access_token/mac.rb +109 -0
  6. data/lib/rack/oauth2/access_token/mac/body_hash.rb +15 -0
  7. data/lib/rack/oauth2/access_token/mac/signature.rb +49 -0
  8. data/lib/rack/oauth2/access_token/mac/verifier.rb +43 -0
  9. data/lib/rack/oauth2/server/authorize/code.rb +0 -1
  10. data/lib/rack/oauth2/server/resource.rb +55 -1
  11. data/lib/rack/oauth2/server/resource/bearer.rb +12 -39
  12. data/lib/rack/oauth2/server/resource/bearer/error.rb +5 -60
  13. data/lib/rack/oauth2/server/resource/error.rb +81 -0
  14. data/lib/rack/oauth2/server/resource/mac.rb +39 -0
  15. data/lib/rack/oauth2/server/resource/mac/error.rb +24 -0
  16. data/lib/rack/oauth2/server/token.rb +3 -10
  17. data/lib/rack/oauth2/server/token/refresh_token.rb +0 -2
  18. data/lib/rack/oauth2/util.rb +10 -0
  19. data/spec/fake_response/facebook_token_response.txt +1 -0
  20. data/spec/fake_response/resources/fake.txt +1 -0
  21. data/spec/helpers/time.rb +19 -0
  22. data/spec/rack/oauth2/access_token/bearer_spec.rb +43 -0
  23. data/spec/rack/oauth2/access_token/mac/verifier_spec.rb +23 -0
  24. data/spec/rack/oauth2/access_token/mac_spec.rb +163 -0
  25. data/spec/rack/oauth2/access_token_spec.rb +48 -0
  26. data/spec/rack/oauth2/client_spec.rb +18 -6
  27. data/spec/rack/oauth2/server/resource/bearer/error_spec.rb +9 -87
  28. data/spec/rack/oauth2/server/resource/bearer_spec.rb +40 -69
  29. data/spec/rack/oauth2/server/resource/error_spec.rb +147 -0
  30. data/spec/rack/oauth2/server/resource/mac/error_spec.rb +52 -0
  31. data/spec/rack/oauth2/server/resource/mac_spec.rb +92 -0
  32. data/spec/rack/oauth2/server/resource_spec.rb +23 -0
  33. data/spec/rack/oauth2/server/token/authorization_code_spec.rb +1 -2
  34. data/spec/rack/oauth2/server/token/client_credentials_spec.rb +1 -2
  35. data/spec/rack/oauth2/server/token/password_spec.rb +1 -2
  36. data/spec/rack/oauth2/server/token/refresh_token_spec.rb +1 -2
  37. data/spec/rack/oauth2/server/token_spec.rb +1 -2
  38. data/spec/rack/oauth2/util_spec.rb +10 -0
  39. data/spec/spec_helper.rb +1 -0
  40. metadata +38 -6
@@ -0,0 +1,48 @@
1
+ require 'spec_helper'
2
+
3
+ describe Rack::OAuth2::AccessToken do
4
+ subject do
5
+ Rack::OAuth2::AccessToken::Bearer.new(
6
+ :access_token => 'access_token',
7
+ :refresh_token => 'refresh_token',
8
+ :expires_in => 3600,
9
+ :scope => [:scope1, :scope2]
10
+ )
11
+ end
12
+
13
+ its(:access_token) { should == 'access_token' }
14
+ its(:refresh_token) { should == 'refresh_token' }
15
+ its(:expires_in) { should == 3600 }
16
+ its(:scope) { should == [:scope1, :scope2] }
17
+ its(:token_response) do
18
+ should == {
19
+ :token_type => :bearer,
20
+ :access_token => 'access_token',
21
+ :refresh_token => 'refresh_token',
22
+ :expires_in => 3600,
23
+ :scope => 'scope1 scope2'
24
+ }
25
+ end
26
+
27
+ context 'when access_token is missing' do
28
+ it do
29
+ expect do
30
+ Rack::OAuth2::AccessToken::Bearer.new(
31
+ :refresh_token => 'refresh_token',
32
+ :expires_in => 3600,
33
+ :scope => [:scope1, :scope2]
34
+ )
35
+ end.should raise_error AttrRequired::AttrMissing
36
+ end
37
+ end
38
+
39
+ context 'otherwise' do
40
+ it do
41
+ expect do
42
+ Rack::OAuth2::AccessToken::Bearer.new(
43
+ :access_token => 'access_token'
44
+ )
45
+ end.should_not raise_error
46
+ end
47
+ end
48
+ end
@@ -18,9 +18,7 @@ describe Rack::OAuth2::Client do
18
18
 
19
19
  context 'when identifier is missing' do
20
20
  it do
21
- lambda do
22
- Rack::OAuth2::Client.new
23
- end.should raise_error AttrRequired::AttrMissing
21
+ expect { Rack::OAuth2::Client.new }.should raise_error AttrRequired::AttrMissing
24
22
  end
25
23
  end
26
24
 
@@ -100,9 +98,23 @@ describe Rack::OAuth2::Client do
100
98
  )
101
99
  end
102
100
  it do
103
- lambda do
104
- client.access_token!
105
- end.should raise_error Rack::OAuth2::Client::Error
101
+ expect { client.access_token! }.should raise_error Rack::OAuth2::Client::Error
102
+ end
103
+ end
104
+
105
+ context 'when key-value response is given' do
106
+ before do
107
+ fake_response(
108
+ :post,
109
+ 'https://server.example.com/oauth2/token',
110
+ 'facebook_token_response.txt'
111
+ )
112
+ end
113
+ it do
114
+ client.access_token!.should == {
115
+ 'access_token' => 'access_token',
116
+ 'expires_in' => '3600' # NOTE: String not Integer
117
+ }
106
118
  end
107
119
  end
108
120
  end
@@ -1,94 +1,30 @@
1
1
  require 'spec_helper.rb'
2
2
 
3
- describe Rack::OAuth2::Server::Resource::Bearer::BadRequest do
4
- let(:error) { Rack::OAuth2::Server::Resource::Bearer::BadRequest.new(:invalid_request) }
5
-
6
- it { should be_a Rack::OAuth2::Server::Abstract::BadRequest }
7
- describe '#finish' do
8
- it 'should respond in JSON' do
9
- status, header, response = error.finish
10
- status.should == 400
11
- header['Content-Type'].should == 'application/json'
12
- response.body.should == ['{"error":"invalid_request"}']
13
- end
14
- end
15
- end
16
-
17
3
  describe Rack::OAuth2::Server::Resource::Bearer::Unauthorized do
18
4
  let(:error) { Rack::OAuth2::Server::Resource::Bearer::Unauthorized.new(:invalid_token) }
19
- let(:realm) { Rack::OAuth2::Server::Resource::Bearer::DEFAULT_REALM }
20
5
 
21
- it { should be_a Rack::OAuth2::Server::Abstract::Unauthorized }
22
- describe '#finish' do
23
- it 'should respond in JSON' do
24
- status, header, response = error.finish
25
- status.should == 401
26
- header['Content-Type'].should == 'application/json'
27
- header['WWW-Authenticate'].should == "Bearer realm=\"#{realm}\" error=\"invalid_token\""
28
- response.body.should == ['{"error":"invalid_token"}']
29
- end
30
- end
6
+ it { should be_a Rack::OAuth2::Server::Resource::Unauthorized }
31
7
 
32
- context 'when error_code is not invalid_token' do
33
- let(:error) { Rack::OAuth2::Server::Resource::Bearer::Unauthorized.new(:something) }
34
-
35
- it 'should have error_code in body but not in WWW-Authenticate header' do
36
- status, header, response = error.finish
37
- header['WWW-Authenticate'].should == "Bearer realm=\"#{realm}\""
38
- response.body.first.should include '"error":"something"'
39
- end
40
- end
41
-
42
- context 'when realm is specified' do
43
- let(:realm) { 'server.example.com' }
44
- let(:error) { Rack::OAuth2::Server::Resource::Bearer::Unauthorized.new(:something, nil, :realm => realm) }
45
-
46
- it 'should use given realm' do
47
- status, header, response = error.finish
48
- header['WWW-Authenticate'].should == "Bearer realm=\"#{realm}\""
49
- response.body.first.should include '"error":"something"'
50
- end
8
+ describe '#scheme' do
9
+ subject { error }
10
+ its(:scheme) { should == :Bearer }
51
11
  end
52
- end
53
-
54
- describe Rack::OAuth2::Server::Resource::Bearer::Forbidden do
55
- let(:error) { Rack::OAuth2::Server::Resource::Bearer::Forbidden.new(:insufficient_scope) }
56
12
 
57
- it { should be_a Rack::OAuth2::Server::Abstract::Forbidden }
58
13
  describe '#finish' do
59
- it 'should respond in JSON' do
14
+ it 'should use Bearer scheme' do
60
15
  status, header, response = error.finish
61
- status.should == 403
62
- header['Content-Type'].should == 'application/json'
63
- response.body.should == ['{"error":"insufficient_scope"}']
64
- end
65
- end
66
-
67
- context 'when scope option is given' do
68
- let(:error) { Rack::OAuth2::Server::Resource::Bearer::Forbidden.new(:insufficient_scope, 'Desc', :scope => [:scope1, :scope2]) }
69
-
70
- it 'should have blank WWW-Authenticate header' do
71
- status, header, response = error.finish
72
- response.body.first.should include '"scope":"scope1 scope2"'
16
+ header['WWW-Authenticate'].should include 'Bearer'
73
17
  end
74
18
  end
75
19
  end
76
20
 
77
21
  describe Rack::OAuth2::Server::Resource::Bearer::ErrorMethods do
78
- let(:bad_request) { Rack::OAuth2::Server::Resource::Bearer::BadRequest }
79
22
  let(:unauthorized) { Rack::OAuth2::Server::Resource::Bearer::Unauthorized }
80
- let(:forbidden) { Rack::OAuth2::Server::Resource::Bearer::Forbidden }
81
23
  let(:redirect_uri) { 'http://client.example.com/callback' }
82
- let(:default_description) { Rack::OAuth2::Server::Resource::Bearer::ErrorMethods::DEFAULT_DESCRIPTION }
24
+ let(:default_description) { Rack::OAuth2::Server::Resource::ErrorMethods::DEFAULT_DESCRIPTION }
83
25
  let(:env) { Rack::MockRequest.env_for("/authorize?client_id=client_id") }
84
26
  let(:request) { Rack::OAuth2::Server::Resource::Bearer::Request.new env }
85
27
 
86
- describe 'bad_request!' do
87
- it do
88
- expect { request.bad_request! :invalid_request }.should raise_error bad_request
89
- end
90
- end
91
-
92
28
  describe 'unauthorized!' do
93
29
  it do
94
30
  expect { request.unauthorized! :invalid_client }.should raise_error unauthorized
@@ -99,23 +35,9 @@ describe Rack::OAuth2::Server::Resource::Bearer::ErrorMethods do
99
35
  method = "#{error_code}!"
100
36
  case error_code
101
37
  when :invalid_request
102
- describe method do
103
- it "should raise Rack::OAuth2::Server::Resource::Bearer::BadRequest with error = :#{error_code}" do
104
- expect { request.send method }.should raise_error(bad_request) { |error|
105
- error.error.should == error_code
106
- error.description.should == default_description[error_code]
107
- }
108
- end
109
- end
38
+ # ignore
110
39
  when :insufficient_scope
111
- describe method do
112
- it "should raise Rack::OAuth2::Server::Resource::Bearer::Forbidden with error = :#{error_code}" do
113
- expect { request.send method }.should raise_error(forbidden) { |error|
114
- error.error.should == error_code
115
- error.description.should == default_description[error_code]
116
- }
117
- end
118
- end
40
+ # ignore
119
41
  else
120
42
  describe method do
121
43
  it "should raise Rack::OAuth2::Server::Resource::Bearer::Unauthorized with error = :#{error_code}" do
@@ -13,25 +13,18 @@ describe Rack::OAuth2::Server::Resource::Bearer do
13
13
  end
14
14
  end
15
15
  end
16
- let(:access_token) { env[Rack::OAuth2::Server::Resource::Bearer::ACCESS_TOKEN] }
16
+ let(:access_token) { env[Rack::OAuth2::Server::Resource::ACCESS_TOKEN] }
17
17
  let(:request) { app.call(env) }
18
18
  subject { app.call(env) }
19
19
 
20
- shared_examples_for :non_oauth2_request do
21
- it 'should skip OAuth 2.0 authentication' do
22
- status, header, response = request
23
- status.should == 200
24
- access_token.should be_nil
25
- end
26
- end
27
- shared_examples_for :authenticated_request do
20
+ shared_examples_for :authenticated_bearer_request do
28
21
  it 'should be authenticated' do
29
22
  status, header, response = request
30
23
  status.should == 200
31
24
  access_token.should == 'valid_token'
32
25
  end
33
26
  end
34
- shared_examples_for :unauthorized_request do
27
+ shared_examples_for :unauthorized_bearer_request do
35
28
  it 'should be unauthorized' do
36
29
  status, header, response = request
37
30
  status.should == 401
@@ -39,8 +32,8 @@ describe Rack::OAuth2::Server::Resource::Bearer do
39
32
  access_token.should be_nil
40
33
  end
41
34
  end
42
- shared_examples_for :bad_request do
43
- it 'should be unauthorized' do
35
+ shared_examples_for :bad_bearer_request do
36
+ it 'should be bad_request' do
44
37
  status, header, response = request
45
38
  status.should == 400
46
39
  access_token.should be_nil
@@ -49,30 +42,58 @@ describe Rack::OAuth2::Server::Resource::Bearer do
49
42
 
50
43
  context 'when no access token is given' do
51
44
  let(:env) { Rack::MockRequest.env_for('/protected_resource') }
52
- it_behaves_like :non_oauth2_request
45
+ it 'should skip OAuth 2.0 authentication' do
46
+ status, header, response = request
47
+ status.should == 200
48
+ access_token.should be_nil
49
+ end
53
50
  end
54
51
 
55
52
  context 'when valid_token is given' do
56
53
  context 'when token is in Authorization header' do
57
54
  let(:env) { Rack::MockRequest.env_for('/protected_resource', 'HTTP_AUTHORIZATION' => 'Bearer valid_token') }
58
- it_behaves_like :authenticated_request
55
+ it_behaves_like :authenticated_bearer_request
59
56
  end
60
57
 
61
58
  context 'when token is in params' do
62
59
  let(:env) { Rack::MockRequest.env_for('/protected_resource', :params => {:bearer_token => 'valid_token'}) }
63
- it_behaves_like :authenticated_request
60
+ it_behaves_like :authenticated_bearer_request
64
61
  end
65
62
  end
66
63
 
67
64
  context 'when invalid_token is given' do
65
+ let(:env) { Rack::MockRequest.env_for('/protected_resource', 'HTTP_AUTHORIZATION' => 'Bearer invalid_token') }
66
+
68
67
  context 'when token is in Authorization header' do
69
- let(:env) { Rack::MockRequest.env_for('/protected_resource', 'HTTP_AUTHORIZATION' => 'Bearer invalid_token') }
70
- it_behaves_like :unauthorized_request
68
+ it_behaves_like :unauthorized_bearer_request
71
69
  end
72
70
 
73
71
  context 'when token is in params' do
74
72
  let(:env) { Rack::MockRequest.env_for('/protected_resource', :params => {:bearer_token => 'invalid_token'}) }
75
- it_behaves_like :unauthorized_request
73
+ it_behaves_like :unauthorized_bearer_request
74
+ end
75
+
76
+ describe 'realm' do
77
+
78
+ context 'when specified' do
79
+ let(:realm) { 'server.example.com' }
80
+ let(:app) do
81
+ Rack::OAuth2::Server::Resource::Bearer.new(simple_app, realm) do |request|
82
+ request.unauthorized!
83
+ end
84
+ end
85
+ it 'should use specified realm' do
86
+ status, header, response = request
87
+ header['WWW-Authenticate'].should include "Bearer realm=\"#{realm}\""
88
+ end
89
+ end
90
+
91
+ context 'otherwize' do
92
+ it 'should use default realm' do
93
+ status, header, response = request
94
+ header['WWW-Authenticate'].should include "Bearer realm=\"#{Rack::OAuth2::Server::Resource::Bearer::DEFAULT_REALM}\""
95
+ end
96
+ end
76
97
  end
77
98
  end
78
99
 
@@ -85,57 +106,7 @@ describe Rack::OAuth2::Server::Resource::Bearer do
85
106
  :params => {:bearer_token => 'valid_token'}
86
107
  )
87
108
  end
88
- it_behaves_like :bad_request
89
- end
90
- end
91
-
92
- context 'when OAuth 1.0 request' do
93
- context 'when token is in Authorization header' do
94
- let(:env) do
95
- Rack::MockRequest.env_for(
96
- '/protected_resource',
97
- 'HTTP_AUTHORIZATION' => 'OAuth oauth_consumer_key="key" oauth_token="token" oauth_signature_method="HMAC-SHA1" oauth_signature="sig" oauth_timestamp="123456789" oauth_nonce="nonce"'
98
- )
99
- end
100
- it_behaves_like :non_oauth2_request
101
- end
102
-
103
- context 'when token is in params' do
104
- let(:env) do
105
- Rack::MockRequest.env_for('/protected_resource', :params => {
106
- :oauth_consumer_key => 'key',
107
- :oauth_token => 'token',
108
- :oauth_signature_method => 'HMAC-SHA1',
109
- :oauth_signature => 'sig',
110
- :oauth_timestamp => 123456789,
111
- :oauth_nonce => 'nonce'
112
- })
113
- end
114
- it_behaves_like :non_oauth2_request
115
- end
116
- end
117
-
118
- describe 'realm' do
119
- let(:env) { Rack::MockRequest.env_for('/protected_resource', 'HTTP_AUTHORIZATION' => 'Bearer invalid_token') }
120
-
121
- context 'when specified' do
122
- let(:realm) { 'server.example.com' }
123
- let(:app) do
124
- Rack::OAuth2::Server::Resource::Bearer.new(simple_app, realm) do |request|
125
- request.unauthorized!
126
- end
127
- end
128
- it 'should use specified realm' do
129
- status, header, response = request
130
- header['WWW-Authenticate'].should include "Bearer realm=\"#{realm}\""
131
- end
132
- end
133
-
134
- context 'otherwize' do
135
- it 'should use default realm' do
136
- status, header, response = request
137
- header['WWW-Authenticate'].should include "Bearer realm=\"#{Rack::OAuth2::Server::Resource::Bearer::DEFAULT_REALM}\""
138
- end
109
+ it_behaves_like :bad_bearer_request
139
110
  end
140
111
  end
141
112
  end
@@ -0,0 +1,147 @@
1
+ require 'spec_helper.rb'
2
+
3
+ describe Rack::OAuth2::Server::Resource::BadRequest do
4
+ let(:error) { Rack::OAuth2::Server::Resource::BadRequest.new(:invalid_request) }
5
+
6
+ it { should be_a Rack::OAuth2::Server::Abstract::BadRequest }
7
+
8
+ describe '#finish' do
9
+ it 'should respond in JSON' do
10
+ status, header, response = error.finish
11
+ status.should == 400
12
+ header['Content-Type'].should == 'application/json'
13
+ response.body.should == ['{"error":"invalid_request"}']
14
+ end
15
+ end
16
+ end
17
+
18
+ describe Rack::OAuth2::Server::Resource::Unauthorized do
19
+ let(:error) { Rack::OAuth2::Server::Resource::Unauthorized.new(:invalid_token) }
20
+ let(:realm) { Rack::OAuth2::Server::Resource::DEFAULT_REALM }
21
+
22
+ it { should be_a Rack::OAuth2::Server::Abstract::Unauthorized }
23
+
24
+ describe '#scheme' do
25
+ it do
26
+ expect { error.scheme }.should raise_error(RuntimeError, 'Define me!')
27
+ end
28
+ end
29
+
30
+ context 'when scheme is defined' do
31
+ let :error_with_scheme do
32
+ e = error
33
+ e.instance_eval do
34
+ def scheme
35
+ :Scheme
36
+ end
37
+ end
38
+ e
39
+ end
40
+
41
+ describe '#finish' do
42
+ it 'should respond in JSON' do
43
+ status, header, response = error_with_scheme.finish
44
+ status.should == 401
45
+ header['Content-Type'].should == 'application/json'
46
+ header['WWW-Authenticate'].should == "Scheme realm=\"#{realm}\" error=\"invalid_token\""
47
+ response.body.should == ['{"error":"invalid_token"}']
48
+ end
49
+
50
+ context 'when error_code is not invalid_token' do
51
+ let(:error) { Rack::OAuth2::Server::Resource::Unauthorized.new(:something) }
52
+
53
+ it 'should have error_code in body but not in WWW-Authenticate header' do
54
+ status, header, response = error_with_scheme.finish
55
+ header['WWW-Authenticate'].should == "Scheme realm=\"#{realm}\""
56
+ response.body.first.should include '"error":"something"'
57
+ end
58
+ end
59
+
60
+ context 'when realm is specified' do
61
+ let(:realm) { 'server.example.com' }
62
+ let(:error) { Rack::OAuth2::Server::Resource::Bearer::Unauthorized.new(:something, nil, :realm => realm) }
63
+
64
+ it 'should use given realm' do
65
+ status, header, response = error_with_scheme.finish
66
+ header['WWW-Authenticate'].should == "Scheme realm=\"#{realm}\""
67
+ response.body.first.should include '"error":"something"'
68
+ end
69
+ end
70
+ end
71
+ end
72
+ end
73
+
74
+ describe Rack::OAuth2::Server::Resource::Forbidden do
75
+ let(:error) { Rack::OAuth2::Server::Resource::Forbidden.new(:insufficient_scope) }
76
+
77
+ it { should be_a Rack::OAuth2::Server::Abstract::Forbidden }
78
+
79
+ describe '#finish' do
80
+ it 'should respond in JSON' do
81
+ status, header, response = error.finish
82
+ status.should == 403
83
+ header['Content-Type'].should == 'application/json'
84
+ response.body.should == ['{"error":"insufficient_scope"}']
85
+ end
86
+ end
87
+
88
+ context 'when scope option is given' do
89
+ let(:error) { Rack::OAuth2::Server::Resource::Bearer::Forbidden.new(:insufficient_scope, 'Desc', :scope => [:scope1, :scope2]) }
90
+
91
+ it 'should have blank WWW-Authenticate header' do
92
+ status, header, response = error.finish
93
+ response.body.first.should include '"scope":"scope1 scope2"'
94
+ end
95
+ end
96
+ end
97
+
98
+ describe Rack::OAuth2::Server::Resource::Bearer::ErrorMethods do
99
+ let(:bad_request) { Rack::OAuth2::Server::Resource::BadRequest }
100
+ let(:forbidden) { Rack::OAuth2::Server::Resource::Forbidden }
101
+ let(:redirect_uri) { 'http://client.example.com/callback' }
102
+ let(:default_description) { Rack::OAuth2::Server::Resource::ErrorMethods::DEFAULT_DESCRIPTION }
103
+ let(:env) { Rack::MockRequest.env_for("/authorize?client_id=client_id") }
104
+ let(:request) { Rack::OAuth2::Server::Resource::Request.new env }
105
+
106
+ describe 'bad_request!' do
107
+ it do
108
+ expect { request.bad_request! :invalid_request }.should raise_error bad_request
109
+ end
110
+ end
111
+
112
+ describe 'unauthorized!' do
113
+ it do
114
+ expect { request.unauthorized! :invalid_client }.should raise_error(RuntimeError, 'Define me!')
115
+ end
116
+ end
117
+
118
+ Rack::OAuth2::Server::Resource::ErrorMethods::DEFAULT_DESCRIPTION.keys.each do |error_code|
119
+ method = "#{error_code}!"
120
+ case error_code
121
+ when :invalid_request
122
+ describe method do
123
+ it "should raise Rack::OAuth2::Server::Resource::BadRequest with error = :#{error_code}" do
124
+ expect { request.send method }.should raise_error(bad_request) { |error|
125
+ error.error.should == error_code
126
+ error.description.should == default_description[error_code]
127
+ }
128
+ end
129
+ end
130
+ when :insufficient_scope
131
+ describe method do
132
+ it "should raise Rack::OAuth2::Server::Resource::Forbidden with error = :#{error_code}" do
133
+ expect { request.send method }.should raise_error(forbidden) { |error|
134
+ error.error.should == error_code
135
+ error.description.should == default_description[error_code]
136
+ }
137
+ end
138
+ end
139
+ else
140
+ describe method do
141
+ it do
142
+ expect { request.send method }.should raise_error(RuntimeError, 'Define me!')
143
+ end
144
+ end
145
+ end
146
+ end
147
+ end