Merge remote-tracking branch 'official/master' into saltation
[gitorious:taladars-gitorious-saltation.git] / test / functional / repositories_controller_test.rb
1 # encoding: utf-8
2 #--
3 #   Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies)
4 #
5 #   This program is free software: you can redistribute it and/or modify
6 #   it under the terms of the GNU Affero General Public License as published by
7 #   the Free Software Foundation, either version 3 of the License, or
8 #   (at your option) any later version.
9 #
10 #   This program is distributed in the hope that it will be useful,
11 #   but WITHOUT ANY WARRANTY; without even the implied warranty of
12 #   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13 #   GNU Affero General Public License for more details.
14 #
15 #   You should have received a copy of the GNU Affero General Public License
16 #   along with this program.  If not, see <http://www.gnu.org/licenses/>.
17 #++
18
19
20 require File.dirname(__FILE__) + '/../test_helper'
21
22 class RepositoriesControllerTest < ActionController::TestCase
23   should_enforce_ssl_for(:delete, :destroy)
24   should_enforce_ssl_for(:get, :clone)
25   should_enforce_ssl_for(:get, :confirm_delete)
26   should_enforce_ssl_for(:get, :edit)
27   should_enforce_ssl_for(:get, :index)
28   should_enforce_ssl_for(:get, :new)
29   should_enforce_ssl_for(:get, :search_clones)
30   should_enforce_ssl_for(:get, :show)
31   should_enforce_ssl_for(:post, :create)
32   should_enforce_ssl_for(:put, :update)
33   
34   def setup
35     @project = projects(:johans)
36     @repo = repositories(:johans)
37     @grit = Grit::Repo.new(grit_test_repo("dot_git"), :is_bare => true)
38     Repository.any_instance.stubs(:git).returns(@grit)
39   end
40
41   should_render_in_site_specific_context :except => [:writable_by, :viewable_by, :config]
42
43   context "Routing, by projects" do
44     should "recognizes routing like /projectname/reponame" do
45       assert_recognizes({
46         :controller => "repositories",
47         :action => "show",
48         :project_id => @project.to_param,
49         :id => @repo.to_param,
50       }, {:path => "/#{@project.to_param}/#{@repo.to_param}", :method => :get})
51       assert_recognizes({
52         :controller => "merge_requests",
53         :action => "index",
54         :project_id => @project.to_param,
55         :repository_id => @repo.to_param,
56       }, {:path => "/#{@project.to_param}/#{@repo.to_param}/merge_requests", :method => :get})
57       assert_generates("/#{@project.to_param}/#{@repo.to_param}", {
58         :controller => "repositories",
59         :action => "show",
60         :project_id => @project.to_param,
61         :id => @repo.to_param,
62       })
63
64       assert_generates("/#{@project.to_param}/#{@repo.to_param}/trees", {
65         :controller => "trees",
66         :action => "index",
67         :project_id => @project.to_param,
68         :repository_id => @repo.to_param,
69       })
70
71       assert_generates("/#{@project.to_param}/#{@repo.to_param}/trees/foo/bar/baz", {
72         :controller => "trees",
73         :action => "show",
74         :project_id => @project.to_param,
75         :repository_id => @repo.to_param,
76         :branch_and_path => %w[foo bar baz]
77       })
78     end
79
80     should "recognizes routing like /projectname/repositories" do
81       assert_recognizes({
82         :controller => "repositories",
83         :action => "index",
84         :project_id => @project.to_param
85       }, "/#{@project.to_param}/repositories")
86
87       assert_recognizes({
88         :controller => "repositories",
89         :action => "index",
90         :project_id => @project.to_param
91       }, "/#{@project.to_param}/repositories/")
92       assert_generates("/#{@project.to_param}/repositories", {
93         :controller => "repositories",
94         :action => "index",
95         :project_id => @project.to_param
96       })
97     end
98
99     should "recognize routing like /projectname/starts-with-reserved-name" do
100       assert_recognizes({
101         :controller => "repositories",
102         :action => "show",
103         :project_id => "myproject",
104         :id => "users-test-repo",
105       }, "/myproject/users-test-repo")
106
107       assert_generates("/myproject/users-test-repo", {
108         :controller => "repositories",
109         :action => "show",
110         :project_id => "myproject",
111         :id => "users-test-repo",
112       })
113     end
114
115     should "recognizes routing like /projectname/reponame, with a non-html format" do
116       assert_recognizes({
117         :controller => "repositories",
118         :action => "show",
119         :project_id => @project.to_param,
120         :format => "xml",
121         :id => @repo.to_param,
122       }, "/#{@project.to_param}/#{@repo.to_param}.xml")
123       assert_recognizes({
124         :controller => "merge_requests",
125         :action => "index",
126         :format => "xml",
127         :project_id => @project.to_param,
128         :repository_id => @repo.to_param,
129       }, "/#{@project.to_param}/#{@repo.to_param}/merge_requests.xml")
130
131       assert_generates("/#{@project.to_param}/#{@repo.to_param}.xml", {
132         :controller => "repositories",
133         :action => "show",
134         :project_id => @project.to_param,
135         :id => @repo.to_param,
136         :format => "xml",
137       })
138       assert_generates("/#{@project.to_param}/#{@repo.to_param}/merge_requests", {
139         :controller => "merge_requests",
140         :action => "index",
141         :project_id => @project.to_param,
142         :repository_id => @repo.to_param,
143       })
144     end
145
146     should "recognizes routing like /projectname/repositories, with a non-html format" do
147       assert_recognizes({
148         :controller => "repositories",
149         :action => "index",
150         :format => "xml",
151         :project_id => @project.to_param
152       }, "/#{@project.to_param}/repositories.xml")
153
154       assert_generates("/#{@project.to_param}/repositories.xml", {
155         :controller => "repositories",
156         :action => "index",
157         :project_id => @project.to_param,
158         :format => "xml",
159       })
160     end
161
162     should "recognize routing for clones search" do
163       assert_recognizes({
164           :controller => "repositories",
165           :action => "search_clones",
166           :format => "json",
167           :project_id => @project.to_param,
168           :id => @repo.to_param
169         }, "/projects/#{@project.to_param}/repositories/#{@repo.to_param}/search_clones.json")
170
171       assert_generates("/#{@project.to_param}/#{@repo.to_param}/search_clones.json", {
172           :controller => "repositories",
173           :action => "search_clones",
174           :project_id => @project.to_param,
175           :id => @repo.to_param,
176           :format => "json"
177         })
178     end
179   end
180
181   context "Routing, by users" do
182     should "recognizes routing like /~username/repositories" do
183       user = users(:johan)
184       assert_recognizes({
185         :controller => "repositories",
186         :action => "index",
187         :user_id => user.to_param
188       }, "/~#{user.to_param}/repositories")
189
190       assert_generates("/~#{user.to_param}/repositories", {
191         :controller => "repositories",
192         :action => "index",
193         :user_id => user.to_param,
194       })
195     end
196
197     should "recognizes routing like /~username/repositories, with a non-html format" do
198       user = users(:johan)
199       assert_recognizes({
200         :controller => "repositories",
201         :action => "index",
202         :format => "xml",
203         :user_id => user.to_param
204       }, "/~#{user.to_param}/repositories.xml")
205
206       assert_generates("/~#{user.to_param}/repositories.xml", {
207         :controller => "repositories",
208         :action => "index",
209         :user_id => user.to_param,
210         :format => "xml",
211       })
212     end
213
214     should "recognize routing like /~user/reponame" do
215       user = users(:johan)
216       assert_recognizes({
217         :controller => "repositories",
218         :action => "show",
219         :user_id => user.to_param,
220         :id => @repo.to_param,
221       }, "/~#{user.to_param}/#{@repo.to_param}")
222
223       assert_generates("/~#{user.to_param}/#{@repo.to_param}", {
224         :controller => "repositories",
225         :action => "show",
226         :user_id => user.to_param,
227         :id => @repo.to_param,
228       })
229     end
230
231     should "recognize routing like /~user/reponame/action" do
232       user = users(:johan)
233       assert_recognizes({
234         :controller => "repositories",
235         :action => "edit",
236         :user_id => user.to_param,
237         :id => @repo.to_param,
238       }, "/~#{user.to_param}/#{@repo.to_param}/edit")
239
240       assert_generates("/~#{user.to_param}/#{@repo.to_param}/edit", {
241         :controller => "repositories",
242         :action => "edit",
243         :user_id => user.to_param,
244         :id => @repo.to_param,
245       })
246     end
247
248     should "recognize routing like /~user/projectname/reponame" do
249       user = users(:johan)
250       assert_recognizes({
251         :controller => "repositories",
252         :action => "show",
253         :project_id => @project.to_param,
254         :user_id => user.to_param,
255         :id => @repo.to_param,
256       }, "/~#{user.to_param}/#{@project.to_param}/#{@repo.to_param}")
257
258       assert_generates("/~#{user.to_param}/#{@project.to_param}/#{@repo.to_param}", {
259         :controller => "repositories",
260         :action => "show",
261         :project_id => @project.to_param,
262         :user_id => user.to_param,
263         :id => @repo.to_param,
264       })
265     end
266
267     should "recognize routing like /~user/projectname/reponame/action" do
268       user = users(:johan)
269       assert_recognizes({
270         :controller => "repositories",
271         :action => "clone",
272         :project_id => @project.to_param,
273         :user_id => user.to_param,
274         :id => @repo.to_param,
275       }, "/~#{user.to_param}/#{@project.to_param}/#{@repo.to_param}/clone")
276
277       assert_generates("/~#{user.to_param}/#{@project.to_param}/#{@repo.to_param}/clone", {
278         :controller => "repositories",
279         :action => "clone",
280         :project_id => @project.to_param,
281         :user_id => user.to_param,
282         :id => @repo.to_param,
283       })
284     end
285
286     context "usernames, with a dot" do
287       should "recognize routing like /~user.name/myproject/myrepo" do
288         assert_recognizes({
289           :controller => "repositories",
290           :action => "show",
291           :project_id => "myproject",
292           :user_id => "user.name",
293           :id => "myrepo",
294         }, "/~user.name/myproject/myrepo")
295
296         assert_generates("/~user.name/myproject/myrepo", {
297           :controller => "repositories",
298           :action => "show",
299           :project_id => "myproject",
300           :user_id => "user.name",
301           :id => "myrepo",
302         })
303       end
304
305       should "recognize routing like /~user.name/myproject/myrepo/action" do
306         user = users(:johan)
307         assert_recognizes({
308           :controller => "repositories",
309           :action => "clone",
310           :project_id => "myproject",
311           :user_id => "user.name",
312           :id => "myrepo",
313         }, "/~user.name/myproject/myrepo/clone")
314
315         assert_generates("/~user.name/myproject/myrepo/clone", {
316           :controller => "repositories",
317           :action => "clone",
318           :project_id => "myproject",
319           :user_id => "user.name",
320           :id => "myrepo",
321         })
322       end
323     end
324   end
325
326   context "Routing, by teams" do
327     should "recognizes routing like /+teamname/repositories" do
328       team = groups(:team_thunderbird)
329       assert_recognizes({
330         :controller => "repositories",
331         :action => "index",
332         :group_id => team.to_param
333       }, "/+#{team.to_param}/repositories")
334
335       assert_generates("/+#{team.to_param}/repositories", {
336         :controller => "repositories",
337         :action => "index",
338         :group_id => team.to_param,
339       })
340     end
341
342     should "recognizes routing like /+teamname/repo" do
343       team = groups(:team_thunderbird)
344       repo = team.repositories.first
345       assert_recognizes({
346         :controller => "repositories",
347         :action => "show",
348         :group_id => team.to_param,
349         :id => repo.to_param
350       }, "/+#{team.to_param}/#{repo.to_param}")
351
352       assert_generates("/+#{team.to_param}/#{repo.to_param}", {
353         :controller => "repositories",
354         :action => "show",
355         :group_id => team.to_param,
356         :id => repo.to_param
357       })
358     end
359
360     should "recognizes routing like /+teamname/repo/action" do
361       team = groups(:team_thunderbird)
362       repo = team.repositories.first
363       assert_recognizes({
364         :controller => "repositories",
365         :action => "clone",
366         :group_id => team.to_param,
367         :id => repo.to_param
368       }, "/+#{team.to_param}/#{repo.to_param}/clone")
369
370       assert_generates("/+#{team.to_param}/#{repo.to_param}/clone", {
371         :controller => "repositories",
372         :action => "clone",
373         :group_id => team.to_param,
374         :id => repo.to_param
375       })
376     end
377
378     should "recognizes routing like /+teamname/repositories, with a non-html format" do
379       team = groups(:team_thunderbird)
380       assert_recognizes({
381         :controller => "repositories",
382         :action => "index",
383         :format => "xml",
384         :group_id => team.to_param
385       }, "/+#{team.to_param}/repositories.xml")
386       assert_generates("/+#{team.to_param}/repositories.xml", {
387         :controller => "repositories",
388         :action => "index",
389         :group_id => team.to_param,
390         :format => "xml",
391       })
392     end
393   end
394
395   context "#index" do
396     setup do
397       @project = projects(:johans)
398     end
399
400     should "gets all the projects repositories" do
401       get :index, :project_id => @project.slug
402       assert_response :success
403       assert_equal @project.repositories, assigns(:repositories)
404     end
405
406     should 'render xml if requested' do
407       get :index, :project_id => @project.slug, :format => 'xml'
408       assert_response :success
409     end
410   end
411
412   context "Searching" do
413     setup do
414       @project = projects(:johans)
415     end
416
417     should "render repositories matching a search term" do
418       get :index, :project_id => @project.to_param, :filter => "clone", :format => "json"
419       assert_response :success
420       assert_equal([repositories(:johans2)], assigns(:repositories))
421     end
422   end
423
424   context "showing a user namespaced repo" do
425     setup do
426       @user = users(:johan)
427       @project = projects(:johans)
428     end
429
430     should "GET users/johan/repositories/foo is successful" do
431       repo = @user.repositories.first
432       repo.stubs(:git).returns(stub_everything("git mock"))
433       get :show, :user_id => @user.to_param, :project_id => repo.project.to_param,
434         :id => repo.to_param
435       assert_response :success
436       assert_equal @user, assigns(:owner)
437     end
438
439     should "set the correct atom feed discovery url" do
440       repo = @user.repositories.first
441       repo.kind = Repository::KIND_USER_REPO
442       repo.owner = @user
443       repo.save!
444       repo.stubs(:git).returns(stub_everything("git mock"))
445       get :show, :user_id => @user.to_param, :project_id => repo.project.to_param,
446         :id => repo.to_param
447       assert_response :success
448       atom_url = user_project_repository_path(@user, repo.project, repo, :format => :atom)
449       assert_equal atom_url, assigns(:atom_auto_discovery_url)
450     end
451
452     should "find the correct owner for clone, if the project is owned by someone else" do
453       clone_repo = @project.repositories.clones.first
454       clone_repo.owner = users(:moe)
455       clone_repo.save!
456       clone_repo.stubs(:git).returns(stub_everything("git mock"))
457
458       get :show, :user_id => users(:moe).to_param,
459         :project_id => clone_repo.project.to_param, :id => clone_repo.to_param
460       assert_response :success
461       assert_equal clone_repo, assigns(:repository)
462       assert_equal users(:moe), assigns(:owner)
463     end
464
465     should "find the correct repository, even if the repo is named similar to another one in another project" do
466       repo_clone = Repository.new_by_cloning(repositories(:moes), users(:johan).login)
467       repo_clone.owner = users(:johan)
468       repo_clone.user = users(:johan)
469       repo_clone.name = "johansprojectrepos"
470       repo_clone.save!
471
472       get :show, :user_id => users(:johan).to_param,
473         :project_id => projects(:moes).to_param, :id => repo_clone.to_param
474       assert_response :success
475       assert_equal users(:johan), assigns(:owner)
476       assert_equal repo_clone, assigns(:repository)
477     end
478
479     should "find the project repository" do
480       get :show, :project_id => repositories(:johans).project.to_param,
481         :id => repositories(:johans).to_param
482       assert_response :success
483       assert_equal repositories(:johans).project, assigns(:owner)
484       assert_equal repositories(:johans), assigns(:repository)
485     end
486   end
487
488   context "showing a team namespaced repo" do
489     setup do
490       @group = groups(:team_thunderbird)
491     end
492
493     should "GET teams/foo/repositories/bar is successful" do
494       repo = @group.repositories.first
495       repo.stubs(:git).returns(stub_everything("git mock"))
496       get :show, :project_id => repo.project.to_param,
497         :group_id => @group.to_param, :id => repo.to_param
498       assert_response :success
499       assert_equal @group, assigns(:owner)
500     end
501   end
502
503   def do_show_get(repos)
504     get :show, :project_id => @project.slug, :id => repos.name
505   end
506
507   context "#show" do
508     setup do
509       @project = projects(:johans)
510       @repo = @project.repositories.mainlines.first
511     end
512
513     should "GET projects/1/repositories/1 is successful" do
514       @repo.stubs(:git).returns(stub_everything("git mock"))
515       do_show_get @repo
516       assert_response :success
517     end
518
519     should "scopes GET :show to the project_id" do
520       repo = repositories(:moes)
521       repo.stubs(:git).returns(stub_everything("git mock"))
522       do_show_get repo
523       assert_response 404
524     end
525
526     should "issues a Refresh header if repo is not ready yet" do
527       @repo.stubs(:ready).returns(false)
528       do_show_get @repo
529       assert_response :success
530       assert_not_nil @response.headers['Refresh']
531     end
532   end
533
534   context "#show as XML" do
535
536     setup do
537       @project = projects(:johans)
538     end
539
540     should "GET projects/1/repositories/1.xml is successful" do
541       repo = @project.repositories.mainlines.first
542       repo.stubs(:has_commits?).returns(false)
543       repo.stubs(:git).returns(stub_everything("git mock"))
544       get :show, :project_id => @project.to_param, :id => repo.to_param, :format => "xml"
545       assert_response :success
546       assert_equal repo.to_xml, @response.body
547     end
548   end
549
550   def do_clone_get()
551     get :clone, :project_id => @project.slug, :id => @repository.name
552   end
553
554   context "#clone" do
555     setup do
556       login_as :johan
557       @project = projects(:johans)
558       @repository = @project.repositories.mainlines.first
559     end
560
561     should " require login" do
562       session[:user_id] = nil
563       do_clone_get
564       assert_redirected_to(new_sessions_path)
565     end
566
567     should "GET projects/1/repositories/3/clone is successful" do
568       Project.expects(:find_by_slug!).with(@project.slug).returns(@project)
569       @repository.stubs(:has_commits?).returns(true)
570       @project.repositories.expects(:find_by_name_in_project!).with(@repository.name, nil).returns(@repository)
571       do_clone_get
572       assert_equal nil, flash[:error]
573       assert_response :success
574       assert_equal @repository, assigns(:repository_to_clone)
575       assert_instance_of Repository, assigns(:repository)
576       assert_equal "johans-johansprojectrepos", assigns(:repository).name
577     end
578
579     should "redirects to new_account_key_path if no keys on user" do
580       users(:johan).ssh_keys.destroy_all
581       login_as :johan
582       do_clone_get
583       assert_redirected_to(new_user_key_path(users(:johan)))
584     end
585
586     should "redirects with a flash if repos cannot be cloned" do
587       login_as :johan
588       Project.expects(:find_by_slug!).with(@project.slug).returns(@project)
589       @repository.stubs(:has_commits?).returns(false)
590       @project.repositories.expects(:find_by_name_in_project!).with(@repository.name, nil).returns(@repository)
591       do_clone_get
592       assert_redirected_to(project_repository_path(@project, @repository))
593       assert_match(/cannot clone an empty/i, flash[:error])
594     end
595   end
596
597   def do_create_clone_post(opts={})
598     post(:create_clone, :project_id => @project.slug, :id => @repository.name,
599       :repository => {:owner_type => "User"}.merge(opts))
600   end
601
602   context "#create_clone" do
603     setup do
604       login_as :johan
605       @project = projects(:johans)
606       @repository = @project.repositories.mainlines.first
607     end
608
609     should " require login" do
610       session[:user_id] = nil
611       do_create_clone_post
612       assert_redirected_to(new_sessions_path)
613     end
614
615     should "post projects/1/repositories/3/create_clone is successful" do
616       Project.expects(:find_by_slug!).with(@project.slug).returns(@project)
617       @repository.stubs(:has_commits?).returns(true)
618       @project.repositories.expects(:find_by_name_in_project!).with(@repository.name, nil).returns(@repository)
619       do_create_clone_post(:name => "foo-clone")
620       assert_response :redirect
621     end
622
623     should "post projects/1/repositories/3/create_clone is successful sets the owner to the user" do
624       Project.expects(:find_by_slug!).with(@project.slug).returns(@project)
625       @repository.stubs(:has_commits?).returns(true)
626       @project.repositories.expects(:find_by_name_in_project!).with(@repository.name, nil).returns(@repository)
627       do_create_clone_post(:name => "foo-clone", :owner_type => "User")
628       assert_response :redirect
629       assert_equal users(:johan), assigns(:repository).owner
630       assert_equal Repository::KIND_USER_REPO, assigns(:repository).kind
631     end
632
633     should "post projects/1/repositories/3/create_clone is successful sets the owner to the group" do
634       groups(:team_thunderbird).add_member(users(:johan), Role.admin)
635       Project.expects(:find_by_slug!).with(@project.slug).returns(@project)
636       @repository.stubs(:has_commits?).returns(true)
637       @project.repositories.expects(:find_by_name_in_project!).with(@repository.name, nil).returns(@repository)
638       do_create_clone_post(:name => "foo-clone", :owner_type => "Group", :owner_id => groups(:team_thunderbird).id)
639       assert_response :redirect
640       assert_equal groups(:team_thunderbird), assigns(:repository).owner
641       assert_equal Repository::KIND_TEAM_REPO, assigns(:repository).kind
642     end
643
644     should "redirects to new_user_key_path if no keys on user" do
645       users(:johan).ssh_keys.destroy_all
646       login_as :johan
647       do_create_clone_post
648       assert_redirected_to(new_user_key_path(users(:johan)))
649     end
650
651     should "redirects with a flash if repos cannot be cloned" do
652       login_as :johan
653       Project.expects(:find_by_slug!).with(@project.slug).returns(@project)
654       @repository.stubs(:has_commits?).returns(false)
655       @project.repositories.expects(:find_by_name_in_project!).with(@repository.name, nil).returns(@repository)
656       do_create_clone_post(:name => "foobar")
657       assert_redirected_to(project_repository_path(@project, @repository))
658       assert_match(/cannot clone an empty/i, flash[:error])
659     end
660   end
661
662   context "#create_clone as XML" do
663
664     setup do
665       authorize_as :johan
666       @project = projects(:johans)
667       @repository = @project.repositories.mainlines.first
668       @request.env["HTTP_ACCEPT"] = "application/xml"
669     end
670
671     should " require login" do
672       authorize_as(nil)
673       do_create_clone_post(:name => "foo")
674       assert_response 401
675     end
676
677     should "post projects/1/repositories/3/create_copy is successful" do
678       Project.expects(:find_by_slug!).with(@project.slug).returns(@project)
679       @repository.stubs(:has_commits?).returns(true)
680       @project.repositories.expects(:find_by_name_in_project!).with(@repository.name, nil).returns(@repository)
681       do_create_clone_post(:name => "foo-clone")
682       assert_response 201
683     end
684
685     should "renders text if repos cannot be cloned" do
686       Project.expects(:find_by_slug!).with(@project.slug).returns(@project)
687       @repository.stubs(:has_commits?).returns(false)
688       @project.repositories.expects(:find_by_name_in_project!).with(@repository.name, nil).returns(@repository)
689       do_create_clone_post(:name => "foobar")
690       assert_response 422
691       assert_match(/cannot clone an empty/i, @response.body)
692     end
693   end
694
695   def do_writable_by_get(options={})
696     post(:writable_by, {:project_id => @project.slug, :id => @repository.name,
697       :username => "johan"}.merge(options))
698   end
699
700   context "#writable_by" do
701     setup do
702       login_as :johan
703       @project = projects(:johans)
704       @repository = @project.repositories.mainlines.first
705     end
706
707     should " not require login" do
708       session[:user_id] = nil
709       do_writable_by_get :username => "johan"
710       assert_response :success
711     end
712
713     should "get projects/1/repositories/3/writable_by?username=johan is true" do
714       do_writable_by_get :username => "johan"
715       assert_response :success
716       assert_equal "true", @response.body
717     end
718
719     should "get projects/1/repositories/2/writable_by?username=johan is false" do
720       do_writable_by_get :username => "johan", :project_id => projects(:moes).slug,
721         :id => projects(:moes).repositories.first.name
722       assert_response :success
723       assert_equal "false", @response.body
724     end
725
726     should "get projects/1/repositories/2/writable_by?username=nonexistinguser is false" do
727       do_writable_by_get :username => "nonexistinguser"
728       assert_response :success
729       assert_equal "false", @response.body
730     end
731
732     should "finds the repository in the whole project realm, if the (url) root is a project" do
733       # in case someone changes a mainline to be owned by a group
734       assert_equal @project, repositories(:johans2).project
735       do_writable_by_get :id => repositories(:johans2).to_param
736       assert_response :success
737       assert_equal @project, assigns(:project)
738       assert_equal repositories(:johans2), assigns(:repository)
739     end
740
741     should "scope to the correc project" do
742       repo_clone = Repository.new_by_cloning(repositories(:moes), users(:johan).login)
743       repo_clone.owner = users(:johan)
744       repo_clone.user = users(:johan)
745       repo_clone.name = "johansprojectrepos"
746       repo_clone.save!
747
748       do_writable_by_get({
749         :user_id => users(:johan).to_param,
750         :project_id => projects(:moes).to_param,
751         :id => repo_clone.to_param,
752       })
753       assert_response :success
754       assert_nil assigns(:project)
755       assert_equal repo_clone.project, assigns(:containing_project)
756       assert_equal repo_clone, assigns(:repository)
757     end
758
759     should "not require any particular subdomain (if Project belongs_to a site)" do
760       project = projects(:johans)
761       assert_not_nil project.site
762       do_writable_by_get :project_id => project.to_param,
763         :id => project.repositories.mainlines.first.to_param
764       assert_response :success
765     end
766
767     should 'not identify a non-merge request git path as a merge request' do
768       do_writable_by_get({
769         :git_path => "refs/heads/master"})
770       assert_response :success
771       assert_equal 'true', @response.body
772     end
773
774     should 'identify that a merge request is being pushed to' do
775       @merge_request = merge_requests(:mikes_to_johans)
776       assert !@merge_request.user.can_write_to?(@merge_request.target_repository)
777       do_writable_by_get({
778         :username => @merge_request.user.to_param,
779         :project_id => @merge_request.target_repository.project.to_param,
780         :id => @merge_request.target_repository.to_param,
781         :git_path => "refs/merge-requests/#{@merge_request.to_param}"})
782       assert_response :success
783       assert_equal 'true', @response.body
784     end
785
786     should 'not allow other users than the owner of a merge request push to a merge request' do
787       @merge_request = merge_requests(:mikes_to_johans)
788       do_writable_by_get({
789         :username => 'johan',
790         :project_id => @merge_request.target_repository.project.to_param,
791         :id => @merge_request.target_repository.to_param,
792         :git_path => "refs/merge-requests/#{@merge_request.to_param}"})
793       assert_response :success
794       assert_equal 'false', @response.body
795     end
796
797     should 'not allow pushes to non-existing merge requests' do
798       @merge_request = merge_requests(:mikes_to_johans)
799       do_writable_by_get({
800         :username => 'johan',
801         :project_id => @merge_request.target_repository.project.to_param,
802         :id => @merge_request.target_repository.to_param,
803         :git_path => "refs/merge-requests/42"})
804       assert_response :success
805       assert_equal 'false', @response.body
806     end
807
808
809     should "allow pushing to wiki repositories" do
810       project = projects(:johans)
811       wiki = project.wiki_repository
812       user = users(:johan)
813       do_writable_by_get(:id => wiki.to_param)
814       assert_response :success
815     end
816   end
817
818   def do_config_get(options={})
819     get(:config, {:project_id => @project.slug, :id => @repository.name}.merge(options))
820   end
821
822   context "#config" do
823     setup do
824       login_as :johan
825       @project = projects(:johans)
826       @repository = @project.repositories.mainlines.first
827     end
828
829     should "not require login" do
830       session[:user_id] = nil
831       do_config_get
832       assert_response :success
833     end
834
835     should "get projects/1/repositories/3/config is true" do
836       do_config_get
837       assert_response :success
838       exp = "real_path:#{@repository.real_gitdir}\nforce_pushing_denied:false"
839       assert_equal exp, @response.body
840     end
841
842     should "expose the wiki repository" do
843       wiki = @project.wiki_repository
844       assert_not_nil wiki
845       do_config_get(:id => wiki.to_param)
846       expected = "real_path:#{wiki.real_gitdir}\nforce_pushing_denied:false"
847       assert_equal expected, @response.body
848     end
849
850     should "not use a session cookie" do
851       do_config_get
852
853       assert_equal [], @response.headers["Set-Cookie"]
854     end
855
856     should "send cache friendly headers" do
857       do_config_get
858
859       assert_equal "public, max-age=600", @response.headers["Cache-Control"]
860     end
861   end
862
863   def do_delete(repos)
864     delete :destroy, :project_id => @project.slug, :id => repos.name
865   end
866
867   context "#destroy" do
868     setup do
869       @project = projects(:johans)
870       @repo = @project.repositories.first
871       assert @repo.admin?(users(:johan))
872       login_as :johan
873     end
874
875     should "require login" do
876       session[:user_id] = nil
877       do_delete(@repo)
878       assert_redirected_to(new_sessions_path)
879     end
880
881     should "can only be deleted by the admins" do
882       login_as :mike
883       assert !@repo.admin?(users(:mike));
884       do_delete(@repo)
885       assert_redirected_to([@project, @repo])
886       assert_match(/only repository admins are allowed/i, flash[:error])
887     end
888
889     should "the owner can delete his own repos" do
890       repo = repositories(:johans2)
891       repo.user = users(:johan)
892       repo.save!
893       repo.committerships.create_with_permissions!({
894           :committer => users(:johan)
895         }, (Committership::CAN_ADMIN | Committership::CAN_COMMIT))
896       assert repo.reload.admin?(users(:johan))
897       delete :destroy, :project_id => repo.project.to_param,
898         :group_id => repo.owner.to_param, :id => repo.to_param
899       assert_equal nil, flash[:error]
900       assert_equal "The repository was deleted", flash[:notice]
901       assert_redirected_to(group_path(repo.owner))
902     end
903
904     should "destroying a project creates an event in the project" do
905       Repository.any_instance.expects(:can_be_deleted_by?).returns(true)
906       assert_difference("@project.events.count") do
907         do_delete(@repo)
908         assert_response :redirect
909         assert_nil flash[:error]
910       end
911     end
912
913     should "work for user/group clones" do
914       repo = repositories(:johans2)
915       repo.user = users(:mike)
916       repo.committerships.create_with_permissions!({
917           :committer => users(:mike)
918         }, (Committership::CAN_ADMIN | Committership::CAN_COMMIT))
919       repo.save!
920       login_as :mike
921       get :confirm_delete, :group_id => repo.owner.to_param,
922         :project_id => repo.project.to_param, :id => repo.to_param
923       assert_response :success
924       assert_template "confirm_delete"
925     end
926   end
927
928   context "new / create" do
929     setup do
930       @project = projects(:johans)
931       @user = users(:johan)
932       @group = groups(:team_thunderbird)
933       @group.add_member(@user, Role.admin)
934       login_as :johan
935     end
936
937     should " require login" do
938       login_as nil
939       get :new, :project_id => @project.to_param
940       assert_redirected_to(new_sessions_path)
941     end
942
943     should "require adminship" do
944       login_as :moe
945       get :new, :project_id => @project.to_param
946       assert_match(/only repository admins are allowed/, flash[:error])
947       assert_redirected_to(project_path(@project))
948
949       post :create, :project_id => @project.to_param, :repository => {}
950       assert_match(/only repository admins are allowed/, flash[:error])
951       assert_redirected_to(project_path(@project))
952     end
953
954     should "only be allowed to add new repositories to Project" do
955       get :new, :project_id => @project.to_param, :group_id => @group.to_param
956       assert_match(/can only add new repositories directly to a project/, flash[:error])
957       assert_redirected_to(group_path(@group))
958
959       get :new, :project_id => @project.to_param, :user_id => @user.to_param
960       assert_match(/can only add new repositories directly to a project/, flash[:error])
961       assert_redirected_to(user_path(@user))
962
963       post :create, :project_id => @project.to_param, :group_id => @group.to_param, :repository => {}
964       assert_match(/can only add new repositories directly to a project/, flash[:error])
965       assert_redirected_to(group_path(@group))
966
967       post :create, :project_id => @project.to_param, :user_id => @user.to_param, :repository => {}
968       assert_match(/can only add new repositories directly to a project/, flash[:error])
969       assert_redirected_to(user_path(@user))
970     end
971
972     # See the above example ("should only be allowed to add new repositories to Project")
973     # for why this is commented out
974     #
975     # it "should GET new successfully, and set the owner to a user" do
976     #   get :new, :user_id => @user.to_param
977     #   assert_response :success
978     #   assert_equal @user, #   assigns(:owner)
979     # end
980     #
981     # it "should GET new successfully, and set the owner to a group" do
982     #   get :new, :group_id => @group.to_param
983     #   assert_response :success
984     #   assert_equal @group, #   assigns(:owner)
985     # end
986     #
987     # it "creates a new repository belonging to a user" do
988     #   proc {
989     #     post :create, :user_id => @user.to_param, :repository => {:name => "my-new-repo"}
990     #   }.should change(Repository, :count)
991     #   assert_equal @user, #   assigns(:repository).owner
992     #  assert_response :redirect
993     #  assert_redirected_to(user_repository_path(@user, assigns(:repository)))
994     # end
995     #
996     # it "creates a new repository belonging to a group" do
997     #   proc {
998     #     post :create, :group_id => @group.to_param, :repository => {:name => "my-new-repo"}
999     #   }.should change(Repository, :count)
1000     #   assert_equal @group, #   assigns(:repository).owner
1001     #   assert_response :redirect
1002     #   assert_redirected_to(group_repository_path(@group, assigns(:repository)))
1003     # end
1004
1005     should " GET new successfully, and set the owner to a project" do
1006       get :new, :project_id => @project.to_param
1007       assert_response :success
1008       assert_equal @project, assigns(:owner)
1009     end
1010
1011     should "creates a new repository belonging to a Project" do
1012       assert_difference("Repository.count") do
1013         post :create, :project_id => @project.to_param, :repository => {:name => "my-new-repo"}
1014       end
1015       assert_equal @project.owner, assigns(:repository).owner
1016       assert_equal Repository::KIND_PROJECT_REPO, assigns(:repository).kind
1017       assert_response :redirect
1018       assert_redirected_to(project_repository_path(@project, assigns(:repository)))
1019     end
1020
1021     should "respect the creator's choice of merge requests or not" do
1022       post :create, :project_id => @project.to_param, :repository => {
1023         :name => "mine"
1024       }
1025       assert_not_nil repo = assigns(:repository)
1026       assert !repo.merge_requests_enabled?
1027       post :create, :project_id => @project.to_param, :repository => {
1028         :name => "mine",
1029         :merge_requests_enabled => "1"
1030       }
1031       assert_not_nil repo = assigns(:repository)
1032       assert repo.merge_requests_enabled?
1033     end
1034   end
1035
1036   context "edit / update" do
1037     setup do
1038       @project = projects(:johans)
1039       @repository = @project.repositories.mainlines.first
1040       login_as :johan
1041     end
1042
1043     should "requires login" do
1044       login_as nil
1045       get :edit, :project_id => @project.to_param, :id => @repository.to_param
1046       assert_redirected_to(new_sessions_path)
1047
1048       put :update, :project_id => @project.to_param, :id => @repository.to_param
1049       assert_redirected_to(new_sessions_path)
1050     end
1051
1052     should "requires adminship on the project if owner is a project" do
1053       login_as :moe
1054       get :edit, :project_id => @project.to_param, :id => @repository.to_param
1055       assert_match(/only repository admins are allowed/, flash[:error])
1056       assert_response :redirect
1057     end
1058
1059     should "requires adminship on the user if owner is a user" do
1060       login_as :moe
1061       @repository.owner = users(:moe)
1062       @repository.kind = Repository::KIND_USER_REPO
1063       @repository.committerships.create_with_permissions!({
1064           :committer => users(:moe)
1065         }, Committership::CAN_ADMIN)
1066       @repository.save!
1067       get :edit, :project_id => @repository.project.to_param,
1068         :user_id => users(:moe).to_param, :id => @repository.to_param
1069       assert_response :success
1070     end
1071
1072     should "requires adminship on the repo" do
1073       login_as :mike
1074       @repository.committerships.create_with_permissions!({
1075           :committer => groups(:team_thunderbird)
1076         }, Committership::CAN_ADMIN)
1077       @repository.kind = Repository::KIND_TEAM_REPO
1078       @repository.owner = groups(:team_thunderbird)
1079       @repository.save!
1080       assert @repository.admin?(users(:mike))
1081       get :edit, :project_id => @repository.project.to_param,
1082         :group_id => groups(:team_thunderbird).to_param, :id => @repository.to_param
1083       assert_response :success
1084     end
1085
1086     should "GETs edit/n successfully" do
1087       get :edit, :project_id => @project.to_param, :id => @repository.to_param
1088       assert_response :success
1089       assert_equal @repository, assigns(:repository)
1090       assert_equal @grit.heads, assigns(:heads)
1091     end
1092
1093     should "PUT update successfully and creates an event when changing the description" do
1094       assert_incremented_by(@repository.events, :size, 1) do
1095         put :update, :project_id => @project.to_param, :id => @repository.to_param,
1096           :repository => {:description => "blablabla"}
1097         @repository.events.reload
1098       end
1099       assert_redirected_to(project_repository_path(@project, @repository))
1100       assert_equal "blablabla", @repository.reload.description
1101     end
1102
1103     should "be able to remove the repository description" do
1104       @repository.update_attribute(:description, "blabla bla")
1105       put :update, :project_id => @project.to_param, :id => @repository.to_param,
1106         :repository => {:description => ""}
1107       assert @repository.reload.description.blank?,
1108         "descr: #{@repository.description.inspect}"
1109     end
1110
1111     should 'update the repository name and create an event if a new name is provided' do
1112       description = @repository.description
1113       assert_incremented_by(@repository.events, :size, 1) do
1114         put :update, :project_id => @project.to_param, :id => @repository.to_param,
1115           :repository => {:name => 'new_name'}
1116         @repository.events.reload
1117         @repository.reload
1118         assert_redirected_to project_repository_path(@project, @repository)
1119       end
1120       assert_equal 'new_name', @repository.name
1121       assert_equal description, @repository.description
1122     end
1123
1124
1125     should 'not create an event on update if the description is not changed' do
1126       assert_no_difference("@repository.events.size") do
1127         put :update, :project_id => @project.to_param, :id => @repository.to_param,
1128           :repository => {:description => @repository.description}
1129         @repository.events.reload
1130       end
1131     end
1132
1133     should "gets a list of the users' groups on edit" do
1134       groups(:team_thunderbird).add_member(users(:johan), Role.admin)
1135       get :edit, :project_id => @project.to_param, :id => @repository.to_param
1136       assert_response :success
1137       assert_equal users(:johan).groups, assigns(:groups)
1138     end
1139
1140     should "gets a list of the users' groups on update" do
1141       groups(:team_thunderbird).add_member(users(:johan), Role.admin)
1142       put :update, :project_id => @project.to_param, :id => @repository.to_param,
1143             :repository => {:description => "foo"}
1144       assert_equal users(:johan).groups, assigns(:groups)
1145     end
1146
1147     should "changes the owner" do
1148       group = groups(:team_thunderbird)
1149       group.add_member(users(:johan), Role.admin)
1150       put :update, :project_id => @project.to_param, :id => @repository.to_param,
1151       :repository => { :owner_id => group.id}
1152       assert_redirected_to(project_repository_path(@repository.project, @repository))
1153       assert_equal group, @repository.reload.owner
1154     end
1155
1156     should "changes the owner, only if the original owner was a user" do
1157       group = groups(:team_thunderbird)
1158       group.add_member(users(:johan), Role.admin)
1159       @repository.owner = group
1160       @repository.kind = Repository::KIND_TEAM_REPO
1161       @repository.save!
1162       new_group = Group.create!(:name => "temp")
1163       new_group.add_member(users(:johan), Role.admin)
1164
1165       put :update, :project_id => @repository.project.to_param,
1166         :group_id => group.to_param, :id => @repository.to_param, :repository => {
1167           :owner_id => new_group.id
1168         }
1169       assert_response :redirect
1170       assert_redirected_to(group_repository_path(group, @repository))
1171       assert_equal group, @repository.reload.owner
1172     end
1173
1174     should "be able to deny force pushing" do
1175       @repository.update_attribute(:deny_force_pushing, false)
1176       put :update, :project_id => @repository.project.to_param, :id => @repository.to_param,
1177         :repository => { :deny_force_pushing => true }
1178       assert_response :redirect
1179       assert @repository.reload.deny_force_pushing?
1180     end
1181
1182     should "be able to disable merge requests" do
1183       @repository.update_attribute(:merge_requests_enabled, true)
1184       put :update, :project_id => @repository.project.to_param, :id => @repository.to_param,
1185         :repository => {}
1186       assert_response :redirect
1187       assert !@repository.reload.merge_requests_enabled?
1188       put :update, :project_id => @repository.project.to_param, :id => @repository.to_param,
1189         :repository => {:merge_requests_enabled => 1}
1190       assert_response :redirect
1191       assert @repository.reload.merge_requests_enabled?
1192     end
1193
1194     should "be able to turn off notify_committers_on_new_merge_request" do
1195       @repository.update_attribute(:notify_committers_on_new_merge_request, true)
1196       put :update, :project_id => @repository.project.to_param, :id => @repository.to_param,
1197         :repository => { :notify_committers_on_new_merge_request => false }
1198       assert_response :redirect
1199       assert !@repository.reload.notify_committers_on_new_merge_request?
1200     end
1201
1202     context "Changing the HEAD" do
1203       should "update the HEAD if it is changed" do
1204         the_head = @grit.get_head("test/master")
1205         @grit.expects(:update_head).with(the_head).returns(true)
1206         put :update, :project_id => @project.to_param, :id => @repository.to_param,
1207               :repository => { :head => the_head.name }
1208         assert_equal @grit.heads, assigns(:heads)
1209       end
1210     end
1211   end
1212
1213   context "with committer (not owner) logged in" do
1214     should "GET projects/1/repositories/3 and have merge request link" do
1215       login_as :mike
1216       project = projects(:johans)
1217       repository = project.repositories.clones.first
1218       repository.committerships.create!({
1219           :committer => users(:mike),
1220           :permissions => Committership::CAN_REVIEW | Committership::CAN_COMMIT
1221         })
1222
1223       Project.expects(:find_by_slug!).with(project.slug).returns(project)
1224       repository.stubs(:has_commits?).returns(true)
1225
1226       get :show, :project_id => project.to_param, :id => repository.to_param
1227       assert_equal nil, flash[:error]
1228       assert_select("#sidebar ul.links li a[href=?]",
1229         new_project_repository_merge_request_path(project, repository),
1230         :content => "Request merge")
1231     end
1232   end
1233
1234   context "search clones" do
1235     setup do
1236       @repo = repositories(:johans)
1237       @clone_repo = repositories(:johans2)
1238     end
1239
1240     should "return a list of clones matching the query" do
1241       get :search_clones, :project_id => @repo.project.to_param, :id => @repo.to_param,
1242         :filter => "projectrepos", :format => "json"
1243       assert_response :success
1244       assert assigns(:repositories).include?(@clone_repo)
1245     end
1246   end
1247 end