Merge branch '12167-python-request-id'
[arvados.git] / services / api / test / functional / arvados / v1 / groups_controller_test.rb
index 6623c726df01923b7227d33f17e6f2098cab649e..3442eda2447aa1e75ecc254b3ffcfb2392853a8f 100644 (file)
@@ -1,3 +1,7 @@
+# Copyright (C) The Arvados Authors. All rights reserved.
+#
+# SPDX-License-Identifier: AGPL-3.0
+
 require 'test_helper'
 
 class Arvados::V1::GroupsControllerTest < ActionController::TestCase
@@ -55,12 +59,12 @@ class Arvados::V1::GroupsControllerTest < ActionController::TestCase
     assert_equal 0, json_response['items_available']
   end
 
-  def check_project_contents_response
+  def check_project_contents_response disabled_kinds=[]
     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'
+    expect_kinds = %w'arvados#group arvados#specimen arvados#pipelineTemplate arvados#job' - disabled_kinds
     assert_equal expect_kinds, (expect_kinds & kinds)
 
     json_response['items'].each do |i|
@@ -69,6 +73,10 @@ 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
@@ -112,6 +120,7 @@ class Arvados::V1::GroupsControllerTest < ActionController::TestCase
     authorize_with :active
     get :contents, {
       format: :json,
+      limit: 200,
       id: users(:active).uuid
     }
     assert_response :success
@@ -376,9 +385,8 @@ class Arvados::V1::GroupsControllerTest < ActionController::TestCase
     assert_not_equal(new_project['uuid'],
                      groups(:aproject).uuid,
                      "create returned same uuid as existing project")
-    assert_equal(new_project['name'],
-                 'A Project (2)',
-                 "new project name '#{new_project['name']}' was expected to be 'A Project (2)'")
+    assert_match(/^A Project \(\d{4}-\d\d-\d\dT\d\d:\d\d:\d\d\.\d{3}Z\)$/,
+                 new_project['name'])
   end
 
   test "unsharing a project results in hiding it from previously shared user" do
@@ -389,7 +397,7 @@ class Arvados::V1::GroupsControllerTest < ActionController::TestCase
     assert_response :success
 
     # verify that the user can no longer see the project
-    @counter = 0  # Reset executed action counter
+    @test_counter = 0  # Reset executed action counter
     @controller = Arvados::V1::GroupsController.new
     authorize_with :project_viewer
     get :index, filters: [['group_class', '=', 'project']], format: :json
@@ -401,7 +409,7 @@ class Arvados::V1::GroupsControllerTest < ActionController::TestCase
     assert_equal false, found_projects.include?(groups(:starred_and_shared_active_user_project).uuid)
 
     # share the project
-    @counter = 0
+    @test_counter = 0
     @controller = Arvados::V1::LinksController.new
     authorize_with :system_user
     post :create, link: {
@@ -412,7 +420,7 @@ class Arvados::V1::GroupsControllerTest < ActionController::TestCase
     }
 
     # verify that project_viewer user can now see shared project again
-    @counter = 0
+    @test_counter = 0
     @controller = Arvados::V1::GroupsController.new
     authorize_with :project_viewer
     get :index, filters: [['group_class', '=', 'project']], format: :json
@@ -423,4 +431,278 @@ class Arvados::V1::GroupsControllerTest < ActionController::TestCase
     end
     assert_equal true, found_projects.include?(groups(:starred_and_shared_active_user_project).uuid)
   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'],
+    [['container_requests.requesting_container_uuid', '=', nil], 200,
+        'zzzzz-xvhdp-cr4queuedcontnr', 'zzzzz-xvhdp-cr4requestercn2'],
+    [['container_requests.no_such_column', '=', nil], 422],
+    [['container_requests.', '=', nil], 422],
+    [['.requesting_container_uuid', '=', nil], 422],
+    [['no_such_table.uuid', '!=', 'zzzzz-tpzed-xurymjxw79nv3jz'], 422],
+  ].each do |filter, expect_code, expect_uuid, not_expect_uuid|
+    test "get contents with '#{filter}' filter" do
+      authorize_with :active
+      get :contents, filters: [filter], format: :json
+      assert_response expect_code
+      if expect_code == 200
+        assert_not_empty json_response['items']
+        item_uuids = json_response['items'].collect {|item| item['uuid']}
+        assert_includes(item_uuids, expect_uuid)
+        assert_not_includes(item_uuids, not_expect_uuid)
+      end
+    end
+  end
+
+  test 'get contents with jobs and pipeline instances disabled' do
+    Rails.configuration.disable_api_methods = ['jobs.index', 'pipeline_instances.index']
+
+    authorize_with :active
+    get :contents, {
+      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
+    Rails.configuration.max_index_database_read = 12
+    authorize_with :active
+    get :contents, {
+          id: groups(:aproject).uuid,
+          format: :json,
+        }
+    assert_response :success
+    assert_not_empty(json_response['items'])
+    assert_operator(json_response['items'].count,
+                    :<, json_response['items_available'])
+  end
+
+  test 'get contents, recursive=true' do
+    authorize_with :active
+    params = {
+      id: groups(:aproject).uuid,
+      recursive: true,
+      format: :json,
+    }
+    get :contents, params
+    owners = json_response['items'].map do |item|
+      item['owner_uuid']
+    end
+    assert_includes(owners, groups(:aproject).uuid)
+    assert_includes(owners, groups(:asubproject).uuid)
+  end
+
+  [false, nil].each do |recursive|
+    test "get contents, recursive=#{recursive.inspect}" do
+      authorize_with :active
+      params = {
+        id: groups(:aproject).uuid,
+        format: :json,
+      }
+      params[:recursive] = false if recursive == false
+      get :contents, params
+      owners = json_response['items'].map do |item|
+        item['owner_uuid']
+      end
+      assert_includes(owners, groups(:aproject).uuid)
+      refute_includes(owners, groups(:asubproject).uuid)
+    end
+  end
+
+  test 'get home project contents, recursive=true' do
+    authorize_with :active
+    get :contents, {
+          id: users(:active).uuid,
+          recursive: true,
+          format: :json,
+        }
+    owners = json_response['items'].map do |item|
+      item['owner_uuid']
+    end
+    assert_includes(owners, users(:active).uuid)
+    assert_includes(owners, groups(:aproject).uuid)
+    assert_includes(owners, groups(:asubproject).uuid)
+  end
+
+  ### trashed project tests ###
+
+  [:active, :admin].each do |auth|
+    # project: to query,    to untrash,    is visible, parent contents listing success
+    [[:trashed_project,     [],                 false, true],
+     [:trashed_project,     [:trashed_project], true,  true],
+     [:trashed_subproject,  [],                 false, false],
+     [:trashed_subproject,  [:trashed_project], true,  true],
+     [:trashed_subproject3, [:trashed_project], false, true],
+     [:trashed_subproject3, [:trashed_subproject3], false, false],
+     [:trashed_subproject3, [:trashed_project, :trashed_subproject3], true, true],
+    ].each do |project, untrash, visible, success|
+
+      test "contents listing #{project} #{untrash} as #{auth}" do
+        authorize_with auth
+        untrash.each do |pr|
+          Group.find_by_uuid(groups(pr).uuid).update! is_trashed: false
+        end
+        get :contents, {
+              id: groups(project).owner_uuid,
+              format: :json
+            }
+        if success
+          assert_response :success
+          item_uuids = json_response['items'].map do |item|
+            item['uuid']
+          end
+          if visible
+            assert_includes(item_uuids, groups(project).uuid)
+          else
+            assert_not_includes(item_uuids, groups(project).uuid)
+          end
+        else
+          assert_response 404
+        end
+      end
+
+      test "contents of #{project} #{untrash} as #{auth}" do
+        authorize_with auth
+        untrash.each do |pr|
+          Group.find_by_uuid(groups(pr).uuid).update! is_trashed: false
+        end
+        get :contents, {
+              id: groups(project).uuid,
+              format: :json
+            }
+        if visible
+          assert_response :success
+        else
+          assert_response 404
+        end
+      end
+
+      test "index #{project} #{untrash} as #{auth}" do
+        authorize_with auth
+        untrash.each do |pr|
+          Group.find_by_uuid(groups(pr).uuid).update! is_trashed: false
+        end
+        get :index, {
+              format: :json,
+            }
+        assert_response :success
+        item_uuids = json_response['items'].map do |item|
+          item['uuid']
+        end
+        if visible
+          assert_includes(item_uuids, groups(project).uuid)
+        else
+          assert_not_includes(item_uuids, groups(project).uuid)
+        end
+      end
+
+      test "show #{project} #{untrash} as #{auth}" do
+        authorize_with auth
+        untrash.each do |pr|
+          Group.find_by_uuid(groups(pr).uuid).update! is_trashed: false
+        end
+        get :show, {
+              id: groups(project).uuid,
+              format: :json
+            }
+        if visible
+          assert_response :success
+        else
+          assert_response 404
+        end
+      end
+
+      test "show include_trash #{project} #{untrash} as #{auth}" do
+        authorize_with auth
+        untrash.each do |pr|
+          Group.find_by_uuid(groups(pr).uuid).update! is_trashed: false
+        end
+        get :show, {
+              id: groups(project).uuid,
+              format: :json,
+              include_trash: true
+            }
+        assert_response :success
+      end
+
+      test "index include_trash #{project} #{untrash} as #{auth}" do
+        authorize_with auth
+        untrash.each do |pr|
+          Group.find_by_uuid(groups(pr).uuid).update! is_trashed: false
+        end
+        get :index, {
+              format: :json,
+              include_trash: true
+            }
+        assert_response :success
+        item_uuids = json_response['items'].map do |item|
+          item['uuid']
+        end
+        assert_includes(item_uuids, groups(project).uuid)
+      end
+    end
+
+    test "delete project #{auth}" do
+      authorize_with auth
+      [:trashed_project].each do |pr|
+        Group.find_by_uuid(groups(pr).uuid).update! is_trashed: false
+      end
+      assert !Group.find_by_uuid(groups(:trashed_project).uuid).is_trashed
+      post :destroy, {
+            id: groups(:trashed_project).uuid,
+            format: :json,
+          }
+      assert_response :success
+      assert Group.find_by_uuid(groups(:trashed_project).uuid).is_trashed
+    end
+
+    test "untrash project #{auth}" do
+      authorize_with auth
+      assert Group.find_by_uuid(groups(:trashed_project).uuid).is_trashed
+      post :untrash, {
+            id: groups(:trashed_project).uuid,
+            format: :json,
+          }
+      assert_response :success
+      assert !Group.find_by_uuid(groups(:trashed_project).uuid).is_trashed
+    end
+
+    test "untrash project with name conflict #{auth}" do
+      authorize_with auth
+      [:trashed_project].each do |pr|
+        Group.find_by_uuid(groups(pr).uuid).update! is_trashed: false
+      end
+      gc = Group.create!({owner_uuid: "zzzzz-j7d0g-trashedproject1",
+                         name: "trashed subproject 3",
+                         group_class: "project"})
+      post :untrash, {
+            id: groups(:trashed_subproject3).uuid,
+            format: :json,
+            ensure_unique_name: true
+           }
+      assert_response :success
+      assert_match /^trashed subproject 3 \(\d{4}-\d\d-\d\d.*?Z\)$/, json_response['name']
+    end
+
+    test "move trashed subproject to new owner #{auth}" do
+      authorize_with auth
+      assert_nil Group.readable_by(users(auth)).where(uuid: groups(:trashed_subproject).uuid).first
+      put :update, {
+            id: groups(:trashed_subproject).uuid,
+            group: {
+              owner_uuid: users(:active).uuid
+            },
+            include_trash: true,
+            format: :json,
+          }
+      assert_response :success
+      assert_not_nil Group.readable_by(users(auth)).where(uuid: groups(:trashed_subproject).uuid).first
+    end
+  end
 end