##// END OF EJS Templates
Refactor: Convert the tests for Issues#index and #show APIs to shoulda. #6447...
Eric Davis -
r4250:c967899b1456
parent child
Show More
@@ -1,349 +1,314
1 1 # Redmine - project management software
2 2 # Copyright (C) 2006-2010 Jean-Philippe Lang
3 3 #
4 4 # This program is free software; you can redistribute it and/or
5 5 # modify it under the terms of the GNU General Public License
6 6 # as published by the Free Software Foundation; either version 2
7 7 # of the License, or (at your option) any later version.
8 8 #
9 9 # This program is distributed in the hope that it will be useful,
10 10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 12 # GNU General Public License for more details.
13 13 #
14 14 # You should have received a copy of the GNU General Public License
15 15 # along with this program; if not, write to the Free Software
16 16 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17 17
18 18 require "#{File.dirname(__FILE__)}/../../test_helper"
19 19
20 20 class ApiTest::IssuesTest < ActionController::IntegrationTest
21 21 fixtures :projects,
22 22 :users,
23 23 :roles,
24 24 :members,
25 25 :member_roles,
26 26 :issues,
27 27 :issue_statuses,
28 28 :versions,
29 29 :trackers,
30 30 :projects_trackers,
31 31 :issue_categories,
32 32 :enabled_modules,
33 33 :enumerations,
34 34 :attachments,
35 35 :workflows,
36 36 :custom_fields,
37 37 :custom_values,
38 38 :custom_fields_projects,
39 39 :custom_fields_trackers,
40 40 :time_entries,
41 41 :journals,
42 42 :journal_details,
43 43 :queries
44 44
45 45 def setup
46 46 Setting.rest_api_enabled = '1'
47 47 end
48 48
49 # Use a private project to make sure auth is really working and not just
50 # only showing public issues.
49 51 context "/index.xml" do
50 setup do
51 get '/issues.xml'
52 end
53
54 should_respond_with :success
55 should_respond_with_content_type 'application/xml'
52 should_allow_api_authentication(:get, "/projects/private-child/issues.xml")
56 53 end
57 54
58 55 context "/index.json" do
59 setup do
60 get '/issues.json'
61 end
62
63 should_respond_with :success
64 should_respond_with_content_type 'application/json'
65
66 should 'return a valid JSON string' do
67 assert ActiveSupport::JSON.decode(response.body)
68 end
56 should_allow_api_authentication(:get, "/projects/private-child/issues.json")
69 57 end
70 58
71 59 context "/index.xml with filter" do
72 setup do
73 get '/issues.xml?status_id=5'
74 end
60 should_allow_api_authentication(:get, "/projects/private-child/issues.xml?status_id=5")
75 61
76 should_respond_with :success
77 should_respond_with_content_type 'application/xml'
78 62 should "show only issues with the status_id" do
63 get '/issues.xml?status_id=5'
79 64 assert_tag :tag => 'issues',
80 65 :children => { :count => Issue.visible.count(:conditions => {:status_id => 5}),
81 66 :only => { :tag => 'issue' } }
82 67 end
83 68 end
84 69
85 70 context "/index.json with filter" do
86 setup do
87 get '/issues.json?status_id=5'
88 end
89
90 should_respond_with :success
91 should_respond_with_content_type 'application/json'
92
93 should 'return a valid JSON string' do
94 assert ActiveSupport::JSON.decode(response.body)
95 end
71 should_allow_api_authentication(:get, "/projects/private-child/issues.json?status_id=5")
96 72
97 73 should "show only issues with the status_id" do
74 get '/issues.json?status_id=5'
75
98 76 json = ActiveSupport::JSON.decode(response.body)
99 77 status_ids_used = json.collect {|j| j['status_id'] }
100 78 assert_equal 3, status_ids_used.length
101 79 assert status_ids_used.all? {|id| id == 5 }
102 80 end
103 81
104 82 end
105 83
106 context "/issues/1.xml" do
107 setup do
108 get '/issues/1.xml'
84 # Issue 6 is on a private project
85 context "/issues/6.xml" do
86 should_allow_api_authentication(:get, "/issues/6.xml")
109 87 end
110 88
111 should_respond_with :success
112 should_respond_with_content_type 'application/xml'
113 end
114
115 context "/issues/1.json" do
116 setup do
117 get '/issues/1.json'
118 end
119
120 should_respond_with :success
121 should_respond_with_content_type 'application/json'
122
123 should 'return a valid JSON string' do
124 assert ActiveSupport::JSON.decode(response.body)
125 end
89 context "/issues/6.json" do
90 should_allow_api_authentication(:get, "/issues/6.json")
126 91 end
127 92
128 93 context "POST /issues.xml" do
129 94 setup do
130 95 @issue_count = Issue.count
131 96 @attributes = {:project_id => 1, :subject => 'API test', :tracker_id => 2, :status_id => 3}
132 97 post '/issues.xml', {:issue => @attributes}, :authorization => credentials('jsmith')
133 98 end
134 99
135 100 should_respond_with :created
136 101 should_respond_with_content_type 'application/xml'
137 102
138 103 should "create an issue with the attributes" do
139 104 assert_equal Issue.count, @issue_count + 1
140 105
141 106 issue = Issue.first(:order => 'id DESC')
142 107 @attributes.each do |attribute, value|
143 108 assert_equal value, issue.send(attribute)
144 109 end
145 110 end
146 111 end
147 112
148 113 context "POST /issues.xml with failure" do
149 114 setup do
150 115 @attributes = {:project_id => 1}
151 116 post '/issues.xml', {:issue => @attributes}, :authorization => credentials('jsmith')
152 117 end
153 118
154 119 should_respond_with :unprocessable_entity
155 120 should_respond_with_content_type 'application/xml'
156 121
157 122 should "have an errors tag" do
158 123 assert_tag :errors, :child => {:tag => 'error', :content => "Subject can't be blank"}
159 124 end
160 125 end
161 126
162 127 context "POST /issues.json" do
163 128 setup do
164 129 @issue_count = Issue.count
165 130 @attributes = {:project_id => 1, :subject => 'API test', :tracker_id => 2, :status_id => 3}
166 131 post '/issues.json', {:issue => @attributes}, :authorization => credentials('jsmith')
167 132 end
168 133
169 134 should_respond_with :created
170 135 should_respond_with_content_type 'application/json'
171 136
172 137 should "create an issue with the attributes" do
173 138 assert_equal Issue.count, @issue_count + 1
174 139
175 140 issue = Issue.first(:order => 'id DESC')
176 141 @attributes.each do |attribute, value|
177 142 assert_equal value, issue.send(attribute)
178 143 end
179 144 end
180 145 end
181 146
182 147 context "POST /issues.json with failure" do
183 148 setup do
184 149 @attributes = {:project_id => 1}
185 150 post '/issues.json', {:issue => @attributes}, :authorization => credentials('jsmith')
186 151 end
187 152
188 153 should_respond_with :unprocessable_entity
189 154 should_respond_with_content_type 'application/json'
190 155
191 156 should "have an errors element" do
192 157 json = ActiveSupport::JSON.decode(response.body)
193 158 assert_equal "can't be blank", json.first['subject']
194 159 end
195 160 end
196 161
197 162 context "PUT /issues/1.xml" do
198 163 setup do
199 164 @issue_count = Issue.count
200 165 @journal_count = Journal.count
201 166 @attributes = {:subject => 'API update', :notes => 'A new note'}
202 167
203 168 put '/issues/1.xml', {:issue => @attributes}, :authorization => credentials('jsmith')
204 169 end
205 170
206 171 should_respond_with :ok
207 172 should_respond_with_content_type 'application/xml'
208 173
209 174 should "not create a new issue" do
210 175 assert_equal Issue.count, @issue_count
211 176 end
212 177
213 178 should "create a new journal" do
214 179 assert_equal Journal.count, @journal_count + 1
215 180 end
216 181
217 182 should "add the note to the journal" do
218 183 journal = Journal.last
219 184 assert_equal "A new note", journal.notes
220 185 end
221 186
222 187 should "update the issue" do
223 188 issue = Issue.find(1)
224 189 @attributes.each do |attribute, value|
225 190 assert_equal value, issue.send(attribute) unless attribute == :notes
226 191 end
227 192 end
228 193
229 194 end
230 195
231 196 context "PUT /issues/1.xml with failed update" do
232 197 setup do
233 198 @attributes = {:subject => ''}
234 199 @issue_count = Issue.count
235 200 @journal_count = Journal.count
236 201
237 202 put '/issues/1.xml', {:issue => @attributes}, :authorization => credentials('jsmith')
238 203 end
239 204
240 205 should_respond_with :unprocessable_entity
241 206 should_respond_with_content_type 'application/xml'
242 207
243 208 should "not create a new issue" do
244 209 assert_equal Issue.count, @issue_count
245 210 end
246 211
247 212 should "not create a new journal" do
248 213 assert_equal Journal.count, @journal_count
249 214 end
250 215
251 216 should "have an errors tag" do
252 217 assert_tag :errors, :child => {:tag => 'error', :content => "Subject can't be blank"}
253 218 end
254 219 end
255 220
256 221 context "PUT /issues/1.json" do
257 222 setup do
258 223 @issue_count = Issue.count
259 224 @journal_count = Journal.count
260 225 @attributes = {:subject => 'API update', :notes => 'A new note'}
261 226
262 227 put '/issues/1.json', {:issue => @attributes}, :authorization => credentials('jsmith')
263 228 end
264 229
265 230 should_respond_with :ok
266 231 should_respond_with_content_type 'application/json'
267 232
268 233 should "not create a new issue" do
269 234 assert_equal Issue.count, @issue_count
270 235 end
271 236
272 237 should "create a new journal" do
273 238 assert_equal Journal.count, @journal_count + 1
274 239 end
275 240
276 241 should "add the note to the journal" do
277 242 journal = Journal.last
278 243 assert_equal "A new note", journal.notes
279 244 end
280 245
281 246 should "update the issue" do
282 247 issue = Issue.find(1)
283 248 @attributes.each do |attribute, value|
284 249 assert_equal value, issue.send(attribute) unless attribute == :notes
285 250 end
286 251 end
287 252
288 253 end
289 254
290 255 context "PUT /issues/1.json with failed update" do
291 256 setup do
292 257 @attributes = {:subject => ''}
293 258 @issue_count = Issue.count
294 259 @journal_count = Journal.count
295 260
296 261 put '/issues/1.json', {:issue => @attributes}, :authorization => credentials('jsmith')
297 262 end
298 263
299 264 should_respond_with :unprocessable_entity
300 265 should_respond_with_content_type 'application/json'
301 266
302 267 should "not create a new issue" do
303 268 assert_equal Issue.count, @issue_count
304 269 end
305 270
306 271 should "not create a new journal" do
307 272 assert_equal Journal.count, @journal_count
308 273 end
309 274
310 275 should "have an errors attribute" do
311 276 json = ActiveSupport::JSON.decode(response.body)
312 277 assert_equal "can't be blank", json.first['subject']
313 278 end
314 279 end
315 280
316 281 context "DELETE /issues/1.xml" do
317 282 setup do
318 283 @issue_count = Issue.count
319 284 delete '/issues/1.xml', {}, :authorization => credentials('jsmith')
320 285 end
321 286
322 287 should_respond_with :ok
323 288 should_respond_with_content_type 'application/xml'
324 289
325 290 should "delete the issue" do
326 291 assert_equal Issue.count, @issue_count -1
327 292 assert_nil Issue.find_by_id(1)
328 293 end
329 294 end
330 295
331 296 context "DELETE /issues/1.json" do
332 297 setup do
333 298 @issue_count = Issue.count
334 299 delete '/issues/1.json', {}, :authorization => credentials('jsmith')
335 300 end
336 301
337 302 should_respond_with :ok
338 303 should_respond_with_content_type 'application/json'
339 304
340 305 should "delete the issue" do
341 306 assert_equal Issue.count, @issue_count -1
342 307 assert_nil Issue.find_by_id(1)
343 308 end
344 309 end
345 310
346 311 def credentials(user, password=nil)
347 312 ActionController::HttpAuthentication::Basic.encode_credentials(user, password || user)
348 313 end
349 314 end
@@ -1,336 +1,393
1 1 # redMine - project management software
2 2 # Copyright (C) 2006 Jean-Philippe Lang
3 3 #
4 4 # This program is free software; you can redistribute it and/or
5 5 # modify it under the terms of the GNU General Public License
6 6 # as published by the Free Software Foundation; either version 2
7 7 # of the License, or (at your option) any later version.
8 8 #
9 9 # This program is distributed in the hope that it will be useful,
10 10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 12 # GNU General Public License for more details.
13 13 #
14 14 # You should have received a copy of the GNU General Public License
15 15 # along with this program; if not, write to the Free Software
16 16 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17 17
18 18 ENV["RAILS_ENV"] = "test"
19 19 require File.expand_path(File.dirname(__FILE__) + "/../config/environment")
20 20 require 'test_help'
21 21 require File.expand_path(File.dirname(__FILE__) + '/helper_testcase')
22 22 require File.join(RAILS_ROOT,'test', 'mocks', 'open_id_authentication_mock.rb')
23 23
24 24 require File.expand_path(File.dirname(__FILE__) + '/object_daddy_helpers')
25 25 include ObjectDaddyHelpers
26 26
27 27 class ActiveSupport::TestCase
28 28 # Transactional fixtures accelerate your tests by wrapping each test method
29 29 # in a transaction that's rolled back on completion. This ensures that the
30 30 # test database remains unchanged so your fixtures don't have to be reloaded
31 31 # between every test method. Fewer database queries means faster tests.
32 32 #
33 33 # Read Mike Clark's excellent walkthrough at
34 34 # http://clarkware.com/cgi/blosxom/2005/10/24#Rails10FastTesting
35 35 #
36 36 # Every Active Record database supports transactions except MyISAM tables
37 37 # in MySQL. Turn off transactional fixtures in this case; however, if you
38 38 # don't care one way or the other, switching from MyISAM to InnoDB tables
39 39 # is recommended.
40 40 self.use_transactional_fixtures = true
41 41
42 42 # Instantiated fixtures are slow, but give you @david where otherwise you
43 43 # would need people(:david). If you don't want to migrate your existing
44 44 # test cases which use the @david style and don't mind the speed hit (each
45 45 # instantiated fixtures translates to a database query per test method),
46 46 # then set this back to true.
47 47 self.use_instantiated_fixtures = false
48 48
49 49 # Add more helper methods to be used by all tests here...
50 50
51 51 def log_user(login, password)
52 52 User.anonymous
53 53 get "/login"
54 54 assert_equal nil, session[:user_id]
55 55 assert_response :success
56 56 assert_template "account/login"
57 57 post "/login", :username => login, :password => password
58 58 assert_equal login, User.find(session[:user_id]).login
59 59 end
60 60
61 61 def uploaded_test_file(name, mime)
62 62 ActionController::TestUploadedFile.new(ActiveSupport::TestCase.fixture_path + "/files/#{name}", mime)
63 63 end
64 64
65 65 # Mock out a file
66 66 def self.mock_file
67 67 file = 'a_file.png'
68 68 file.stubs(:size).returns(32)
69 69 file.stubs(:original_filename).returns('a_file.png')
70 70 file.stubs(:content_type).returns('image/png')
71 71 file.stubs(:read).returns(false)
72 72 file
73 73 end
74 74
75 75 def mock_file
76 76 self.class.mock_file
77 77 end
78 78
79 79 # Use a temporary directory for attachment related tests
80 80 def set_tmp_attachments_directory
81 81 Dir.mkdir "#{RAILS_ROOT}/tmp/test" unless File.directory?("#{RAILS_ROOT}/tmp/test")
82 82 Dir.mkdir "#{RAILS_ROOT}/tmp/test/attachments" unless File.directory?("#{RAILS_ROOT}/tmp/test/attachments")
83 83 Attachment.storage_path = "#{RAILS_ROOT}/tmp/test/attachments"
84 84 end
85 85
86 86 def with_settings(options, &block)
87 87 saved_settings = options.keys.inject({}) {|h, k| h[k] = Setting[k].dup; h}
88 88 options.each {|k, v| Setting[k] = v}
89 89 yield
90 90 saved_settings.each {|k, v| Setting[k] = v}
91 91 end
92 92
93 93 def change_user_password(login, new_password)
94 94 user = User.first(:conditions => {:login => login})
95 95 user.password, user.password_confirmation = new_password, new_password
96 96 user.save!
97 97 end
98 98
99 99 def self.ldap_configured?
100 100 @test_ldap = Net::LDAP.new(:host => '127.0.0.1', :port => 389)
101 101 return @test_ldap.bind
102 102 rescue Exception => e
103 103 # LDAP is not listening
104 104 return nil
105 105 end
106 106
107 107 # Returns the path to the test +vendor+ repository
108 108 def self.repository_path(vendor)
109 109 File.join(RAILS_ROOT.gsub(%r{config\/\.\.}, ''), "/tmp/test/#{vendor.downcase}_repository")
110 110 end
111 111
112 112 # Returns true if the +vendor+ test repository is configured
113 113 def self.repository_configured?(vendor)
114 114 File.directory?(repository_path(vendor))
115 115 end
116 116
117 117 def assert_error_tag(options={})
118 118 assert_tag({:tag => 'p', :attributes => { :id => 'errorExplanation' }}.merge(options))
119 119 end
120 120
121 121 # Shoulda macros
122 122 def self.should_render_404
123 123 should_respond_with :not_found
124 124 should_render_template 'common/error'
125 125 end
126 126
127 127 def self.should_have_before_filter(expected_method, options = {})
128 128 should_have_filter('before', expected_method, options)
129 129 end
130 130
131 131 def self.should_have_after_filter(expected_method, options = {})
132 132 should_have_filter('after', expected_method, options)
133 133 end
134 134
135 135 def self.should_have_filter(filter_type, expected_method, options)
136 136 description = "have #{filter_type}_filter :#{expected_method}"
137 137 description << " with #{options.inspect}" unless options.empty?
138 138
139 139 should description do
140 140 klass = "action_controller/filters/#{filter_type}_filter".classify.constantize
141 141 expected = klass.new(:filter, expected_method.to_sym, options)
142 142 assert_equal 1, @controller.class.filter_chain.select { |filter|
143 143 filter.method == expected.method && filter.kind == expected.kind &&
144 144 filter.options == expected.options && filter.class == expected.class
145 145 }.size
146 146 end
147 147 end
148 148
149 149 def self.should_show_the_old_and_new_values_for(prop_key, model, &block)
150 150 context "" do
151 151 setup do
152 152 if block_given?
153 153 instance_eval &block
154 154 else
155 155 @old_value = model.generate!
156 156 @new_value = model.generate!
157 157 end
158 158 end
159 159
160 160 should "use the new value's name" do
161 161 @detail = JournalDetail.generate!(:property => 'attr',
162 162 :old_value => @old_value.id,
163 163 :value => @new_value.id,
164 164 :prop_key => prop_key)
165 165
166 166 assert_match @new_value.name, show_detail(@detail, true)
167 167 end
168 168
169 169 should "use the old value's name" do
170 170 @detail = JournalDetail.generate!(:property => 'attr',
171 171 :old_value => @old_value.id,
172 172 :value => @new_value.id,
173 173 :prop_key => prop_key)
174 174
175 175 assert_match @old_value.name, show_detail(@detail, true)
176 176 end
177 177 end
178 178 end
179 179
180 180 def self.should_create_a_new_user(&block)
181 181 should "create a new user" do
182 182 user = instance_eval &block
183 183 assert user
184 184 assert_kind_of User, user
185 185 assert !user.new_record?
186 186 end
187 187 end
188 188
189 # Test that a request allows the three types of API authentication
190 #
191 # * HTTP Basic with username and password
192 # * HTTP Basic with an api key for the username
193 # * Key based with the key=X parameter
194 #
195 # @param [Symbol] http_method the HTTP method for request (:get, :post, :put, :delete)
196 # @param [String] url the request url
197 # @param [optional, Hash] parameters additional request parameters
198 def self.should_allow_api_authentication(http_method, url, parameters={})
199 should_allow_http_basic_auth_with_username_and_password(http_method, url, parameters)
200 should_allow_http_basic_auth_with_key(http_method, url, parameters)
201 should_allow_key_based_auth(http_method, url, parameters)
202 end
203
189 204 # Test that a request allows the username and password for HTTP BASIC
190 205 #
191 206 # @param [Symbol] http_method the HTTP method for request (:get, :post, :put, :delete)
192 207 # @param [String] url the request url
193 208 # @param [optional, Hash] parameters additional request parameters
194 209 def self.should_allow_http_basic_auth_with_username_and_password(http_method, url, parameters={})
195 210 context "should allow http basic auth using a username and password for #{http_method} #{url}" do
196 211 context "with a valid HTTP authentication" do
197 212 setup do
198 213 @user = User.generate_with_protected!(:password => 'my_password', :password_confirmation => 'my_password', :admin => true) # Admin so they can access the project
199 214 @authorization = ActionController::HttpAuthentication::Basic.encode_credentials(@user.login, 'my_password')
200 215 send(http_method, url, parameters, {:authorization => @authorization})
201 216 end
202 217
203 218 should_respond_with :success
204 219 should_respond_with_content_type_based_on_url(url)
205 220 should "login as the user" do
206 221 assert_equal @user, User.current
207 222 end
208 223 end
209 224
210 225 context "with an invalid HTTP authentication" do
211 226 setup do
212 227 @user = User.generate_with_protected!
213 228 @authorization = ActionController::HttpAuthentication::Basic.encode_credentials(@user.login, 'wrong_password')
214 229 send(http_method, url, parameters, {:authorization => @authorization})
215 230 end
216 231
217 232 should_respond_with :unauthorized
218 233 should_respond_with_content_type_based_on_url(url)
219 234 should "not login as the user" do
220 235 assert_equal User.anonymous, User.current
221 236 end
222 237 end
223 238
224 239 context "without credentials" do
225 240 setup do
226 241 send(http_method, url, parameters, {:authorization => ''})
227 242 end
228 243
229 244 should_respond_with :unauthorized
230 245 should_respond_with_content_type_based_on_url(url)
231 246 should "include_www_authenticate_header" do
232 247 assert @controller.response.headers.has_key?('WWW-Authenticate')
233 248 end
234 249 end
235 250 end
236 251
237 252 end
238 253
239 254 # Test that a request allows the API key with HTTP BASIC
240 255 #
241 256 # @param [Symbol] http_method the HTTP method for request (:get, :post, :put, :delete)
242 257 # @param [String] url the request url
243 258 # @param [optional, Hash] parameters additional request parameters
244 259 def self.should_allow_http_basic_auth_with_key(http_method, url, parameters={})
245 260 context "should allow http basic auth with a key for #{http_method} #{url}" do
246 261 context "with a valid HTTP authentication using the API token" do
247 262 setup do
248 @user = User.generate_with_protected!
263 @user = User.generate_with_protected!(:admin => true)
249 264 @token = Token.generate!(:user => @user, :action => 'api')
250 265 @authorization = ActionController::HttpAuthentication::Basic.encode_credentials(@token.value, 'X')
251 266 send(http_method, url, parameters, {:authorization => @authorization})
252 267 end
253 268
254 269 should_respond_with :success
255 270 should_respond_with_content_type_based_on_url(url)
271 should_be_a_valid_response_string_based_on_url(url)
256 272 should "login as the user" do
257 273 assert_equal @user, User.current
258 274 end
259 275 end
260 276
261 277 context "with an invalid HTTP authentication" do
262 278 setup do
263 279 @user = User.generate_with_protected!
264 280 @token = Token.generate!(:user => @user, :action => 'feeds')
265 281 @authorization = ActionController::HttpAuthentication::Basic.encode_credentials(@token.value, 'X')
266 282 send(http_method, url, parameters, {:authorization => @authorization})
267 283 end
268 284
269 285 should_respond_with :unauthorized
270 286 should_respond_with_content_type_based_on_url(url)
271 287 should "not login as the user" do
272 288 assert_equal User.anonymous, User.current
273 289 end
274 290 end
275 291 end
276 292 end
277 293
278 294 # Test that a request allows full key authentication
279 295 #
280 296 # @param [Symbol] http_method the HTTP method for request (:get, :post, :put, :delete)
281 297 # @param [String] url the request url, without the key=ZXY parameter
282 def self.should_allow_key_based_auth(http_method, url)
298 # @param [optional, Hash] parameters additional request parameters
299 def self.should_allow_key_based_auth(http_method, url, parameters={})
283 300 context "should allow key based auth using key=X for #{http_method} #{url}" do
284 301 context "with a valid api token" do
285 302 setup do
286 @user = User.generate_with_protected!
303 @user = User.generate_with_protected!(:admin => true)
287 304 @token = Token.generate!(:user => @user, :action => 'api')
288 send(http_method, url + "?key=#{@token.value}")
305 # Simple url parse to add on ?key= or &key=
306 request_url = if url.match(/\?/)
307 url + "&key=#{@token.value}"
308 else
309 url + "?key=#{@token.value}"
310 end
311 send(http_method, request_url, parameters)
289 312 end
290 313
291 314 should_respond_with :success
292 315 should_respond_with_content_type_based_on_url(url)
316 should_be_a_valid_response_string_based_on_url(url)
293 317 should "login as the user" do
294 318 assert_equal @user, User.current
295 319 end
296 320 end
297 321
298 322 context "with an invalid api token" do
299 323 setup do
300 324 @user = User.generate_with_protected!
301 325 @token = Token.generate!(:user => @user, :action => 'feeds')
302 326 send(http_method, url + "?key=#{@token.value}")
303 327 end
304 328
305 329 should_respond_with :unauthorized
306 330 should_respond_with_content_type_based_on_url(url)
307 331 should "not login as the user" do
308 332 assert_equal User.anonymous, User.current
309 333 end
310 334 end
311 335 end
312 336
313 337 end
314 338
315 339 # Uses should_respond_with_content_type based on what's in the url:
316 340 #
317 341 # '/project/issues.xml' => should_respond_with_content_type :xml
318 342 # '/project/issues.json' => should_respond_with_content_type :json
319 343 #
320 344 # @param [String] url Request
321 345 def self.should_respond_with_content_type_based_on_url(url)
322 346 case
323 347 when url.match(/xml/i)
324 348 should_respond_with_content_type :xml
325 349 when url.match(/json/i)
326 350 should_respond_with_content_type :json
327 351 else
328 352 raise "Unknown content type for should_respond_with_content_type_based_on_url: #{url}"
329 353 end
330 354
331 355 end
356
357 # Uses the url to assert which format the response should be in
358 #
359 # '/project/issues.xml' => should_be_a_valid_xml_string
360 # '/project/issues.json' => should_be_a_valid_json_string
361 #
362 # @param [String] url Request
363 def self.should_be_a_valid_response_string_based_on_url(url)
364 case
365 when url.match(/xml/i)
366 should_be_a_valid_xml_string
367 when url.match(/json/i)
368 should_be_a_valid_json_string
369 else
370 raise "Unknown content type for should_be_a_valid_response_based_on_url: #{url}"
371 end
372
373 end
374
375 # Checks that the response is a valid JSON string
376 def self.should_be_a_valid_json_string
377 should "be a valid JSON string" do
378 assert ActiveSupport::JSON.decode(response.body)
379 end
380 end
381
382 # Checks that the response is a valid XML string
383 def self.should_be_a_valid_xml_string
384 should "be a valid XML string" do
385 assert REXML::Document.new(response.body)
386 end
387 end
388
332 389 end
333 390
334 391 # Simple module to "namespace" all of the API tests
335 392 module ApiTest
336 393 end
General Comments 0
You need to be logged in to leave comments. Login now