##// END OF EJS Templates
Restore settings even if a test failure occurs....
Jean-Philippe Lang -
r5107:3ef5daaf3518
parent child
Show More
@@ -1,441 +1,442
1 # Redmine - project management software
1 # Redmine - project management software
2 # Copyright (C) 2006-2011 Jean-Philippe Lang
2 # Copyright (C) 2006-2011 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 ENV["RAILS_ENV"] = "test"
18 ENV["RAILS_ENV"] = "test"
19 require File.expand_path(File.dirname(__FILE__) + "/../config/environment")
19 require File.expand_path(File.dirname(__FILE__) + "/../config/environment")
20 require 'test_help'
20 require 'test_help'
21 require File.expand_path(File.dirname(__FILE__) + '/helper_testcase')
21 require File.expand_path(File.dirname(__FILE__) + '/helper_testcase')
22 require File.join(RAILS_ROOT,'test', 'mocks', 'open_id_authentication_mock.rb')
22 require File.join(RAILS_ROOT,'test', 'mocks', 'open_id_authentication_mock.rb')
23
23
24 require File.expand_path(File.dirname(__FILE__) + '/object_daddy_helpers')
24 require File.expand_path(File.dirname(__FILE__) + '/object_daddy_helpers')
25 include ObjectDaddyHelpers
25 include ObjectDaddyHelpers
26
26
27 class ActiveSupport::TestCase
27 class ActiveSupport::TestCase
28 # Transactional fixtures accelerate your tests by wrapping each test method
28 # Transactional fixtures accelerate your tests by wrapping each test method
29 # in a transaction that's rolled back on completion. This ensures that the
29 # 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
30 # test database remains unchanged so your fixtures don't have to be reloaded
31 # between every test method. Fewer database queries means faster tests.
31 # between every test method. Fewer database queries means faster tests.
32 #
32 #
33 # Read Mike Clark's excellent walkthrough at
33 # Read Mike Clark's excellent walkthrough at
34 # http://clarkware.com/cgi/blosxom/2005/10/24#Rails10FastTesting
34 # http://clarkware.com/cgi/blosxom/2005/10/24#Rails10FastTesting
35 #
35 #
36 # Every Active Record database supports transactions except MyISAM tables
36 # Every Active Record database supports transactions except MyISAM tables
37 # in MySQL. Turn off transactional fixtures in this case; however, if you
37 # in MySQL. Turn off transactional fixtures in this case; however, if you
38 # don't care one way or the other, switching from MyISAM to InnoDB tables
38 # don't care one way or the other, switching from MyISAM to InnoDB tables
39 # is recommended.
39 # is recommended.
40 self.use_transactional_fixtures = true
40 self.use_transactional_fixtures = true
41
41
42 # Instantiated fixtures are slow, but give you @david where otherwise you
42 # Instantiated fixtures are slow, but give you @david where otherwise you
43 # would need people(:david). If you don't want to migrate your existing
43 # would need people(:david). If you don't want to migrate your existing
44 # test cases which use the @david style and don't mind the speed hit (each
44 # test cases which use the @david style and don't mind the speed hit (each
45 # instantiated fixtures translates to a database query per test method),
45 # instantiated fixtures translates to a database query per test method),
46 # then set this back to true.
46 # then set this back to true.
47 self.use_instantiated_fixtures = false
47 self.use_instantiated_fixtures = false
48
48
49 # Add more helper methods to be used by all tests here...
49 # Add more helper methods to be used by all tests here...
50
50
51 def log_user(login, password)
51 def log_user(login, password)
52 User.anonymous
52 User.anonymous
53 get "/login"
53 get "/login"
54 assert_equal nil, session[:user_id]
54 assert_equal nil, session[:user_id]
55 assert_response :success
55 assert_response :success
56 assert_template "account/login"
56 assert_template "account/login"
57 post "/login", :username => login, :password => password
57 post "/login", :username => login, :password => password
58 assert_equal login, User.find(session[:user_id]).login
58 assert_equal login, User.find(session[:user_id]).login
59 end
59 end
60
60
61 def uploaded_test_file(name, mime)
61 def uploaded_test_file(name, mime)
62 ActionController::TestUploadedFile.new(ActiveSupport::TestCase.fixture_path + "/files/#{name}", mime, true)
62 ActionController::TestUploadedFile.new(ActiveSupport::TestCase.fixture_path + "/files/#{name}", mime, true)
63 end
63 end
64
64
65 # Mock out a file
65 # Mock out a file
66 def self.mock_file
66 def self.mock_file
67 file = 'a_file.png'
67 file = 'a_file.png'
68 file.stubs(:size).returns(32)
68 file.stubs(:size).returns(32)
69 file.stubs(:original_filename).returns('a_file.png')
69 file.stubs(:original_filename).returns('a_file.png')
70 file.stubs(:content_type).returns('image/png')
70 file.stubs(:content_type).returns('image/png')
71 file.stubs(:read).returns(false)
71 file.stubs(:read).returns(false)
72 file
72 file
73 end
73 end
74
74
75 def mock_file
75 def mock_file
76 self.class.mock_file
76 self.class.mock_file
77 end
77 end
78
78
79 # Use a temporary directory for attachment related tests
79 # Use a temporary directory for attachment related tests
80 def set_tmp_attachments_directory
80 def set_tmp_attachments_directory
81 Dir.mkdir "#{RAILS_ROOT}/tmp/test" unless File.directory?("#{RAILS_ROOT}/tmp/test")
81 Dir.mkdir "#{RAILS_ROOT}/tmp/test" unless File.directory?("#{RAILS_ROOT}/tmp/test")
82 Dir.mkdir "#{RAILS_ROOT}/tmp/test/attachments" unless File.directory?("#{RAILS_ROOT}/tmp/test/attachments")
82 Dir.mkdir "#{RAILS_ROOT}/tmp/test/attachments" unless File.directory?("#{RAILS_ROOT}/tmp/test/attachments")
83 Attachment.storage_path = "#{RAILS_ROOT}/tmp/test/attachments"
83 Attachment.storage_path = "#{RAILS_ROOT}/tmp/test/attachments"
84 end
84 end
85
85
86 def with_settings(options, &block)
86 def with_settings(options, &block)
87 saved_settings = options.keys.inject({}) {|h, k| h[k] = Setting[k].dup; h}
87 saved_settings = options.keys.inject({}) {|h, k| h[k] = Setting[k].dup; h}
88 options.each {|k, v| Setting[k] = v}
88 options.each {|k, v| Setting[k] = v}
89 yield
89 yield
90 ensure
90 saved_settings.each {|k, v| Setting[k] = v}
91 saved_settings.each {|k, v| Setting[k] = v}
91 end
92 end
92
93
93 def change_user_password(login, new_password)
94 def change_user_password(login, new_password)
94 user = User.first(:conditions => {:login => login})
95 user = User.first(:conditions => {:login => login})
95 user.password, user.password_confirmation = new_password, new_password
96 user.password, user.password_confirmation = new_password, new_password
96 user.save!
97 user.save!
97 end
98 end
98
99
99 def self.ldap_configured?
100 def self.ldap_configured?
100 @test_ldap = Net::LDAP.new(:host => '127.0.0.1', :port => 389)
101 @test_ldap = Net::LDAP.new(:host => '127.0.0.1', :port => 389)
101 return @test_ldap.bind
102 return @test_ldap.bind
102 rescue Exception => e
103 rescue Exception => e
103 # LDAP is not listening
104 # LDAP is not listening
104 return nil
105 return nil
105 end
106 end
106
107
107 # Returns the path to the test +vendor+ repository
108 # Returns the path to the test +vendor+ repository
108 def self.repository_path(vendor)
109 def self.repository_path(vendor)
109 File.join(RAILS_ROOT.gsub(%r{config\/\.\.}, ''), "/tmp/test/#{vendor.downcase}_repository")
110 File.join(RAILS_ROOT.gsub(%r{config\/\.\.}, ''), "/tmp/test/#{vendor.downcase}_repository")
110 end
111 end
111
112
112 # Returns the url of the subversion test repository
113 # Returns the url of the subversion test repository
113 def self.subversion_repository_url
114 def self.subversion_repository_url
114 path = repository_path('subversion')
115 path = repository_path('subversion')
115 path = '/' + path unless path.starts_with?('/')
116 path = '/' + path unless path.starts_with?('/')
116 "file://#{path}"
117 "file://#{path}"
117 end
118 end
118
119
119 # Returns true if the +vendor+ test repository is configured
120 # Returns true if the +vendor+ test repository is configured
120 def self.repository_configured?(vendor)
121 def self.repository_configured?(vendor)
121 File.directory?(repository_path(vendor))
122 File.directory?(repository_path(vendor))
122 end
123 end
123
124
124 def assert_error_tag(options={})
125 def assert_error_tag(options={})
125 assert_tag({:attributes => { :id => 'errorExplanation' }}.merge(options))
126 assert_tag({:attributes => { :id => 'errorExplanation' }}.merge(options))
126 end
127 end
127
128
128 # Shoulda macros
129 # Shoulda macros
129 def self.should_render_404
130 def self.should_render_404
130 should_respond_with :not_found
131 should_respond_with :not_found
131 should_render_template 'common/error'
132 should_render_template 'common/error'
132 end
133 end
133
134
134 def self.should_have_before_filter(expected_method, options = {})
135 def self.should_have_before_filter(expected_method, options = {})
135 should_have_filter('before', expected_method, options)
136 should_have_filter('before', expected_method, options)
136 end
137 end
137
138
138 def self.should_have_after_filter(expected_method, options = {})
139 def self.should_have_after_filter(expected_method, options = {})
139 should_have_filter('after', expected_method, options)
140 should_have_filter('after', expected_method, options)
140 end
141 end
141
142
142 def self.should_have_filter(filter_type, expected_method, options)
143 def self.should_have_filter(filter_type, expected_method, options)
143 description = "have #{filter_type}_filter :#{expected_method}"
144 description = "have #{filter_type}_filter :#{expected_method}"
144 description << " with #{options.inspect}" unless options.empty?
145 description << " with #{options.inspect}" unless options.empty?
145
146
146 should description do
147 should description do
147 klass = "action_controller/filters/#{filter_type}_filter".classify.constantize
148 klass = "action_controller/filters/#{filter_type}_filter".classify.constantize
148 expected = klass.new(:filter, expected_method.to_sym, options)
149 expected = klass.new(:filter, expected_method.to_sym, options)
149 assert_equal 1, @controller.class.filter_chain.select { |filter|
150 assert_equal 1, @controller.class.filter_chain.select { |filter|
150 filter.method == expected.method && filter.kind == expected.kind &&
151 filter.method == expected.method && filter.kind == expected.kind &&
151 filter.options == expected.options && filter.class == expected.class
152 filter.options == expected.options && filter.class == expected.class
152 }.size
153 }.size
153 end
154 end
154 end
155 end
155
156
156 def self.should_show_the_old_and_new_values_for(prop_key, model, &block)
157 def self.should_show_the_old_and_new_values_for(prop_key, model, &block)
157 context "" do
158 context "" do
158 setup do
159 setup do
159 if block_given?
160 if block_given?
160 instance_eval &block
161 instance_eval &block
161 else
162 else
162 @old_value = model.generate!
163 @old_value = model.generate!
163 @new_value = model.generate!
164 @new_value = model.generate!
164 end
165 end
165 end
166 end
166
167
167 should "use the new value's name" do
168 should "use the new value's name" do
168 @detail = JournalDetail.generate!(:property => 'attr',
169 @detail = JournalDetail.generate!(:property => 'attr',
169 :old_value => @old_value.id,
170 :old_value => @old_value.id,
170 :value => @new_value.id,
171 :value => @new_value.id,
171 :prop_key => prop_key)
172 :prop_key => prop_key)
172
173
173 assert_match @new_value.name, show_detail(@detail, true)
174 assert_match @new_value.name, show_detail(@detail, true)
174 end
175 end
175
176
176 should "use the old value's name" do
177 should "use the old value's name" do
177 @detail = JournalDetail.generate!(:property => 'attr',
178 @detail = JournalDetail.generate!(:property => 'attr',
178 :old_value => @old_value.id,
179 :old_value => @old_value.id,
179 :value => @new_value.id,
180 :value => @new_value.id,
180 :prop_key => prop_key)
181 :prop_key => prop_key)
181
182
182 assert_match @old_value.name, show_detail(@detail, true)
183 assert_match @old_value.name, show_detail(@detail, true)
183 end
184 end
184 end
185 end
185 end
186 end
186
187
187 def self.should_create_a_new_user(&block)
188 def self.should_create_a_new_user(&block)
188 should "create a new user" do
189 should "create a new user" do
189 user = instance_eval &block
190 user = instance_eval &block
190 assert user
191 assert user
191 assert_kind_of User, user
192 assert_kind_of User, user
192 assert !user.new_record?
193 assert !user.new_record?
193 end
194 end
194 end
195 end
195
196
196 # Test that a request allows the three types of API authentication
197 # Test that a request allows the three types of API authentication
197 #
198 #
198 # * HTTP Basic with username and password
199 # * HTTP Basic with username and password
199 # * HTTP Basic with an api key for the username
200 # * HTTP Basic with an api key for the username
200 # * Key based with the key=X parameter
201 # * Key based with the key=X parameter
201 #
202 #
202 # @param [Symbol] http_method the HTTP method for request (:get, :post, :put, :delete)
203 # @param [Symbol] http_method the HTTP method for request (:get, :post, :put, :delete)
203 # @param [String] url the request url
204 # @param [String] url the request url
204 # @param [optional, Hash] parameters additional request parameters
205 # @param [optional, Hash] parameters additional request parameters
205 # @param [optional, Hash] options additional options
206 # @param [optional, Hash] options additional options
206 # @option options [Symbol] :success_code Successful response code (:success)
207 # @option options [Symbol] :success_code Successful response code (:success)
207 # @option options [Symbol] :failure_code Failure response code (:unauthorized)
208 # @option options [Symbol] :failure_code Failure response code (:unauthorized)
208 def self.should_allow_api_authentication(http_method, url, parameters={}, options={})
209 def self.should_allow_api_authentication(http_method, url, parameters={}, options={})
209 should_allow_http_basic_auth_with_username_and_password(http_method, url, parameters, options)
210 should_allow_http_basic_auth_with_username_and_password(http_method, url, parameters, options)
210 should_allow_http_basic_auth_with_key(http_method, url, parameters, options)
211 should_allow_http_basic_auth_with_key(http_method, url, parameters, options)
211 should_allow_key_based_auth(http_method, url, parameters, options)
212 should_allow_key_based_auth(http_method, url, parameters, options)
212 end
213 end
213
214
214 # Test that a request allows the username and password for HTTP BASIC
215 # Test that a request allows the username and password for HTTP BASIC
215 #
216 #
216 # @param [Symbol] http_method the HTTP method for request (:get, :post, :put, :delete)
217 # @param [Symbol] http_method the HTTP method for request (:get, :post, :put, :delete)
217 # @param [String] url the request url
218 # @param [String] url the request url
218 # @param [optional, Hash] parameters additional request parameters
219 # @param [optional, Hash] parameters additional request parameters
219 # @param [optional, Hash] options additional options
220 # @param [optional, Hash] options additional options
220 # @option options [Symbol] :success_code Successful response code (:success)
221 # @option options [Symbol] :success_code Successful response code (:success)
221 # @option options [Symbol] :failure_code Failure response code (:unauthorized)
222 # @option options [Symbol] :failure_code Failure response code (:unauthorized)
222 def self.should_allow_http_basic_auth_with_username_and_password(http_method, url, parameters={}, options={})
223 def self.should_allow_http_basic_auth_with_username_and_password(http_method, url, parameters={}, options={})
223 success_code = options[:success_code] || :success
224 success_code = options[:success_code] || :success
224 failure_code = options[:failure_code] || :unauthorized
225 failure_code = options[:failure_code] || :unauthorized
225
226
226 context "should allow http basic auth using a username and password for #{http_method} #{url}" do
227 context "should allow http basic auth using a username and password for #{http_method} #{url}" do
227 context "with a valid HTTP authentication" do
228 context "with a valid HTTP authentication" do
228 setup do
229 setup do
229 @user = User.generate_with_protected!(:password => 'my_password', :password_confirmation => 'my_password', :admin => true) # Admin so they can access the project
230 @user = User.generate_with_protected!(:password => 'my_password', :password_confirmation => 'my_password', :admin => true) # Admin so they can access the project
230 @authorization = ActionController::HttpAuthentication::Basic.encode_credentials(@user.login, 'my_password')
231 @authorization = ActionController::HttpAuthentication::Basic.encode_credentials(@user.login, 'my_password')
231 send(http_method, url, parameters, {:authorization => @authorization})
232 send(http_method, url, parameters, {:authorization => @authorization})
232 end
233 end
233
234
234 should_respond_with success_code
235 should_respond_with success_code
235 should_respond_with_content_type_based_on_url(url)
236 should_respond_with_content_type_based_on_url(url)
236 should "login as the user" do
237 should "login as the user" do
237 assert_equal @user, User.current
238 assert_equal @user, User.current
238 end
239 end
239 end
240 end
240
241
241 context "with an invalid HTTP authentication" do
242 context "with an invalid HTTP authentication" do
242 setup do
243 setup do
243 @user = User.generate_with_protected!
244 @user = User.generate_with_protected!
244 @authorization = ActionController::HttpAuthentication::Basic.encode_credentials(@user.login, 'wrong_password')
245 @authorization = ActionController::HttpAuthentication::Basic.encode_credentials(@user.login, 'wrong_password')
245 send(http_method, url, parameters, {:authorization => @authorization})
246 send(http_method, url, parameters, {:authorization => @authorization})
246 end
247 end
247
248
248 should_respond_with failure_code
249 should_respond_with failure_code
249 should_respond_with_content_type_based_on_url(url)
250 should_respond_with_content_type_based_on_url(url)
250 should "not login as the user" do
251 should "not login as the user" do
251 assert_equal User.anonymous, User.current
252 assert_equal User.anonymous, User.current
252 end
253 end
253 end
254 end
254
255
255 context "without credentials" do
256 context "without credentials" do
256 setup do
257 setup do
257 send(http_method, url, parameters, {:authorization => ''})
258 send(http_method, url, parameters, {:authorization => ''})
258 end
259 end
259
260
260 should_respond_with failure_code
261 should_respond_with failure_code
261 should_respond_with_content_type_based_on_url(url)
262 should_respond_with_content_type_based_on_url(url)
262 should "include_www_authenticate_header" do
263 should "include_www_authenticate_header" do
263 assert @controller.response.headers.has_key?('WWW-Authenticate')
264 assert @controller.response.headers.has_key?('WWW-Authenticate')
264 end
265 end
265 end
266 end
266 end
267 end
267
268
268 end
269 end
269
270
270 # Test that a request allows the API key with HTTP BASIC
271 # Test that a request allows the API key with HTTP BASIC
271 #
272 #
272 # @param [Symbol] http_method the HTTP method for request (:get, :post, :put, :delete)
273 # @param [Symbol] http_method the HTTP method for request (:get, :post, :put, :delete)
273 # @param [String] url the request url
274 # @param [String] url the request url
274 # @param [optional, Hash] parameters additional request parameters
275 # @param [optional, Hash] parameters additional request parameters
275 # @param [optional, Hash] options additional options
276 # @param [optional, Hash] options additional options
276 # @option options [Symbol] :success_code Successful response code (:success)
277 # @option options [Symbol] :success_code Successful response code (:success)
277 # @option options [Symbol] :failure_code Failure response code (:unauthorized)
278 # @option options [Symbol] :failure_code Failure response code (:unauthorized)
278 def self.should_allow_http_basic_auth_with_key(http_method, url, parameters={}, options={})
279 def self.should_allow_http_basic_auth_with_key(http_method, url, parameters={}, options={})
279 success_code = options[:success_code] || :success
280 success_code = options[:success_code] || :success
280 failure_code = options[:failure_code] || :unauthorized
281 failure_code = options[:failure_code] || :unauthorized
281
282
282 context "should allow http basic auth with a key for #{http_method} #{url}" do
283 context "should allow http basic auth with a key for #{http_method} #{url}" do
283 context "with a valid HTTP authentication using the API token" do
284 context "with a valid HTTP authentication using the API token" do
284 setup do
285 setup do
285 @user = User.generate_with_protected!(:admin => true)
286 @user = User.generate_with_protected!(:admin => true)
286 @token = Token.generate!(:user => @user, :action => 'api')
287 @token = Token.generate!(:user => @user, :action => 'api')
287 @authorization = ActionController::HttpAuthentication::Basic.encode_credentials(@token.value, 'X')
288 @authorization = ActionController::HttpAuthentication::Basic.encode_credentials(@token.value, 'X')
288 send(http_method, url, parameters, {:authorization => @authorization})
289 send(http_method, url, parameters, {:authorization => @authorization})
289 end
290 end
290
291
291 should_respond_with success_code
292 should_respond_with success_code
292 should_respond_with_content_type_based_on_url(url)
293 should_respond_with_content_type_based_on_url(url)
293 should_be_a_valid_response_string_based_on_url(url)
294 should_be_a_valid_response_string_based_on_url(url)
294 should "login as the user" do
295 should "login as the user" do
295 assert_equal @user, User.current
296 assert_equal @user, User.current
296 end
297 end
297 end
298 end
298
299
299 context "with an invalid HTTP authentication" do
300 context "with an invalid HTTP authentication" do
300 setup do
301 setup do
301 @user = User.generate_with_protected!
302 @user = User.generate_with_protected!
302 @token = Token.generate!(:user => @user, :action => 'feeds')
303 @token = Token.generate!(:user => @user, :action => 'feeds')
303 @authorization = ActionController::HttpAuthentication::Basic.encode_credentials(@token.value, 'X')
304 @authorization = ActionController::HttpAuthentication::Basic.encode_credentials(@token.value, 'X')
304 send(http_method, url, parameters, {:authorization => @authorization})
305 send(http_method, url, parameters, {:authorization => @authorization})
305 end
306 end
306
307
307 should_respond_with failure_code
308 should_respond_with failure_code
308 should_respond_with_content_type_based_on_url(url)
309 should_respond_with_content_type_based_on_url(url)
309 should "not login as the user" do
310 should "not login as the user" do
310 assert_equal User.anonymous, User.current
311 assert_equal User.anonymous, User.current
311 end
312 end
312 end
313 end
313 end
314 end
314 end
315 end
315
316
316 # Test that a request allows full key authentication
317 # Test that a request allows full key authentication
317 #
318 #
318 # @param [Symbol] http_method the HTTP method for request (:get, :post, :put, :delete)
319 # @param [Symbol] http_method the HTTP method for request (:get, :post, :put, :delete)
319 # @param [String] url the request url, without the key=ZXY parameter
320 # @param [String] url the request url, without the key=ZXY parameter
320 # @param [optional, Hash] parameters additional request parameters
321 # @param [optional, Hash] parameters additional request parameters
321 # @param [optional, Hash] options additional options
322 # @param [optional, Hash] options additional options
322 # @option options [Symbol] :success_code Successful response code (:success)
323 # @option options [Symbol] :success_code Successful response code (:success)
323 # @option options [Symbol] :failure_code Failure response code (:unauthorized)
324 # @option options [Symbol] :failure_code Failure response code (:unauthorized)
324 def self.should_allow_key_based_auth(http_method, url, parameters={}, options={})
325 def self.should_allow_key_based_auth(http_method, url, parameters={}, options={})
325 success_code = options[:success_code] || :success
326 success_code = options[:success_code] || :success
326 failure_code = options[:failure_code] || :unauthorized
327 failure_code = options[:failure_code] || :unauthorized
327
328
328 context "should allow key based auth using key=X for #{http_method} #{url}" do
329 context "should allow key based auth using key=X for #{http_method} #{url}" do
329 context "with a valid api token" do
330 context "with a valid api token" do
330 setup do
331 setup do
331 @user = User.generate_with_protected!(:admin => true)
332 @user = User.generate_with_protected!(:admin => true)
332 @token = Token.generate!(:user => @user, :action => 'api')
333 @token = Token.generate!(:user => @user, :action => 'api')
333 # Simple url parse to add on ?key= or &key=
334 # Simple url parse to add on ?key= or &key=
334 request_url = if url.match(/\?/)
335 request_url = if url.match(/\?/)
335 url + "&key=#{@token.value}"
336 url + "&key=#{@token.value}"
336 else
337 else
337 url + "?key=#{@token.value}"
338 url + "?key=#{@token.value}"
338 end
339 end
339 send(http_method, request_url, parameters)
340 send(http_method, request_url, parameters)
340 end
341 end
341
342
342 should_respond_with success_code
343 should_respond_with success_code
343 should_respond_with_content_type_based_on_url(url)
344 should_respond_with_content_type_based_on_url(url)
344 should_be_a_valid_response_string_based_on_url(url)
345 should_be_a_valid_response_string_based_on_url(url)
345 should "login as the user" do
346 should "login as the user" do
346 assert_equal @user, User.current
347 assert_equal @user, User.current
347 end
348 end
348 end
349 end
349
350
350 context "with an invalid api token" do
351 context "with an invalid api token" do
351 setup do
352 setup do
352 @user = User.generate_with_protected!
353 @user = User.generate_with_protected!
353 @token = Token.generate!(:user => @user, :action => 'feeds')
354 @token = Token.generate!(:user => @user, :action => 'feeds')
354 # Simple url parse to add on ?key= or &key=
355 # Simple url parse to add on ?key= or &key=
355 request_url = if url.match(/\?/)
356 request_url = if url.match(/\?/)
356 url + "&key=#{@token.value}"
357 url + "&key=#{@token.value}"
357 else
358 else
358 url + "?key=#{@token.value}"
359 url + "?key=#{@token.value}"
359 end
360 end
360 send(http_method, request_url, parameters)
361 send(http_method, request_url, parameters)
361 end
362 end
362
363
363 should_respond_with failure_code
364 should_respond_with failure_code
364 should_respond_with_content_type_based_on_url(url)
365 should_respond_with_content_type_based_on_url(url)
365 should "not login as the user" do
366 should "not login as the user" do
366 assert_equal User.anonymous, User.current
367 assert_equal User.anonymous, User.current
367 end
368 end
368 end
369 end
369 end
370 end
370
371
371 context "should allow key based auth using X-Redmine-API-Key header for #{http_method} #{url}" do
372 context "should allow key based auth using X-Redmine-API-Key header for #{http_method} #{url}" do
372 setup do
373 setup do
373 @user = User.generate_with_protected!(:admin => true)
374 @user = User.generate_with_protected!(:admin => true)
374 @token = Token.generate!(:user => @user, :action => 'api')
375 @token = Token.generate!(:user => @user, :action => 'api')
375 send(http_method, url, parameters, {'X-Redmine-API-Key' => @token.value.to_s})
376 send(http_method, url, parameters, {'X-Redmine-API-Key' => @token.value.to_s})
376 end
377 end
377
378
378 should_respond_with success_code
379 should_respond_with success_code
379 should_respond_with_content_type_based_on_url(url)
380 should_respond_with_content_type_based_on_url(url)
380 should_be_a_valid_response_string_based_on_url(url)
381 should_be_a_valid_response_string_based_on_url(url)
381 should "login as the user" do
382 should "login as the user" do
382 assert_equal @user, User.current
383 assert_equal @user, User.current
383 end
384 end
384 end
385 end
385 end
386 end
386
387
387 # Uses should_respond_with_content_type based on what's in the url:
388 # Uses should_respond_with_content_type based on what's in the url:
388 #
389 #
389 # '/project/issues.xml' => should_respond_with_content_type :xml
390 # '/project/issues.xml' => should_respond_with_content_type :xml
390 # '/project/issues.json' => should_respond_with_content_type :json
391 # '/project/issues.json' => should_respond_with_content_type :json
391 #
392 #
392 # @param [String] url Request
393 # @param [String] url Request
393 def self.should_respond_with_content_type_based_on_url(url)
394 def self.should_respond_with_content_type_based_on_url(url)
394 case
395 case
395 when url.match(/xml/i)
396 when url.match(/xml/i)
396 should_respond_with_content_type :xml
397 should_respond_with_content_type :xml
397 when url.match(/json/i)
398 when url.match(/json/i)
398 should_respond_with_content_type :json
399 should_respond_with_content_type :json
399 else
400 else
400 raise "Unknown content type for should_respond_with_content_type_based_on_url: #{url}"
401 raise "Unknown content type for should_respond_with_content_type_based_on_url: #{url}"
401 end
402 end
402
403
403 end
404 end
404
405
405 # Uses the url to assert which format the response should be in
406 # Uses the url to assert which format the response should be in
406 #
407 #
407 # '/project/issues.xml' => should_be_a_valid_xml_string
408 # '/project/issues.xml' => should_be_a_valid_xml_string
408 # '/project/issues.json' => should_be_a_valid_json_string
409 # '/project/issues.json' => should_be_a_valid_json_string
409 #
410 #
410 # @param [String] url Request
411 # @param [String] url Request
411 def self.should_be_a_valid_response_string_based_on_url(url)
412 def self.should_be_a_valid_response_string_based_on_url(url)
412 case
413 case
413 when url.match(/xml/i)
414 when url.match(/xml/i)
414 should_be_a_valid_xml_string
415 should_be_a_valid_xml_string
415 when url.match(/json/i)
416 when url.match(/json/i)
416 should_be_a_valid_json_string
417 should_be_a_valid_json_string
417 else
418 else
418 raise "Unknown content type for should_be_a_valid_response_based_on_url: #{url}"
419 raise "Unknown content type for should_be_a_valid_response_based_on_url: #{url}"
419 end
420 end
420
421
421 end
422 end
422
423
423 # Checks that the response is a valid JSON string
424 # Checks that the response is a valid JSON string
424 def self.should_be_a_valid_json_string
425 def self.should_be_a_valid_json_string
425 should "be a valid JSON string (or empty)" do
426 should "be a valid JSON string (or empty)" do
426 assert(response.body.blank? || ActiveSupport::JSON.decode(response.body))
427 assert(response.body.blank? || ActiveSupport::JSON.decode(response.body))
427 end
428 end
428 end
429 end
429
430
430 # Checks that the response is a valid XML string
431 # Checks that the response is a valid XML string
431 def self.should_be_a_valid_xml_string
432 def self.should_be_a_valid_xml_string
432 should "be a valid XML string" do
433 should "be a valid XML string" do
433 assert REXML::Document.new(response.body)
434 assert REXML::Document.new(response.body)
434 end
435 end
435 end
436 end
436
437
437 end
438 end
438
439
439 # Simple module to "namespace" all of the API tests
440 # Simple module to "namespace" all of the API tests
440 module ApiTest
441 module ApiTest
441 end
442 end
General Comments 0
You need to be logged in to leave comments. Login now