3 class Arvados::V1::CollectionsControllerTest < ActionController::TestCase
6 def permit_unsigned_manifests isok=true
7 # Set security model for the life of a test.
8 Rails.configuration.permit_create_collection_with_unsigned_manifest = isok
11 def assert_signed_manifest manifest_text, label=''
12 assert_not_nil manifest_text, "#{label} manifest_text was nil"
13 manifest_text.scan(/ [[:xdigit:]]{32}\S*/) do |tok|
14 assert_match(/\+A[[:xdigit:]]+@[[:xdigit:]]{8}\b/, tok,
15 "Locator in #{label} manifest_text was not signed")
19 test "should get index" do
20 authorize_with :active
22 assert_response :success
23 assert(assigns(:objects).andand.any?, "no Collections returned in index")
24 refute(json_response["items"].any? { |c| c.has_key?("manifest_text") },
25 "basic Collections index included manifest_text")
28 test "collections.get returns signed locators" do
29 permit_unsigned_manifests
30 authorize_with :active
31 get :show, {id: collections(:foo_file).uuid}
32 assert_response :success
33 assert_signed_manifest json_response['manifest_text'], 'foo_file'
36 test "index with manifest_text selected returns signed locators" do
37 columns = %w(uuid owner_uuid manifest_text)
38 authorize_with :active
39 get :index, select: columns
40 assert_response :success
41 assert(assigns(:objects).andand.any?,
42 "no Collections returned for index with columns selected")
43 json_response["items"].each do |coll|
44 assert_equal(columns, columns & coll.keys,
45 "Collections index did not respect selected columns")
46 assert_signed_manifest coll['manifest_text'], coll['uuid']
50 test 'index without select returns everything except manifest' do
51 authorize_with :active
53 assert_response :success
54 assert json_response['items'].any?
55 json_response['items'].each do |coll|
56 assert_includes(coll.keys, 'uuid')
57 assert_includes(coll.keys, 'name')
58 assert_includes(coll.keys, 'created_at')
59 refute_includes(coll.keys, 'manifest_text')
63 ['', nil, false, 'null'].each do |select|
64 test "index with select=#{select.inspect} returns everything except manifest" do
65 authorize_with :active
66 get :index, select: select
67 assert_response :success
68 assert json_response['items'].any?
69 json_response['items'].each do |coll|
70 assert_includes(coll.keys, 'uuid')
71 assert_includes(coll.keys, 'name')
72 assert_includes(coll.keys, 'created_at')
73 refute_includes(coll.keys, 'manifest_text')
79 ["uuid", "manifest_text"],
81 '["uuid", "manifest_text"]'].each do |select|
82 test "index with select=#{select.inspect} returns no name" do
83 authorize_with :active
84 get :index, select: select
85 assert_response :success
86 assert json_response['items'].any?
87 json_response['items'].each do |coll|
88 refute_includes(coll.keys, 'name')
93 [0,1,2].each do |limit|
94 test "get index with limit=#{limit}" do
95 authorize_with :active
96 get :index, limit: limit
97 assert_response :success
98 assert_equal limit, assigns(:objects).count
99 resp = JSON.parse(@response.body)
100 assert_equal limit, resp['limit']
104 test "items.count == items_available" do
105 authorize_with :active
106 get :index, limit: 100000
107 assert_response :success
108 resp = JSON.parse(@response.body)
109 assert_equal resp['items_available'], assigns(:objects).length
110 assert_equal resp['items_available'], resp['items'].count
111 unique_uuids = resp['items'].collect { |i| i['uuid'] }.compact.uniq
112 assert_equal unique_uuids.count, resp['items'].count
115 test "items.count == items_available with filters" do
116 authorize_with :active
119 filters: [['uuid','=',collections(:foo_file).uuid]]
121 assert_response :success
122 assert_equal 1, assigns(:objects).length
123 assert_equal 1, json_response['items_available']
124 assert_equal 1, json_response['items'].count
127 test "get index with limit=2 offset=99999" do
128 # Assume there are not that many test fixtures.
129 authorize_with :active
130 get :index, limit: 2, offset: 99999
131 assert_response :success
132 assert_equal 0, assigns(:objects).count
133 resp = JSON.parse(@response.body)
134 assert_equal 2, resp['limit']
135 assert_equal 99999, resp['offset']
138 def request_capped_index(params={})
139 authorize_with :user1_with_load
140 coll1 = collections(:collection_1_of_201)
141 Rails.configuration.max_index_database_read =
142 yield(coll1.manifest_text.size)
144 select: %w(uuid manifest_text),
145 filters: [["owner_uuid", "=", coll1.owner_uuid]],
150 test "index with manifest_text limited by max_index_database_read returns non-empty" do
151 request_capped_index() { |_| 1 }
152 assert_response :success
153 assert_equal(1, json_response["items"].size)
154 assert_equal(1, json_response["limit"])
155 assert_equal(201, json_response["items_available"])
158 test "max_index_database_read size check follows same order as real query" do
159 authorize_with :user1_with_load
160 txt = '.' + ' d41d8cd98f00b204e9800998ecf8427e+0'*1000 + " 0:0:empty.txt\n"
161 c = Collection.create! manifest_text: txt, name: '0000000000000000000'
162 request_capped_index(select: %w(uuid manifest_text name),
164 filters: [['name','>=',c.name]]) do |_|
167 assert_response :success
168 assert_equal(1, json_response["items"].size)
169 assert_equal(1, json_response["limit"])
170 assert_equal(c.uuid, json_response["items"][0]["uuid"])
171 # The effectiveness of the test depends on >1 item matching the filters.
172 assert_operator(1, :<, json_response["items_available"])
175 test "index with manifest_text limited by max_index_database_read" do
176 request_capped_index() { |size| (size * 3) + 1 }
177 assert_response :success
178 assert_equal(3, json_response["items"].size)
179 assert_equal(3, json_response["limit"])
180 assert_equal(201, json_response["items_available"])
183 test "max_index_database_read does not interfere with limit" do
184 request_capped_index(limit: 5) { |size| size * 20 }
185 assert_response :success
186 assert_equal(5, json_response["items"].size)
187 assert_equal(5, json_response["limit"])
188 assert_equal(201, json_response["items_available"])
191 test "max_index_database_read does not interfere with order" do
192 request_capped_index(select: %w(uuid manifest_text name),
193 order: "name DESC") { |size| (size * 11) + 1 }
194 assert_response :success
195 assert_equal(11, json_response["items"].size)
196 assert_empty(json_response["items"].reject do |coll|
197 coll["name"] =~ /^Collection_9/
199 assert_equal(11, json_response["limit"])
200 assert_equal(201, json_response["items_available"])
203 test "admin can create collection with unsigned manifest" do
204 authorize_with :admin
206 manifest_text: <<-EOS
207 . d41d8cd98f00b204e9800998ecf8427e+0 0:0:foo.txt
208 . acbd18db4cc2f85cedef654fccc4a4d8+3 0:3:bar.txt
209 . acbd18db4cc2f85cedef654fccc4a4d8+3 0:3:bar.txt
210 ./baz acbd18db4cc2f85cedef654fccc4a4d8+3 0:3:bar.txt
213 test_collection[:portable_data_hash] =
214 Digest::MD5.hexdigest(test_collection[:manifest_text]) +
216 test_collection[:manifest_text].length.to_s
218 # post :create will modify test_collection in place, so we save a copy first.
219 # Hash.deep_dup is not sufficient as it preserves references of strings (??!?)
220 post_collection = Marshal.load(Marshal.dump(test_collection))
222 collection: post_collection
225 assert_response :success
226 assert_nil assigns(:objects)
228 response_collection = assigns(:object)
230 stored_collection = Collection.select([:uuid, :portable_data_hash, :manifest_text]).
231 where(portable_data_hash: response_collection['portable_data_hash']).first
233 assert_equal test_collection[:portable_data_hash], stored_collection['portable_data_hash']
235 # The manifest in the response will have had permission hints added.
236 # Remove any permission hints in the response before comparing it to the source.
237 stripped_manifest = stored_collection['manifest_text'].gsub(/\+A[A-Za-z0-9@_-]+/, '')
238 assert_equal test_collection[:manifest_text], stripped_manifest
240 # TBD: create action should add permission signatures to manifest_text in the response,
241 # and we need to check those permission signatures here.
244 [:admin, :active].each do |user|
245 test "#{user} can get collection using portable data hash" do
248 foo_collection = collections(:foo_file)
250 # Get foo_file using its portable data hash
252 id: foo_collection[:portable_data_hash]
254 assert_response :success
255 assert_not_nil assigns(:object)
256 resp = assigns(:object)
257 assert_equal foo_collection[:portable_data_hash], resp['portable_data_hash']
258 assert_signed_manifest resp['manifest_text']
260 # The manifest in the response will have had permission hints added.
261 # Remove any permission hints in the response before comparing it to the source.
262 stripped_manifest = resp['manifest_text'].gsub(/\+A[A-Za-z0-9@_-]+/, '')
263 assert_equal foo_collection[:manifest_text], stripped_manifest
267 test "create with owner_uuid set to owned group" do
268 permit_unsigned_manifests
269 authorize_with :active
270 manifest_text = ". d41d8cd98f00b204e9800998ecf8427e 0:0:foo.txt\n"
273 owner_uuid: 'zzzzz-j7d0g-rew6elm53kancon',
274 manifest_text: manifest_text,
275 portable_data_hash: "d30fe8ae534397864cb96c544f4cf102+47"
278 assert_response :success
279 resp = JSON.parse(@response.body)
280 assert_equal 'zzzzz-j7d0g-rew6elm53kancon', resp['owner_uuid']
283 test "create fails with duplicate name" do
284 permit_unsigned_manifests
285 authorize_with :admin
286 manifest_text = ". d41d8cd98f00b204e9800998ecf8427e 0:0:foo.txt\n"
289 owner_uuid: 'zzzzz-tpzed-000000000000000',
290 manifest_text: manifest_text,
291 portable_data_hash: "d30fe8ae534397864cb96c544f4cf102+47",
296 response_errors = json_response['errors']
297 assert_not_nil response_errors, 'Expected error in response'
298 assert(response_errors.first.include?('duplicate key'),
299 "Expected 'duplicate key' error in #{response_errors.first}")
302 [false, true].each do |unsigned|
303 test "create with duplicate name, ensure_unique_name, unsigned=#{unsigned}" do
304 permit_unsigned_manifests unsigned
305 authorize_with :active
306 manifest_text = ". acbd18db4cc2f85cedef654fccc4a4d8+3 0:0:foo.txt\n"
308 manifest_text = Collection.sign_manifest manifest_text, api_token(:active)
312 owner_uuid: users(:active).uuid,
313 manifest_text: manifest_text,
314 name: "owned_by_active"
316 ensure_unique_name: true
318 assert_response :success
319 assert_equal 'owned_by_active (2)', json_response['name']
323 test "create with owner_uuid set to group i can_manage" do
324 permit_unsigned_manifests
325 authorize_with :active
326 manifest_text = ". d41d8cd98f00b204e9800998ecf8427e 0:0:foo.txt\n"
329 owner_uuid: groups(:active_user_has_can_manage).uuid,
330 manifest_text: manifest_text,
331 portable_data_hash: "d30fe8ae534397864cb96c544f4cf102+47"
334 assert_response :success
335 resp = JSON.parse(@response.body)
336 assert_equal groups(:active_user_has_can_manage).uuid, resp['owner_uuid']
339 test "create with owner_uuid fails on group with only can_read permission" do
340 permit_unsigned_manifests
341 authorize_with :active
342 manifest_text = ". d41d8cd98f00b204e9800998ecf8427e 0:0:foo.txt\n"
345 owner_uuid: groups(:all_users).uuid,
346 manifest_text: manifest_text,
347 portable_data_hash: "d30fe8ae534397864cb96c544f4cf102+47"
353 test "create with owner_uuid fails on group with no permission" do
354 permit_unsigned_manifests
355 authorize_with :active
356 manifest_text = ". d41d8cd98f00b204e9800998ecf8427e 0:0:foo.txt\n"
359 owner_uuid: groups(:public).uuid,
360 manifest_text: manifest_text,
361 portable_data_hash: "d30fe8ae534397864cb96c544f4cf102+47"
367 test "admin create with owner_uuid set to group with no permission" do
368 permit_unsigned_manifests
369 authorize_with :admin
370 manifest_text = ". d41d8cd98f00b204e9800998ecf8427e 0:0:foo.txt\n"
373 owner_uuid: 'zzzzz-j7d0g-it30l961gq3t0oi',
374 manifest_text: manifest_text,
375 portable_data_hash: "d30fe8ae534397864cb96c544f4cf102+47"
378 assert_response :success
381 test "should create with collection passed as json" do
382 permit_unsigned_manifests
383 authorize_with :active
387 "manifest_text":". d41d8cd98f00b204e9800998ecf8427e 0:0:foo.txt\n",\
388 "portable_data_hash":"d30fe8ae534397864cb96c544f4cf102+47"\
392 assert_response :success
395 test "should fail to create with checksum mismatch" do
396 permit_unsigned_manifests
397 authorize_with :active
401 "manifest_text":". d41d8cd98f00b204e9800998ecf8427e 0:0:bar.txt\n",\
402 "portable_data_hash":"d30fe8ae534397864cb96c544f4cf102+47"\
409 test "collection UUID is normalized when created" do
410 permit_unsigned_manifests
411 authorize_with :active
414 manifest_text: ". d41d8cd98f00b204e9800998ecf8427e 0:0:foo.txt\n",
415 portable_data_hash: "d30fe8ae534397864cb96c544f4cf102+47+Khint+Xhint+Zhint"
418 assert_response :success
419 assert_not_nil assigns(:object)
420 resp = JSON.parse(@response.body)
421 assert_equal "d30fe8ae534397864cb96c544f4cf102+47", resp['portable_data_hash']
424 test "get full provenance for baz file" do
425 authorize_with :active
426 get :provenance, id: 'ea10d51bcf88862dbcc36eb292017dfd+45'
427 assert_response :success
428 resp = JSON.parse(@response.body)
429 assert_not_nil resp['ea10d51bcf88862dbcc36eb292017dfd+45'] # baz
430 assert_not_nil resp['fa7aeb5140e2848d39b416daeef4ffc5+45'] # bar
431 assert_not_nil resp['1f4b0bc7583c2a7f9102c395f4ffc5e3+45'] # foo
432 assert_not_nil resp['zzzzz-8i9sb-cjs4pklxxjykyuq'] # bar->baz
433 assert_not_nil resp['zzzzz-8i9sb-aceg2bnq7jt7kon'] # foo->bar
436 test "get no provenance for foo file" do
437 # spectator user cannot even see baz collection
438 authorize_with :spectator
439 get :provenance, id: '1f4b0bc7583c2a7f9102c395f4ffc5e3+45'
443 test "get partial provenance for baz file" do
444 # spectator user can see bar->baz job, but not foo->bar job
445 authorize_with :spectator
446 get :provenance, id: 'ea10d51bcf88862dbcc36eb292017dfd+45'
447 assert_response :success
448 resp = JSON.parse(@response.body)
449 assert_not_nil resp['ea10d51bcf88862dbcc36eb292017dfd+45'] # baz
450 assert_not_nil resp['fa7aeb5140e2848d39b416daeef4ffc5+45'] # bar
451 assert_not_nil resp['zzzzz-8i9sb-cjs4pklxxjykyuq'] # bar->baz
452 assert_nil resp['zzzzz-8i9sb-aceg2bnq7jt7kon'] # foo->bar
453 assert_nil resp['1f4b0bc7583c2a7f9102c395f4ffc5e3+45'] # foo
456 test "search collections with 'any' operator" do
457 expect_pdh = collections(:docker_image).portable_data_hash
458 authorize_with :active
460 where: { any: ['contains', expect_pdh[5..25]] }
462 assert_response :success
463 found = assigns(:objects)
464 assert_equal 1, found.count
465 assert_equal expect_pdh, found.first.portable_data_hash
468 [false, true].each do |permit_unsigned|
469 test "create collection with signed manifest, permit_unsigned=#{permit_unsigned}" do
470 permit_unsigned_manifests permit_unsigned
471 authorize_with :active
473 d41d8cd98f00b204e9800998ecf8427e+0
474 acbd18db4cc2f85cedef654fccc4a4d8+3
475 ea10d51bcf88862dbcc36eb292017dfd+45)
477 unsigned_manifest = locators.map { |loc|
478 ". " + loc + " 0:0:foo.txt\n"
480 manifest_uuid = Digest::MD5.hexdigest(unsigned_manifest) +
482 unsigned_manifest.length.to_s
484 # Build a manifest with both signed and unsigned locators.
486 key: Rails.configuration.blob_signing_key,
487 api_token: api_token(:active),
489 signed_locators = locators.collect do |x|
490 Blob.sign_locator x, signing_opts
493 # Leave a non-empty blob unsigned.
494 signed_locators[1] = locators[1]
496 # Leave the empty blob unsigned. This should still be allowed.
497 signed_locators[0] = locators[0]
500 ". " + signed_locators[0] + " 0:0:foo.txt\n" +
501 ". " + signed_locators[1] + " 0:0:foo.txt\n" +
502 ". " + signed_locators[2] + " 0:0:foo.txt\n"
506 manifest_text: signed_manifest,
507 portable_data_hash: manifest_uuid,
510 assert_response :success
511 assert_not_nil assigns(:object)
512 resp = JSON.parse(@response.body)
513 assert_equal manifest_uuid, resp['portable_data_hash']
514 # All of the locators in the output must be signed.
515 resp['manifest_text'].lines.each do |entry|
516 m = /([[:xdigit:]]{32}\+\S+)/.match(entry)
518 assert Blob.verify_signature m[0], signing_opts
524 test "create collection with signed manifest and explicit TTL" do
525 authorize_with :active
527 d41d8cd98f00b204e9800998ecf8427e+0
528 acbd18db4cc2f85cedef654fccc4a4d8+3
529 ea10d51bcf88862dbcc36eb292017dfd+45)
531 unsigned_manifest = locators.map { |loc|
532 ". " + loc + " 0:0:foo.txt\n"
534 manifest_uuid = Digest::MD5.hexdigest(unsigned_manifest) +
536 unsigned_manifest.length.to_s
538 # build a manifest with both signed and unsigned locators.
539 # TODO(twp): in phase 4, all locators will need to be signed, so
540 # this test should break and will need to be rewritten. Issue #2755.
542 key: Rails.configuration.blob_signing_key,
543 api_token: api_token(:active),
547 ". " + locators[0] + " 0:0:foo.txt\n" +
548 ". " + Blob.sign_locator(locators[1], signing_opts) + " 0:0:foo.txt\n" +
549 ". " + Blob.sign_locator(locators[2], signing_opts) + " 0:0:foo.txt\n"
553 manifest_text: signed_manifest,
554 portable_data_hash: manifest_uuid,
557 assert_response :success
558 assert_not_nil assigns(:object)
559 resp = JSON.parse(@response.body)
560 assert_equal manifest_uuid, resp['portable_data_hash']
561 # All of the locators in the output must be signed.
562 resp['manifest_text'].lines.each do |entry|
563 m = /([[:xdigit:]]{32}\+\S+)/.match(entry)
565 assert Blob.verify_signature m[0], signing_opts
570 test "create fails with invalid signature" do
571 authorize_with :active
573 key: Rails.configuration.blob_signing_key,
574 api_token: api_token(:active),
577 # Generate a locator with a bad signature.
578 unsigned_locator = "acbd18db4cc2f85cedef654fccc4a4d8+3"
579 bad_locator = unsigned_locator + "+Affffffffffffffffffffffffffffffffffffffff@ffffffff"
580 assert !Blob.verify_signature(bad_locator, signing_opts)
582 # Creating a collection with this locator should
583 # produce 403 Permission denied.
584 unsigned_manifest = ". #{unsigned_locator} 0:0:foo.txt\n"
585 manifest_uuid = Digest::MD5.hexdigest(unsigned_manifest) +
587 unsigned_manifest.length.to_s
589 bad_manifest = ". #{bad_locator} 0:0:foo.txt\n"
592 manifest_text: bad_manifest,
593 portable_data_hash: manifest_uuid
600 test "create fails with uuid of signed manifest" do
601 authorize_with :active
603 key: Rails.configuration.blob_signing_key,
604 api_token: api_token(:active),
607 unsigned_locator = "d41d8cd98f00b204e9800998ecf8427e+0"
608 signed_locator = Blob.sign_locator(unsigned_locator, signing_opts)
609 signed_manifest = ". #{signed_locator} 0:0:foo.txt\n"
610 manifest_uuid = Digest::MD5.hexdigest(signed_manifest) +
612 signed_manifest.length.to_s
616 manifest_text: signed_manifest,
617 portable_data_hash: manifest_uuid
624 test "reject manifest with unsigned block as stream name" do
625 authorize_with :active
628 manifest_text: "00000000000000000000000000000000+1234 d41d8cd98f00b204e9800998ecf8427e+0 0:0:foo.txt\n"
631 assert_includes [422, 403], response.code.to_i
634 test "multiple locators per line" do
635 permit_unsigned_manifests
636 authorize_with :active
638 d41d8cd98f00b204e9800998ecf8427e+0
639 acbd18db4cc2f85cedef654fccc4a4d8+3
640 ea10d51bcf88862dbcc36eb292017dfd+45)
642 manifest_text = [".", *locators, "0:0:foo.txt\n"].join(" ")
643 manifest_uuid = Digest::MD5.hexdigest(manifest_text) +
645 manifest_text.length.to_s
648 manifest_text: manifest_text,
649 portable_data_hash: manifest_uuid,
651 post_collection = Marshal.load(Marshal.dump(test_collection))
653 collection: post_collection
655 assert_response :success
656 assert_not_nil assigns(:object)
657 resp = JSON.parse(@response.body)
658 assert_equal manifest_uuid, resp['portable_data_hash']
660 # The manifest in the response will have had permission hints added.
661 # Remove any permission hints in the response before comparing it to the source.
662 stripped_manifest = resp['manifest_text'].gsub(/\+A[A-Za-z0-9@_-]+/, '')
663 assert_equal manifest_text, stripped_manifest
666 test "multiple signed locators per line" do
667 permit_unsigned_manifests
668 authorize_with :active
670 d41d8cd98f00b204e9800998ecf8427e+0
671 acbd18db4cc2f85cedef654fccc4a4d8+3
672 ea10d51bcf88862dbcc36eb292017dfd+45)
675 key: Rails.configuration.blob_signing_key,
676 api_token: api_token(:active),
679 unsigned_manifest = [".", *locators, "0:0:foo.txt\n"].join(" ")
680 manifest_uuid = Digest::MD5.hexdigest(unsigned_manifest) +
682 unsigned_manifest.length.to_s
684 signed_locators = locators.map { |loc| Blob.sign_locator loc, signing_opts }
685 signed_manifest = [".", *signed_locators, "0:0:foo.txt\n"].join(" ")
689 manifest_text: signed_manifest,
690 portable_data_hash: manifest_uuid,
693 assert_response :success
694 assert_not_nil assigns(:object)
695 resp = JSON.parse(@response.body)
696 assert_equal manifest_uuid, resp['portable_data_hash']
697 # All of the locators in the output must be signed.
698 # Each line is of the form "path locator locator ... 0:0:file.txt"
699 # entry.split[1..-2] will yield just the tokens in the middle of the line
700 returned_locator_count = 0
701 resp['manifest_text'].lines.each do |entry|
702 entry.split[1..-2].each do |tok|
703 returned_locator_count += 1
704 assert Blob.verify_signature tok, signing_opts
707 assert_equal locators.count, returned_locator_count
710 test 'Reject manifest with unsigned blob' do
711 permit_unsigned_manifests false
712 authorize_with :active
713 unsigned_manifest = ". 0cc175b9c0f1b6a831c399e269772661+1 0:1:a.txt\n"
714 manifest_uuid = Digest::MD5.hexdigest(unsigned_manifest)
717 manifest_text: unsigned_manifest,
718 portable_data_hash: manifest_uuid,
722 "Creating a collection with unsigned blobs should respond 403"
723 assert_empty Collection.where('uuid like ?', manifest_uuid+'%'),
724 "Collection should not exist in database after failed create"
727 test 'List expired collection returns empty list' do
728 authorize_with :active
730 where: {name: 'expired_collection'},
732 assert_response :success
733 found = assigns(:objects)
734 assert_equal 0, found.count
737 test 'Show expired collection returns 404' do
738 authorize_with :active
740 id: 'zzzzz-4zz18-mto52zx1s7sn3ih',
745 test 'Update expired collection returns 404' do
746 authorize_with :active
748 id: 'zzzzz-4zz18-mto52zx1s7sn3ih',
750 name: "still expired"
756 test 'List collection with future expiration time succeeds' do
757 authorize_with :active
759 where: {name: 'collection_expires_in_future'},
761 found = assigns(:objects)
762 assert_equal 1, found.count
766 test 'Show collection with future expiration time succeeds' do
767 authorize_with :active
769 id: 'zzzzz-4zz18-padkqo7yb8d9i3j',
771 assert_response :success
774 test 'Update collection with future expiration time succeeds' do
775 authorize_with :active
777 id: 'zzzzz-4zz18-padkqo7yb8d9i3j',
779 name: "still not expired"
782 assert_response :success
785 test "get collection and verify that file_names is not included" do
786 authorize_with :active
787 get :show, {id: collections(:foo_file).uuid}
788 assert_response :success
789 assert_equal collections(:foo_file).uuid, json_response['uuid']
790 assert_nil json_response['file_names']
791 assert json_response['manifest_text']
797 ].each do |description_size, expected_response|
798 # Descriptions are not part of search indexes. Skip until
799 # full-text search is implemented, at which point replace with a
800 # search in description.
801 skip "create collection with description size #{description_size}
802 and expect response #{expected_response}" do
803 authorize_with :active
805 description = 'here is a collection with a very large description'
806 while description.length < description_size
807 description = description + description
810 post :create, collection: {
811 manifest_text: ". d41d8cd98f00b204e9800998ecf8427e+0 0:0:foo.txt\n",
812 description: description,
815 assert_response expected_response
819 [1, 5, nil].each do |ask|
820 test "Set replication_desired=#{ask.inspect}" do
821 Rails.configuration.default_collection_replication = 2
822 authorize_with :active
824 id: collections(:replication_undesired_unconfirmed).uuid,
826 replication_desired: ask,
829 assert_response :success
830 assert_equal ask, json_response['replication_desired']
834 test "get collection with properties" do
835 authorize_with :active
836 get :show, {id: collections(:collection_with_one_property).uuid}
837 assert_response :success
838 assert_not_nil json_response['uuid']
839 assert_equal 'value1', json_response['properties']['property1']
842 test "create collection with properties" do
843 authorize_with :active
844 manifest_text = ". d41d8cd98f00b204e9800998ecf8427e 0:0:foo.txt\n"
847 manifest_text: manifest_text,
848 portable_data_hash: "d30fe8ae534397864cb96c544f4cf102+47",
849 properties: {'property_1' => 'value_1'}
852 assert_response :success
853 assert_not_nil json_response['uuid']
854 assert_equal 'value_1', json_response['properties']['property_1']
859 ". d41d8cd98f00b204e9800998ecf8427e foo.txt",
860 "d41d8cd98f00b204e9800998ecf8427e 0:0:foo.txt",
861 ". d41d8cd98f00b204e9800998ecf8427e 0:0:foo.txt",
862 ].each do |manifest_text|
863 test "create collection with invalid manifest #{manifest_text} and expect error" do
864 authorize_with :active
867 manifest_text: manifest_text,
868 portable_data_hash: "d41d8cd98f00b204e9800998ecf8427e+0"
872 response_errors = json_response['errors']
873 assert_not_nil response_errors, 'Expected error in response'
874 assert(response_errors.first.include?('Invalid manifest'),
875 "Expected 'Invalid manifest' error in #{response_errors.first}")
880 [nil, "d41d8cd98f00b204e9800998ecf8427e+0"],
881 ["", "d41d8cd98f00b204e9800998ecf8427e+0"],
882 [". d41d8cd98f00b204e9800998ecf8427e 0:0:foo.txt\n", "d30fe8ae534397864cb96c544f4cf102+47"],
883 ].each do |manifest_text, pdh|
884 test "create collection with valid manifest #{manifest_text.inspect} and expect success" do
885 authorize_with :active
888 manifest_text: manifest_text,
889 portable_data_hash: pdh
898 ". d41d8cd98f00b204e9800998ecf8427e foo.txt",
899 "d41d8cd98f00b204e9800998ecf8427e 0:0:foo.txt",
900 ". d41d8cd98f00b204e9800998ecf8427e 0:0:foo.txt",
901 ].each do |manifest_text|
902 test "update collection with invalid manifest #{manifest_text} and expect error" do
903 authorize_with :active
905 id: 'zzzzz-4zz18-bv31uwvy3neko21',
907 manifest_text: manifest_text,
911 response_errors = json_response['errors']
912 assert_not_nil response_errors, 'Expected error in response'
913 assert(response_errors.first.include?('Invalid manifest'),
914 "Expected 'Invalid manifest' error in #{response_errors.first}")
921 ". d41d8cd98f00b204e9800998ecf8427e 0:0:foo.txt\n",
922 ].each do |manifest_text|
923 test "update collection with valid manifest #{manifest_text.inspect} and expect success" do
924 authorize_with :active
926 id: 'zzzzz-4zz18-bv31uwvy3neko21',
928 manifest_text: manifest_text,
935 test 'get trashed collection with include_trash' do
936 uuid = 'zzzzz-4zz18-mto52zx1s7sn3ih' # expired_collection
937 authorize_with :active
945 test 'get trashed collection without include_trash' do
946 uuid = 'zzzzz-4zz18-mto52zx1s7sn3ih' # expired_collection
947 authorize_with :active
954 test 'trash collection using http DELETE verb' do
955 uuid = collections(:collection_owned_by_active).uuid
956 authorize_with :active
961 c = Collection.unscoped.find_by_uuid(uuid)
962 assert_operator c.trash_at, :<, db_current_time
963 assert_equal c.delete_at, c.trash_at + Rails.configuration.blob_signature_ttl
966 test 'delete long-trashed collection immediately using http DELETE verb' do
967 uuid = 'zzzzz-4zz18-mto52zx1s7sn3ih' # expired_collection
968 authorize_with :active
973 c = Collection.unscoped.find_by_uuid(uuid)
974 assert_operator c.trash_at, :<, db_current_time
975 assert_operator c.delete_at, :<, db_current_time
978 ['zzzzz-4zz18-mto52zx1s7sn3ih', # expired_collection
979 :empty_collection_name_in_active_user_home_project,
981 test "trash collection #{fixture} via trash action with grace period" do
982 if fixture.is_a? String
985 uuid = collections(fixture).uuid
987 authorize_with :active
988 time_before_trashing = db_current_time
993 c = Collection.unscoped.find_by_uuid(uuid)
994 assert_operator c.trash_at, :<, db_current_time
995 assert_operator c.delete_at, :>=, time_before_trashing + Rails.configuration.default_trash_lifetime