18691: Add groups.frozen_by_uuid attribute.
[arvados.git] / services / api / test / unit / group_test.rb
index 10932e116d7adbed60880f4fc84d0a55242039db..f3367118c580728cb4cb48a64a278a2fe3f1097d 100644 (file)
@@ -313,4 +313,124 @@ update links set tail_uuid='#{g5}' where uuid='#{l1.uuid}'
     assert Link.where(tail_uuid: g3, head_uuid: g4, link_class: "permission", name: "can_manage").any?
     assert !Link.where(link_class: 'permission', name: 'can_manage', tail_uuid: g5, head_uuid: g4).any?
   end
+
+  test "freeze project" do
+    act_as_user users(:active) do
+      Rails.configuration.API.UnfreezeProjectRequiresAdmin = false
+      proj = Group.create!(group_class: 'project', name: 'freeze-test', owner_uuid: users(:active).uuid)
+      proj_inner = Group.create!(group_class: 'project', name: 'freeze-test-inner', owner_uuid: proj.uuid)
+      coll = Collection.create!(name: 'foo', manifest_text: '')
+
+      # Cannot set frozen_by_uuid to a different user
+      assert_raises do
+        proj.update_attributes!(frozen_by_uuid: users(:spectator).uuid)
+      end
+      proj.reload
+
+      # Cannot set frozen_by_uuid without description (if so configured)
+      Rails.configuration.API.FreezeProjectRequiresDescription = true
+      err = assert_raises do
+        proj.update_attributes!(frozen_by_uuid: users(:active).uuid)
+      end
+      assert_match /can only be set if description is non-empty/, err.inspect
+      proj.reload
+      err = assert_raises do
+        proj.update_attributes!(frozen_by_uuid: users(:active).uuid, description: '')
+      end
+      assert_match /can only be set if description is non-empty/, err.inspect
+      proj.reload
+
+      # Cannot set frozen_by_uuid without properties (if so configured)
+      Rails.configuration.API.FreezeProjectRequiresProperties['frobity'] = true
+      err = assert_raises do
+        proj.update_attributes!(
+          frozen_by_uuid: users(:active).uuid,
+          description: 'ready to freeze')
+      end
+      assert_match /can only be set if properties\[frobity\] value is non-empty/, err.inspect
+      proj.reload
+
+      # Can set frozen_by_uuid if all conditions are met
+      ok = proj.update_attributes(
+        frozen_by_uuid: users(:active).uuid,
+        description: 'ready to freeze',
+        properties: {'frobity' => 'bar baz'})
+      assert ok, proj.errors.messages.inspect
+
+      # Once project is frozen, cannot change name/contents, trash, or
+      # delete the project or anything beneath it
+      [proj, proj_inner, coll].each do |frozen|
+        assert_raises do
+          frozen.update_attributes!(name: 'foo2')
+        end
+        if frozen.is_a?(Collection)
+          assert_raises do
+            frozen.update_attributes!(manifest_text: ". d41d8cd98f00b204e9800998ecf8427e+0 0:0:foo\n")
+          end
+        end
+        assert_raises do
+          frozen.update_attributes!(trash_at: db_current_time)
+        end
+        assert_raises do
+          frozen.destroy
+        end
+      end
+
+      # Once project is frozen, cannot create new items inside it or
+      # its descendants
+      [proj, proj_inner].each do |parent|
+        assert_raises do
+          Collection.create!(owner_uuid: parent.uuid, name: 'inside-frozen-project')
+        end
+        assert_raises do
+          Group.create!(owner_uuid: parent.uuid, group_class: 'project', name: 'inside-frozen-project')
+        end
+        cr = ContainerRequest.create(
+          command: ["echo", "foo"],
+          container_image: links(:docker_image_collection_tag).name,
+          cwd: "/tmp",
+          environment: {},
+          mounts: {"/out" => {"kind" => "tmp", "capacity" => 1000000}},
+          output_path: "/out",
+          runtime_constraints: {"vcpus" => 1, "ram" => 2},
+          name: "foo",
+          description: "bar",
+          owner_uuid: parent.uuid,
+        )
+        assert_raises do
+          cr.save!
+        end
+        assert_match cr.errors.inspect, /frozen/
+      end
+
+      # User with manage permission can unfreeze, then create items
+      # inside it and its children
+      assert proj.update_attributes(frozen_by_uuid: nil)
+      assert Collection.create!(owner_uuid: proj.uuid, name: 'inside-unfrozen-project')
+      assert Collection.create!(owner_uuid: proj_inner.uuid, name: 'inside-inner-unfrozen-project')
+
+      # Re-freeze, and reconfigure so only admins can unfreeze.
+      assert proj.update_attributes(frozen_by_uuid: users(:active).uuid)
+      Rails.configuration.API.UnfreezeProjectRequiresAdmin = true
+
+      # Owner cannot unfreeze, because not admin.
+      err = assert_raises do
+        proj.update_attributes!(frozen_by_uuid: nil)
+      end
+      assert_match /can only be changed by an admin user, once set/, err.inspect
+      proj.reload
+
+      act_as_user users(:admin) do
+        # Even admin cannot change frozen_by_uuid to someone else's UUID.
+        err = assert_raises do
+          proj.update_attributes!(frozen_by_uuid: users(:project_viewer).uuid)
+        end
+        assert_match /can only be set to the current user's UUID/, err.inspect
+        proj.reload
+
+        # Admin can unfreeze.
+        assert proj.update_attributes(frozen_by_uuid: nil), proj.errors.messages
+      end
+    end
+  end
 end