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