3 class Arvados::V1::GroupsControllerTest < ActionController::TestCase
5 test "attempt to delete group without read or write access" do
7 post :destroy, id: groups(:empty_lonely_group).uuid
11 test "attempt to delete group without write access" do
12 authorize_with :active
13 post :destroy, id: groups(:all_users).uuid
17 test "get list of projects" do
18 authorize_with :active
19 get :index, filters: [['group_class', '=', 'project']], format: :json
20 assert_response :success
22 json_response['items'].each do |group|
23 assert_equal 'project', group['group_class']
24 group_uuids << group['uuid']
26 assert_includes group_uuids, groups(:aproject).uuid
27 assert_includes group_uuids, groups(:asubproject).uuid
28 assert_not_includes group_uuids, groups(:system_group).uuid
29 assert_not_includes group_uuids, groups(:private).uuid
32 test "get list of groups that are not projects" do
33 authorize_with :active
34 get :index, filters: [['group_class', '!=', 'project']], format: :json
35 assert_response :success
37 json_response['items'].each do |group|
38 assert_not_equal 'project', group['group_class']
39 group_uuids << group['uuid']
41 assert_not_includes group_uuids, groups(:aproject).uuid
42 assert_not_includes group_uuids, groups(:asubproject).uuid
43 assert_includes group_uuids, groups(:private).uuid
44 assert_includes group_uuids, groups(:group_with_no_class).uuid
47 test "get list of groups with bogus group_class" do
48 authorize_with :active
50 filters: [['group_class', '=', 'nogrouphasthislittleclass']],
53 assert_response :success
54 assert_equal [], json_response['items']
55 assert_equal 0, json_response['items_available']
58 def check_project_contents_response disabled_kinds=[]
59 assert_response :success
60 assert_operator 2, :<=, json_response['items_available']
61 assert_operator 2, :<=, json_response['items'].count
62 kinds = json_response['items'].collect { |i| i['kind'] }.uniq
63 expect_kinds = %w'arvados#group arvados#specimen arvados#pipelineTemplate arvados#job' - disabled_kinds
64 assert_equal expect_kinds, (expect_kinds & kinds)
66 json_response['items'].each do |i|
67 if i['kind'] == 'arvados#group'
68 assert(i['group_class'] == 'project',
69 "group#contents returned a non-project group")
73 disabled_kinds.each do |d|
74 assert_equal true, !kinds.include?(d)
78 test 'get group-owned objects' do
79 authorize_with :active
81 id: groups(:aproject).uuid,
84 check_project_contents_response
87 test "user with project read permission can see project objects" do
88 authorize_with :project_viewer
90 id: groups(:aproject).uuid,
93 check_project_contents_response
96 test "list objects across projects" do
97 authorize_with :project_viewer
100 filters: [['uuid', 'is_a', 'arvados#specimen']]
102 assert_response :success
103 found_uuids = json_response['items'].collect { |i| i['uuid'] }
104 [[:in_aproject, true],
105 [:in_asubproject, true],
106 [:owned_by_private_group, false]].each do |specimen_fixture, should_find|
108 assert_includes found_uuids, specimens(specimen_fixture).uuid, "did not find specimen fixture '#{specimen_fixture}'"
110 refute_includes found_uuids, specimens(specimen_fixture).uuid, "found specimen fixture '#{specimen_fixture}'"
115 test "list objects in home project" do
116 authorize_with :active
120 id: users(:active).uuid
122 assert_response :success
123 found_uuids = json_response['items'].collect { |i| i['uuid'] }
124 assert_includes found_uuids, specimens(:owned_by_active_user).uuid, "specimen did not appear in home project"
125 refute_includes found_uuids, specimens(:in_asubproject).uuid, "specimen appeared unexpectedly in home project"
128 test "user with project read permission can see project collections" do
129 authorize_with :project_viewer
131 id: groups(:asubproject).uuid,
134 ids = json_response['items'].map { |item| item["uuid"] }
135 assert_includes ids, collections(:baz_file_in_asubproject).uuid
139 ['desc', :>=]].each do |order, operator|
140 test "user with project read permission can sort project collections #{order}" do
141 authorize_with :project_viewer
143 id: groups(:asubproject).uuid,
145 filters: [['uuid', 'is_a', "arvados#collection"]],
146 order: "collections.name #{order}"
148 sorted_names = json_response['items'].collect { |item| item["name"] }
149 # Here we avoid assuming too much about the database
150 # collation. Both "alice"<"Bob" and "alice">"Bob" can be
151 # correct. Hopefully it _is_ safe to assume that if "a" comes
152 # before "b" in the ascii alphabet, "aX">"bY" is never true for
153 # any strings X and Y.
154 reliably_sortable_names = sorted_names.select do |name|
155 name[0] >= 'a' and name[0] <= 'z'
159 # Preserve order of sorted_names. But do not use &=. If
160 # sorted_names has out-of-order duplicates, we want to preserve
161 # them here, so we can detect them and fail the test below.
162 sorted_names.select! do |name|
163 reliably_sortable_names.include? name
165 actually_checked_anything = false
167 sorted_names.each do |entry|
169 assert_operator(previous, operator, entry,
170 "Entries sorted incorrectly.")
171 actually_checked_anything = true
175 assert actually_checked_anything, "Didn't even find two names to compare."
179 test 'list objects across multiple projects' do
180 authorize_with :project_viewer
183 filters: [['uuid', 'is_a', 'arvados#specimen']]
185 assert_response :success
186 found_uuids = json_response['items'].collect { |i| i['uuid'] }
187 [[:in_aproject, true],
188 [:in_asubproject, true],
189 [:owned_by_private_group, false]].each do |specimen_fixture, should_find|
191 assert_includes found_uuids, specimens(specimen_fixture).uuid, "did not find specimen fixture '#{specimen_fixture}'"
193 refute_includes found_uuids, specimens(specimen_fixture).uuid, "found specimen fixture '#{specimen_fixture}'"
198 # Even though the project_viewer tests go through other controllers,
199 # I'm putting them here so they're easy to find alongside the other
201 def check_new_project_link_fails(link_attrs)
202 @controller = Arvados::V1::LinksController.new
203 post :create, link: {
204 link_class: "permission",
206 head_uuid: groups(:aproject).uuid,
208 assert_includes(403..422, response.status)
211 test "user with project read permission can't add users to it" do
212 authorize_with :project_viewer
213 check_new_project_link_fails(tail_uuid: users(:spectator).uuid)
216 test "user with project read permission can't add items to it" do
217 authorize_with :project_viewer
218 check_new_project_link_fails(tail_uuid: collections(:baz_file).uuid)
221 test "user with project read permission can't rename items in it" do
222 authorize_with :project_viewer
223 @controller = Arvados::V1::LinksController.new
225 id: jobs(:running).uuid,
226 name: "Denied test name",
228 assert_includes(403..404, response.status)
231 test "user with project read permission can't remove items from it" do
232 @controller = Arvados::V1::PipelineTemplatesController.new
233 authorize_with :project_viewer
235 id: pipeline_templates(:two_part).uuid,
237 owner_uuid: users(:project_viewer).uuid,
243 test "user with project read permission can't delete it" do
244 authorize_with :project_viewer
245 post :destroy, {id: groups(:aproject).uuid}
249 test 'get group-owned objects with limit' do
250 authorize_with :active
252 id: groups(:aproject).uuid,
256 assert_response :success
257 assert_operator 1, :<, json_response['items_available']
258 assert_equal 1, json_response['items'].count
261 test 'get group-owned objects with limit and offset' do
262 authorize_with :active
264 id: groups(:aproject).uuid,
269 assert_response :success
270 assert_operator 1, :<, json_response['items_available']
271 assert_equal 0, json_response['items'].count
274 test 'get group-owned objects with additional filter matching nothing' do
275 authorize_with :active
277 id: groups(:aproject).uuid,
278 filters: [['uuid', 'in', ['foo_not_a_uuid','bar_not_a_uuid']]],
281 assert_response :success
282 assert_equal [], json_response['items']
283 assert_equal 0, json_response['items_available']
286 %w(offset limit).each do |arg|
287 ['foo', '', '1234five', '0x10', '-8'].each do |val|
288 test "Raise error on bogus #{arg} parameter #{val.inspect}" do
289 authorize_with :active
291 :id => groups(:aproject).uuid,
300 test "Collection contents don't include manifest_text" do
301 authorize_with :active
303 id: groups(:aproject).uuid,
304 filters: [["uuid", "is_a", "arvados#collection"]],
307 assert_response :success
308 refute(json_response["items"].any? { |c| not c["portable_data_hash"] },
309 "response included an item without a portable data hash")
310 refute(json_response["items"].any? { |c| c.include?("manifest_text") },
311 "response included an item with a manifest text")
314 test 'get writable_by list for owned group' do
315 authorize_with :active
317 id: groups(:aproject).uuid,
320 assert_response :success
321 assert_not_nil(json_response['writable_by'],
322 "Should receive uuid list in 'writable_by' field")
323 assert_includes(json_response['writable_by'], users(:active).uuid,
324 "owner should be included in writable_by list")
327 test 'no writable_by list for group with read-only access' do
328 authorize_with :rominiadmin
330 id: groups(:testusergroup_admins).uuid,
333 assert_response :success
334 assert_equal([json_response['owner_uuid']],
335 json_response['writable_by'],
336 "Should only see owner_uuid in 'writable_by' field")
339 test 'get writable_by list by admin user' do
340 authorize_with :admin
342 id: groups(:testusergroup_admins).uuid,
345 assert_response :success
346 assert_not_nil(json_response['writable_by'],
347 "Should receive uuid list in 'writable_by' field")
348 assert_includes(json_response['writable_by'],
350 "Current user should be included in 'writable_by' field")
353 test 'creating subproject with duplicate name fails' do
354 authorize_with :active
358 owner_uuid: users(:active).uuid,
359 group_class: 'project',
363 response_errors = json_response['errors']
364 assert_not_nil response_errors, 'Expected error in response'
365 assert(response_errors.first.include?('duplicate key'),
366 "Expected 'duplicate key' error in #{response_errors.first}")
369 test 'creating duplicate named subproject succeeds with ensure_unique_name' do
370 authorize_with :active
374 owner_uuid: users(:active).uuid,
375 group_class: 'project',
377 ensure_unique_name: true
379 assert_response :success
380 new_project = json_response
381 assert_not_equal(new_project['uuid'],
382 groups(:aproject).uuid,
383 "create returned same uuid as existing project")
384 assert_match(/^A Project \(\d{4}-\d\d-\d\dT\d\d:\d\d:\d\d\.\d{3}Z\)$/,
388 test "unsharing a project results in hiding it from previously shared user" do
389 # remove sharing link for project
390 @controller = Arvados::V1::LinksController.new
391 authorize_with :admin
392 post :destroy, id: links(:share_starred_project_with_project_viewer).uuid
393 assert_response :success
395 # verify that the user can no longer see the project
396 @test_counter = 0 # Reset executed action counter
397 @controller = Arvados::V1::GroupsController.new
398 authorize_with :project_viewer
399 get :index, filters: [['group_class', '=', 'project']], format: :json
400 assert_response :success
402 json_response['items'].each do |g|
403 found_projects[g['uuid']] = g
405 assert_equal false, found_projects.include?(groups(:starred_and_shared_active_user_project).uuid)
409 @controller = Arvados::V1::LinksController.new
410 authorize_with :system_user
411 post :create, link: {
412 link_class: "permission",
414 head_uuid: groups(:starred_and_shared_active_user_project).uuid,
415 tail_uuid: users(:project_viewer).uuid,
418 # verify that project_viewer user can now see shared project again
420 @controller = Arvados::V1::GroupsController.new
421 authorize_with :project_viewer
422 get :index, filters: [['group_class', '=', 'project']], format: :json
423 assert_response :success
425 json_response['items'].each do |g|
426 found_projects[g['uuid']] = g
428 assert_equal true, found_projects.include?(groups(:starred_and_shared_active_user_project).uuid)
432 [['owner_uuid', '!=', 'zzzzz-tpzed-xurymjxw79nv3jz'], 200,
433 'zzzzz-d1hrv-subprojpipeline', 'zzzzz-d1hrv-1xfj6xkicf2muk2'],
434 [["pipeline_instances.state", "not in", ["Complete", "Failed"]], 200,
435 'zzzzz-d1hrv-1xfj6xkicf2muk2', 'zzzzz-d1hrv-i3e77t9z5y8j9cc'],
436 [['container_requests.requesting_container_uuid', '=', nil], 200,
437 'zzzzz-xvhdp-cr4queuedcontnr', 'zzzzz-xvhdp-cr4requestercn2'],
438 [['container_requests.no_such_column', '=', nil], 422],
439 [['container_requests.', '=', nil], 422],
440 [['.requesting_container_uuid', '=', nil], 422],
441 [['no_such_table.uuid', '!=', 'zzzzz-tpzed-xurymjxw79nv3jz'], 422],
442 ].each do |filter, expect_code, expect_uuid, not_expect_uuid|
443 test "get contents with '#{filter}' filter" do
444 authorize_with :active
445 get :contents, filters: [filter], format: :json
446 assert_response expect_code
447 if expect_code == 200
448 assert_not_empty json_response['items']
449 item_uuids = json_response['items'].collect {|item| item['uuid']}
450 assert_includes(item_uuids, expect_uuid)
451 assert_not_includes(item_uuids, not_expect_uuid)
456 test 'get contents with jobs and pipeline instances disabled' do
457 Rails.configuration.disable_api_methods = ['jobs.index', 'pipeline_instances.index']
459 authorize_with :active
461 id: groups(:aproject).uuid,
464 check_project_contents_response %w'arvados#pipelineInstance arvados#job'
467 test 'get contents with low max_index_database_read' do
468 # Some result will certainly have at least 12 bytes in a
470 Rails.configuration.max_index_database_read = 12
471 authorize_with :active
473 id: groups(:aproject).uuid,
476 assert_response :success
477 assert_not_empty(json_response['items'])
478 assert_operator(json_response['items'].count,
479 :<, json_response['items_available'])
482 test 'get contents, recursive=true' do
483 authorize_with :active
485 id: groups(:aproject).uuid,
489 get :contents, params
490 owners = json_response['items'].map do |item|
493 assert_includes(owners, groups(:aproject).uuid)
494 assert_includes(owners, groups(:asubproject).uuid)
497 [false, nil].each do |recursive|
498 test "get contents, recursive=#{recursive.inspect}" do
499 authorize_with :active
501 id: groups(:aproject).uuid,
504 params[:recursive] = false if recursive == false
505 get :contents, params
506 owners = json_response['items'].map do |item|
509 assert_includes(owners, groups(:aproject).uuid)
510 refute_includes(owners, groups(:asubproject).uuid)
514 test 'get home project contents, recursive=true' do
515 authorize_with :active
517 id: users(:active).uuid,
521 owners = json_response['items'].map do |item|
524 assert_includes(owners, users(:active).uuid)
525 assert_includes(owners, groups(:aproject).uuid)
526 assert_includes(owners, groups(:asubproject).uuid)