To check out this repository please hg clone the following URL, or open the URL using EasyMercurial or your preferred Mercurial client.

Statistics Download as Zip
| Branch: | Tag: | Revision:

root / .svn / pristine / 00 / 00e064a58814bd1506484c9e41b6bc1f8553a834.svn-base @ 1297:0a574315af3e

History | View | Annotate | Download (24.6 KB)

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