##// END OF EJS Templates
code layout cleanup test/integration/api_test/issues_test.rb...
Toshi MARUYAMA -
r10363:92f92803522a
parent child
Show More
@@ -1,765 +1,795
1 # Redmine - project management software
1 # Redmine - project management software
2 # Copyright (C) 2006-2012 Jean-Philippe Lang
2 # Copyright (C) 2006-2012 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
19
20 class ApiTest::IssuesTest < ActionController::IntegrationTest
20 class ApiTest::IssuesTest < ActionController::IntegrationTest
21 fixtures :projects,
21 fixtures :projects,
22 :users,
22 :users,
23 :roles,
23 :roles,
24 :members,
24 :members,
25 :member_roles,
25 :member_roles,
26 :issues,
26 :issues,
27 :issue_statuses,
27 :issue_statuses,
28 :issue_relations,
28 :issue_relations,
29 :versions,
29 :versions,
30 :trackers,
30 :trackers,
31 :projects_trackers,
31 :projects_trackers,
32 :issue_categories,
32 :issue_categories,
33 :enabled_modules,
33 :enabled_modules,
34 :enumerations,
34 :enumerations,
35 :attachments,
35 :attachments,
36 :workflows,
36 :workflows,
37 :custom_fields,
37 :custom_fields,
38 :custom_values,
38 :custom_values,
39 :custom_fields_projects,
39 :custom_fields_projects,
40 :custom_fields_trackers,
40 :custom_fields_trackers,
41 :time_entries,
41 :time_entries,
42 :journals,
42 :journals,
43 :journal_details,
43 :journal_details,
44 :queries,
44 :queries,
45 :attachments
45 :attachments
46
46
47 def setup
47 def setup
48 Setting.rest_api_enabled = '1'
48 Setting.rest_api_enabled = '1'
49 end
49 end
50
50
51 context "/issues" do
51 context "/issues" do
52 # Use a private project to make sure auth is really working and not just
52 # Use a private project to make sure auth is really working and not just
53 # only showing public issues.
53 # only showing public issues.
54 should_allow_api_authentication(:get, "/projects/private-child/issues.xml")
54 should_allow_api_authentication(:get, "/projects/private-child/issues.xml")
55
55
56 should "contain metadata" do
56 should "contain metadata" do
57 get '/issues.xml'
57 get '/issues.xml'
58
58
59 assert_tag :tag => 'issues',
59 assert_tag :tag => 'issues',
60 :attributes => {
60 :attributes => {
61 :type => 'array',
61 :type => 'array',
62 :total_count => assigns(:issue_count),
62 :total_count => assigns(:issue_count),
63 :limit => 25,
63 :limit => 25,
64 :offset => 0
64 :offset => 0
65 }
65 }
66 end
66 end
67
67
68 context "with offset and limit" do
68 context "with offset and limit" do
69 should "use the params" do
69 should "use the params" do
70 get '/issues.xml?offset=2&limit=3'
70 get '/issues.xml?offset=2&limit=3'
71
71
72 assert_equal 3, assigns(:limit)
72 assert_equal 3, assigns(:limit)
73 assert_equal 2, assigns(:offset)
73 assert_equal 2, assigns(:offset)
74 assert_tag :tag => 'issues', :children => {:count => 3, :only => {:tag => 'issue'}}
74 assert_tag :tag => 'issues', :children => {:count => 3, :only => {:tag => 'issue'}}
75 end
75 end
76 end
76 end
77
77
78 context "with nometa param" do
78 context "with nometa param" do
79 should "not contain metadata" do
79 should "not contain metadata" do
80 get '/issues.xml?nometa=1'
80 get '/issues.xml?nometa=1'
81
81
82 assert_tag :tag => 'issues',
82 assert_tag :tag => 'issues',
83 :attributes => {
83 :attributes => {
84 :type => 'array',
84 :type => 'array',
85 :total_count => nil,
85 :total_count => nil,
86 :limit => nil,
86 :limit => nil,
87 :offset => nil
87 :offset => nil
88 }
88 }
89 end
89 end
90 end
90 end
91
91
92 context "with nometa header" do
92 context "with nometa header" do
93 should "not contain metadata" do
93 should "not contain metadata" do
94 get '/issues.xml', {}, {'X-Redmine-Nometa' => '1'}
94 get '/issues.xml', {}, {'X-Redmine-Nometa' => '1'}
95
95
96 assert_tag :tag => 'issues',
96 assert_tag :tag => 'issues',
97 :attributes => {
97 :attributes => {
98 :type => 'array',
98 :type => 'array',
99 :total_count => nil,
99 :total_count => nil,
100 :limit => nil,
100 :limit => nil,
101 :offset => nil
101 :offset => nil
102 }
102 }
103 end
103 end
104 end
104 end
105
105
106 context "with relations" do
106 context "with relations" do
107 should "display relations" do
107 should "display relations" do
108 get '/issues.xml?include=relations'
108 get '/issues.xml?include=relations'
109
109
110 assert_response :success
110 assert_response :success
111 assert_equal 'application/xml', @response.content_type
111 assert_equal 'application/xml', @response.content_type
112 assert_tag 'relations',
112 assert_tag 'relations',
113 :parent => {:tag => 'issue', :child => {:tag => 'id', :content => '3'}},
113 :parent => {:tag => 'issue', :child => {:tag => 'id', :content => '3'}},
114 :children => {:count => 1},
114 :children => {:count => 1},
115 :child => {
115 :child => {
116 :tag => 'relation',
116 :tag => 'relation',
117 :attributes => {:id => '2', :issue_id => '2', :issue_to_id => '3', :relation_type => 'relates'}
117 :attributes => {:id => '2', :issue_id => '2', :issue_to_id => '3',
118 :relation_type => 'relates'}
118 }
119 }
119 assert_tag 'relations',
120 assert_tag 'relations',
120 :parent => {:tag => 'issue', :child => {:tag => 'id', :content => '1'}},
121 :parent => {:tag => 'issue', :child => {:tag => 'id', :content => '1'}},
121 :children => {:count => 0}
122 :children => {:count => 0}
122 end
123 end
123 end
124 end
124
125
125 context "with invalid query params" do
126 context "with invalid query params" do
126 should "return errors" do
127 should "return errors" do
127 get '/issues.xml', {:f => ['start_date'], :op => {:start_date => '='}}
128 get '/issues.xml', {:f => ['start_date'], :op => {:start_date => '='}}
128
129
129 assert_response :unprocessable_entity
130 assert_response :unprocessable_entity
130 assert_equal 'application/xml', @response.content_type
131 assert_equal 'application/xml', @response.content_type
131 assert_tag 'errors', :child => {:tag => 'error', :content => "Start date can't be blank"}
132 assert_tag 'errors', :child => {:tag => 'error', :content => "Start date can't be blank"}
132 end
133 end
133 end
134 end
134
135
135 context "with custom field filter" do
136 context "with custom field filter" do
136 should "show only issues with the custom field value" do
137 should "show only issues with the custom field value" do
137 get '/issues.xml', { :set_filter => 1, :f => ['cf_1'], :op => {:cf_1 => '='}, :v => {:cf_1 => ['MySQL']}}
138 get '/issues.xml',
138
139 {:set_filter => 1, :f => ['cf_1'], :op => {:cf_1 => '='},
140 :v => {:cf_1 => ['MySQL']}}
139 expected_ids = Issue.visible.all(
141 expected_ids = Issue.visible.all(
140 :include => :custom_values,
142 :include => :custom_values,
141 :conditions => {:custom_values => {:custom_field_id => 1, :value => 'MySQL'}}).map(&:id)
143 :conditions => {:custom_values => {:custom_field_id => 1, :value => 'MySQL'}}).map(&:id)
142
143 assert_select 'issues > issue > id', :count => expected_ids.count do |ids|
144 assert_select 'issues > issue > id', :count => expected_ids.count do |ids|
144 ids.each { |id| assert expected_ids.delete(id.children.first.content.to_i) }
145 ids.each { |id| assert expected_ids.delete(id.children.first.content.to_i) }
145 end
146 end
146 end
147 end
147 end
148 end
148
149
149 context "with custom field filter (shorthand method)" do
150 context "with custom field filter (shorthand method)" do
150 should "show only issues with the custom field value" do
151 should "show only issues with the custom field value" do
151 get '/issues.xml', { :cf_1 => 'MySQL' }
152 get '/issues.xml', { :cf_1 => 'MySQL' }
152
153
153 expected_ids = Issue.visible.all(
154 expected_ids = Issue.visible.all(
154 :include => :custom_values,
155 :include => :custom_values,
155 :conditions => {:custom_values => {:custom_field_id => 1, :value => 'MySQL'}}).map(&:id)
156 :conditions => {:custom_values => {:custom_field_id => 1, :value => 'MySQL'}}).map(&:id)
156
157
157 assert_select 'issues > issue > id', :count => expected_ids.count do |ids|
158 assert_select 'issues > issue > id', :count => expected_ids.count do |ids|
158 ids.each { |id| assert expected_ids.delete(id.children.first.content.to_i) }
159 ids.each { |id| assert expected_ids.delete(id.children.first.content.to_i) }
159 end
160 end
160 end
161 end
161 end
162 end
162 end
163 end
163
164
164 context "/index.json" do
165 context "/index.json" do
165 should_allow_api_authentication(:get, "/projects/private-child/issues.json")
166 should_allow_api_authentication(:get, "/projects/private-child/issues.json")
166 end
167 end
167
168
168 context "/index.xml with filter" do
169 context "/index.xml with filter" do
169 should "show only issues with the status_id" do
170 should "show only issues with the status_id" do
170 get '/issues.xml?status_id=5'
171 get '/issues.xml?status_id=5'
171
172
172 expected_ids = Issue.visible.all(:conditions => {:status_id => 5}).map(&:id)
173 expected_ids = Issue.visible.all(:conditions => {:status_id => 5}).map(&:id)
173
174
174 assert_select 'issues > issue > id', :count => expected_ids.count do |ids|
175 assert_select 'issues > issue > id', :count => expected_ids.count do |ids|
175 ids.each { |id| assert expected_ids.delete(id.children.first.content.to_i) }
176 ids.each { |id| assert expected_ids.delete(id.children.first.content.to_i) }
176 end
177 end
177 end
178 end
178 end
179 end
179
180
180 context "/index.json with filter" do
181 context "/index.json with filter" do
181 should "show only issues with the status_id" do
182 should "show only issues with the status_id" do
182 get '/issues.json?status_id=5'
183 get '/issues.json?status_id=5'
183
184
184 json = ActiveSupport::JSON.decode(response.body)
185 json = ActiveSupport::JSON.decode(response.body)
185 status_ids_used = json['issues'].collect {|j| j['status']['id'] }
186 status_ids_used = json['issues'].collect {|j| j['status']['id'] }
186 assert_equal 3, status_ids_used.length
187 assert_equal 3, status_ids_used.length
187 assert status_ids_used.all? {|id| id == 5 }
188 assert status_ids_used.all? {|id| id == 5 }
188 end
189 end
189
190
190 end
191 end
191
192
192 # Issue 6 is on a private project
193 # Issue 6 is on a private project
193 context "/issues/6.xml" do
194 context "/issues/6.xml" do
194 should_allow_api_authentication(:get, "/issues/6.xml")
195 should_allow_api_authentication(:get, "/issues/6.xml")
195 end
196 end
196
197
197 context "/issues/6.json" do
198 context "/issues/6.json" do
198 should_allow_api_authentication(:get, "/issues/6.json")
199 should_allow_api_authentication(:get, "/issues/6.json")
199 end
200 end
200
201
201 context "GET /issues/:id" do
202 context "GET /issues/:id" do
202 context "with journals" do
203 context "with journals" do
203 context ".xml" do
204 context ".xml" do
204 should "display journals" do
205 should "display journals" do
205 get '/issues/1.xml?include=journals'
206 get '/issues/1.xml?include=journals'
206
207
207 assert_tag :tag => 'issue',
208 assert_tag :tag => 'issue',
208 :child => {
209 :child => {
209 :tag => 'journals',
210 :tag => 'journals',
210 :attributes => { :type => 'array' },
211 :attributes => { :type => 'array' },
211 :child => {
212 :child => {
212 :tag => 'journal',
213 :tag => 'journal',
213 :attributes => { :id => '1'},
214 :attributes => { :id => '1'},
214 :child => {
215 :child => {
215 :tag => 'details',
216 :tag => 'details',
216 :attributes => { :type => 'array' },
217 :attributes => { :type => 'array' },
217 :child => {
218 :child => {
218 :tag => 'detail',
219 :tag => 'detail',
219 :attributes => { :name => 'status_id' },
220 :attributes => { :name => 'status_id' },
220 :child => {
221 :child => {
221 :tag => 'old_value',
222 :tag => 'old_value',
222 :content => '1',
223 :content => '1',
223 :sibling => {
224 :sibling => {
224 :tag => 'new_value',
225 :tag => 'new_value',
225 :content => '2'
226 :content => '2'
226 }
227 }
227 }
228 }
228 }
229 }
229 }
230 }
230 }
231 }
231 }
232 }
232 end
233 end
233 end
234 end
234 end
235 end
235
236
236 context "with custom fields" do
237 context "with custom fields" do
237 context ".xml" do
238 context ".xml" do
238 should "display custom fields" do
239 should "display custom fields" do
239 get '/issues/3.xml'
240 get '/issues/3.xml'
240
241
241 assert_tag :tag => 'issue',
242 assert_tag :tag => 'issue',
242 :child => {
243 :child => {
243 :tag => 'custom_fields',
244 :tag => 'custom_fields',
244 :attributes => { :type => 'array' },
245 :attributes => { :type => 'array' },
245 :child => {
246 :child => {
246 :tag => 'custom_field',
247 :tag => 'custom_field',
247 :attributes => { :id => '1'},
248 :attributes => { :id => '1'},
248 :child => {
249 :child => {
249 :tag => 'value',
250 :tag => 'value',
250 :content => 'MySQL'
251 :content => 'MySQL'
251 }
252 }
252 }
253 }
253 }
254 }
254
255
255 assert_nothing_raised do
256 assert_nothing_raised do
256 Hash.from_xml(response.body).to_xml
257 Hash.from_xml(response.body).to_xml
257 end
258 end
258 end
259 end
259 end
260 end
260 end
261 end
261
262
262 context "with multi custom fields" do
263 context "with multi custom fields" do
263 setup do
264 setup do
264 field = CustomField.find(1)
265 field = CustomField.find(1)
265 field.update_attribute :multiple, true
266 field.update_attribute :multiple, true
266 issue = Issue.find(3)
267 issue = Issue.find(3)
267 issue.custom_field_values = {1 => ['MySQL', 'Oracle']}
268 issue.custom_field_values = {1 => ['MySQL', 'Oracle']}
268 issue.save!
269 issue.save!
269 end
270 end
270
271
271 context ".xml" do
272 context ".xml" do
272 should "display custom fields" do
273 should "display custom fields" do
273 get '/issues/3.xml'
274 get '/issues/3.xml'
274 assert_response :success
275 assert_response :success
275 assert_tag :tag => 'issue',
276 assert_tag :tag => 'issue',
276 :child => {
277 :child => {
277 :tag => 'custom_fields',
278 :tag => 'custom_fields',
278 :attributes => { :type => 'array' },
279 :attributes => { :type => 'array' },
279 :child => {
280 :child => {
280 :tag => 'custom_field',
281 :tag => 'custom_field',
281 :attributes => { :id => '1'},
282 :attributes => { :id => '1'},
282 :child => {
283 :child => {
283 :tag => 'value',
284 :tag => 'value',
284 :attributes => { :type => 'array' },
285 :attributes => { :type => 'array' },
285 :children => { :count => 2 }
286 :children => { :count => 2 }
286 }
287 }
287 }
288 }
288 }
289 }
289
290
290 xml = Hash.from_xml(response.body)
291 xml = Hash.from_xml(response.body)
291 custom_fields = xml['issue']['custom_fields']
292 custom_fields = xml['issue']['custom_fields']
292 assert_kind_of Array, custom_fields
293 assert_kind_of Array, custom_fields
293 field = custom_fields.detect {|f| f['id'] == '1'}
294 field = custom_fields.detect {|f| f['id'] == '1'}
294 assert_kind_of Hash, field
295 assert_kind_of Hash, field
295 assert_equal ['MySQL', 'Oracle'], field['value'].sort
296 assert_equal ['MySQL', 'Oracle'], field['value'].sort
296 end
297 end
297 end
298 end
298
299
299 context ".json" do
300 context ".json" do
300 should "display custom fields" do
301 should "display custom fields" do
301 get '/issues/3.json'
302 get '/issues/3.json'
302 assert_response :success
303 assert_response :success
303 json = ActiveSupport::JSON.decode(response.body)
304 json = ActiveSupport::JSON.decode(response.body)
304 custom_fields = json['issue']['custom_fields']
305 custom_fields = json['issue']['custom_fields']
305 assert_kind_of Array, custom_fields
306 assert_kind_of Array, custom_fields
306 field = custom_fields.detect {|f| f['id'] == 1}
307 field = custom_fields.detect {|f| f['id'] == 1}
307 assert_kind_of Hash, field
308 assert_kind_of Hash, field
308 assert_equal ['MySQL', 'Oracle'], field['value'].sort
309 assert_equal ['MySQL', 'Oracle'], field['value'].sort
309 end
310 end
310 end
311 end
311 end
312 end
312
313
313 context "with empty value for multi custom field" do
314 context "with empty value for multi custom field" do
314 setup do
315 setup do
315 field = CustomField.find(1)
316 field = CustomField.find(1)
316 field.update_attribute :multiple, true
317 field.update_attribute :multiple, true
317 issue = Issue.find(3)
318 issue = Issue.find(3)
318 issue.custom_field_values = {1 => ['']}
319 issue.custom_field_values = {1 => ['']}
319 issue.save!
320 issue.save!
320 end
321 end
321
322
322 context ".xml" do
323 context ".xml" do
323 should "display custom fields" do
324 should "display custom fields" do
324 get '/issues/3.xml'
325 get '/issues/3.xml'
325 assert_response :success
326 assert_response :success
326 assert_tag :tag => 'issue',
327 assert_tag :tag => 'issue',
327 :child => {
328 :child => {
328 :tag => 'custom_fields',
329 :tag => 'custom_fields',
329 :attributes => { :type => 'array' },
330 :attributes => { :type => 'array' },
330 :child => {
331 :child => {
331 :tag => 'custom_field',
332 :tag => 'custom_field',
332 :attributes => { :id => '1'},
333 :attributes => { :id => '1'},
333 :child => {
334 :child => {
334 :tag => 'value',
335 :tag => 'value',
335 :attributes => { :type => 'array' },
336 :attributes => { :type => 'array' },
336 :children => { :count => 0 }
337 :children => { :count => 0 }
337 }
338 }
338 }
339 }
339 }
340 }
340
341
341 xml = Hash.from_xml(response.body)
342 xml = Hash.from_xml(response.body)
342 custom_fields = xml['issue']['custom_fields']
343 custom_fields = xml['issue']['custom_fields']
343 assert_kind_of Array, custom_fields
344 assert_kind_of Array, custom_fields
344 field = custom_fields.detect {|f| f['id'] == '1'}
345 field = custom_fields.detect {|f| f['id'] == '1'}
345 assert_kind_of Hash, field
346 assert_kind_of Hash, field
346 assert_equal [], field['value']
347 assert_equal [], field['value']
347 end
348 end
348 end
349 end
349
350
350 context ".json" do
351 context ".json" do
351 should "display custom fields" do
352 should "display custom fields" do
352 get '/issues/3.json'
353 get '/issues/3.json'
353 assert_response :success
354 assert_response :success
354 json = ActiveSupport::JSON.decode(response.body)
355 json = ActiveSupport::JSON.decode(response.body)
355 custom_fields = json['issue']['custom_fields']
356 custom_fields = json['issue']['custom_fields']
356 assert_kind_of Array, custom_fields
357 assert_kind_of Array, custom_fields
357 field = custom_fields.detect {|f| f['id'] == 1}
358 field = custom_fields.detect {|f| f['id'] == 1}
358 assert_kind_of Hash, field
359 assert_kind_of Hash, field
359 assert_equal [], field['value'].sort
360 assert_equal [], field['value'].sort
360 end
361 end
361 end
362 end
362 end
363 end
363
364
364 context "with attachments" do
365 context "with attachments" do
365 context ".xml" do
366 context ".xml" do
366 should "display attachments" do
367 should "display attachments" do
367 get '/issues/3.xml?include=attachments'
368 get '/issues/3.xml?include=attachments'
368
369
369 assert_tag :tag => 'issue',
370 assert_tag :tag => 'issue',
370 :child => {
371 :child => {
371 :tag => 'attachments',
372 :tag => 'attachments',
372 :children => {:count => 5},
373 :children => {:count => 5},
373 :child => {
374 :child => {
374 :tag => 'attachment',
375 :tag => 'attachment',
375 :child => {
376 :child => {
376 :tag => 'filename',
377 :tag => 'filename',
377 :content => 'source.rb',
378 :content => 'source.rb',
378 :sibling => {
379 :sibling => {
379 :tag => 'content_url',
380 :tag => 'content_url',
380 :content => 'http://www.example.com/attachments/download/4/source.rb'
381 :content => 'http://www.example.com/attachments/download/4/source.rb'
381 }
382 }
382 }
383 }
383 }
384 }
384 }
385 }
385 end
386 end
386 end
387 end
387 end
388 end
388
389
389 context "with subtasks" do
390 context "with subtasks" do
390 setup do
391 setup do
391 @c1 = Issue.create!(:status_id => 1, :subject => "child c1", :tracker_id => 1, :project_id => 1, :author_id => 1, :parent_issue_id => 1)
392 @c1 = Issue.create!(
392 @c2 = Issue.create!(:status_id => 1, :subject => "child c2", :tracker_id => 1, :project_id => 1, :author_id => 1, :parent_issue_id => 1)
393 :status_id => 1, :subject => "child c1",
393 @c3 = Issue.create!(:status_id => 1, :subject => "child c3", :tracker_id => 1, :project_id => 1, :author_id => 1, :parent_issue_id => @c1.id)
394 :tracker_id => 1, :project_id => 1, :author_id => 1,
395 :parent_issue_id => 1
396 )
397 @c2 = Issue.create!(
398 :status_id => 1, :subject => "child c2",
399 :tracker_id => 1, :project_id => 1, :author_id => 1,
400 :parent_issue_id => 1
401 )
402 @c3 = Issue.create!(
403 :status_id => 1, :subject => "child c3",
404 :tracker_id => 1, :project_id => 1, :author_id => 1,
405 :parent_issue_id => @c1.id
406 )
394 end
407 end
395
408
396 context ".xml" do
409 context ".xml" do
397 should "display children" do
410 should "display children" do
398 get '/issues/1.xml?include=children'
411 get '/issues/1.xml?include=children'
399
412
400 assert_tag :tag => 'issue',
413 assert_tag :tag => 'issue',
401 :child => {
414 :child => {
402 :tag => 'children',
415 :tag => 'children',
403 :children => {:count => 2},
416 :children => {:count => 2},
404 :child => {
417 :child => {
405 :tag => 'issue',
418 :tag => 'issue',
406 :attributes => {:id => @c1.id.to_s},
419 :attributes => {:id => @c1.id.to_s},
407 :child => {
420 :child => {
408 :tag => 'subject',
421 :tag => 'subject',
409 :content => 'child c1',
422 :content => 'child c1',
410 :sibling => {
423 :sibling => {
411 :tag => 'children',
424 :tag => 'children',
412 :children => {:count => 1},
425 :children => {:count => 1},
413 :child => {
426 :child => {
414 :tag => 'issue',
427 :tag => 'issue',
415 :attributes => {:id => @c3.id.to_s}
428 :attributes => {:id => @c3.id.to_s}
416 }
429 }
417 }
430 }
418 }
431 }
419 }
432 }
420 }
433 }
421 end
434 end
422
435
423 context ".json" do
436 context ".json" do
424 should "display children" do
437 should "display children" do
425 get '/issues/1.json?include=children'
438 get '/issues/1.json?include=children'
426
439
427 json = ActiveSupport::JSON.decode(response.body)
440 json = ActiveSupport::JSON.decode(response.body)
428 assert_equal([
441 assert_equal([
429 {
442 {
430 'id' => @c1.id, 'subject' => 'child c1', 'tracker' => {'id' => 1, 'name' => 'Bug'},
443 'id' => @c1.id, 'subject' => 'child c1', 'tracker' => {'id' => 1, 'name' => 'Bug'},
431 'children' => [{ 'id' => @c3.id, 'subject' => 'child c3', 'tracker' => {'id' => 1, 'name' => 'Bug'} }]
444 'children' => [{'id' => @c3.id, 'subject' => 'child c3',
445 'tracker' => {'id' => 1, 'name' => 'Bug'} }]
432 },
446 },
433 { 'id' => @c2.id, 'subject' => 'child c2', 'tracker' => {'id' => 1, 'name' => 'Bug'} }
447 { 'id' => @c2.id, 'subject' => 'child c2', 'tracker' => {'id' => 1, 'name' => 'Bug'} }
434 ],
448 ],
435 json['issue']['children'])
449 json['issue']['children'])
436 end
450 end
437 end
451 end
438 end
452 end
439 end
453 end
440 end
454 end
441
455
442 context "POST /issues.xml" do
456 context "POST /issues.xml" do
443 should_allow_api_authentication(:post,
457 should_allow_api_authentication(
444 '/issues.xml',
458 :post,
445 {:issue => {:project_id => 1, :subject => 'API test', :tracker_id => 2, :status_id => 3}},
459 '/issues.xml',
446 {:success_code => :created})
460 {:issue => {:project_id => 1, :subject => 'API test', :tracker_id => 2, :status_id => 3}},
447
461 {:success_code => :created}
462 )
448 should "create an issue with the attributes" do
463 should "create an issue with the attributes" do
449 assert_difference('Issue.count') do
464 assert_difference('Issue.count') do
450 post '/issues.xml', {:issue => {:project_id => 1, :subject => 'API test', :tracker_id => 2, :status_id => 3}}, credentials('jsmith')
465 post '/issues.xml',
466 {:issue => {:project_id => 1, :subject => 'API test',
467 :tracker_id => 2, :status_id => 3}}, credentials('jsmith')
451 end
468 end
452
453 issue = Issue.first(:order => 'id DESC')
469 issue = Issue.first(:order => 'id DESC')
454 assert_equal 1, issue.project_id
470 assert_equal 1, issue.project_id
455 assert_equal 2, issue.tracker_id
471 assert_equal 2, issue.tracker_id
456 assert_equal 3, issue.status_id
472 assert_equal 3, issue.status_id
457 assert_equal 'API test', issue.subject
473 assert_equal 'API test', issue.subject
458
474
459 assert_response :created
475 assert_response :created
460 assert_equal 'application/xml', @response.content_type
476 assert_equal 'application/xml', @response.content_type
461 assert_tag 'issue', :child => {:tag => 'id', :content => issue.id.to_s}
477 assert_tag 'issue', :child => {:tag => 'id', :content => issue.id.to_s}
462 end
478 end
463 end
479 end
464
480
465 context "POST /issues.xml with failure" do
481 context "POST /issues.xml with failure" do
466 should "have an errors tag" do
482 should "have an errors tag" do
467 assert_no_difference('Issue.count') do
483 assert_no_difference('Issue.count') do
468 post '/issues.xml', {:issue => {:project_id => 1}}, credentials('jsmith')
484 post '/issues.xml', {:issue => {:project_id => 1}}, credentials('jsmith')
469 end
485 end
470
486
471 assert_tag :errors, :child => {:tag => 'error', :content => "Subject can't be blank"}
487 assert_tag :errors, :child => {:tag => 'error', :content => "Subject can't be blank"}
472 end
488 end
473 end
489 end
474
490
475 context "POST /issues.json" do
491 context "POST /issues.json" do
476 should_allow_api_authentication(:post,
492 should_allow_api_authentication(:post,
477 '/issues.json',
493 '/issues.json',
478 {:issue => {:project_id => 1, :subject => 'API test', :tracker_id => 2, :status_id => 3}},
494 {:issue => {:project_id => 1, :subject => 'API test',
495 :tracker_id => 2, :status_id => 3}},
479 {:success_code => :created})
496 {:success_code => :created})
480
497
481 should "create an issue with the attributes" do
498 should "create an issue with the attributes" do
482 assert_difference('Issue.count') do
499 assert_difference('Issue.count') do
483 post '/issues.json', {:issue => {:project_id => 1, :subject => 'API test', :tracker_id => 2, :status_id => 3}}, credentials('jsmith')
500 post '/issues.json',
501 {:issue => {:project_id => 1, :subject => 'API test',
502 :tracker_id => 2, :status_id => 3}},
503 credentials('jsmith')
484 end
504 end
485
505
486 issue = Issue.first(:order => 'id DESC')
506 issue = Issue.first(:order => 'id DESC')
487 assert_equal 1, issue.project_id
507 assert_equal 1, issue.project_id
488 assert_equal 2, issue.tracker_id
508 assert_equal 2, issue.tracker_id
489 assert_equal 3, issue.status_id
509 assert_equal 3, issue.status_id
490 assert_equal 'API test', issue.subject
510 assert_equal 'API test', issue.subject
491 end
511 end
492
512
493 end
513 end
494
514
495 context "POST /issues.json with failure" do
515 context "POST /issues.json with failure" do
496 should "have an errors element" do
516 should "have an errors element" do
497 assert_no_difference('Issue.count') do
517 assert_no_difference('Issue.count') do
498 post '/issues.json', {:issue => {:project_id => 1}}, credentials('jsmith')
518 post '/issues.json', {:issue => {:project_id => 1}}, credentials('jsmith')
499 end
519 end
500
520
501 json = ActiveSupport::JSON.decode(response.body)
521 json = ActiveSupport::JSON.decode(response.body)
502 assert json['errors'].include?("Subject can't be blank")
522 assert json['errors'].include?("Subject can't be blank")
503 end
523 end
504 end
524 end
505
525
506 # Issue 6 is on a private project
526 # Issue 6 is on a private project
507 context "PUT /issues/6.xml" do
527 context "PUT /issues/6.xml" do
508 setup do
528 setup do
509 @parameters = {:issue => {:subject => 'API update', :notes => 'A new note'}}
529 @parameters = {:issue => {:subject => 'API update', :notes => 'A new note'}}
510 end
530 end
511
531
512 should_allow_api_authentication(:put,
532 should_allow_api_authentication(:put,
513 '/issues/6.xml',
533 '/issues/6.xml',
514 {:issue => {:subject => 'API update', :notes => 'A new note'}},
534 {:issue => {:subject => 'API update', :notes => 'A new note'}},
515 {:success_code => :ok})
535 {:success_code => :ok})
516
536
517 should "not create a new issue" do
537 should "not create a new issue" do
518 assert_no_difference('Issue.count') do
538 assert_no_difference('Issue.count') do
519 put '/issues/6.xml', @parameters, credentials('jsmith')
539 put '/issues/6.xml', @parameters, credentials('jsmith')
520 end
540 end
521 end
541 end
522
542
523 should "create a new journal" do
543 should "create a new journal" do
524 assert_difference('Journal.count') do
544 assert_difference('Journal.count') do
525 put '/issues/6.xml', @parameters, credentials('jsmith')
545 put '/issues/6.xml', @parameters, credentials('jsmith')
526 end
546 end
527 end
547 end
528
548
529 should "add the note to the journal" do
549 should "add the note to the journal" do
530 put '/issues/6.xml', @parameters, credentials('jsmith')
550 put '/issues/6.xml', @parameters, credentials('jsmith')
531
551
532 journal = Journal.last
552 journal = Journal.last
533 assert_equal "A new note", journal.notes
553 assert_equal "A new note", journal.notes
534 end
554 end
535
555
536 should "update the issue" do
556 should "update the issue" do
537 put '/issues/6.xml', @parameters, credentials('jsmith')
557 put '/issues/6.xml', @parameters, credentials('jsmith')
538
558
539 issue = Issue.find(6)
559 issue = Issue.find(6)
540 assert_equal "API update", issue.subject
560 assert_equal "API update", issue.subject
541 end
561 end
542
562
543 end
563 end
544
564
545 context "PUT /issues/3.xml with custom fields" do
565 context "PUT /issues/3.xml with custom fields" do
546 setup do
566 setup do
547 @parameters = {:issue => {:custom_fields => [{'id' => '1', 'value' => 'PostgreSQL' }, {'id' => '2', 'value' => '150'}]}}
567 @parameters = {
568 :issue => {:custom_fields => [{'id' => '1', 'value' => 'PostgreSQL' },
569 {'id' => '2', 'value' => '150'}]}
570 }
548 end
571 end
549
572
550 should "update custom fields" do
573 should "update custom fields" do
551 assert_no_difference('Issue.count') do
574 assert_no_difference('Issue.count') do
552 put '/issues/3.xml', @parameters, credentials('jsmith')
575 put '/issues/3.xml', @parameters, credentials('jsmith')
553 end
576 end
554
577
555 issue = Issue.find(3)
578 issue = Issue.find(3)
556 assert_equal '150', issue.custom_value_for(2).value
579 assert_equal '150', issue.custom_value_for(2).value
557 assert_equal 'PostgreSQL', issue.custom_value_for(1).value
580 assert_equal 'PostgreSQL', issue.custom_value_for(1).value
558 end
581 end
559 end
582 end
560
583
561 context "PUT /issues/3.xml with multi custom fields" do
584 context "PUT /issues/3.xml with multi custom fields" do
562 setup do
585 setup do
563 field = CustomField.find(1)
586 field = CustomField.find(1)
564 field.update_attribute :multiple, true
587 field.update_attribute :multiple, true
565 @parameters = {:issue => {:custom_fields => [{'id' => '1', 'value' => ['MySQL', 'PostgreSQL'] }, {'id' => '2', 'value' => '150'}]}}
588 @parameters = {
589 :issue => {:custom_fields => [{'id' => '1', 'value' => ['MySQL', 'PostgreSQL'] },
590 {'id' => '2', 'value' => '150'}]}
591 }
566 end
592 end
567
593
568 should "update custom fields" do
594 should "update custom fields" do
569 assert_no_difference('Issue.count') do
595 assert_no_difference('Issue.count') do
570 put '/issues/3.xml', @parameters, credentials('jsmith')
596 put '/issues/3.xml', @parameters, credentials('jsmith')
571 end
597 end
572
598
573 issue = Issue.find(3)
599 issue = Issue.find(3)
574 assert_equal '150', issue.custom_value_for(2).value
600 assert_equal '150', issue.custom_value_for(2).value
575 assert_equal ['MySQL', 'PostgreSQL'], issue.custom_field_value(1).sort
601 assert_equal ['MySQL', 'PostgreSQL'], issue.custom_field_value(1).sort
576 end
602 end
577 end
603 end
578
604
579 context "PUT /issues/3.xml with project change" do
605 context "PUT /issues/3.xml with project change" do
580 setup do
606 setup do
581 @parameters = {:issue => {:project_id => 2, :subject => 'Project changed'}}
607 @parameters = {:issue => {:project_id => 2, :subject => 'Project changed'}}
582 end
608 end
583
609
584 should "update project" do
610 should "update project" do
585 assert_no_difference('Issue.count') do
611 assert_no_difference('Issue.count') do
586 put '/issues/3.xml', @parameters, credentials('jsmith')
612 put '/issues/3.xml', @parameters, credentials('jsmith')
587 end
613 end
588
614
589 issue = Issue.find(3)
615 issue = Issue.find(3)
590 assert_equal 2, issue.project_id
616 assert_equal 2, issue.project_id
591 assert_equal 'Project changed', issue.subject
617 assert_equal 'Project changed', issue.subject
592 end
618 end
593 end
619 end
594
620
595 context "PUT /issues/6.xml with failed update" do
621 context "PUT /issues/6.xml with failed update" do
596 setup do
622 setup do
597 @parameters = {:issue => {:subject => ''}}
623 @parameters = {:issue => {:subject => ''}}
598 end
624 end
599
625
600 should "not create a new issue" do
626 should "not create a new issue" do
601 assert_no_difference('Issue.count') do
627 assert_no_difference('Issue.count') do
602 put '/issues/6.xml', @parameters, credentials('jsmith')
628 put '/issues/6.xml', @parameters, credentials('jsmith')
603 end
629 end
604 end
630 end
605
631
606 should "not create a new journal" do
632 should "not create a new journal" do
607 assert_no_difference('Journal.count') do
633 assert_no_difference('Journal.count') do
608 put '/issues/6.xml', @parameters, credentials('jsmith')
634 put '/issues/6.xml', @parameters, credentials('jsmith')
609 end
635 end
610 end
636 end
611
637
612 should "have an errors tag" do
638 should "have an errors tag" do
613 put '/issues/6.xml', @parameters, credentials('jsmith')
639 put '/issues/6.xml', @parameters, credentials('jsmith')
614
640
615 assert_tag :errors, :child => {:tag => 'error', :content => "Subject can't be blank"}
641 assert_tag :errors, :child => {:tag => 'error', :content => "Subject can't be blank"}
616 end
642 end
617 end
643 end
618
644
619 context "PUT /issues/6.json" do
645 context "PUT /issues/6.json" do
620 setup do
646 setup do
621 @parameters = {:issue => {:subject => 'API update', :notes => 'A new note'}}
647 @parameters = {:issue => {:subject => 'API update', :notes => 'A new note'}}
622 end
648 end
623
649
624 should_allow_api_authentication(:put,
650 should_allow_api_authentication(:put,
625 '/issues/6.json',
651 '/issues/6.json',
626 {:issue => {:subject => 'API update', :notes => 'A new note'}},
652 {:issue => {:subject => 'API update', :notes => 'A new note'}},
627 {:success_code => :ok})
653 {:success_code => :ok})
628
654
629 should "update the issue" do
655 should "update the issue" do
630 assert_no_difference('Issue.count') do
656 assert_no_difference('Issue.count') do
631 assert_difference('Journal.count') do
657 assert_difference('Journal.count') do
632 put '/issues/6.json', @parameters, credentials('jsmith')
658 put '/issues/6.json', @parameters, credentials('jsmith')
633
659
634 assert_response :ok
660 assert_response :ok
635 assert_equal '', response.body
661 assert_equal '', response.body
636 end
662 end
637 end
663 end
638
664
639 issue = Issue.find(6)
665 issue = Issue.find(6)
640 assert_equal "API update", issue.subject
666 assert_equal "API update", issue.subject
641 journal = Journal.last
667 journal = Journal.last
642 assert_equal "A new note", journal.notes
668 assert_equal "A new note", journal.notes
643 end
669 end
644 end
670 end
645
671
646 context "PUT /issues/6.json with failed update" do
672 context "PUT /issues/6.json with failed update" do
647 should "return errors" do
673 should "return errors" do
648 assert_no_difference('Issue.count') do
674 assert_no_difference('Issue.count') do
649 assert_no_difference('Journal.count') do
675 assert_no_difference('Journal.count') do
650 put '/issues/6.json', {:issue => {:subject => ''}}, credentials('jsmith')
676 put '/issues/6.json', {:issue => {:subject => ''}}, credentials('jsmith')
651
677
652 assert_response :unprocessable_entity
678 assert_response :unprocessable_entity
653 end
679 end
654 end
680 end
655
681
656 json = ActiveSupport::JSON.decode(response.body)
682 json = ActiveSupport::JSON.decode(response.body)
657 assert json['errors'].include?("Subject can't be blank")
683 assert json['errors'].include?("Subject can't be blank")
658 end
684 end
659 end
685 end
660
686
661 context "DELETE /issues/1.xml" do
687 context "DELETE /issues/1.xml" do
662 should_allow_api_authentication(:delete,
688 should_allow_api_authentication(:delete,
663 '/issues/6.xml',
689 '/issues/6.xml',
664 {},
690 {},
665 {:success_code => :ok})
691 {:success_code => :ok})
666
692
667 should "delete the issue" do
693 should "delete the issue" do
668 assert_difference('Issue.count', -1) do
694 assert_difference('Issue.count', -1) do
669 delete '/issues/6.xml', {}, credentials('jsmith')
695 delete '/issues/6.xml', {}, credentials('jsmith')
670
696
671 assert_response :ok
697 assert_response :ok
672 assert_equal '', response.body
698 assert_equal '', response.body
673 end
699 end
674
700
675 assert_nil Issue.find_by_id(6)
701 assert_nil Issue.find_by_id(6)
676 end
702 end
677 end
703 end
678
704
679 context "DELETE /issues/1.json" do
705 context "DELETE /issues/1.json" do
680 should_allow_api_authentication(:delete,
706 should_allow_api_authentication(:delete,
681 '/issues/6.json',
707 '/issues/6.json',
682 {},
708 {},
683 {:success_code => :ok})
709 {:success_code => :ok})
684
710
685 should "delete the issue" do
711 should "delete the issue" do
686 assert_difference('Issue.count', -1) do
712 assert_difference('Issue.count', -1) do
687 delete '/issues/6.json', {}, credentials('jsmith')
713 delete '/issues/6.json', {}, credentials('jsmith')
688
714
689 assert_response :ok
715 assert_response :ok
690 assert_equal '', response.body
716 assert_equal '', response.body
691 end
717 end
692
718
693 assert_nil Issue.find_by_id(6)
719 assert_nil Issue.find_by_id(6)
694 end
720 end
695 end
721 end
696
722
697 def test_create_issue_with_uploaded_file
723 def test_create_issue_with_uploaded_file
698 set_tmp_attachments_directory
724 set_tmp_attachments_directory
699
700 # upload the file
725 # upload the file
701 assert_difference 'Attachment.count' do
726 assert_difference 'Attachment.count' do
702 post '/uploads.xml', 'test_create_with_upload', {"CONTENT_TYPE" => 'application/octet-stream'}.merge(credentials('jsmith'))
727 post '/uploads.xml', 'test_create_with_upload',
728 {"CONTENT_TYPE" => 'application/octet-stream'}.merge(credentials('jsmith'))
703 assert_response :created
729 assert_response :created
704 end
730 end
705 xml = Hash.from_xml(response.body)
731 xml = Hash.from_xml(response.body)
706 token = xml['upload']['token']
732 token = xml['upload']['token']
707 attachment = Attachment.first(:order => 'id DESC')
733 attachment = Attachment.first(:order => 'id DESC')
708
734
709 # create the issue with the upload's token
735 # create the issue with the upload's token
710 assert_difference 'Issue.count' do
736 assert_difference 'Issue.count' do
711 post '/issues.xml',
737 post '/issues.xml',
712 {:issue => {:project_id => 1, :subject => 'Uploaded file', :uploads => [{:token => token, :filename => 'test.txt', :content_type => 'text/plain'}]}},
738 {:issue => {:project_id => 1, :subject => 'Uploaded file',
713 credentials('jsmith')
739 :uploads => [{:token => token, :filename => 'test.txt',
740 :content_type => 'text/plain'}]}},
741 credentials('jsmith')
714 assert_response :created
742 assert_response :created
715 end
743 end
716 issue = Issue.first(:order => 'id DESC')
744 issue = Issue.first(:order => 'id DESC')
717 assert_equal 1, issue.attachments.count
745 assert_equal 1, issue.attachments.count
718 assert_equal attachment, issue.attachments.first
746 assert_equal attachment, issue.attachments.first
719
747
720 attachment.reload
748 attachment.reload
721 assert_equal 'test.txt', attachment.filename
749 assert_equal 'test.txt', attachment.filename
722 assert_equal 'text/plain', attachment.content_type
750 assert_equal 'text/plain', attachment.content_type
723 assert_equal 'test_create_with_upload'.size, attachment.filesize
751 assert_equal 'test_create_with_upload'.size, attachment.filesize
724 assert_equal 2, attachment.author_id
752 assert_equal 2, attachment.author_id
725
753
726 # get the issue with its attachments
754 # get the issue with its attachments
727 get "/issues/#{issue.id}.xml", :include => 'attachments'
755 get "/issues/#{issue.id}.xml", :include => 'attachments'
728 assert_response :success
756 assert_response :success
729 xml = Hash.from_xml(response.body)
757 xml = Hash.from_xml(response.body)
730 attachments = xml['issue']['attachments']
758 attachments = xml['issue']['attachments']
731 assert_kind_of Array, attachments
759 assert_kind_of Array, attachments
732 assert_equal 1, attachments.size
760 assert_equal 1, attachments.size
733 url = attachments.first['content_url']
761 url = attachments.first['content_url']
734 assert_not_nil url
762 assert_not_nil url
735
763
736 # download the attachment
764 # download the attachment
737 get url
765 get url
738 assert_response :success
766 assert_response :success
739 end
767 end
740
768
741 def test_update_issue_with_uploaded_file
769 def test_update_issue_with_uploaded_file
742 set_tmp_attachments_directory
770 set_tmp_attachments_directory
743
744 # upload the file
771 # upload the file
745 assert_difference 'Attachment.count' do
772 assert_difference 'Attachment.count' do
746 post '/uploads.xml', 'test_upload_with_upload', {"CONTENT_TYPE" => 'application/octet-stream'}.merge(credentials('jsmith'))
773 post '/uploads.xml', 'test_upload_with_upload',
774 {"CONTENT_TYPE" => 'application/octet-stream'}.merge(credentials('jsmith'))
747 assert_response :created
775 assert_response :created
748 end
776 end
749 xml = Hash.from_xml(response.body)
777 xml = Hash.from_xml(response.body)
750 token = xml['upload']['token']
778 token = xml['upload']['token']
751 attachment = Attachment.first(:order => 'id DESC')
779 attachment = Attachment.first(:order => 'id DESC')
752
780
753 # update the issue with the upload's token
781 # update the issue with the upload's token
754 assert_difference 'Journal.count' do
782 assert_difference 'Journal.count' do
755 put '/issues/1.xml',
783 put '/issues/1.xml',
756 {:issue => {:notes => 'Attachment added', :uploads => [{:token => token, :filename => 'test.txt', :content_type => 'text/plain'}]}},
784 {:issue => {:notes => 'Attachment added',
757 credentials('jsmith')
785 :uploads => [{:token => token, :filename => 'test.txt',
786 :content_type => 'text/plain'}]}},
787 credentials('jsmith')
758 assert_response :ok
788 assert_response :ok
759 assert_equal '', @response.body
789 assert_equal '', @response.body
760 end
790 end
761
791
762 issue = Issue.find(1)
792 issue = Issue.find(1)
763 assert_include attachment, issue.attachments
793 assert_include attachment, issue.attachments
764 end
794 end
765 end
795 end
General Comments 0
You need to be logged in to leave comments. Login now