##// END OF EJS Templates
Test cleanup....
Jean-Philippe Lang -
r8357:131f258f5fba
parent child
Show More
@@ -1,86 +1,85
1 1 # Redmine - project management software
2 2 # Copyright (C) 2006-2011 Jean-Philippe Lang
3 3 #
4 4 # This program is free software; you can redistribute it and/or
5 5 # modify it under the terms of the GNU General Public License
6 6 # as published by the Free Software Foundation; either version 2
7 7 # of the License, or (at your option) any later version.
8 8 #
9 9 # This program is distributed in the hope that it will be useful,
10 10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 12 # GNU General Public License for more details.
13 13 #
14 14 # You should have received a copy of the GNU General Public License
15 15 # along with this program; if not, write to the Free Software
16 16 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17 17
18 18 require File.expand_path('../../../test_helper', __FILE__)
19 19
20 20 class ApiTest::AttachmentsTest < ActionController::IntegrationTest
21 21 fixtures :projects, :trackers, :issue_statuses, :issues,
22 22 :enumerations, :users, :issue_categories,
23 23 :projects_trackers,
24 24 :roles,
25 25 :member_roles,
26 26 :members,
27 27 :enabled_modules,
28 28 :workflows,
29 29 :attachments
30 30
31 31 def setup
32 32 Setting.rest_api_enabled = '1'
33 33 set_fixtures_attachments_directory
34 34 end
35 35
36 36 def teardown
37 37 set_tmp_attachments_directory
38 38 end
39 39
40 40 context "/attachments/:id" do
41 41 context "GET" do
42 42 should "return the attachment" do
43 get '/attachments/7.xml', {}, :authorization => credentials('jsmith')
43 get '/attachments/7.xml', {}, credentials('jsmith')
44 44 assert_response :success
45 45 assert_equal 'application/xml', @response.content_type
46 46 assert_tag :tag => 'attachment',
47 47 :child => {
48 48 :tag => 'id',
49 49 :content => '7',
50 50 :sibling => {
51 51 :tag => 'filename',
52 52 :content => 'archive.zip',
53 53 :sibling => {
54 54 :tag => 'content_url',
55 55 :content => 'http://www.example.com/attachments/download/7/archive.zip'
56 56 }
57 57 }
58 58 }
59 59 end
60 60
61 61 should "deny access without credentials" do
62 62 get '/attachments/7.xml'
63 63 assert_response 401
64 64 set_tmp_attachments_directory
65 65 end
66 66 end
67 67 end
68 68
69 69 context "/attachments/download/:id/:filename" do
70 70 context "GET" do
71 71 should "return the attachment content" do
72 get '/attachments/download/7/archive.zip',
73 {}, :authorization => credentials('jsmith')
72 get '/attachments/download/7/archive.zip', {}, credentials('jsmith')
74 73 assert_response :success
75 74 assert_equal 'application/octet-stream', @response.content_type
76 75 set_tmp_attachments_directory
77 76 end
78 77
79 78 should "deny access without credentials" do
80 79 get '/attachments/download/7/archive.zip'
81 80 assert_response 302
82 81 set_tmp_attachments_directory
83 82 end
84 83 end
85 84 end
86 85 end
@@ -1,113 +1,113
1 1 require File.expand_path('../../../test_helper', __FILE__)
2 2
3 3 class ApiTest::DisabledRestApiTest < ActionController::IntegrationTest
4 4 fixtures :projects, :trackers, :issue_statuses, :issues,
5 5 :enumerations, :users, :issue_categories,
6 6 :projects_trackers,
7 7 :roles,
8 8 :member_roles,
9 9 :members,
10 10 :enabled_modules,
11 11 :workflows
12 12
13 13 def setup
14 14 Setting.rest_api_enabled = '0'
15 15 Setting.login_required = '1'
16 16 end
17 17
18 18 def teardown
19 19 Setting.rest_api_enabled = '1'
20 20 Setting.login_required = '0'
21 21 end
22 22
23 23 # Using the NewsController because it's a simple API.
24 24 context "get /news with the API disabled" do
25 25
26 26 context "in :xml format" do
27 27 context "with a valid api token" do
28 28 setup do
29 29 @user = User.generate_with_protected!
30 30 @token = Token.generate!(:user => @user, :action => 'api')
31 31 get "/news.xml?key=#{@token.value}"
32 32 end
33 33
34 34 should_respond_with :unauthorized
35 35 should_respond_with_content_type :xml
36 36 should "not login as the user" do
37 37 assert_equal User.anonymous, User.current
38 38 end
39 39 end
40 40
41 41 context "with a valid HTTP authentication" do
42 42 setup do
43 43 @user = User.generate_with_protected!(:password => 'my_password', :password_confirmation => 'my_password')
44 get "/news.xml", nil, :authorization => credentials(@user.login, 'my_password')
44 get "/news.xml", nil, credentials(@user.login, 'my_password')
45 45 end
46 46
47 47 should_respond_with :unauthorized
48 48 should_respond_with_content_type :xml
49 49 should "not login as the user" do
50 50 assert_equal User.anonymous, User.current
51 51 end
52 52 end
53 53
54 54 context "with a valid HTTP authentication using the API token" do
55 55 setup do
56 56 @user = User.generate_with_protected!
57 57 @token = Token.generate!(:user => @user, :action => 'api')
58 get "/news.xml", nil, :authorization => credentials(@token.value, 'X')
58 get "/news.xml", nil, credentials(@token.value, 'X')
59 59 end
60 60
61 61 should_respond_with :unauthorized
62 62 should_respond_with_content_type :xml
63 63 should "not login as the user" do
64 64 assert_equal User.anonymous, User.current
65 65 end
66 66 end
67 67 end
68 68
69 69 context "in :json format" do
70 70 context "with a valid api token" do
71 71 setup do
72 72 @user = User.generate_with_protected!
73 73 @token = Token.generate!(:user => @user, :action => 'api')
74 74 get "/news.json?key=#{@token.value}"
75 75 end
76 76
77 77 should_respond_with :unauthorized
78 78 should_respond_with_content_type :json
79 79 should "not login as the user" do
80 80 assert_equal User.anonymous, User.current
81 81 end
82 82 end
83 83
84 84 context "with a valid HTTP authentication" do
85 85 setup do
86 86 @user = User.generate_with_protected!(:password => 'my_password', :password_confirmation => 'my_password')
87 get "/news.json", nil, :authorization => credentials(@user.login, 'my_password')
87 get "/news.json", nil, credentials(@user.login, 'my_password')
88 88 end
89 89
90 90 should_respond_with :unauthorized
91 91 should_respond_with_content_type :json
92 92 should "not login as the user" do
93 93 assert_equal User.anonymous, User.current
94 94 end
95 95 end
96 96
97 97 context "with a valid HTTP authentication using the API token" do
98 98 setup do
99 99 @user = User.generate_with_protected!
100 100 @token = Token.generate!(:user => @user, :action => 'api')
101 get "/news.json", nil, :authorization => credentials(@token.value, 'DoesNotMatter')
101 get "/news.json", nil, credentials(@token.value, 'DoesNotMatter')
102 102 end
103 103
104 104 should_respond_with :unauthorized
105 105 should_respond_with_content_type :json
106 106 should "not login as the user" do
107 107 assert_equal User.anonymous, User.current
108 108 end
109 109 end
110 110
111 111 end
112 112 end
113 113 end
@@ -1,123 +1,123
1 1 # Redmine - project management software
2 2 # Copyright (C) 2006-2011 Jean-Philippe Lang
3 3 #
4 4 # This program is free software; you can redistribute it and/or
5 5 # modify it under the terms of the GNU General Public License
6 6 # as published by the Free Software Foundation; either version 2
7 7 # of the License, or (at your option) any later version.
8 8 #
9 9 # This program is distributed in the hope that it will be useful,
10 10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 12 # GNU General Public License for more details.
13 13 #
14 14 # You should have received a copy of the GNU General Public License
15 15 # along with this program; if not, write to the Free Software
16 16 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17 17
18 18 require File.expand_path('../../../test_helper', __FILE__)
19 19
20 20 class ApiTest::IssueCategoriesTest < ActionController::IntegrationTest
21 21 fixtures :projects, :users, :issue_categories, :issues,
22 22 :roles,
23 23 :member_roles,
24 24 :members,
25 25 :enabled_modules
26 26
27 27 def setup
28 28 Setting.rest_api_enabled = '1'
29 29 end
30 30
31 31 context "GET /projects/:project_id/issue_categories.xml" do
32 32 should "return issue categories" do
33 get '/projects/1/issue_categories.xml', {}, :authorization => credentials('jsmith')
33 get '/projects/1/issue_categories.xml', {}, credentials('jsmith')
34 34 assert_response :success
35 35 assert_equal 'application/xml', @response.content_type
36 36 assert_tag :tag => 'issue_categories',
37 37 :child => {:tag => 'issue_category', :child => {:tag => 'id', :content => '2'}}
38 38 end
39 39 end
40 40
41 41 context "GET /issue_categories/2.xml" do
42 42 should "return requested issue category" do
43 get '/issue_categories/2.xml', {}, :authorization => credentials('jsmith')
43 get '/issue_categories/2.xml', {}, credentials('jsmith')
44 44 assert_response :success
45 45 assert_equal 'application/xml', @response.content_type
46 46 assert_tag :tag => 'issue_category',
47 47 :child => {:tag => 'id', :content => '2'}
48 48 end
49 49 end
50 50
51 51 context "POST /projects/:project_id/issue_categories.xml" do
52 52 should "return create issue category" do
53 53 assert_difference 'IssueCategory.count' do
54 post '/projects/1/issue_categories.xml', {:issue_category => {:name => 'API'}}, :authorization => credentials('jsmith')
54 post '/projects/1/issue_categories.xml', {:issue_category => {:name => 'API'}}, credentials('jsmith')
55 55 end
56 56 assert_response :created
57 57 assert_equal 'application/xml', @response.content_type
58 58
59 59 category = IssueCategory.first(:order => 'id DESC')
60 60 assert_equal 'API', category.name
61 61 assert_equal 1, category.project_id
62 62 end
63 63
64 64 context "with invalid parameters" do
65 65 should "return errors" do
66 66 assert_no_difference 'IssueCategory.count' do
67 post '/projects/1/issue_categories.xml', {:issue_category => {:name => ''}}, :authorization => credentials('jsmith')
67 post '/projects/1/issue_categories.xml', {:issue_category => {:name => ''}}, credentials('jsmith')
68 68 end
69 69 assert_response :unprocessable_entity
70 70 assert_equal 'application/xml', @response.content_type
71 71
72 72 assert_tag 'errors', :child => {:tag => 'error', :content => "Name can't be blank"}
73 73 end
74 74 end
75 75 end
76 76
77 77 context "PUT /issue_categories/2.xml" do
78 78 context "with valid parameters" do
79 79 should "update issue category" do
80 80 assert_no_difference 'IssueCategory.count' do
81 put '/issue_categories/2.xml', {:issue_category => {:name => 'API Update'}}, :authorization => credentials('jsmith')
81 put '/issue_categories/2.xml', {:issue_category => {:name => 'API Update'}}, credentials('jsmith')
82 82 end
83 83 assert_response :ok
84 84 assert_equal 'API Update', IssueCategory.find(2).name
85 85 end
86 86 end
87 87
88 88 context "with invalid parameters" do
89 89 should "return errors" do
90 90 assert_no_difference 'IssueCategory.count' do
91 put '/issue_categories/2.xml', {:issue_category => {:name => ''}}, :authorization => credentials('jsmith')
91 put '/issue_categories/2.xml', {:issue_category => {:name => ''}}, credentials('jsmith')
92 92 end
93 93 assert_response :unprocessable_entity
94 94 assert_equal 'application/xml', @response.content_type
95 95
96 96 assert_tag 'errors', :child => {:tag => 'error', :content => "Name can't be blank"}
97 97 end
98 98 end
99 99 end
100 100
101 101 context "DELETE /issue_categories/1.xml" do
102 102 should "destroy issue categories" do
103 103 assert_difference 'IssueCategory.count', -1 do
104 delete '/issue_categories/1.xml', {}, :authorization => credentials('jsmith')
104 delete '/issue_categories/1.xml', {}, credentials('jsmith')
105 105 end
106 106 assert_response :ok
107 107 assert_nil IssueCategory.find_by_id(1)
108 108 end
109 109
110 110 should "reassign issues with :reassign_to_id param" do
111 111 issue_count = Issue.count(:conditions => {:category_id => 1})
112 112 assert issue_count > 0
113 113
114 114 assert_difference 'IssueCategory.count', -1 do
115 115 assert_difference 'Issue.count(:conditions => {:category_id => 2})', 3 do
116 delete '/issue_categories/1.xml', {:reassign_to_id => 2}, :authorization => credentials('jsmith')
116 delete '/issue_categories/1.xml', {:reassign_to_id => 2}, credentials('jsmith')
117 117 end
118 118 end
119 119 assert_response :ok
120 120 assert_nil IssueCategory.find_by_id(1)
121 121 end
122 122 end
123 123 end
@@ -1,106 +1,106
1 1 # Redmine - project management software
2 2 # Copyright (C) 2006-2011 Jean-Philippe Lang
3 3 #
4 4 # This program is free software; you can redistribute it and/or
5 5 # modify it under the terms of the GNU General Public License
6 6 # as published by the Free Software Foundation; either version 2
7 7 # of the License, or (at your option) any later version.
8 8 #
9 9 # This program is distributed in the hope that it will be useful,
10 10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 12 # GNU General Public License for more details.
13 13 #
14 14 # You should have received a copy of the GNU General Public License
15 15 # along with this program; if not, write to the Free Software
16 16 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17 17
18 18 require File.expand_path('../../../test_helper', __FILE__)
19 19
20 20 class ApiTest::IssueRelationsTest < ActionController::IntegrationTest
21 21 fixtures :projects, :trackers, :issue_statuses, :issues,
22 22 :enumerations, :users, :issue_categories,
23 23 :projects_trackers,
24 24 :roles,
25 25 :member_roles,
26 26 :members,
27 27 :enabled_modules,
28 28 :workflows,
29 29 :issue_relations
30 30
31 31 def setup
32 32 Setting.rest_api_enabled = '1'
33 33 end
34 34
35 35 context "/issues/:issue_id/relations" do
36 36 context "GET" do
37 37 should "return issue relations" do
38 get '/issues/9/relations.xml', {}, :authorization => credentials('jsmith')
38 get '/issues/9/relations.xml', {}, credentials('jsmith')
39 39
40 40 assert_response :success
41 41 assert_equal 'application/xml', @response.content_type
42 42
43 43 assert_tag :tag => 'relations',
44 44 :attributes => { :type => 'array' },
45 45 :child => {
46 46 :tag => 'relation',
47 47 :child => {
48 48 :tag => 'id',
49 49 :content => '1'
50 50 }
51 51 }
52 52 end
53 53 end
54 54
55 55 context "POST" do
56 56 should "create a relation" do
57 57 assert_difference('IssueRelation.count') do
58 post '/issues/2/relations.xml', {:relation => {:issue_to_id => 7, :relation_type => 'relates'}}, :authorization => credentials('jsmith')
58 post '/issues/2/relations.xml', {:relation => {:issue_to_id => 7, :relation_type => 'relates'}}, credentials('jsmith')
59 59 end
60 60
61 61 relation = IssueRelation.first(:order => 'id DESC')
62 62 assert_equal 2, relation.issue_from_id
63 63 assert_equal 7, relation.issue_to_id
64 64 assert_equal 'relates', relation.relation_type
65 65
66 66 assert_response :created
67 67 assert_equal 'application/xml', @response.content_type
68 68 assert_tag 'relation', :child => {:tag => 'id', :content => relation.id.to_s}
69 69 end
70 70
71 71 context "with failure" do
72 72 should "return the errors" do
73 73 assert_no_difference('IssueRelation.count') do
74 post '/issues/2/relations.xml', {:relation => {:issue_to_id => 7, :relation_type => 'foo'}}, :authorization => credentials('jsmith')
74 post '/issues/2/relations.xml', {:relation => {:issue_to_id => 7, :relation_type => 'foo'}}, credentials('jsmith')
75 75 end
76 76
77 77 assert_response :unprocessable_entity
78 78 assert_tag :errors, :child => {:tag => 'error', :content => 'relation_type is not included in the list'}
79 79 end
80 80 end
81 81 end
82 82 end
83 83
84 84 context "/relations/:id" do
85 85 context "GET" do
86 86 should "return the relation" do
87 get '/relations/2.xml', {}, :authorization => credentials('jsmith')
87 get '/relations/2.xml', {}, credentials('jsmith')
88 88
89 89 assert_response :success
90 90 assert_equal 'application/xml', @response.content_type
91 91 assert_tag 'relation', :child => {:tag => 'id', :content => '2'}
92 92 end
93 93 end
94 94
95 95 context "DELETE" do
96 96 should "delete the relation" do
97 97 assert_difference('IssueRelation.count', -1) do
98 delete '/relations/2.xml', {}, :authorization => credentials('jsmith')
98 delete '/relations/2.xml', {}, credentials('jsmith')
99 99 end
100 100
101 101 assert_response :ok
102 102 assert_nil IssueRelation.find_by_id(2)
103 103 end
104 104 end
105 105 end
106 106 end
@@ -1,579 +1,574
1 1 # Redmine - project management software
2 2 # Copyright (C) 2006-2011 Jean-Philippe Lang
3 3 #
4 4 # This program is free software; you can redistribute it and/or
5 5 # modify it under the terms of the GNU General Public License
6 6 # as published by the Free Software Foundation; either version 2
7 7 # of the License, or (at your option) any later version.
8 8 #
9 9 # This program is distributed in the hope that it will be useful,
10 10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 12 # GNU General Public License for more details.
13 13 #
14 14 # You should have received a copy of the GNU General Public License
15 15 # along with this program; if not, write to the Free Software
16 16 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17 17
18 18 require File.expand_path('../../../test_helper', __FILE__)
19 19
20 20 class ApiTest::IssuesTest < ActionController::IntegrationTest
21 21 fixtures :projects,
22 22 :users,
23 23 :roles,
24 24 :members,
25 25 :member_roles,
26 26 :issues,
27 27 :issue_statuses,
28 28 :versions,
29 29 :trackers,
30 30 :projects_trackers,
31 31 :issue_categories,
32 32 :enabled_modules,
33 33 :enumerations,
34 34 :attachments,
35 35 :workflows,
36 36 :custom_fields,
37 37 :custom_values,
38 38 :custom_fields_projects,
39 39 :custom_fields_trackers,
40 40 :time_entries,
41 41 :journals,
42 42 :journal_details,
43 43 :queries,
44 44 :attachments
45 45
46 46 def setup
47 47 Setting.rest_api_enabled = '1'
48 48 end
49 49
50 50 context "/issues" do
51 51 # Use a private project to make sure auth is really working and not just
52 52 # only showing public issues.
53 53 should_allow_api_authentication(:get, "/projects/private-child/issues.xml")
54 54
55 55 should "contain metadata" do
56 56 get '/issues.xml'
57 57
58 58 assert_tag :tag => 'issues',
59 59 :attributes => {
60 60 :type => 'array',
61 61 :total_count => assigns(:issue_count),
62 62 :limit => 25,
63 63 :offset => 0
64 64 }
65 65 end
66 66
67 67 context "with offset and limit" do
68 68 should "use the params" do
69 69 get '/issues.xml?offset=2&limit=3'
70 70
71 71 assert_equal 3, assigns(:limit)
72 72 assert_equal 2, assigns(:offset)
73 73 assert_tag :tag => 'issues', :children => {:count => 3, :only => {:tag => 'issue'}}
74 74 end
75 75 end
76 76
77 77 context "with nometa param" do
78 78 should "not contain metadata" do
79 79 get '/issues.xml?nometa=1'
80 80
81 81 assert_tag :tag => 'issues',
82 82 :attributes => {
83 83 :type => 'array',
84 84 :total_count => nil,
85 85 :limit => nil,
86 86 :offset => nil
87 87 }
88 88 end
89 89 end
90 90
91 91 context "with nometa header" do
92 92 should "not contain metadata" do
93 93 get '/issues.xml', {}, {'X-Redmine-Nometa' => '1'}
94 94
95 95 assert_tag :tag => 'issues',
96 96 :attributes => {
97 97 :type => 'array',
98 98 :total_count => nil,
99 99 :limit => nil,
100 100 :offset => nil
101 101 }
102 102 end
103 103 end
104 104
105 105 context "with relations" do
106 106 should "display relations" do
107 107 get '/issues.xml?include=relations'
108 108
109 109 assert_response :success
110 110 assert_equal 'application/xml', @response.content_type
111 111 assert_tag 'relations',
112 112 :parent => {:tag => 'issue', :child => {:tag => 'id', :content => '3'}},
113 113 :children => {:count => 1},
114 114 :child => {
115 115 :tag => 'relation',
116 116 :attributes => {:id => '2', :issue_id => '2', :issue_to_id => '3', :relation_type => 'relates'}
117 117 }
118 118 assert_tag 'relations',
119 119 :parent => {:tag => 'issue', :child => {:tag => 'id', :content => '1'}},
120 120 :children => {:count => 0}
121 121 end
122 122 end
123 123
124 124 context "with invalid query params" do
125 125 should "return errors" do
126 126 get '/issues.xml', {:f => ['start_date'], :op => {:start_date => '='}}
127 127
128 128 assert_response :unprocessable_entity
129 129 assert_equal 'application/xml', @response.content_type
130 130 assert_tag 'errors', :child => {:tag => 'error', :content => "Start date can't be blank"}
131 131 end
132 132 end
133 133
134 134 context "with custom field filter" do
135 135 should "show only issues with the custom field value" do
136 136 get '/issues.xml', { :set_filter => 1, :f => ['cf_1'], :op => {:cf_1 => '='}, :v => {:cf_1 => ['MySQL']}}
137 137
138 138 expected_ids = Issue.visible.all(
139 139 :include => :custom_values,
140 140 :conditions => {:custom_values => {:custom_field_id => 1, :value => 'MySQL'}}).map(&:id)
141 141
142 142 assert_select 'issues > issue > id', :count => expected_ids.count do |ids|
143 143 ids.each { |id| assert expected_ids.delete(id.children.first.content.to_i) }
144 144 end
145 145 end
146 146 end
147 147
148 148 context "with custom field filter (shorthand method)" do
149 149 should "show only issues with the custom field value" do
150 150 get '/issues.xml', { :cf_1 => 'MySQL' }
151 151
152 152 expected_ids = Issue.visible.all(
153 153 :include => :custom_values,
154 154 :conditions => {:custom_values => {:custom_field_id => 1, :value => 'MySQL'}}).map(&:id)
155 155
156 156 assert_select 'issues > issue > id', :count => expected_ids.count do |ids|
157 157 ids.each { |id| assert expected_ids.delete(id.children.first.content.to_i) }
158 158 end
159 159 end
160 160 end
161 161 end
162 162
163 163 context "/index.json" do
164 164 should_allow_api_authentication(:get, "/projects/private-child/issues.json")
165 165 end
166 166
167 167 context "/index.xml with filter" do
168 168 should "show only issues with the status_id" do
169 169 get '/issues.xml?status_id=5'
170 170
171 171 expected_ids = Issue.visible.all(:conditions => {:status_id => 5}).map(&:id)
172 172
173 173 assert_select 'issues > issue > id', :count => expected_ids.count do |ids|
174 174 ids.each { |id| assert expected_ids.delete(id.children.first.content.to_i) }
175 175 end
176 176 end
177 177 end
178 178
179 179 context "/index.json with filter" do
180 180 should "show only issues with the status_id" do
181 181 get '/issues.json?status_id=5'
182 182
183 183 json = ActiveSupport::JSON.decode(response.body)
184 184 status_ids_used = json['issues'].collect {|j| j['status']['id'] }
185 185 assert_equal 3, status_ids_used.length
186 186 assert status_ids_used.all? {|id| id == 5 }
187 187 end
188 188
189 189 end
190 190
191 191 # Issue 6 is on a private project
192 192 context "/issues/6.xml" do
193 193 should_allow_api_authentication(:get, "/issues/6.xml")
194 194 end
195 195
196 196 context "/issues/6.json" do
197 197 should_allow_api_authentication(:get, "/issues/6.json")
198 198 end
199 199
200 200 context "GET /issues/:id" do
201 201 context "with journals" do
202 202 context ".xml" do
203 203 should "display journals" do
204 204 get '/issues/1.xml?include=journals'
205 205
206 206 assert_tag :tag => 'issue',
207 207 :child => {
208 208 :tag => 'journals',
209 209 :attributes => { :type => 'array' },
210 210 :child => {
211 211 :tag => 'journal',
212 212 :attributes => { :id => '1'},
213 213 :child => {
214 214 :tag => 'details',
215 215 :attributes => { :type => 'array' },
216 216 :child => {
217 217 :tag => 'detail',
218 218 :attributes => { :name => 'status_id' },
219 219 :child => {
220 220 :tag => 'old_value',
221 221 :content => '1',
222 222 :sibling => {
223 223 :tag => 'new_value',
224 224 :content => '2'
225 225 }
226 226 }
227 227 }
228 228 }
229 229 }
230 230 }
231 231 end
232 232 end
233 233 end
234 234
235 235 context "with custom fields" do
236 236 context ".xml" do
237 237 should "display custom fields" do
238 238 get '/issues/3.xml'
239 239
240 240 assert_tag :tag => 'issue',
241 241 :child => {
242 242 :tag => 'custom_fields',
243 243 :attributes => { :type => 'array' },
244 244 :child => {
245 245 :tag => 'custom_field',
246 246 :attributes => { :id => '1'},
247 247 :child => {
248 248 :tag => 'value',
249 249 :content => 'MySQL'
250 250 }
251 251 }
252 252 }
253 253
254 254 assert_nothing_raised do
255 255 Hash.from_xml(response.body).to_xml
256 256 end
257 257 end
258 258 end
259 259 end
260 260
261 261 context "with attachments" do
262 262 context ".xml" do
263 263 should "display attachments" do
264 264 get '/issues/3.xml?include=attachments'
265 265
266 266 assert_tag :tag => 'issue',
267 267 :child => {
268 268 :tag => 'attachments',
269 269 :children => {:count => 5},
270 270 :child => {
271 271 :tag => 'attachment',
272 272 :child => {
273 273 :tag => 'filename',
274 274 :content => 'source.rb',
275 275 :sibling => {
276 276 :tag => 'content_url',
277 277 :content => 'http://www.example.com/attachments/download/4/source.rb'
278 278 }
279 279 }
280 280 }
281 281 }
282 282 end
283 283 end
284 284 end
285 285
286 286 context "with subtasks" do
287 287 setup do
288 288 @c1 = Issue.generate!(:status_id => 1, :subject => "child c1", :tracker_id => 1, :project_id => 1, :parent_issue_id => 1)
289 289 @c2 = Issue.generate!(:status_id => 1, :subject => "child c2", :tracker_id => 1, :project_id => 1, :parent_issue_id => 1)
290 290 @c3 = Issue.generate!(:status_id => 1, :subject => "child c3", :tracker_id => 1, :project_id => 1, :parent_issue_id => @c1.id)
291 291 end
292 292
293 293 context ".xml" do
294 294 should "display children" do
295 295 get '/issues/1.xml?include=children'
296 296
297 297 assert_tag :tag => 'issue',
298 298 :child => {
299 299 :tag => 'children',
300 300 :children => {:count => 2},
301 301 :child => {
302 302 :tag => 'issue',
303 303 :attributes => {:id => @c1.id.to_s},
304 304 :child => {
305 305 :tag => 'subject',
306 306 :content => 'child c1',
307 307 :sibling => {
308 308 :tag => 'children',
309 309 :children => {:count => 1},
310 310 :child => {
311 311 :tag => 'issue',
312 312 :attributes => {:id => @c3.id.to_s}
313 313 }
314 314 }
315 315 }
316 316 }
317 317 }
318 318 end
319 319
320 320 context ".json" do
321 321 should "display children" do
322 322 get '/issues/1.json?include=children'
323 323
324 324 json = ActiveSupport::JSON.decode(response.body)
325 325 assert_equal([
326 326 {
327 327 'id' => @c1.id, 'subject' => 'child c1', 'tracker' => {'id' => 1, 'name' => 'Bug'},
328 328 'children' => [{ 'id' => @c3.id, 'subject' => 'child c3', 'tracker' => {'id' => 1, 'name' => 'Bug'} }]
329 329 },
330 330 { 'id' => @c2.id, 'subject' => 'child c2', 'tracker' => {'id' => 1, 'name' => 'Bug'} }
331 331 ],
332 332 json['issue']['children'])
333 333 end
334 334 end
335 335 end
336 336 end
337 337 end
338 338
339 339 context "POST /issues.xml" do
340 340 should_allow_api_authentication(:post,
341 341 '/issues.xml',
342 342 {:issue => {:project_id => 1, :subject => 'API test', :tracker_id => 2, :status_id => 3}},
343 343 {:success_code => :created})
344 344
345 345 should "create an issue with the attributes" do
346 346 assert_difference('Issue.count') do
347 post '/issues.xml', {:issue => {:project_id => 1, :subject => 'API test', :tracker_id => 2, :status_id => 3}}, :authorization => credentials('jsmith')
347 post '/issues.xml', {:issue => {:project_id => 1, :subject => 'API test', :tracker_id => 2, :status_id => 3}}, credentials('jsmith')
348 348 end
349 349
350 350 issue = Issue.first(:order => 'id DESC')
351 351 assert_equal 1, issue.project_id
352 352 assert_equal 2, issue.tracker_id
353 353 assert_equal 3, issue.status_id
354 354 assert_equal 'API test', issue.subject
355 355
356 356 assert_response :created
357 357 assert_equal 'application/xml', @response.content_type
358 358 assert_tag 'issue', :child => {:tag => 'id', :content => issue.id.to_s}
359 359 end
360 360 end
361 361
362 362 context "POST /issues.xml with failure" do
363 363 should "have an errors tag" do
364 364 assert_no_difference('Issue.count') do
365 post '/issues.xml', {:issue => {:project_id => 1}}, :authorization => credentials('jsmith')
365 post '/issues.xml', {:issue => {:project_id => 1}}, credentials('jsmith')
366 366 end
367 367
368 368 assert_tag :errors, :child => {:tag => 'error', :content => "Subject can't be blank"}
369 369 end
370 370 end
371 371
372 372 context "POST /issues.json" do
373 373 should_allow_api_authentication(:post,
374 374 '/issues.json',
375 375 {:issue => {:project_id => 1, :subject => 'API test', :tracker_id => 2, :status_id => 3}},
376 376 {:success_code => :created})
377 377
378 378 should "create an issue with the attributes" do
379 379 assert_difference('Issue.count') do
380 post '/issues.json', {:issue => {:project_id => 1, :subject => 'API test', :tracker_id => 2, :status_id => 3}}, :authorization => credentials('jsmith')
380 post '/issues.json', {:issue => {:project_id => 1, :subject => 'API test', :tracker_id => 2, :status_id => 3}}, credentials('jsmith')
381 381 end
382 382
383 383 issue = Issue.first(:order => 'id DESC')
384 384 assert_equal 1, issue.project_id
385 385 assert_equal 2, issue.tracker_id
386 386 assert_equal 3, issue.status_id
387 387 assert_equal 'API test', issue.subject
388 388 end
389 389
390 390 end
391 391
392 392 context "POST /issues.json with failure" do
393 393 should "have an errors element" do
394 394 assert_no_difference('Issue.count') do
395 post '/issues.json', {:issue => {:project_id => 1}}, :authorization => credentials('jsmith')
395 post '/issues.json', {:issue => {:project_id => 1}}, credentials('jsmith')
396 396 end
397 397
398 398 json = ActiveSupport::JSON.decode(response.body)
399 399 assert json['errors'].include?(['subject', "can't be blank"])
400 400 end
401 401 end
402 402
403 403 # Issue 6 is on a private project
404 404 context "PUT /issues/6.xml" do
405 405 setup do
406 406 @parameters = {:issue => {:subject => 'API update', :notes => 'A new note'}}
407 @headers = { :authorization => credentials('jsmith') }
408 407 end
409 408
410 409 should_allow_api_authentication(:put,
411 410 '/issues/6.xml',
412 411 {:issue => {:subject => 'API update', :notes => 'A new note'}},
413 412 {:success_code => :ok})
414 413
415 414 should "not create a new issue" do
416 415 assert_no_difference('Issue.count') do
417 put '/issues/6.xml', @parameters, @headers
416 put '/issues/6.xml', @parameters, credentials('jsmith')
418 417 end
419 418 end
420 419
421 420 should "create a new journal" do
422 421 assert_difference('Journal.count') do
423 put '/issues/6.xml', @parameters, @headers
422 put '/issues/6.xml', @parameters, credentials('jsmith')
424 423 end
425 424 end
426 425
427 426 should "add the note to the journal" do
428 put '/issues/6.xml', @parameters, @headers
427 put '/issues/6.xml', @parameters, credentials('jsmith')
429 428
430 429 journal = Journal.last
431 430 assert_equal "A new note", journal.notes
432 431 end
433 432
434 433 should "update the issue" do
435 put '/issues/6.xml', @parameters, @headers
434 put '/issues/6.xml', @parameters, credentials('jsmith')
436 435
437 436 issue = Issue.find(6)
438 437 assert_equal "API update", issue.subject
439 438 end
440 439
441 440 end
442 441
443 442 context "PUT /issues/3.xml with custom fields" do
444 443 setup do
445 444 @parameters = {:issue => {:custom_fields => [{'id' => '1', 'value' => 'PostgreSQL' }, {'id' => '2', 'value' => '150'}]}}
446 @headers = { :authorization => credentials('jsmith') }
447 445 end
448 446
449 447 should "update custom fields" do
450 448 assert_no_difference('Issue.count') do
451 put '/issues/3.xml', @parameters, @headers
449 put '/issues/3.xml', @parameters, credentials('jsmith')
452 450 end
453 451
454 452 issue = Issue.find(3)
455 453 assert_equal '150', issue.custom_value_for(2).value
456 454 assert_equal 'PostgreSQL', issue.custom_value_for(1).value
457 455 end
458 456 end
459 457
460 458 context "PUT /issues/6.xml with failed update" do
461 459 setup do
462 460 @parameters = {:issue => {:subject => ''}}
463 @headers = { :authorization => credentials('jsmith') }
464 461 end
465 462
466 463 should "not create a new issue" do
467 464 assert_no_difference('Issue.count') do
468 put '/issues/6.xml', @parameters, @headers
465 put '/issues/6.xml', @parameters, credentials('jsmith')
469 466 end
470 467 end
471 468
472 469 should "not create a new journal" do
473 470 assert_no_difference('Journal.count') do
474 put '/issues/6.xml', @parameters, @headers
471 put '/issues/6.xml', @parameters, credentials('jsmith')
475 472 end
476 473 end
477 474
478 475 should "have an errors tag" do
479 put '/issues/6.xml', @parameters, @headers
476 put '/issues/6.xml', @parameters, credentials('jsmith')
480 477
481 478 assert_tag :errors, :child => {:tag => 'error', :content => "Subject can't be blank"}
482 479 end
483 480 end
484 481
485 482 context "PUT /issues/6.json" do
486 483 setup do
487 484 @parameters = {:issue => {:subject => 'API update', :notes => 'A new note'}}
488 @headers = { :authorization => credentials('jsmith') }
489 485 end
490 486
491 487 should_allow_api_authentication(:put,
492 488 '/issues/6.json',
493 489 {:issue => {:subject => 'API update', :notes => 'A new note'}},
494 490 {:success_code => :ok})
495 491
496 492 should "not create a new issue" do
497 493 assert_no_difference('Issue.count') do
498 put '/issues/6.json', @parameters, @headers
494 put '/issues/6.json', @parameters, credentials('jsmith')
499 495 end
500 496 end
501 497
502 498 should "create a new journal" do
503 499 assert_difference('Journal.count') do
504 put '/issues/6.json', @parameters, @headers
500 put '/issues/6.json', @parameters, credentials('jsmith')
505 501 end
506 502 end
507 503
508 504 should "add the note to the journal" do
509 put '/issues/6.json', @parameters, @headers
505 put '/issues/6.json', @parameters, credentials('jsmith')
510 506
511 507 journal = Journal.last
512 508 assert_equal "A new note", journal.notes
513 509 end
514 510
515 511 should "update the issue" do
516 put '/issues/6.json', @parameters, @headers
512 put '/issues/6.json', @parameters, credentials('jsmith')
517 513
518 514 issue = Issue.find(6)
519 515 assert_equal "API update", issue.subject
520 516 end
521 517
522 518 end
523 519
524 520 context "PUT /issues/6.json with failed update" do
525 521 setup do
526 522 @parameters = {:issue => {:subject => ''}}
527 @headers = { :authorization => credentials('jsmith') }
528 523 end
529 524
530 525 should "not create a new issue" do
531 526 assert_no_difference('Issue.count') do
532 put '/issues/6.json', @parameters, @headers
527 put '/issues/6.json', @parameters, credentials('jsmith')
533 528 end
534 529 end
535 530
536 531 should "not create a new journal" do
537 532 assert_no_difference('Journal.count') do
538 put '/issues/6.json', @parameters, @headers
533 put '/issues/6.json', @parameters, credentials('jsmith')
539 534 end
540 535 end
541 536
542 537 should "have an errors attribute" do
543 put '/issues/6.json', @parameters, @headers
538 put '/issues/6.json', @parameters, credentials('jsmith')
544 539
545 540 json = ActiveSupport::JSON.decode(response.body)
546 541 assert json['errors'].include?(['subject', "can't be blank"])
547 542 end
548 543 end
549 544
550 545 context "DELETE /issues/1.xml" do
551 546 should_allow_api_authentication(:delete,
552 547 '/issues/6.xml',
553 548 {},
554 549 {:success_code => :ok})
555 550
556 551 should "delete the issue" do
557 552 assert_difference('Issue.count',-1) do
558 delete '/issues/6.xml', {}, :authorization => credentials('jsmith')
553 delete '/issues/6.xml', {}, credentials('jsmith')
559 554 end
560 555
561 556 assert_nil Issue.find_by_id(6)
562 557 end
563 558 end
564 559
565 560 context "DELETE /issues/1.json" do
566 561 should_allow_api_authentication(:delete,
567 562 '/issues/6.json',
568 563 {},
569 564 {:success_code => :ok})
570 565
571 566 should "delete the issue" do
572 567 assert_difference('Issue.count',-1) do
573 delete '/issues/6.json', {}, :authorization => credentials('jsmith')
568 delete '/issues/6.json', {}, credentials('jsmith')
574 569 end
575 570
576 571 assert_nil Issue.find_by_id(6)
577 572 end
578 573 end
579 574 end
@@ -1,293 +1,293
1 1 # Redmine - project management software
2 2 # Copyright (C) 2006-2011 Jean-Philippe Lang
3 3 #
4 4 # This program is free software; you can redistribute it and/or
5 5 # modify it under the terms of the GNU General Public License
6 6 # as published by the Free Software Foundation; either version 2
7 7 # of the License, or (at your option) any later version.
8 8 #
9 9 # This program is distributed in the hope that it will be useful,
10 10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 12 # GNU General Public License for more details.
13 13 #
14 14 # You should have received a copy of the GNU General Public License
15 15 # along with this program; if not, write to the Free Software
16 16 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17 17
18 18 require File.expand_path('../../../test_helper', __FILE__)
19 19
20 20 class ApiTest::ProjectsTest < ActionController::IntegrationTest
21 21 fixtures :projects, :versions, :users, :roles, :members, :member_roles, :issues, :journals, :journal_details,
22 22 :trackers, :projects_trackers, :issue_statuses, :enabled_modules, :enumerations, :boards, :messages,
23 23 :attachments, :custom_fields, :custom_values, :time_entries, :issue_categories
24 24
25 25 def setup
26 26 Setting.rest_api_enabled = '1'
27 27 set_tmp_attachments_directory
28 28 end
29 29
30 30 context "GET /projects" do
31 31 context ".xml" do
32 32 should "return projects" do
33 33 get '/projects.xml'
34 34 assert_response :success
35 35 assert_equal 'application/xml', @response.content_type
36 36
37 37 assert_tag :tag => 'projects',
38 38 :child => {:tag => 'project', :child => {:tag => 'id', :content => '1'}}
39 39 end
40 40 end
41 41
42 42 context ".json" do
43 43 should "return projects" do
44 44 get '/projects.json'
45 45 assert_response :success
46 46 assert_equal 'application/json', @response.content_type
47 47
48 48 json = ActiveSupport::JSON.decode(response.body)
49 49 assert_kind_of Hash, json
50 50 assert_kind_of Array, json['projects']
51 51 assert_kind_of Hash, json['projects'].first
52 52 assert json['projects'].first.has_key?('id')
53 53 end
54 54 end
55 55 end
56 56
57 57 context "GET /projects/:id" do
58 58 context ".xml" do
59 59 # TODO: A private project is needed because should_allow_api_authentication
60 60 # actually tests that authentication is *required*, not just allowed
61 61 should_allow_api_authentication(:get, "/projects/2.xml")
62 62
63 63 should "return requested project" do
64 64 get '/projects/1.xml'
65 65 assert_response :success
66 66 assert_equal 'application/xml', @response.content_type
67 67
68 68 assert_tag :tag => 'project',
69 69 :child => {:tag => 'id', :content => '1'}
70 70 assert_tag :tag => 'custom_field',
71 71 :attributes => {:name => 'Development status'}, :content => 'Stable'
72 72
73 73 assert_no_tag 'trackers'
74 74 assert_no_tag 'issue_categories'
75 75 end
76 76
77 77 context "with hidden custom fields" do
78 78 setup do
79 79 ProjectCustomField.find_by_name('Development status').update_attribute :visible, false
80 80 end
81 81
82 82 should "not display hidden custom fields" do
83 83 get '/projects/1.xml'
84 84 assert_response :success
85 85 assert_equal 'application/xml', @response.content_type
86 86
87 87 assert_no_tag 'custom_field',
88 88 :attributes => {:name => 'Development status'}
89 89 end
90 90 end
91 91
92 92 should "return categories with include=issue_categories" do
93 93 get '/projects/1.xml?include=issue_categories'
94 94 assert_response :success
95 95 assert_equal 'application/xml', @response.content_type
96 96
97 97 assert_tag 'issue_categories',
98 98 :attributes => {:type => 'array'},
99 99 :child => {
100 100 :tag => 'issue_category',
101 101 :attributes => {
102 102 :id => '2',
103 103 :name => 'Recipes'
104 104 }
105 105 }
106 106 end
107 107
108 108 should "return trackers with include=trackers" do
109 109 get '/projects/1.xml?include=trackers'
110 110 assert_response :success
111 111 assert_equal 'application/xml', @response.content_type
112 112
113 113 assert_tag 'trackers',
114 114 :attributes => {:type => 'array'},
115 115 :child => {
116 116 :tag => 'tracker',
117 117 :attributes => {
118 118 :id => '2',
119 119 :name => 'Feature request'
120 120 }
121 121 }
122 122 end
123 123 end
124 124
125 125 context ".json" do
126 126 should_allow_api_authentication(:get, "/projects/2.json")
127 127
128 128 should "return requested project" do
129 129 get '/projects/1.json'
130 130
131 131 json = ActiveSupport::JSON.decode(response.body)
132 132 assert_kind_of Hash, json
133 133 assert_kind_of Hash, json['project']
134 134 assert_equal 1, json['project']['id']
135 135 end
136 136 end
137 137 end
138 138
139 139 context "POST /projects" do
140 140 context "with valid parameters" do
141 141 setup do
142 142 Setting.default_projects_modules = ['issue_tracking', 'repository']
143 143 @parameters = {:project => {:name => 'API test', :identifier => 'api-test'}}
144 144 end
145 145
146 146 context ".xml" do
147 147 should_allow_api_authentication(:post,
148 148 '/projects.xml',
149 149 {:project => {:name => 'API test', :identifier => 'api-test'}},
150 150 {:success_code => :created})
151 151
152 152
153 153 should "create a project with the attributes" do
154 154 assert_difference('Project.count') do
155 post '/projects.xml', @parameters, :authorization => credentials('admin')
155 post '/projects.xml', @parameters, credentials('admin')
156 156 end
157 157
158 158 project = Project.first(:order => 'id DESC')
159 159 assert_equal 'API test', project.name
160 160 assert_equal 'api-test', project.identifier
161 161 assert_equal ['issue_tracking', 'repository'], project.enabled_module_names.sort
162 162 assert_equal Tracker.all.size, project.trackers.size
163 163
164 164 assert_response :created
165 165 assert_equal 'application/xml', @response.content_type
166 166 assert_tag 'project', :child => {:tag => 'id', :content => project.id.to_s}
167 167 end
168 168
169 169 should "accept enabled_module_names attribute" do
170 170 @parameters[:project].merge!({:enabled_module_names => ['issue_tracking', 'news', 'time_tracking']})
171 171
172 172 assert_difference('Project.count') do
173 post '/projects.xml', @parameters, :authorization => credentials('admin')
173 post '/projects.xml', @parameters, credentials('admin')
174 174 end
175 175
176 176 project = Project.first(:order => 'id DESC')
177 177 assert_equal ['issue_tracking', 'news', 'time_tracking'], project.enabled_module_names.sort
178 178 end
179 179
180 180 should "accept tracker_ids attribute" do
181 181 @parameters[:project].merge!({:tracker_ids => [1, 3]})
182 182
183 183 assert_difference('Project.count') do
184 post '/projects.xml', @parameters, :authorization => credentials('admin')
184 post '/projects.xml', @parameters, credentials('admin')
185 185 end
186 186
187 187 project = Project.first(:order => 'id DESC')
188 188 assert_equal [1, 3], project.trackers.map(&:id).sort
189 189 end
190 190 end
191 191 end
192 192
193 193 context "with invalid parameters" do
194 194 setup do
195 195 @parameters = {:project => {:name => 'API test'}}
196 196 end
197 197
198 198 context ".xml" do
199 199 should "return errors" do
200 200 assert_no_difference('Project.count') do
201 post '/projects.xml', @parameters, :authorization => credentials('admin')
201 post '/projects.xml', @parameters, credentials('admin')
202 202 end
203 203
204 204 assert_response :unprocessable_entity
205 205 assert_equal 'application/xml', @response.content_type
206 206 assert_tag 'errors', :child => {:tag => 'error', :content => "Identifier can't be blank"}
207 207 end
208 208 end
209 209 end
210 210 end
211 211
212 212 context "PUT /projects/:id" do
213 213 context "with valid parameters" do
214 214 setup do
215 215 @parameters = {:project => {:name => 'API update'}}
216 216 end
217 217
218 218 context ".xml" do
219 219 should_allow_api_authentication(:put,
220 220 '/projects/2.xml',
221 221 {:project => {:name => 'API update'}},
222 222 {:success_code => :ok})
223 223
224 224 should "update the project" do
225 225 assert_no_difference 'Project.count' do
226 put '/projects/2.xml', @parameters, :authorization => credentials('jsmith')
226 put '/projects/2.xml', @parameters, credentials('jsmith')
227 227 end
228 228 assert_response :ok
229 229 assert_equal 'application/xml', @response.content_type
230 230 project = Project.find(2)
231 231 assert_equal 'API update', project.name
232 232 end
233 233
234 234 should "accept enabled_module_names attribute" do
235 235 @parameters[:project].merge!({:enabled_module_names => ['issue_tracking', 'news', 'time_tracking']})
236 236
237 237 assert_no_difference 'Project.count' do
238 put '/projects/2.xml', @parameters, :authorization => credentials('admin')
238 put '/projects/2.xml', @parameters, credentials('admin')
239 239 end
240 240 assert_response :ok
241 241 project = Project.find(2)
242 242 assert_equal ['issue_tracking', 'news', 'time_tracking'], project.enabled_module_names.sort
243 243 end
244 244
245 245 should "accept tracker_ids attribute" do
246 246 @parameters[:project].merge!({:tracker_ids => [1, 3]})
247 247
248 248 assert_no_difference 'Project.count' do
249 put '/projects/2.xml', @parameters, :authorization => credentials('admin')
249 put '/projects/2.xml', @parameters, credentials('admin')
250 250 end
251 251 assert_response :ok
252 252 project = Project.find(2)
253 253 assert_equal [1, 3], project.trackers.map(&:id).sort
254 254 end
255 255 end
256 256 end
257 257
258 258 context "with invalid parameters" do
259 259 setup do
260 260 @parameters = {:project => {:name => ''}}
261 261 end
262 262
263 263 context ".xml" do
264 264 should "return errors" do
265 265 assert_no_difference('Project.count') do
266 put '/projects/2.xml', @parameters, :authorization => credentials('admin')
266 put '/projects/2.xml', @parameters, credentials('admin')
267 267 end
268 268
269 269 assert_response :unprocessable_entity
270 270 assert_equal 'application/xml', @response.content_type
271 271 assert_tag 'errors', :child => {:tag => 'error', :content => "Name can't be blank"}
272 272 end
273 273 end
274 274 end
275 275 end
276 276
277 277 context "DELETE /projects/:id" do
278 278 context ".xml" do
279 279 should_allow_api_authentication(:delete,
280 280 '/projects/2.xml',
281 281 {},
282 282 {:success_code => :ok})
283 283
284 284 should "delete the project" do
285 285 assert_difference('Project.count',-1) do
286 delete '/projects/2.xml', {}, :authorization => credentials('admin')
286 delete '/projects/2.xml', {}, credentials('admin')
287 287 end
288 288 assert_response :ok
289 289 assert_nil Project.find_by_id(2)
290 290 end
291 291 end
292 292 end
293 293 end
@@ -1,148 +1,148
1 1 # Redmine - project management software
2 2 # Copyright (C) 2006-2011 Jean-Philippe Lang
3 3 #
4 4 # This program is free software; you can redistribute it and/or
5 5 # modify it under the terms of the GNU General Public License
6 6 # as published by the Free Software Foundation; either version 2
7 7 # of the License, or (at your option) any later version.
8 8 #
9 9 # This program is distributed in the hope that it will be useful,
10 10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 12 # GNU General Public License for more details.
13 13 #
14 14 # You should have received a copy of the GNU General Public License
15 15 # along with this program; if not, write to the Free Software
16 16 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17 17
18 18 require File.expand_path('../../../test_helper', __FILE__)
19 19
20 20 class ApiTest::TimeEntriesTest < ActionController::IntegrationTest
21 21 fixtures :projects, :trackers, :issue_statuses, :issues,
22 22 :enumerations, :users, :issue_categories,
23 23 :projects_trackers,
24 24 :roles,
25 25 :member_roles,
26 26 :members,
27 27 :enabled_modules,
28 28 :workflows,
29 29 :time_entries
30 30
31 31 def setup
32 32 Setting.rest_api_enabled = '1'
33 33 end
34 34
35 35 context "GET /time_entries.xml" do
36 36 should "return time entries" do
37 get '/time_entries.xml', {}, :authorization => credentials('jsmith')
37 get '/time_entries.xml', {}, credentials('jsmith')
38 38 assert_response :success
39 39 assert_equal 'application/xml', @response.content_type
40 40 assert_tag :tag => 'time_entries',
41 41 :child => {:tag => 'time_entry', :child => {:tag => 'id', :content => '2'}}
42 42 end
43 43
44 44 context "with limit" do
45 45 should "return limited results" do
46 get '/time_entries.xml?limit=2', {}, :authorization => credentials('jsmith')
46 get '/time_entries.xml?limit=2', {}, credentials('jsmith')
47 47 assert_response :success
48 48 assert_equal 'application/xml', @response.content_type
49 49 assert_tag :tag => 'time_entries',
50 50 :children => {:count => 2}
51 51 end
52 52 end
53 53 end
54 54
55 55 context "GET /time_entries/2.xml" do
56 56 should "return requested time entry" do
57 get '/time_entries/2.xml', {}, :authorization => credentials('jsmith')
57 get '/time_entries/2.xml', {}, credentials('jsmith')
58 58 assert_response :success
59 59 assert_equal 'application/xml', @response.content_type
60 60 assert_tag :tag => 'time_entry',
61 61 :child => {:tag => 'id', :content => '2'}
62 62 end
63 63 end
64 64
65 65 context "POST /time_entries.xml" do
66 66 context "with issue_id" do
67 67 should "return create time entry" do
68 68 assert_difference 'TimeEntry.count' do
69 post '/time_entries.xml', {:time_entry => {:issue_id => '1', :spent_on => '2010-12-02', :hours => '3.5', :activity_id => '11'}}, :authorization => credentials('jsmith')
69 post '/time_entries.xml', {:time_entry => {:issue_id => '1', :spent_on => '2010-12-02', :hours => '3.5', :activity_id => '11'}}, credentials('jsmith')
70 70 end
71 71 assert_response :created
72 72 assert_equal 'application/xml', @response.content_type
73 73
74 74 entry = TimeEntry.first(:order => 'id DESC')
75 75 assert_equal 'jsmith', entry.user.login
76 76 assert_equal Issue.find(1), entry.issue
77 77 assert_equal Project.find(1), entry.project
78 78 assert_equal Date.parse('2010-12-02'), entry.spent_on
79 79 assert_equal 3.5, entry.hours
80 80 assert_equal TimeEntryActivity.find(11), entry.activity
81 81 end
82 82 end
83 83
84 84 context "with project_id" do
85 85 should "return create time entry" do
86 86 assert_difference 'TimeEntry.count' do
87 post '/time_entries.xml', {:time_entry => {:project_id => '1', :spent_on => '2010-12-02', :hours => '3.5', :activity_id => '11'}}, :authorization => credentials('jsmith')
87 post '/time_entries.xml', {:time_entry => {:project_id => '1', :spent_on => '2010-12-02', :hours => '3.5', :activity_id => '11'}}, credentials('jsmith')
88 88 end
89 89 assert_response :created
90 90 assert_equal 'application/xml', @response.content_type
91 91
92 92 entry = TimeEntry.first(:order => 'id DESC')
93 93 assert_equal 'jsmith', entry.user.login
94 94 assert_nil entry.issue
95 95 assert_equal Project.find(1), entry.project
96 96 assert_equal Date.parse('2010-12-02'), entry.spent_on
97 97 assert_equal 3.5, entry.hours
98 98 assert_equal TimeEntryActivity.find(11), entry.activity
99 99 end
100 100 end
101 101
102 102 context "with invalid parameters" do
103 103 should "return errors" do
104 104 assert_no_difference 'TimeEntry.count' do
105 post '/time_entries.xml', {:time_entry => {:project_id => '1', :spent_on => '2010-12-02', :activity_id => '11'}}, :authorization => credentials('jsmith')
105 post '/time_entries.xml', {:time_entry => {:project_id => '1', :spent_on => '2010-12-02', :activity_id => '11'}}, credentials('jsmith')
106 106 end
107 107 assert_response :unprocessable_entity
108 108 assert_equal 'application/xml', @response.content_type
109 109
110 110 assert_tag 'errors', :child => {:tag => 'error', :content => "Hours can't be blank"}
111 111 end
112 112 end
113 113 end
114 114
115 115 context "PUT /time_entries/2.xml" do
116 116 context "with valid parameters" do
117 117 should "update time entry" do
118 118 assert_no_difference 'TimeEntry.count' do
119 put '/time_entries/2.xml', {:time_entry => {:comments => 'API Update'}}, :authorization => credentials('jsmith')
119 put '/time_entries/2.xml', {:time_entry => {:comments => 'API Update'}}, credentials('jsmith')
120 120 end
121 121 assert_response :ok
122 122 assert_equal 'API Update', TimeEntry.find(2).comments
123 123 end
124 124 end
125 125
126 126 context "with invalid parameters" do
127 127 should "return errors" do
128 128 assert_no_difference 'TimeEntry.count' do
129 put '/time_entries/2.xml', {:time_entry => {:hours => '', :comments => 'API Update'}}, :authorization => credentials('jsmith')
129 put '/time_entries/2.xml', {:time_entry => {:hours => '', :comments => 'API Update'}}, credentials('jsmith')
130 130 end
131 131 assert_response :unprocessable_entity
132 132 assert_equal 'application/xml', @response.content_type
133 133
134 134 assert_tag 'errors', :child => {:tag => 'error', :content => "Hours can't be blank"}
135 135 end
136 136 end
137 137 end
138 138
139 139 context "DELETE /time_entries/2.xml" do
140 140 should "destroy time entry" do
141 141 assert_difference 'TimeEntry.count', -1 do
142 delete '/time_entries/2.xml', {}, :authorization => credentials('jsmith')
142 delete '/time_entries/2.xml', {}, credentials('jsmith')
143 143 end
144 144 assert_response :ok
145 145 assert_nil TimeEntry.find_by_id(2)
146 146 end
147 147 end
148 148 end
@@ -1,315 +1,315
1 1 # Redmine - project management software
2 2 # Copyright (C) 2006-2011 Jean-Philippe Lang
3 3 #
4 4 # This program is free software; you can redistribute it and/or
5 5 # modify it under the terms of the GNU General Public License
6 6 # as published by the Free Software Foundation; either version 2
7 7 # of the License, or (at your option) any later version.
8 8 #
9 9 # This program is distributed in the hope that it will be useful,
10 10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 12 # GNU General Public License for more details.
13 13 #
14 14 # You should have received a copy of the GNU General Public License
15 15 # along with this program; if not, write to the Free Software
16 16 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17 17
18 18 require File.expand_path('../../../test_helper', __FILE__)
19 19 require 'pp'
20 20 class ApiTest::UsersTest < ActionController::IntegrationTest
21 21 fixtures :users
22 22
23 23 def setup
24 24 Setting.rest_api_enabled = '1'
25 25 end
26 26
27 27 context "GET /users" do
28 28 should_allow_api_authentication(:get, "/users.xml")
29 29 should_allow_api_authentication(:get, "/users.json")
30 30 end
31 31
32 32 context "GET /users/2" do
33 33 context ".xml" do
34 34 should "return requested user" do
35 35 get '/users/2.xml'
36 36
37 37 assert_tag :tag => 'user',
38 38 :child => {:tag => 'id', :content => '2'}
39 39 end
40 40 end
41 41
42 42 context ".json" do
43 43 should "return requested user" do
44 44 get '/users/2.json'
45 45
46 46 json = ActiveSupport::JSON.decode(response.body)
47 47 assert_kind_of Hash, json
48 48 assert_kind_of Hash, json['user']
49 49 assert_equal 2, json['user']['id']
50 50 end
51 51 end
52 52 end
53 53
54 54 context "GET /users/current" do
55 55 context ".xml" do
56 56 should "require authentication" do
57 57 get '/users/current.xml'
58 58
59 59 assert_response 401
60 60 end
61 61
62 62 should "return current user" do
63 get '/users/current.xml', {}, :authorization => credentials('jsmith')
63 get '/users/current.xml', {}, credentials('jsmith')
64 64
65 65 assert_tag :tag => 'user',
66 66 :child => {:tag => 'id', :content => '2'}
67 67 end
68 68 end
69 69 end
70 70
71 71 context "POST /users" do
72 72 context "with valid parameters" do
73 73 setup do
74 74 @parameters = {
75 75 :user => {
76 76 :login => 'foo', :firstname => 'Firstname', :lastname => 'Lastname',
77 77 :mail => 'foo@example.net', :password => 'secret',
78 78 :mail_notification => 'only_assigned'
79 79 }
80 80 }
81 81 end
82 82
83 83 context ".xml" do
84 84 should_allow_api_authentication(:post,
85 85 '/users.xml',
86 86 {:user => {
87 87 :login => 'foo', :firstname => 'Firstname', :lastname => 'Lastname',
88 88 :mail => 'foo@example.net', :password => 'secret'
89 89 }},
90 90 {:success_code => :created})
91 91
92 92 should "create a user with the attributes" do
93 93 assert_difference('User.count') do
94 post '/users.xml', @parameters, :authorization => credentials('admin')
94 post '/users.xml', @parameters, credentials('admin')
95 95 end
96 96
97 97 user = User.first(:order => 'id DESC')
98 98 assert_equal 'foo', user.login
99 99 assert_equal 'Firstname', user.firstname
100 100 assert_equal 'Lastname', user.lastname
101 101 assert_equal 'foo@example.net', user.mail
102 102 assert_equal 'only_assigned', user.mail_notification
103 103 assert !user.admin?
104 104 assert user.check_password?('secret')
105 105
106 106 assert_response :created
107 107 assert_equal 'application/xml', @response.content_type
108 108 assert_tag 'user', :child => {:tag => 'id', :content => user.id.to_s}
109 109 end
110 110 end
111 111
112 112 context ".json" do
113 113 should_allow_api_authentication(:post,
114 114 '/users.json',
115 115 {:user => {
116 116 :login => 'foo', :firstname => 'Firstname', :lastname => 'Lastname',
117 117 :mail => 'foo@example.net'
118 118 }},
119 119 {:success_code => :created})
120 120
121 121 should "create a user with the attributes" do
122 122 assert_difference('User.count') do
123 post '/users.json', @parameters, :authorization => credentials('admin')
123 post '/users.json', @parameters, credentials('admin')
124 124 end
125 125
126 126 user = User.first(:order => 'id DESC')
127 127 assert_equal 'foo', user.login
128 128 assert_equal 'Firstname', user.firstname
129 129 assert_equal 'Lastname', user.lastname
130 130 assert_equal 'foo@example.net', user.mail
131 131 assert !user.admin?
132 132
133 133 assert_response :created
134 134 assert_equal 'application/json', @response.content_type
135 135 json = ActiveSupport::JSON.decode(response.body)
136 136 assert_kind_of Hash, json
137 137 assert_kind_of Hash, json['user']
138 138 assert_equal user.id, json['user']['id']
139 139 end
140 140 end
141 141 end
142 142
143 143 context "with invalid parameters" do
144 144 setup do
145 145 @parameters = {:user => {:login => 'foo', :lastname => 'Lastname', :mail => 'foo'}}
146 146 end
147 147
148 148 context ".xml" do
149 149 should "return errors" do
150 150 assert_no_difference('User.count') do
151 post '/users.xml', @parameters, :authorization => credentials('admin')
151 post '/users.xml', @parameters, credentials('admin')
152 152 end
153 153
154 154 assert_response :unprocessable_entity
155 155 assert_equal 'application/xml', @response.content_type
156 156 assert_tag 'errors', :child => {
157 157 :tag => 'error',
158 158 :content => "First name can't be blank"
159 159 }
160 160 end
161 161 end
162 162
163 163 context ".json" do
164 164 should "return errors" do
165 165 assert_no_difference('User.count') do
166 post '/users.json', @parameters, :authorization => credentials('admin')
166 post '/users.json', @parameters, credentials('admin')
167 167 end
168 168
169 169 assert_response :unprocessable_entity
170 170 assert_equal 'application/json', @response.content_type
171 171 json = ActiveSupport::JSON.decode(response.body)
172 172 assert_kind_of Hash, json
173 173 assert json.has_key?('errors')
174 174 assert_kind_of Array, json['errors']
175 175 end
176 176 end
177 177 end
178 178 end
179 179
180 180 context "PUT /users/2" do
181 181 context "with valid parameters" do
182 182 setup do
183 183 @parameters = {
184 184 :user => {
185 185 :login => 'jsmith', :firstname => 'John', :lastname => 'Renamed',
186 186 :mail => 'jsmith@somenet.foo'
187 187 }
188 188 }
189 189 end
190 190
191 191 context ".xml" do
192 192 should_allow_api_authentication(:put,
193 193 '/users/2.xml',
194 194 {:user => {
195 195 :login => 'jsmith', :firstname => 'John', :lastname => 'Renamed',
196 196 :mail => 'jsmith@somenet.foo'
197 197 }},
198 198 {:success_code => :ok})
199 199
200 200 should "update user with the attributes" do
201 201 assert_no_difference('User.count') do
202 put '/users/2.xml', @parameters, :authorization => credentials('admin')
202 put '/users/2.xml', @parameters, credentials('admin')
203 203 end
204 204
205 205 user = User.find(2)
206 206 assert_equal 'jsmith', user.login
207 207 assert_equal 'John', user.firstname
208 208 assert_equal 'Renamed', user.lastname
209 209 assert_equal 'jsmith@somenet.foo', user.mail
210 210 assert !user.admin?
211 211
212 212 assert_response :ok
213 213 end
214 214 end
215 215
216 216 context ".json" do
217 217 should_allow_api_authentication(:put,
218 218 '/users/2.json',
219 219 {:user => {
220 220 :login => 'jsmith', :firstname => 'John', :lastname => 'Renamed',
221 221 :mail => 'jsmith@somenet.foo'
222 222 }},
223 223 {:success_code => :ok})
224 224
225 225 should "update user with the attributes" do
226 226 assert_no_difference('User.count') do
227 put '/users/2.json', @parameters, :authorization => credentials('admin')
227 put '/users/2.json', @parameters, credentials('admin')
228 228 end
229 229
230 230 user = User.find(2)
231 231 assert_equal 'jsmith', user.login
232 232 assert_equal 'John', user.firstname
233 233 assert_equal 'Renamed', user.lastname
234 234 assert_equal 'jsmith@somenet.foo', user.mail
235 235 assert !user.admin?
236 236
237 237 assert_response :ok
238 238 end
239 239 end
240 240 end
241 241
242 242 context "with invalid parameters" do
243 243 setup do
244 244 @parameters = {
245 245 :user => {
246 246 :login => 'jsmith', :firstname => '', :lastname => 'Lastname',
247 247 :mail => 'foo'
248 248 }
249 249 }
250 250 end
251 251
252 252 context ".xml" do
253 253 should "return errors" do
254 254 assert_no_difference('User.count') do
255 put '/users/2.xml', @parameters, :authorization => credentials('admin')
255 put '/users/2.xml', @parameters, credentials('admin')
256 256 end
257 257
258 258 assert_response :unprocessable_entity
259 259 assert_equal 'application/xml', @response.content_type
260 260 assert_tag 'errors', :child => {
261 261 :tag => 'error',
262 262 :content => "First name can't be blank"
263 263 }
264 264 end
265 265 end
266 266
267 267 context ".json" do
268 268 should "return errors" do
269 269 assert_no_difference('User.count') do
270 put '/users/2.json', @parameters, :authorization => credentials('admin')
270 put '/users/2.json', @parameters, credentials('admin')
271 271 end
272 272
273 273 assert_response :unprocessable_entity
274 274 assert_equal 'application/json', @response.content_type
275 275 json = ActiveSupport::JSON.decode(response.body)
276 276 assert_kind_of Hash, json
277 277 assert json.has_key?('errors')
278 278 assert_kind_of Array, json['errors']
279 279 end
280 280 end
281 281 end
282 282 end
283 283
284 284 context "DELETE /users/2" do
285 285 context ".xml" do
286 286 should_allow_api_authentication(:delete,
287 287 '/users/2.xml',
288 288 {},
289 289 {:success_code => :ok})
290 290
291 291 should "delete user" do
292 292 assert_difference('User.count', -1) do
293 delete '/users/2.xml', {}, :authorization => credentials('admin')
293 delete '/users/2.xml', {}, credentials('admin')
294 294 end
295 295
296 296 assert_response :ok
297 297 end
298 298 end
299 299
300 300 context ".json" do
301 301 should_allow_api_authentication(:delete,
302 302 '/users/2.xml',
303 303 {},
304 304 {:success_code => :ok})
305 305
306 306 should "delete user" do
307 307 assert_difference('User.count', -1) do
308 delete '/users/2.json', {}, :authorization => credentials('admin')
308 delete '/users/2.json', {}, credentials('admin')
309 309 end
310 310
311 311 assert_response :ok
312 312 end
313 313 end
314 314 end
315 315 end
@@ -1,124 +1,124
1 1 # Redmine - project management software
2 2 # Copyright (C) 2006-2011 Jean-Philippe Lang
3 3 #
4 4 # This program is free software; you can redistribute it and/or
5 5 # modify it under the terms of the GNU General Public License
6 6 # as published by the Free Software Foundation; either version 2
7 7 # of the License, or (at your option) any later version.
8 8 #
9 9 # This program is distributed in the hope that it will be useful,
10 10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 12 # GNU General Public License for more details.
13 13 #
14 14 # You should have received a copy of the GNU General Public License
15 15 # along with this program; if not, write to the Free Software
16 16 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17 17
18 18 require File.expand_path('../../../test_helper', __FILE__)
19 19
20 20 class ApiTest::VersionsTest < ActionController::IntegrationTest
21 21 fixtures :projects, :trackers, :issue_statuses, :issues,
22 22 :enumerations, :users, :issue_categories,
23 23 :projects_trackers,
24 24 :roles,
25 25 :member_roles,
26 26 :members,
27 27 :enabled_modules,
28 28 :workflows,
29 29 :versions
30 30
31 31 def setup
32 32 Setting.rest_api_enabled = '1'
33 33 end
34 34
35 35 context "/projects/:project_id/versions" do
36 36 context "GET" do
37 37 should "return project versions" do
38 38 get '/projects/1/versions.xml'
39 39
40 40 assert_response :success
41 41 assert_equal 'application/xml', @response.content_type
42 42 assert_tag :tag => 'versions',
43 43 :attributes => {:type => 'array'},
44 44 :child => {
45 45 :tag => 'version',
46 46 :child => {
47 47 :tag => 'id',
48 48 :content => '2',
49 49 :sibling => {
50 50 :tag => 'name',
51 51 :content => '1.0'
52 52 }
53 53 }
54 54 }
55 55 end
56 56 end
57 57
58 58 context "POST" do
59 59 should "create the version" do
60 60 assert_difference 'Version.count' do
61 post '/projects/1/versions.xml', {:version => {:name => 'API test'}}, :authorization => credentials('jsmith')
61 post '/projects/1/versions.xml', {:version => {:name => 'API test'}}, credentials('jsmith')
62 62 end
63 63
64 64 version = Version.first(:order => 'id DESC')
65 65 assert_equal 'API test', version.name
66 66
67 67 assert_response :created
68 68 assert_equal 'application/xml', @response.content_type
69 69 assert_tag 'version', :child => {:tag => 'id', :content => version.id.to_s}
70 70 end
71 71
72 72 context "with failure" do
73 73 should "return the errors" do
74 74 assert_no_difference('Version.count') do
75 post '/projects/1/versions.xml', {:version => {:name => ''}}, :authorization => credentials('jsmith')
75 post '/projects/1/versions.xml', {:version => {:name => ''}}, credentials('jsmith')
76 76 end
77 77
78 78 assert_response :unprocessable_entity
79 79 assert_tag :errors, :child => {:tag => 'error', :content => "Name can't be blank"}
80 80 end
81 81 end
82 82 end
83 83 end
84 84
85 85 context "/versions/:id" do
86 86 context "GET" do
87 87 should "return the version" do
88 88 get '/versions/2.xml'
89 89
90 90 assert_response :success
91 91 assert_equal 'application/xml', @response.content_type
92 92 assert_tag 'version',
93 93 :child => {
94 94 :tag => 'id',
95 95 :content => '2',
96 96 :sibling => {
97 97 :tag => 'name',
98 98 :content => '1.0'
99 99 }
100 100 }
101 101 end
102 102 end
103 103
104 104 context "PUT" do
105 105 should "update the version" do
106 put '/versions/2.xml', {:version => {:name => 'API update'}}, :authorization => credentials('jsmith')
106 put '/versions/2.xml', {:version => {:name => 'API update'}}, credentials('jsmith')
107 107
108 108 assert_response :ok
109 109 assert_equal 'API update', Version.find(2).name
110 110 end
111 111 end
112 112
113 113 context "DELETE" do
114 114 should "destroy the version" do
115 115 assert_difference 'Version.count', -1 do
116 delete '/versions/3.xml', {}, :authorization => credentials('jsmith')
116 delete '/versions/3.xml', {}, credentials('jsmith')
117 117 end
118 118
119 119 assert_response :ok
120 120 assert_nil Version.find_by_id(3)
121 121 end
122 122 end
123 123 end
124 124 end
@@ -1,454 +1,454
1 1 # Redmine - project management software
2 2 # Copyright (C) 2006-2011 Jean-Philippe Lang
3 3 #
4 4 # This program is free software; you can redistribute it and/or
5 5 # modify it under the terms of the GNU General Public License
6 6 # as published by the Free Software Foundation; either version 2
7 7 # of the License, or (at your option) any later version.
8 8 #
9 9 # This program is distributed in the hope that it will be useful,
10 10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 12 # GNU General Public License for more details.
13 13 #
14 14 # You should have received a copy of the GNU General Public License
15 15 # along with this program; if not, write to the Free Software
16 16 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17 17
18 18 ENV["RAILS_ENV"] = "test"
19 19 require File.expand_path(File.dirname(__FILE__) + "/../config/environment")
20 20 require 'test_help'
21 21 require Rails.root.join('test', 'mocks', 'open_id_authentication_mock.rb').to_s
22 22
23 23 require File.expand_path(File.dirname(__FILE__) + '/object_daddy_helpers')
24 24 include ObjectDaddyHelpers
25 25
26 26 class ActiveSupport::TestCase
27 27 # Transactional fixtures accelerate your tests by wrapping each test method
28 28 # in a transaction that's rolled back on completion. This ensures that the
29 29 # test database remains unchanged so your fixtures don't have to be reloaded
30 30 # between every test method. Fewer database queries means faster tests.
31 31 #
32 32 # Read Mike Clark's excellent walkthrough at
33 33 # http://clarkware.com/cgi/blosxom/2005/10/24#Rails10FastTesting
34 34 #
35 35 # Every Active Record database supports transactions except MyISAM tables
36 36 # in MySQL. Turn off transactional fixtures in this case; however, if you
37 37 # don't care one way or the other, switching from MyISAM to InnoDB tables
38 38 # is recommended.
39 39 self.use_transactional_fixtures = true
40 40
41 41 # Instantiated fixtures are slow, but give you @david where otherwise you
42 42 # would need people(:david). If you don't want to migrate your existing
43 43 # test cases which use the @david style and don't mind the speed hit (each
44 44 # instantiated fixtures translates to a database query per test method),
45 45 # then set this back to true.
46 46 self.use_instantiated_fixtures = false
47 47
48 48 # Add more helper methods to be used by all tests here...
49 49
50 50 def log_user(login, password)
51 51 User.anonymous
52 52 get "/login"
53 53 assert_equal nil, session[:user_id]
54 54 assert_response :success
55 55 assert_template "account/login"
56 56 post "/login", :username => login, :password => password
57 57 assert_equal login, User.find(session[:user_id]).login
58 58 end
59 59
60 60 def uploaded_test_file(name, mime)
61 61 ActionController::TestUploadedFile.new(
62 62 ActiveSupport::TestCase.fixture_path + "/files/#{name}", mime, true)
63 63 end
64 64
65 65 def credentials(user, password=nil)
66 ActionController::HttpAuthentication::Basic.encode_credentials(user, password || user)
66 {:authorization => ActionController::HttpAuthentication::Basic.encode_credentials(user, password || user)}
67 67 end
68 68
69 69 # Mock out a file
70 70 def self.mock_file
71 71 file = 'a_file.png'
72 72 file.stubs(:size).returns(32)
73 73 file.stubs(:original_filename).returns('a_file.png')
74 74 file.stubs(:content_type).returns('image/png')
75 75 file.stubs(:read).returns(false)
76 76 file
77 77 end
78 78
79 79 def mock_file
80 80 self.class.mock_file
81 81 end
82 82
83 83 def mock_file_with_options(options={})
84 84 file = ''
85 85 file.stubs(:size).returns(32)
86 86 original_filename = options[:original_filename] || nil
87 87 file.stubs(:original_filename).returns(original_filename)
88 88 content_type = options[:content_type] || nil
89 89 file.stubs(:content_type).returns(content_type)
90 90 file.stubs(:read).returns(false)
91 91 file
92 92 end
93 93
94 94 # Use a temporary directory for attachment related tests
95 95 def set_tmp_attachments_directory
96 96 Dir.mkdir "#{Rails.root}/tmp/test" unless File.directory?("#{Rails.root}/tmp/test")
97 97 unless File.directory?("#{Rails.root}/tmp/test/attachments")
98 98 Dir.mkdir "#{Rails.root}/tmp/test/attachments"
99 99 end
100 100 Attachment.storage_path = "#{Rails.root}/tmp/test/attachments"
101 101 end
102 102
103 103 def set_fixtures_attachments_directory
104 104 Attachment.storage_path = "#{Rails.root}/test/fixtures/files"
105 105 end
106 106
107 107 def with_settings(options, &block)
108 108 saved_settings = options.keys.inject({}) {|h, k| h[k] = Setting[k].is_a?(Symbol) ? Setting[k] : Setting[k].dup; h}
109 109 options.each {|k, v| Setting[k] = v}
110 110 yield
111 111 ensure
112 112 saved_settings.each {|k, v| Setting[k] = v} if saved_settings
113 113 end
114 114
115 115 def change_user_password(login, new_password)
116 116 user = User.first(:conditions => {:login => login})
117 117 user.password, user.password_confirmation = new_password, new_password
118 118 user.save!
119 119 end
120 120
121 121 def self.ldap_configured?
122 122 @test_ldap = Net::LDAP.new(:host => '127.0.0.1', :port => 389)
123 123 return @test_ldap.bind
124 124 rescue Exception => e
125 125 # LDAP is not listening
126 126 return nil
127 127 end
128 128
129 129 # Returns the path to the test +vendor+ repository
130 130 def self.repository_path(vendor)
131 131 Rails.root.join("tmp/test/#{vendor.downcase}_repository").to_s
132 132 end
133 133
134 134 # Returns the url of the subversion test repository
135 135 def self.subversion_repository_url
136 136 path = repository_path('subversion')
137 137 path = '/' + path unless path.starts_with?('/')
138 138 "file://#{path}"
139 139 end
140 140
141 141 # Returns true if the +vendor+ test repository is configured
142 142 def self.repository_configured?(vendor)
143 143 File.directory?(repository_path(vendor))
144 144 end
145 145
146 146 def assert_error_tag(options={})
147 147 assert_tag({:attributes => { :id => 'errorExplanation' }}.merge(options))
148 148 end
149 149
150 150 def assert_include(expected, s)
151 151 assert s.include?(expected), "\"#{expected}\" not found in \"#{s}\""
152 152 end
153 153
154 154 # Shoulda macros
155 155 def self.should_render_404
156 156 should_respond_with :not_found
157 157 should_render_template 'common/error'
158 158 end
159 159
160 160 def self.should_have_before_filter(expected_method, options = {})
161 161 should_have_filter('before', expected_method, options)
162 162 end
163 163
164 164 def self.should_have_after_filter(expected_method, options = {})
165 165 should_have_filter('after', expected_method, options)
166 166 end
167 167
168 168 def self.should_have_filter(filter_type, expected_method, options)
169 169 description = "have #{filter_type}_filter :#{expected_method}"
170 170 description << " with #{options.inspect}" unless options.empty?
171 171
172 172 should description do
173 173 klass = "action_controller/filters/#{filter_type}_filter".classify.constantize
174 174 expected = klass.new(:filter, expected_method.to_sym, options)
175 175 assert_equal 1, @controller.class.filter_chain.select { |filter|
176 176 filter.method == expected.method && filter.kind == expected.kind &&
177 177 filter.options == expected.options && filter.class == expected.class
178 178 }.size
179 179 end
180 180 end
181 181
182 182 def self.should_show_the_old_and_new_values_for(prop_key, model, &block)
183 183 context "" do
184 184 setup do
185 185 if block_given?
186 186 instance_eval &block
187 187 else
188 188 @old_value = model.generate!
189 189 @new_value = model.generate!
190 190 end
191 191 end
192 192
193 193 should "use the new value's name" do
194 194 @detail = JournalDetail.generate!(:property => 'attr',
195 195 :old_value => @old_value.id,
196 196 :value => @new_value.id,
197 197 :prop_key => prop_key)
198 198
199 199 assert_match @new_value.name, show_detail(@detail, true)
200 200 end
201 201
202 202 should "use the old value's name" do
203 203 @detail = JournalDetail.generate!(:property => 'attr',
204 204 :old_value => @old_value.id,
205 205 :value => @new_value.id,
206 206 :prop_key => prop_key)
207 207
208 208 assert_match @old_value.name, show_detail(@detail, true)
209 209 end
210 210 end
211 211 end
212 212
213 213 # Test that a request allows the three types of API authentication
214 214 #
215 215 # * HTTP Basic with username and password
216 216 # * HTTP Basic with an api key for the username
217 217 # * Key based with the key=X parameter
218 218 #
219 219 # @param [Symbol] http_method the HTTP method for request (:get, :post, :put, :delete)
220 220 # @param [String] url the request url
221 221 # @param [optional, Hash] parameters additional request parameters
222 222 # @param [optional, Hash] options additional options
223 223 # @option options [Symbol] :success_code Successful response code (:success)
224 224 # @option options [Symbol] :failure_code Failure response code (:unauthorized)
225 225 def self.should_allow_api_authentication(http_method, url, parameters={}, options={})
226 226 should_allow_http_basic_auth_with_username_and_password(http_method, url, parameters, options)
227 227 should_allow_http_basic_auth_with_key(http_method, url, parameters, options)
228 228 should_allow_key_based_auth(http_method, url, parameters, options)
229 229 end
230 230
231 231 # Test that a request allows the username and password for HTTP BASIC
232 232 #
233 233 # @param [Symbol] http_method the HTTP method for request (:get, :post, :put, :delete)
234 234 # @param [String] url the request url
235 235 # @param [optional, Hash] parameters additional request parameters
236 236 # @param [optional, Hash] options additional options
237 237 # @option options [Symbol] :success_code Successful response code (:success)
238 238 # @option options [Symbol] :failure_code Failure response code (:unauthorized)
239 239 def self.should_allow_http_basic_auth_with_username_and_password(http_method, url, parameters={}, options={})
240 240 success_code = options[:success_code] || :success
241 241 failure_code = options[:failure_code] || :unauthorized
242 242
243 243 context "should allow http basic auth using a username and password for #{http_method} #{url}" do
244 244 context "with a valid HTTP authentication" do
245 245 setup do
246 246 @user = User.generate_with_protected!(:password => 'my_password', :password_confirmation => 'my_password', :admin => true) # Admin so they can access the project
247 send(http_method, url, parameters, {:authorization => credentials(@user.login, 'my_password')})
247 send(http_method, url, parameters, credentials(@user.login, 'my_password'))
248 248 end
249 249
250 250 should_respond_with success_code
251 251 should_respond_with_content_type_based_on_url(url)
252 252 should "login as the user" do
253 253 assert_equal @user, User.current
254 254 end
255 255 end
256 256
257 257 context "with an invalid HTTP authentication" do
258 258 setup do
259 259 @user = User.generate_with_protected!
260 send(http_method, url, parameters, {:authorization => credentials(@user.login, 'wrong_password')})
260 send(http_method, url, parameters, credentials(@user.login, 'wrong_password'))
261 261 end
262 262
263 263 should_respond_with failure_code
264 264 should_respond_with_content_type_based_on_url(url)
265 265 should "not login as the user" do
266 266 assert_equal User.anonymous, User.current
267 267 end
268 268 end
269 269
270 270 context "without credentials" do
271 271 setup do
272 send(http_method, url, parameters, {:authorization => ''})
272 send(http_method, url, parameters)
273 273 end
274 274
275 275 should_respond_with failure_code
276 276 should_respond_with_content_type_based_on_url(url)
277 277 should "include_www_authenticate_header" do
278 278 assert @controller.response.headers.has_key?('WWW-Authenticate')
279 279 end
280 280 end
281 281 end
282 282
283 283 end
284 284
285 285 # Test that a request allows the API key with HTTP BASIC
286 286 #
287 287 # @param [Symbol] http_method the HTTP method for request (:get, :post, :put, :delete)
288 288 # @param [String] url the request url
289 289 # @param [optional, Hash] parameters additional request parameters
290 290 # @param [optional, Hash] options additional options
291 291 # @option options [Symbol] :success_code Successful response code (:success)
292 292 # @option options [Symbol] :failure_code Failure response code (:unauthorized)
293 293 def self.should_allow_http_basic_auth_with_key(http_method, url, parameters={}, options={})
294 294 success_code = options[:success_code] || :success
295 295 failure_code = options[:failure_code] || :unauthorized
296 296
297 297 context "should allow http basic auth with a key for #{http_method} #{url}" do
298 298 context "with a valid HTTP authentication using the API token" do
299 299 setup do
300 300 @user = User.generate_with_protected!(:admin => true)
301 301 @token = Token.generate!(:user => @user, :action => 'api')
302 send(http_method, url, parameters, {:authorization => credentials(@token.value, 'X')})
302 send(http_method, url, parameters, credentials(@token.value, 'X'))
303 303 end
304 304
305 305 should_respond_with success_code
306 306 should_respond_with_content_type_based_on_url(url)
307 307 should_be_a_valid_response_string_based_on_url(url)
308 308 should "login as the user" do
309 309 assert_equal @user, User.current
310 310 end
311 311 end
312 312
313 313 context "with an invalid HTTP authentication" do
314 314 setup do
315 315 @user = User.generate_with_protected!
316 316 @token = Token.generate!(:user => @user, :action => 'feeds')
317 send(http_method, url, parameters, {:authorization => credentials(@token.value, 'X')})
317 send(http_method, url, parameters, credentials(@token.value, 'X'))
318 318 end
319 319
320 320 should_respond_with failure_code
321 321 should_respond_with_content_type_based_on_url(url)
322 322 should "not login as the user" do
323 323 assert_equal User.anonymous, User.current
324 324 end
325 325 end
326 326 end
327 327 end
328 328
329 329 # Test that a request allows full key authentication
330 330 #
331 331 # @param [Symbol] http_method the HTTP method for request (:get, :post, :put, :delete)
332 332 # @param [String] url the request url, without the key=ZXY parameter
333 333 # @param [optional, Hash] parameters additional request parameters
334 334 # @param [optional, Hash] options additional options
335 335 # @option options [Symbol] :success_code Successful response code (:success)
336 336 # @option options [Symbol] :failure_code Failure response code (:unauthorized)
337 337 def self.should_allow_key_based_auth(http_method, url, parameters={}, options={})
338 338 success_code = options[:success_code] || :success
339 339 failure_code = options[:failure_code] || :unauthorized
340 340
341 341 context "should allow key based auth using key=X for #{http_method} #{url}" do
342 342 context "with a valid api token" do
343 343 setup do
344 344 @user = User.generate_with_protected!(:admin => true)
345 345 @token = Token.generate!(:user => @user, :action => 'api')
346 346 # Simple url parse to add on ?key= or &key=
347 347 request_url = if url.match(/\?/)
348 348 url + "&key=#{@token.value}"
349 349 else
350 350 url + "?key=#{@token.value}"
351 351 end
352 352 send(http_method, request_url, parameters)
353 353 end
354 354
355 355 should_respond_with success_code
356 356 should_respond_with_content_type_based_on_url(url)
357 357 should_be_a_valid_response_string_based_on_url(url)
358 358 should "login as the user" do
359 359 assert_equal @user, User.current
360 360 end
361 361 end
362 362
363 363 context "with an invalid api token" do
364 364 setup do
365 365 @user = User.generate_with_protected!
366 366 @token = Token.generate!(:user => @user, :action => 'feeds')
367 367 # Simple url parse to add on ?key= or &key=
368 368 request_url = if url.match(/\?/)
369 369 url + "&key=#{@token.value}"
370 370 else
371 371 url + "?key=#{@token.value}"
372 372 end
373 373 send(http_method, request_url, parameters)
374 374 end
375 375
376 376 should_respond_with failure_code
377 377 should_respond_with_content_type_based_on_url(url)
378 378 should "not login as the user" do
379 379 assert_equal User.anonymous, User.current
380 380 end
381 381 end
382 382 end
383 383
384 384 context "should allow key based auth using X-Redmine-API-Key header for #{http_method} #{url}" do
385 385 setup do
386 386 @user = User.generate_with_protected!(:admin => true)
387 387 @token = Token.generate!(:user => @user, :action => 'api')
388 388 send(http_method, url, parameters, {'X-Redmine-API-Key' => @token.value.to_s})
389 389 end
390 390
391 391 should_respond_with success_code
392 392 should_respond_with_content_type_based_on_url(url)
393 393 should_be_a_valid_response_string_based_on_url(url)
394 394 should "login as the user" do
395 395 assert_equal @user, User.current
396 396 end
397 397 end
398 398 end
399 399
400 400 # Uses should_respond_with_content_type based on what's in the url:
401 401 #
402 402 # '/project/issues.xml' => should_respond_with_content_type :xml
403 403 # '/project/issues.json' => should_respond_with_content_type :json
404 404 #
405 405 # @param [String] url Request
406 406 def self.should_respond_with_content_type_based_on_url(url)
407 407 case
408 408 when url.match(/xml/i)
409 409 should_respond_with_content_type :xml
410 410 when url.match(/json/i)
411 411 should_respond_with_content_type :json
412 412 else
413 413 raise "Unknown content type for should_respond_with_content_type_based_on_url: #{url}"
414 414 end
415 415
416 416 end
417 417
418 418 # Uses the url to assert which format the response should be in
419 419 #
420 420 # '/project/issues.xml' => should_be_a_valid_xml_string
421 421 # '/project/issues.json' => should_be_a_valid_json_string
422 422 #
423 423 # @param [String] url Request
424 424 def self.should_be_a_valid_response_string_based_on_url(url)
425 425 case
426 426 when url.match(/xml/i)
427 427 should_be_a_valid_xml_string
428 428 when url.match(/json/i)
429 429 should_be_a_valid_json_string
430 430 else
431 431 raise "Unknown content type for should_be_a_valid_response_based_on_url: #{url}"
432 432 end
433 433
434 434 end
435 435
436 436 # Checks that the response is a valid JSON string
437 437 def self.should_be_a_valid_json_string
438 438 should "be a valid JSON string (or empty)" do
439 439 assert(response.body.blank? || ActiveSupport::JSON.decode(response.body))
440 440 end
441 441 end
442 442
443 443 # Checks that the response is a valid XML string
444 444 def self.should_be_a_valid_xml_string
445 445 should "be a valid XML string" do
446 446 assert REXML::Document.new(response.body)
447 447 end
448 448 end
449 449
450 450 end
451 451
452 452 # Simple module to "namespace" all of the API tests
453 453 module ApiTest
454 454 end
General Comments 0
You need to be logged in to leave comments. Login now