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