19146: Add can_write/can_manage to users#list, fix select=can_*.
[arvados.git] / services / api / test / functional / arvados / v1 / links_controller_test.rb
index b4b78168f2444eb169d00c148bf076418f5830aa..8f1d37224f7e25c689a071274652b2a7e12db8e4 100644 (file)
@@ -1,18 +1,26 @@
+# Copyright (C) The Arvados Authors. All rights reserved.
+#
+# SPDX-License-Identifier: AGPL-3.0
+
 require 'test_helper'
 
 class Arvados::V1::LinksControllerTest < ActionController::TestCase
 
-  test "no symbol keys in serialized hash" do
-    link = {
-      properties: {username: 'testusername'},
-      link_class: 'test',
-      name: 'encoding',
-      tail_uuid: users(:admin).uuid,
-      head_uuid: virtual_machines(:testvm).uuid
-    }
-    authorize_with :admin
-    [link, link.to_json].each do |formatted_link|
-      post :create, link: formatted_link
+  ['link', 'link_json'].each do |formatted_link|
+    test "no symbol keys in serialized hash #{formatted_link}" do
+      link = {
+        properties: {username: 'testusername'},
+        link_class: 'test',
+        name: 'encoding',
+        tail_uuid: users(:admin).uuid,
+        head_uuid: virtual_machines(:testvm).uuid
+      }
+      authorize_with :admin
+      if formatted_link == 'link_json'
+        post :create, params: {link: link.to_json}
+      else
+        post :create, params: {link: link}
+      end
       assert_response :success
       assert_not_nil assigns(:object)
       assert_equal 'testusername', assigns(:object).properties['username']
@@ -24,7 +32,7 @@ class Arvados::V1::LinksControllerTest < ActionController::TestCase
     {nil: nil, bogus: 2.days.ago}.each do |bogustype, bogusvalue|
       test "cannot set #{bogustype} #{attr} in create" do
         authorize_with :active
-        post :create, {
+        post :create, params: {
           link: {
             properties: {},
             link_class: 'test',
@@ -38,7 +46,7 @@ class Arvados::V1::LinksControllerTest < ActionController::TestCase
       test "cannot set #{bogustype} #{attr} in update" do
         really_created_at = links(:test_timestamps).created_at
         authorize_with :active
-        put :update, {
+        put :update, params: {
           id: links(:test_timestamps).uuid,
           link: {
             :properties => {test: 'test'},
@@ -65,7 +73,7 @@ class Arvados::V1::LinksControllerTest < ActionController::TestCase
       head_uuid: 'zzzzz-tpzed-xyzxyzxerrrorxx'
     }
     authorize_with :admin
-    post :create, link: link
+    post :create, params: {link: link}
     assert_response 422
   end
 
@@ -77,7 +85,7 @@ class Arvados::V1::LinksControllerTest < ActionController::TestCase
       tail_uuid: 'zzzzz-tpzed-xyzxyzxerrrorxx'
     }
     authorize_with :admin
-    post :create, link: link
+    post :create, params: {link: link}
     assert_response 422
   end
 
@@ -89,7 +97,7 @@ class Arvados::V1::LinksControllerTest < ActionController::TestCase
       tail_uuid: users(:spectator).uuid,
     }
     authorize_with :admin
-    post :create, link: link
+    post :create, params: {link: link}
     assert_response :success
     l = JSON.parse(@response.body)
     assert 'arvados#user', l['head_kind']
@@ -106,7 +114,7 @@ class Arvados::V1::LinksControllerTest < ActionController::TestCase
       tail_kind: "arvados#user",
     }
     authorize_with :admin
-    post :create, link: link
+    post :create, params: {link: link}
     assert_response :success
     l = JSON.parse(@response.body)
     assert 'arvados#user', l['head_kind']
@@ -118,38 +126,58 @@ class Arvados::V1::LinksControllerTest < ActionController::TestCase
       link_class: 'test',
       name: 'stuff',
       head_uuid: users(:active).uuid,
-      tail_uuid: virtual_machines(:testvm2).uuid
+      tail_uuid: authorized_keys(:admin).uuid,
     }
     authorize_with :active
-    post :create, link: link
+    post :create, params: {link: link}
     assert_response 422
   end
 
   test "filter links with 'is_a' operator" do
     authorize_with :admin
-    get :index, {
+    get :index, params: {
       filters: [ ['tail_uuid', 'is_a', 'arvados#user'] ]
     }
     assert_response :success
     found = assigns(:objects)
     assert_not_equal 0, found.count
-    assert_equal found.count, (found.select { |f| f.tail_uuid.match /[a-z0-9]{5}-tpzed-[a-z0-9]{15}/}).count
+    assert_equal found.count, (found.select { |f| f.tail_uuid.match User.uuid_regex }).count
+  end
+
+  test "filter links with 'is_a' operator includes remote objects" do
+    authorize_with :admin
+    get :index, params: {
+      filters: [
+        ['tail_uuid', 'is_a', 'arvados#user'],
+        ['link_class', '=', 'permission'],
+        ['name', '=', 'can_read'],
+        ['head_uuid', '=', collections(:foo_file).uuid],
+      ]
+    }
+    assert_response :success
+    found = assigns(:objects)
+    assert_not_equal 0, found.count
+    assert_includes(found.map(&:tail_uuid),
+                    users(:federated_active).uuid)
   end
 
   test "filter links with 'is_a' operator with more than one" do
     authorize_with :admin
-    get :index, {
+    get :index, params: {
       filters: [ ['tail_uuid', 'is_a', ['arvados#user', 'arvados#group'] ] ],
     }
     assert_response :success
     found = assigns(:objects)
     assert_not_equal 0, found.count
-    assert_equal found.count, (found.select { |f| f.tail_uuid.match /[a-z0-9]{5}-(tpzed|j7d0g)-[a-z0-9]{15}/}).count
+    assert_equal found.count, (found.select { |f|
+                                 f.tail_uuid.match User.uuid_regex or
+                                 f.tail_uuid.match Group.uuid_regex
+                               }).count
   end
 
   test "filter links with 'is_a' operator with bogus type" do
     authorize_with :admin
-    get :index, {
+    get :index, params: {
       filters: [ ['tail_uuid', 'is_a', ['arvados#bogus'] ] ],
     }
     assert_response :success
@@ -159,57 +187,57 @@ class Arvados::V1::LinksControllerTest < ActionController::TestCase
 
   test "filter links with 'is_a' operator with collection" do
     authorize_with :admin
-    get :index, {
+    get :index, params: {
       filters: [ ['head_uuid', 'is_a', ['arvados#collection'] ] ],
     }
     assert_response :success
     found = assigns(:objects)
     assert_not_equal 0, found.count
-    assert_equal found.count, (found.select { |f| f.head_uuid.match /.....-4zz18-.............../}).count
+    assert_equal found.count, (found.select { |f| f.head_uuid.match Collection.uuid_regex}).count
   end
 
   test "test can still use where tail_kind" do
     authorize_with :admin
-    get :index, {
+    get :index, params: {
       where: { tail_kind: 'arvados#user' }
     }
     assert_response :success
     found = assigns(:objects)
     assert_not_equal 0, found.count
-    assert_equal found.count, (found.select { |f| f.tail_uuid.match /[a-z0-9]{5}-tpzed-[a-z0-9]{15}/}).count
+    assert_equal found.count, (found.select { |f| f.tail_uuid.match User.uuid_regex }).count
   end
 
   test "test can still use where head_kind" do
     authorize_with :admin
-    get :index, {
+    get :index, params: {
       where: { head_kind: 'arvados#user' }
     }
     assert_response :success
     found = assigns(:objects)
     assert_not_equal 0, found.count
-    assert_equal found.count, (found.select { |f| f.head_uuid.match /[a-z0-9]{5}-tpzed-[a-z0-9]{15}/}).count
+    assert_equal found.count, (found.select { |f| f.head_uuid.match User.uuid_regex }).count
   end
 
   test "test can still use filter tail_kind" do
     authorize_with :admin
-    get :index, {
+    get :index, params: {
       filters: [ ['tail_kind', '=', 'arvados#user'] ]
     }
     assert_response :success
     found = assigns(:objects)
     assert_not_equal 0, found.count
-    assert_equal found.count, (found.select { |f| f.tail_uuid.match /[a-z0-9]{5}-tpzed-[a-z0-9]{15}/}).count
+    assert_equal found.count, (found.select { |f| f.tail_uuid.match User.uuid_regex }).count
   end
 
   test "test can still use filter head_kind" do
     authorize_with :admin
-    get :index, {
+    get :index, params: {
       filters: [ ['head_kind', '=', 'arvados#user'] ]
     }
     assert_response :success
     found = assigns(:objects)
     assert_not_equal 0, found.count
-    assert_equal found.count, (found.select { |f| f.head_uuid.match /[a-z0-9]{5}-tpzed-[a-z0-9]{15}/}).count
+    assert_equal found.count, (found.select { |f| f.head_uuid.match User.uuid_regex }).count
   end
 
   test "head_kind matches head_uuid" do
@@ -222,7 +250,7 @@ class Arvados::V1::LinksControllerTest < ActionController::TestCase
       tail_kind: "arvados#user",
     }
     authorize_with :admin
-    post :create, link: link
+    post :create, params: {link: link}
     assert_response 422
   end
 
@@ -236,7 +264,7 @@ class Arvados::V1::LinksControllerTest < ActionController::TestCase
       tail_kind: "arvados#user",
     }
     authorize_with :admin
-    post :create, link: link
+    post :create, params: {link: link}
     assert_response 422
   end
 
@@ -251,7 +279,7 @@ class Arvados::V1::LinksControllerTest < ActionController::TestCase
       properties: {username: "repo_and_user_name"}
     }
     authorize_with :admin
-    post :create, link: link
+    post :create, params: {link: link}
     assert_response 422
   end
 
@@ -266,14 +294,14 @@ class Arvados::V1::LinksControllerTest < ActionController::TestCase
       properties: {username: "repo_and_user_name"}
     }
     authorize_with :admin
-    post :create, link: link
+    post :create, params: {link: link}
     assert_response :success
   end
 
   test "project owner can show a project permission" do
     uuid = links(:project_viewer_can_read_project).uuid
     authorize_with :active
-    get :show, id: uuid
+    get :show, params: {id: uuid}
     assert_response :success
     assert_equal(uuid, assigns(:object).andand.uuid)
   end
@@ -281,25 +309,25 @@ class Arvados::V1::LinksControllerTest < ActionController::TestCase
   test "admin can show a project permission" do
     uuid = links(:project_viewer_can_read_project).uuid
     authorize_with :admin
-    get :show, id: uuid
+    get :show, params: {id: uuid}
     assert_response :success
     assert_equal(uuid, assigns(:object).andand.uuid)
   end
 
   test "project viewer can't show others' project permissions" do
     authorize_with :project_viewer
-    get :show, id: links(:admin_can_write_aproject).uuid
+    get :show, params: {id: links(:admin_can_write_aproject).uuid}
     assert_response 404
   end
 
   test "requesting a nonexistent link returns 404" do
     authorize_with :active
-    get :show, id: 'zzzzz-zzzzz-zzzzzzzzzzzzzzz'
+    get :show, params: {id: 'zzzzz-zzzzz-zzzzzzzzzzzzzzz'}
     assert_response 404
   end
 
-  test "retrieve all permissions using generic links index api" do
-    skip "(not implemented)"
+  # not implemented
+  skip "retrieve all permissions using generic links index api" do
     # Links.readable_by() does not return the full set of permission
     # links that are visible to a user (i.e., all permission links
     # whose head_uuid references an object for which the user has
@@ -309,8 +337,10 @@ class Arvados::V1::LinksControllerTest < ActionController::TestCase
     # It is possible to retrieve the full set of permissions for a
     # single object via /arvados/v1/permissions.
     authorize_with :active
-    get :index, filters: [['link_class', '=', 'permission'],
-                          ['head_uuid', '=', groups(:aproject).uuid]]
+    get :index, params: {
+      filters: [['link_class', '=', 'permission'],
+                ['head_uuid', '=', groups(:aproject).uuid]]
+    }
     assert_response :success
     assert_not_nil assigns(:objects)
     assert_includes(assigns(:objects).map(&:uuid),
@@ -319,8 +349,10 @@ class Arvados::V1::LinksControllerTest < ActionController::TestCase
 
   test "admin can index project permissions" do
     authorize_with :admin
-    get :index, filters: [['link_class', '=', 'permission'],
-                          ['head_uuid', '=', groups(:aproject).uuid]]
+    get :index, params: {
+      filters: [['link_class', '=', 'permission'],
+                ['head_uuid', '=', groups(:aproject).uuid]]
+    }
     assert_response :success
     assert_not_nil assigns(:objects)
     assert_includes(assigns(:objects).map(&:uuid),
@@ -329,11 +361,31 @@ class Arvados::V1::LinksControllerTest < ActionController::TestCase
 
   test "project viewer can't index others' project permissions" do
     authorize_with :project_viewer
-    get :index, filters: [['link_class', '=', 'permission'],
-                          ['head_uuid', '=', groups(:aproject).uuid],
-                          ['tail_uuid', '!=', users(:project_viewer).uuid]]
+    get :index, params: {
+      filters: [['link_class', '=', 'permission'],
+                ['head_uuid', '=', groups(:aproject).uuid],
+                ['tail_uuid', '!=', users(:project_viewer).uuid]]
+    }
     assert_response :success
     assert_not_nil assigns(:objects)
     assert_empty assigns(:objects)
   end
+
+  # Granting permissions.
+  test "grant can_read on project to other users in group" do
+    authorize_with :user_foo_in_sharing_group
+
+    refute users(:user_bar_in_sharing_group).can?(read: collections(:collection_owned_by_foo).uuid)
+
+    post :create, params: {
+      link: {
+        tail_uuid: users(:user_bar_in_sharing_group).uuid,
+        link_class: 'permission',
+        name: 'can_read',
+        head_uuid: collections(:collection_owned_by_foo).uuid,
+      }
+    }
+    assert_response :success
+    assert users(:user_bar_in_sharing_group).can?(read: collections(:collection_owned_by_foo).uuid)
+  end
 end