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