X-Git-Url: https://git.arvados.org/arvados.git/blobdiff_plain/adedc9a3791fbed1d08da4d8681f1d0e0b36e024..HEAD:/services/api/test/functional/arvados/v1/groups_controller_test.rb diff --git a/services/api/test/functional/arvados/v1/groups_controller_test.rb b/services/api/test/functional/arvados/v1/groups_controller_test.rb index 30ab89c7e2..52ed140bae 100644 --- a/services/api/test/functional/arvados/v1/groups_controller_test.rb +++ b/services/api/test/functional/arvados/v1/groups_controller_test.rb @@ -6,12 +6,19 @@ require 'test_helper' class Arvados::V1::GroupsControllerTest < ActionController::TestCase - test "attempt to delete group without read or write access" do + test "attempt to delete group that cannot be seen" do + Rails.configuration.Users.RoleGroupsVisibleToAll = false authorize_with :active post :destroy, params: {id: groups(:empty_lonely_group).uuid} assert_response 404 end + test "attempt to delete group without read or write access" do + authorize_with :active + post :destroy, params: {id: groups(:empty_lonely_group).uuid} + assert_response 403 + end + test "attempt to delete group without write access" do authorize_with :active post :destroy, params: {id: groups(:all_users).uuid} @@ -29,8 +36,9 @@ class Arvados::V1::GroupsControllerTest < ActionController::TestCase end assert_includes group_uuids, groups(:aproject).uuid assert_includes group_uuids, groups(:asubproject).uuid + assert_includes group_uuids, groups(:private).uuid assert_not_includes group_uuids, groups(:system_group).uuid - assert_not_includes group_uuids, groups(:private).uuid + assert_not_includes group_uuids, groups(:private_and_can_read_foofile).uuid end test "get list of groups that are not projects" do @@ -44,8 +52,6 @@ class Arvados::V1::GroupsControllerTest < ActionController::TestCase end assert_not_includes group_uuids, groups(:aproject).uuid assert_not_includes group_uuids, groups(:asubproject).uuid - assert_includes group_uuids, groups(:private).uuid - assert_includes group_uuids, groups(:group_with_no_class).uuid end test "get list of groups with bogus group_class" do @@ -59,12 +65,12 @@ class Arvados::V1::GroupsControllerTest < ActionController::TestCase assert_equal 0, json_response['items_available'] end - def check_project_contents_response disabled_kinds=[] + def check_project_contents_response assert_response :success assert_operator 2, :<=, json_response['items_available'] assert_operator 2, :<=, json_response['items'].count kinds = json_response['items'].collect { |i| i['kind'] }.uniq - expect_kinds = %w'arvados#group arvados#specimen arvados#pipelineTemplate arvados#job' - disabled_kinds + expect_kinds = %w'arvados#group' assert_equal expect_kinds, (expect_kinds & kinds) json_response['items'].each do |i| @@ -73,10 +79,6 @@ class Arvados::V1::GroupsControllerTest < ActionController::TestCase "group#contents returned a non-project group") end end - - disabled_kinds.each do |d| - assert_equal true, !kinds.include?(d) - end end test 'get group-owned objects' do @@ -101,17 +103,17 @@ class Arvados::V1::GroupsControllerTest < ActionController::TestCase authorize_with :project_viewer get :contents, params: { format: :json, - filters: [['uuid', 'is_a', 'arvados#specimen']] + filters: [['uuid', 'is_a', 'arvados#collection']] } assert_response :success found_uuids = json_response['items'].collect { |i| i['uuid'] } - [[:in_aproject, true], - [:in_asubproject, true], - [:owned_by_private_group, false]].each do |specimen_fixture, should_find| + [[:foo_collection_in_aproject, true], + [:baz_collection_name_in_asubproject, true], + [:collection_not_readable_by_active, false]].each do |collection_fixture, should_find| if should_find - assert_includes found_uuids, specimens(specimen_fixture).uuid, "did not find specimen fixture '#{specimen_fixture}'" + assert_includes found_uuids, collections(collection_fixture).uuid, "did not find collection fixture '#{collection_fixture}'" else - refute_includes found_uuids, specimens(specimen_fixture).uuid, "found specimen fixture '#{specimen_fixture}'" + refute_includes found_uuids, collections(collection_fixture).uuid, "found collection fixture '#{collection_fixture}'" end end end @@ -144,8 +146,41 @@ class Arvados::V1::GroupsControllerTest < ActionController::TestCase } assert_response :success found_uuids = json_response['items'].collect { |i| i['uuid'] } - assert_includes found_uuids, specimens(:owned_by_active_user).uuid, "specimen did not appear in home project" - refute_includes found_uuids, specimens(:in_asubproject).uuid, "specimen appeared unexpectedly in home project" + assert_includes found_uuids, collections(:collection_owned_by_active).uuid, "collection did not appear in home project" + refute_includes found_uuids, collections(:foo_collection_in_aproject).uuid, "collection appeared unexpectedly in home project" + end + + test "list collections in home project" do + authorize_with :active + get(:contents, params: { + format: :json, + filters: [ + ['uuid', 'is_a', 'arvados#collection'], + ], + limit: 200, + id: users(:active).uuid, + }) + assert_response :success + found_uuids = json_response['items'].collect { |i| i['uuid'] } + assert_includes found_uuids, collections(:collection_owned_by_active).uuid, "collection did not appear in home project" + refute_includes found_uuids, collections(:collection_owned_by_active_past_version_1).uuid, "collection appeared unexpectedly in home project" + end + + test "list collections in home project, including old versions" do + authorize_with :active + get(:contents, params: { + format: :json, + include_old_versions: true, + filters: [ + ['uuid', 'is_a', 'arvados#collection'], + ], + limit: 200, + id: users(:active).uuid, + }) + assert_response :success + found_uuids = json_response['items'].collect { |i| i['uuid'] } + assert_includes found_uuids, collections(:collection_owned_by_active).uuid, "collection did not appear in home project" + assert_includes found_uuids, collections(:collection_owned_by_active_past_version_1).uuid, "old collection version did not appear in home project" end test "user with project read permission can see project collections" do @@ -240,20 +275,20 @@ class Arvados::V1::GroupsControllerTest < ActionController::TestCase test "user with project read permission can't rename items in it" do authorize_with :project_viewer - @controller = Arvados::V1::LinksController.new + @controller = Arvados::V1::CollectionsController.new post :update, params: { - id: jobs(:running).uuid, + id: collections(:collection_to_search_for_in_aproject).uuid, name: "Denied test name", } assert_includes(403..404, response.status) end test "user with project read permission can't remove items from it" do - @controller = Arvados::V1::PipelineTemplatesController.new + @controller = Arvados::V1::CollectionsController.new authorize_with :project_viewer post :update, params: { - id: pipeline_templates(:two_part).uuid, - pipeline_template: { + id: collections(:collection_to_search_for_in_aproject).uuid, + collection: { owner_uuid: users(:project_viewer).uuid, } } @@ -291,6 +326,38 @@ class Arvados::V1::GroupsControllerTest < ActionController::TestCase assert_equal 0, json_response['items'].count end + test 'get group-owned objects with select' do + authorize_with :active + get :contents, params: { + id: groups(:aproject).uuid, + limit: 100, + format: :json, + select: ["uuid", "storage_classes_desired"] + } + assert_response :success + assert_equal 6, json_response['items_available'] + assert_equal 6, json_response['items'].count + json_response['items'].each do |item| + # Expect collections to have a storage_classes field, other items should not. + if item["kind"] == "arvados#collection" + assert !item["storage_classes_desired"].nil? + else + assert item["storage_classes_desired"].nil? + end + end + end + + test 'get group-owned objects with invalid field in select' do + authorize_with :active + get :contents, params: { + id: groups(:aproject).uuid, + limit: 100, + format: :json, + select: ["uuid", "storage_classes_desire"] + } + assert_response 422 + end + test 'get group-owned objects with additional filter matching nothing' do authorize_with :active get :contents, params: { @@ -317,7 +384,7 @@ class Arvados::V1::GroupsControllerTest < ActionController::TestCase end end - test "Collection contents don't include manifest_text" do + test "Collection contents don't include manifest_text or unsigned_manifest_text" do authorize_with :active get :contents, params: { id: groups(:aproject).uuid, @@ -328,7 +395,9 @@ class Arvados::V1::GroupsControllerTest < ActionController::TestCase refute(json_response["items"].any? { |c| not c["portable_data_hash"] }, "response included an item without a portable data hash") refute(json_response["items"].any? { |c| c.include?("manifest_text") }, - "response included an item with a manifest text") + "response included an item with manifest_text") + refute(json_response["items"].any? { |c| c.include?("unsigned_manifest_text") }, + "response included an item with unsigned_manifest_text") end test 'get writable_by list for owned group' do @@ -401,15 +470,15 @@ class Arvados::V1::GroupsControllerTest < ActionController::TestCase assert_not_equal(new_project['uuid'], groups(:aproject).uuid, "create returned same uuid as existing project") - assert_match(/^A Project \(\d{4}-\d\d-\d\dT\d\d:\d\d:\d\d\.\d{3}Z\)$/, + assert_match(/^A Project \(#{new_project['uuid'][-15..-1]}\)$/, new_project['name']) end [ [['owner_uuid', '!=', 'zzzzz-tpzed-xurymjxw79nv3jz'], 200, - 'zzzzz-d1hrv-subprojpipeline', 'zzzzz-d1hrv-1xfj6xkicf2muk2'], - [["pipeline_instances.state", "not in", ["Complete", "Failed"]], 200, - 'zzzzz-d1hrv-1xfj6xkicf2muk2', 'zzzzz-d1hrv-i3e77t9z5y8j9cc'], + 'zzzzz-j7d0g-publicfavorites', 'zzzzz-xvhdp-cr4queuedcontnr'], + [["container_requests.state", "not in", ["Final"]], 200, + 'zzzzz-xvhdp-cr4queuedcontnr', 'zzzzz-xvhdp-cr4completedctr'], [['container_requests.requesting_container_uuid', '=', nil], 200, 'zzzzz-xvhdp-cr4queuedcontnr', 'zzzzz-xvhdp-cr4requestercn2'], [['container_requests.no_such_column', '=', nil], 422], @@ -430,24 +499,17 @@ class Arvados::V1::GroupsControllerTest < ActionController::TestCase end end - test 'get contents with jobs and pipeline instances disabled' do - Rails.configuration.API.DisabledAPIs = {'jobs.index'=>{}, 'pipeline_instances.index'=>{}} - - authorize_with :active - get :contents, params: { - id: groups(:aproject).uuid, - format: :json, - } - check_project_contents_response %w'arvados#pipelineInstance arvados#job' - end - test 'get contents with low max_index_database_read' do # Some result will certainly have at least 12 bytes in a - # restricted column + # restricted column. + # + # We cannot use collections.manifest_text to test this, because + # GroupsController refuses to select manifest_text, because + # controller doesn't sign manifests in a groups#contents response. Rails.configuration.API.MaxIndexDatabaseRead = 12 authorize_with :active get :contents, params: { - id: groups(:aproject).uuid, + uuid: users(:active).uuid, format: :json, } assert_response :success @@ -503,11 +565,60 @@ class Arvados::V1::GroupsControllerTest < ActionController::TestCase assert_includes(owners, groups(:asubproject).uuid) end + [:afiltergroup, :private_role].each do |grp| + test "delete non-project group #{grp}" do + authorize_with :admin + assert_not_nil Group.find_by_uuid(groups(grp).uuid) + assert !Group.find_by_uuid(groups(grp).uuid).is_trashed + post :destroy, params: { + id: groups(grp).uuid, + format: :json, + } + assert_response :success + # Should not be trashed + assert_nil Group.find_by_uuid(groups(grp).uuid) + end + end + + [ + [false, :inactive, :private_role, false], + [false, :spectator, :private_role, false], + [false, :admin, :private_role, true], + [true, :inactive, :private_role, false], + [true, :spectator, :private_role, true], + [true, :admin, :private_role, true], + # project (non-role) groups are invisible even when RoleGroupsVisibleToAll is true + [true, :inactive, :private, false], + [true, :spectator, :private, false], + [true, :admin, :private, true], + ].each do |visibleToAll, userFixture, groupFixture, visible| + test "with RoleGroupsVisibleToAll=#{visibleToAll}, #{groupFixture} group is #{visible ? '' : 'in'}visible to #{userFixture} user" do + Rails.configuration.Users.RoleGroupsVisibleToAll = visibleToAll + authorize_with userFixture + get :show, params: {id: groups(groupFixture).uuid, format: :json} + if visible + assert_response :success + else + assert_response 404 + end + end + end + ### trashed project tests ### - [:active, :admin].each do |auth| + # + # The structure is + # + # trashed_project (zzzzz-j7d0g-trashedproject1) + # trashed_subproject (zzzzz-j7d0g-trashedproject2) + # trashed_subproject3 (zzzzz-j7d0g-trashedproject3) + # zzzzz-xvhdp-cr5trashedcontr + + [:active, + :admin].each do |auth| # project: to query, to untrash, is visible, parent contents listing success - [[:trashed_project, [], false, true], + [ + [:trashed_project, [], false, true], [:trashed_project, [:trashed_project], true, true], [:trashed_subproject, [], false, false], [:trashed_subproject, [:trashed_project], true, true], @@ -677,7 +788,7 @@ class Arvados::V1::GroupsControllerTest < ActionController::TestCase ensure_unique_name: true } assert_response :success - assert_match /^trashed subproject 3 \(\d{4}-\d\d-\d\d.*?Z\)$/, json_response['name'] + assert_match /^trashed subproject 3 \(#{json_response['uuid'][-15..-1]}\)$/, json_response['name'] end test "move trashed subproject to new owner #{auth}" do @@ -696,6 +807,28 @@ class Arvados::V1::GroupsControllerTest < ActionController::TestCase end end + # the group class overrides the destroy method. Make sure that the destroyed + # object is returned + [ + {group_class: "project"}, + {group_class: "role"}, + {group_class: "filter", properties: {"filters":[]}}, + ].each do |params| + test "destroy group #{params} returns object" do + authorize_with :active + + group = Group.create!(params) + + post :destroy, params: { + id: group.uuid, + format: :json, + } + assert_response :success + assert_not_nil json_response + assert_equal group.uuid, json_response["uuid"] + end + end + test 'get shared owned by another user' do authorize_with :user_bar_in_sharing_group @@ -736,20 +869,23 @@ class Arvados::V1::GroupsControllerTest < ActionController::TestCase assert_equal 0, json_response['included'].length end - test 'get shared, owned by non-project' do + test 'get shared, add permission link' do authorize_with :user_bar_in_sharing_group act_as_system_user do - Group.find_by_uuid(groups(:project_owned_by_foo).uuid).update!(owner_uuid: groups(:group_for_sharing_tests).uuid) + Link.create!(tail_uuid: groups(:group_for_sharing_tests).uuid, + head_uuid: groups(:project_owned_by_foo).uuid, + link_class: 'permission', + name: 'can_manage') end get :shared, params: {:filters => [["group_class", "=", "project"]], :include => "owner_uuid"} assert_equal 1, json_response['items'].length - assert_equal json_response['items'][0]["uuid"], groups(:project_owned_by_foo).uuid + assert_equal groups(:project_owned_by_foo).uuid, json_response['items'][0]["uuid"] assert_equal 1, json_response['included'].length - assert_equal json_response['included'][0]["uuid"], groups(:group_for_sharing_tests).uuid + assert_equal users(:user_foo_in_sharing_group).uuid, json_response['included'][0]["uuid"] end ### contents with exclude_home_project @@ -800,20 +936,24 @@ class Arvados::V1::GroupsControllerTest < ActionController::TestCase assert_equal 0, json_response['included'].length end - test 'contents, exclude home, owned by non-project' do + test 'contents, exclude home, add permission link' do authorize_with :user_bar_in_sharing_group act_as_system_user do - Group.find_by_uuid(groups(:project_owned_by_foo).uuid).update!(owner_uuid: groups(:group_for_sharing_tests).uuid) + Link.create!(tail_uuid: groups(:group_for_sharing_tests).uuid, + head_uuid: groups(:project_owned_by_foo).uuid, + link_class: 'permission', + name: 'can_manage') end get :contents, params: {:include => "owner_uuid", :exclude_home_project => true} + assert_response 200 assert_equal 1, json_response['items'].length - assert_equal json_response['items'][0]["uuid"], groups(:project_owned_by_foo).uuid + assert_equal groups(:project_owned_by_foo).uuid, json_response['items'][0]["uuid"] assert_equal 1, json_response['included'].length - assert_equal json_response['included'][0]["uuid"], groups(:group_for_sharing_tests).uuid + assert_equal users(:user_foo_in_sharing_group).uuid, json_response['included'][0]["uuid"] end test 'contents, exclude home, with parent specified' do @@ -823,4 +963,60 @@ class Arvados::V1::GroupsControllerTest < ActionController::TestCase assert_response 422 end + + [[false, 'owner_uuid'], + [false, []], + [false, ''], + [true, 'container_uuid'], + [true, ['container_uuid']], + [true, ['owner_uuid', 'container_uuid'], ['uuid', 'container_uuid', 'state', 'output']], + ].each do |check_container_included, include_param, select_param| + test "contents, include=#{include_param.inspect}" do + authorize_with :active + get :contents, params: { + :id => users(:active).uuid, + :include => include_param, + :limit => 1000, + :select => select_param, + } + assert_response 200 + if include_param.empty? + assert_equal false, json_response.include?('included') + return + end + incl = {} + json_response['included'].andand.each do |ctr| + incl[ctr['uuid']] = ctr + end + next if !check_container_included + checked_crs = 0 + json_response['items'].each do |item| + next if !item['container_uuid'] + assert_equal item['container_uuid'], incl[item['container_uuid']]['uuid'] + assert_not_empty incl[item['container_uuid']]['state'] + checked_crs += 1 + end + assert_operator 0, :<, checked_crs + end + end + + test "include_trash does not return trash inside frozen project" do + authorize_with :active + trashtime = Time.now - 1.second + outerproj = Group.create!(group_class: 'project') + innerproj = Group.create!(group_class: 'project', owner_uuid: outerproj.uuid) + innercoll = Collection.create!(name: 'inner-not-trashed', owner_uuid: innerproj.uuid) + innertrash = Collection.create!(name: 'inner-trashed', owner_uuid: innerproj.uuid, trash_at: trashtime) + innertrashproj = Group.create!(group_class: 'project', name: 'inner-trashed-proj', owner_uuid: innerproj.uuid, trash_at: trashtime) + outertrash = Collection.create!(name: 'outer-trashed', owner_uuid: outerproj.uuid, trash_at: trashtime) + innerproj.update!(frozen_by_uuid: users(:active).uuid) + get :contents, params: {id: outerproj.uuid, include_trash: true, recursive: true} + assert_response :success + uuids = json_response['items'].collect { |item| item['uuid'] } + assert_includes uuids, outertrash.uuid + assert_includes uuids, innerproj.uuid + assert_includes uuids, innercoll.uuid + refute_includes uuids, innertrash.uuid + refute_includes uuids, innertrashproj.uuid + end end