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