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