diff --git a/test/integration/api_test/issues_test.rb b/test/integration/api_test/issues_test.rb index 161beee..439e1d4 100644 --- a/test/integration/api_test/issues_test.rb +++ b/test/integration/api_test/issues_test.rb @@ -561,6 +561,63 @@ class Redmine::ApiTest::IssuesTest < Redmine::ApiTest::Base assert_response :success end + def test_create_issue_with_multiple_uploaded_files_as_xml + token1 = xml_upload('File content 1', credentials('jsmith')) + token2 = xml_upload('File content 2', credentials('jsmith')) + + payload = <<-XML + + + 1 + 1 + Issue with multiple attachments + + + #{token1} + test1.txt + + + #{token2} + test1.txt + + + +XML + + assert_difference 'Issue.count' do + post '/issues.xml', payload, {"CONTENT_TYPE" => 'application/xml'}.merge(credentials('jsmith')) + assert_response :created + end + issue = Issue.order('id DESC').first + assert_equal 2, issue.attachments.count + end + + def test_create_issue_with_multiple_uploaded_files_as_json + token1 = json_upload('File content 1', credentials('jsmith')) + token2 = json_upload('File content 2', credentials('jsmith')) + + payload = <<-JSON +{ + "issue": { + "project_id": "1", + "tracker_id": "1", + "subject": "Issue with multiple attachments", + "uploads": [ + {"token": "#{token1}", "filename": "test1.txt"}, + {"token": "#{token2}", "filename": "test2.txt"} + ] + } +} +JSON + + assert_difference 'Issue.count' do + post '/issues.json', payload, {"CONTENT_TYPE" => 'application/json'}.merge(credentials('jsmith')) + assert_response :created + end + issue = Issue.order('id DESC').first + assert_equal 2, issue.attachments.count + end + def test_update_issue_with_uploaded_file set_tmp_attachments_directory # upload the file diff --git a/test/test_helper.rb b/test/test_helper.rb index 44ea86f..22b96a8 100644 --- a/test/test_helper.rb +++ b/test/test_helper.rb @@ -271,6 +271,45 @@ module Redmine def teardown Setting.rest_api_enabled = '0' end + + # Uploads content using the XML API and returns the attachment token + def xml_upload(content, credentials) + upload('xml', content, credentials) + end + + # Uploads content using the JSON API and returns the attachment token + def json_upload(content, credentials) + upload('json', content, credentials) + end + + def upload(format, content, credentials) + set_tmp_attachments_directory + assert_difference 'Attachment.count' do + post "/uploads.#{format}", content, {"CONTENT_TYPE" => 'application/octet-stream'}.merge(credentials) + assert_response :created + end + data = response_data + assert_kind_of Hash, data['upload'] + token = data['upload']['token'] + assert_not_nil token + token + end + + # Parses the response body based on its content type + def response_data + unless response.content_type.to_s =~ /^application\/(.+)/ + raise "Unexpected response type: #{response.content_type}" + end + format = $1 + case format + when 'xml' + Hash.from_xml(response.body) + when 'json' + ActiveSupport::JSON.decode(response.body) + else + raise "Unknown response format: #{format}" + end + end end class Routing < Redmine::RoutingTest