+# Copyright (C) The Arvados Authors. All rights reserved.
+#
+# SPDX-License-Identifier: AGPL-3.0
+
require 'test_helper'
class Arvados::V1::CollectionsControllerTest < ActionController::TestCase
def permit_unsigned_manifests isok=true
# Set security model for the life of a test.
- Rails.configuration.permit_create_collection_with_unsigned_manifest = isok
+ Rails.configuration.Collections.BlobSigning = !isok
end
- def assert_signed_manifest manifest_text, label=''
+ def assert_signed_manifest manifest_text, label='', token: false
assert_not_nil manifest_text, "#{label} manifest_text was nil"
manifest_text.scan(/ [[:xdigit:]]{32}\S*/) do |tok|
assert_match(PERM_TOKEN_RE, tok,
"Locator in #{label} manifest_text was not signed")
+ if token
+ bare = tok.gsub(/\+A[^\+]*/, '').sub(/^ /, '')
+ exp = tok[/\+A[[:xdigit:]]+@([[:xdigit:]]+)/, 1].to_i(16)
+ sig = Blob.sign_locator(
+ bare,
+ key: Rails.configuration.Collections.BlobSigningKey,
+ expire: exp,
+ api_token: token)[/\+A[^\+]*/, 0]
+ assert_includes tok, sig
+ end
end
end
assert(assigns(:objects).andand.any?, "no Collections returned in index")
refute(json_response["items"].any? { |c| c.has_key?("manifest_text") },
"basic Collections index included manifest_text")
+ refute(json_response["items"].any? { |c| c["uuid"] == collections(:collection_owned_by_active_past_version_1).uuid },
+ "basic Collections index included past version")
+ end
+
+ test "get index with include_old_versions" do
+ authorize_with :active
+ get :index, params: {
+ include_old_versions: true
+ }
+ assert_response :success
+ assert(assigns(:objects).andand.any?, "no Collections returned in index")
+ assert(json_response["items"].any? { |c| c["uuid"] == collections(:collection_owned_by_active_past_version_1).uuid },
+ "past version not included on index")
end
test "collections.get returns signed locators, and no unsigned_manifest_text" do
permit_unsigned_manifests
authorize_with :active
- get :show, {id: collections(:foo_file).uuid}
+ get :show, params: {id: collections(:foo_file).uuid}
assert_response :success
assert_signed_manifest json_response['manifest_text'], 'foo_file'
refute_includes json_response, 'unsigned_manifest_text'
end
+ ['v1token', 'v2token'].each do |token_method|
+ test "correct signatures are given for #{token_method}" do
+ token = api_client_authorizations(:active).send(token_method)
+ authorize_with_token token
+ get :show, params: {id: collections(:foo_file).uuid}
+ assert_response :success
+ assert_signed_manifest json_response['manifest_text'], 'foo_file', token: token
+ end
+
+ test "signatures with #{token_method} are accepted" do
+ token = api_client_authorizations(:active).send(token_method)
+ signed = Blob.sign_locator(
+ 'acbd18db4cc2f85cedef654fccc4a4d8+3',
+ key: Rails.configuration.Collections.BlobSigningKey,
+ api_token: token)
+ authorize_with_token token
+ put :update, params: {
+ id: collections(:collection_owned_by_active).uuid,
+ collection: {
+ manifest_text: ". #{signed} 0:3:foo.txt\n",
+ },
+ }
+ assert_response :success
+ assert_signed_manifest json_response['manifest_text'], 'updated', token: token
+ end
+ end
+
test "index with manifest_text selected returns signed locators" do
columns = %w(uuid owner_uuid manifest_text)
authorize_with :active
- get :index, select: columns
+ get :index, params: {select: columns}
assert_response :success
assert(assigns(:objects).andand.any?,
"no Collections returned for index with columns selected")
test "index with unsigned_manifest_text selected returns only unsigned locators" do
authorize_with :active
- get :index, select: ['unsigned_manifest_text']
+ get :index, params: {select: ['unsigned_manifest_text']}
assert_response :success
assert_operator json_response["items"].count, :>, 0
locs = 0
['', nil, false, 'null'].each do |select|
test "index with select=#{select.inspect} returns everything except manifest" do
authorize_with :active
- get :index, select: select
+ get :index, params: {select: select}
assert_response :success
assert json_response['items'].any?
json_response['items'].each do |coll|
'["uuid", "manifest_text"]'].each do |select|
test "index with select=#{select.inspect} returns no name" do
authorize_with :active
- get :index, select: select
+ get :index, params: {select: select}
assert_response :success
assert json_response['items'].any?
json_response['items'].each do |coll|
[0,1,2].each do |limit|
test "get index with limit=#{limit}" do
authorize_with :active
- get :index, limit: limit
+ get :index, params: {limit: limit}
assert_response :success
assert_equal limit, assigns(:objects).count
resp = JSON.parse(@response.body)
test "items.count == items_available" do
authorize_with :active
- get :index, limit: 100000
+ get :index, params: {limit: 100000}
assert_response :success
resp = JSON.parse(@response.body)
assert_equal resp['items_available'], assigns(:objects).length
test "items.count == items_available with filters" do
authorize_with :active
- get :index, {
+ get :index, params: {
limit: 100,
filters: [['uuid','=',collections(:foo_file).uuid]]
}
test "get index with limit=2 offset=99999" do
# Assume there are not that many test fixtures.
authorize_with :active
- get :index, limit: 2, offset: 99999
+ get :index, params: {limit: 2, offset: 99999}
assert_response :success
assert_equal 0, assigns(:objects).count
resp = JSON.parse(@response.body)
def request_capped_index(params={})
authorize_with :user1_with_load
coll1 = collections(:collection_1_of_201)
- Rails.configuration.max_index_database_read =
+ Rails.configuration.API.MaxIndexDatabaseRead =
yield(coll1.manifest_text.size)
- get :index, {
+ get :index, params: {
select: %w(uuid manifest_text),
filters: [["owner_uuid", "=", coll1.owner_uuid]],
limit: 300,
# post :create will modify test_collection in place, so we save a copy first.
# Hash.deep_dup is not sufficient as it preserves references of strings (??!?)
post_collection = Marshal.load(Marshal.dump(test_collection))
- post :create, {
+ post :create, params: {
collection: post_collection
}
foo_collection = collections(:foo_file)
# Get foo_file using its portable data hash
- get :show, {
+ get :show, params: {
id: foo_collection[:portable_data_hash]
}
assert_response :success
permit_unsigned_manifests
authorize_with :active
manifest_text = ". d41d8cd98f00b204e9800998ecf8427e 0:0:foo.txt\n"
- post :create, {
+ post :create, params: {
collection: {
owner_uuid: 'zzzzz-j7d0g-rew6elm53kancon',
manifest_text: manifest_text,
permit_unsigned_manifests
authorize_with :admin
manifest_text = ". d41d8cd98f00b204e9800998ecf8427e 0:0:foo.txt\n"
- post :create, {
+ post :create, params: {
collection: {
owner_uuid: 'zzzzz-tpzed-000000000000000',
manifest_text: manifest_text,
if !unsigned
manifest_text = Collection.sign_manifest manifest_text, api_token(:active)
end
- post :create, {
+ post :create, params: {
collection: {
owner_uuid: users(:active).uuid,
manifest_text: manifest_text,
permit_unsigned_manifests
authorize_with :active
manifest_text = ". d41d8cd98f00b204e9800998ecf8427e 0:0:foo.txt\n"
- post :create, {
+ post :create, params: {
collection: {
owner_uuid: groups(:active_user_has_can_manage).uuid,
manifest_text: manifest_text,
permit_unsigned_manifests
authorize_with :active
manifest_text = ". d41d8cd98f00b204e9800998ecf8427e 0:0:foo.txt\n"
- post :create, {
+ post :create, params: {
collection: {
owner_uuid: groups(:all_users).uuid,
manifest_text: manifest_text,
permit_unsigned_manifests
authorize_with :active
manifest_text = ". d41d8cd98f00b204e9800998ecf8427e 0:0:foo.txt\n"
- post :create, {
+ post :create, params: {
collection: {
owner_uuid: groups(:public).uuid,
manifest_text: manifest_text,
permit_unsigned_manifests
authorize_with :admin
manifest_text = ". d41d8cd98f00b204e9800998ecf8427e 0:0:foo.txt\n"
- post :create, {
+ post :create, params: {
collection: {
owner_uuid: 'zzzzz-j7d0g-it30l961gq3t0oi',
manifest_text: manifest_text,
test "should create with collection passed as json" do
permit_unsigned_manifests
authorize_with :active
- post :create, {
+ post :create, params: {
collection: <<-EOS
{
"manifest_text":". d41d8cd98f00b204e9800998ecf8427e 0:0:foo.txt\n",\
test "should fail to create with checksum mismatch" do
permit_unsigned_manifests
authorize_with :active
- post :create, {
+ post :create, params: {
collection: <<-EOS
{
"manifest_text":". d41d8cd98f00b204e9800998ecf8427e 0:0:bar.txt\n",\
test "collection UUID is normalized when created" do
permit_unsigned_manifests
authorize_with :active
- post :create, {
+ post :create, params: {
collection: {
manifest_text: ". d41d8cd98f00b204e9800998ecf8427e 0:0:foo.txt\n",
portable_data_hash: "d30fe8ae534397864cb96c544f4cf102+47+Khint+Xhint+Zhint"
test "get full provenance for baz file" do
authorize_with :active
- get :provenance, id: 'ea10d51bcf88862dbcc36eb292017dfd+45'
+ get :provenance, params: {id: 'ea10d51bcf88862dbcc36eb292017dfd+45'}
assert_response :success
resp = JSON.parse(@response.body)
assert_not_nil resp['ea10d51bcf88862dbcc36eb292017dfd+45'] # baz
test "get no provenance for foo file" do
# spectator user cannot even see baz collection
authorize_with :spectator
- get :provenance, id: '1f4b0bc7583c2a7f9102c395f4ffc5e3+45'
+ get :provenance, params: {id: '1f4b0bc7583c2a7f9102c395f4ffc5e3+45'}
assert_response 404
end
test "get partial provenance for baz file" do
# spectator user can see bar->baz job, but not foo->bar job
authorize_with :spectator
- get :provenance, id: 'ea10d51bcf88862dbcc36eb292017dfd+45'
+ get :provenance, params: {id: 'ea10d51bcf88862dbcc36eb292017dfd+45'}
assert_response :success
resp = JSON.parse(@response.body)
assert_not_nil resp['ea10d51bcf88862dbcc36eb292017dfd+45'] # baz
test "search collections with 'any' operator" do
expect_pdh = collections(:docker_image).portable_data_hash
authorize_with :active
- get :index, {
+ get :index, params: {
where: { any: ['contains', expect_pdh[5..25]] }
}
assert_response :success
# Build a manifest with both signed and unsigned locators.
signing_opts = {
- key: Rails.configuration.blob_signing_key,
+ key: Rails.configuration.Collections.BlobSigningKey,
api_token: api_token(:active),
}
signed_locators = locators.collect do |x|
". " + signed_locators[1] + " 0:0:foo.txt\n" +
". " + signed_locators[2] + " 0:0:foo.txt\n"
- post :create, {
+ post :create, params: {
collection: {
manifest_text: signed_manifest,
portable_data_hash: manifest_uuid,
# TODO(twp): in phase 4, all locators will need to be signed, so
# this test should break and will need to be rewritten. Issue #2755.
signing_opts = {
- key: Rails.configuration.blob_signing_key,
+ key: Rails.configuration.Collections.BlobSigningKey,
api_token: api_token(:active),
ttl: 3600 # 1 hour
}
". " + Blob.sign_locator(locators[1], signing_opts) + " 0:0:foo.txt\n" +
". " + Blob.sign_locator(locators[2], signing_opts) + " 0:0:foo.txt\n"
- post :create, {
+ post :create, params: {
collection: {
manifest_text: signed_manifest,
portable_data_hash: manifest_uuid,
test "create fails with invalid signature" do
authorize_with :active
signing_opts = {
- key: Rails.configuration.blob_signing_key,
+ key: Rails.configuration.Collections.BlobSigningKey,
api_token: api_token(:active),
}
unsigned_manifest.length.to_s
bad_manifest = ". #{bad_locator} 0:0:foo.txt\n"
- post :create, {
+ post :create, params: {
collection: {
manifest_text: bad_manifest,
portable_data_hash: manifest_uuid
test "create fails with uuid of signed manifest" do
authorize_with :active
signing_opts = {
- key: Rails.configuration.blob_signing_key,
+ key: Rails.configuration.Collections.BlobSigningKey,
api_token: api_token(:active),
}
'+' +
signed_manifest.length.to_s
- post :create, {
+ post :create, params: {
collection: {
manifest_text: signed_manifest,
portable_data_hash: manifest_uuid
test "reject manifest with unsigned block as stream name" do
authorize_with :active
- post :create, {
+ post :create, params: {
collection: {
manifest_text: "00000000000000000000000000000000+1234 d41d8cd98f00b204e9800998ecf8427e+0 0:0:foo.txt\n"
}
portable_data_hash: manifest_uuid,
}
post_collection = Marshal.load(Marshal.dump(test_collection))
- post :create, {
+ post :create, params: {
collection: post_collection
}
assert_response :success
ea10d51bcf88862dbcc36eb292017dfd+45)
signing_opts = {
- key: Rails.configuration.blob_signing_key,
+ key: Rails.configuration.Collections.BlobSigningKey,
api_token: api_token(:active),
}
signed_locators = locators.map { |loc| Blob.sign_locator loc, signing_opts }
signed_manifest = [".", *signed_locators, "0:0:foo.txt\n"].join(" ")
- post :create, {
+ post :create, params: {
collection: {
manifest_text: signed_manifest,
portable_data_hash: manifest_uuid,
authorize_with :active
unsigned_manifest = ". 0cc175b9c0f1b6a831c399e269772661+1 0:1:a.txt\n"
manifest_uuid = Digest::MD5.hexdigest(unsigned_manifest)
- post :create, {
+ post :create, params: {
collection: {
manifest_text: unsigned_manifest,
portable_data_hash: manifest_uuid,
test 'List expired collection returns empty list' do
authorize_with :active
- get :index, {
+ get :index, params: {
where: {name: 'expired_collection'},
}
assert_response :success
test 'Show expired collection returns 404' do
authorize_with :active
- get :show, {
+ get :show, params: {
id: 'zzzzz-4zz18-mto52zx1s7sn3ih',
}
assert_response 404
test 'Update expired collection returns 404' do
authorize_with :active
- post :update, {
+ post :update, params: {
id: 'zzzzz-4zz18-mto52zx1s7sn3ih',
collection: {
name: "still expired"
test 'List collection with future expiration time succeeds' do
authorize_with :active
- get :index, {
+ get :index, params: {
where: {name: 'collection_expires_in_future'},
}
found = assigns(:objects)
test 'Show collection with future expiration time succeeds' do
authorize_with :active
- get :show, {
+ get :show, params: {
id: 'zzzzz-4zz18-padkqo7yb8d9i3j',
}
assert_response :success
test 'Update collection with future expiration time succeeds' do
authorize_with :active
- post :update, {
+ post :update, params: {
id: 'zzzzz-4zz18-padkqo7yb8d9i3j',
collection: {
name: "still not expired"
test "get collection and verify that file_names is not included" do
authorize_with :active
- get :show, {id: collections(:foo_file).uuid}
+ get :show, params: {id: collections(:foo_file).uuid}
assert_response :success
assert_equal collections(:foo_file).uuid, json_response['uuid']
assert_nil json_response['file_names']
description = description + description
end
- post :create, collection: {
- manifest_text: ". d41d8cd98f00b204e9800998ecf8427e+0 0:0:foo.txt\n",
- description: description,
+ post :create, params: {
+ collection: {
+ manifest_text: ". d41d8cd98f00b204e9800998ecf8427e+0 0:0:foo.txt\n",
+ description: description,
+ }
}
assert_response expected_response
[1, 5, nil].each do |ask|
test "Set replication_desired=#{ask.inspect}" do
- Rails.configuration.default_collection_replication = 2
+ Rails.configuration.Collections.DefaultReplication = 2
authorize_with :active
- put :update, {
+ put :update, params: {
id: collections(:replication_undesired_unconfirmed).uuid,
collection: {
replication_desired: ask,
test "get collection with properties" do
authorize_with :active
- get :show, {id: collections(:collection_with_one_property).uuid}
+ get :show, params: {id: collections(:collection_with_one_property).uuid}
assert_response :success
assert_not_nil json_response['uuid']
assert_equal 'value1', json_response['properties']['property1']
end
- test "create collection with properties" do
+ [
+ {'property_1' => 'value_1'},
+ "{\"property_1\":\"value_1\"}",
+ ].each do |p|
+ test "create collection with valid properties param #{p.inspect}" do
+ authorize_with :active
+ manifest_text = ". d41d8cd98f00b204e9800998ecf8427e 0:0:foo.txt\n"
+ post :create, params: {
+ collection: {
+ manifest_text: manifest_text,
+ portable_data_hash: "d30fe8ae534397864cb96c544f4cf102+47",
+ properties: p
+ }
+ }
+ assert_response :success
+ assert_not_nil json_response['uuid']
+ assert_equal Hash, json_response['properties'].class, 'Collection properties attribute should be of type hash'
+ assert_equal 'value_1', json_response['properties']['property_1']
+ end
+ end
+
+ [
+ false,
+ [],
+ 42,
+ 'some string',
+ '["json", "encoded", "array"]',
+ ].each do |p|
+ test "create collection with non-valid properties param #{p.inspect}" do
+ authorize_with :active
+ post :create, params: {
+ collection: {
+ name: "test collection with non-valid properties param '#{p.inspect}'",
+ manifest_text: '',
+ properties: p
+ }
+ }
+ assert_response 422
+ response_errors = json_response['errors']
+ assert_not_nil response_errors, 'Expected error in response'
+ end
+ end
+
+ [
+ [". d41d8cd98f00b204e9800998ecf8427e 0:34:foo.txt\n", 1, 34],
+ [". d41d8cd98f00b204e9800998ecf8427e 0:34:foo.txt 0:30:foo.txt 0:30:foo1.txt 0:30:foo2.txt 0:30:foo3.txt 0:30:foo4.txt\n", 5, 184],
+ [". d41d8cd98f00b204e9800998ecf8427e 0:0:.\n", 0, 0]
+ ].each do |manifest, count, size|
+ test "create collection with valid manifest #{manifest} and expect file stats" do
+ authorize_with :active
+ post :create, params: {
+ collection: {
+ manifest_text: manifest
+ }
+ }
+ assert_response 200
+ assert_equal count, json_response['file_count']
+ assert_equal size, json_response['file_size_total']
+ end
+ end
+
+ test "update collection manifest and expect new file stats" do
authorize_with :active
- manifest_text = ". d41d8cd98f00b204e9800998ecf8427e 0:0:foo.txt\n"
- post :create, {
+ post :update, params: {
+ id: collections(:collection_owned_by_active_with_file_stats).uuid,
collection: {
- manifest_text: manifest_text,
- portable_data_hash: "d30fe8ae534397864cb96c544f4cf102+47",
- properties: {'property_1' => 'value_1'}
+ manifest_text: ". d41d8cd98f00b204e9800998ecf8427e 0:34:foo.txt\n"
}
}
- assert_response :success
- assert_not_nil json_response['uuid']
- assert_equal 'value_1', json_response['properties']['property_1']
+ assert_response 200
+ assert_equal 1, json_response['file_count']
+ assert_equal 34, json_response['file_size_total']
+ end
+
+ [
+ ['file_count', 1],
+ ['file_size_total', 34]
+ ].each do |attribute, val|
+ test "create collection with #{attribute} and expect overwrite" do
+ authorize_with :active
+ post :create, params: {
+ collection: {
+ manifest_text: ". d41d8cd98f00b204e9800998ecf8427e 0:34:foo.txt\n",
+ "#{attribute}": 10
+ }
+ }
+ assert_response 200
+ assert_equal val, json_response[attribute]
+ end
+ end
+
+ [
+ ['file_count', 1],
+ ['file_size_total', 3]
+ ].each do |attribute, val|
+ test "update collection with #{attribute} and expect ignore" do
+ authorize_with :active
+ post :update, params: {
+ id: collections(:collection_owned_by_active_with_file_stats).uuid,
+ collection: {
+ "#{attribute}": 10
+ }
+ }
+ assert_response 200
+ assert_equal val, json_response[attribute]
+ end
+ end
+
+ [
+ ['file_count', 1],
+ ['file_size_total', 34]
+ ].each do |attribute, val|
+ test "update collection with #{attribute} and manifest and expect manifest values" do
+ authorize_with :active
+ post :update, params: {
+ id: collections(:collection_owned_by_active_with_file_stats).uuid,
+ collection: {
+ manifest_text: ". d41d8cd98f00b204e9800998ecf8427e 0:34:foo.txt\n",
+ "#{attribute}": 10
+ }
+ }
+ assert_response 200
+ assert_equal val, json_response[attribute]
+ end
end
[
].each do |manifest_text|
test "create collection with invalid manifest #{manifest_text} and expect error" do
authorize_with :active
- post :create, {
+ post :create, params: {
collection: {
manifest_text: manifest_text,
portable_data_hash: "d41d8cd98f00b204e9800998ecf8427e+0"
].each do |manifest_text, pdh|
test "create collection with valid manifest #{manifest_text.inspect} and expect success" do
authorize_with :active
- post :create, {
+ post :create, params: {
collection: {
manifest_text: manifest_text,
portable_data_hash: pdh
].each do |manifest_text|
test "update collection with invalid manifest #{manifest_text} and expect error" do
authorize_with :active
- post :update, {
+ post :update, params: {
id: 'zzzzz-4zz18-bv31uwvy3neko21',
collection: {
manifest_text: manifest_text,
].each do |manifest_text|
test "update collection with valid manifest #{manifest_text.inspect} and expect success" do
authorize_with :active
- post :update, {
+ post :update, params: {
id: 'zzzzz-4zz18-bv31uwvy3neko21',
collection: {
manifest_text: manifest_text,
end
end
- test 'get trashed collection with include_trash' do
- uuid = 'zzzzz-4zz18-mto52zx1s7sn3ih' # expired_collection
+ [true, false].each do |include_trash|
+ test "get trashed collection with include_trash=#{include_trash}" do
+ uuid = 'zzzzz-4zz18-mto52zx1s7sn3ih' # expired_collection
+ authorize_with :active
+ get :show, params: {
+ id: uuid,
+ include_trash: include_trash,
+ }
+ if include_trash
+ assert_response 200
+ else
+ assert_response 404
+ end
+ end
+ end
+
+ [:admin, :active].each do |user|
+ test "get trashed collection via filters and #{user} user" do
+ uuid = 'zzzzz-4zz18-mto52zx1s7sn3ih' # expired_collection
+ authorize_with user
+ get :index, params: {
+ filters: [["current_version_uuid", "=", uuid]],
+ include_trash: true,
+ }
+ assert_response 200
+ # Only the current version is returned
+ assert_equal 1, json_response["items"].size
+ end
+ end
+
+ [:admin, :active].each do |user|
+ test "get trashed collection via filters and #{user} user, including its past versions" do
+ uuid = 'zzzzz-4zz18-mto52zx1s7sn3ih' # expired_collection
+ authorize_with :admin
+ get :index, params: {
+ filters: [["current_version_uuid", "=", uuid]],
+ include_trash: true,
+ include_old_versions: true,
+ }
+ assert_response 200
+ # Both current & past version are returned
+ assert_equal 2, json_response["items"].size
+ end
+ end
+
+ test "trash collection also trash its past versions" do
+ uuid = collections(:collection_owned_by_active).uuid
authorize_with :active
- get :show, {
+ versions = Collection.where(current_version_uuid: uuid)
+ assert_equal 2, versions.size
+ versions.each do |col|
+ refute col.is_trashed
+ end
+ post :trash, params: {
id: uuid,
- include_trash: true,
}
assert_response 200
+ versions = Collection.where(current_version_uuid: uuid)
+ assert_equal 2, versions.size
+ versions.each do |col|
+ assert col.is_trashed
+ end
end
test 'get trashed collection without include_trash' do
uuid = 'zzzzz-4zz18-mto52zx1s7sn3ih' # expired_collection
authorize_with :active
- get :show, {
+ get :show, params: {
id: uuid,
}
assert_response 404
test 'trash collection using http DELETE verb' do
uuid = collections(:collection_owned_by_active).uuid
authorize_with :active
- delete :destroy, {
+ delete :destroy, params: {
id: uuid,
}
assert_response 200
- c = Collection.unscoped.find_by_uuid(uuid)
+ c = Collection.find_by_uuid(uuid)
assert_operator c.trash_at, :<, db_current_time
- assert_equal c.delete_at, c.trash_at + Rails.configuration.blob_signature_ttl
+ assert_equal c.delete_at, c.trash_at + Rails.configuration.Collections.BlobSigningTTL
end
test 'delete long-trashed collection immediately using http DELETE verb' do
uuid = 'zzzzz-4zz18-mto52zx1s7sn3ih' # expired_collection
authorize_with :active
- delete :destroy, {
+ delete :destroy, params: {
id: uuid,
}
assert_response 200
- c = Collection.unscoped.find_by_uuid(uuid)
+ c = Collection.find_by_uuid(uuid)
assert_operator c.trash_at, :<, db_current_time
assert_operator c.delete_at, :<, db_current_time
end
end
authorize_with :active
time_before_trashing = db_current_time
- post :trash, {
+ post :trash, params: {
id: uuid,
}
assert_response 200
- c = Collection.unscoped.find_by_uuid(uuid)
+ c = Collection.find_by_uuid(uuid)
assert_operator c.trash_at, :<, db_current_time
- assert_operator c.delete_at, :>=, time_before_trashing + Rails.configuration.default_trash_lifetime
+ assert_operator c.delete_at, :>=, time_before_trashing + Rails.configuration.Collections.DefaultTrashLifetime
end
end
test 'untrash a trashed collection' do
authorize_with :active
- post :untrash, {
+ post :untrash, params: {
id: collections(:expired_collection).uuid,
}
assert_response 200
test 'untrash error on not trashed collection' do
authorize_with :active
- post :untrash, {
+ post :untrash, params: {
id: collections(:collection_owned_by_active).uuid,
}
assert_response 422
[:active, :admin].each do |user|
test "get trashed collections as #{user}" do
authorize_with user
- get :index, {
+ get :index, params: {
filters: [["is_trashed", "=", true]],
include_trash: true,
}
end
end
end
+
+ test 'untrash collection with same name as another with no ensure unique name' do
+ authorize_with :active
+ post :untrash, params: {
+ id: collections(:trashed_collection_to_test_name_conflict_on_untrash).uuid,
+ }
+ assert_response 422
+ end
+
+ test 'untrash collection with same name as another with ensure unique name' do
+ authorize_with :active
+ post :untrash, params: {
+ id: collections(:trashed_collection_to_test_name_conflict_on_untrash).uuid,
+ ensure_unique_name: true
+ }
+ assert_response 200
+ assert_equal false, json_response['is_trashed']
+ assert_nil json_response['trash_at']
+ assert_nil json_response['delete_at']
+ assert_match /^same name for trashed and persisted collections \(\d{4}-\d\d-\d\d.*?Z\)$/, json_response['name']
+ end
+
+ test 'cannot show collection in trashed subproject' do
+ authorize_with :active
+ get :show, params: {
+ id: collections(:collection_in_trashed_subproject).uuid,
+ format: :json
+ }
+ assert_response 404
+ end
+
+ test 'can show collection in untrashed subproject' do
+ authorize_with :active
+ Group.find_by_uuid(groups(:trashed_project).uuid).update! is_trashed: false
+ get :show, params: {
+ id: collections(:collection_in_trashed_subproject).uuid,
+ format: :json,
+ }
+ assert_response :success
+ end
+
+ test 'cannot index collection in trashed subproject' do
+ authorize_with :active
+ get :index, params: { limit: 1000 }
+ assert_response :success
+ item_uuids = json_response['items'].map do |item|
+ item['uuid']
+ end
+ assert_not_includes(item_uuids, collections(:collection_in_trashed_subproject).uuid)
+ end
+
+ test 'can index collection in untrashed subproject' do
+ authorize_with :active
+ Group.find_by_uuid(groups(:trashed_project).uuid).update! is_trashed: false
+ get :index, params: { limit: 1000 }
+ assert_response :success
+ item_uuids = json_response['items'].map do |item|
+ item['uuid']
+ end
+ assert_includes(item_uuids, collections(:collection_in_trashed_subproject).uuid)
+ end
+
+ test 'can index trashed subproject collection with include_trash' do
+ authorize_with :active
+ get :index, params: {
+ include_trash: true,
+ limit: 1000
+ }
+ assert_response :success
+ item_uuids = json_response['items'].map do |item|
+ item['uuid']
+ end
+ assert_includes(item_uuids, collections(:collection_in_trashed_subproject).uuid)
+ end
+
+ test 'can get collection with past versions' do
+ authorize_with :active
+ get :index, params: {
+ filters: [['current_version_uuid','=',collections(:collection_owned_by_active).uuid]],
+ include_old_versions: true
+ }
+ assert_response :success
+ assert_equal 2, assigns(:objects).length
+ assert_equal 2, json_response['items_available']
+ assert_equal 2, json_response['items'].count
+ json_response['items'].each do |c|
+ assert_equal collections(:collection_owned_by_active).uuid,
+ c['current_version_uuid'],
+ 'response includes a version from a different collection'
+ end
+ end
+
+ test 'can get old version collection by uuid' do
+ authorize_with :active
+ get :show, params: {
+ id: collections(:collection_owned_by_active_past_version_1).uuid,
+ }
+ assert_response :success
+ assert_equal collections(:collection_owned_by_active_past_version_1).name,
+ json_response['name']
+ end
+
+ test 'version and current_version_uuid are ignored at creation time' do
+ permit_unsigned_manifests
+ authorize_with :active
+ manifest_text = ". d41d8cd98f00b204e9800998ecf8427e 0:0:foo.txt\n"
+ post :create, params: {
+ collection: {
+ name: 'Test collection',
+ version: 42,
+ current_version_uuid: collections(:collection_owned_by_active).uuid,
+ manifest_text: manifest_text,
+ }
+ }
+ assert_response :success
+ resp = JSON.parse(@response.body)
+ assert_equal 1, resp['version']
+ assert_equal resp['uuid'], resp['current_version_uuid']
+ end
+
+ test "update collection with versioning enabled" do
+ Rails.configuration.Collections.CollectionVersioning = true
+ Rails.configuration.Collections.PreserveVersionIfIdle = 1 # 1 second
+
+ col = collections(:collection_owned_by_active)
+ assert_equal 2, col.version
+ assert col.modified_at < Time.now - 1.second
+
+ token = api_client_authorizations(:active).v2token
+ signed = Blob.sign_locator(
+ 'acbd18db4cc2f85cedef654fccc4a4d8+3',
+ key: Rails.configuration.Collections.BlobSigningKey,
+ api_token: token)
+ authorize_with_token token
+ put :update, params: {
+ id: col.uuid,
+ collection: {
+ manifest_text: ". #{signed} 0:3:foo.txt\n",
+ },
+ }
+ assert_response :success
+ assert_equal 3, json_response['version']
+ end
+
+ test "delete collection with versioning enabled" do
+ Rails.configuration.Collections.CollectionVersioning = true
+ Rails.configuration.Collections.PreserveVersionIfIdle = 1 # 1 second
+
+ col = collections(:collection_owned_by_active)
+ assert_equal 2, col.version
+ assert col.modified_at < Time.now - 1.second
+
+ authorize_with(:active)
+ post :trash, params: {
+ id: col.uuid,
+ }
+ assert_response :success
+ assert_equal col.version, json_response['version'], 'Trashing a collection should not create a new version'
+ end
end