Merge branch 'master' into 3198-writable-fuse
[arvados.git] / services / api / test / unit / repository_test.rb
1 require 'test_helper'
2 require 'helpers/git_test_helper'
3
4 class RepositoryTest < ActiveSupport::TestCase
5   include GitTestHelper
6
7   def new_repo(owner_key, attrs={})
8     set_user_from_auth owner_key
9     owner = users(owner_key)
10     Repository.new({owner_uuid: owner.uuid}.merge(attrs))
11   end
12
13   def changed_repo(repo_key, changes)
14     repo = repositories(repo_key)
15     changes.each_pair { |attr, value| repo.send("#{attr}=".to_sym, value) }
16     repo
17   end
18
19   def default_git_url(repo_name, user_name=nil)
20     if user_name
21       "git@git.%s.arvadosapi.com:%s/%s.git" %
22         [Rails.configuration.uuid_prefix, user_name, repo_name]
23     else
24       "git@git.%s.arvadosapi.com:%s.git" %
25         [Rails.configuration.uuid_prefix, repo_name]
26     end
27   end
28
29   def assert_server_path(path_tail, repo_sym)
30     assert_equal(File.join(Rails.configuration.git_repositories_dir, path_tail),
31                  repositories(repo_sym).server_path)
32   end
33
34   ### name validation
35
36   {active: "active/", admin: "admin/", system_user: ""}.
37       each_pair do |user_sym, name_prefix|
38     %w(a aa a0 aA Aa AA A0).each do |name|
39       test "'#{name_prefix}#{name}' is a valid name for #{user_sym} repo" do
40         repo = new_repo(user_sym, name: name_prefix + name)
41         assert(repo.valid?)
42       end
43     end
44
45     test "name is required for #{user_sym} repo" do
46       refute(new_repo(user_sym).valid?)
47     end
48
49     test "repo name beginning with numeral is invalid for #{user_sym}" do
50       repo = new_repo(user_sym, name: "#{name_prefix}0a")
51       refute(repo.valid?)
52     end
53
54     "\\.-_/!@#$%^&*()[]{}".each_char do |bad_char|
55       test "name containing #{bad_char.inspect} is invalid for #{user_sym}" do
56         repo = new_repo(user_sym, name: "#{name_prefix}bad#{bad_char}reponame")
57         refute(repo.valid?)
58       end
59     end
60   end
61
62   test "admin can create valid repo for other user with correct name prefix" do
63     owner = users(:active)
64     repo = new_repo(:admin, name: "#{owner.username}/validnametest",
65                     owner_uuid: owner.uuid)
66     assert(repo.valid?)
67   end
68
69   test "admin can create valid system repo without name prefix" do
70     repo = new_repo(:admin, name: "validnametest",
71                     owner_uuid: users(:system_user).uuid)
72     assert(repo.valid?)
73   end
74
75   test "repo name prefix must match owner_uuid username" do
76     repo = new_repo(:admin, name: "admin/badusernametest",
77                     owner_uuid: users(:active).uuid)
78     refute(repo.valid?)
79   end
80
81   test "repo name prefix must be empty for system repo" do
82     repo = new_repo(:admin, name: "root/badprefixtest",
83                     owner_uuid: users(:system_user).uuid)
84     refute(repo.valid?)
85   end
86
87   ### owner validation
88
89   test "name must be unique per user" do
90     repo = new_repo(:active, name: repositories(:foo).name)
91     refute(repo.valid?)
92   end
93
94   test "name can be duplicated across users" do
95     repo = new_repo(:active, name: "active/#{repositories(:arvados).name}")
96     assert(repo.valid?)
97   end
98
99   test "repository cannot be owned by a group" do
100     set_user_from_auth :active
101     repo = Repository.new(owner_uuid: groups(:all_users).uuid,
102                           name: "ownedbygroup")
103     refute(repo.valid?)
104     refute_empty(repo.errors[:owner_uuid] || [])
105   end
106
107   ### URL generation
108
109   test "fetch_url" do
110     repo = new_repo(:active, name: "active/fetchtest")
111     repo.save
112     assert_equal(default_git_url("fetchtest", "active"), repo.fetch_url)
113   end
114
115   test "fetch_url owned by system user" do
116     set_user_from_auth :admin
117     repo = Repository.new(owner_uuid: users(:system_user).uuid,
118                           name: "fetchtest")
119     repo.save
120     assert_equal(default_git_url("fetchtest"), repo.fetch_url)
121   end
122
123   test "push_url" do
124     repo = new_repo(:active, name: "active/pushtest")
125     repo.save
126     assert_equal(default_git_url("pushtest", "active"), repo.push_url)
127   end
128
129   test "push_url owned by system user" do
130     set_user_from_auth :admin
131     repo = Repository.new(owner_uuid: users(:system_user).uuid,
132                           name: "pushtest")
133     repo.save
134     assert_equal(default_git_url("pushtest"), repo.push_url)
135   end
136
137   ### Path generation
138
139   test "disk path stored by UUID" do
140     assert_server_path("zzzzz-s0uqq-382brsig8rp3666/.git", :foo)
141   end
142
143   test "disk path stored by name" do
144     assert_server_path("arvados/.git", :arvados)
145   end
146
147   test "disk path for repository not on disk" do
148     assert_nil(Repository.new.server_path)
149   end
150
151   ### Repository creation
152
153   test "non-admin can create a repository for themselves" do
154     repo = new_repo(:active, name: "active/newtestrepo")
155     assert(repo.save)
156   end
157
158   test "non-admin can't create a repository for another visible user" do
159     repo = new_repo(:active, name: "repoforanon",
160                     owner_uuid: users(:anonymous).uuid)
161     assert_not_allowed { repo.save }
162   end
163
164   test "admin can create a repository for themselves" do
165     repo = new_repo(:admin, name: "admin/newtestrepo")
166     assert(repo.save)
167   end
168
169   test "admin can create a repository for others" do
170     repo = new_repo(:admin, name: "active/repoforactive",
171                     owner_uuid: users(:active).uuid)
172     assert(repo.save)
173   end
174
175   test "admin can create a system repository" do
176     repo = new_repo(:admin, name: "repoforsystem",
177                     owner_uuid: users(:system_user).uuid)
178     assert(repo.save)
179   end
180
181   ### Repository destruction
182
183   test "non-admin can destroy their own repository" do
184     set_user_from_auth :active
185     assert(repositories(:foo).destroy)
186   end
187
188   test "non-admin can't destroy others' repository" do
189     set_user_from_auth :active
190     assert_not_allowed { repositories(:repository3).destroy }
191   end
192
193   test "non-admin can't destroy system repository" do
194     set_user_from_auth :active
195     assert_not_allowed { repositories(:arvados).destroy }
196   end
197
198   test "admin can destroy their own repository" do
199     set_user_from_auth :admin
200     assert(repositories(:repository3).destroy)
201   end
202
203   test "admin can destroy others' repository" do
204     set_user_from_auth :admin
205     assert(repositories(:foo).destroy)
206   end
207
208   test "admin can destroy system repository" do
209     set_user_from_auth :admin
210     assert(repositories(:arvados).destroy)
211   end
212
213   ### Changing ownership
214
215   test "non-admin can't make their repository a system repository" do
216     set_user_from_auth :active
217     repo = changed_repo(:foo, owner_uuid: users(:system_user).uuid)
218     assert_not_allowed { repo.save }
219   end
220
221   test "admin can give their repository to someone else" do
222     set_user_from_auth :admin
223     repo = changed_repo(:repository3, owner_uuid: users(:active).uuid,
224                         name: "active/foo3")
225     assert(repo.save)
226   end
227
228   test "admin can make their repository a system repository" do
229     set_user_from_auth :admin
230     repo = changed_repo(:repository3, owner_uuid: users(:system_user).uuid,
231                         name: "foo3")
232     assert(repo.save)
233   end
234
235   test 'write permission allows changing modified_at' do
236     act_as_user users(:active) do
237       r = repositories(:foo)
238       modtime_was = r.modified_at
239       r.modified_at = Time.now
240       assert r.save
241       assert_operator modtime_was, :<, r.modified_at
242     end
243   end
244
245   test 'write permission necessary for changing modified_at' do
246     act_as_user users(:spectator) do
247       r = repositories(:foo)
248       modtime_was = r.modified_at
249       r.modified_at = Time.now
250       assert_raises ArvadosModel::PermissionDeniedError do
251         r.save!
252       end
253       r.reload
254       assert_equal modtime_was, r.modified_at
255     end
256   end
257
258   ### Renaming
259
260   test "non-admin can rename own repo" do
261     act_as_user users(:active) do
262       assert repositories(:foo).update_attributes(name: 'active/foo12345')
263     end
264   end
265
266   test "top level repo can be touched by non-admin with can_manage" do
267     add_permission_link users(:active), repositories(:arvados), 'can_manage'
268     act_as_user users(:active) do
269       assert changed_repo(:arvados, modified_at: Time.now).save
270     end
271   end
272
273   test "top level repo cannot be renamed by non-admin with can_manage" do
274     add_permission_link users(:active), repositories(:arvados), 'can_manage'
275     act_as_user users(:active) do
276       assert_not_allowed { changed_repo(:arvados, name: 'xarvados').save }
277     end
278   end
279 end