##// END OF EJS Templates
Fixed: Missing template wiki/update.erb error introduced in r4272 (#6987)....
Jean-Philippe Lang -
r4315:4a6a551d074c
parent child
Show More
@@ -1,277 +1,279
1 # redMine - project management software
1 # redMine - project management software
2 # Copyright (C) 2006-2007 Jean-Philippe Lang
2 # Copyright (C) 2006-2007 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 'diff'
18 require 'diff'
19
19
20 # The WikiController follows the Rails REST controller pattern but with
20 # The WikiController follows the Rails REST controller pattern but with
21 # a few differences
21 # a few differences
22 #
22 #
23 # * index - shows a list of WikiPages grouped by page or date
23 # * index - shows a list of WikiPages grouped by page or date
24 # * new - not used
24 # * new - not used
25 # * create - not used
25 # * create - not used
26 # * show - will also show the form for creating a new wiki page
26 # * show - will also show the form for creating a new wiki page
27 # * edit - used to edit an existing or new page
27 # * edit - used to edit an existing or new page
28 # * update - used to save a wiki page update to the database, including new pages
28 # * update - used to save a wiki page update to the database, including new pages
29 # * destroy - normal
29 # * destroy - normal
30 #
30 #
31 # Other member and collection methods are also used
31 # Other member and collection methods are also used
32 #
32 #
33 # TODO: still being worked on
33 # TODO: still being worked on
34 class WikiController < ApplicationController
34 class WikiController < ApplicationController
35 default_search_scope :wiki_pages
35 default_search_scope :wiki_pages
36 before_filter :find_wiki, :authorize
36 before_filter :find_wiki, :authorize
37 before_filter :find_existing_page, :only => [:rename, :protect, :history, :diff, :annotate, :add_attachment, :destroy]
37 before_filter :find_existing_page, :only => [:rename, :protect, :history, :diff, :annotate, :add_attachment, :destroy]
38
38
39 verify :method => :post, :only => [:protect], :redirect_to => { :action => :show }
39 verify :method => :post, :only => [:protect], :redirect_to => { :action => :show }
40
40
41 helper :attachments
41 helper :attachments
42 include AttachmentsHelper
42 include AttachmentsHelper
43 helper :watchers
43 helper :watchers
44
44
45 # List of pages, sorted alphabetically and by parent (hierarchy)
45 # List of pages, sorted alphabetically and by parent (hierarchy)
46 def index
46 def index
47 load_pages_grouped_by_date_without_content
47 load_pages_grouped_by_date_without_content
48 end
48 end
49
49
50 # display a page (in editing mode if it doesn't exist)
50 # display a page (in editing mode if it doesn't exist)
51 def show
51 def show
52 page_title = params[:id]
52 page_title = params[:id]
53 @page = @wiki.find_or_new_page(page_title)
53 @page = @wiki.find_or_new_page(page_title)
54 if @page.new_record?
54 if @page.new_record?
55 if User.current.allowed_to?(:edit_wiki_pages, @project) && editable?
55 if User.current.allowed_to?(:edit_wiki_pages, @project) && editable?
56 edit
56 edit
57 render :action => 'edit'
57 render :action => 'edit'
58 else
58 else
59 render_404
59 render_404
60 end
60 end
61 return
61 return
62 end
62 end
63 if params[:version] && !User.current.allowed_to?(:view_wiki_edits, @project)
63 if params[:version] && !User.current.allowed_to?(:view_wiki_edits, @project)
64 # Redirects user to the current version if he's not allowed to view previous versions
64 # Redirects user to the current version if he's not allowed to view previous versions
65 redirect_to :version => nil
65 redirect_to :version => nil
66 return
66 return
67 end
67 end
68 @content = @page.content_for_version(params[:version])
68 @content = @page.content_for_version(params[:version])
69 if User.current.allowed_to?(:export_wiki_pages, @project)
69 if User.current.allowed_to?(:export_wiki_pages, @project)
70 if params[:format] == 'html'
70 if params[:format] == 'html'
71 export = render_to_string :action => 'export', :layout => false
71 export = render_to_string :action => 'export', :layout => false
72 send_data(export, :type => 'text/html', :filename => "#{@page.title}.html")
72 send_data(export, :type => 'text/html', :filename => "#{@page.title}.html")
73 return
73 return
74 elsif params[:format] == 'txt'
74 elsif params[:format] == 'txt'
75 send_data(@content.text, :type => 'text/plain', :filename => "#{@page.title}.txt")
75 send_data(@content.text, :type => 'text/plain', :filename => "#{@page.title}.txt")
76 return
76 return
77 end
77 end
78 end
78 end
79 @editable = editable?
79 @editable = editable?
80 render :action => 'show'
80 render :action => 'show'
81 end
81 end
82
82
83 # edit an existing page or a new one
83 # edit an existing page or a new one
84 def edit
84 def edit
85 @page = @wiki.find_or_new_page(params[:id])
85 @page = @wiki.find_or_new_page(params[:id])
86 return render_403 unless editable?
86 return render_403 unless editable?
87 @page.content = WikiContent.new(:page => @page) if @page.new_record?
87 @page.content = WikiContent.new(:page => @page) if @page.new_record?
88
88
89 @content = @page.content_for_version(params[:version])
89 @content = @page.content_for_version(params[:version])
90 @content.text = initial_page_content(@page) if @content.text.blank?
90 @content.text = initial_page_content(@page) if @content.text.blank?
91 # don't keep previous comment
91 # don't keep previous comment
92 @content.comments = nil
92 @content.comments = nil
93
93
94 # To prevent StaleObjectError exception when reverting to a previous version
94 # To prevent StaleObjectError exception when reverting to a previous version
95 @content.version = @page.content.version
95 @content.version = @page.content.version
96 rescue ActiveRecord::StaleObjectError
96 rescue ActiveRecord::StaleObjectError
97 # Optimistic locking exception
97 # Optimistic locking exception
98 flash[:error] = l(:notice_locking_conflict)
98 flash[:error] = l(:notice_locking_conflict)
99 end
99 end
100
100
101 verify :method => :put, :only => :update, :render => {:nothing => true, :status => :method_not_allowed }
101 verify :method => :put, :only => :update, :render => {:nothing => true, :status => :method_not_allowed }
102 # Creates a new page or updates an existing one
102 # Creates a new page or updates an existing one
103 def update
103 def update
104 @page = @wiki.find_or_new_page(params[:id])
104 @page = @wiki.find_or_new_page(params[:id])
105 return render_403 unless editable?
105 return render_403 unless editable?
106 @page.content = WikiContent.new(:page => @page) if @page.new_record?
106 @page.content = WikiContent.new(:page => @page) if @page.new_record?
107
107
108 @content = @page.content_for_version(params[:version])
108 @content = @page.content_for_version(params[:version])
109 @content.text = initial_page_content(@page) if @content.text.blank?
109 @content.text = initial_page_content(@page) if @content.text.blank?
110 # don't keep previous comment
110 # don't keep previous comment
111 @content.comments = nil
111 @content.comments = nil
112
112
113 if !@page.new_record? && params[:content].present? && @content.text == params[:content][:text]
113 if !@page.new_record? && params[:content].present? && @content.text == params[:content][:text]
114 attachments = Attachment.attach_files(@page, params[:attachments])
114 attachments = Attachment.attach_files(@page, params[:attachments])
115 render_attachment_warning_if_needed(@page)
115 render_attachment_warning_if_needed(@page)
116 # don't save if text wasn't changed
116 # don't save if text wasn't changed
117 redirect_to :action => 'show', :project_id => @project, :id => @page.title
117 redirect_to :action => 'show', :project_id => @project, :id => @page.title
118 return
118 return
119 end
119 end
120 @content.attributes = params[:content]
120 @content.attributes = params[:content]
121 @content.author = User.current
121 @content.author = User.current
122 # if page is new @page.save will also save content, but not if page isn't a new record
122 # if page is new @page.save will also save content, but not if page isn't a new record
123 if (@page.new_record? ? @page.save : @content.save)
123 if (@page.new_record? ? @page.save : @content.save)
124 attachments = Attachment.attach_files(@page, params[:attachments])
124 attachments = Attachment.attach_files(@page, params[:attachments])
125 render_attachment_warning_if_needed(@page)
125 render_attachment_warning_if_needed(@page)
126 call_hook(:controller_wiki_edit_after_save, { :params => params, :page => @page})
126 call_hook(:controller_wiki_edit_after_save, { :params => params, :page => @page})
127 redirect_to :action => 'show', :project_id => @project, :id => @page.title
127 redirect_to :action => 'show', :project_id => @project, :id => @page.title
128 else
129 render :action => 'edit'
128 end
130 end
129
131
130 rescue ActiveRecord::StaleObjectError
132 rescue ActiveRecord::StaleObjectError
131 # Optimistic locking exception
133 # Optimistic locking exception
132 flash[:error] = l(:notice_locking_conflict)
134 flash[:error] = l(:notice_locking_conflict)
133 end
135 end
134
136
135 # rename a page
137 # rename a page
136 def rename
138 def rename
137 return render_403 unless editable?
139 return render_403 unless editable?
138 @page.redirect_existing_links = true
140 @page.redirect_existing_links = true
139 # used to display the *original* title if some AR validation errors occur
141 # used to display the *original* title if some AR validation errors occur
140 @original_title = @page.pretty_title
142 @original_title = @page.pretty_title
141 if request.post? && @page.update_attributes(params[:wiki_page])
143 if request.post? && @page.update_attributes(params[:wiki_page])
142 flash[:notice] = l(:notice_successful_update)
144 flash[:notice] = l(:notice_successful_update)
143 redirect_to :action => 'show', :project_id => @project, :id => @page.title
145 redirect_to :action => 'show', :project_id => @project, :id => @page.title
144 end
146 end
145 end
147 end
146
148
147 def protect
149 def protect
148 @page.update_attribute :protected, params[:protected]
150 @page.update_attribute :protected, params[:protected]
149 redirect_to :action => 'show', :project_id => @project, :id => @page.title
151 redirect_to :action => 'show', :project_id => @project, :id => @page.title
150 end
152 end
151
153
152 # show page history
154 # show page history
153 def history
155 def history
154 @version_count = @page.content.versions.count
156 @version_count = @page.content.versions.count
155 @version_pages = Paginator.new self, @version_count, per_page_option, params['p']
157 @version_pages = Paginator.new self, @version_count, per_page_option, params['p']
156 # don't load text
158 # don't load text
157 @versions = @page.content.versions.find :all,
159 @versions = @page.content.versions.find :all,
158 :select => "id, author_id, comments, updated_on, version",
160 :select => "id, author_id, comments, updated_on, version",
159 :order => 'version DESC',
161 :order => 'version DESC',
160 :limit => @version_pages.items_per_page + 1,
162 :limit => @version_pages.items_per_page + 1,
161 :offset => @version_pages.current.offset
163 :offset => @version_pages.current.offset
162
164
163 render :layout => false if request.xhr?
165 render :layout => false if request.xhr?
164 end
166 end
165
167
166 def diff
168 def diff
167 @diff = @page.diff(params[:version], params[:version_from])
169 @diff = @page.diff(params[:version], params[:version_from])
168 render_404 unless @diff
170 render_404 unless @diff
169 end
171 end
170
172
171 def annotate
173 def annotate
172 @annotate = @page.annotate(params[:version])
174 @annotate = @page.annotate(params[:version])
173 render_404 unless @annotate
175 render_404 unless @annotate
174 end
176 end
175
177
176 verify :method => :delete, :only => [:destroy], :redirect_to => { :action => :show }
178 verify :method => :delete, :only => [:destroy], :redirect_to => { :action => :show }
177 # Removes a wiki page and its history
179 # Removes a wiki page and its history
178 # Children can be either set as root pages, removed or reassigned to another parent page
180 # Children can be either set as root pages, removed or reassigned to another parent page
179 def destroy
181 def destroy
180 return render_403 unless editable?
182 return render_403 unless editable?
181
183
182 @descendants_count = @page.descendants.size
184 @descendants_count = @page.descendants.size
183 if @descendants_count > 0
185 if @descendants_count > 0
184 case params[:todo]
186 case params[:todo]
185 when 'nullify'
187 when 'nullify'
186 # Nothing to do
188 # Nothing to do
187 when 'destroy'
189 when 'destroy'
188 # Removes all its descendants
190 # Removes all its descendants
189 @page.descendants.each(&:destroy)
191 @page.descendants.each(&:destroy)
190 when 'reassign'
192 when 'reassign'
191 # Reassign children to another parent page
193 # Reassign children to another parent page
192 reassign_to = @wiki.pages.find_by_id(params[:reassign_to_id].to_i)
194 reassign_to = @wiki.pages.find_by_id(params[:reassign_to_id].to_i)
193 return unless reassign_to
195 return unless reassign_to
194 @page.children.each do |child|
196 @page.children.each do |child|
195 child.update_attribute(:parent, reassign_to)
197 child.update_attribute(:parent, reassign_to)
196 end
198 end
197 else
199 else
198 @reassignable_to = @wiki.pages - @page.self_and_descendants
200 @reassignable_to = @wiki.pages - @page.self_and_descendants
199 return
201 return
200 end
202 end
201 end
203 end
202 @page.destroy
204 @page.destroy
203 redirect_to :action => 'index', :project_id => @project
205 redirect_to :action => 'index', :project_id => @project
204 end
206 end
205
207
206 # Export wiki to a single html file
208 # Export wiki to a single html file
207 def export
209 def export
208 if User.current.allowed_to?(:export_wiki_pages, @project)
210 if User.current.allowed_to?(:export_wiki_pages, @project)
209 @pages = @wiki.pages.find :all, :order => 'title'
211 @pages = @wiki.pages.find :all, :order => 'title'
210 export = render_to_string :action => 'export_multiple', :layout => false
212 export = render_to_string :action => 'export_multiple', :layout => false
211 send_data(export, :type => 'text/html', :filename => "wiki.html")
213 send_data(export, :type => 'text/html', :filename => "wiki.html")
212 else
214 else
213 redirect_to :action => 'show', :project_id => @project, :id => nil
215 redirect_to :action => 'show', :project_id => @project, :id => nil
214 end
216 end
215 end
217 end
216
218
217 def date_index
219 def date_index
218 load_pages_grouped_by_date_without_content
220 load_pages_grouped_by_date_without_content
219 end
221 end
220
222
221 def preview
223 def preview
222 page = @wiki.find_page(params[:id])
224 page = @wiki.find_page(params[:id])
223 # page is nil when previewing a new page
225 # page is nil when previewing a new page
224 return render_403 unless page.nil? || editable?(page)
226 return render_403 unless page.nil? || editable?(page)
225 if page
227 if page
226 @attachements = page.attachments
228 @attachements = page.attachments
227 @previewed = page.content
229 @previewed = page.content
228 end
230 end
229 @text = params[:content][:text]
231 @text = params[:content][:text]
230 render :partial => 'common/preview'
232 render :partial => 'common/preview'
231 end
233 end
232
234
233 def add_attachment
235 def add_attachment
234 return render_403 unless editable?
236 return render_403 unless editable?
235 attachments = Attachment.attach_files(@page, params[:attachments])
237 attachments = Attachment.attach_files(@page, params[:attachments])
236 render_attachment_warning_if_needed(@page)
238 render_attachment_warning_if_needed(@page)
237 redirect_to :action => 'show', :id => @page.title, :project_id => @project
239 redirect_to :action => 'show', :id => @page.title, :project_id => @project
238 end
240 end
239
241
240 private
242 private
241
243
242 def find_wiki
244 def find_wiki
243 @project = Project.find(params[:project_id])
245 @project = Project.find(params[:project_id])
244 @wiki = @project.wiki
246 @wiki = @project.wiki
245 render_404 unless @wiki
247 render_404 unless @wiki
246 rescue ActiveRecord::RecordNotFound
248 rescue ActiveRecord::RecordNotFound
247 render_404
249 render_404
248 end
250 end
249
251
250 # Finds the requested page and returns a 404 error if it doesn't exist
252 # Finds the requested page and returns a 404 error if it doesn't exist
251 def find_existing_page
253 def find_existing_page
252 @page = @wiki.find_page(params[:id])
254 @page = @wiki.find_page(params[:id])
253 render_404 if @page.nil?
255 render_404 if @page.nil?
254 end
256 end
255
257
256 # Returns true if the current user is allowed to edit the page, otherwise false
258 # Returns true if the current user is allowed to edit the page, otherwise false
257 def editable?(page = @page)
259 def editable?(page = @page)
258 page.editable_by?(User.current)
260 page.editable_by?(User.current)
259 end
261 end
260
262
261 # Returns the default content of a new wiki page
263 # Returns the default content of a new wiki page
262 def initial_page_content(page)
264 def initial_page_content(page)
263 helper = Redmine::WikiFormatting.helper_for(Setting.text_formatting)
265 helper = Redmine::WikiFormatting.helper_for(Setting.text_formatting)
264 extend helper unless self.instance_of?(helper)
266 extend helper unless self.instance_of?(helper)
265 helper.instance_method(:initial_page_content).bind(self).call(page)
267 helper.instance_method(:initial_page_content).bind(self).call(page)
266 end
268 end
267
269
268 # eager load information about last updates, without loading text
270 # eager load information about last updates, without loading text
269 def load_pages_grouped_by_date_without_content
271 def load_pages_grouped_by_date_without_content
270 @pages = @wiki.pages.find :all, :select => "#{WikiPage.table_name}.*, #{WikiContent.table_name}.updated_on",
272 @pages = @wiki.pages.find :all, :select => "#{WikiPage.table_name}.*, #{WikiContent.table_name}.updated_on",
271 :joins => "LEFT JOIN #{WikiContent.table_name} ON #{WikiContent.table_name}.page_id = #{WikiPage.table_name}.id",
273 :joins => "LEFT JOIN #{WikiContent.table_name} ON #{WikiContent.table_name}.page_id = #{WikiPage.table_name}.id",
272 :order => 'title'
274 :order => 'title'
273 @pages_by_date = @pages.group_by {|p| p.updated_on.to_date}
275 @pages_by_date = @pages.group_by {|p| p.updated_on.to_date}
274 @pages_by_parent_id = @pages.group_by(&:parent_id)
276 @pages_by_parent_id = @pages.group_by(&:parent_id)
275 end
277 end
276
278
277 end
279 end
@@ -1,413 +1,459
1 # redMine - project management software
1 # redMine - project management software
2 # Copyright (C) 2006-2007 Jean-Philippe Lang
2 # Copyright (C) 2006-2007 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.dirname(__FILE__) + '/../test_helper'
18 require File.dirname(__FILE__) + '/../test_helper'
19 require 'wiki_controller'
19 require 'wiki_controller'
20
20
21 # Re-raise errors caught by the controller.
21 # Re-raise errors caught by the controller.
22 class WikiController; def rescue_action(e) raise e end; end
22 class WikiController; def rescue_action(e) raise e end; end
23
23
24 class WikiControllerTest < ActionController::TestCase
24 class WikiControllerTest < ActionController::TestCase
25 fixtures :projects, :users, :roles, :members, :member_roles, :enabled_modules, :wikis, :wiki_pages, :wiki_contents, :wiki_content_versions, :attachments
25 fixtures :projects, :users, :roles, :members, :member_roles, :enabled_modules, :wikis, :wiki_pages, :wiki_contents, :wiki_content_versions, :attachments
26
26
27 def setup
27 def setup
28 @controller = WikiController.new
28 @controller = WikiController.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_show_start_page
34 def test_show_start_page
35 get :show, :project_id => 'ecookbook'
35 get :show, :project_id => 'ecookbook'
36 assert_response :success
36 assert_response :success
37 assert_template 'show'
37 assert_template 'show'
38 assert_tag :tag => 'h1', :content => /CookBook documentation/
38 assert_tag :tag => 'h1', :content => /CookBook documentation/
39
39
40 # child_pages macro
40 # child_pages macro
41 assert_tag :ul, :attributes => { :class => 'pages-hierarchy' },
41 assert_tag :ul, :attributes => { :class => 'pages-hierarchy' },
42 :child => { :tag => 'li',
42 :child => { :tag => 'li',
43 :child => { :tag => 'a', :attributes => { :href => '/projects/ecookbook/wiki/Page_with_an_inline_image' },
43 :child => { :tag => 'a', :attributes => { :href => '/projects/ecookbook/wiki/Page_with_an_inline_image' },
44 :content => 'Page with an inline image' } }
44 :content => 'Page with an inline image' } }
45 end
45 end
46
46
47 def test_show_page_with_name
47 def test_show_page_with_name
48 get :show, :project_id => 1, :id => 'Another_page'
48 get :show, :project_id => 1, :id => 'Another_page'
49 assert_response :success
49 assert_response :success
50 assert_template 'show'
50 assert_template 'show'
51 assert_tag :tag => 'h1', :content => /Another page/
51 assert_tag :tag => 'h1', :content => /Another page/
52 # Included page with an inline image
52 # Included page with an inline image
53 assert_tag :tag => 'p', :content => /This is an inline image/
53 assert_tag :tag => 'p', :content => /This is an inline image/
54 assert_tag :tag => 'img', :attributes => { :src => '/attachments/download/3',
54 assert_tag :tag => 'img', :attributes => { :src => '/attachments/download/3',
55 :alt => 'This is a logo' }
55 :alt => 'This is a logo' }
56 end
56 end
57
57
58 def test_show_with_sidebar
58 def test_show_with_sidebar
59 page = Project.find(1).wiki.pages.new(:title => 'Sidebar')
59 page = Project.find(1).wiki.pages.new(:title => 'Sidebar')
60 page.content = WikiContent.new(:text => 'Side bar content for test_show_with_sidebar')
60 page.content = WikiContent.new(:text => 'Side bar content for test_show_with_sidebar')
61 page.save!
61 page.save!
62
62
63 get :show, :project_id => 1, :id => 'Another_page'
63 get :show, :project_id => 1, :id => 'Another_page'
64 assert_response :success
64 assert_response :success
65 assert_tag :tag => 'div', :attributes => {:id => 'sidebar'},
65 assert_tag :tag => 'div', :attributes => {:id => 'sidebar'},
66 :content => /Side bar content for test_show_with_sidebar/
66 :content => /Side bar content for test_show_with_sidebar/
67 end
67 end
68
68
69 def test_show_unexistent_page_without_edit_right
69 def test_show_unexistent_page_without_edit_right
70 get :show, :project_id => 1, :id => 'Unexistent page'
70 get :show, :project_id => 1, :id => 'Unexistent page'
71 assert_response 404
71 assert_response 404
72 end
72 end
73
73
74 def test_show_unexistent_page_with_edit_right
74 def test_show_unexistent_page_with_edit_right
75 @request.session[:user_id] = 2
75 @request.session[:user_id] = 2
76 get :show, :project_id => 1, :id => 'Unexistent page'
76 get :show, :project_id => 1, :id => 'Unexistent page'
77 assert_response :success
77 assert_response :success
78 assert_template 'edit'
78 assert_template 'edit'
79 end
79 end
80
80
81 def test_create_page
81 def test_create_page
82 @request.session[:user_id] = 2
82 @request.session[:user_id] = 2
83 put :update, :project_id => 1,
83 put :update, :project_id => 1,
84 :id => 'New page',
84 :id => 'New page',
85 :content => {:comments => 'Created the page',
85 :content => {:comments => 'Created the page',
86 :text => "h1. New page\n\nThis is a new page",
86 :text => "h1. New page\n\nThis is a new page",
87 :version => 0}
87 :version => 0}
88 assert_redirected_to :action => 'show', :project_id => 'ecookbook', :id => 'New_page'
88 assert_redirected_to :action => 'show', :project_id => 'ecookbook', :id => 'New_page'
89 page = Project.find(1).wiki.find_page('New page')
89 page = Project.find(1).wiki.find_page('New page')
90 assert !page.new_record?
90 assert !page.new_record?
91 assert_not_nil page.content
91 assert_not_nil page.content
92 assert_equal 'Created the page', page.content.comments
92 assert_equal 'Created the page', page.content.comments
93 end
93 end
94
94
95 def test_create_page_with_attachments
95 def test_create_page_with_attachments
96 @request.session[:user_id] = 2
96 @request.session[:user_id] = 2
97 assert_difference 'WikiPage.count' do
97 assert_difference 'WikiPage.count' do
98 assert_difference 'Attachment.count' do
98 assert_difference 'Attachment.count' do
99 put :update, :project_id => 1,
99 put :update, :project_id => 1,
100 :id => 'New page',
100 :id => 'New page',
101 :content => {:comments => 'Created the page',
101 :content => {:comments => 'Created the page',
102 :text => "h1. New page\n\nThis is a new page",
102 :text => "h1. New page\n\nThis is a new page",
103 :version => 0},
103 :version => 0},
104 :attachments => {'1' => {'file' => uploaded_test_file('testfile.txt', 'text/plain')}}
104 :attachments => {'1' => {'file' => uploaded_test_file('testfile.txt', 'text/plain')}}
105 end
105 end
106 end
106 end
107 page = Project.find(1).wiki.find_page('New page')
107 page = Project.find(1).wiki.find_page('New page')
108 assert_equal 1, page.attachments.count
108 assert_equal 1, page.attachments.count
109 assert_equal 'testfile.txt', page.attachments.first.filename
109 assert_equal 'testfile.txt', page.attachments.first.filename
110 end
110 end
111
111
112 def test_update_page
113 @request.session[:user_id] = 2
114 assert_no_difference 'WikiPage.count' do
115 assert_no_difference 'WikiContent.count' do
116 assert_difference 'WikiContent::Version.count' do
117 put :update, :project_id => 1,
118 :id => 'Another_page',
119 :content => {
120 :comments => "my comments",
121 :text => "edited",
122 :version => 1
123 }
124 end
125 end
126 end
127 assert_redirected_to '/projects/ecookbook/wiki/Another_page'
128
129 page = Wiki.find(1).pages.find_by_title('Another_page')
130 assert_equal "edited", page.content.text
131 assert_equal 2, page.content.version
132 assert_equal "my comments", page.content.comments
133 end
134
135 def test_update_page_with_failure
136 @request.session[:user_id] = 2
137 assert_no_difference 'WikiPage.count' do
138 assert_no_difference 'WikiContent.count' do
139 assert_no_difference 'WikiContent::Version.count' do
140 put :update, :project_id => 1,
141 :id => 'Another_page',
142 :content => {
143 :comments => 'a' * 300, # failure here, comment is too long
144 :text => 'edited',
145 :version => 1
146 }
147 end
148 end
149 end
150 assert_response :success
151 assert_template 'edit'
152
153 assert_error_tag :descendant => {:content => /Comment is too long/}
154 assert_tag :tag => 'textarea', :attributes => {:id => 'content_text'}, :content => 'edited'
155 assert_tag :tag => 'input', :attributes => {:id => 'content_version', :value => '1'}
156 end
157
112 def test_preview
158 def test_preview
113 @request.session[:user_id] = 2
159 @request.session[:user_id] = 2
114 xhr :post, :preview, :project_id => 1, :id => 'CookBook_documentation',
160 xhr :post, :preview, :project_id => 1, :id => 'CookBook_documentation',
115 :content => { :comments => '',
161 :content => { :comments => '',
116 :text => 'this is a *previewed text*',
162 :text => 'this is a *previewed text*',
117 :version => 3 }
163 :version => 3 }
118 assert_response :success
164 assert_response :success
119 assert_template 'common/_preview'
165 assert_template 'common/_preview'
120 assert_tag :tag => 'strong', :content => /previewed text/
166 assert_tag :tag => 'strong', :content => /previewed text/
121 end
167 end
122
168
123 def test_preview_new_page
169 def test_preview_new_page
124 @request.session[:user_id] = 2
170 @request.session[:user_id] = 2
125 xhr :post, :preview, :project_id => 1, :id => 'New page',
171 xhr :post, :preview, :project_id => 1, :id => 'New page',
126 :content => { :text => 'h1. New page',
172 :content => { :text => 'h1. New page',
127 :comments => '',
173 :comments => '',
128 :version => 0 }
174 :version => 0 }
129 assert_response :success
175 assert_response :success
130 assert_template 'common/_preview'
176 assert_template 'common/_preview'
131 assert_tag :tag => 'h1', :content => /New page/
177 assert_tag :tag => 'h1', :content => /New page/
132 end
178 end
133
179
134 def test_history
180 def test_history
135 get :history, :project_id => 1, :id => 'CookBook_documentation'
181 get :history, :project_id => 1, :id => 'CookBook_documentation'
136 assert_response :success
182 assert_response :success
137 assert_template 'history'
183 assert_template 'history'
138 assert_not_nil assigns(:versions)
184 assert_not_nil assigns(:versions)
139 assert_equal 3, assigns(:versions).size
185 assert_equal 3, assigns(:versions).size
140 assert_select "input[type=submit][name=commit]"
186 assert_select "input[type=submit][name=commit]"
141 end
187 end
142
188
143 def test_history_with_one_version
189 def test_history_with_one_version
144 get :history, :project_id => 1, :id => 'Another_page'
190 get :history, :project_id => 1, :id => 'Another_page'
145 assert_response :success
191 assert_response :success
146 assert_template 'history'
192 assert_template 'history'
147 assert_not_nil assigns(:versions)
193 assert_not_nil assigns(:versions)
148 assert_equal 1, assigns(:versions).size
194 assert_equal 1, assigns(:versions).size
149 assert_select "input[type=submit][name=commit]", false
195 assert_select "input[type=submit][name=commit]", false
150 end
196 end
151
197
152 def test_diff
198 def test_diff
153 get :diff, :project_id => 1, :id => 'CookBook_documentation', :version => 2, :version_from => 1
199 get :diff, :project_id => 1, :id => 'CookBook_documentation', :version => 2, :version_from => 1
154 assert_response :success
200 assert_response :success
155 assert_template 'diff'
201 assert_template 'diff'
156 assert_tag :tag => 'span', :attributes => { :class => 'diff_in'},
202 assert_tag :tag => 'span', :attributes => { :class => 'diff_in'},
157 :content => /updated/
203 :content => /updated/
158 end
204 end
159
205
160 def test_annotate
206 def test_annotate
161 get :annotate, :project_id => 1, :id => 'CookBook_documentation', :version => 2
207 get :annotate, :project_id => 1, :id => 'CookBook_documentation', :version => 2
162 assert_response :success
208 assert_response :success
163 assert_template 'annotate'
209 assert_template 'annotate'
164 # Line 1
210 # Line 1
165 assert_tag :tag => 'tr', :child => { :tag => 'th', :attributes => {:class => 'line-num'}, :content => '1' },
211 assert_tag :tag => 'tr', :child => { :tag => 'th', :attributes => {:class => 'line-num'}, :content => '1' },
166 :child => { :tag => 'td', :attributes => {:class => 'author'}, :content => /John Smith/ },
212 :child => { :tag => 'td', :attributes => {:class => 'author'}, :content => /John Smith/ },
167 :child => { :tag => 'td', :content => /h1\. CookBook documentation/ }
213 :child => { :tag => 'td', :content => /h1\. CookBook documentation/ }
168 # Line 2
214 # Line 2
169 assert_tag :tag => 'tr', :child => { :tag => 'th', :attributes => {:class => 'line-num'}, :content => '2' },
215 assert_tag :tag => 'tr', :child => { :tag => 'th', :attributes => {:class => 'line-num'}, :content => '2' },
170 :child => { :tag => 'td', :attributes => {:class => 'author'}, :content => /redMine Admin/ },
216 :child => { :tag => 'td', :attributes => {:class => 'author'}, :content => /redMine Admin/ },
171 :child => { :tag => 'td', :content => /Some updated \[\[documentation\]\] here/ }
217 :child => { :tag => 'td', :content => /Some updated \[\[documentation\]\] here/ }
172 end
218 end
173
219
174 def test_get_rename
220 def test_get_rename
175 @request.session[:user_id] = 2
221 @request.session[:user_id] = 2
176 get :rename, :project_id => 1, :id => 'Another_page'
222 get :rename, :project_id => 1, :id => 'Another_page'
177 assert_response :success
223 assert_response :success
178 assert_template 'rename'
224 assert_template 'rename'
179 assert_tag 'option',
225 assert_tag 'option',
180 :attributes => {:value => ''},
226 :attributes => {:value => ''},
181 :content => '',
227 :content => '',
182 :parent => {:tag => 'select', :attributes => {:name => 'wiki_page[parent_id]'}}
228 :parent => {:tag => 'select', :attributes => {:name => 'wiki_page[parent_id]'}}
183 assert_no_tag 'option',
229 assert_no_tag 'option',
184 :attributes => {:selected => 'selected'},
230 :attributes => {:selected => 'selected'},
185 :parent => {:tag => 'select', :attributes => {:name => 'wiki_page[parent_id]'}}
231 :parent => {:tag => 'select', :attributes => {:name => 'wiki_page[parent_id]'}}
186 end
232 end
187
233
188 def test_get_rename_child_page
234 def test_get_rename_child_page
189 @request.session[:user_id] = 2
235 @request.session[:user_id] = 2
190 get :rename, :project_id => 1, :id => 'Child_1'
236 get :rename, :project_id => 1, :id => 'Child_1'
191 assert_response :success
237 assert_response :success
192 assert_template 'rename'
238 assert_template 'rename'
193 assert_tag 'option',
239 assert_tag 'option',
194 :attributes => {:value => ''},
240 :attributes => {:value => ''},
195 :content => '',
241 :content => '',
196 :parent => {:tag => 'select', :attributes => {:name => 'wiki_page[parent_id]'}}
242 :parent => {:tag => 'select', :attributes => {:name => 'wiki_page[parent_id]'}}
197 assert_tag 'option',
243 assert_tag 'option',
198 :attributes => {:value => '2', :selected => 'selected'},
244 :attributes => {:value => '2', :selected => 'selected'},
199 :content => /Another page/,
245 :content => /Another page/,
200 :parent => {
246 :parent => {
201 :tag => 'select',
247 :tag => 'select',
202 :attributes => {:name => 'wiki_page[parent_id]'}
248 :attributes => {:name => 'wiki_page[parent_id]'}
203 }
249 }
204 end
250 end
205
251
206 def test_rename_with_redirect
252 def test_rename_with_redirect
207 @request.session[:user_id] = 2
253 @request.session[:user_id] = 2
208 post :rename, :project_id => 1, :id => 'Another_page',
254 post :rename, :project_id => 1, :id => 'Another_page',
209 :wiki_page => { :title => 'Another renamed page',
255 :wiki_page => { :title => 'Another renamed page',
210 :redirect_existing_links => 1 }
256 :redirect_existing_links => 1 }
211 assert_redirected_to :action => 'show', :project_id => 'ecookbook', :id => 'Another_renamed_page'
257 assert_redirected_to :action => 'show', :project_id => 'ecookbook', :id => 'Another_renamed_page'
212 wiki = Project.find(1).wiki
258 wiki = Project.find(1).wiki
213 # Check redirects
259 # Check redirects
214 assert_not_nil wiki.find_page('Another page')
260 assert_not_nil wiki.find_page('Another page')
215 assert_nil wiki.find_page('Another page', :with_redirect => false)
261 assert_nil wiki.find_page('Another page', :with_redirect => false)
216 end
262 end
217
263
218 def test_rename_without_redirect
264 def test_rename_without_redirect
219 @request.session[:user_id] = 2
265 @request.session[:user_id] = 2
220 post :rename, :project_id => 1, :id => 'Another_page',
266 post :rename, :project_id => 1, :id => 'Another_page',
221 :wiki_page => { :title => 'Another renamed page',
267 :wiki_page => { :title => 'Another renamed page',
222 :redirect_existing_links => "0" }
268 :redirect_existing_links => "0" }
223 assert_redirected_to :action => 'show', :project_id => 'ecookbook', :id => 'Another_renamed_page'
269 assert_redirected_to :action => 'show', :project_id => 'ecookbook', :id => 'Another_renamed_page'
224 wiki = Project.find(1).wiki
270 wiki = Project.find(1).wiki
225 # Check that there's no redirects
271 # Check that there's no redirects
226 assert_nil wiki.find_page('Another page')
272 assert_nil wiki.find_page('Another page')
227 end
273 end
228
274
229 def test_rename_with_parent_assignment
275 def test_rename_with_parent_assignment
230 @request.session[:user_id] = 2
276 @request.session[:user_id] = 2
231 post :rename, :project_id => 1, :id => 'Another_page',
277 post :rename, :project_id => 1, :id => 'Another_page',
232 :wiki_page => { :title => 'Another page', :redirect_existing_links => "0", :parent_id => '4' }
278 :wiki_page => { :title => 'Another page', :redirect_existing_links => "0", :parent_id => '4' }
233 assert_redirected_to :action => 'show', :project_id => 'ecookbook', :id => 'Another_page'
279 assert_redirected_to :action => 'show', :project_id => 'ecookbook', :id => 'Another_page'
234 assert_equal WikiPage.find(4), WikiPage.find_by_title('Another_page').parent
280 assert_equal WikiPage.find(4), WikiPage.find_by_title('Another_page').parent
235 end
281 end
236
282
237 def test_rename_with_parent_unassignment
283 def test_rename_with_parent_unassignment
238 @request.session[:user_id] = 2
284 @request.session[:user_id] = 2
239 post :rename, :project_id => 1, :id => 'Child_1',
285 post :rename, :project_id => 1, :id => 'Child_1',
240 :wiki_page => { :title => 'Child 1', :redirect_existing_links => "0", :parent_id => '' }
286 :wiki_page => { :title => 'Child 1', :redirect_existing_links => "0", :parent_id => '' }
241 assert_redirected_to :action => 'show', :project_id => 'ecookbook', :id => 'Child_1'
287 assert_redirected_to :action => 'show', :project_id => 'ecookbook', :id => 'Child_1'
242 assert_nil WikiPage.find_by_title('Child_1').parent
288 assert_nil WikiPage.find_by_title('Child_1').parent
243 end
289 end
244
290
245 def test_destroy_child
291 def test_destroy_child
246 @request.session[:user_id] = 2
292 @request.session[:user_id] = 2
247 delete :destroy, :project_id => 1, :id => 'Child_1'
293 delete :destroy, :project_id => 1, :id => 'Child_1'
248 assert_redirected_to :action => 'index', :project_id => 'ecookbook'
294 assert_redirected_to :action => 'index', :project_id => 'ecookbook'
249 end
295 end
250
296
251 def test_destroy_parent
297 def test_destroy_parent
252 @request.session[:user_id] = 2
298 @request.session[:user_id] = 2
253 assert_no_difference('WikiPage.count') do
299 assert_no_difference('WikiPage.count') do
254 delete :destroy, :project_id => 1, :id => 'Another_page'
300 delete :destroy, :project_id => 1, :id => 'Another_page'
255 end
301 end
256 assert_response :success
302 assert_response :success
257 assert_template 'destroy'
303 assert_template 'destroy'
258 end
304 end
259
305
260 def test_destroy_parent_with_nullify
306 def test_destroy_parent_with_nullify
261 @request.session[:user_id] = 2
307 @request.session[:user_id] = 2
262 assert_difference('WikiPage.count', -1) do
308 assert_difference('WikiPage.count', -1) do
263 delete :destroy, :project_id => 1, :id => 'Another_page', :todo => 'nullify'
309 delete :destroy, :project_id => 1, :id => 'Another_page', :todo => 'nullify'
264 end
310 end
265 assert_redirected_to :action => 'index', :project_id => 'ecookbook'
311 assert_redirected_to :action => 'index', :project_id => 'ecookbook'
266 assert_nil WikiPage.find_by_id(2)
312 assert_nil WikiPage.find_by_id(2)
267 end
313 end
268
314
269 def test_destroy_parent_with_cascade
315 def test_destroy_parent_with_cascade
270 @request.session[:user_id] = 2
316 @request.session[:user_id] = 2
271 assert_difference('WikiPage.count', -3) do
317 assert_difference('WikiPage.count', -3) do
272 delete :destroy, :project_id => 1, :id => 'Another_page', :todo => 'destroy'
318 delete :destroy, :project_id => 1, :id => 'Another_page', :todo => 'destroy'
273 end
319 end
274 assert_redirected_to :action => 'index', :project_id => 'ecookbook'
320 assert_redirected_to :action => 'index', :project_id => 'ecookbook'
275 assert_nil WikiPage.find_by_id(2)
321 assert_nil WikiPage.find_by_id(2)
276 assert_nil WikiPage.find_by_id(5)
322 assert_nil WikiPage.find_by_id(5)
277 end
323 end
278
324
279 def test_destroy_parent_with_reassign
325 def test_destroy_parent_with_reassign
280 @request.session[:user_id] = 2
326 @request.session[:user_id] = 2
281 assert_difference('WikiPage.count', -1) do
327 assert_difference('WikiPage.count', -1) do
282 delete :destroy, :project_id => 1, :id => 'Another_page', :todo => 'reassign', :reassign_to_id => 1
328 delete :destroy, :project_id => 1, :id => 'Another_page', :todo => 'reassign', :reassign_to_id => 1
283 end
329 end
284 assert_redirected_to :action => 'index', :project_id => 'ecookbook'
330 assert_redirected_to :action => 'index', :project_id => 'ecookbook'
285 assert_nil WikiPage.find_by_id(2)
331 assert_nil WikiPage.find_by_id(2)
286 assert_equal WikiPage.find(1), WikiPage.find_by_id(5).parent
332 assert_equal WikiPage.find(1), WikiPage.find_by_id(5).parent
287 end
333 end
288
334
289 def test_index
335 def test_index
290 get :index, :project_id => 'ecookbook'
336 get :index, :project_id => 'ecookbook'
291 assert_response :success
337 assert_response :success
292 assert_template 'index'
338 assert_template 'index'
293 pages = assigns(:pages)
339 pages = assigns(:pages)
294 assert_not_nil pages
340 assert_not_nil pages
295 assert_equal Project.find(1).wiki.pages.size, pages.size
341 assert_equal Project.find(1).wiki.pages.size, pages.size
296
342
297 assert_tag :ul, :attributes => { :class => 'pages-hierarchy' },
343 assert_tag :ul, :attributes => { :class => 'pages-hierarchy' },
298 :child => { :tag => 'li', :child => { :tag => 'a', :attributes => { :href => '/projects/ecookbook/wiki/CookBook_documentation' },
344 :child => { :tag => 'li', :child => { :tag => 'a', :attributes => { :href => '/projects/ecookbook/wiki/CookBook_documentation' },
299 :content => 'CookBook documentation' },
345 :content => 'CookBook documentation' },
300 :child => { :tag => 'ul',
346 :child => { :tag => 'ul',
301 :child => { :tag => 'li',
347 :child => { :tag => 'li',
302 :child => { :tag => 'a', :attributes => { :href => '/projects/ecookbook/wiki/Page_with_an_inline_image' },
348 :child => { :tag => 'a', :attributes => { :href => '/projects/ecookbook/wiki/Page_with_an_inline_image' },
303 :content => 'Page with an inline image' } } } },
349 :content => 'Page with an inline image' } } } },
304 :child => { :tag => 'li', :child => { :tag => 'a', :attributes => { :href => '/projects/ecookbook/wiki/Another_page' },
350 :child => { :tag => 'li', :child => { :tag => 'a', :attributes => { :href => '/projects/ecookbook/wiki/Another_page' },
305 :content => 'Another page' } }
351 :content => 'Another page' } }
306 end
352 end
307
353
308 context "GET :export" do
354 context "GET :export" do
309 context "with an authorized user to export the wiki" do
355 context "with an authorized user to export the wiki" do
310 setup do
356 setup do
311 @request.session[:user_id] = 2
357 @request.session[:user_id] = 2
312 get :export, :project_id => 'ecookbook'
358 get :export, :project_id => 'ecookbook'
313 end
359 end
314
360
315 should_respond_with :success
361 should_respond_with :success
316 should_assign_to :pages
362 should_assign_to :pages
317 should_respond_with_content_type "text/html"
363 should_respond_with_content_type "text/html"
318 should "export all of the wiki pages to a single html file" do
364 should "export all of the wiki pages to a single html file" do
319 assert_select "a[name=?]", "CookBook_documentation"
365 assert_select "a[name=?]", "CookBook_documentation"
320 assert_select "a[name=?]", "Another_page"
366 assert_select "a[name=?]", "Another_page"
321 assert_select "a[name=?]", "Page_with_an_inline_image"
367 assert_select "a[name=?]", "Page_with_an_inline_image"
322 end
368 end
323
369
324 end
370 end
325
371
326 context "with an unauthorized user" do
372 context "with an unauthorized user" do
327 setup do
373 setup do
328 get :export, :project_id => 'ecookbook'
374 get :export, :project_id => 'ecookbook'
329
375
330 should_respond_with :redirect
376 should_respond_with :redirect
331 should_redirect_to('wiki index') { {:action => 'show', :project_id => @project, :id => nil} }
377 should_redirect_to('wiki index') { {:action => 'show', :project_id => @project, :id => nil} }
332 end
378 end
333 end
379 end
334 end
380 end
335
381
336 context "GET :date_index" do
382 context "GET :date_index" do
337 setup do
383 setup do
338 get :date_index, :project_id => 'ecookbook'
384 get :date_index, :project_id => 'ecookbook'
339 end
385 end
340
386
341 should_respond_with :success
387 should_respond_with :success
342 should_assign_to :pages
388 should_assign_to :pages
343 should_assign_to :pages_by_date
389 should_assign_to :pages_by_date
344 should_render_template 'wiki/date_index'
390 should_render_template 'wiki/date_index'
345
391
346 end
392 end
347
393
348 def test_not_found
394 def test_not_found
349 get :show, :project_id => 999
395 get :show, :project_id => 999
350 assert_response 404
396 assert_response 404
351 end
397 end
352
398
353 def test_protect_page
399 def test_protect_page
354 page = WikiPage.find_by_wiki_id_and_title(1, 'Another_page')
400 page = WikiPage.find_by_wiki_id_and_title(1, 'Another_page')
355 assert !page.protected?
401 assert !page.protected?
356 @request.session[:user_id] = 2
402 @request.session[:user_id] = 2
357 post :protect, :project_id => 1, :id => page.title, :protected => '1'
403 post :protect, :project_id => 1, :id => page.title, :protected => '1'
358 assert_redirected_to :action => 'show', :project_id => 'ecookbook', :id => 'Another_page'
404 assert_redirected_to :action => 'show', :project_id => 'ecookbook', :id => 'Another_page'
359 assert page.reload.protected?
405 assert page.reload.protected?
360 end
406 end
361
407
362 def test_unprotect_page
408 def test_unprotect_page
363 page = WikiPage.find_by_wiki_id_and_title(1, 'CookBook_documentation')
409 page = WikiPage.find_by_wiki_id_and_title(1, 'CookBook_documentation')
364 assert page.protected?
410 assert page.protected?
365 @request.session[:user_id] = 2
411 @request.session[:user_id] = 2
366 post :protect, :project_id => 1, :id => page.title, :protected => '0'
412 post :protect, :project_id => 1, :id => page.title, :protected => '0'
367 assert_redirected_to :action => 'show', :project_id => 'ecookbook', :id => 'CookBook_documentation'
413 assert_redirected_to :action => 'show', :project_id => 'ecookbook', :id => 'CookBook_documentation'
368 assert !page.reload.protected?
414 assert !page.reload.protected?
369 end
415 end
370
416
371 def test_show_page_with_edit_link
417 def test_show_page_with_edit_link
372 @request.session[:user_id] = 2
418 @request.session[:user_id] = 2
373 get :show, :project_id => 1
419 get :show, :project_id => 1
374 assert_response :success
420 assert_response :success
375 assert_template 'show'
421 assert_template 'show'
376 assert_tag :tag => 'a', :attributes => { :href => '/projects/1/wiki/CookBook_documentation/edit' }
422 assert_tag :tag => 'a', :attributes => { :href => '/projects/1/wiki/CookBook_documentation/edit' }
377 end
423 end
378
424
379 def test_show_page_without_edit_link
425 def test_show_page_without_edit_link
380 @request.session[:user_id] = 4
426 @request.session[:user_id] = 4
381 get :show, :project_id => 1
427 get :show, :project_id => 1
382 assert_response :success
428 assert_response :success
383 assert_template 'show'
429 assert_template 'show'
384 assert_no_tag :tag => 'a', :attributes => { :href => '/projects/1/wiki/CookBook_documentation/edit' }
430 assert_no_tag :tag => 'a', :attributes => { :href => '/projects/1/wiki/CookBook_documentation/edit' }
385 end
431 end
386
432
387 def test_edit_unprotected_page
433 def test_edit_unprotected_page
388 # Non members can edit unprotected wiki pages
434 # Non members can edit unprotected wiki pages
389 @request.session[:user_id] = 4
435 @request.session[:user_id] = 4
390 get :edit, :project_id => 1, :id => 'Another_page'
436 get :edit, :project_id => 1, :id => 'Another_page'
391 assert_response :success
437 assert_response :success
392 assert_template 'edit'
438 assert_template 'edit'
393 end
439 end
394
440
395 def test_edit_protected_page_by_nonmember
441 def test_edit_protected_page_by_nonmember
396 # Non members can't edit protected wiki pages
442 # Non members can't edit protected wiki pages
397 @request.session[:user_id] = 4
443 @request.session[:user_id] = 4
398 get :edit, :project_id => 1, :id => 'CookBook_documentation'
444 get :edit, :project_id => 1, :id => 'CookBook_documentation'
399 assert_response 403
445 assert_response 403
400 end
446 end
401
447
402 def test_edit_protected_page_by_member
448 def test_edit_protected_page_by_member
403 @request.session[:user_id] = 2
449 @request.session[:user_id] = 2
404 get :edit, :project_id => 1, :id => 'CookBook_documentation'
450 get :edit, :project_id => 1, :id => 'CookBook_documentation'
405 assert_response :success
451 assert_response :success
406 assert_template 'edit'
452 assert_template 'edit'
407 end
453 end
408
454
409 def test_history_of_non_existing_page_should_return_404
455 def test_history_of_non_existing_page_should_return_404
410 get :history, :project_id => 1, :id => 'Unknown_page'
456 get :history, :project_id => 1, :id => 'Unknown_page'
411 assert_response 404
457 assert_response 404
412 end
458 end
413 end
459 end
@@ -1,420 +1,420
1 # redMine - project management software
1 # redMine - project management software
2 # Copyright (C) 2006 Jean-Philippe Lang
2 # Copyright (C) 2006 Jean-Philippe Lang
3 #
3 #
4 # This program is free software; you can redistribute it and/or
4 # This program is free software; you can redistribute it and/or
5 # modify it under the terms of the GNU General Public License
5 # modify it under the terms of the GNU General Public License
6 # as published by the Free Software Foundation; either version 2
6 # as published by the Free Software Foundation; either version 2
7 # of the License, or (at your option) any later version.
7 # of the License, or (at your option) any later version.
8 #
8 #
9 # This program is distributed in the hope that it will be useful,
9 # This program is distributed in the hope that it will be useful,
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 # GNU General Public License for more details.
12 # GNU General Public License for more details.
13 #
13 #
14 # You should have received a copy of the GNU General Public License
14 # You should have received a copy of the GNU General Public License
15 # along with this program; if not, write to the Free Software
15 # along with this program; if not, write to the Free Software
16 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
16 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17
17
18 ENV["RAILS_ENV"] = "test"
18 ENV["RAILS_ENV"] = "test"
19 require File.expand_path(File.dirname(__FILE__) + "/../config/environment")
19 require File.expand_path(File.dirname(__FILE__) + "/../config/environment")
20 require 'test_help'
20 require 'test_help'
21 require File.expand_path(File.dirname(__FILE__) + '/helper_testcase')
21 require File.expand_path(File.dirname(__FILE__) + '/helper_testcase')
22 require File.join(RAILS_ROOT,'test', 'mocks', 'open_id_authentication_mock.rb')
22 require File.join(RAILS_ROOT,'test', 'mocks', 'open_id_authentication_mock.rb')
23
23
24 require File.expand_path(File.dirname(__FILE__) + '/object_daddy_helpers')
24 require File.expand_path(File.dirname(__FILE__) + '/object_daddy_helpers')
25 include ObjectDaddyHelpers
25 include ObjectDaddyHelpers
26
26
27 class ActiveSupport::TestCase
27 class ActiveSupport::TestCase
28 # Transactional fixtures accelerate your tests by wrapping each test method
28 # Transactional fixtures accelerate your tests by wrapping each test method
29 # in a transaction that's rolled back on completion. This ensures that the
29 # in a transaction that's rolled back on completion. This ensures that the
30 # test database remains unchanged so your fixtures don't have to be reloaded
30 # test database remains unchanged so your fixtures don't have to be reloaded
31 # between every test method. Fewer database queries means faster tests.
31 # between every test method. Fewer database queries means faster tests.
32 #
32 #
33 # Read Mike Clark's excellent walkthrough at
33 # Read Mike Clark's excellent walkthrough at
34 # http://clarkware.com/cgi/blosxom/2005/10/24#Rails10FastTesting
34 # http://clarkware.com/cgi/blosxom/2005/10/24#Rails10FastTesting
35 #
35 #
36 # Every Active Record database supports transactions except MyISAM tables
36 # Every Active Record database supports transactions except MyISAM tables
37 # in MySQL. Turn off transactional fixtures in this case; however, if you
37 # in MySQL. Turn off transactional fixtures in this case; however, if you
38 # don't care one way or the other, switching from MyISAM to InnoDB tables
38 # don't care one way or the other, switching from MyISAM to InnoDB tables
39 # is recommended.
39 # is recommended.
40 self.use_transactional_fixtures = true
40 self.use_transactional_fixtures = true
41
41
42 # Instantiated fixtures are slow, but give you @david where otherwise you
42 # Instantiated fixtures are slow, but give you @david where otherwise you
43 # would need people(:david). If you don't want to migrate your existing
43 # would need people(:david). If you don't want to migrate your existing
44 # test cases which use the @david style and don't mind the speed hit (each
44 # test cases which use the @david style and don't mind the speed hit (each
45 # instantiated fixtures translates to a database query per test method),
45 # instantiated fixtures translates to a database query per test method),
46 # then set this back to true.
46 # then set this back to true.
47 self.use_instantiated_fixtures = false
47 self.use_instantiated_fixtures = false
48
48
49 # Add more helper methods to be used by all tests here...
49 # Add more helper methods to be used by all tests here...
50
50
51 def log_user(login, password)
51 def log_user(login, password)
52 User.anonymous
52 User.anonymous
53 get "/login"
53 get "/login"
54 assert_equal nil, session[:user_id]
54 assert_equal nil, session[:user_id]
55 assert_response :success
55 assert_response :success
56 assert_template "account/login"
56 assert_template "account/login"
57 post "/login", :username => login, :password => password
57 post "/login", :username => login, :password => password
58 assert_equal login, User.find(session[:user_id]).login
58 assert_equal login, User.find(session[:user_id]).login
59 end
59 end
60
60
61 def uploaded_test_file(name, mime)
61 def uploaded_test_file(name, mime)
62 ActionController::TestUploadedFile.new(ActiveSupport::TestCase.fixture_path + "/files/#{name}", mime)
62 ActionController::TestUploadedFile.new(ActiveSupport::TestCase.fixture_path + "/files/#{name}", mime)
63 end
63 end
64
64
65 # Mock out a file
65 # Mock out a file
66 def self.mock_file
66 def self.mock_file
67 file = 'a_file.png'
67 file = 'a_file.png'
68 file.stubs(:size).returns(32)
68 file.stubs(:size).returns(32)
69 file.stubs(:original_filename).returns('a_file.png')
69 file.stubs(:original_filename).returns('a_file.png')
70 file.stubs(:content_type).returns('image/png')
70 file.stubs(:content_type).returns('image/png')
71 file.stubs(:read).returns(false)
71 file.stubs(:read).returns(false)
72 file
72 file
73 end
73 end
74
74
75 def mock_file
75 def mock_file
76 self.class.mock_file
76 self.class.mock_file
77 end
77 end
78
78
79 # Use a temporary directory for attachment related tests
79 # Use a temporary directory for attachment related tests
80 def set_tmp_attachments_directory
80 def set_tmp_attachments_directory
81 Dir.mkdir "#{RAILS_ROOT}/tmp/test" unless File.directory?("#{RAILS_ROOT}/tmp/test")
81 Dir.mkdir "#{RAILS_ROOT}/tmp/test" unless File.directory?("#{RAILS_ROOT}/tmp/test")
82 Dir.mkdir "#{RAILS_ROOT}/tmp/test/attachments" unless File.directory?("#{RAILS_ROOT}/tmp/test/attachments")
82 Dir.mkdir "#{RAILS_ROOT}/tmp/test/attachments" unless File.directory?("#{RAILS_ROOT}/tmp/test/attachments")
83 Attachment.storage_path = "#{RAILS_ROOT}/tmp/test/attachments"
83 Attachment.storage_path = "#{RAILS_ROOT}/tmp/test/attachments"
84 end
84 end
85
85
86 def with_settings(options, &block)
86 def with_settings(options, &block)
87 saved_settings = options.keys.inject({}) {|h, k| h[k] = Setting[k].dup; h}
87 saved_settings = options.keys.inject({}) {|h, k| h[k] = Setting[k].dup; h}
88 options.each {|k, v| Setting[k] = v}
88 options.each {|k, v| Setting[k] = v}
89 yield
89 yield
90 saved_settings.each {|k, v| Setting[k] = v}
90 saved_settings.each {|k, v| Setting[k] = v}
91 end
91 end
92
92
93 def change_user_password(login, new_password)
93 def change_user_password(login, new_password)
94 user = User.first(:conditions => {:login => login})
94 user = User.first(:conditions => {:login => login})
95 user.password, user.password_confirmation = new_password, new_password
95 user.password, user.password_confirmation = new_password, new_password
96 user.save!
96 user.save!
97 end
97 end
98
98
99 def self.ldap_configured?
99 def self.ldap_configured?
100 @test_ldap = Net::LDAP.new(:host => '127.0.0.1', :port => 389)
100 @test_ldap = Net::LDAP.new(:host => '127.0.0.1', :port => 389)
101 return @test_ldap.bind
101 return @test_ldap.bind
102 rescue Exception => e
102 rescue Exception => e
103 # LDAP is not listening
103 # LDAP is not listening
104 return nil
104 return nil
105 end
105 end
106
106
107 # Returns the path to the test +vendor+ repository
107 # Returns the path to the test +vendor+ repository
108 def self.repository_path(vendor)
108 def self.repository_path(vendor)
109 File.join(RAILS_ROOT.gsub(%r{config\/\.\.}, ''), "/tmp/test/#{vendor.downcase}_repository")
109 File.join(RAILS_ROOT.gsub(%r{config\/\.\.}, ''), "/tmp/test/#{vendor.downcase}_repository")
110 end
110 end
111
111
112 # Returns true if the +vendor+ test repository is configured
112 # Returns true if the +vendor+ test repository is configured
113 def self.repository_configured?(vendor)
113 def self.repository_configured?(vendor)
114 File.directory?(repository_path(vendor))
114 File.directory?(repository_path(vendor))
115 end
115 end
116
116
117 def assert_error_tag(options={})
117 def assert_error_tag(options={})
118 assert_tag({:tag => 'p', :attributes => { :id => 'errorExplanation' }}.merge(options))
118 assert_tag({:attributes => { :id => 'errorExplanation' }}.merge(options))
119 end
119 end
120
120
121 # Shoulda macros
121 # Shoulda macros
122 def self.should_render_404
122 def self.should_render_404
123 should_respond_with :not_found
123 should_respond_with :not_found
124 should_render_template 'common/error'
124 should_render_template 'common/error'
125 end
125 end
126
126
127 def self.should_have_before_filter(expected_method, options = {})
127 def self.should_have_before_filter(expected_method, options = {})
128 should_have_filter('before', expected_method, options)
128 should_have_filter('before', expected_method, options)
129 end
129 end
130
130
131 def self.should_have_after_filter(expected_method, options = {})
131 def self.should_have_after_filter(expected_method, options = {})
132 should_have_filter('after', expected_method, options)
132 should_have_filter('after', expected_method, options)
133 end
133 end
134
134
135 def self.should_have_filter(filter_type, expected_method, options)
135 def self.should_have_filter(filter_type, expected_method, options)
136 description = "have #{filter_type}_filter :#{expected_method}"
136 description = "have #{filter_type}_filter :#{expected_method}"
137 description << " with #{options.inspect}" unless options.empty?
137 description << " with #{options.inspect}" unless options.empty?
138
138
139 should description do
139 should description do
140 klass = "action_controller/filters/#{filter_type}_filter".classify.constantize
140 klass = "action_controller/filters/#{filter_type}_filter".classify.constantize
141 expected = klass.new(:filter, expected_method.to_sym, options)
141 expected = klass.new(:filter, expected_method.to_sym, options)
142 assert_equal 1, @controller.class.filter_chain.select { |filter|
142 assert_equal 1, @controller.class.filter_chain.select { |filter|
143 filter.method == expected.method && filter.kind == expected.kind &&
143 filter.method == expected.method && filter.kind == expected.kind &&
144 filter.options == expected.options && filter.class == expected.class
144 filter.options == expected.options && filter.class == expected.class
145 }.size
145 }.size
146 end
146 end
147 end
147 end
148
148
149 def self.should_show_the_old_and_new_values_for(prop_key, model, &block)
149 def self.should_show_the_old_and_new_values_for(prop_key, model, &block)
150 context "" do
150 context "" do
151 setup do
151 setup do
152 if block_given?
152 if block_given?
153 instance_eval &block
153 instance_eval &block
154 else
154 else
155 @old_value = model.generate!
155 @old_value = model.generate!
156 @new_value = model.generate!
156 @new_value = model.generate!
157 end
157 end
158 end
158 end
159
159
160 should "use the new value's name" do
160 should "use the new value's name" do
161 @detail = JournalDetail.generate!(:property => 'attr',
161 @detail = JournalDetail.generate!(:property => 'attr',
162 :old_value => @old_value.id,
162 :old_value => @old_value.id,
163 :value => @new_value.id,
163 :value => @new_value.id,
164 :prop_key => prop_key)
164 :prop_key => prop_key)
165
165
166 assert_match @new_value.name, show_detail(@detail, true)
166 assert_match @new_value.name, show_detail(@detail, true)
167 end
167 end
168
168
169 should "use the old value's name" do
169 should "use the old value's name" do
170 @detail = JournalDetail.generate!(:property => 'attr',
170 @detail = JournalDetail.generate!(:property => 'attr',
171 :old_value => @old_value.id,
171 :old_value => @old_value.id,
172 :value => @new_value.id,
172 :value => @new_value.id,
173 :prop_key => prop_key)
173 :prop_key => prop_key)
174
174
175 assert_match @old_value.name, show_detail(@detail, true)
175 assert_match @old_value.name, show_detail(@detail, true)
176 end
176 end
177 end
177 end
178 end
178 end
179
179
180 def self.should_create_a_new_user(&block)
180 def self.should_create_a_new_user(&block)
181 should "create a new user" do
181 should "create a new user" do
182 user = instance_eval &block
182 user = instance_eval &block
183 assert user
183 assert user
184 assert_kind_of User, user
184 assert_kind_of User, user
185 assert !user.new_record?
185 assert !user.new_record?
186 end
186 end
187 end
187 end
188
188
189 # Test that a request allows the three types of API authentication
189 # Test that a request allows the three types of API authentication
190 #
190 #
191 # * HTTP Basic with username and password
191 # * HTTP Basic with username and password
192 # * HTTP Basic with an api key for the username
192 # * HTTP Basic with an api key for the username
193 # * Key based with the key=X parameter
193 # * Key based with the key=X parameter
194 #
194 #
195 # @param [Symbol] http_method the HTTP method for request (:get, :post, :put, :delete)
195 # @param [Symbol] http_method the HTTP method for request (:get, :post, :put, :delete)
196 # @param [String] url the request url
196 # @param [String] url the request url
197 # @param [optional, Hash] parameters additional request parameters
197 # @param [optional, Hash] parameters additional request parameters
198 # @param [optional, Hash] options additional options
198 # @param [optional, Hash] options additional options
199 # @option options [Symbol] :success_code Successful response code (:success)
199 # @option options [Symbol] :success_code Successful response code (:success)
200 # @option options [Symbol] :failure_code Failure response code (:unauthorized)
200 # @option options [Symbol] :failure_code Failure response code (:unauthorized)
201 def self.should_allow_api_authentication(http_method, url, parameters={}, options={})
201 def self.should_allow_api_authentication(http_method, url, parameters={}, options={})
202 should_allow_http_basic_auth_with_username_and_password(http_method, url, parameters, options)
202 should_allow_http_basic_auth_with_username_and_password(http_method, url, parameters, options)
203 should_allow_http_basic_auth_with_key(http_method, url, parameters, options)
203 should_allow_http_basic_auth_with_key(http_method, url, parameters, options)
204 should_allow_key_based_auth(http_method, url, parameters, options)
204 should_allow_key_based_auth(http_method, url, parameters, options)
205 end
205 end
206
206
207 # Test that a request allows the username and password for HTTP BASIC
207 # Test that a request allows the username and password for HTTP BASIC
208 #
208 #
209 # @param [Symbol] http_method the HTTP method for request (:get, :post, :put, :delete)
209 # @param [Symbol] http_method the HTTP method for request (:get, :post, :put, :delete)
210 # @param [String] url the request url
210 # @param [String] url the request url
211 # @param [optional, Hash] parameters additional request parameters
211 # @param [optional, Hash] parameters additional request parameters
212 # @param [optional, Hash] options additional options
212 # @param [optional, Hash] options additional options
213 # @option options [Symbol] :success_code Successful response code (:success)
213 # @option options [Symbol] :success_code Successful response code (:success)
214 # @option options [Symbol] :failure_code Failure response code (:unauthorized)
214 # @option options [Symbol] :failure_code Failure response code (:unauthorized)
215 def self.should_allow_http_basic_auth_with_username_and_password(http_method, url, parameters={}, options={})
215 def self.should_allow_http_basic_auth_with_username_and_password(http_method, url, parameters={}, options={})
216 success_code = options[:success_code] || :success
216 success_code = options[:success_code] || :success
217 failure_code = options[:failure_code] || :unauthorized
217 failure_code = options[:failure_code] || :unauthorized
218
218
219 context "should allow http basic auth using a username and password for #{http_method} #{url}" do
219 context "should allow http basic auth using a username and password for #{http_method} #{url}" do
220 context "with a valid HTTP authentication" do
220 context "with a valid HTTP authentication" do
221 setup do
221 setup do
222 @user = User.generate_with_protected!(:password => 'my_password', :password_confirmation => 'my_password', :admin => true) # Admin so they can access the project
222 @user = User.generate_with_protected!(:password => 'my_password', :password_confirmation => 'my_password', :admin => true) # Admin so they can access the project
223 @authorization = ActionController::HttpAuthentication::Basic.encode_credentials(@user.login, 'my_password')
223 @authorization = ActionController::HttpAuthentication::Basic.encode_credentials(@user.login, 'my_password')
224 send(http_method, url, parameters, {:authorization => @authorization})
224 send(http_method, url, parameters, {:authorization => @authorization})
225 end
225 end
226
226
227 should_respond_with success_code
227 should_respond_with success_code
228 should_respond_with_content_type_based_on_url(url)
228 should_respond_with_content_type_based_on_url(url)
229 should "login as the user" do
229 should "login as the user" do
230 assert_equal @user, User.current
230 assert_equal @user, User.current
231 end
231 end
232 end
232 end
233
233
234 context "with an invalid HTTP authentication" do
234 context "with an invalid HTTP authentication" do
235 setup do
235 setup do
236 @user = User.generate_with_protected!
236 @user = User.generate_with_protected!
237 @authorization = ActionController::HttpAuthentication::Basic.encode_credentials(@user.login, 'wrong_password')
237 @authorization = ActionController::HttpAuthentication::Basic.encode_credentials(@user.login, 'wrong_password')
238 send(http_method, url, parameters, {:authorization => @authorization})
238 send(http_method, url, parameters, {:authorization => @authorization})
239 end
239 end
240
240
241 should_respond_with failure_code
241 should_respond_with failure_code
242 should_respond_with_content_type_based_on_url(url)
242 should_respond_with_content_type_based_on_url(url)
243 should "not login as the user" do
243 should "not login as the user" do
244 assert_equal User.anonymous, User.current
244 assert_equal User.anonymous, User.current
245 end
245 end
246 end
246 end
247
247
248 context "without credentials" do
248 context "without credentials" do
249 setup do
249 setup do
250 send(http_method, url, parameters, {:authorization => ''})
250 send(http_method, url, parameters, {:authorization => ''})
251 end
251 end
252
252
253 should_respond_with failure_code
253 should_respond_with failure_code
254 should_respond_with_content_type_based_on_url(url)
254 should_respond_with_content_type_based_on_url(url)
255 should "include_www_authenticate_header" do
255 should "include_www_authenticate_header" do
256 assert @controller.response.headers.has_key?('WWW-Authenticate')
256 assert @controller.response.headers.has_key?('WWW-Authenticate')
257 end
257 end
258 end
258 end
259 end
259 end
260
260
261 end
261 end
262
262
263 # Test that a request allows the API key with HTTP BASIC
263 # Test that a request allows the API key with HTTP BASIC
264 #
264 #
265 # @param [Symbol] http_method the HTTP method for request (:get, :post, :put, :delete)
265 # @param [Symbol] http_method the HTTP method for request (:get, :post, :put, :delete)
266 # @param [String] url the request url
266 # @param [String] url the request url
267 # @param [optional, Hash] parameters additional request parameters
267 # @param [optional, Hash] parameters additional request parameters
268 # @param [optional, Hash] options additional options
268 # @param [optional, Hash] options additional options
269 # @option options [Symbol] :success_code Successful response code (:success)
269 # @option options [Symbol] :success_code Successful response code (:success)
270 # @option options [Symbol] :failure_code Failure response code (:unauthorized)
270 # @option options [Symbol] :failure_code Failure response code (:unauthorized)
271 def self.should_allow_http_basic_auth_with_key(http_method, url, parameters={}, options={})
271 def self.should_allow_http_basic_auth_with_key(http_method, url, parameters={}, options={})
272 success_code = options[:success_code] || :success
272 success_code = options[:success_code] || :success
273 failure_code = options[:failure_code] || :unauthorized
273 failure_code = options[:failure_code] || :unauthorized
274
274
275 context "should allow http basic auth with a key for #{http_method} #{url}" do
275 context "should allow http basic auth with a key for #{http_method} #{url}" do
276 context "with a valid HTTP authentication using the API token" do
276 context "with a valid HTTP authentication using the API token" do
277 setup do
277 setup do
278 @user = User.generate_with_protected!(:admin => true)
278 @user = User.generate_with_protected!(:admin => true)
279 @token = Token.generate!(:user => @user, :action => 'api')
279 @token = Token.generate!(:user => @user, :action => 'api')
280 @authorization = ActionController::HttpAuthentication::Basic.encode_credentials(@token.value, 'X')
280 @authorization = ActionController::HttpAuthentication::Basic.encode_credentials(@token.value, 'X')
281 send(http_method, url, parameters, {:authorization => @authorization})
281 send(http_method, url, parameters, {:authorization => @authorization})
282 end
282 end
283
283
284 should_respond_with success_code
284 should_respond_with success_code
285 should_respond_with_content_type_based_on_url(url)
285 should_respond_with_content_type_based_on_url(url)
286 should_be_a_valid_response_string_based_on_url(url)
286 should_be_a_valid_response_string_based_on_url(url)
287 should "login as the user" do
287 should "login as the user" do
288 assert_equal @user, User.current
288 assert_equal @user, User.current
289 end
289 end
290 end
290 end
291
291
292 context "with an invalid HTTP authentication" do
292 context "with an invalid HTTP authentication" do
293 setup do
293 setup do
294 @user = User.generate_with_protected!
294 @user = User.generate_with_protected!
295 @token = Token.generate!(:user => @user, :action => 'feeds')
295 @token = Token.generate!(:user => @user, :action => 'feeds')
296 @authorization = ActionController::HttpAuthentication::Basic.encode_credentials(@token.value, 'X')
296 @authorization = ActionController::HttpAuthentication::Basic.encode_credentials(@token.value, 'X')
297 send(http_method, url, parameters, {:authorization => @authorization})
297 send(http_method, url, parameters, {:authorization => @authorization})
298 end
298 end
299
299
300 should_respond_with failure_code
300 should_respond_with failure_code
301 should_respond_with_content_type_based_on_url(url)
301 should_respond_with_content_type_based_on_url(url)
302 should "not login as the user" do
302 should "not login as the user" do
303 assert_equal User.anonymous, User.current
303 assert_equal User.anonymous, User.current
304 end
304 end
305 end
305 end
306 end
306 end
307 end
307 end
308
308
309 # Test that a request allows full key authentication
309 # Test that a request allows full key authentication
310 #
310 #
311 # @param [Symbol] http_method the HTTP method for request (:get, :post, :put, :delete)
311 # @param [Symbol] http_method the HTTP method for request (:get, :post, :put, :delete)
312 # @param [String] url the request url, without the key=ZXY parameter
312 # @param [String] url the request url, without the key=ZXY parameter
313 # @param [optional, Hash] parameters additional request parameters
313 # @param [optional, Hash] parameters additional request parameters
314 # @param [optional, Hash] options additional options
314 # @param [optional, Hash] options additional options
315 # @option options [Symbol] :success_code Successful response code (:success)
315 # @option options [Symbol] :success_code Successful response code (:success)
316 # @option options [Symbol] :failure_code Failure response code (:unauthorized)
316 # @option options [Symbol] :failure_code Failure response code (:unauthorized)
317 def self.should_allow_key_based_auth(http_method, url, parameters={}, options={})
317 def self.should_allow_key_based_auth(http_method, url, parameters={}, options={})
318 success_code = options[:success_code] || :success
318 success_code = options[:success_code] || :success
319 failure_code = options[:failure_code] || :unauthorized
319 failure_code = options[:failure_code] || :unauthorized
320
320
321 context "should allow key based auth using key=X for #{http_method} #{url}" do
321 context "should allow key based auth using key=X for #{http_method} #{url}" do
322 context "with a valid api token" do
322 context "with a valid api token" do
323 setup do
323 setup do
324 @user = User.generate_with_protected!(:admin => true)
324 @user = User.generate_with_protected!(:admin => true)
325 @token = Token.generate!(:user => @user, :action => 'api')
325 @token = Token.generate!(:user => @user, :action => 'api')
326 # Simple url parse to add on ?key= or &key=
326 # Simple url parse to add on ?key= or &key=
327 request_url = if url.match(/\?/)
327 request_url = if url.match(/\?/)
328 url + "&key=#{@token.value}"
328 url + "&key=#{@token.value}"
329 else
329 else
330 url + "?key=#{@token.value}"
330 url + "?key=#{@token.value}"
331 end
331 end
332 send(http_method, request_url, parameters)
332 send(http_method, request_url, parameters)
333 end
333 end
334
334
335 should_respond_with success_code
335 should_respond_with success_code
336 should_respond_with_content_type_based_on_url(url)
336 should_respond_with_content_type_based_on_url(url)
337 should_be_a_valid_response_string_based_on_url(url)
337 should_be_a_valid_response_string_based_on_url(url)
338 should "login as the user" do
338 should "login as the user" do
339 assert_equal @user, User.current
339 assert_equal @user, User.current
340 end
340 end
341 end
341 end
342
342
343 context "with an invalid api token" do
343 context "with an invalid api token" do
344 setup do
344 setup do
345 @user = User.generate_with_protected!
345 @user = User.generate_with_protected!
346 @token = Token.generate!(:user => @user, :action => 'feeds')
346 @token = Token.generate!(:user => @user, :action => 'feeds')
347 # Simple url parse to add on ?key= or &key=
347 # Simple url parse to add on ?key= or &key=
348 request_url = if url.match(/\?/)
348 request_url = if url.match(/\?/)
349 url + "&key=#{@token.value}"
349 url + "&key=#{@token.value}"
350 else
350 else
351 url + "?key=#{@token.value}"
351 url + "?key=#{@token.value}"
352 end
352 end
353 send(http_method, request_url, parameters)
353 send(http_method, request_url, parameters)
354 end
354 end
355
355
356 should_respond_with failure_code
356 should_respond_with failure_code
357 should_respond_with_content_type_based_on_url(url)
357 should_respond_with_content_type_based_on_url(url)
358 should "not login as the user" do
358 should "not login as the user" do
359 assert_equal User.anonymous, User.current
359 assert_equal User.anonymous, User.current
360 end
360 end
361 end
361 end
362 end
362 end
363
363
364 end
364 end
365
365
366 # Uses should_respond_with_content_type based on what's in the url:
366 # Uses should_respond_with_content_type based on what's in the url:
367 #
367 #
368 # '/project/issues.xml' => should_respond_with_content_type :xml
368 # '/project/issues.xml' => should_respond_with_content_type :xml
369 # '/project/issues.json' => should_respond_with_content_type :json
369 # '/project/issues.json' => should_respond_with_content_type :json
370 #
370 #
371 # @param [String] url Request
371 # @param [String] url Request
372 def self.should_respond_with_content_type_based_on_url(url)
372 def self.should_respond_with_content_type_based_on_url(url)
373 case
373 case
374 when url.match(/xml/i)
374 when url.match(/xml/i)
375 should_respond_with_content_type :xml
375 should_respond_with_content_type :xml
376 when url.match(/json/i)
376 when url.match(/json/i)
377 should_respond_with_content_type :json
377 should_respond_with_content_type :json
378 else
378 else
379 raise "Unknown content type for should_respond_with_content_type_based_on_url: #{url}"
379 raise "Unknown content type for should_respond_with_content_type_based_on_url: #{url}"
380 end
380 end
381
381
382 end
382 end
383
383
384 # Uses the url to assert which format the response should be in
384 # Uses the url to assert which format the response should be in
385 #
385 #
386 # '/project/issues.xml' => should_be_a_valid_xml_string
386 # '/project/issues.xml' => should_be_a_valid_xml_string
387 # '/project/issues.json' => should_be_a_valid_json_string
387 # '/project/issues.json' => should_be_a_valid_json_string
388 #
388 #
389 # @param [String] url Request
389 # @param [String] url Request
390 def self.should_be_a_valid_response_string_based_on_url(url)
390 def self.should_be_a_valid_response_string_based_on_url(url)
391 case
391 case
392 when url.match(/xml/i)
392 when url.match(/xml/i)
393 should_be_a_valid_xml_string
393 should_be_a_valid_xml_string
394 when url.match(/json/i)
394 when url.match(/json/i)
395 should_be_a_valid_json_string
395 should_be_a_valid_json_string
396 else
396 else
397 raise "Unknown content type for should_be_a_valid_response_based_on_url: #{url}"
397 raise "Unknown content type for should_be_a_valid_response_based_on_url: #{url}"
398 end
398 end
399
399
400 end
400 end
401
401
402 # Checks that the response is a valid JSON string
402 # Checks that the response is a valid JSON string
403 def self.should_be_a_valid_json_string
403 def self.should_be_a_valid_json_string
404 should "be a valid JSON string (or empty)" do
404 should "be a valid JSON string (or empty)" do
405 assert (response.body.blank? || ActiveSupport::JSON.decode(response.body))
405 assert (response.body.blank? || ActiveSupport::JSON.decode(response.body))
406 end
406 end
407 end
407 end
408
408
409 # Checks that the response is a valid XML string
409 # Checks that the response is a valid XML string
410 def self.should_be_a_valid_xml_string
410 def self.should_be_a_valid_xml_string
411 should "be a valid XML string" do
411 should "be a valid XML string" do
412 assert REXML::Document.new(response.body)
412 assert REXML::Document.new(response.body)
413 end
413 end
414 end
414 end
415
415
416 end
416 end
417
417
418 # Simple module to "namespace" all of the API tests
418 # Simple module to "namespace" all of the API tests
419 module ApiTest
419 module ApiTest
420 end
420 end
General Comments 0
You need to be logged in to leave comments. Login now