##// END OF EJS Templates
Change tests to use ruby/rails assertions....
Jean-Philippe Lang -
r8129:9b1e831fa67e
parent child
Show More
@@ -1,223 +1,215
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 require File.expand_path('../../test_helper', __FILE__)
18 require File.expand_path('../../test_helper', __FILE__)
19 require 'account_controller'
19 require 'account_controller'
20
20
21 # Re-raise errors caught by the controller.
21 # Re-raise errors caught by the controller.
22 class AccountController; def rescue_action(e) raise e end; end
22 class AccountController; def rescue_action(e) raise e end; end
23
23
24 class AccountControllerTest < ActionController::TestCase
24 class AccountControllerTest < ActionController::TestCase
25 fixtures :users, :roles
25 fixtures :users, :roles
26
26
27 def setup
27 def setup
28 @controller = AccountController.new
28 @controller = AccountController.new
29 @request = ActionController::TestRequest.new
29 @request = ActionController::TestRequest.new
30 @response = ActionController::TestResponse.new
30 @response = ActionController::TestResponse.new
31 User.current = nil
31 User.current = nil
32 end
32 end
33
33
34 def test_login_should_redirect_to_back_url_param
34 def test_login_should_redirect_to_back_url_param
35 # request.uri is "test.host" in test environment
35 # request.uri is "test.host" in test environment
36 post :login, :username => 'jsmith', :password => 'jsmith', :back_url => 'http%3A%2F%2Ftest.host%2Fissues%2Fshow%2F1'
36 post :login, :username => 'jsmith', :password => 'jsmith', :back_url => 'http%3A%2F%2Ftest.host%2Fissues%2Fshow%2F1'
37 assert_redirected_to '/issues/show/1'
37 assert_redirected_to '/issues/show/1'
38 end
38 end
39
39
40 def test_login_should_not_redirect_to_another_host
40 def test_login_should_not_redirect_to_another_host
41 post :login, :username => 'jsmith', :password => 'jsmith', :back_url => 'http%3A%2F%2Ftest.foo%2Ffake'
41 post :login, :username => 'jsmith', :password => 'jsmith', :back_url => 'http%3A%2F%2Ftest.foo%2Ffake'
42 assert_redirected_to '/my/page'
42 assert_redirected_to '/my/page'
43 end
43 end
44
44
45 def test_login_with_wrong_password
45 def test_login_with_wrong_password
46 post :login, :username => 'admin', :password => 'bad'
46 post :login, :username => 'admin', :password => 'bad'
47 assert_response :success
47 assert_response :success
48 assert_template 'login'
48 assert_template 'login'
49 assert_tag 'div',
49 assert_tag 'div',
50 :attributes => { :class => "flash error" },
50 :attributes => { :class => "flash error" },
51 :content => /Invalid user or password/
51 :content => /Invalid user or password/
52 end
52 end
53
53
54 if Object.const_defined?(:OpenID)
54 if Object.const_defined?(:OpenID)
55
55
56 def test_login_with_openid_for_existing_user
56 def test_login_with_openid_for_existing_user
57 Setting.self_registration = '3'
57 Setting.self_registration = '3'
58 Setting.openid = '1'
58 Setting.openid = '1'
59 existing_user = User.new(:firstname => 'Cool',
59 existing_user = User.new(:firstname => 'Cool',
60 :lastname => 'User',
60 :lastname => 'User',
61 :mail => 'user@somedomain.com',
61 :mail => 'user@somedomain.com',
62 :identity_url => 'http://openid.example.com/good_user')
62 :identity_url => 'http://openid.example.com/good_user')
63 existing_user.login = 'cool_user'
63 existing_user.login = 'cool_user'
64 assert existing_user.save!
64 assert existing_user.save!
65
65
66 post :login, :openid_url => existing_user.identity_url
66 post :login, :openid_url => existing_user.identity_url
67 assert_redirected_to '/my/page'
67 assert_redirected_to '/my/page'
68 end
68 end
69
69
70 def test_login_with_invalid_openid_provider
70 def test_login_with_invalid_openid_provider
71 Setting.self_registration = '0'
71 Setting.self_registration = '0'
72 Setting.openid = '1'
72 Setting.openid = '1'
73 post :login, :openid_url => 'http;//openid.example.com/good_user'
73 post :login, :openid_url => 'http;//openid.example.com/good_user'
74 assert_redirected_to home_url
74 assert_redirected_to home_url
75 end
75 end
76
76
77 def test_login_with_openid_for_existing_non_active_user
77 def test_login_with_openid_for_existing_non_active_user
78 Setting.self_registration = '2'
78 Setting.self_registration = '2'
79 Setting.openid = '1'
79 Setting.openid = '1'
80 existing_user = User.new(:firstname => 'Cool',
80 existing_user = User.new(:firstname => 'Cool',
81 :lastname => 'User',
81 :lastname => 'User',
82 :mail => 'user@somedomain.com',
82 :mail => 'user@somedomain.com',
83 :identity_url => 'http://openid.example.com/good_user',
83 :identity_url => 'http://openid.example.com/good_user',
84 :status => User::STATUS_REGISTERED)
84 :status => User::STATUS_REGISTERED)
85 existing_user.login = 'cool_user'
85 existing_user.login = 'cool_user'
86 assert existing_user.save!
86 assert existing_user.save!
87
87
88 post :login, :openid_url => existing_user.identity_url
88 post :login, :openid_url => existing_user.identity_url
89 assert_redirected_to '/login'
89 assert_redirected_to '/login'
90 end
90 end
91
91
92 def test_login_with_openid_with_new_user_created
92 def test_login_with_openid_with_new_user_created
93 Setting.self_registration = '3'
93 Setting.self_registration = '3'
94 Setting.openid = '1'
94 Setting.openid = '1'
95 post :login, :openid_url => 'http://openid.example.com/good_user'
95 post :login, :openid_url => 'http://openid.example.com/good_user'
96 assert_redirected_to '/my/account'
96 assert_redirected_to '/my/account'
97 user = User.find_by_login('cool_user')
97 user = User.find_by_login('cool_user')
98 assert user
98 assert user
99 assert_equal 'Cool', user.firstname
99 assert_equal 'Cool', user.firstname
100 assert_equal 'User', user.lastname
100 assert_equal 'User', user.lastname
101 end
101 end
102
102
103 def test_login_with_openid_with_new_user_and_self_registration_off
103 def test_login_with_openid_with_new_user_and_self_registration_off
104 Setting.self_registration = '0'
104 Setting.self_registration = '0'
105 Setting.openid = '1'
105 Setting.openid = '1'
106 post :login, :openid_url => 'http://openid.example.com/good_user'
106 post :login, :openid_url => 'http://openid.example.com/good_user'
107 assert_redirected_to home_url
107 assert_redirected_to home_url
108 user = User.find_by_login('cool_user')
108 user = User.find_by_login('cool_user')
109 assert ! user
109 assert ! user
110 end
110 end
111
111
112 def test_login_with_openid_with_new_user_created_with_email_activation_should_have_a_token
112 def test_login_with_openid_with_new_user_created_with_email_activation_should_have_a_token
113 Setting.self_registration = '1'
113 Setting.self_registration = '1'
114 Setting.openid = '1'
114 Setting.openid = '1'
115 post :login, :openid_url => 'http://openid.example.com/good_user'
115 post :login, :openid_url => 'http://openid.example.com/good_user'
116 assert_redirected_to '/login'
116 assert_redirected_to '/login'
117 user = User.find_by_login('cool_user')
117 user = User.find_by_login('cool_user')
118 assert user
118 assert user
119
119
120 token = Token.find_by_user_id_and_action(user.id, 'register')
120 token = Token.find_by_user_id_and_action(user.id, 'register')
121 assert token
121 assert token
122 end
122 end
123
123
124 def test_login_with_openid_with_new_user_created_with_manual_activation
124 def test_login_with_openid_with_new_user_created_with_manual_activation
125 Setting.self_registration = '2'
125 Setting.self_registration = '2'
126 Setting.openid = '1'
126 Setting.openid = '1'
127 post :login, :openid_url => 'http://openid.example.com/good_user'
127 post :login, :openid_url => 'http://openid.example.com/good_user'
128 assert_redirected_to '/login'
128 assert_redirected_to '/login'
129 user = User.find_by_login('cool_user')
129 user = User.find_by_login('cool_user')
130 assert user
130 assert user
131 assert_equal User::STATUS_REGISTERED, user.status
131 assert_equal User::STATUS_REGISTERED, user.status
132 end
132 end
133
133
134 def test_login_with_openid_with_new_user_with_conflict_should_register
134 def test_login_with_openid_with_new_user_with_conflict_should_register
135 Setting.self_registration = '3'
135 Setting.self_registration = '3'
136 Setting.openid = '1'
136 Setting.openid = '1'
137 existing_user = User.new(:firstname => 'Cool', :lastname => 'User', :mail => 'user@somedomain.com')
137 existing_user = User.new(:firstname => 'Cool', :lastname => 'User', :mail => 'user@somedomain.com')
138 existing_user.login = 'cool_user'
138 existing_user.login = 'cool_user'
139 assert existing_user.save!
139 assert existing_user.save!
140
140
141 post :login, :openid_url => 'http://openid.example.com/good_user'
141 post :login, :openid_url => 'http://openid.example.com/good_user'
142 assert_response :success
142 assert_response :success
143 assert_template 'register'
143 assert_template 'register'
144 assert assigns(:user)
144 assert assigns(:user)
145 assert_equal 'http://openid.example.com/good_user', assigns(:user)[:identity_url]
145 assert_equal 'http://openid.example.com/good_user', assigns(:user)[:identity_url]
146 end
146 end
147
147
148 def test_setting_openid_should_return_true_when_set_to_true
148 def test_setting_openid_should_return_true_when_set_to_true
149 Setting.openid = '1'
149 Setting.openid = '1'
150 assert_equal true, Setting.openid?
150 assert_equal true, Setting.openid?
151 end
151 end
152
152
153 else
153 else
154 puts "Skipping openid tests."
154 puts "Skipping openid tests."
155 end
155 end
156
156
157 def test_logout
157 def test_logout
158 @request.session[:user_id] = 2
158 @request.session[:user_id] = 2
159 get :logout
159 get :logout
160 assert_redirected_to '/'
160 assert_redirected_to '/'
161 assert_nil @request.session[:user_id]
161 assert_nil @request.session[:user_id]
162 end
162 end
163
163
164 context "GET #register" do
164 def test_get_register_with_registration_on
165 context "with self registration on" do
165 with_settings :self_registration => '3' do
166 setup do
166 get :register
167 Setting.self_registration = '3'
167 assert_response :success
168 get :register
168 assert_template 'register'
169 end
169 assert_not_nil assigns(:user)
170
171 should_respond_with :success
172 should_render_template :register
173 should_assign_to :user
174 end
170 end
171 end
175
172
176 context "with self registration off" do
173 def test_get_register_with_registration_off_should_redirect
177 setup do
174 with_settings :self_registration => '0' do
178 Setting.self_registration = '0'
175 get :register
179 get :register
176 assert_redirected_to '/'
180 end
181
182 should_redirect_to('/') { home_url }
183 end
177 end
184 end
178 end
185
179
186 # See integration/account_test.rb for the full test
180 # See integration/account_test.rb for the full test
187 context "POST #register" do
181 def test_post_register_with_registration_on
188 context "with self registration on automatic" do
182 with_settings :self_registration => '3' do
189 setup do
183 assert_difference 'User.count' do
190 Setting.self_registration = '3'
191 post :register, :user => {
184 post :register, :user => {
192 :login => 'register',
185 :login => 'register',
193 :password => 'test',
186 :password => 'test',
194 :password_confirmation => 'test',
187 :password_confirmation => 'test',
195 :firstname => 'John',
188 :firstname => 'John',
196 :lastname => 'Doe',
189 :lastname => 'Doe',
197 :mail => 'register@example.com'
190 :mail => 'register@example.com'
198 }
191 }
192 assert_redirected_to '/my/account'
199 end
193 end
200
194 user = User.first(:order => 'id DESC')
201 should_respond_with :redirect
195 assert_equal 'register', user.login
202 should_assign_to :user
196 assert user.active?
203 should_redirect_to('my page') { {:controller => 'my', :action => 'account'} }
204
205 should_create_a_new_user { User.last(:conditions => {:login => 'register'}) }
206
207 should 'set the user status to active' do
208 user = User.last(:conditions => {:login => 'register'})
209 assert user
210 assert_equal User::STATUS_ACTIVE, user.status
211 end
212 end
197 end
213
198 end
214 context "with self registration off" do
199
215 setup do
200 def test_post_register_with_registration_off_should_redirect
216 Setting.self_registration = '0'
201 with_settings :self_registration => '0' do
217 post :register
202 assert_no_difference 'User.count' do
203 post :register, :user => {
204 :login => 'register',
205 :password => 'test',
206 :password_confirmation => 'test',
207 :firstname => 'John',
208 :lastname => 'Doe',
209 :mail => 'register@example.com'
210 }
211 assert_redirected_to '/'
218 end
212 end
219
220 should_redirect_to('/') { home_url }
221 end
213 end
222 end
214 end
223 end
215 end
@@ -1,464 +1,455
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 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_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(
62 ActionController::TestUploadedFile.new(
63 ActiveSupport::TestCase.fixture_path + "/files/#{name}", mime, true)
63 ActiveSupport::TestCase.fixture_path + "/files/#{name}", mime, true)
64 end
64 end
65
65
66 # Mock out a file
66 # Mock out a file
67 def self.mock_file
67 def self.mock_file
68 file = 'a_file.png'
68 file = 'a_file.png'
69 file.stubs(:size).returns(32)
69 file.stubs(:size).returns(32)
70 file.stubs(:original_filename).returns('a_file.png')
70 file.stubs(:original_filename).returns('a_file.png')
71 file.stubs(:content_type).returns('image/png')
71 file.stubs(:content_type).returns('image/png')
72 file.stubs(:read).returns(false)
72 file.stubs(:read).returns(false)
73 file
73 file
74 end
74 end
75
75
76 def mock_file
76 def mock_file
77 self.class.mock_file
77 self.class.mock_file
78 end
78 end
79
79
80 def mock_file_with_options(options={})
80 def mock_file_with_options(options={})
81 file = ''
81 file = ''
82 file.stubs(:size).returns(32)
82 file.stubs(:size).returns(32)
83 original_filename = options[:original_filename] || nil
83 original_filename = options[:original_filename] || nil
84 file.stubs(:original_filename).returns(original_filename)
84 file.stubs(:original_filename).returns(original_filename)
85 content_type = options[:content_type] || nil
85 content_type = options[:content_type] || nil
86 file.stubs(:content_type).returns(content_type)
86 file.stubs(:content_type).returns(content_type)
87 file.stubs(:read).returns(false)
87 file.stubs(:read).returns(false)
88 file
88 file
89 end
89 end
90
90
91 # Use a temporary directory for attachment related tests
91 # Use a temporary directory for attachment related tests
92 def set_tmp_attachments_directory
92 def set_tmp_attachments_directory
93 Dir.mkdir "#{Rails.root}/tmp/test" unless File.directory?("#{Rails.root}/tmp/test")
93 Dir.mkdir "#{Rails.root}/tmp/test" unless File.directory?("#{Rails.root}/tmp/test")
94 unless File.directory?("#{Rails.root}/tmp/test/attachments")
94 unless File.directory?("#{Rails.root}/tmp/test/attachments")
95 Dir.mkdir "#{Rails.root}/tmp/test/attachments"
95 Dir.mkdir "#{Rails.root}/tmp/test/attachments"
96 end
96 end
97 Attachment.storage_path = "#{Rails.root}/tmp/test/attachments"
97 Attachment.storage_path = "#{Rails.root}/tmp/test/attachments"
98 end
98 end
99
99
100 def set_fixtures_attachments_directory
100 def set_fixtures_attachments_directory
101 Attachment.storage_path = "#{Rails.root}/test/fixtures/files"
101 Attachment.storage_path = "#{Rails.root}/test/fixtures/files"
102 end
102 end
103
103
104 def with_settings(options, &block)
104 def with_settings(options, &block)
105 saved_settings = options.keys.inject({}) {|h, k| h[k] = Setting[k].is_a?(Symbol) ? Setting[k] : Setting[k].dup; h}
105 saved_settings = options.keys.inject({}) {|h, k| h[k] = Setting[k].is_a?(Symbol) ? Setting[k] : Setting[k].dup; h}
106 options.each {|k, v| Setting[k] = v}
106 options.each {|k, v| Setting[k] = v}
107 yield
107 yield
108 ensure
108 ensure
109 saved_settings.each {|k, v| Setting[k] = v} if saved_settings
109 saved_settings.each {|k, v| Setting[k] = v} if saved_settings
110 end
110 end
111
111
112 def change_user_password(login, new_password)
112 def change_user_password(login, new_password)
113 user = User.first(:conditions => {:login => login})
113 user = User.first(:conditions => {:login => login})
114 user.password, user.password_confirmation = new_password, new_password
114 user.password, user.password_confirmation = new_password, new_password
115 user.save!
115 user.save!
116 end
116 end
117
117
118 def self.ldap_configured?
118 def self.ldap_configured?
119 @test_ldap = Net::LDAP.new(:host => '127.0.0.1', :port => 389)
119 @test_ldap = Net::LDAP.new(:host => '127.0.0.1', :port => 389)
120 return @test_ldap.bind
120 return @test_ldap.bind
121 rescue Exception => e
121 rescue Exception => e
122 # LDAP is not listening
122 # LDAP is not listening
123 return nil
123 return nil
124 end
124 end
125
125
126 # Returns the path to the test +vendor+ repository
126 # Returns the path to the test +vendor+ repository
127 def self.repository_path(vendor)
127 def self.repository_path(vendor)
128 Rails.root.join("tmp/test/#{vendor.downcase}_repository").to_s
128 Rails.root.join("tmp/test/#{vendor.downcase}_repository").to_s
129 end
129 end
130
130
131 # Returns the url of the subversion test repository
131 # Returns the url of the subversion test repository
132 def self.subversion_repository_url
132 def self.subversion_repository_url
133 path = repository_path('subversion')
133 path = repository_path('subversion')
134 path = '/' + path unless path.starts_with?('/')
134 path = '/' + path unless path.starts_with?('/')
135 "file://#{path}"
135 "file://#{path}"
136 end
136 end
137
137
138 # Returns true if the +vendor+ test repository is configured
138 # Returns true if the +vendor+ test repository is configured
139 def self.repository_configured?(vendor)
139 def self.repository_configured?(vendor)
140 File.directory?(repository_path(vendor))
140 File.directory?(repository_path(vendor))
141 end
141 end
142
142
143 def assert_error_tag(options={})
143 def assert_error_tag(options={})
144 assert_tag({:attributes => { :id => 'errorExplanation' }}.merge(options))
144 assert_tag({:attributes => { :id => 'errorExplanation' }}.merge(options))
145 end
145 end
146
146
147 def assert_include(expected, s)
147 def assert_include(expected, s)
148 assert s.include?(expected), "\"#{expected}\" not found in \"#{s}\""
148 assert s.include?(expected), "\"#{expected}\" not found in \"#{s}\""
149 end
149 end
150
150
151 # Shoulda macros
151 # Shoulda macros
152 def self.should_render_404
152 def self.should_render_404
153 should_respond_with :not_found
153 should_respond_with :not_found
154 should_render_template 'common/error'
154 should_render_template 'common/error'
155 end
155 end
156
156
157 def self.should_have_before_filter(expected_method, options = {})
157 def self.should_have_before_filter(expected_method, options = {})
158 should_have_filter('before', expected_method, options)
158 should_have_filter('before', expected_method, options)
159 end
159 end
160
160
161 def self.should_have_after_filter(expected_method, options = {})
161 def self.should_have_after_filter(expected_method, options = {})
162 should_have_filter('after', expected_method, options)
162 should_have_filter('after', expected_method, options)
163 end
163 end
164
164
165 def self.should_have_filter(filter_type, expected_method, options)
165 def self.should_have_filter(filter_type, expected_method, options)
166 description = "have #{filter_type}_filter :#{expected_method}"
166 description = "have #{filter_type}_filter :#{expected_method}"
167 description << " with #{options.inspect}" unless options.empty?
167 description << " with #{options.inspect}" unless options.empty?
168
168
169 should description do
169 should description do
170 klass = "action_controller/filters/#{filter_type}_filter".classify.constantize
170 klass = "action_controller/filters/#{filter_type}_filter".classify.constantize
171 expected = klass.new(:filter, expected_method.to_sym, options)
171 expected = klass.new(:filter, expected_method.to_sym, options)
172 assert_equal 1, @controller.class.filter_chain.select { |filter|
172 assert_equal 1, @controller.class.filter_chain.select { |filter|
173 filter.method == expected.method && filter.kind == expected.kind &&
173 filter.method == expected.method && filter.kind == expected.kind &&
174 filter.options == expected.options && filter.class == expected.class
174 filter.options == expected.options && filter.class == expected.class
175 }.size
175 }.size
176 end
176 end
177 end
177 end
178
178
179 def self.should_show_the_old_and_new_values_for(prop_key, model, &block)
179 def self.should_show_the_old_and_new_values_for(prop_key, model, &block)
180 context "" do
180 context "" do
181 setup do
181 setup do
182 if block_given?
182 if block_given?
183 instance_eval &block
183 instance_eval &block
184 else
184 else
185 @old_value = model.generate!
185 @old_value = model.generate!
186 @new_value = model.generate!
186 @new_value = model.generate!
187 end
187 end
188 end
188 end
189
189
190 should "use the new value's name" do
190 should "use the new value's name" do
191 @detail = JournalDetail.generate!(:property => 'attr',
191 @detail = JournalDetail.generate!(:property => 'attr',
192 :old_value => @old_value.id,
192 :old_value => @old_value.id,
193 :value => @new_value.id,
193 :value => @new_value.id,
194 :prop_key => prop_key)
194 :prop_key => prop_key)
195
195
196 assert_match @new_value.name, show_detail(@detail, true)
196 assert_match @new_value.name, show_detail(@detail, true)
197 end
197 end
198
198
199 should "use the old value's name" do
199 should "use the old value's name" do
200 @detail = JournalDetail.generate!(:property => 'attr',
200 @detail = JournalDetail.generate!(:property => 'attr',
201 :old_value => @old_value.id,
201 :old_value => @old_value.id,
202 :value => @new_value.id,
202 :value => @new_value.id,
203 :prop_key => prop_key)
203 :prop_key => prop_key)
204
204
205 assert_match @old_value.name, show_detail(@detail, true)
205 assert_match @old_value.name, show_detail(@detail, true)
206 end
206 end
207 end
207 end
208 end
208 end
209
209
210 def self.should_create_a_new_user(&block)
211 should "create a new user" do
212 user = instance_eval &block
213 assert user
214 assert_kind_of User, user
215 assert !user.new_record?
216 end
217 end
218
219 # Test that a request allows the three types of API authentication
210 # Test that a request allows the three types of API authentication
220 #
211 #
221 # * HTTP Basic with username and password
212 # * HTTP Basic with username and password
222 # * HTTP Basic with an api key for the username
213 # * HTTP Basic with an api key for the username
223 # * Key based with the key=X parameter
214 # * Key based with the key=X parameter
224 #
215 #
225 # @param [Symbol] http_method the HTTP method for request (:get, :post, :put, :delete)
216 # @param [Symbol] http_method the HTTP method for request (:get, :post, :put, :delete)
226 # @param [String] url the request url
217 # @param [String] url the request url
227 # @param [optional, Hash] parameters additional request parameters
218 # @param [optional, Hash] parameters additional request parameters
228 # @param [optional, Hash] options additional options
219 # @param [optional, Hash] options additional options
229 # @option options [Symbol] :success_code Successful response code (:success)
220 # @option options [Symbol] :success_code Successful response code (:success)
230 # @option options [Symbol] :failure_code Failure response code (:unauthorized)
221 # @option options [Symbol] :failure_code Failure response code (:unauthorized)
231 def self.should_allow_api_authentication(http_method, url, parameters={}, options={})
222 def self.should_allow_api_authentication(http_method, url, parameters={}, options={})
232 should_allow_http_basic_auth_with_username_and_password(http_method, url, parameters, options)
223 should_allow_http_basic_auth_with_username_and_password(http_method, url, parameters, options)
233 should_allow_http_basic_auth_with_key(http_method, url, parameters, options)
224 should_allow_http_basic_auth_with_key(http_method, url, parameters, options)
234 should_allow_key_based_auth(http_method, url, parameters, options)
225 should_allow_key_based_auth(http_method, url, parameters, options)
235 end
226 end
236
227
237 # Test that a request allows the username and password for HTTP BASIC
228 # Test that a request allows the username and password for HTTP BASIC
238 #
229 #
239 # @param [Symbol] http_method the HTTP method for request (:get, :post, :put, :delete)
230 # @param [Symbol] http_method the HTTP method for request (:get, :post, :put, :delete)
240 # @param [String] url the request url
231 # @param [String] url the request url
241 # @param [optional, Hash] parameters additional request parameters
232 # @param [optional, Hash] parameters additional request parameters
242 # @param [optional, Hash] options additional options
233 # @param [optional, Hash] options additional options
243 # @option options [Symbol] :success_code Successful response code (:success)
234 # @option options [Symbol] :success_code Successful response code (:success)
244 # @option options [Symbol] :failure_code Failure response code (:unauthorized)
235 # @option options [Symbol] :failure_code Failure response code (:unauthorized)
245 def self.should_allow_http_basic_auth_with_username_and_password(http_method, url, parameters={}, options={})
236 def self.should_allow_http_basic_auth_with_username_and_password(http_method, url, parameters={}, options={})
246 success_code = options[:success_code] || :success
237 success_code = options[:success_code] || :success
247 failure_code = options[:failure_code] || :unauthorized
238 failure_code = options[:failure_code] || :unauthorized
248
239
249 context "should allow http basic auth using a username and password for #{http_method} #{url}" do
240 context "should allow http basic auth using a username and password for #{http_method} #{url}" do
250 context "with a valid HTTP authentication" do
241 context "with a valid HTTP authentication" do
251 setup do
242 setup do
252 @user = User.generate_with_protected!(:password => 'my_password', :password_confirmation => 'my_password', :admin => true) # Admin so they can access the project
243 @user = User.generate_with_protected!(:password => 'my_password', :password_confirmation => 'my_password', :admin => true) # Admin so they can access the project
253 @authorization = ActionController::HttpAuthentication::Basic.encode_credentials(@user.login, 'my_password')
244 @authorization = ActionController::HttpAuthentication::Basic.encode_credentials(@user.login, 'my_password')
254 send(http_method, url, parameters, {:authorization => @authorization})
245 send(http_method, url, parameters, {:authorization => @authorization})
255 end
246 end
256
247
257 should_respond_with success_code
248 should_respond_with success_code
258 should_respond_with_content_type_based_on_url(url)
249 should_respond_with_content_type_based_on_url(url)
259 should "login as the user" do
250 should "login as the user" do
260 assert_equal @user, User.current
251 assert_equal @user, User.current
261 end
252 end
262 end
253 end
263
254
264 context "with an invalid HTTP authentication" do
255 context "with an invalid HTTP authentication" do
265 setup do
256 setup do
266 @user = User.generate_with_protected!
257 @user = User.generate_with_protected!
267 @authorization = ActionController::HttpAuthentication::Basic.encode_credentials(@user.login, 'wrong_password')
258 @authorization = ActionController::HttpAuthentication::Basic.encode_credentials(@user.login, 'wrong_password')
268 send(http_method, url, parameters, {:authorization => @authorization})
259 send(http_method, url, parameters, {:authorization => @authorization})
269 end
260 end
270
261
271 should_respond_with failure_code
262 should_respond_with failure_code
272 should_respond_with_content_type_based_on_url(url)
263 should_respond_with_content_type_based_on_url(url)
273 should "not login as the user" do
264 should "not login as the user" do
274 assert_equal User.anonymous, User.current
265 assert_equal User.anonymous, User.current
275 end
266 end
276 end
267 end
277
268
278 context "without credentials" do
269 context "without credentials" do
279 setup do
270 setup do
280 send(http_method, url, parameters, {:authorization => ''})
271 send(http_method, url, parameters, {:authorization => ''})
281 end
272 end
282
273
283 should_respond_with failure_code
274 should_respond_with failure_code
284 should_respond_with_content_type_based_on_url(url)
275 should_respond_with_content_type_based_on_url(url)
285 should "include_www_authenticate_header" do
276 should "include_www_authenticate_header" do
286 assert @controller.response.headers.has_key?('WWW-Authenticate')
277 assert @controller.response.headers.has_key?('WWW-Authenticate')
287 end
278 end
288 end
279 end
289 end
280 end
290
281
291 end
282 end
292
283
293 # Test that a request allows the API key with HTTP BASIC
284 # Test that a request allows the API key with HTTP BASIC
294 #
285 #
295 # @param [Symbol] http_method the HTTP method for request (:get, :post, :put, :delete)
286 # @param [Symbol] http_method the HTTP method for request (:get, :post, :put, :delete)
296 # @param [String] url the request url
287 # @param [String] url the request url
297 # @param [optional, Hash] parameters additional request parameters
288 # @param [optional, Hash] parameters additional request parameters
298 # @param [optional, Hash] options additional options
289 # @param [optional, Hash] options additional options
299 # @option options [Symbol] :success_code Successful response code (:success)
290 # @option options [Symbol] :success_code Successful response code (:success)
300 # @option options [Symbol] :failure_code Failure response code (:unauthorized)
291 # @option options [Symbol] :failure_code Failure response code (:unauthorized)
301 def self.should_allow_http_basic_auth_with_key(http_method, url, parameters={}, options={})
292 def self.should_allow_http_basic_auth_with_key(http_method, url, parameters={}, options={})
302 success_code = options[:success_code] || :success
293 success_code = options[:success_code] || :success
303 failure_code = options[:failure_code] || :unauthorized
294 failure_code = options[:failure_code] || :unauthorized
304
295
305 context "should allow http basic auth with a key for #{http_method} #{url}" do
296 context "should allow http basic auth with a key for #{http_method} #{url}" do
306 context "with a valid HTTP authentication using the API token" do
297 context "with a valid HTTP authentication using the API token" do
307 setup do
298 setup do
308 @user = User.generate_with_protected!(:admin => true)
299 @user = User.generate_with_protected!(:admin => true)
309 @token = Token.generate!(:user => @user, :action => 'api')
300 @token = Token.generate!(:user => @user, :action => 'api')
310 @authorization = ActionController::HttpAuthentication::Basic.encode_credentials(@token.value, 'X')
301 @authorization = ActionController::HttpAuthentication::Basic.encode_credentials(@token.value, 'X')
311 send(http_method, url, parameters, {:authorization => @authorization})
302 send(http_method, url, parameters, {:authorization => @authorization})
312 end
303 end
313
304
314 should_respond_with success_code
305 should_respond_with success_code
315 should_respond_with_content_type_based_on_url(url)
306 should_respond_with_content_type_based_on_url(url)
316 should_be_a_valid_response_string_based_on_url(url)
307 should_be_a_valid_response_string_based_on_url(url)
317 should "login as the user" do
308 should "login as the user" do
318 assert_equal @user, User.current
309 assert_equal @user, User.current
319 end
310 end
320 end
311 end
321
312
322 context "with an invalid HTTP authentication" do
313 context "with an invalid HTTP authentication" do
323 setup do
314 setup do
324 @user = User.generate_with_protected!
315 @user = User.generate_with_protected!
325 @token = Token.generate!(:user => @user, :action => 'feeds')
316 @token = Token.generate!(:user => @user, :action => 'feeds')
326 @authorization = ActionController::HttpAuthentication::Basic.encode_credentials(@token.value, 'X')
317 @authorization = ActionController::HttpAuthentication::Basic.encode_credentials(@token.value, 'X')
327 send(http_method, url, parameters, {:authorization => @authorization})
318 send(http_method, url, parameters, {:authorization => @authorization})
328 end
319 end
329
320
330 should_respond_with failure_code
321 should_respond_with failure_code
331 should_respond_with_content_type_based_on_url(url)
322 should_respond_with_content_type_based_on_url(url)
332 should "not login as the user" do
323 should "not login as the user" do
333 assert_equal User.anonymous, User.current
324 assert_equal User.anonymous, User.current
334 end
325 end
335 end
326 end
336 end
327 end
337 end
328 end
338
329
339 # Test that a request allows full key authentication
330 # Test that a request allows full key authentication
340 #
331 #
341 # @param [Symbol] http_method the HTTP method for request (:get, :post, :put, :delete)
332 # @param [Symbol] http_method the HTTP method for request (:get, :post, :put, :delete)
342 # @param [String] url the request url, without the key=ZXY parameter
333 # @param [String] url the request url, without the key=ZXY parameter
343 # @param [optional, Hash] parameters additional request parameters
334 # @param [optional, Hash] parameters additional request parameters
344 # @param [optional, Hash] options additional options
335 # @param [optional, Hash] options additional options
345 # @option options [Symbol] :success_code Successful response code (:success)
336 # @option options [Symbol] :success_code Successful response code (:success)
346 # @option options [Symbol] :failure_code Failure response code (:unauthorized)
337 # @option options [Symbol] :failure_code Failure response code (:unauthorized)
347 def self.should_allow_key_based_auth(http_method, url, parameters={}, options={})
338 def self.should_allow_key_based_auth(http_method, url, parameters={}, options={})
348 success_code = options[:success_code] || :success
339 success_code = options[:success_code] || :success
349 failure_code = options[:failure_code] || :unauthorized
340 failure_code = options[:failure_code] || :unauthorized
350
341
351 context "should allow key based auth using key=X for #{http_method} #{url}" do
342 context "should allow key based auth using key=X for #{http_method} #{url}" do
352 context "with a valid api token" do
343 context "with a valid api token" do
353 setup do
344 setup do
354 @user = User.generate_with_protected!(:admin => true)
345 @user = User.generate_with_protected!(:admin => true)
355 @token = Token.generate!(:user => @user, :action => 'api')
346 @token = Token.generate!(:user => @user, :action => 'api')
356 # Simple url parse to add on ?key= or &key=
347 # Simple url parse to add on ?key= or &key=
357 request_url = if url.match(/\?/)
348 request_url = if url.match(/\?/)
358 url + "&key=#{@token.value}"
349 url + "&key=#{@token.value}"
359 else
350 else
360 url + "?key=#{@token.value}"
351 url + "?key=#{@token.value}"
361 end
352 end
362 send(http_method, request_url, parameters)
353 send(http_method, request_url, parameters)
363 end
354 end
364
355
365 should_respond_with success_code
356 should_respond_with success_code
366 should_respond_with_content_type_based_on_url(url)
357 should_respond_with_content_type_based_on_url(url)
367 should_be_a_valid_response_string_based_on_url(url)
358 should_be_a_valid_response_string_based_on_url(url)
368 should "login as the user" do
359 should "login as the user" do
369 assert_equal @user, User.current
360 assert_equal @user, User.current
370 end
361 end
371 end
362 end
372
363
373 context "with an invalid api token" do
364 context "with an invalid api token" do
374 setup do
365 setup do
375 @user = User.generate_with_protected!
366 @user = User.generate_with_protected!
376 @token = Token.generate!(:user => @user, :action => 'feeds')
367 @token = Token.generate!(:user => @user, :action => 'feeds')
377 # Simple url parse to add on ?key= or &key=
368 # Simple url parse to add on ?key= or &key=
378 request_url = if url.match(/\?/)
369 request_url = if url.match(/\?/)
379 url + "&key=#{@token.value}"
370 url + "&key=#{@token.value}"
380 else
371 else
381 url + "?key=#{@token.value}"
372 url + "?key=#{@token.value}"
382 end
373 end
383 send(http_method, request_url, parameters)
374 send(http_method, request_url, parameters)
384 end
375 end
385
376
386 should_respond_with failure_code
377 should_respond_with failure_code
387 should_respond_with_content_type_based_on_url(url)
378 should_respond_with_content_type_based_on_url(url)
388 should "not login as the user" do
379 should "not login as the user" do
389 assert_equal User.anonymous, User.current
380 assert_equal User.anonymous, User.current
390 end
381 end
391 end
382 end
392 end
383 end
393
384
394 context "should allow key based auth using X-Redmine-API-Key header for #{http_method} #{url}" do
385 context "should allow key based auth using X-Redmine-API-Key header for #{http_method} #{url}" do
395 setup do
386 setup do
396 @user = User.generate_with_protected!(:admin => true)
387 @user = User.generate_with_protected!(:admin => true)
397 @token = Token.generate!(:user => @user, :action => 'api')
388 @token = Token.generate!(:user => @user, :action => 'api')
398 send(http_method, url, parameters, {'X-Redmine-API-Key' => @token.value.to_s})
389 send(http_method, url, parameters, {'X-Redmine-API-Key' => @token.value.to_s})
399 end
390 end
400
391
401 should_respond_with success_code
392 should_respond_with success_code
402 should_respond_with_content_type_based_on_url(url)
393 should_respond_with_content_type_based_on_url(url)
403 should_be_a_valid_response_string_based_on_url(url)
394 should_be_a_valid_response_string_based_on_url(url)
404 should "login as the user" do
395 should "login as the user" do
405 assert_equal @user, User.current
396 assert_equal @user, User.current
406 end
397 end
407 end
398 end
408 end
399 end
409
400
410 # Uses should_respond_with_content_type based on what's in the url:
401 # Uses should_respond_with_content_type based on what's in the url:
411 #
402 #
412 # '/project/issues.xml' => should_respond_with_content_type :xml
403 # '/project/issues.xml' => should_respond_with_content_type :xml
413 # '/project/issues.json' => should_respond_with_content_type :json
404 # '/project/issues.json' => should_respond_with_content_type :json
414 #
405 #
415 # @param [String] url Request
406 # @param [String] url Request
416 def self.should_respond_with_content_type_based_on_url(url)
407 def self.should_respond_with_content_type_based_on_url(url)
417 case
408 case
418 when url.match(/xml/i)
409 when url.match(/xml/i)
419 should_respond_with_content_type :xml
410 should_respond_with_content_type :xml
420 when url.match(/json/i)
411 when url.match(/json/i)
421 should_respond_with_content_type :json
412 should_respond_with_content_type :json
422 else
413 else
423 raise "Unknown content type for should_respond_with_content_type_based_on_url: #{url}"
414 raise "Unknown content type for should_respond_with_content_type_based_on_url: #{url}"
424 end
415 end
425
416
426 end
417 end
427
418
428 # Uses the url to assert which format the response should be in
419 # Uses the url to assert which format the response should be in
429 #
420 #
430 # '/project/issues.xml' => should_be_a_valid_xml_string
421 # '/project/issues.xml' => should_be_a_valid_xml_string
431 # '/project/issues.json' => should_be_a_valid_json_string
422 # '/project/issues.json' => should_be_a_valid_json_string
432 #
423 #
433 # @param [String] url Request
424 # @param [String] url Request
434 def self.should_be_a_valid_response_string_based_on_url(url)
425 def self.should_be_a_valid_response_string_based_on_url(url)
435 case
426 case
436 when url.match(/xml/i)
427 when url.match(/xml/i)
437 should_be_a_valid_xml_string
428 should_be_a_valid_xml_string
438 when url.match(/json/i)
429 when url.match(/json/i)
439 should_be_a_valid_json_string
430 should_be_a_valid_json_string
440 else
431 else
441 raise "Unknown content type for should_be_a_valid_response_based_on_url: #{url}"
432 raise "Unknown content type for should_be_a_valid_response_based_on_url: #{url}"
442 end
433 end
443
434
444 end
435 end
445
436
446 # Checks that the response is a valid JSON string
437 # Checks that the response is a valid JSON string
447 def self.should_be_a_valid_json_string
438 def self.should_be_a_valid_json_string
448 should "be a valid JSON string (or empty)" do
439 should "be a valid JSON string (or empty)" do
449 assert(response.body.blank? || ActiveSupport::JSON.decode(response.body))
440 assert(response.body.blank? || ActiveSupport::JSON.decode(response.body))
450 end
441 end
451 end
442 end
452
443
453 # Checks that the response is a valid XML string
444 # Checks that the response is a valid XML string
454 def self.should_be_a_valid_xml_string
445 def self.should_be_a_valid_xml_string
455 should "be a valid XML string" do
446 should "be a valid XML string" do
456 assert REXML::Document.new(response.body)
447 assert REXML::Document.new(response.body)
457 end
448 end
458 end
449 end
459
450
460 end
451 end
461
452
462 # Simple module to "namespace" all of the API tests
453 # Simple module to "namespace" all of the API tests
463 module ApiTest
454 module ApiTest
464 end
455 end
General Comments 0
You need to be logged in to leave comments. Login now