3410: Merge branch 'master' into 3410-replication-attrs
[arvados.git] / services / api / test / functional / arvados / v1 / links_controller_test.rb
1 require 'test_helper'
2
3 class Arvados::V1::LinksControllerTest < ActionController::TestCase
4
5   ['link', 'link_json'].each do |formatted_link|
6     test "no symbol keys in serialized hash #{formatted_link}" do
7       link = {
8         properties: {username: 'testusername'},
9         link_class: 'test',
10         name: 'encoding',
11         tail_uuid: users(:admin).uuid,
12         head_uuid: virtual_machines(:testvm).uuid
13       }
14       authorize_with :admin
15       if formatted_link == 'link_json'
16         post :create, link: link.to_json
17       else
18         post :create, link: link
19       end
20       assert_response :success
21       assert_not_nil assigns(:object)
22       assert_equal 'testusername', assigns(:object).properties['username']
23       assert_equal false, assigns(:object).properties.has_key?(:username)
24     end
25   end
26
27   %w(created_at modified_at).each do |attr|
28     {nil: nil, bogus: 2.days.ago}.each do |bogustype, bogusvalue|
29       test "cannot set #{bogustype} #{attr} in create" do
30         authorize_with :active
31         post :create, {
32           link: {
33             properties: {},
34             link_class: 'test',
35             name: 'test',
36           }.merge(attr => bogusvalue)
37         }
38         assert_response :success
39         resp = JSON.parse @response.body
40         assert_in_delta Time.now, Time.parse(resp[attr]), 3.0
41       end
42       test "cannot set #{bogustype} #{attr} in update" do
43         really_created_at = links(:test_timestamps).created_at
44         authorize_with :active
45         put :update, {
46           id: links(:test_timestamps).uuid,
47           link: {
48             :properties => {test: 'test'},
49             attr => bogusvalue
50           }
51         }
52         assert_response :success
53         resp = JSON.parse @response.body
54         case attr
55         when 'created_at'
56           assert_in_delta really_created_at, Time.parse(resp[attr]), 0.001
57         else
58           assert_in_delta Time.now, Time.parse(resp[attr]), 3.0
59         end
60       end
61     end
62   end
63
64   test "head must exist" do
65     link = {
66       link_class: 'test',
67       name: 'stuff',
68       tail_uuid: users(:active).uuid,
69       head_uuid: 'zzzzz-tpzed-xyzxyzxerrrorxx'
70     }
71     authorize_with :admin
72     post :create, link: link
73     assert_response 422
74   end
75
76   test "tail must exist" do
77     link = {
78       link_class: 'test',
79       name: 'stuff',
80       head_uuid: users(:active).uuid,
81       tail_uuid: 'zzzzz-tpzed-xyzxyzxerrrorxx'
82     }
83     authorize_with :admin
84     post :create, link: link
85     assert_response 422
86   end
87
88   test "head and tail exist, head_kind and tail_kind are returned" do
89     link = {
90       link_class: 'test',
91       name: 'stuff',
92       head_uuid: users(:active).uuid,
93       tail_uuid: users(:spectator).uuid,
94     }
95     authorize_with :admin
96     post :create, link: link
97     assert_response :success
98     l = JSON.parse(@response.body)
99     assert 'arvados#user', l['head_kind']
100     assert 'arvados#user', l['tail_kind']
101   end
102
103   test "can supply head_kind and tail_kind without error" do
104     link = {
105       link_class: 'test',
106       name: 'stuff',
107       head_uuid: users(:active).uuid,
108       tail_uuid: users(:spectator).uuid,
109       head_kind: "arvados#user",
110       tail_kind: "arvados#user",
111     }
112     authorize_with :admin
113     post :create, link: link
114     assert_response :success
115     l = JSON.parse(@response.body)
116     assert 'arvados#user', l['head_kind']
117     assert 'arvados#user', l['tail_kind']
118   end
119
120   test "tail must be visible by user" do
121     link = {
122       link_class: 'test',
123       name: 'stuff',
124       head_uuid: users(:active).uuid,
125       tail_uuid: virtual_machines(:testvm2).uuid
126     }
127     authorize_with :active
128     post :create, link: link
129     assert_response 422
130   end
131
132   test "filter links with 'is_a' operator" do
133     authorize_with :admin
134     get :index, {
135       filters: [ ['tail_uuid', 'is_a', 'arvados#user'] ]
136     }
137     assert_response :success
138     found = assigns(:objects)
139     assert_not_equal 0, found.count
140     assert_equal found.count, (found.select { |f| f.tail_uuid.match User.uuid_regex }).count
141   end
142
143   test "filter links with 'is_a' operator with more than one" do
144     authorize_with :admin
145     get :index, {
146       filters: [ ['tail_uuid', 'is_a', ['arvados#user', 'arvados#group'] ] ],
147     }
148     assert_response :success
149     found = assigns(:objects)
150     assert_not_equal 0, found.count
151     assert_equal found.count, (found.select { |f|
152                                  f.tail_uuid.match User.uuid_regex or
153                                  f.tail_uuid.match Group.uuid_regex
154                                }).count
155   end
156
157   test "filter links with 'is_a' operator with bogus type" do
158     authorize_with :admin
159     get :index, {
160       filters: [ ['tail_uuid', 'is_a', ['arvados#bogus'] ] ],
161     }
162     assert_response :success
163     found = assigns(:objects)
164     assert_equal 0, found.count
165   end
166
167   test "filter links with 'is_a' operator with collection" do
168     authorize_with :admin
169     get :index, {
170       filters: [ ['head_uuid', 'is_a', ['arvados#collection'] ] ],
171     }
172     assert_response :success
173     found = assigns(:objects)
174     assert_not_equal 0, found.count
175     assert_equal found.count, (found.select { |f| f.head_uuid.match Collection.uuid_regex}).count
176   end
177
178   test "test can still use where tail_kind" do
179     authorize_with :admin
180     get :index, {
181       where: { tail_kind: 'arvados#user' }
182     }
183     assert_response :success
184     found = assigns(:objects)
185     assert_not_equal 0, found.count
186     assert_equal found.count, (found.select { |f| f.tail_uuid.match User.uuid_regex }).count
187   end
188
189   test "test can still use where head_kind" do
190     authorize_with :admin
191     get :index, {
192       where: { head_kind: 'arvados#user' }
193     }
194     assert_response :success
195     found = assigns(:objects)
196     assert_not_equal 0, found.count
197     assert_equal found.count, (found.select { |f| f.head_uuid.match User.uuid_regex }).count
198   end
199
200   test "test can still use filter tail_kind" do
201     authorize_with :admin
202     get :index, {
203       filters: [ ['tail_kind', '=', 'arvados#user'] ]
204     }
205     assert_response :success
206     found = assigns(:objects)
207     assert_not_equal 0, found.count
208     assert_equal found.count, (found.select { |f| f.tail_uuid.match User.uuid_regex }).count
209   end
210
211   test "test can still use filter head_kind" do
212     authorize_with :admin
213     get :index, {
214       filters: [ ['head_kind', '=', 'arvados#user'] ]
215     }
216     assert_response :success
217     found = assigns(:objects)
218     assert_not_equal 0, found.count
219     assert_equal found.count, (found.select { |f| f.head_uuid.match User.uuid_regex }).count
220   end
221
222   test "head_kind matches head_uuid" do
223     link = {
224       link_class: 'test',
225       name: 'stuff',
226       head_uuid: groups(:public).uuid,
227       head_kind: "arvados#user",
228       tail_uuid: users(:spectator).uuid,
229       tail_kind: "arvados#user",
230     }
231     authorize_with :admin
232     post :create, link: link
233     assert_response 422
234   end
235
236   test "tail_kind matches tail_uuid" do
237     link = {
238       link_class: 'test',
239       name: 'stuff',
240       head_uuid: users(:active).uuid,
241       head_kind: "arvados#user",
242       tail_uuid: groups(:public).uuid,
243       tail_kind: "arvados#user",
244     }
245     authorize_with :admin
246     post :create, link: link
247     assert_response 422
248   end
249
250   test "test with virtual_machine" do
251     link = {
252       tail_kind: "arvados#user",
253       tail_uuid: users(:active).uuid,
254       head_kind: "arvados#virtual_machine",
255       head_uuid: virtual_machines(:testvm).uuid,
256       link_class: "permission",
257       name: "can_login",
258       properties: {username: "repo_and_user_name"}
259     }
260     authorize_with :admin
261     post :create, link: link
262     assert_response 422
263   end
264
265   test "test with virtualMachine" do
266     link = {
267       tail_kind: "arvados#user",
268       tail_uuid: users(:active).uuid,
269       head_kind: "arvados#virtualMachine",
270       head_uuid: virtual_machines(:testvm).uuid,
271       link_class: "permission",
272       name: "can_login",
273       properties: {username: "repo_and_user_name"}
274     }
275     authorize_with :admin
276     post :create, link: link
277     assert_response :success
278   end
279
280   test "project owner can show a project permission" do
281     uuid = links(:project_viewer_can_read_project).uuid
282     authorize_with :active
283     get :show, id: uuid
284     assert_response :success
285     assert_equal(uuid, assigns(:object).andand.uuid)
286   end
287
288   test "admin can show a project permission" do
289     uuid = links(:project_viewer_can_read_project).uuid
290     authorize_with :admin
291     get :show, id: uuid
292     assert_response :success
293     assert_equal(uuid, assigns(:object).andand.uuid)
294   end
295
296   test "project viewer can't show others' project permissions" do
297     authorize_with :project_viewer
298     get :show, id: links(:admin_can_write_aproject).uuid
299     assert_response 404
300   end
301
302   test "requesting a nonexistent link returns 404" do
303     authorize_with :active
304     get :show, id: 'zzzzz-zzzzz-zzzzzzzzzzzzzzz'
305     assert_response 404
306   end
307
308   test "retrieve all permissions using generic links index api" do
309     skip "(not implemented)"
310     # Links.readable_by() does not return the full set of permission
311     # links that are visible to a user (i.e., all permission links
312     # whose head_uuid references an object for which the user has
313     # ownership or can_manage permission). Therefore, neither does
314     # /arvados/v1/links.
315     #
316     # It is possible to retrieve the full set of permissions for a
317     # single object via /arvados/v1/permissions.
318     authorize_with :active
319     get :index, filters: [['link_class', '=', 'permission'],
320                           ['head_uuid', '=', groups(:aproject).uuid]]
321     assert_response :success
322     assert_not_nil assigns(:objects)
323     assert_includes(assigns(:objects).map(&:uuid),
324                     links(:project_viewer_can_read_project).uuid)
325   end
326
327   test "admin can index project permissions" do
328     authorize_with :admin
329     get :index, filters: [['link_class', '=', 'permission'],
330                           ['head_uuid', '=', groups(:aproject).uuid]]
331     assert_response :success
332     assert_not_nil assigns(:objects)
333     assert_includes(assigns(:objects).map(&:uuid),
334                     links(:project_viewer_can_read_project).uuid)
335   end
336
337   test "project viewer can't index others' project permissions" do
338     authorize_with :project_viewer
339     get :index, filters: [['link_class', '=', 'permission'],
340                           ['head_uuid', '=', groups(:aproject).uuid],
341                           ['tail_uuid', '!=', users(:project_viewer).uuid]]
342     assert_response :success
343     assert_not_nil assigns(:objects)
344     assert_empty assigns(:objects)
345   end
346
347   # Granting permissions.
348   test "grant can_read on project to other users in group" do
349     authorize_with :user_foo_in_sharing_group
350
351     refute users(:user_bar_in_sharing_group).can?(read: collections(:collection_owned_by_foo).uuid)
352
353     post :create, {
354       link: {
355         tail_uuid: users(:user_bar_in_sharing_group).uuid,
356         link_class: 'permission',
357         name: 'can_read',
358         head_uuid: collections(:collection_owned_by_foo).uuid,
359       }
360     }
361     assert_response :success
362     assert users(:user_bar_in_sharing_group).can?(read: collections(:collection_owned_by_foo).uuid)
363   end
364 end