Authorization for trees controller
[gitorious:mainline.git] / test / functional / trees_controller_test.rb
1 # encoding: utf-8
2 #--
3 #   Copyright (C) 2012 Gitorious AS
4 #   Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies)
5 #
6 #   This program is free software: you can redistribute it and/or modify
7 #   it under the terms of the GNU Affero General Public License as published by
8 #   the Free Software Foundation, either version 3 of the License, or
9 #   (at your option) any later version.
10 #
11 #   This program is distributed in the hope that it will be useful,
12 #   but WITHOUT ANY WARRANTY; without even the implied warranty of
13 #   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14 #   GNU Affero General Public License for more details.
15 #
16 #   You should have received a copy of the GNU Affero General Public License
17 #   along with this program.  If not, see <http://www.gnu.org/licenses/>.
18 #++
19
20 require File.dirname(__FILE__) + "/../test_helper"
21
22 class TreesControllerTest < ActionController::TestCase
23
24   should_render_in_site_specific_context :except => [:archive]
25
26   should_enforce_ssl_for(:get, :archive)
27   should_enforce_ssl_for(:get, :index)
28   should_enforce_ssl_for(:get, :show)
29
30   context "routing" do
31     should_eventually "recognize a single glob with a format" do
32       pending "fix rails bug #1939"
33       assert_recognizes({
34         :controller => "trees",
35         :action => "archive",
36         :project_id => "proj",
37         :repository_id => "repo",
38         :branch => ["foo"],
39         :format => "tar.gz",
40       }, "/proj/repo/archive/foo.tar.gz")
41       assert_recognizes({
42         :controller => "trees",
43         :action => "archive",
44         :project_id => "proj",
45         :repository_id => "repo",
46         :branch => ["foo"],
47         :format => "zip",
48       }, "/proj/repo/archive/foo.zip")
49     end
50
51     should_eventually "recognize multiple globs with a format" do
52       pending "fix rails bug #1939"
53       assert_recognizes({
54         :controller => "trees",
55         :action => "archive",
56         :project_id => "proj",
57         :repository_id => "repo",
58         :branch => ["foo", "bar"],
59         :format => "zip",
60       }, "/proj/repo/archive/foo/bar.zip")
61       assert_recognizes({
62         :controller => "trees",
63         :action => "archive",
64         :project_id => "proj",
65         :repository_id => "repo",
66         :branch => ["foo", "bar"],
67         :format => "tar.gz",
68       }, "/proj/repo/archive/foo/bar.tar.gz")
69     end
70   end
71
72   def setup
73     @project = projects(:johans)
74     @repository = @project.repositories.mainlines.first
75     @repository.update_attribute(:ready, true)
76
77     Repository.any_instance.stubs(:full_repository_path).returns(grit_test_repo("dot_git"))
78     @grit = Grit::Repo.new(grit_test_repo("dot_git"), :is_bare => true)
79     Repository.any_instance.stubs(:git).returns(@grit)
80   end
81
82   context "#index" do
83     should "redirect to the master head, if not :id given" do
84       get :index, params
85       assert_redirected_to(project_repository_tree_path(@project, @repository, ["master"]))
86     end
87   end
88
89   context "#show" do
90     should "GET successfully" do
91       get :show, params(:branch_and_path => ["master", "lib", "grit"])
92
93       assert_response :success
94       assert_equal @repository.git.tree("81a18c36ebe04e406ab84ccc911d79e65e14d1c0"), assigns(:tree)
95       assert_equal "master", assigns(:ref)
96       assert_equal ["lib", "grit"], assigns(:path)
97     end
98
99     should "redirect to HEAD if provided sha was not found (backwards compat)" do
100       get :show, params(:branch_and_path => ["a"*40, "foo"])
101
102       assert_redirected_to(project_repository_tree_path(@project, @repository, ["HEAD", "foo"]))
103     end
104
105     should "set a pseudo-head if the tree ref is a sha" do
106       ref = "3fa4e130fa18c92e3030d4accb5d3e0cadd40157"
107       get :show, params(:branch_and_path => [ref])
108
109       assert_response :success
110       assert_equal ref[0..6], assigns(:root).breadcrumb_parent.title
111     end
112
113     should "support browsing a namespaced branch" do
114       get :show, params(:branch_and_path => ["test", "master", "lib"])
115
116       assert_response :success
117       assert_equal "test/master", assigns(:root).breadcrumb_parent.breadcrumb_parent.title
118       assert_equal ["lib"], assigns(:path)
119     end
120
121     should "cache the tree" do
122       get :show, params(:branch_and_path => ["test", "master", "lib"])
123
124       assert_response :success
125       assert_equal "max-age=30, private", @response.headers["Cache-Control"]
126     end
127
128     should "redirect to the tree index with a msg if the tree SHA1 was not found" do
129       @grit.expects(:commit).with("master").returns(nil)
130       get :show, params(:branch_and_path => ["master", "lib"])
131       assert_response :redirect
132       assert_match(/no such tree sha/i, flash[:error])
133     end
134   end
135
136   context "Branch names containing a # character" do
137     should "show branches with a # in them with great success" do
138       git_repo = Grit::Repo.new(grit_test_repo("dot_git"), :is_bare => true)
139       @repository.git.expects(:commit).with("ticket-#42") \
140         .returns(git_repo.commit("master"))
141       get :show, params(:branch_and_path => ["ticket-%2342"])
142       assert_response :success
143       assert_equal "ticket-#42", assigns(:ref)
144     end
145
146     should "urlencode # in branch names" do
147       Repository.any_instance.expects(:head_candidate_name).returns("ticket-#42")
148       get :index, params
149       assert_response :redirect
150       assert_redirected_to project_repository_tree_path(@project, @repository, ["ticket-#42"])
151     end
152   end
153
154   context "Archive downloads" do
155     setup do
156       @master_sha = "ca8a30f5a7f0f163bbe3b6f0abf18a6c83b0687a"
157       @test_master_sha = "2d3acf90f35989df8f262dc50beadc4ee3ae1560"
158     end
159
160     should "return the correct for an existing cached tarball" do
161       cached_path = File.join(GitoriousConfig["archive_cache_dir"],
162                         "#{@repository.hashed_path.gsub(/\//, '-')}-#{@master_sha}.tar.gz")
163       File.expects(:exist?).with(cached_path).returns(true)
164
165       get :archive, params(:branch => %w[master], :archive_format => "tar.gz")
166
167       assert_response :success
168       assert_equal cached_path, @response.headers["X-Sendfile"]
169       assert_equal "application/x-gzip; charset=utf-8", @response.headers["Content-Type"]
170       exp_filename = "#{@repository.project.to_param}-#{@repository.to_param}-master.tar.gz"
171       assert_equal "Content-Disposition: attachment; filename=\"#{exp_filename}\"", @response.headers["Content-Disposition"]
172     end
173
174     should "enqueue a job when the tarball is not cached" do
175       cached_path = File.join(GitoriousConfig["archive_cache_dir"],
176                       "#{@repository.hashed_path.gsub(/\//, '-')}-#{@test_master_sha}.tar.gz")
177       work_path = File.join(GitoriousConfig["archive_work_dir"],
178                       "#{@repository.hashed_path.gsub(/\//, '-')}-#{@test_master_sha}.tar.gz")
179       File.expects(:exist?).with(cached_path).returns(false)
180       File.expects(:exist?).with(work_path).returns(false)
181
182       get :archive, params(:branch => %w[test master], :archive_format => "tar.gz")
183
184       assert_response 202 # Accepted
185       assert_match(/is currently being generated, try again later/, @response.body)
186       assert_equal "text/plain; charset=utf-8", @response.headers["Content-Type"]
187
188       assert_published("/queue/GitoriousRepositoryArchiving", {
189                          "full_repository_path" => @repository.full_repository_path,
190                          "output_path" => cached_path,
191                          "format" => "tar.gz"
192                        })
193     end
194
195     should "not enqueue a job when work has already begun" do
196       cached_path = File.join(GitoriousConfig["archive_cache_dir"],
197                       "#{@repository.hashed_path.gsub(/\//, '-')}-#{@master_sha}.tar.gz")
198       work_path = File.join(GitoriousConfig["archive_work_dir"],
199                       "#{@repository.hashed_path.gsub(/\//, '-')}-#{@master_sha}.tar.gz")
200       File.expects(:exist?).with(cached_path).returns(false)
201       File.expects(:exist?).with(work_path).returns(true)
202
203       get :archive, params(:branch => %w[master], :archive_format => "tar.gz")
204
205       assert_response 202 # Accepted
206
207       messages = Gitorious::Messaging::TestAdapter.messages_on("/queue/GitoriousRepositoryArchiving")
208       assert_nil messages.find { |m| m["comit_sha"] == @master_sha }
209     end
210
211     should "redirect to the first tree when an invalid ref is requested" do
212       get :archive, params(:branch => %w[foo], :archive_format => "tar.gz")
213
214       assert_response :redirect
215       assert_redirected_to project_repository_tree_path(@project, @repository, "HEAD")
216     end
217   end
218
219   context "With private repositories" do
220     setup do
221       enable_private_repositories
222     end
223
224     should "disallow unauthorized users from listing trees" do
225       get :index, params
226       assert_response 403
227     end
228
229     should "allow authorized users to list trees" do
230       login_as :johan
231       get :index, params
232       assert_response 302
233     end
234
235     should "disallow unauthorized users from showing tree" do
236       get :show, params(:branch_and_path => ["master", "lib", "grit"])
237       assert_response 403
238     end
239
240     should "allow authorized users to show tree" do
241       login_as :johan
242       get :show, params(:branch_and_path => ["master", "lib", "grit"])
243       assert_response 302
244     end
245
246     should "disallow unauthorized users from showing archive" do
247       get :archive, params(:branch => %w[master], :archive_format => "tar.gz")
248       assert_response 403
249     end
250
251     should "allow authorized users to show archive" do
252       login_as :johan
253       get :archive, params(:branch => %w[master], :archive_format => "tar.gz")
254       assert_response 302
255     end
256   end
257
258   private
259   def params(data = {})
260     { :project_id => @project.slug, :repository_id => @repository.name }.merge(data)
261   end
262 end