comparison test/test_helper.rb @ 1115:433d4f72a19b redmine-2.2

Update to Redmine SVN revision 11137 on 2.2-stable branch
author Chris Cannam
date Mon, 07 Jan 2013 12:01:42 +0000
parents cbb26bc654de
children bb32da3bea34 622f24f53b42 261b3d9a4903
comparison
equal deleted inserted replaced
929:5f33065ddc4b 1115:433d4f72a19b
1 # Redmine - project management software 1 # Redmine - project management software
2 # Copyright (C) 2006-2011 Jean-Philippe Lang 2 # Copyright (C) 2006-2012 Jean-Philippe Lang
3 # 3 #
4 # This program is free software; you can redistribute it and/or 4 # This program is free software; you can redistribute it and/or
5 # modify it under the terms of the GNU General Public License 5 # modify it under the terms of the GNU General Public License
6 # as published by the Free Software Foundation; either version 2 6 # as published by the Free Software Foundation; either version 2
7 # of the License, or (at your option) any later version. 7 # of the License, or (at your option) any later version.
13 # 13 #
14 # You should have received a copy of the GNU General Public License 14 # You should have received a copy of the GNU General Public License
15 # along with this program; if not, write to the Free Software 15 # along with this program; if not, write to the Free Software
16 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 16 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17 17
18 #require 'shoulda'
18 ENV["RAILS_ENV"] = "test" 19 ENV["RAILS_ENV"] = "test"
19 require File.expand_path(File.dirname(__FILE__) + "/../config/environment") 20 require File.expand_path(File.dirname(__FILE__) + "/../config/environment")
20 require 'test_help' 21 require 'rails/test_help'
21 require File.expand_path(File.dirname(__FILE__) + '/helper_testcase')
22 require Rails.root.join('test', 'mocks', 'open_id_authentication_mock.rb').to_s 22 require Rails.root.join('test', 'mocks', 'open_id_authentication_mock.rb').to_s
23 23
24 require File.expand_path(File.dirname(__FILE__) + '/object_daddy_helpers') 24 require File.expand_path(File.dirname(__FILE__) + '/object_helpers')
25 include ObjectDaddyHelpers 25 include ObjectHelpers
26 26
27 class ActiveSupport::TestCase 27 class ActiveSupport::TestCase
28 include ActionDispatch::TestProcess
29
28 # Transactional fixtures accelerate your tests by wrapping each test method 30 # Transactional fixtures accelerate your tests by wrapping each test method
29 # in a transaction that's rolled back on completion. This ensures that the 31 # in a transaction that's rolled back on completion. This ensures that the
30 # test database remains unchanged so your fixtures don't have to be reloaded 32 # test database remains unchanged so your fixtures don't have to be reloaded
31 # between every test method. Fewer database queries means faster tests. 33 # between every test method. Fewer database queries means faster tests.
32 # 34 #
57 post "/login", :username => login, :password => password 59 post "/login", :username => login, :password => password
58 assert_equal login, User.find(session[:user_id]).login 60 assert_equal login, User.find(session[:user_id]).login
59 end 61 end
60 62
61 def uploaded_test_file(name, mime) 63 def uploaded_test_file(name, mime)
62 ActionController::TestUploadedFile.new( 64 fixture_file_upload("files/#{name}", mime, true)
63 ActiveSupport::TestCase.fixture_path + "/files/#{name}", mime, true) 65 end
66
67 def credentials(user, password=nil)
68 {'HTTP_AUTHORIZATION' => ActionController::HttpAuthentication::Basic.encode_credentials(user, password || user)}
64 end 69 end
65 70
66 # Mock out a file 71 # Mock out a file
67 def self.mock_file 72 def self.mock_file
68 file = 'a_file.png' 73 file = 'a_file.png'
95 Dir.mkdir "#{Rails.root}/tmp/test/attachments" 100 Dir.mkdir "#{Rails.root}/tmp/test/attachments"
96 end 101 end
97 Attachment.storage_path = "#{Rails.root}/tmp/test/attachments" 102 Attachment.storage_path = "#{Rails.root}/tmp/test/attachments"
98 end 103 end
99 104
105 def set_fixtures_attachments_directory
106 Attachment.storage_path = "#{Rails.root}/test/fixtures/files"
107 end
108
100 def with_settings(options, &block) 109 def with_settings(options, &block)
101 saved_settings = options.keys.inject({}) {|h, k| h[k] = Setting[k].is_a?(Symbol) ? Setting[k] : Setting[k].dup; h} 110 saved_settings = options.keys.inject({}) {|h, k| h[k] = Setting[k].is_a?(Symbol) ? Setting[k] : Setting[k].dup; h}
102 options.each {|k, v| Setting[k] = v} 111 options.each {|k, v| Setting[k] = v}
103 yield 112 yield
104 ensure 113 ensure
105 saved_settings.each {|k, v| Setting[k] = v} if saved_settings 114 saved_settings.each {|k, v| Setting[k] = v} if saved_settings
106 end 115 end
107 116
117 # Yields the block with user as the current user
118 def with_current_user(user, &block)
119 saved_user = User.current
120 User.current = user
121 yield
122 ensure
123 User.current = saved_user
124 end
125
108 def change_user_password(login, new_password) 126 def change_user_password(login, new_password)
109 user = User.first(:conditions => {:login => login}) 127 user = User.first(:conditions => {:login => login})
110 user.password, user.password_confirmation = new_password, new_password 128 user.password, user.password_confirmation = new_password, new_password
111 user.save! 129 user.save!
112 end 130 end
117 rescue Exception => e 135 rescue Exception => e
118 # LDAP is not listening 136 # LDAP is not listening
119 return nil 137 return nil
120 end 138 end
121 139
140 def self.convert_installed?
141 Redmine::Thumbnail.convert_available?
142 end
143
122 # Returns the path to the test +vendor+ repository 144 # Returns the path to the test +vendor+ repository
123 def self.repository_path(vendor) 145 def self.repository_path(vendor)
124 Rails.root.join("tmp/test/#{vendor.downcase}_repository").to_s 146 Rails.root.join("tmp/test/#{vendor.downcase}_repository").to_s
125 end 147 end
126 148
134 # Returns true if the +vendor+ test repository is configured 156 # Returns true if the +vendor+ test repository is configured
135 def self.repository_configured?(vendor) 157 def self.repository_configured?(vendor)
136 File.directory?(repository_path(vendor)) 158 File.directory?(repository_path(vendor))
137 end 159 end
138 160
161 def repository_path_hash(arr)
162 hs = {}
163 hs[:path] = arr.join("/")
164 hs[:param] = arr.join("/")
165 hs
166 end
167
168 def assert_save(object)
169 saved = object.save
170 message = "#{object.class} could not be saved"
171 errors = object.errors.full_messages.map {|m| "- #{m}"}
172 message << ":\n#{errors.join("\n")}" if errors.any?
173 assert_equal true, saved, message
174 end
175
139 def assert_error_tag(options={}) 176 def assert_error_tag(options={})
140 assert_tag({:attributes => { :id => 'errorExplanation' }}.merge(options)) 177 assert_tag({:attributes => { :id => 'errorExplanation' }}.merge(options))
141 end 178 end
142 179
143 def assert_include(expected, s) 180 def assert_include(expected, s, message=nil)
144 assert s.include?(expected), "\"#{expected}\" not found in \"#{s}\"" 181 assert s.include?(expected), (message || "\"#{expected}\" not found in \"#{s}\"")
182 end
183
184 def assert_not_include(expected, s)
185 assert !s.include?(expected), "\"#{expected}\" found in \"#{s}\""
186 end
187
188 def assert_select_in(text, *args, &block)
189 d = HTML::Document.new(CGI::unescapeHTML(String.new(text))).root
190 assert_select(d, *args, &block)
191 end
192
193 def assert_mail_body_match(expected, mail)
194 if expected.is_a?(String)
195 assert_include expected, mail_body(mail)
196 else
197 assert_match expected, mail_body(mail)
198 end
199 end
200
201 def assert_mail_body_no_match(expected, mail)
202 if expected.is_a?(String)
203 assert_not_include expected, mail_body(mail)
204 else
205 assert_no_match expected, mail_body(mail)
206 end
207 end
208
209 def mail_body(mail)
210 mail.parts.first.body.encoded
145 end 211 end
146 212
147 # Shoulda macros 213 # Shoulda macros
148 def self.should_render_404 214 def self.should_render_404
149 should_respond_with :not_found 215 should_respond_with :not_found
167 expected = klass.new(:filter, expected_method.to_sym, options) 233 expected = klass.new(:filter, expected_method.to_sym, options)
168 assert_equal 1, @controller.class.filter_chain.select { |filter| 234 assert_equal 1, @controller.class.filter_chain.select { |filter|
169 filter.method == expected.method && filter.kind == expected.kind && 235 filter.method == expected.method && filter.kind == expected.kind &&
170 filter.options == expected.options && filter.class == expected.class 236 filter.options == expected.options && filter.class == expected.class
171 }.size 237 }.size
172 end
173 end
174
175 def self.should_show_the_old_and_new_values_for(prop_key, model, &block)
176 context "" do
177 setup do
178 if block_given?
179 instance_eval &block
180 else
181 @old_value = model.generate!
182 @new_value = model.generate!
183 end
184 end
185
186 should "use the new value's name" do
187 @detail = JournalDetail.generate!(:property => 'attr',
188 :old_value => @old_value.id,
189 :value => @new_value.id,
190 :prop_key => prop_key)
191
192 assert_match @new_value.name, show_detail(@detail, true)
193 end
194
195 should "use the old value's name" do
196 @detail = JournalDetail.generate!(:property => 'attr',
197 :old_value => @old_value.id,
198 :value => @new_value.id,
199 :prop_key => prop_key)
200
201 assert_match @old_value.name, show_detail(@detail, true)
202 end
203 end
204 end
205
206 def self.should_create_a_new_user(&block)
207 should "create a new user" do
208 user = instance_eval &block
209 assert user
210 assert_kind_of User, user
211 assert !user.new_record?
212 end 238 end
213 end 239 end
214 240
215 # Test that a request allows the three types of API authentication 241 # Test that a request allows the three types of API authentication
216 # 242 #
243 failure_code = options[:failure_code] || :unauthorized 269 failure_code = options[:failure_code] || :unauthorized
244 270
245 context "should allow http basic auth using a username and password for #{http_method} #{url}" do 271 context "should allow http basic auth using a username and password for #{http_method} #{url}" do
246 context "with a valid HTTP authentication" do 272 context "with a valid HTTP authentication" do
247 setup do 273 setup do
248 @user = User.generate_with_protected!(:password => 'my_password', :password_confirmation => 'my_password', :admin => true) # Admin so they can access the project 274 @user = User.generate! do |user|
249 @authorization = ActionController::HttpAuthentication::Basic.encode_credentials(@user.login, 'my_password') 275 user.admin = true
250 send(http_method, url, parameters, {:authorization => @authorization}) 276 user.password = 'my_password'
277 end
278 send(http_method, url, parameters, credentials(@user.login, 'my_password'))
251 end 279 end
252 280
253 should_respond_with success_code 281 should_respond_with success_code
254 should_respond_with_content_type_based_on_url(url) 282 should_respond_with_content_type_based_on_url(url)
255 should "login as the user" do 283 should "login as the user" do
257 end 285 end
258 end 286 end
259 287
260 context "with an invalid HTTP authentication" do 288 context "with an invalid HTTP authentication" do
261 setup do 289 setup do
262 @user = User.generate_with_protected! 290 @user = User.generate!
263 @authorization = ActionController::HttpAuthentication::Basic.encode_credentials(@user.login, 'wrong_password') 291 send(http_method, url, parameters, credentials(@user.login, 'wrong_password'))
264 send(http_method, url, parameters, {:authorization => @authorization})
265 end 292 end
266 293
267 should_respond_with failure_code 294 should_respond_with failure_code
268 should_respond_with_content_type_based_on_url(url) 295 should_respond_with_content_type_based_on_url(url)
269 should "not login as the user" do 296 should "not login as the user" do
271 end 298 end
272 end 299 end
273 300
274 context "without credentials" do 301 context "without credentials" do
275 setup do 302 setup do
276 send(http_method, url, parameters, {:authorization => ''}) 303 send(http_method, url, parameters)
277 end 304 end
278 305
279 should_respond_with failure_code 306 should_respond_with failure_code
280 should_respond_with_content_type_based_on_url(url) 307 should_respond_with_content_type_based_on_url(url)
281 should "include_www_authenticate_header" do 308 should "include_www_authenticate_header" do
282 assert @controller.response.headers.has_key?('WWW-Authenticate') 309 assert @controller.response.headers.has_key?('WWW-Authenticate')
283 end 310 end
284 end 311 end
285 end 312 end
286
287 end 313 end
288 314
289 # Test that a request allows the API key with HTTP BASIC 315 # Test that a request allows the API key with HTTP BASIC
290 # 316 #
291 # @param [Symbol] http_method the HTTP method for request (:get, :post, :put, :delete) 317 # @param [Symbol] http_method the HTTP method for request (:get, :post, :put, :delete)
299 failure_code = options[:failure_code] || :unauthorized 325 failure_code = options[:failure_code] || :unauthorized
300 326
301 context "should allow http basic auth with a key for #{http_method} #{url}" do 327 context "should allow http basic auth with a key for #{http_method} #{url}" do
302 context "with a valid HTTP authentication using the API token" do 328 context "with a valid HTTP authentication using the API token" do
303 setup do 329 setup do
304 @user = User.generate_with_protected!(:admin => true) 330 @user = User.generate! do |user|
305 @token = Token.generate!(:user => @user, :action => 'api') 331 user.admin = true
306 @authorization = ActionController::HttpAuthentication::Basic.encode_credentials(@token.value, 'X') 332 end
307 send(http_method, url, parameters, {:authorization => @authorization}) 333 @token = Token.create!(:user => @user, :action => 'api')
308 end 334 send(http_method, url, parameters, credentials(@token.value, 'X'))
309 335 end
310 should_respond_with success_code 336 should_respond_with success_code
311 should_respond_with_content_type_based_on_url(url) 337 should_respond_with_content_type_based_on_url(url)
312 should_be_a_valid_response_string_based_on_url(url) 338 should_be_a_valid_response_string_based_on_url(url)
313 should "login as the user" do 339 should "login as the user" do
314 assert_equal @user, User.current 340 assert_equal @user, User.current
315 end 341 end
316 end 342 end
317 343
318 context "with an invalid HTTP authentication" do 344 context "with an invalid HTTP authentication" do
319 setup do 345 setup do
320 @user = User.generate_with_protected! 346 @user = User.generate!
321 @token = Token.generate!(:user => @user, :action => 'feeds') 347 @token = Token.create!(:user => @user, :action => 'feeds')
322 @authorization = ActionController::HttpAuthentication::Basic.encode_credentials(@token.value, 'X') 348 send(http_method, url, parameters, credentials(@token.value, 'X'))
323 send(http_method, url, parameters, {:authorization => @authorization}) 349 end
324 end
325
326 should_respond_with failure_code 350 should_respond_with failure_code
327 should_respond_with_content_type_based_on_url(url) 351 should_respond_with_content_type_based_on_url(url)
328 should "not login as the user" do 352 should "not login as the user" do
329 assert_equal User.anonymous, User.current 353 assert_equal User.anonymous, User.current
330 end 354 end
345 failure_code = options[:failure_code] || :unauthorized 369 failure_code = options[:failure_code] || :unauthorized
346 370
347 context "should allow key based auth using key=X for #{http_method} #{url}" do 371 context "should allow key based auth using key=X for #{http_method} #{url}" do
348 context "with a valid api token" do 372 context "with a valid api token" do
349 setup do 373 setup do
350 @user = User.generate_with_protected!(:admin => true) 374 @user = User.generate! do |user|
351 @token = Token.generate!(:user => @user, :action => 'api') 375 user.admin = true
376 end
377 @token = Token.create!(:user => @user, :action => 'api')
352 # Simple url parse to add on ?key= or &key= 378 # Simple url parse to add on ?key= or &key=
353 request_url = if url.match(/\?/) 379 request_url = if url.match(/\?/)
354 url + "&key=#{@token.value}" 380 url + "&key=#{@token.value}"
355 else 381 else
356 url + "?key=#{@token.value}" 382 url + "?key=#{@token.value}"
357 end 383 end
358 send(http_method, request_url, parameters) 384 send(http_method, request_url, parameters)
359 end 385 end
360
361 should_respond_with success_code 386 should_respond_with success_code
362 should_respond_with_content_type_based_on_url(url) 387 should_respond_with_content_type_based_on_url(url)
363 should_be_a_valid_response_string_based_on_url(url) 388 should_be_a_valid_response_string_based_on_url(url)
364 should "login as the user" do 389 should "login as the user" do
365 assert_equal @user, User.current 390 assert_equal @user, User.current
366 end 391 end
367 end 392 end
368 393
369 context "with an invalid api token" do 394 context "with an invalid api token" do
370 setup do 395 setup do
371 @user = User.generate_with_protected! 396 @user = User.generate! do |user|
372 @token = Token.generate!(:user => @user, :action => 'feeds') 397 user.admin = true
398 end
399 @token = Token.create!(:user => @user, :action => 'feeds')
373 # Simple url parse to add on ?key= or &key= 400 # Simple url parse to add on ?key= or &key=
374 request_url = if url.match(/\?/) 401 request_url = if url.match(/\?/)
375 url + "&key=#{@token.value}" 402 url + "&key=#{@token.value}"
376 else 403 else
377 url + "?key=#{@token.value}" 404 url + "?key=#{@token.value}"
378 end 405 end
379 send(http_method, request_url, parameters) 406 send(http_method, request_url, parameters)
380 end 407 end
381
382 should_respond_with failure_code 408 should_respond_with failure_code
383 should_respond_with_content_type_based_on_url(url) 409 should_respond_with_content_type_based_on_url(url)
384 should "not login as the user" do 410 should "not login as the user" do
385 assert_equal User.anonymous, User.current 411 assert_equal User.anonymous, User.current
386 end 412 end
387 end 413 end
388 end 414 end
389 415
390 context "should allow key based auth using X-Redmine-API-Key header for #{http_method} #{url}" do 416 context "should allow key based auth using X-Redmine-API-Key header for #{http_method} #{url}" do
391 setup do 417 setup do
392 @user = User.generate_with_protected!(:admin => true) 418 @user = User.generate! do |user|
393 @token = Token.generate!(:user => @user, :action => 'api') 419 user.admin = true
420 end
421 @token = Token.create!(:user => @user, :action => 'api')
394 send(http_method, url, parameters, {'X-Redmine-API-Key' => @token.value.to_s}) 422 send(http_method, url, parameters, {'X-Redmine-API-Key' => @token.value.to_s})
395 end 423 end
396
397 should_respond_with success_code 424 should_respond_with success_code
398 should_respond_with_content_type_based_on_url(url) 425 should_respond_with_content_type_based_on_url(url)
399 should_be_a_valid_response_string_based_on_url(url) 426 should_be_a_valid_response_string_based_on_url(url)
400 should "login as the user" do 427 should "login as the user" do
401 assert_equal @user, User.current 428 assert_equal @user, User.current
410 # 437 #
411 # @param [String] url Request 438 # @param [String] url Request
412 def self.should_respond_with_content_type_based_on_url(url) 439 def self.should_respond_with_content_type_based_on_url(url)
413 case 440 case
414 when url.match(/xml/i) 441 when url.match(/xml/i)
415 should_respond_with_content_type :xml 442 should "respond with XML" do
443 assert_equal 'application/xml', @response.content_type
444 end
416 when url.match(/json/i) 445 when url.match(/json/i)
417 should_respond_with_content_type :json 446 should "respond with JSON" do
447 assert_equal 'application/json', @response.content_type
448 end
418 else 449 else
419 raise "Unknown content type for should_respond_with_content_type_based_on_url: #{url}" 450 raise "Unknown content type for should_respond_with_content_type_based_on_url: #{url}"
420 end 451 end
421
422 end 452 end
423 453
424 # Uses the url to assert which format the response should be in 454 # Uses the url to assert which format the response should be in
425 # 455 #
426 # '/project/issues.xml' => should_be_a_valid_xml_string 456 # '/project/issues.xml' => should_be_a_valid_xml_string
434 when url.match(/json/i) 464 when url.match(/json/i)
435 should_be_a_valid_json_string 465 should_be_a_valid_json_string
436 else 466 else
437 raise "Unknown content type for should_be_a_valid_response_based_on_url: #{url}" 467 raise "Unknown content type for should_be_a_valid_response_based_on_url: #{url}"
438 end 468 end
439
440 end 469 end
441 470
442 # Checks that the response is a valid JSON string 471 # Checks that the response is a valid JSON string
443 def self.should_be_a_valid_json_string 472 def self.should_be_a_valid_json_string
444 should "be a valid JSON string (or empty)" do 473 should "be a valid JSON string (or empty)" do
451 should "be a valid XML string" do 480 should "be a valid XML string" do
452 assert REXML::Document.new(response.body) 481 assert REXML::Document.new(response.body)
453 end 482 end
454 end 483 end
455 484
485 def self.should_respond_with(status)
486 should "respond with #{status}" do
487 assert_response status
488 end
489 end
456 end 490 end
457 491
458 # Simple module to "namespace" all of the API tests 492 # Simple module to "namespace" all of the API tests
459 module ApiTest 493 module ApiTest
460 end 494 end