|
|
@@ -48,98 +48,117 @@ class Redmine::ApiTest::IssuesTest < Redmine::ApiTest::Base |
|
|
|
Setting.rest_api_enabled = '1' |
|
|
|
end |
|
|
|
|
|
|
|
context "/issues" do |
|
|
|
# Use a private project to make sure auth is really working and not just |
|
|
|
# only showing public issues. |
|
|
|
should_allow_api_authentication(:get, "/projects/private-child/issues.xml") |
|
|
|
|
|
|
|
should "contain metadata" do |
|
|
|
get '/issues.xml' |
|
|
|
# Use a private project to make sure auth is really working and not just |
|
|
|
# only showing public issues. |
|
|
|
should_allow_api_authentication(:get, "/projects/private-child/issues.xml") |
|
|
|
should_allow_api_authentication(:get, "/projects/private-child/issues.json") |
|
|
|
|
|
|
|
should_allow_api_authentication(:get, "/issues/6.xml") |
|
|
|
should_allow_api_authentication(:get, "/issues/6.json") |
|
|
|
|
|
|
|
should_allow_api_authentication( |
|
|
|
:post, |
|
|
|
'/issues.xml', |
|
|
|
{:issue => {:project_id => 1, :subject => 'API test', :tracker_id => 2, :status_id => 3}}, |
|
|
|
{:success_code => :created} |
|
|
|
) |
|
|
|
should_allow_api_authentication(:post, |
|
|
|
'/issues.json', |
|
|
|
{:issue => {:project_id => 1, :subject => 'API test', |
|
|
|
:tracker_id => 2, :status_id => 3}}, |
|
|
|
{:success_code => :created}) |
|
|
|
|
|
|
|
should_allow_api_authentication(:put, |
|
|
|
'/issues/6.xml', |
|
|
|
{:issue => {:subject => 'API update', :notes => 'A new note'}}, |
|
|
|
{:success_code => :ok}) |
|
|
|
should_allow_api_authentication(:put, |
|
|
|
'/issues/6.json', |
|
|
|
{:issue => {:subject => 'API update', :notes => 'A new note'}}, |
|
|
|
{:success_code => :ok}) |
|
|
|
|
|
|
|
should_allow_api_authentication(:delete, |
|
|
|
'/issues/6.xml', |
|
|
|
{}, |
|
|
|
{:success_code => :ok}) |
|
|
|
should_allow_api_authentication(:delete, |
|
|
|
'/issues/6.json', |
|
|
|
{}, |
|
|
|
{:success_code => :ok}) |
|
|
|
|
|
|
|
test "GET /issues.xml should contain metadata" do |
|
|
|
get '/issues.xml' |
|
|
|
assert_select 'issues[type=array][total_count=?][limit="25"][offset="0"]', |
|
|
|
assigns(:issue_count).to_s |
|
|
|
end |
|
|
|
|
|
|
|
assert_select 'issues[type=array][total_count=?][limit="25"][offset="0"]', assigns(:issue_count).to_s |
|
|
|
end |
|
|
|
test "GET /issues.xml with nometa param should not contain metadata" do |
|
|
|
get '/issues.xml?nometa=1' |
|
|
|
assert_select 'issues[type=array]:not([total_count]):not([limit]):not([offset])' |
|
|
|
end |
|
|
|
|
|
|
|
context "with offset and limit" do |
|
|
|
should "use the params" do |
|
|
|
get '/issues.xml?offset=2&limit=3' |
|
|
|
test "GET /issues.xml with nometa header should not contain metadata" do |
|
|
|
get '/issues.xml', {}, {'X-Redmine-Nometa' => '1'} |
|
|
|
assert_select 'issues[type=array]:not([total_count]):not([limit]):not([offset])' |
|
|
|
end |
|
|
|
|
|
|
|
assert_equal 3, assigns(:limit) |
|
|
|
assert_equal 2, assigns(:offset) |
|
|
|
assert_select 'issues issue', 3 |
|
|
|
end |
|
|
|
end |
|
|
|
test "GET /issues.xml with offset and limit" do |
|
|
|
get '/issues.xml?offset=2&limit=3' |
|
|
|
|
|
|
|
context "with nometa param" do |
|
|
|
should "not contain metadata" do |
|
|
|
get '/issues.xml?nometa=1' |
|
|
|
assert_equal 3, assigns(:limit) |
|
|
|
assert_equal 2, assigns(:offset) |
|
|
|
assert_select 'issues issue', 3 |
|
|
|
end |
|
|
|
|
|
|
|
assert_select 'issues[type=array]:not([total_count]):not([limit]):not([offset])' |
|
|
|
end |
|
|
|
end |
|
|
|
test "GET /issues.xml with relations" do |
|
|
|
get '/issues.xml?include=relations' |
|
|
|
|
|
|
|
context "with nometa header" do |
|
|
|
should "not contain metadata" do |
|
|
|
get '/issues.xml', {}, {'X-Redmine-Nometa' => '1'} |
|
|
|
assert_response :success |
|
|
|
assert_equal 'application/xml', @response.content_type |
|
|
|
|
|
|
|
assert_select 'issues[type=array]:not([total_count]):not([limit]):not([offset])' |
|
|
|
end |
|
|
|
assert_select 'issue id:content(3)' do |
|
|
|
assert_select '~ relations relation', 1 |
|
|
|
assert_select '~ relations relation[id="2"][issue_id="2"][issue_to_id="3"][relation_type=relates]' |
|
|
|
end |
|
|
|
|
|
|
|
context "with relations" do |
|
|
|
should "display relations" do |
|
|
|
get '/issues.xml?include=relations' |
|
|
|
|
|
|
|
assert_response :success |
|
|
|
assert_equal 'application/xml', @response.content_type |
|
|
|
assert_select 'issue id:content(1)' do |
|
|
|
assert_select '~ relations' |
|
|
|
assert_select '~ relations relation', 0 |
|
|
|
end |
|
|
|
end |
|
|
|
|
|
|
|
assert_select 'issue id:content(3)' do |
|
|
|
assert_select '~ relations relation', 1 |
|
|
|
assert_select '~ relations relation[id="2"][issue_id="2"][issue_to_id="3"][relation_type=relates]' |
|
|
|
end |
|
|
|
test "GET /issues.xml with invalid query params" do |
|
|
|
get '/issues.xml', {:f => ['start_date'], :op => {:start_date => '='}} |
|
|
|
|
|
|
|
assert_select 'issue id:content(1)' do |
|
|
|
assert_select '~ relations' |
|
|
|
assert_select '~ relations relation', 0 |
|
|
|
end |
|
|
|
end |
|
|
|
end |
|
|
|
assert_response :unprocessable_entity |
|
|
|
assert_equal 'application/xml', @response.content_type |
|
|
|
assert_select 'errors error', :text => "Start date can't be blank" |
|
|
|
end |
|
|
|
|
|
|
|
context "with invalid query params" do |
|
|
|
should "return errors" do |
|
|
|
get '/issues.xml', {:f => ['start_date'], :op => {:start_date => '='}} |
|
|
|
test "GET /issues.xml with custom field filter" do |
|
|
|
get '/issues.xml', |
|
|
|
{:set_filter => 1, :f => ['cf_1'], :op => {:cf_1 => '='}, :v => {:cf_1 => ['MySQL']}} |
|
|
|
|
|
|
|
assert_response :unprocessable_entity |
|
|
|
assert_equal 'application/xml', @response.content_type |
|
|
|
assert_select 'errors error', :text => "Start date can't be blank" |
|
|
|
end |
|
|
|
end |
|
|
|
expected_ids = Issue.visible. |
|
|
|
joins(:custom_values). |
|
|
|
where(:custom_values => {:custom_field_id => 1, :value => 'MySQL'}).map(&:id) |
|
|
|
assert expected_ids.any? |
|
|
|
|
|
|
|
context "with custom field filter" do |
|
|
|
should "show only issues with the custom field value" do |
|
|
|
get '/issues.xml', |
|
|
|
{:set_filter => 1, :f => ['cf_1'], :op => {:cf_1 => '='}, |
|
|
|
:v => {:cf_1 => ['MySQL']}} |
|
|
|
expected_ids = Issue.visible. |
|
|
|
joins(:custom_values). |
|
|
|
where(:custom_values => {:custom_field_id => 1, :value => 'MySQL'}).map(&:id) |
|
|
|
assert_select 'issues > issue > id', :count => expected_ids.count do |ids| |
|
|
|
ids.each { |id| assert expected_ids.delete(id.children.first.content.to_i) } |
|
|
|
end |
|
|
|
end |
|
|
|
assert_select 'issues > issue > id', :count => expected_ids.count do |ids| |
|
|
|
ids.each { |id| assert expected_ids.delete(id.children.first.content.to_i) } |
|
|
|
end |
|
|
|
end |
|
|
|
|
|
|
|
context "with custom field filter (shorthand method)" do |
|
|
|
should "show only issues with the custom field value" do |
|
|
|
get '/issues.xml', { :cf_1 => 'MySQL' } |
|
|
|
test "GET /issues.xml with custom field filter (shorthand method)" do |
|
|
|
get '/issues.xml', {:cf_1 => 'MySQL'} |
|
|
|
|
|
|
|
expected_ids = Issue.visible. |
|
|
|
joins(:custom_values). |
|
|
|
where(:custom_values => {:custom_field_id => 1, :value => 'MySQL'}).map(&:id) |
|
|
|
expected_ids = Issue.visible. |
|
|
|
joins(:custom_values). |
|
|
|
where(:custom_values => {:custom_field_id => 1, :value => 'MySQL'}).map(&:id) |
|
|
|
assert expected_ids.any? |
|
|
|
|
|
|
|
assert_select 'issues > issue > id', :count => expected_ids.count do |ids| |
|
|
|
ids.each { |id| assert expected_ids.delete(id.children.first.content.to_i) } |
|
|
|
end |
|
|
|
end |
|
|
|
assert_select 'issues > issue > id', :count => expected_ids.count do |ids| |
|
|
|
ids.each { |id| assert expected_ids.delete(id.children.first.content.to_i) } |
|
|
|
end |
|
|
|
end |
|
|
|
|
|
|
@@ -171,234 +190,163 @@ class Redmine::ApiTest::IssuesTest < Redmine::ApiTest::Base |
|
|
|
assert_select 'issues>issue', :count => 2 |
|
|
|
end |
|
|
|
|
|
|
|
context "/index.json" do |
|
|
|
should_allow_api_authentication(:get, "/projects/private-child/issues.json") |
|
|
|
end |
|
|
|
test "GET /issues.xml with filter" do |
|
|
|
get '/issues.xml?status_id=5' |
|
|
|
|
|
|
|
context "/index.xml with filter" do |
|
|
|
should "show only issues with the status_id" do |
|
|
|
get '/issues.xml?status_id=5' |
|
|
|
expected_ids = Issue.visible.where(:status_id => 5).map(&:id) |
|
|
|
assert expected_ids.any? |
|
|
|
|
|
|
|
expected_ids = Issue.visible.where(:status_id => 5).map(&:id) |
|
|
|
|
|
|
|
assert_select 'issues > issue > id', :count => expected_ids.count do |ids| |
|
|
|
ids.each { |id| assert expected_ids.delete(id.children.first.content.to_i) } |
|
|
|
end |
|
|
|
assert_select 'issues > issue > id', :count => expected_ids.count do |ids| |
|
|
|
ids.each { |id| assert expected_ids.delete(id.children.first.content.to_i) } |
|
|
|
end |
|
|
|
end |
|
|
|
|
|
|
|
context "/index.json with filter" do |
|
|
|
should "show only issues with the status_id" do |
|
|
|
get '/issues.json?status_id=5' |
|
|
|
|
|
|
|
json = ActiveSupport::JSON.decode(response.body) |
|
|
|
status_ids_used = json['issues'].collect {|j| j['status']['id'] } |
|
|
|
assert_equal 3, status_ids_used.length |
|
|
|
assert status_ids_used.all? {|id| id == 5 } |
|
|
|
end |
|
|
|
test "GET /issues.json with filter" do |
|
|
|
get '/issues.json?status_id=5' |
|
|
|
|
|
|
|
json = ActiveSupport::JSON.decode(response.body) |
|
|
|
status_ids_used = json['issues'].collect {|j| j['status']['id'] } |
|
|
|
assert_equal 3, status_ids_used.length |
|
|
|
assert status_ids_used.all? {|id| id == 5 } |
|
|
|
end |
|
|
|
|
|
|
|
# Issue 6 is on a private project |
|
|
|
context "/issues/6.xml" do |
|
|
|
should_allow_api_authentication(:get, "/issues/6.xml") |
|
|
|
end |
|
|
|
test "GET /issues/:id.xml with journals" do |
|
|
|
get '/issues/1.xml?include=journals' |
|
|
|
|
|
|
|
context "/issues/6.json" do |
|
|
|
should_allow_api_authentication(:get, "/issues/6.json") |
|
|
|
assert_select 'issue journals[type=array]' do |
|
|
|
assert_select 'journal[id="1"]' do |
|
|
|
assert_select 'details[type=array]' do |
|
|
|
assert_select 'detail[name=status_id]' do |
|
|
|
assert_select 'old_value', :text => '1' |
|
|
|
assert_select 'new_value', :text => '2' |
|
|
|
end |
|
|
|
end |
|
|
|
end |
|
|
|
end |
|
|
|
end |
|
|
|
|
|
|
|
context "GET /issues/:id" do |
|
|
|
context "with journals" do |
|
|
|
context ".xml" do |
|
|
|
should "display journals" do |
|
|
|
get '/issues/1.xml?include=journals' |
|
|
|
test "GET /issues/:id.xml with custom fields" do |
|
|
|
get '/issues/3.xml' |
|
|
|
|
|
|
|
assert_select 'issue journals[type=array]' do |
|
|
|
assert_select 'journal[id="1"]' do |
|
|
|
assert_select 'details[type=array]' do |
|
|
|
assert_select 'detail[name=status_id]' do |
|
|
|
assert_select 'old_value', :text => '1' |
|
|
|
assert_select 'new_value', :text => '2' |
|
|
|
end |
|
|
|
end |
|
|
|
end |
|
|
|
end |
|
|
|
end |
|
|
|
assert_select 'issue custom_fields[type=array]' do |
|
|
|
assert_select 'custom_field[id="1"]' do |
|
|
|
assert_select 'value', :text => 'MySQL' |
|
|
|
end |
|
|
|
end |
|
|
|
assert_nothing_raised do |
|
|
|
Hash.from_xml(response.body).to_xml |
|
|
|
end |
|
|
|
end |
|
|
|
|
|
|
|
context "with custom fields" do |
|
|
|
context ".xml" do |
|
|
|
should "display custom fields" do |
|
|
|
get '/issues/3.xml' |
|
|
|
test "GET /issues/:id.xml with multi custom fields" do |
|
|
|
field = CustomField.find(1) |
|
|
|
field.update_attribute :multiple, true |
|
|
|
issue = Issue.find(3) |
|
|
|
issue.custom_field_values = {1 => ['MySQL', 'Oracle']} |
|
|
|
issue.save! |
|
|
|
|
|
|
|
assert_select 'issue custom_fields[type=array]' do |
|
|
|
assert_select 'custom_field[id="1"]' do |
|
|
|
assert_select 'value', :text => 'MySQL' |
|
|
|
end |
|
|
|
end |
|
|
|
get '/issues/3.xml' |
|
|
|
assert_response :success |
|
|
|
|
|
|
|
assert_nothing_raised do |
|
|
|
Hash.from_xml(response.body).to_xml |
|
|
|
end |
|
|
|
end |
|
|
|
assert_select 'issue custom_fields[type=array]' do |
|
|
|
assert_select 'custom_field[id="1"]' do |
|
|
|
assert_select 'value[type=array] value', 2 |
|
|
|
end |
|
|
|
end |
|
|
|
xml = Hash.from_xml(response.body) |
|
|
|
custom_fields = xml['issue']['custom_fields'] |
|
|
|
assert_kind_of Array, custom_fields |
|
|
|
field = custom_fields.detect {|f| f['id'] == '1'} |
|
|
|
assert_kind_of Hash, field |
|
|
|
assert_equal ['MySQL', 'Oracle'], field['value'].sort |
|
|
|
end |
|
|
|
|
|
|
|
context "with multi custom fields" do |
|
|
|
setup do |
|
|
|
field = CustomField.find(1) |
|
|
|
field.update_attribute :multiple, true |
|
|
|
issue = Issue.find(3) |
|
|
|
issue.custom_field_values = {1 => ['MySQL', 'Oracle']} |
|
|
|
issue.save! |
|
|
|
end |
|
|
|
test "GET /issues/:id.json with multi custom fields" do |
|
|
|
field = CustomField.find(1) |
|
|
|
field.update_attribute :multiple, true |
|
|
|
issue = Issue.find(3) |
|
|
|
issue.custom_field_values = {1 => ['MySQL', 'Oracle']} |
|
|
|
issue.save! |
|
|
|
|
|
|
|
context ".xml" do |
|
|
|
should "display custom fields" do |
|
|
|
get '/issues/3.xml' |
|
|
|
assert_response :success |
|
|
|
get '/issues/3.json' |
|
|
|
assert_response :success |
|
|
|
|
|
|
|
assert_select 'issue custom_fields[type=array]' do |
|
|
|
assert_select 'custom_field[id="1"]' do |
|
|
|
assert_select 'value[type=array] value', 2 |
|
|
|
end |
|
|
|
end |
|
|
|
json = ActiveSupport::JSON.decode(response.body) |
|
|
|
custom_fields = json['issue']['custom_fields'] |
|
|
|
assert_kind_of Array, custom_fields |
|
|
|
field = custom_fields.detect {|f| f['id'] == 1} |
|
|
|
assert_kind_of Hash, field |
|
|
|
assert_equal ['MySQL', 'Oracle'], field['value'].sort |
|
|
|
end |
|
|
|
|
|
|
|
xml = Hash.from_xml(response.body) |
|
|
|
custom_fields = xml['issue']['custom_fields'] |
|
|
|
assert_kind_of Array, custom_fields |
|
|
|
field = custom_fields.detect {|f| f['id'] == '1'} |
|
|
|
assert_kind_of Hash, field |
|
|
|
assert_equal ['MySQL', 'Oracle'], field['value'].sort |
|
|
|
end |
|
|
|
end |
|
|
|
test "GET /issues/:id.xml with empty value for multi custom field" do |
|
|
|
field = CustomField.find(1) |
|
|
|
field.update_attribute :multiple, true |
|
|
|
issue = Issue.find(3) |
|
|
|
issue.custom_field_values = {1 => ['']} |
|
|
|
issue.save! |
|
|
|
|
|
|
|
context ".json" do |
|
|
|
should "display custom fields" do |
|
|
|
get '/issues/3.json' |
|
|
|
assert_response :success |
|
|
|
json = ActiveSupport::JSON.decode(response.body) |
|
|
|
custom_fields = json['issue']['custom_fields'] |
|
|
|
assert_kind_of Array, custom_fields |
|
|
|
field = custom_fields.detect {|f| f['id'] == 1} |
|
|
|
assert_kind_of Hash, field |
|
|
|
assert_equal ['MySQL', 'Oracle'], field['value'].sort |
|
|
|
end |
|
|
|
end |
|
|
|
end |
|
|
|
get '/issues/3.xml' |
|
|
|
|
|
|
|
context "with empty value for multi custom field" do |
|
|
|
setup do |
|
|
|
field = CustomField.find(1) |
|
|
|
field.update_attribute :multiple, true |
|
|
|
issue = Issue.find(3) |
|
|
|
issue.custom_field_values = {1 => ['']} |
|
|
|
issue.save! |
|
|
|
assert_select 'issue custom_fields[type=array]' do |
|
|
|
assert_select 'custom_field[id="1"]' do |
|
|
|
assert_select 'value[type=array]:empty' |
|
|
|
end |
|
|
|
end |
|
|
|
xml = Hash.from_xml(response.body) |
|
|
|
custom_fields = xml['issue']['custom_fields'] |
|
|
|
assert_kind_of Array, custom_fields |
|
|
|
field = custom_fields.detect {|f| f['id'] == '1'} |
|
|
|
assert_kind_of Hash, field |
|
|
|
assert_equal [], field['value'] |
|
|
|
end |
|
|
|
|
|
|
|
context ".xml" do |
|
|
|
should "display custom fields" do |
|
|
|
get '/issues/3.xml' |
|
|
|
test "GET /issues/:id.json with empty value for multi custom field" do |
|
|
|
field = CustomField.find(1) |
|
|
|
field.update_attribute :multiple, true |
|
|
|
issue = Issue.find(3) |
|
|
|
issue.custom_field_values = {1 => ['']} |
|
|
|
issue.save! |
|
|
|
|
|
|
|
assert_select 'issue custom_fields[type=array]' do |
|
|
|
assert_select 'custom_field[id="1"]' do |
|
|
|
assert_select 'value[type=array]:empty' |
|
|
|
end |
|
|
|
end |
|
|
|
get '/issues/3.json' |
|
|
|
assert_response :success |
|
|
|
json = ActiveSupport::JSON.decode(response.body) |
|
|
|
custom_fields = json['issue']['custom_fields'] |
|
|
|
assert_kind_of Array, custom_fields |
|
|
|
field = custom_fields.detect {|f| f['id'] == 1} |
|
|
|
assert_kind_of Hash, field |
|
|
|
assert_equal [], field['value'].sort |
|
|
|
end |
|
|
|
|
|
|
|
xml = Hash.from_xml(response.body) |
|
|
|
custom_fields = xml['issue']['custom_fields'] |
|
|
|
assert_kind_of Array, custom_fields |
|
|
|
field = custom_fields.detect {|f| f['id'] == '1'} |
|
|
|
assert_kind_of Hash, field |
|
|
|
assert_equal [], field['value'] |
|
|
|
end |
|
|
|
end |
|
|
|
test "GET /issues/:id.xml with attachments" do |
|
|
|
get '/issues/3.xml?include=attachments' |
|
|
|
|
|
|
|
context ".json" do |
|
|
|
should "display custom fields" do |
|
|
|
get '/issues/3.json' |
|
|
|
assert_response :success |
|
|
|
json = ActiveSupport::JSON.decode(response.body) |
|
|
|
custom_fields = json['issue']['custom_fields'] |
|
|
|
assert_kind_of Array, custom_fields |
|
|
|
field = custom_fields.detect {|f| f['id'] == 1} |
|
|
|
assert_kind_of Hash, field |
|
|
|
assert_equal [], field['value'].sort |
|
|
|
end |
|
|
|
assert_select 'issue attachments[type=array]' do |
|
|
|
assert_select 'attachment', 5 |
|
|
|
assert_select 'attachment id:content(4)' do |
|
|
|
assert_select '~ filename', :text => 'source.rb' |
|
|
|
assert_select '~ content_url', :text => 'http://www.example.com/attachments/download/4/source.rb' |
|
|
|
end |
|
|
|
end |
|
|
|
end |
|
|
|
|
|
|
|
context "with attachments" do |
|
|
|
context ".xml" do |
|
|
|
should "display attachments" do |
|
|
|
get '/issues/3.xml?include=attachments' |
|
|
|
|
|
|
|
assert_select 'issue attachments[type=array]' do |
|
|
|
assert_select 'attachment', 5 |
|
|
|
assert_select 'attachment id:content(4)' do |
|
|
|
assert_select '~ filename', :text => 'source.rb' |
|
|
|
assert_select '~ content_url', :text => 'http://www.example.com/attachments/download/4/source.rb' |
|
|
|
end |
|
|
|
end |
|
|
|
end |
|
|
|
end |
|
|
|
end |
|
|
|
test "GET /issues/:id.xml with subtasks" do |
|
|
|
issue = Issue.generate_with_descendants!(:project_id => 1) |
|
|
|
get "/issues/#{issue.id}.xml?include=children" |
|
|
|
|
|
|
|
context "with subtasks" do |
|
|
|
setup do |
|
|
|
@c1 = Issue.create!( |
|
|
|
:status_id => 1, :subject => "child c1", |
|
|
|
:tracker_id => 1, :project_id => 1, :author_id => 1, |
|
|
|
:parent_issue_id => 1 |
|
|
|
) |
|
|
|
@c2 = Issue.create!( |
|
|
|
:status_id => 1, :subject => "child c2", |
|
|
|
:tracker_id => 1, :project_id => 1, :author_id => 1, |
|
|
|
:parent_issue_id => 1 |
|
|
|
) |
|
|
|
@c3 = Issue.create!( |
|
|
|
:status_id => 1, :subject => "child c3", |
|
|
|
:tracker_id => 1, :project_id => 1, :author_id => 1, |
|
|
|
:parent_issue_id => @c1.id |
|
|
|
) |
|
|
|
end |
|
|
|
assert_select 'issue children[type=array]' do |
|
|
|
assert_select 'issue', 2 |
|
|
|
assert_select 'issue children', 1 |
|
|
|
end |
|
|
|
end |
|
|
|
|
|
|
|
context ".xml" do |
|
|
|
should "display children" do |
|
|
|
get '/issues/1.xml?include=children' |
|
|
|
|
|
|
|
assert_select 'issue children[type=array]' do |
|
|
|
assert_select 'issue', 2 |
|
|
|
assert_select 'issue[id=?]', @c1.id.to_s do |
|
|
|
assert_select 'subject', :text => 'child c1' |
|
|
|
assert_select 'children' do |
|
|
|
assert_select 'issue[id=?]', @c3.id.to_s |
|
|
|
end |
|
|
|
end |
|
|
|
end |
|
|
|
end |
|
|
|
test "GET /issues/:id.json with subtasks" do |
|
|
|
issue = Issue.generate_with_descendants!(:project_id => 1) |
|
|
|
get "/issues/#{issue.id}.json?include=children" |
|
|
|
|
|
|
|
context ".json" do |
|
|
|
should "display children" do |
|
|
|
get '/issues/1.json?include=children' |
|
|
|
|
|
|
|
json = ActiveSupport::JSON.decode(response.body) |
|
|
|
assert_equal([ |
|
|
|
{ |
|
|
|
'id' => @c1.id, 'subject' => 'child c1', 'tracker' => {'id' => 1, 'name' => 'Bug'}, |
|
|
|
'children' => [{'id' => @c3.id, 'subject' => 'child c3', |
|
|
|
'tracker' => {'id' => 1, 'name' => 'Bug'} }] |
|
|
|
}, |
|
|
|
{ 'id' => @c2.id, 'subject' => 'child c2', 'tracker' => {'id' => 1, 'name' => 'Bug'} } |
|
|
|
], |
|
|
|
json['issue']['children']) |
|
|
|
end |
|
|
|
end |
|
|
|
end |
|
|
|
end |
|
|
|
json = ActiveSupport::JSON.decode(response.body) |
|
|
|
assert_equal 2, json['issue']['children'].size |
|
|
|
assert_equal 1, json['issue']['children'].select {|child| child.key?('children')}.size |
|
|
|
end |
|
|
|
|
|
|
|
def test_show_should_include_issue_attributes |
|
|
@@ -421,29 +369,21 @@ class Redmine::ApiTest::IssuesTest < Redmine::ApiTest::Base |
|
|
|
end |
|
|
|
end |
|
|
|
|
|
|
|
context "POST /issues.xml" do |
|
|
|
should_allow_api_authentication( |
|
|
|
:post, |
|
|
|
'/issues.xml', |
|
|
|
{:issue => {:project_id => 1, :subject => 'API test', :tracker_id => 2, :status_id => 3}}, |
|
|
|
{:success_code => :created} |
|
|
|
) |
|
|
|
should "create an issue with the attributes" do |
|
|
|
assert_difference('Issue.count') do |
|
|
|
post '/issues.xml', |
|
|
|
{:issue => {:project_id => 1, :subject => 'API test', |
|
|
|
:tracker_id => 2, :status_id => 3}}, credentials('jsmith') |
|
|
|
end |
|
|
|
issue = Issue.order('id DESC').first |
|
|
|
assert_equal 1, issue.project_id |
|
|
|
assert_equal 2, issue.tracker_id |
|
|
|
assert_equal 3, issue.status_id |
|
|
|
assert_equal 'API test', issue.subject |
|
|
|
|
|
|
|
assert_response :created |
|
|
|
assert_equal 'application/xml', @response.content_type |
|
|
|
assert_select 'issue > id', :text => issue.id.to_s |
|
|
|
test "POST /issues.xml should create an issue with the attributes" do |
|
|
|
assert_difference('Issue.count') do |
|
|
|
post '/issues.xml', |
|
|
|
{:issue => {:project_id => 1, :subject => 'API test', |
|
|
|
:tracker_id => 2, :status_id => 3}}, credentials('jsmith') |
|
|
|
end |
|
|
|
issue = Issue.order('id DESC').first |
|
|
|
assert_equal 1, issue.project_id |
|
|
|
assert_equal 2, issue.tracker_id |
|
|
|
assert_equal 3, issue.status_id |
|
|
|
assert_equal 'API test', issue.subject |
|
|
|
|
|
|
|
assert_response :created |
|
|
|
assert_equal 'application/xml', @response.content_type |
|
|
|
assert_select 'issue > id', :text => issue.id.to_s |
|
|
|
end |
|
|
|
|
|
|
|
test "POST /issues.xml with watcher_user_ids should create issue with watchers" do |
|
|
@@ -458,246 +398,139 @@ class Redmine::ApiTest::IssuesTest < Redmine::ApiTest::Base |
|
|
|
assert_equal [1, 3], issue.watcher_user_ids.sort |
|
|
|
end |
|
|
|
|
|
|
|
context "POST /issues.xml with failure" do |
|
|
|
should "have an errors tag" do |
|
|
|
assert_no_difference('Issue.count') do |
|
|
|
post '/issues.xml', {:issue => {:project_id => 1}}, credentials('jsmith') |
|
|
|
end |
|
|
|
|
|
|
|
assert_select 'errors error', :text => "Subject can't be blank" |
|
|
|
end |
|
|
|
end |
|
|
|
|
|
|
|
context "POST /issues.json" do |
|
|
|
should_allow_api_authentication(:post, |
|
|
|
'/issues.json', |
|
|
|
{:issue => {:project_id => 1, :subject => 'API test', |
|
|
|
:tracker_id => 2, :status_id => 3}}, |
|
|
|
{:success_code => :created}) |
|
|
|
|
|
|
|
should "create an issue with the attributes" do |
|
|
|
assert_difference('Issue.count') do |
|
|
|
post '/issues.json', |
|
|
|
{:issue => {:project_id => 1, :subject => 'API test', |
|
|
|
:tracker_id => 2, :status_id => 3}}, |
|
|
|
credentials('jsmith') |
|
|
|
end |
|
|
|
|
|
|
|
issue = Issue.order('id DESC').first |
|
|
|
assert_equal 1, issue.project_id |
|
|
|
assert_equal 2, issue.tracker_id |
|
|
|
assert_equal 3, issue.status_id |
|
|
|
assert_equal 'API test', issue.subject |
|
|
|
test "POST /issues.xml with failure should return errors" do |
|
|
|
assert_no_difference('Issue.count') do |
|
|
|
post '/issues.xml', {:issue => {:project_id => 1}}, credentials('jsmith') |
|
|
|
end |
|
|
|
|
|
|
|
assert_select 'errors error', :text => "Subject can't be blank" |
|
|
|
end |
|
|
|
|
|
|
|
context "POST /issues.json with failure" do |
|
|
|
should "have an errors element" do |
|
|
|
assert_no_difference('Issue.count') do |
|
|
|
post '/issues.json', {:issue => {:project_id => 1}}, credentials('jsmith') |
|
|
|
end |
|
|
|
|
|
|
|
json = ActiveSupport::JSON.decode(response.body) |
|
|
|
assert json['errors'].include?("Subject can't be blank") |
|
|
|
end |
|
|
|
end |
|
|
|
|
|
|
|
# Issue 6 is on a private project |
|
|
|
context "PUT /issues/6.xml" do |
|
|
|
setup do |
|
|
|
@parameters = {:issue => {:subject => 'API update', :notes => 'A new note'}} |
|
|
|
end |
|
|
|
|
|
|
|
should_allow_api_authentication(:put, |
|
|
|
'/issues/6.xml', |
|
|
|
{:issue => {:subject => 'API update', :notes => 'A new note'}}, |
|
|
|
{:success_code => :ok}) |
|
|
|
|
|
|
|
should "not create a new issue" do |
|
|
|
assert_no_difference('Issue.count') do |
|
|
|
put '/issues/6.xml', @parameters, credentials('jsmith') |
|
|
|
end |
|
|
|
end |
|
|
|
|
|
|
|
should "create a new journal" do |
|
|
|
assert_difference('Journal.count') do |
|
|
|
put '/issues/6.xml', @parameters, credentials('jsmith') |
|
|
|
end |
|
|
|
end |
|
|
|
|
|
|
|
should "add the note to the journal" do |
|
|
|
put '/issues/6.xml', @parameters, credentials('jsmith') |
|
|
|
|
|
|
|
journal = Journal.last |
|
|
|
assert_equal "A new note", journal.notes |
|
|
|
end |
|
|
|
|
|
|
|
should "update the issue" do |
|
|
|
put '/issues/6.xml', @parameters, credentials('jsmith') |
|
|
|
|
|
|
|
issue = Issue.find(6) |
|
|
|
assert_equal "API update", issue.subject |
|
|
|
test "POST /issues.json should create an issue with the attributes" do |
|
|
|
assert_difference('Issue.count') do |
|
|
|
post '/issues.json', |
|
|
|
{:issue => {:project_id => 1, :subject => 'API test', |
|
|
|
:tracker_id => 2, :status_id => 3}}, |
|
|
|
credentials('jsmith') |
|
|
|
end |
|
|
|
|
|
|
|
issue = Issue.order('id DESC').first |
|
|
|
assert_equal 1, issue.project_id |
|
|
|
assert_equal 2, issue.tracker_id |
|
|
|
assert_equal 3, issue.status_id |
|
|
|
assert_equal 'API test', issue.subject |
|
|
|
end |
|
|
|
|
|
|
|
context "PUT /issues/3.xml with custom fields" do |
|
|
|
setup do |
|
|
|
@parameters = { |
|
|
|
:issue => {:custom_fields => [{'id' => '1', 'value' => 'PostgreSQL' }, |
|
|
|
{'id' => '2', 'value' => '150'}]} |
|
|
|
} |
|
|
|
test "POST /issues.json with failure should return errors" do |
|
|
|
assert_no_difference('Issue.count') do |
|
|
|
post '/issues.json', {:issue => {:project_id => 1}}, credentials('jsmith') |
|
|
|
end |
|
|
|
|
|
|
|
should "update custom fields" do |
|
|
|
assert_no_difference('Issue.count') do |
|
|
|
put '/issues/3.xml', @parameters, credentials('jsmith') |
|
|
|
end |
|
|
|
|
|
|
|
issue = Issue.find(3) |
|
|
|
assert_equal '150', issue.custom_value_for(2).value |
|
|
|
assert_equal 'PostgreSQL', issue.custom_value_for(1).value |
|
|
|
end |
|
|
|
json = ActiveSupport::JSON.decode(response.body) |
|
|
|
assert json['errors'].include?("Subject can't be blank") |
|
|
|
end |
|
|
|
|
|
|
|
context "PUT /issues/3.xml with multi custom fields" do |
|
|
|
setup do |
|
|
|
field = CustomField.find(1) |
|
|
|
field.update_attribute :multiple, true |
|
|
|
@parameters = { |
|
|
|
:issue => {:custom_fields => [{'id' => '1', 'value' => ['MySQL', 'PostgreSQL'] }, |
|
|
|
{'id' => '2', 'value' => '150'}]} |
|
|
|
} |
|
|
|
test "PUT /issues/:id.xml" do |
|
|
|
assert_difference('Journal.count') do |
|
|
|
put '/issues/6.xml', |
|
|
|
{:issue => {:subject => 'API update', :notes => 'A new note'}}, |
|
|
|
credentials('jsmith') |
|
|
|
end |
|
|
|
|
|
|
|
should "update custom fields" do |
|
|
|
assert_no_difference('Issue.count') do |
|
|
|
put '/issues/3.xml', @parameters, credentials('jsmith') |
|
|
|
end |
|
|
|
|
|
|
|
issue = Issue.find(3) |
|
|
|
assert_equal '150', issue.custom_value_for(2).value |
|
|
|
assert_equal ['MySQL', 'PostgreSQL'], issue.custom_field_value(1).sort |
|
|
|
end |
|
|
|
issue = Issue.find(6) |
|
|
|
assert_equal "API update", issue.subject |
|
|
|
journal = Journal.last |
|
|
|
assert_equal "A new note", journal.notes |
|
|
|
end |
|
|
|
|
|
|
|
context "PUT /issues/3.xml with project change" do |
|
|
|
setup do |
|
|
|
@parameters = {:issue => {:project_id => 2, :subject => 'Project changed'}} |
|
|
|
end |
|
|
|
|
|
|
|
should "update project" do |
|
|
|
assert_no_difference('Issue.count') do |
|
|
|
put '/issues/3.xml', @parameters, credentials('jsmith') |
|
|
|
end |
|
|
|
|
|
|
|
issue = Issue.find(3) |
|
|
|
assert_equal 2, issue.project_id |
|
|
|
assert_equal 'Project changed', issue.subject |
|
|
|
end |
|
|
|
test "PUT /issues/:id.xml with custom fields" do |
|
|
|
put '/issues/3.xml', |
|
|
|
{:issue => {:custom_fields => [ |
|
|
|
{'id' => '1', 'value' => 'PostgreSQL' }, |
|
|
|
{'id' => '2', 'value' => '150'} |
|
|
|
]}}, |
|
|
|
credentials('jsmith') |
|
|
|
|
|
|
|
issue = Issue.find(3) |
|
|
|
assert_equal '150', issue.custom_value_for(2).value |
|
|
|
assert_equal 'PostgreSQL', issue.custom_value_for(1).value |
|
|
|
end |
|
|
|
|
|
|
|
context "PUT /issues/6.xml with failed update" do |
|
|
|
setup do |
|
|
|
@parameters = {:issue => {:subject => ''}} |
|
|
|
end |
|
|
|
|
|
|
|
should "not create a new issue" do |
|
|
|
assert_no_difference('Issue.count') do |
|
|
|
put '/issues/6.xml', @parameters, credentials('jsmith') |
|
|
|
end |
|
|
|
end |
|
|
|
|
|
|
|
should "not create a new journal" do |
|
|
|
assert_no_difference('Journal.count') do |
|
|
|
put '/issues/6.xml', @parameters, credentials('jsmith') |
|
|
|
end |
|
|
|
end |
|
|
|
test "PUT /issues/:id.xml with multi custom fields" do |
|
|
|
field = CustomField.find(1) |
|
|
|
field.update_attribute :multiple, true |
|
|
|
|
|
|
|
should "have an errors tag" do |
|
|
|
put '/issues/6.xml', @parameters, credentials('jsmith') |
|
|
|
put '/issues/3.xml', |
|
|
|
{:issue => {:custom_fields => [ |
|
|
|
{'id' => '1', 'value' => ['MySQL', 'PostgreSQL'] }, |
|
|
|
{'id' => '2', 'value' => '150'} |
|
|
|
]}}, |
|
|
|
credentials('jsmith') |
|
|
|
|
|
|
|
assert_select 'errors error', :text => "Subject can't be blank" |
|
|
|
end |
|
|
|
issue = Issue.find(3) |
|
|
|
assert_equal '150', issue.custom_value_for(2).value |
|
|
|
assert_equal ['MySQL', 'PostgreSQL'], issue.custom_field_value(1).sort |
|
|
|
end |
|
|
|
|
|
|
|
context "PUT /issues/6.json" do |
|
|
|
setup do |
|
|
|
@parameters = {:issue => {:subject => 'API update', :notes => 'A new note'}} |
|
|
|
end |
|
|
|
|
|
|
|
should_allow_api_authentication(:put, |
|
|
|
'/issues/6.json', |
|
|
|
{:issue => {:subject => 'API update', :notes => 'A new note'}}, |
|
|
|
{:success_code => :ok}) |
|
|
|
test "PUT /issues/:id.xml with project change" do |
|
|
|
put '/issues/3.xml', |
|
|
|
{:issue => {:project_id => 2, :subject => 'Project changed'}}, |
|
|
|
credentials('jsmith') |
|
|
|
|
|
|
|
should "update the issue" do |
|
|
|
assert_no_difference('Issue.count') do |
|
|
|
assert_difference('Journal.count') do |
|
|
|
put '/issues/6.json', @parameters, credentials('jsmith') |
|
|
|
issue = Issue.find(3) |
|
|
|
assert_equal 2, issue.project_id |
|
|
|
assert_equal 'Project changed', issue.subject |
|
|
|
end |
|
|
|
|
|
|
|
assert_response :ok |
|
|
|
assert_equal '', response.body |
|
|
|
end |
|
|
|
end |
|
|
|
test "PUT /issues/:id.xml with failed update" do |
|
|
|
put '/issues/6.xml', {:issue => {:subject => ''}}, credentials('jsmith') |
|
|
|
|
|
|
|
issue = Issue.find(6) |
|
|
|
assert_equal "API update", issue.subject |
|
|
|
journal = Journal.last |
|
|
|
assert_equal "A new note", journal.notes |
|
|
|
end |
|
|
|
assert_response :unprocessable_entity |
|
|
|
assert_select 'errors error', :text => "Subject can't be blank" |
|
|
|
end |
|
|
|
|
|
|
|
context "PUT /issues/6.json with failed update" do |
|
|
|
should "return errors" do |
|
|
|
assert_no_difference('Issue.count') do |
|
|
|
assert_no_difference('Journal.count') do |
|
|
|
put '/issues/6.json', {:issue => {:subject => ''}}, credentials('jsmith') |
|
|
|
|
|
|
|
assert_response :unprocessable_entity |
|
|
|
end |
|
|
|
end |
|
|
|
test "PUT /issues/:id.json" do |
|
|
|
assert_difference('Journal.count') do |
|
|
|
put '/issues/6.json', |
|
|
|
{:issue => {:subject => 'API update', :notes => 'A new note'}}, |
|
|
|
credentials('jsmith') |
|
|
|
|
|
|
|
json = ActiveSupport::JSON.decode(response.body) |
|
|
|
assert json['errors'].include?("Subject can't be blank") |
|
|
|
assert_response :ok |
|
|
|
assert_equal '', response.body |
|
|
|
end |
|
|
|
|
|
|
|
issue = Issue.find(6) |
|
|
|
assert_equal "API update", issue.subject |
|
|
|
journal = Journal.last |
|
|
|
assert_equal "A new note", journal.notes |
|
|
|
end |
|
|
|
|
|
|
|
context "DELETE /issues/1.xml" do |
|
|
|
should_allow_api_authentication(:delete, |
|
|
|
'/issues/6.xml', |
|
|
|
{}, |
|
|
|
{:success_code => :ok}) |
|
|
|
test "PUT /issues/:id.json with failed update" do |
|
|
|
put '/issues/6.json', {:issue => {:subject => ''}}, credentials('jsmith') |
|
|
|
|
|
|
|
should "delete the issue" do |
|
|
|
assert_difference('Issue.count', -1) do |
|
|
|
delete '/issues/6.xml', {}, credentials('jsmith') |
|
|
|
assert_response :unprocessable_entity |
|
|
|
json = ActiveSupport::JSON.decode(response.body) |
|
|
|
assert json['errors'].include?("Subject can't be blank") |
|
|
|
end |
|
|
|
|
|
|
|
assert_response :ok |
|
|
|
assert_equal '', response.body |
|
|
|
end |
|
|
|
test "DELETE /issues/:id.xml" do |
|
|
|
assert_difference('Issue.count', -1) do |
|
|
|
delete '/issues/6.xml', {}, credentials('jsmith') |
|
|
|
|
|
|
|
assert_nil Issue.find_by_id(6) |
|
|
|
assert_response :ok |
|
|
|
assert_equal '', response.body |
|
|
|
end |
|
|
|
assert_nil Issue.find_by_id(6) |
|
|
|
end |
|
|
|
|
|
|
|
context "DELETE /issues/1.json" do |
|
|
|
should_allow_api_authentication(:delete, |
|
|
|
'/issues/6.json', |
|
|
|
{}, |
|
|
|
{:success_code => :ok}) |
|
|
|
|
|
|
|
should "delete the issue" do |
|
|
|
assert_difference('Issue.count', -1) do |
|
|
|
delete '/issues/6.json', {}, credentials('jsmith') |
|
|
|
test "DELETE /issues/:id.json" do |
|
|
|
assert_difference('Issue.count', -1) do |
|
|
|
delete '/issues/6.json', {}, credentials('jsmith') |
|
|
|
|
|
|
|
assert_response :ok |
|
|
|
assert_equal '', response.body |
|
|
|
end |
|
|
|
|
|
|
|
assert_nil Issue.find_by_id(6) |
|
|
|
assert_response :ok |
|
|
|
assert_equal '', response.body |
|
|
|
end |
|
|
|
assert_nil Issue.find_by_id(6) |
|
|
|
end |
|
|
|
|
|
|
|
test "POST /issues/:id/watchers.xml should add watcher" do |