14008: Merge branch 'master' into 14008-containers-index
[arvados.git] / services / api / test / functional / arvados / v1 / groups_controller_test.rb
1 # Copyright (C) The Arvados Authors. All rights reserved.
2 #
3 # SPDX-License-Identifier: AGPL-3.0
4
5 require 'test_helper'
6
7 class Arvados::V1::GroupsControllerTest < ActionController::TestCase
8
9   test "attempt to delete group without read or write access" do
10     authorize_with :active
11     post :destroy, id: groups(:empty_lonely_group).uuid
12     assert_response 404
13   end
14
15   test "attempt to delete group without write access" do
16     authorize_with :active
17     post :destroy, id: groups(:all_users).uuid
18     assert_response 403
19   end
20
21   test "get list of projects" do
22     authorize_with :active
23     get :index, filters: [['group_class', '=', 'project']], format: :json
24     assert_response :success
25     group_uuids = []
26     json_response['items'].each do |group|
27       assert_equal 'project', group['group_class']
28       group_uuids << group['uuid']
29     end
30     assert_includes group_uuids, groups(:aproject).uuid
31     assert_includes group_uuids, groups(:asubproject).uuid
32     assert_not_includes group_uuids, groups(:system_group).uuid
33     assert_not_includes group_uuids, groups(:private).uuid
34   end
35
36   test "get list of groups that are not projects" do
37     authorize_with :active
38     get :index, filters: [['group_class', '!=', 'project']], format: :json
39     assert_response :success
40     group_uuids = []
41     json_response['items'].each do |group|
42       assert_not_equal 'project', group['group_class']
43       group_uuids << group['uuid']
44     end
45     assert_not_includes group_uuids, groups(:aproject).uuid
46     assert_not_includes group_uuids, groups(:asubproject).uuid
47     assert_includes group_uuids, groups(:private).uuid
48     assert_includes group_uuids, groups(:group_with_no_class).uuid
49   end
50
51   test "get list of groups with bogus group_class" do
52     authorize_with :active
53     get :index, {
54       filters: [['group_class', '=', 'nogrouphasthislittleclass']],
55       format: :json,
56     }
57     assert_response :success
58     assert_equal [], json_response['items']
59     assert_equal 0, json_response['items_available']
60   end
61
62   def check_project_contents_response disabled_kinds=[]
63     assert_response :success
64     assert_operator 2, :<=, json_response['items_available']
65     assert_operator 2, :<=, json_response['items'].count
66     kinds = json_response['items'].collect { |i| i['kind'] }.uniq
67     expect_kinds = %w'arvados#group arvados#specimen arvados#pipelineTemplate arvados#job' - disabled_kinds
68     assert_equal expect_kinds, (expect_kinds & kinds)
69
70     json_response['items'].each do |i|
71       if i['kind'] == 'arvados#group'
72         assert(i['group_class'] == 'project',
73                "group#contents returned a non-project group")
74       end
75     end
76
77     disabled_kinds.each do |d|
78       assert_equal true, !kinds.include?(d)
79     end
80   end
81
82   test 'get group-owned objects' do
83     authorize_with :active
84     get :contents, {
85       id: groups(:aproject).uuid,
86       format: :json,
87     }
88     check_project_contents_response
89   end
90
91   test "user with project read permission can see project objects" do
92     authorize_with :project_viewer
93     get :contents, {
94       id: groups(:aproject).uuid,
95       format: :json,
96     }
97     check_project_contents_response
98   end
99
100   test "list objects across projects" do
101     authorize_with :project_viewer
102     get :contents, {
103       format: :json,
104       filters: [['uuid', 'is_a', 'arvados#specimen']]
105     }
106     assert_response :success
107     found_uuids = json_response['items'].collect { |i| i['uuid'] }
108     [[:in_aproject, true],
109      [:in_asubproject, true],
110      [:owned_by_private_group, false]].each do |specimen_fixture, should_find|
111       if should_find
112         assert_includes found_uuids, specimens(specimen_fixture).uuid, "did not find specimen fixture '#{specimen_fixture}'"
113       else
114         refute_includes found_uuids, specimens(specimen_fixture).uuid, "found specimen fixture '#{specimen_fixture}'"
115       end
116     end
117   end
118
119   test "list objects in home project" do
120     authorize_with :active
121     get :contents, {
122       format: :json,
123       limit: 200,
124       id: users(:active).uuid
125     }
126     assert_response :success
127     found_uuids = json_response['items'].collect { |i| i['uuid'] }
128     assert_includes found_uuids, specimens(:owned_by_active_user).uuid, "specimen did not appear in home project"
129     refute_includes found_uuids, specimens(:in_asubproject).uuid, "specimen appeared unexpectedly in home project"
130   end
131
132   test "user with project read permission can see project collections" do
133     authorize_with :project_viewer
134     get :contents, {
135       id: groups(:asubproject).uuid,
136       format: :json,
137     }
138     ids = json_response['items'].map { |item| item["uuid"] }
139     assert_includes ids, collections(:baz_file_in_asubproject).uuid
140   end
141
142   [
143     ['collections.name', 'asc', :<=, "name"],
144     ['collections.name', 'desc', :>=, "name"],
145     ['name', 'asc', :<=, "name"],
146     ['name', 'desc', :>=, "name"],
147     ['collections.created_at', 'asc', :<=, "created_at"],
148     ['collections.created_at', 'desc', :>=, "created_at"],
149     ['created_at', 'asc', :<=, "created_at"],
150     ['created_at', 'desc', :>=, "created_at"],
151   ].each do |column, order, operator, field|
152     test "user with project read permission can sort projects on #{column} #{order}" do
153       authorize_with :project_viewer
154       get :contents, {
155         id: groups(:asubproject).uuid,
156         format: :json,
157         filters: [['uuid', 'is_a', "arvados#collection"]],
158         order: "#{column} #{order}"
159       }
160       sorted_values = json_response['items'].collect { |item| item[field] }
161       if field == "name"
162         # Here we avoid assuming too much about the database
163         # collation. Both "alice"<"Bob" and "alice">"Bob" can be
164         # correct. Hopefully it _is_ safe to assume that if "a" comes
165         # before "b" in the ascii alphabet, "aX">"bY" is never true for
166         # any strings X and Y.
167         reliably_sortable_names = sorted_values.select do |name|
168           name[0] >= 'a' && name[0] <= 'z'
169         end.uniq do |name|
170           name[0]
171         end
172         # Preserve order of sorted_values. But do not use &=. If
173         # sorted_values has out-of-order duplicates, we want to preserve
174         # them here, so we can detect them and fail the test below.
175         sorted_values.select! do |name|
176           reliably_sortable_names.include? name
177         end
178       end
179       assert_sorted(operator, sorted_values)
180     end
181   end
182
183   def assert_sorted(operator, sorted_items)
184     actually_checked_anything = false
185     previous = nil
186     sorted_items.each do |entry|
187       if !previous.nil?
188         assert_operator(previous, operator, entry,
189                         "Entries sorted incorrectly.")
190         actually_checked_anything = true
191       end
192       previous = entry
193     end
194     assert actually_checked_anything, "Didn't even find two items to compare."
195   end
196
197   test 'list objects across multiple projects' do
198     authorize_with :project_viewer
199     get :contents, {
200       format: :json,
201       filters: [['uuid', 'is_a', 'arvados#specimen']]
202     }
203     assert_response :success
204     found_uuids = json_response['items'].collect { |i| i['uuid'] }
205     [[:in_aproject, true],
206      [:in_asubproject, true],
207      [:owned_by_private_group, false]].each do |specimen_fixture, should_find|
208       if should_find
209         assert_includes found_uuids, specimens(specimen_fixture).uuid, "did not find specimen fixture '#{specimen_fixture}'"
210       else
211         refute_includes found_uuids, specimens(specimen_fixture).uuid, "found specimen fixture '#{specimen_fixture}'"
212       end
213     end
214   end
215
216   # Even though the project_viewer tests go through other controllers,
217   # I'm putting them here so they're easy to find alongside the other
218   # project tests.
219   def check_new_project_link_fails(link_attrs)
220     @controller = Arvados::V1::LinksController.new
221     post :create, link: {
222       link_class: "permission",
223       name: "can_read",
224       head_uuid: groups(:aproject).uuid,
225     }.merge(link_attrs)
226     assert_includes(403..422, response.status)
227   end
228
229   test "user with project read permission can't add users to it" do
230     authorize_with :project_viewer
231     check_new_project_link_fails(tail_uuid: users(:spectator).uuid)
232   end
233
234   test "user with project read permission can't add items to it" do
235     authorize_with :project_viewer
236     check_new_project_link_fails(tail_uuid: collections(:baz_file).uuid)
237   end
238
239   test "user with project read permission can't rename items in it" do
240     authorize_with :project_viewer
241     @controller = Arvados::V1::LinksController.new
242     post :update, {
243       id: jobs(:running).uuid,
244       name: "Denied test name",
245     }
246     assert_includes(403..404, response.status)
247   end
248
249   test "user with project read permission can't remove items from it" do
250     @controller = Arvados::V1::PipelineTemplatesController.new
251     authorize_with :project_viewer
252     post :update, {
253       id: pipeline_templates(:two_part).uuid,
254       pipeline_template: {
255         owner_uuid: users(:project_viewer).uuid,
256       }
257     }
258     assert_response 403
259   end
260
261   test "user with project read permission can't delete it" do
262     authorize_with :project_viewer
263     post :destroy, {id: groups(:aproject).uuid}
264     assert_response 403
265   end
266
267   test 'get group-owned objects with limit' do
268     authorize_with :active
269     get :contents, {
270       id: groups(:aproject).uuid,
271       limit: 1,
272       format: :json,
273     }
274     assert_response :success
275     assert_operator 1, :<, json_response['items_available']
276     assert_equal 1, json_response['items'].count
277   end
278
279   test 'get group-owned objects with limit and offset' do
280     authorize_with :active
281     get :contents, {
282       id: groups(:aproject).uuid,
283       limit: 1,
284       offset: 12345,
285       format: :json,
286     }
287     assert_response :success
288     assert_operator 1, :<, json_response['items_available']
289     assert_equal 0, json_response['items'].count
290   end
291
292   test 'get group-owned objects with additional filter matching nothing' do
293     authorize_with :active
294     get :contents, {
295       id: groups(:aproject).uuid,
296       filters: [['uuid', 'in', ['foo_not_a_uuid','bar_not_a_uuid']]],
297       format: :json,
298     }
299     assert_response :success
300     assert_equal [], json_response['items']
301     assert_equal 0, json_response['items_available']
302   end
303
304   %w(offset limit).each do |arg|
305     ['foo', '', '1234five', '0x10', '-8'].each do |val|
306       test "Raise error on bogus #{arg} parameter #{val.inspect}" do
307         authorize_with :active
308         get :contents, {
309           :id => groups(:aproject).uuid,
310           :format => :json,
311           arg => val,
312         }
313         assert_response 422
314       end
315     end
316   end
317
318   test "Collection contents don't include manifest_text" do
319     authorize_with :active
320     get :contents, {
321       id: groups(:aproject).uuid,
322       filters: [["uuid", "is_a", "arvados#collection"]],
323       format: :json,
324     }
325     assert_response :success
326     refute(json_response["items"].any? { |c| not c["portable_data_hash"] },
327            "response included an item without a portable data hash")
328     refute(json_response["items"].any? { |c| c.include?("manifest_text") },
329            "response included an item with a manifest text")
330   end
331
332   test 'get writable_by list for owned group' do
333     authorize_with :active
334     get :show, {
335       id: groups(:aproject).uuid,
336       format: :json
337     }
338     assert_response :success
339     assert_not_nil(json_response['writable_by'],
340                    "Should receive uuid list in 'writable_by' field")
341     assert_includes(json_response['writable_by'], users(:active).uuid,
342                     "owner should be included in writable_by list")
343   end
344
345   test 'no writable_by list for group with read-only access' do
346     authorize_with :rominiadmin
347     get :show, {
348       id: groups(:testusergroup_admins).uuid,
349       format: :json
350     }
351     assert_response :success
352     assert_equal([json_response['owner_uuid']],
353                  json_response['writable_by'],
354                  "Should only see owner_uuid in 'writable_by' field")
355   end
356
357   test 'get writable_by list by admin user' do
358     authorize_with :admin
359     get :show, {
360       id: groups(:testusergroup_admins).uuid,
361       format: :json
362     }
363     assert_response :success
364     assert_not_nil(json_response['writable_by'],
365                    "Should receive uuid list in 'writable_by' field")
366     assert_includes(json_response['writable_by'],
367                     users(:admin).uuid,
368                     "Current user should be included in 'writable_by' field")
369   end
370
371   test 'creating subproject with duplicate name fails' do
372     authorize_with :active
373     post :create, {
374       group: {
375         name: 'A Project',
376         owner_uuid: users(:active).uuid,
377         group_class: 'project',
378       },
379     }
380     assert_response 422
381     response_errors = json_response['errors']
382     assert_not_nil response_errors, 'Expected error in response'
383     assert(response_errors.first.include?('duplicate key'),
384            "Expected 'duplicate key' error in #{response_errors.first}")
385   end
386
387   test 'creating duplicate named subproject succeeds with ensure_unique_name' do
388     authorize_with :active
389     post :create, {
390       group: {
391         name: 'A Project',
392         owner_uuid: users(:active).uuid,
393         group_class: 'project',
394       },
395       ensure_unique_name: true
396     }
397     assert_response :success
398     new_project = json_response
399     assert_not_equal(new_project['uuid'],
400                      groups(:aproject).uuid,
401                      "create returned same uuid as existing project")
402     assert_match(/^A Project \(\d{4}-\d\d-\d\dT\d\d:\d\d:\d\d\.\d{3}Z\)$/,
403                  new_project['name'])
404   end
405
406   test "unsharing a project results in hiding it from previously shared user" do
407     # remove sharing link for project
408     @controller = Arvados::V1::LinksController.new
409     authorize_with :admin
410     post :destroy, id: links(:share_starred_project_with_project_viewer).uuid
411     assert_response :success
412
413     # verify that the user can no longer see the project
414     @test_counter = 0  # Reset executed action counter
415     @controller = Arvados::V1::GroupsController.new
416     authorize_with :project_viewer
417     get :index, filters: [['group_class', '=', 'project']], format: :json
418     assert_response :success
419     found_projects = {}
420     json_response['items'].each do |g|
421       found_projects[g['uuid']] = g
422     end
423     assert_equal false, found_projects.include?(groups(:starred_and_shared_active_user_project).uuid)
424
425     # share the project
426     @test_counter = 0
427     @controller = Arvados::V1::LinksController.new
428     authorize_with :system_user
429     post :create, link: {
430       link_class: "permission",
431       name: "can_read",
432       head_uuid: groups(:starred_and_shared_active_user_project).uuid,
433       tail_uuid: users(:project_viewer).uuid,
434     }
435
436     # verify that project_viewer user can now see shared project again
437     @test_counter = 0
438     @controller = Arvados::V1::GroupsController.new
439     authorize_with :project_viewer
440     get :index, filters: [['group_class', '=', 'project']], format: :json
441     assert_response :success
442     found_projects = {}
443     json_response['items'].each do |g|
444       found_projects[g['uuid']] = g
445     end
446     assert_equal true, found_projects.include?(groups(:starred_and_shared_active_user_project).uuid)
447   end
448
449   [
450     [['owner_uuid', '!=', 'zzzzz-tpzed-xurymjxw79nv3jz'], 200,
451         'zzzzz-d1hrv-subprojpipeline', 'zzzzz-d1hrv-1xfj6xkicf2muk2'],
452     [["pipeline_instances.state", "not in", ["Complete", "Failed"]], 200,
453         'zzzzz-d1hrv-1xfj6xkicf2muk2', 'zzzzz-d1hrv-i3e77t9z5y8j9cc'],
454     [['container_requests.requesting_container_uuid', '=', nil], 200,
455         'zzzzz-xvhdp-cr4queuedcontnr', 'zzzzz-xvhdp-cr4requestercn2'],
456     [['container_requests.no_such_column', '=', nil], 422],
457     [['container_requests.', '=', nil], 422],
458     [['.requesting_container_uuid', '=', nil], 422],
459     [['no_such_table.uuid', '!=', 'zzzzz-tpzed-xurymjxw79nv3jz'], 422],
460   ].each do |filter, expect_code, expect_uuid, not_expect_uuid|
461     test "get contents with '#{filter}' filter" do
462       authorize_with :active
463       get :contents, filters: [filter], format: :json
464       assert_response expect_code
465       if expect_code == 200
466         assert_not_empty json_response['items']
467         item_uuids = json_response['items'].collect {|item| item['uuid']}
468         assert_includes(item_uuids, expect_uuid)
469         assert_not_includes(item_uuids, not_expect_uuid)
470       end
471     end
472   end
473
474   test 'get contents with jobs and pipeline instances disabled' do
475     Rails.configuration.disable_api_methods = ['jobs.index', 'pipeline_instances.index']
476
477     authorize_with :active
478     get :contents, {
479       id: groups(:aproject).uuid,
480       format: :json,
481     }
482     check_project_contents_response %w'arvados#pipelineInstance arvados#job'
483   end
484
485   test 'get contents with low max_index_database_read' do
486     # Some result will certainly have at least 12 bytes in a
487     # restricted column
488     Rails.configuration.max_index_database_read = 12
489     authorize_with :active
490     get :contents, {
491           id: groups(:aproject).uuid,
492           format: :json,
493         }
494     assert_response :success
495     assert_not_empty(json_response['items'])
496     assert_operator(json_response['items'].count,
497                     :<, json_response['items_available'])
498   end
499
500   test 'get contents, recursive=true' do
501     authorize_with :active
502     params = {
503       id: groups(:aproject).uuid,
504       recursive: true,
505       format: :json,
506     }
507     get :contents, params
508     owners = json_response['items'].map do |item|
509       item['owner_uuid']
510     end
511     assert_includes(owners, groups(:aproject).uuid)
512     assert_includes(owners, groups(:asubproject).uuid)
513   end
514
515   [false, nil].each do |recursive|
516     test "get contents, recursive=#{recursive.inspect}" do
517       authorize_with :active
518       params = {
519         id: groups(:aproject).uuid,
520         format: :json,
521       }
522       params[:recursive] = false if recursive == false
523       get :contents, params
524       owners = json_response['items'].map do |item|
525         item['owner_uuid']
526       end
527       assert_includes(owners, groups(:aproject).uuid)
528       refute_includes(owners, groups(:asubproject).uuid)
529     end
530   end
531
532   test 'get home project contents, recursive=true' do
533     authorize_with :active
534     get :contents, {
535           id: users(:active).uuid,
536           recursive: true,
537           format: :json,
538         }
539     owners = json_response['items'].map do |item|
540       item['owner_uuid']
541     end
542     assert_includes(owners, users(:active).uuid)
543     assert_includes(owners, groups(:aproject).uuid)
544     assert_includes(owners, groups(:asubproject).uuid)
545   end
546
547   ### trashed project tests ###
548
549   [:active, :admin].each do |auth|
550     # project: to query,    to untrash,    is visible, parent contents listing success
551     [[:trashed_project,     [],                 false, true],
552      [:trashed_project,     [:trashed_project], true,  true],
553      [:trashed_subproject,  [],                 false, false],
554      [:trashed_subproject,  [:trashed_project], true,  true],
555      [:trashed_subproject3, [:trashed_project], false, true],
556      [:trashed_subproject3, [:trashed_subproject3], false, false],
557      [:trashed_subproject3, [:trashed_project, :trashed_subproject3], true, true],
558     ].each do |project, untrash, visible, success|
559
560       test "contents listing #{project} #{untrash} as #{auth}" do
561         authorize_with auth
562         untrash.each do |pr|
563           Group.find_by_uuid(groups(pr).uuid).update! is_trashed: false
564         end
565         get :contents, {
566               id: groups(project).owner_uuid,
567               format: :json
568             }
569         if success
570           assert_response :success
571           item_uuids = json_response['items'].map do |item|
572             item['uuid']
573           end
574           if visible
575             assert_includes(item_uuids, groups(project).uuid)
576           else
577             assert_not_includes(item_uuids, groups(project).uuid)
578           end
579         else
580           assert_response 404
581         end
582       end
583
584       test "contents of #{project} #{untrash} as #{auth}" do
585         authorize_with auth
586         untrash.each do |pr|
587           Group.find_by_uuid(groups(pr).uuid).update! is_trashed: false
588         end
589         get :contents, {
590               id: groups(project).uuid,
591               format: :json
592             }
593         if visible
594           assert_response :success
595         else
596           assert_response 404
597         end
598       end
599
600       test "index #{project} #{untrash} as #{auth}" do
601         authorize_with auth
602         untrash.each do |pr|
603           Group.find_by_uuid(groups(pr).uuid).update! is_trashed: false
604         end
605         get :index, {
606               format: :json,
607             }
608         assert_response :success
609         item_uuids = json_response['items'].map do |item|
610           item['uuid']
611         end
612         if visible
613           assert_includes(item_uuids, groups(project).uuid)
614         else
615           assert_not_includes(item_uuids, groups(project).uuid)
616         end
617       end
618
619       test "show #{project} #{untrash} as #{auth}" do
620         authorize_with auth
621         untrash.each do |pr|
622           Group.find_by_uuid(groups(pr).uuid).update! is_trashed: false
623         end
624         get :show, {
625               id: groups(project).uuid,
626               format: :json
627             }
628         if visible
629           assert_response :success
630         else
631           assert_response 404
632         end
633       end
634
635       test "show include_trash #{project} #{untrash} as #{auth}" do
636         authorize_with auth
637         untrash.each do |pr|
638           Group.find_by_uuid(groups(pr).uuid).update! is_trashed: false
639         end
640         get :show, {
641               id: groups(project).uuid,
642               format: :json,
643               include_trash: true
644             }
645         assert_response :success
646       end
647
648       test "index include_trash #{project} #{untrash} as #{auth}" do
649         authorize_with auth
650         untrash.each do |pr|
651           Group.find_by_uuid(groups(pr).uuid).update! is_trashed: false
652         end
653         get :index, {
654               format: :json,
655               include_trash: true
656             }
657         assert_response :success
658         item_uuids = json_response['items'].map do |item|
659           item['uuid']
660         end
661         assert_includes(item_uuids, groups(project).uuid)
662       end
663     end
664
665     test "delete project #{auth}" do
666       authorize_with auth
667       [:trashed_project].each do |pr|
668         Group.find_by_uuid(groups(pr).uuid).update! is_trashed: false
669       end
670       assert !Group.find_by_uuid(groups(:trashed_project).uuid).is_trashed
671       post :destroy, {
672             id: groups(:trashed_project).uuid,
673             format: :json,
674           }
675       assert_response :success
676       assert Group.find_by_uuid(groups(:trashed_project).uuid).is_trashed
677     end
678
679     test "untrash project #{auth}" do
680       authorize_with auth
681       assert Group.find_by_uuid(groups(:trashed_project).uuid).is_trashed
682       post :untrash, {
683             id: groups(:trashed_project).uuid,
684             format: :json,
685           }
686       assert_response :success
687       assert !Group.find_by_uuid(groups(:trashed_project).uuid).is_trashed
688     end
689
690     test "untrash project with name conflict #{auth}" do
691       authorize_with auth
692       [:trashed_project].each do |pr|
693         Group.find_by_uuid(groups(pr).uuid).update! is_trashed: false
694       end
695       gc = Group.create!({owner_uuid: "zzzzz-j7d0g-trashedproject1",
696                          name: "trashed subproject 3",
697                          group_class: "project"})
698       post :untrash, {
699             id: groups(:trashed_subproject3).uuid,
700             format: :json,
701             ensure_unique_name: true
702            }
703       assert_response :success
704       assert_match /^trashed subproject 3 \(\d{4}-\d\d-\d\d.*?Z\)$/, json_response['name']
705     end
706
707     test "move trashed subproject to new owner #{auth}" do
708       authorize_with auth
709       assert_nil Group.readable_by(users(auth)).where(uuid: groups(:trashed_subproject).uuid).first
710       put :update, {
711             id: groups(:trashed_subproject).uuid,
712             group: {
713               owner_uuid: users(:active).uuid
714             },
715             include_trash: true,
716             format: :json,
717           }
718       assert_response :success
719       assert_not_nil Group.readable_by(users(auth)).where(uuid: groups(:trashed_subproject).uuid).first
720     end
721   end
722
723   test 'get shared owned by another user' do
724     authorize_with :user_bar_in_sharing_group
725
726     act_as_system_user do
727       Link.create!(
728         tail_uuid: users(:user_bar_in_sharing_group).uuid,
729         link_class: 'permission',
730         name: 'can_read',
731         head_uuid: groups(:project_owned_by_foo).uuid)
732     end
733
734     get :shared, {:filters => [["group_class", "=", "project"]], :include => "owner_uuid"}
735
736     assert_equal 1, json_response['items'].length
737     assert_equal json_response['items'][0]["uuid"], groups(:project_owned_by_foo).uuid
738
739     assert_equal 1, json_response['included'].length
740     assert_equal json_response['included'][0]["uuid"], users(:user_foo_in_sharing_group).uuid
741   end
742
743   test 'get shared, owned by unreadable project' do
744     authorize_with :user_bar_in_sharing_group
745
746     act_as_system_user do
747       Group.find_by_uuid(groups(:project_owned_by_foo).uuid).update!(owner_uuid: groups(:aproject).uuid)
748       Link.create!(
749         tail_uuid: users(:user_bar_in_sharing_group).uuid,
750         link_class: 'permission',
751         name: 'can_read',
752         head_uuid: groups(:project_owned_by_foo).uuid)
753     end
754
755     get :shared, {:filters => [["group_class", "=", "project"]], :include => "owner_uuid"}
756
757     assert_equal 1, json_response['items'].length
758     assert_equal json_response['items'][0]["uuid"], groups(:project_owned_by_foo).uuid
759
760     assert_equal 0, json_response['included'].length
761   end
762
763   test 'get shared, owned by non-project' do
764     authorize_with :user_bar_in_sharing_group
765
766     act_as_system_user do
767       Group.find_by_uuid(groups(:project_owned_by_foo).uuid).update!(owner_uuid: groups(:group_for_sharing_tests).uuid)
768     end
769
770     get :shared, {:filters => [["group_class", "=", "project"]], :include => "owner_uuid"}
771
772     assert_equal 1, json_response['items'].length
773     assert_equal json_response['items'][0]["uuid"], groups(:project_owned_by_foo).uuid
774
775     assert_equal 1, json_response['included'].length
776     assert_equal json_response['included'][0]["uuid"], groups(:group_for_sharing_tests).uuid
777   end
778
779 end