Merge branch '15397-remove-obsolete-apis'
[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 that cannot be seen" do
10     Rails.configuration.Users.RoleGroupsVisibleToAll = false
11     authorize_with :active
12     post :destroy, params: {id: groups(:empty_lonely_group).uuid}
13     assert_response 404
14   end
15
16   test "attempt to delete group without read or write access" do
17     authorize_with :active
18     post :destroy, params: {id: groups(:empty_lonely_group).uuid}
19     assert_response 403
20   end
21
22   test "attempt to delete group without write access" do
23     authorize_with :active
24     post :destroy, params: {id: groups(:all_users).uuid}
25     assert_response 403
26   end
27
28   test "get list of projects" do
29     authorize_with :active
30     get :index, params: {filters: [['group_class', '=', 'project']], format: :json}
31     assert_response :success
32     group_uuids = []
33     json_response['items'].each do |group|
34       assert_equal 'project', group['group_class']
35       group_uuids << group['uuid']
36     end
37     assert_includes group_uuids, groups(:aproject).uuid
38     assert_includes group_uuids, groups(:asubproject).uuid
39     assert_includes group_uuids, groups(:private).uuid
40     assert_not_includes group_uuids, groups(:system_group).uuid
41     assert_not_includes group_uuids, groups(:private_and_can_read_foofile).uuid
42   end
43
44   test "get list of groups that are not projects" do
45     authorize_with :active
46     get :index, params: {filters: [['group_class', '!=', 'project']], format: :json}
47     assert_response :success
48     group_uuids = []
49     json_response['items'].each do |group|
50       assert_not_equal 'project', group['group_class']
51       group_uuids << group['uuid']
52     end
53     assert_not_includes group_uuids, groups(:aproject).uuid
54     assert_not_includes group_uuids, groups(:asubproject).uuid
55   end
56
57   test "get list of groups with bogus group_class" do
58     authorize_with :active
59     get :index, params: {
60       filters: [['group_class', '=', 'nogrouphasthislittleclass']],
61       format: :json,
62     }
63     assert_response :success
64     assert_equal [], json_response['items']
65     assert_equal 0, json_response['items_available']
66   end
67
68   def check_project_contents_response
69     assert_response :success
70     assert_operator 2, :<=, json_response['items_available']
71     assert_operator 2, :<=, json_response['items'].count
72     kinds = json_response['items'].collect { |i| i['kind'] }.uniq
73     expect_kinds = %w'arvados#group'
74     assert_equal expect_kinds, (expect_kinds & kinds)
75
76     json_response['items'].each do |i|
77       if i['kind'] == 'arvados#group'
78         assert(i['group_class'] == 'project',
79                "group#contents returned a non-project group")
80       end
81     end
82   end
83
84   test 'get group-owned objects' do
85     authorize_with :active
86     get :contents, params: {
87       id: groups(:aproject).uuid,
88       format: :json,
89     }
90     check_project_contents_response
91   end
92
93   test "user with project read permission can see project objects" do
94     authorize_with :project_viewer
95     get :contents, params: {
96       id: groups(:aproject).uuid,
97       format: :json,
98     }
99     check_project_contents_response
100   end
101
102   test "list objects across projects" do
103     authorize_with :project_viewer
104     get :contents, params: {
105       format: :json,
106       filters: [['uuid', 'is_a', 'arvados#collection']]
107     }
108     assert_response :success
109     found_uuids = json_response['items'].collect { |i| i['uuid'] }
110     [[:foo_collection_in_aproject, true],
111      [:baz_collection_name_in_asubproject, true],
112      [:collection_not_readable_by_active, false]].each do |collection_fixture, should_find|
113       if should_find
114         assert_includes found_uuids, collections(collection_fixture).uuid, "did not find collection fixture '#{collection_fixture}'"
115       else
116         refute_includes found_uuids, collections(collection_fixture).uuid, "found collection fixture '#{collection_fixture}'"
117       end
118     end
119   end
120
121   test "list trashed collections and projects" do
122     authorize_with :active
123     get(:contents, params: {
124           format: :json,
125           include_trash: true,
126           filters: [
127             ['uuid', 'is_a', ['arvados#collection', 'arvados#group']],
128             ['is_trashed', '=', true],
129           ],
130           limit: 10000,
131         })
132     assert_response :success
133     found_uuids = json_response['items'].collect { |i| i['uuid'] }
134     assert_includes found_uuids, groups(:trashed_project).uuid
135     refute_includes found_uuids, groups(:aproject).uuid
136     assert_includes found_uuids, collections(:expired_collection).uuid
137     refute_includes found_uuids, collections(:w_a_z_file).uuid
138   end
139
140   test "list objects in home project" do
141     authorize_with :active
142     get :contents, params: {
143       format: :json,
144       limit: 200,
145       id: users(:active).uuid
146     }
147     assert_response :success
148     found_uuids = json_response['items'].collect { |i| i['uuid'] }
149     assert_includes found_uuids, collections(:collection_owned_by_active).uuid, "collection did not appear in home project"
150     refute_includes found_uuids, collections(:foo_collection_in_aproject).uuid, "collection appeared unexpectedly in home project"
151   end
152
153   test "list collections in home project" do
154     authorize_with :active
155     get(:contents, params: {
156           format: :json,
157           filters: [
158             ['uuid', 'is_a', 'arvados#collection'],
159           ],
160           limit: 200,
161           id: users(:active).uuid,
162         })
163     assert_response :success
164     found_uuids = json_response['items'].collect { |i| i['uuid'] }
165     assert_includes found_uuids, collections(:collection_owned_by_active).uuid, "collection did not appear in home project"
166     refute_includes found_uuids, collections(:collection_owned_by_active_past_version_1).uuid, "collection appeared unexpectedly in home project"
167   end
168
169   test "list collections in home project, including old versions" do
170     authorize_with :active
171     get(:contents, params: {
172           format: :json,
173           include_old_versions: true,
174           filters: [
175             ['uuid', 'is_a', 'arvados#collection'],
176           ],
177           limit: 200,
178           id: users(:active).uuid,
179         })
180     assert_response :success
181     found_uuids = json_response['items'].collect { |i| i['uuid'] }
182     assert_includes found_uuids, collections(:collection_owned_by_active).uuid, "collection did not appear in home project"
183     assert_includes found_uuids, collections(:collection_owned_by_active_past_version_1).uuid, "old collection version did not appear in home project"
184   end
185
186   test "user with project read permission can see project collections" do
187     authorize_with :project_viewer
188     get :contents, params: {
189       id: groups(:asubproject).uuid,
190       format: :json,
191     }
192     ids = json_response['items'].map { |item| item["uuid"] }
193     assert_includes ids, collections(:baz_file_in_asubproject).uuid
194   end
195
196   [
197     ['collections.name', 'asc', :<=, "name"],
198     ['collections.name', 'desc', :>=, "name"],
199     ['name', 'asc', :<=, "name"],
200     ['name', 'desc', :>=, "name"],
201     ['collections.created_at', 'asc', :<=, "created_at"],
202     ['collections.created_at', 'desc', :>=, "created_at"],
203     ['created_at', 'asc', :<=, "created_at"],
204     ['created_at', 'desc', :>=, "created_at"],
205   ].each do |column, order, operator, field|
206     test "user with project read permission can sort projects on #{column} #{order}" do
207       authorize_with :project_viewer
208       get :contents, params: {
209         id: groups(:asubproject).uuid,
210         format: :json,
211         filters: [['uuid', 'is_a', "arvados#collection"]],
212         order: "#{column} #{order}"
213       }
214       sorted_values = json_response['items'].collect { |item| item[field] }
215       if field == "name"
216         # Here we avoid assuming too much about the database
217         # collation. Both "alice"<"Bob" and "alice">"Bob" can be
218         # correct. Hopefully it _is_ safe to assume that if "a" comes
219         # before "b" in the ascii alphabet, "aX">"bY" is never true for
220         # any strings X and Y.
221         reliably_sortable_names = sorted_values.select do |name|
222           name[0] >= 'a' && name[0] <= 'z'
223         end.uniq do |name|
224           name[0]
225         end
226         # Preserve order of sorted_values. But do not use &=. If
227         # sorted_values has out-of-order duplicates, we want to preserve
228         # them here, so we can detect them and fail the test below.
229         sorted_values.select! do |name|
230           reliably_sortable_names.include? name
231         end
232       end
233       assert_sorted(operator, sorted_values)
234     end
235   end
236
237   def assert_sorted(operator, sorted_items)
238     actually_checked_anything = false
239     previous = nil
240     sorted_items.each do |entry|
241       if !previous.nil?
242         assert_operator(previous, operator, entry,
243                         "Entries sorted incorrectly.")
244         actually_checked_anything = true
245       end
246       previous = entry
247     end
248     assert actually_checked_anything, "Didn't even find two items to compare."
249   end
250
251   # Even though the project_viewer tests go through other controllers,
252   # I'm putting them here so they're easy to find alongside the other
253   # project tests.
254   def check_new_project_link_fails(link_attrs)
255     @controller = Arvados::V1::LinksController.new
256     post :create, params: {
257       link: {
258         link_class: "permission",
259         name: "can_read",
260         head_uuid: groups(:aproject).uuid,
261       }.merge(link_attrs)
262     }
263     assert_includes(403..422, response.status)
264   end
265
266   test "user with project read permission can't add users to it" do
267     authorize_with :project_viewer
268     check_new_project_link_fails(tail_uuid: users(:spectator).uuid)
269   end
270
271   test "user with project read permission can't add items to it" do
272     authorize_with :project_viewer
273     check_new_project_link_fails(tail_uuid: collections(:baz_file).uuid)
274   end
275
276   test "user with project read permission can't rename items in it" do
277     authorize_with :project_viewer
278     @controller = Arvados::V1::CollectionsController.new
279     post :update, params: {
280       id: collections(:collection_to_search_for_in_aproject).uuid,
281       name: "Denied test name",
282     }
283     assert_includes(403..404, response.status)
284   end
285
286   test "user with project read permission can't remove items from it" do
287     @controller = Arvados::V1::CollectionsController.new
288     authorize_with :project_viewer
289     post :update, params: {
290       id: collections(:collection_to_search_for_in_aproject).uuid,
291       collection: {
292         owner_uuid: users(:project_viewer).uuid,
293       }
294     }
295     assert_response 403
296   end
297
298   test "user with project read permission can't delete it" do
299     authorize_with :project_viewer
300     post :destroy, params: {id: groups(:aproject).uuid}
301     assert_response 403
302   end
303
304   test 'get group-owned objects with limit' do
305     authorize_with :active
306     get :contents, params: {
307       id: groups(:aproject).uuid,
308       limit: 1,
309       format: :json,
310     }
311     assert_response :success
312     assert_operator 1, :<, json_response['items_available']
313     assert_equal 1, json_response['items'].count
314   end
315
316   test 'get group-owned objects with limit and offset' do
317     authorize_with :active
318     get :contents, params: {
319       id: groups(:aproject).uuid,
320       limit: 1,
321       offset: 12345,
322       format: :json,
323     }
324     assert_response :success
325     assert_operator 1, :<, json_response['items_available']
326     assert_equal 0, json_response['items'].count
327   end
328
329   test 'get group-owned objects with select' do
330     authorize_with :active
331     get :contents, params: {
332       id: groups(:aproject).uuid,
333       limit: 100,
334       format: :json,
335       select: ["uuid", "storage_classes_desired"]
336     }
337     assert_response :success
338     assert_equal 6, json_response['items_available']
339     assert_equal 6, json_response['items'].count
340     json_response['items'].each do |item|
341       # Expect collections to have a storage_classes field, other items should not.
342       if item["kind"] == "arvados#collection"
343         assert !item["storage_classes_desired"].nil?
344       else
345         assert item["storage_classes_desired"].nil?
346       end
347     end
348   end
349
350   test 'get group-owned objects with invalid field in select' do
351     authorize_with :active
352     get :contents, params: {
353       id: groups(:aproject).uuid,
354       limit: 100,
355       format: :json,
356       select: ["uuid", "storage_classes_desire"]
357     }
358     assert_response 422
359   end
360
361   test 'get group-owned objects with additional filter matching nothing' do
362     authorize_with :active
363     get :contents, params: {
364       id: groups(:aproject).uuid,
365       filters: [['uuid', 'in', ['foo_not_a_uuid','bar_not_a_uuid']]],
366       format: :json,
367     }
368     assert_response :success
369     assert_equal [], json_response['items']
370     assert_equal 0, json_response['items_available']
371   end
372
373   %w(offset limit).each do |arg|
374     ['foo', '', '1234five', '0x10', '-8'].each do |val|
375       test "Raise error on bogus #{arg} parameter #{val.inspect}" do
376         authorize_with :active
377         get :contents, params: {
378           :id => groups(:aproject).uuid,
379           :format => :json,
380           arg => val,
381         }
382         assert_response 422
383       end
384     end
385   end
386
387   test "Collection contents don't include manifest_text or unsigned_manifest_text" do
388     authorize_with :active
389     get :contents, params: {
390       id: groups(:aproject).uuid,
391       filters: [["uuid", "is_a", "arvados#collection"]],
392       format: :json,
393     }
394     assert_response :success
395     refute(json_response["items"].any? { |c| not c["portable_data_hash"] },
396            "response included an item without a portable data hash")
397     refute(json_response["items"].any? { |c| c.include?("manifest_text") },
398            "response included an item with manifest_text")
399     refute(json_response["items"].any? { |c| c.include?("unsigned_manifest_text") },
400            "response included an item with unsigned_manifest_text")
401   end
402
403   test 'get writable_by list for owned group' do
404     authorize_with :active
405     get :show, params: {
406       id: groups(:aproject).uuid,
407       format: :json
408     }
409     assert_response :success
410     assert_not_nil(json_response['writable_by'],
411                    "Should receive uuid list in 'writable_by' field")
412     assert_includes(json_response['writable_by'], users(:active).uuid,
413                     "owner should be included in writable_by list")
414   end
415
416   test 'no writable_by list for group with read-only access' do
417     authorize_with :rominiadmin
418     get :show, params: {
419       id: groups(:testusergroup_admins).uuid,
420       format: :json
421     }
422     assert_response :success
423     assert_equal([json_response['owner_uuid']],
424                  json_response['writable_by'],
425                  "Should only see owner_uuid in 'writable_by' field")
426   end
427
428   test 'get writable_by list by admin user' do
429     authorize_with :admin
430     get :show, params: {
431       id: groups(:testusergroup_admins).uuid,
432       format: :json
433     }
434     assert_response :success
435     assert_not_nil(json_response['writable_by'],
436                    "Should receive uuid list in 'writable_by' field")
437     assert_includes(json_response['writable_by'],
438                     users(:admin).uuid,
439                     "Current user should be included in 'writable_by' field")
440   end
441
442   test 'creating subproject with duplicate name fails' do
443     authorize_with :active
444     post :create, params: {
445       group: {
446         name: 'A Project',
447         owner_uuid: users(:active).uuid,
448         group_class: 'project',
449       },
450     }
451     assert_response 422
452     response_errors = json_response['errors']
453     assert_not_nil response_errors, 'Expected error in response'
454     assert(response_errors.first.include?('duplicate key'),
455            "Expected 'duplicate key' error in #{response_errors.first}")
456   end
457
458   test 'creating duplicate named subproject succeeds with ensure_unique_name' do
459     authorize_with :active
460     post :create, params: {
461       group: {
462         name: 'A Project',
463         owner_uuid: users(:active).uuid,
464         group_class: 'project',
465       },
466       ensure_unique_name: true
467     }
468     assert_response :success
469     new_project = json_response
470     assert_not_equal(new_project['uuid'],
471                      groups(:aproject).uuid,
472                      "create returned same uuid as existing project")
473     assert_match(/^A Project \(#{new_project['uuid'][-15..-1]}\)$/,
474                  new_project['name'])
475   end
476
477   [
478     [['owner_uuid', '!=', 'zzzzz-tpzed-xurymjxw79nv3jz'], 200,
479         'zzzzz-j7d0g-publicfavorites', 'zzzzz-xvhdp-cr4queuedcontnr'],
480     [["container_requests.state", "not in", ["Final"]], 200,
481         'zzzzz-xvhdp-cr4queuedcontnr', 'zzzzz-xvhdp-cr4completedctr'],
482     [['container_requests.requesting_container_uuid', '=', nil], 200,
483         'zzzzz-xvhdp-cr4queuedcontnr', 'zzzzz-xvhdp-cr4requestercn2'],
484     [['container_requests.no_such_column', '=', nil], 422],
485     [['container_requests.', '=', nil], 422],
486     [['.requesting_container_uuid', '=', nil], 422],
487     [['no_such_table.uuid', '!=', 'zzzzz-tpzed-xurymjxw79nv3jz'], 422],
488   ].each do |filter, expect_code, expect_uuid, not_expect_uuid|
489     test "get contents with '#{filter}' filter" do
490       authorize_with :active
491       get :contents, params: {filters: [filter], format: :json}
492       assert_response expect_code
493       if expect_code == 200
494         assert_not_empty json_response['items']
495         item_uuids = json_response['items'].collect {|item| item['uuid']}
496         assert_includes(item_uuids, expect_uuid)
497         assert_not_includes(item_uuids, not_expect_uuid)
498       end
499     end
500   end
501
502   test 'get contents with low max_index_database_read' do
503     # Some result will certainly have at least 12 bytes in a
504     # restricted column.
505     #
506     # We cannot use collections.manifest_text to test this, because
507     # GroupsController refuses to select manifest_text, because
508     # controller doesn't sign manifests in a groups#contents response.
509     Rails.configuration.API.MaxIndexDatabaseRead = 12
510     authorize_with :active
511     get :contents, params: {
512           uuid: users(:active).uuid,
513           format: :json,
514         }
515     assert_response :success
516     assert_not_empty(json_response['items'])
517     assert_operator(json_response['items'].count,
518                     :<, json_response['items_available'])
519   end
520
521   test 'get contents, recursive=true' do
522     authorize_with :active
523     params = {
524       id: groups(:aproject).uuid,
525       recursive: true,
526       format: :json,
527     }
528     get :contents, params: params
529     owners = json_response['items'].map do |item|
530       item['owner_uuid']
531     end
532     assert_includes(owners, groups(:aproject).uuid)
533     assert_includes(owners, groups(:asubproject).uuid)
534   end
535
536   [false, nil].each do |recursive|
537     test "get contents, recursive=#{recursive.inspect}" do
538       authorize_with :active
539       params = {
540         id: groups(:aproject).uuid,
541         format: :json,
542       }
543       params[:recursive] = false if recursive == false
544       get :contents, params: params
545       owners = json_response['items'].map do |item|
546         item['owner_uuid']
547       end
548       assert_includes(owners, groups(:aproject).uuid)
549       refute_includes(owners, groups(:asubproject).uuid)
550     end
551   end
552
553   test 'get home project contents, recursive=true' do
554     authorize_with :active
555     get :contents, params: {
556           id: users(:active).uuid,
557           recursive: true,
558           format: :json,
559         }
560     owners = json_response['items'].map do |item|
561       item['owner_uuid']
562     end
563     assert_includes(owners, users(:active).uuid)
564     assert_includes(owners, groups(:aproject).uuid)
565     assert_includes(owners, groups(:asubproject).uuid)
566   end
567
568   [:afiltergroup, :private_role].each do |grp|
569     test "delete non-project group #{grp}" do
570       authorize_with :admin
571       assert_not_nil Group.find_by_uuid(groups(grp).uuid)
572       assert !Group.find_by_uuid(groups(grp).uuid).is_trashed
573       post :destroy, params: {
574             id: groups(grp).uuid,
575             format: :json,
576           }
577       assert_response :success
578       # Should not be trashed
579       assert_nil Group.find_by_uuid(groups(grp).uuid)
580     end
581   end
582
583   [
584     [false, :inactive, :private_role, false],
585     [false, :spectator, :private_role, false],
586     [false, :admin, :private_role, true],
587     [true, :inactive, :private_role, false],
588     [true, :spectator, :private_role, true],
589     [true, :admin, :private_role, true],
590     # project (non-role) groups are invisible even when RoleGroupsVisibleToAll is true
591     [true, :inactive, :private, false],
592     [true, :spectator, :private, false],
593     [true, :admin, :private, true],
594   ].each do |visibleToAll, userFixture, groupFixture, visible|
595     test "with RoleGroupsVisibleToAll=#{visibleToAll}, #{groupFixture} group is #{visible ? '' : 'in'}visible to #{userFixture} user" do
596       Rails.configuration.Users.RoleGroupsVisibleToAll = visibleToAll
597       authorize_with userFixture
598       get :show, params: {id: groups(groupFixture).uuid, format: :json}
599       if visible
600         assert_response :success
601       else
602         assert_response 404
603       end
604     end
605   end
606
607   ### trashed project tests ###
608
609   #
610   # The structure is
611   #
612   # trashed_project         (zzzzz-j7d0g-trashedproject1)
613   #   trashed_subproject    (zzzzz-j7d0g-trashedproject2)
614   #   trashed_subproject3   (zzzzz-j7d0g-trashedproject3)
615   #   zzzzz-xvhdp-cr5trashedcontr
616
617   [:active,
618    :admin].each do |auth|
619     # project: to query,    to untrash,    is visible, parent contents listing success
620     [
621      [:trashed_project,     [],                 false, true],
622      [:trashed_project,     [:trashed_project], true,  true],
623      [:trashed_subproject,  [],                 false, false],
624      [:trashed_subproject,  [:trashed_project], true,  true],
625      [:trashed_subproject3, [:trashed_project], false, true],
626      [:trashed_subproject3, [:trashed_subproject3], false, false],
627      [:trashed_subproject3, [:trashed_project, :trashed_subproject3], true, true],
628     ].each do |project, untrash, visible, success|
629
630       test "contents listing #{project} #{untrash} as #{auth}" do
631         authorize_with auth
632         untrash.each do |pr|
633           Group.find_by_uuid(groups(pr).uuid).update! is_trashed: false
634         end
635         get :contents, params: {
636               id: groups(project).owner_uuid,
637               format: :json
638             }
639         if success
640           assert_response :success
641           item_uuids = json_response['items'].map do |item|
642             item['uuid']
643           end
644           if visible
645             assert_includes(item_uuids, groups(project).uuid)
646           else
647             assert_not_includes(item_uuids, groups(project).uuid)
648           end
649         else
650           assert_response 404
651         end
652       end
653
654       test "contents of #{project} #{untrash} as #{auth}" do
655         authorize_with auth
656         untrash.each do |pr|
657           Group.find_by_uuid(groups(pr).uuid).update! is_trashed: false
658         end
659         get :contents, params: {
660               id: groups(project).uuid,
661               format: :json
662             }
663         if visible
664           assert_response :success
665         else
666           assert_response 404
667         end
668       end
669
670       test "index #{project} #{untrash} as #{auth}" do
671         authorize_with auth
672         untrash.each do |pr|
673           Group.find_by_uuid(groups(pr).uuid).update! is_trashed: false
674         end
675         get :index, params: {
676               format: :json,
677             }
678         assert_response :success
679         item_uuids = json_response['items'].map do |item|
680           item['uuid']
681         end
682         if visible
683           assert_includes(item_uuids, groups(project).uuid)
684         else
685           assert_not_includes(item_uuids, groups(project).uuid)
686         end
687       end
688
689       test "show #{project} #{untrash} as #{auth}" do
690         authorize_with auth
691         untrash.each do |pr|
692           Group.find_by_uuid(groups(pr).uuid).update! is_trashed: false
693         end
694         get :show, params: {
695               id: groups(project).uuid,
696               format: :json
697             }
698         if visible
699           assert_response :success
700         else
701           assert_response 404
702         end
703       end
704
705       test "show include_trash=false #{project} #{untrash} as #{auth}" do
706         authorize_with auth
707         untrash.each do |pr|
708           Group.find_by_uuid(groups(pr).uuid).update! is_trashed: false
709         end
710         get :show, params: {
711               id: groups(project).uuid,
712               format: :json,
713               include_trash: false
714             }
715         if visible
716           assert_response :success
717         else
718           assert_response 404
719         end
720       end
721
722       test "show include_trash #{project} #{untrash} as #{auth}" do
723         authorize_with auth
724         untrash.each do |pr|
725           Group.find_by_uuid(groups(pr).uuid).update! is_trashed: false
726         end
727         get :show, params: {
728               id: groups(project).uuid,
729               format: :json,
730               include_trash: true
731             }
732         assert_response :success
733       end
734
735       test "index include_trash #{project} #{untrash} as #{auth}" do
736         authorize_with auth
737         untrash.each do |pr|
738           Group.find_by_uuid(groups(pr).uuid).update! is_trashed: false
739         end
740         get :index, params: {
741               format: :json,
742               include_trash: true
743             }
744         assert_response :success
745         item_uuids = json_response['items'].map do |item|
746           item['uuid']
747         end
748         assert_includes(item_uuids, groups(project).uuid)
749       end
750     end
751
752     test "delete project #{auth}" do
753       authorize_with auth
754       [:trashed_project].each do |pr|
755         Group.find_by_uuid(groups(pr).uuid).update! is_trashed: false
756       end
757       assert !Group.find_by_uuid(groups(:trashed_project).uuid).is_trashed
758       post :destroy, params: {
759             id: groups(:trashed_project).uuid,
760             format: :json,
761           }
762       assert_response :success
763       assert Group.find_by_uuid(groups(:trashed_project).uuid).is_trashed
764     end
765
766     test "untrash project #{auth}" do
767       authorize_with auth
768       assert Group.find_by_uuid(groups(:trashed_project).uuid).is_trashed
769       post :untrash, params: {
770             id: groups(:trashed_project).uuid,
771             format: :json,
772           }
773       assert_response :success
774       assert !Group.find_by_uuid(groups(:trashed_project).uuid).is_trashed
775     end
776
777     test "untrash project with name conflict #{auth}" do
778       authorize_with auth
779       [:trashed_project].each do |pr|
780         Group.find_by_uuid(groups(pr).uuid).update! is_trashed: false
781       end
782       gc = Group.create!({owner_uuid: "zzzzz-j7d0g-trashedproject1",
783                          name: "trashed subproject 3",
784                          group_class: "project"})
785       post :untrash, params: {
786             id: groups(:trashed_subproject3).uuid,
787             format: :json,
788             ensure_unique_name: true
789            }
790       assert_response :success
791       assert_match /^trashed subproject 3 \(#{json_response['uuid'][-15..-1]}\)$/, json_response['name']
792     end
793
794     test "move trashed subproject to new owner #{auth}" do
795       authorize_with auth
796       assert_nil Group.readable_by(users(auth)).where(uuid: groups(:trashed_subproject).uuid).first
797       put :update, params: {
798             id: groups(:trashed_subproject).uuid,
799             group: {
800               owner_uuid: users(:active).uuid
801             },
802             include_trash: true,
803             format: :json,
804           }
805       assert_response :success
806       assert_not_nil Group.readable_by(users(auth)).where(uuid: groups(:trashed_subproject).uuid).first
807     end
808   end
809
810   # the group class overrides the destroy method. Make sure that the destroyed
811   # object is returned
812   [
813     {group_class: "project"},
814     {group_class: "role"},
815     {group_class: "filter", properties: {"filters":[]}},
816   ].each do |params|
817     test "destroy group #{params} returns object" do
818       authorize_with :active
819
820       group = Group.create!(params)
821
822       post :destroy, params: {
823             id: group.uuid,
824             format: :json,
825           }
826       assert_response :success
827       assert_not_nil json_response
828       assert_equal group.uuid, json_response["uuid"]
829     end
830   end
831
832   test 'get shared owned by another user' do
833     authorize_with :user_bar_in_sharing_group
834
835     act_as_system_user do
836       Link.create!(
837         tail_uuid: users(:user_bar_in_sharing_group).uuid,
838         link_class: 'permission',
839         name: 'can_read',
840         head_uuid: groups(:project_owned_by_foo).uuid)
841     end
842
843     get :shared, params: {:filters => [["group_class", "=", "project"]], :include => "owner_uuid"}
844
845     assert_equal 1, json_response['items'].length
846     assert_equal json_response['items'][0]["uuid"], groups(:project_owned_by_foo).uuid
847
848     assert_equal 1, json_response['included'].length
849     assert_equal json_response['included'][0]["uuid"], users(:user_foo_in_sharing_group).uuid
850   end
851
852   test 'get shared, owned by unreadable project' do
853     authorize_with :user_bar_in_sharing_group
854
855     act_as_system_user do
856       Group.find_by_uuid(groups(:project_owned_by_foo).uuid).update!(owner_uuid: groups(:aproject).uuid)
857       Link.create!(
858         tail_uuid: users(:user_bar_in_sharing_group).uuid,
859         link_class: 'permission',
860         name: 'can_read',
861         head_uuid: groups(:project_owned_by_foo).uuid)
862     end
863
864     get :shared, params: {:filters => [["group_class", "=", "project"]], :include => "owner_uuid"}
865
866     assert_equal 1, json_response['items'].length
867     assert_equal json_response['items'][0]["uuid"], groups(:project_owned_by_foo).uuid
868
869     assert_equal 0, json_response['included'].length
870   end
871
872   test 'get shared, add permission link' do
873     authorize_with :user_bar_in_sharing_group
874
875     act_as_system_user do
876       Link.create!(tail_uuid: groups(:group_for_sharing_tests).uuid,
877                    head_uuid: groups(:project_owned_by_foo).uuid,
878                    link_class: 'permission',
879                    name: 'can_manage')
880     end
881
882     get :shared, params: {:filters => [["group_class", "=", "project"]], :include => "owner_uuid"}
883
884     assert_equal 1, json_response['items'].length
885     assert_equal groups(:project_owned_by_foo).uuid, json_response['items'][0]["uuid"]
886
887     assert_equal 1, json_response['included'].length
888     assert_equal users(:user_foo_in_sharing_group).uuid, json_response['included'][0]["uuid"]
889   end
890
891   ### contents with exclude_home_project
892
893   test 'contents, exclude home owned by another user' do
894     authorize_with :user_bar_in_sharing_group
895
896     act_as_system_user do
897       Link.create!(
898         tail_uuid: users(:user_bar_in_sharing_group).uuid,
899         link_class: 'permission',
900         name: 'can_read',
901         head_uuid: groups(:project_owned_by_foo).uuid)
902       Link.create!(
903         tail_uuid: users(:user_bar_in_sharing_group).uuid,
904         link_class: 'permission',
905         name: 'can_read',
906         head_uuid: collections(:collection_owned_by_foo).uuid)
907     end
908
909     get :contents, params: {:include => "owner_uuid", :exclude_home_project => true}
910
911     assert_equal 2, json_response['items'].length
912     assert_equal json_response['items'][0]["uuid"], groups(:project_owned_by_foo).uuid
913     assert_equal json_response['items'][1]["uuid"], collections(:collection_owned_by_foo).uuid
914
915     assert_equal 1, json_response['included'].length
916     assert_equal json_response['included'][0]["uuid"], users(:user_foo_in_sharing_group).uuid
917   end
918
919   test 'contents, exclude home, owned by unreadable project' do
920     authorize_with :user_bar_in_sharing_group
921
922     act_as_system_user do
923       Group.find_by_uuid(groups(:project_owned_by_foo).uuid).update!(owner_uuid: groups(:aproject).uuid)
924       Link.create!(
925         tail_uuid: users(:user_bar_in_sharing_group).uuid,
926         link_class: 'permission',
927         name: 'can_read',
928         head_uuid: groups(:project_owned_by_foo).uuid)
929     end
930
931     get :contents, params: {:include => "owner_uuid", :exclude_home_project => true}
932
933     assert_equal 1, json_response['items'].length
934     assert_equal json_response['items'][0]["uuid"], groups(:project_owned_by_foo).uuid
935
936     assert_equal 0, json_response['included'].length
937   end
938
939   test 'contents, exclude home, add permission link' do
940     authorize_with :user_bar_in_sharing_group
941
942     act_as_system_user do
943       Link.create!(tail_uuid: groups(:group_for_sharing_tests).uuid,
944                    head_uuid: groups(:project_owned_by_foo).uuid,
945                    link_class: 'permission',
946                    name: 'can_manage')
947     end
948
949     get :contents, params: {:include => "owner_uuid", :exclude_home_project => true}
950
951     assert_equal 1, json_response['items'].length
952     assert_equal groups(:project_owned_by_foo).uuid, json_response['items'][0]["uuid"]
953
954     assert_equal 1, json_response['included'].length
955     assert_equal users(:user_foo_in_sharing_group).uuid, json_response['included'][0]["uuid"]
956   end
957
958   test 'contents, exclude home, with parent specified' do
959     authorize_with :active
960
961     get :contents, params: {id: groups(:aproject).uuid, :include => "owner_uuid", :exclude_home_project => true}
962
963     assert_response 422
964   end
965
966   test "include_trash does not return trash inside frozen project" do
967     authorize_with :active
968     trashtime = Time.now - 1.second
969     outerproj = Group.create!(group_class: 'project')
970     innerproj = Group.create!(group_class: 'project', owner_uuid: outerproj.uuid)
971     innercoll = Collection.create!(name: 'inner-not-trashed', owner_uuid: innerproj.uuid)
972     innertrash = Collection.create!(name: 'inner-trashed', owner_uuid: innerproj.uuid, trash_at: trashtime)
973     innertrashproj = Group.create!(group_class: 'project', name: 'inner-trashed-proj', owner_uuid: innerproj.uuid, trash_at: trashtime)
974     outertrash = Collection.create!(name: 'outer-trashed', owner_uuid: outerproj.uuid, trash_at: trashtime)
975     innerproj.update!(frozen_by_uuid: users(:active).uuid)
976     get :contents, params: {id: outerproj.uuid, include_trash: true, recursive: true}
977     assert_response :success
978     uuids = json_response['items'].collect { |item| item['uuid'] }
979     assert_includes uuids, outertrash.uuid
980     assert_includes uuids, innerproj.uuid
981     assert_includes uuids, innercoll.uuid
982     refute_includes uuids, innertrash.uuid
983     refute_includes uuids, innertrashproj.uuid
984   end
985 end