annotate .svn/pristine/67/67c0428911abf350e9f2025e9810f70bf182d6ea.svn-base @ 1524:82fac3dcf466 redmine-2.5-integration

Fix failure to interpret Javascript when autocompleting members for project
author Chris Cannam <chris.cannam@soundsoftware.ac.uk>
date Thu, 11 Sep 2014 10:24:38 +0100
parents e248c7af89ec
children
rev   line source
Chris@1494 1 # Redmine - project management software
Chris@1494 2 # Copyright (C) 2006-2014 Jean-Philippe Lang
Chris@1494 3 #
Chris@1494 4 # This program is free software; you can redistribute it and/or
Chris@1494 5 # modify it under the terms of the GNU General Public License
Chris@1494 6 # as published by the Free Software Foundation; either version 2
Chris@1494 7 # of the License, or (at your option) any later version.
Chris@1494 8 #
Chris@1494 9 # This program is distributed in the hope that it will be useful,
Chris@1494 10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
Chris@1494 11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
Chris@1494 12 # GNU General Public License for more details.
Chris@1494 13 #
Chris@1494 14 # You should have received a copy of the GNU General Public License
Chris@1494 15 # along with this program; if not, write to the Free Software
Chris@1494 16 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
Chris@1494 17
Chris@1494 18 #require 'shoulda'
Chris@1494 19 ENV["RAILS_ENV"] = "test"
Chris@1494 20 require File.expand_path(File.dirname(__FILE__) + "/../config/environment")
Chris@1494 21 require 'rails/test_help'
Chris@1494 22 require Rails.root.join('test', 'mocks', 'open_id_authentication_mock.rb').to_s
Chris@1494 23
Chris@1494 24 require File.expand_path(File.dirname(__FILE__) + '/object_helpers')
Chris@1494 25 include ObjectHelpers
Chris@1494 26
Chris@1494 27 class ActiveSupport::TestCase
Chris@1494 28 include ActionDispatch::TestProcess
Chris@1494 29
Chris@1494 30 self.use_transactional_fixtures = true
Chris@1494 31 self.use_instantiated_fixtures = false
Chris@1494 32
Chris@1494 33 def log_user(login, password)
Chris@1494 34 User.anonymous
Chris@1494 35 get "/login"
Chris@1494 36 assert_equal nil, session[:user_id]
Chris@1494 37 assert_response :success
Chris@1494 38 assert_template "account/login"
Chris@1494 39 post "/login", :username => login, :password => password
Chris@1494 40 assert_equal login, User.find(session[:user_id]).login
Chris@1494 41 end
Chris@1494 42
Chris@1494 43 def uploaded_test_file(name, mime)
Chris@1494 44 fixture_file_upload("files/#{name}", mime, true)
Chris@1494 45 end
Chris@1494 46
Chris@1494 47 def credentials(user, password=nil)
Chris@1494 48 {'HTTP_AUTHORIZATION' => ActionController::HttpAuthentication::Basic.encode_credentials(user, password || user)}
Chris@1494 49 end
Chris@1494 50
Chris@1494 51 # Mock out a file
Chris@1494 52 def self.mock_file
Chris@1494 53 file = 'a_file.png'
Chris@1494 54 file.stubs(:size).returns(32)
Chris@1494 55 file.stubs(:original_filename).returns('a_file.png')
Chris@1494 56 file.stubs(:content_type).returns('image/png')
Chris@1494 57 file.stubs(:read).returns(false)
Chris@1494 58 file
Chris@1494 59 end
Chris@1494 60
Chris@1494 61 def mock_file
Chris@1494 62 self.class.mock_file
Chris@1494 63 end
Chris@1494 64
Chris@1494 65 def mock_file_with_options(options={})
Chris@1494 66 file = ''
Chris@1494 67 file.stubs(:size).returns(32)
Chris@1494 68 original_filename = options[:original_filename] || nil
Chris@1494 69 file.stubs(:original_filename).returns(original_filename)
Chris@1494 70 content_type = options[:content_type] || nil
Chris@1494 71 file.stubs(:content_type).returns(content_type)
Chris@1494 72 file.stubs(:read).returns(false)
Chris@1494 73 file
Chris@1494 74 end
Chris@1494 75
Chris@1494 76 # Use a temporary directory for attachment related tests
Chris@1494 77 def set_tmp_attachments_directory
Chris@1494 78 Dir.mkdir "#{Rails.root}/tmp/test" unless File.directory?("#{Rails.root}/tmp/test")
Chris@1494 79 unless File.directory?("#{Rails.root}/tmp/test/attachments")
Chris@1494 80 Dir.mkdir "#{Rails.root}/tmp/test/attachments"
Chris@1494 81 end
Chris@1494 82 Attachment.storage_path = "#{Rails.root}/tmp/test/attachments"
Chris@1494 83 end
Chris@1494 84
Chris@1494 85 def set_fixtures_attachments_directory
Chris@1494 86 Attachment.storage_path = "#{Rails.root}/test/fixtures/files"
Chris@1494 87 end
Chris@1494 88
Chris@1494 89 def with_settings(options, &block)
Chris@1494 90 saved_settings = options.keys.inject({}) do |h, k|
Chris@1494 91 h[k] = case Setting[k]
Chris@1494 92 when Symbol, false, true, nil
Chris@1494 93 Setting[k]
Chris@1494 94 else
Chris@1494 95 Setting[k].dup
Chris@1494 96 end
Chris@1494 97 h
Chris@1494 98 end
Chris@1494 99 options.each {|k, v| Setting[k] = v}
Chris@1494 100 yield
Chris@1494 101 ensure
Chris@1494 102 saved_settings.each {|k, v| Setting[k] = v} if saved_settings
Chris@1494 103 end
Chris@1494 104
Chris@1494 105 # Yields the block with user as the current user
Chris@1494 106 def with_current_user(user, &block)
Chris@1494 107 saved_user = User.current
Chris@1494 108 User.current = user
Chris@1494 109 yield
Chris@1494 110 ensure
Chris@1494 111 User.current = saved_user
Chris@1494 112 end
Chris@1494 113
Chris@1494 114 def with_locale(locale, &block)
Chris@1494 115 saved_localed = ::I18n.locale
Chris@1494 116 ::I18n.locale = locale
Chris@1494 117 yield
Chris@1494 118 ensure
Chris@1494 119 ::I18n.locale = saved_localed
Chris@1494 120 end
Chris@1494 121
Chris@1494 122 def change_user_password(login, new_password)
Chris@1494 123 user = User.where(:login => login).first
Chris@1494 124 user.password, user.password_confirmation = new_password, new_password
Chris@1494 125 user.save!
Chris@1494 126 end
Chris@1494 127
Chris@1494 128 def self.ldap_configured?
Chris@1494 129 @test_ldap = Net::LDAP.new(:host => '127.0.0.1', :port => 389)
Chris@1494 130 return @test_ldap.bind
Chris@1494 131 rescue Exception => e
Chris@1494 132 # LDAP is not listening
Chris@1494 133 return nil
Chris@1494 134 end
Chris@1494 135
Chris@1494 136 def self.convert_installed?
Chris@1494 137 Redmine::Thumbnail.convert_available?
Chris@1494 138 end
Chris@1494 139
Chris@1494 140 # Returns the path to the test +vendor+ repository
Chris@1494 141 def self.repository_path(vendor)
Chris@1494 142 Rails.root.join("tmp/test/#{vendor.downcase}_repository").to_s
Chris@1494 143 end
Chris@1494 144
Chris@1494 145 # Returns the url of the subversion test repository
Chris@1494 146 def self.subversion_repository_url
Chris@1494 147 path = repository_path('subversion')
Chris@1494 148 path = '/' + path unless path.starts_with?('/')
Chris@1494 149 "file://#{path}"
Chris@1494 150 end
Chris@1494 151
Chris@1494 152 # Returns true if the +vendor+ test repository is configured
Chris@1494 153 def self.repository_configured?(vendor)
Chris@1494 154 File.directory?(repository_path(vendor))
Chris@1494 155 end
Chris@1494 156
Chris@1494 157 def repository_path_hash(arr)
Chris@1494 158 hs = {}
Chris@1494 159 hs[:path] = arr.join("/")
Chris@1494 160 hs[:param] = arr.join("/")
Chris@1494 161 hs
Chris@1494 162 end
Chris@1494 163
Chris@1494 164 def assert_save(object)
Chris@1494 165 saved = object.save
Chris@1494 166 message = "#{object.class} could not be saved"
Chris@1494 167 errors = object.errors.full_messages.map {|m| "- #{m}"}
Chris@1494 168 message << ":\n#{errors.join("\n")}" if errors.any?
Chris@1494 169 assert_equal true, saved, message
Chris@1494 170 end
Chris@1494 171
Chris@1494 172 def assert_error_tag(options={})
Chris@1494 173 assert_tag({:attributes => { :id => 'errorExplanation' }}.merge(options))
Chris@1494 174 end
Chris@1494 175
Chris@1494 176 def assert_include(expected, s, message=nil)
Chris@1494 177 assert s.include?(expected), (message || "\"#{expected}\" not found in \"#{s}\"")
Chris@1494 178 end
Chris@1494 179
Chris@1494 180 def assert_not_include(expected, s, message=nil)
Chris@1494 181 assert !s.include?(expected), (message || "\"#{expected}\" found in \"#{s}\"")
Chris@1494 182 end
Chris@1494 183
Chris@1494 184 def assert_select_in(text, *args, &block)
Chris@1494 185 d = HTML::Document.new(CGI::unescapeHTML(String.new(text))).root
Chris@1494 186 assert_select(d, *args, &block)
Chris@1494 187 end
Chris@1494 188
Chris@1494 189 def assert_mail_body_match(expected, mail, message=nil)
Chris@1494 190 if expected.is_a?(String)
Chris@1494 191 assert_include expected, mail_body(mail), message
Chris@1494 192 else
Chris@1494 193 assert_match expected, mail_body(mail), message
Chris@1494 194 end
Chris@1494 195 end
Chris@1494 196
Chris@1494 197 def assert_mail_body_no_match(expected, mail, message=nil)
Chris@1494 198 if expected.is_a?(String)
Chris@1494 199 assert_not_include expected, mail_body(mail), message
Chris@1494 200 else
Chris@1494 201 assert_no_match expected, mail_body(mail), message
Chris@1494 202 end
Chris@1494 203 end
Chris@1494 204
Chris@1494 205 def mail_body(mail)
Chris@1494 206 mail.parts.first.body.encoded
Chris@1494 207 end
Chris@1494 208 end
Chris@1494 209
Chris@1494 210 module Redmine
Chris@1494 211 module ApiTest
Chris@1494 212 # Base class for API tests
Chris@1494 213 class Base < ActionDispatch::IntegrationTest
Chris@1494 214 # Test that a request allows the three types of API authentication
Chris@1494 215 #
Chris@1494 216 # * HTTP Basic with username and password
Chris@1494 217 # * HTTP Basic with an api key for the username
Chris@1494 218 # * Key based with the key=X parameter
Chris@1494 219 #
Chris@1494 220 # @param [Symbol] http_method the HTTP method for request (:get, :post, :put, :delete)
Chris@1494 221 # @param [String] url the request url
Chris@1494 222 # @param [optional, Hash] parameters additional request parameters
Chris@1494 223 # @param [optional, Hash] options additional options
Chris@1494 224 # @option options [Symbol] :success_code Successful response code (:success)
Chris@1494 225 # @option options [Symbol] :failure_code Failure response code (:unauthorized)
Chris@1494 226 def self.should_allow_api_authentication(http_method, url, parameters={}, options={})
Chris@1494 227 should_allow_http_basic_auth_with_username_and_password(http_method, url, parameters, options)
Chris@1494 228 should_allow_http_basic_auth_with_key(http_method, url, parameters, options)
Chris@1494 229 should_allow_key_based_auth(http_method, url, parameters, options)
Chris@1494 230 end
Chris@1494 231
Chris@1494 232 # Test that a request allows the username and password for HTTP BASIC
Chris@1494 233 #
Chris@1494 234 # @param [Symbol] http_method the HTTP method for request (:get, :post, :put, :delete)
Chris@1494 235 # @param [String] url the request url
Chris@1494 236 # @param [optional, Hash] parameters additional request parameters
Chris@1494 237 # @param [optional, Hash] options additional options
Chris@1494 238 # @option options [Symbol] :success_code Successful response code (:success)
Chris@1494 239 # @option options [Symbol] :failure_code Failure response code (:unauthorized)
Chris@1494 240 def self.should_allow_http_basic_auth_with_username_and_password(http_method, url, parameters={}, options={})
Chris@1494 241 success_code = options[:success_code] || :success
Chris@1494 242 failure_code = options[:failure_code] || :unauthorized
Chris@1494 243
Chris@1494 244 context "should allow http basic auth using a username and password for #{http_method} #{url}" do
Chris@1494 245 context "with a valid HTTP authentication" do
Chris@1494 246 setup do
Chris@1494 247 @user = User.generate! do |user|
Chris@1494 248 user.admin = true
Chris@1494 249 user.password = 'my_password'
Chris@1494 250 end
Chris@1494 251 send(http_method, url, parameters, credentials(@user.login, 'my_password'))
Chris@1494 252 end
Chris@1494 253
Chris@1494 254 should_respond_with success_code
Chris@1494 255 should_respond_with_content_type_based_on_url(url)
Chris@1494 256 should "login as the user" do
Chris@1494 257 assert_equal @user, User.current
Chris@1494 258 end
Chris@1494 259 end
Chris@1494 260
Chris@1494 261 context "with an invalid HTTP authentication" do
Chris@1494 262 setup do
Chris@1494 263 @user = User.generate!
Chris@1494 264 send(http_method, url, parameters, credentials(@user.login, 'wrong_password'))
Chris@1494 265 end
Chris@1494 266
Chris@1494 267 should_respond_with failure_code
Chris@1494 268 should_respond_with_content_type_based_on_url(url)
Chris@1494 269 should "not login as the user" do
Chris@1494 270 assert_equal User.anonymous, User.current
Chris@1494 271 end
Chris@1494 272 end
Chris@1494 273
Chris@1494 274 context "without credentials" do
Chris@1494 275 setup do
Chris@1494 276 send(http_method, url, parameters)
Chris@1494 277 end
Chris@1494 278
Chris@1494 279 should_respond_with failure_code
Chris@1494 280 should_respond_with_content_type_based_on_url(url)
Chris@1494 281 should "include_www_authenticate_header" do
Chris@1494 282 assert @controller.response.headers.has_key?('WWW-Authenticate')
Chris@1494 283 end
Chris@1494 284 end
Chris@1494 285 end
Chris@1494 286 end
Chris@1494 287
Chris@1494 288 # Test that a request allows the API key with HTTP BASIC
Chris@1494 289 #
Chris@1494 290 # @param [Symbol] http_method the HTTP method for request (:get, :post, :put, :delete)
Chris@1494 291 # @param [String] url the request url
Chris@1494 292 # @param [optional, Hash] parameters additional request parameters
Chris@1494 293 # @param [optional, Hash] options additional options
Chris@1494 294 # @option options [Symbol] :success_code Successful response code (:success)
Chris@1494 295 # @option options [Symbol] :failure_code Failure response code (:unauthorized)
Chris@1494 296 def self.should_allow_http_basic_auth_with_key(http_method, url, parameters={}, options={})
Chris@1494 297 success_code = options[:success_code] || :success
Chris@1494 298 failure_code = options[:failure_code] || :unauthorized
Chris@1494 299
Chris@1494 300 context "should allow http basic auth with a key for #{http_method} #{url}" do
Chris@1494 301 context "with a valid HTTP authentication using the API token" do
Chris@1494 302 setup do
Chris@1494 303 @user = User.generate! do |user|
Chris@1494 304 user.admin = true
Chris@1494 305 end
Chris@1494 306 @token = Token.create!(:user => @user, :action => 'api')
Chris@1494 307 send(http_method, url, parameters, credentials(@token.value, 'X'))
Chris@1494 308 end
Chris@1494 309 should_respond_with success_code
Chris@1494 310 should_respond_with_content_type_based_on_url(url)
Chris@1494 311 should_be_a_valid_response_string_based_on_url(url)
Chris@1494 312 should "login as the user" do
Chris@1494 313 assert_equal @user, User.current
Chris@1494 314 end
Chris@1494 315 end
Chris@1494 316
Chris@1494 317 context "with an invalid HTTP authentication" do
Chris@1494 318 setup do
Chris@1494 319 @user = User.generate!
Chris@1494 320 @token = Token.create!(:user => @user, :action => 'feeds')
Chris@1494 321 send(http_method, url, parameters, credentials(@token.value, 'X'))
Chris@1494 322 end
Chris@1494 323 should_respond_with failure_code
Chris@1494 324 should_respond_with_content_type_based_on_url(url)
Chris@1494 325 should "not login as the user" do
Chris@1494 326 assert_equal User.anonymous, User.current
Chris@1494 327 end
Chris@1494 328 end
Chris@1494 329 end
Chris@1494 330 end
Chris@1494 331
Chris@1494 332 # Test that a request allows full key authentication
Chris@1494 333 #
Chris@1494 334 # @param [Symbol] http_method the HTTP method for request (:get, :post, :put, :delete)
Chris@1494 335 # @param [String] url the request url, without the key=ZXY parameter
Chris@1494 336 # @param [optional, Hash] parameters additional request parameters
Chris@1494 337 # @param [optional, Hash] options additional options
Chris@1494 338 # @option options [Symbol] :success_code Successful response code (:success)
Chris@1494 339 # @option options [Symbol] :failure_code Failure response code (:unauthorized)
Chris@1494 340 def self.should_allow_key_based_auth(http_method, url, parameters={}, options={})
Chris@1494 341 success_code = options[:success_code] || :success
Chris@1494 342 failure_code = options[:failure_code] || :unauthorized
Chris@1494 343
Chris@1494 344 context "should allow key based auth using key=X for #{http_method} #{url}" do
Chris@1494 345 context "with a valid api token" do
Chris@1494 346 setup do
Chris@1494 347 @user = User.generate! do |user|
Chris@1494 348 user.admin = true
Chris@1494 349 end
Chris@1494 350 @token = Token.create!(:user => @user, :action => 'api')
Chris@1494 351 # Simple url parse to add on ?key= or &key=
Chris@1494 352 request_url = if url.match(/\?/)
Chris@1494 353 url + "&key=#{@token.value}"
Chris@1494 354 else
Chris@1494 355 url + "?key=#{@token.value}"
Chris@1494 356 end
Chris@1494 357 send(http_method, request_url, parameters)
Chris@1494 358 end
Chris@1494 359 should_respond_with success_code
Chris@1494 360 should_respond_with_content_type_based_on_url(url)
Chris@1494 361 should_be_a_valid_response_string_based_on_url(url)
Chris@1494 362 should "login as the user" do
Chris@1494 363 assert_equal @user, User.current
Chris@1494 364 end
Chris@1494 365 end
Chris@1494 366
Chris@1494 367 context "with an invalid api token" do
Chris@1494 368 setup do
Chris@1494 369 @user = User.generate! do |user|
Chris@1494 370 user.admin = true
Chris@1494 371 end
Chris@1494 372 @token = Token.create!(:user => @user, :action => 'feeds')
Chris@1494 373 # Simple url parse to add on ?key= or &key=
Chris@1494 374 request_url = if url.match(/\?/)
Chris@1494 375 url + "&key=#{@token.value}"
Chris@1494 376 else
Chris@1494 377 url + "?key=#{@token.value}"
Chris@1494 378 end
Chris@1494 379 send(http_method, request_url, parameters)
Chris@1494 380 end
Chris@1494 381 should_respond_with failure_code
Chris@1494 382 should_respond_with_content_type_based_on_url(url)
Chris@1494 383 should "not login as the user" do
Chris@1494 384 assert_equal User.anonymous, User.current
Chris@1494 385 end
Chris@1494 386 end
Chris@1494 387 end
Chris@1494 388
Chris@1494 389 context "should allow key based auth using X-Redmine-API-Key header for #{http_method} #{url}" do
Chris@1494 390 setup do
Chris@1494 391 @user = User.generate! do |user|
Chris@1494 392 user.admin = true
Chris@1494 393 end
Chris@1494 394 @token = Token.create!(:user => @user, :action => 'api')
Chris@1494 395 send(http_method, url, parameters, {'X-Redmine-API-Key' => @token.value.to_s})
Chris@1494 396 end
Chris@1494 397 should_respond_with success_code
Chris@1494 398 should_respond_with_content_type_based_on_url(url)
Chris@1494 399 should_be_a_valid_response_string_based_on_url(url)
Chris@1494 400 should "login as the user" do
Chris@1494 401 assert_equal @user, User.current
Chris@1494 402 end
Chris@1494 403 end
Chris@1494 404 end
Chris@1494 405
Chris@1494 406 # Uses should_respond_with_content_type based on what's in the url:
Chris@1494 407 #
Chris@1494 408 # '/project/issues.xml' => should_respond_with_content_type :xml
Chris@1494 409 # '/project/issues.json' => should_respond_with_content_type :json
Chris@1494 410 #
Chris@1494 411 # @param [String] url Request
Chris@1494 412 def self.should_respond_with_content_type_based_on_url(url)
Chris@1494 413 case
Chris@1494 414 when url.match(/xml/i)
Chris@1494 415 should "respond with XML" do
Chris@1494 416 assert_equal 'application/xml', @response.content_type
Chris@1494 417 end
Chris@1494 418 when url.match(/json/i)
Chris@1494 419 should "respond with JSON" do
Chris@1494 420 assert_equal 'application/json', @response.content_type
Chris@1494 421 end
Chris@1494 422 else
Chris@1494 423 raise "Unknown content type for should_respond_with_content_type_based_on_url: #{url}"
Chris@1494 424 end
Chris@1494 425 end
Chris@1494 426
Chris@1494 427 # Uses the url to assert which format the response should be in
Chris@1494 428 #
Chris@1494 429 # '/project/issues.xml' => should_be_a_valid_xml_string
Chris@1494 430 # '/project/issues.json' => should_be_a_valid_json_string
Chris@1494 431 #
Chris@1494 432 # @param [String] url Request
Chris@1494 433 def self.should_be_a_valid_response_string_based_on_url(url)
Chris@1494 434 case
Chris@1494 435 when url.match(/xml/i)
Chris@1494 436 should_be_a_valid_xml_string
Chris@1494 437 when url.match(/json/i)
Chris@1494 438 should_be_a_valid_json_string
Chris@1494 439 else
Chris@1494 440 raise "Unknown content type for should_be_a_valid_response_based_on_url: #{url}"
Chris@1494 441 end
Chris@1494 442 end
Chris@1494 443
Chris@1494 444 # Checks that the response is a valid JSON string
Chris@1494 445 def self.should_be_a_valid_json_string
Chris@1494 446 should "be a valid JSON string (or empty)" do
Chris@1494 447 assert(response.body.blank? || ActiveSupport::JSON.decode(response.body))
Chris@1494 448 end
Chris@1494 449 end
Chris@1494 450
Chris@1494 451 # Checks that the response is a valid XML string
Chris@1494 452 def self.should_be_a_valid_xml_string
Chris@1494 453 should "be a valid XML string" do
Chris@1494 454 assert REXML::Document.new(response.body)
Chris@1494 455 end
Chris@1494 456 end
Chris@1494 457
Chris@1494 458 def self.should_respond_with(status)
Chris@1494 459 should "respond with #{status}" do
Chris@1494 460 assert_response status
Chris@1494 461 end
Chris@1494 462 end
Chris@1494 463 end
Chris@1494 464 end
Chris@1494 465 end
Chris@1494 466
Chris@1494 467 # URL helpers do not work with config.threadsafe!
Chris@1494 468 # https://github.com/rspec/rspec-rails/issues/476#issuecomment-4705454
Chris@1494 469 ActionView::TestCase::TestController.instance_eval do
Chris@1494 470 helper Rails.application.routes.url_helpers
Chris@1494 471 end
Chris@1494 472 ActionView::TestCase::TestController.class_eval do
Chris@1494 473 def _routes
Chris@1494 474 Rails.application.routes
Chris@1494 475 end
Chris@1494 476 end