X-Git-Url: https://git.arvados.org/arvados.git/blobdiff_plain/cdc0e1acba106e4c6f857d1b394eaa5d38fde428..924f8f6c13c06afc8a83168929b249e0e8fa7d18:/services/api/test/functional/arvados/v1/collections_controller_test.rb diff --git a/services/api/test/functional/arvados/v1/collections_controller_test.rb b/services/api/test/functional/arvados/v1/collections_controller_test.rb index 4e8b0559aa..8a1d044d6a 100644 --- a/services/api/test/functional/arvados/v1/collections_controller_test.rb +++ b/services/api/test/functional/arvados/v1/collections_controller_test.rb @@ -32,8 +32,7 @@ class Arvados::V1::CollectionsControllerTest < ActionController::TestCase end end - def assert_unsigned_manifest resp, label='' - txt = resp['unsigned_manifest_text'] + def assert_unsigned_manifest txt, label='' assert_not_nil(txt, "#{label} unsigned_manifest_text was nil") locs = 0 txt.scan(/ [[:xdigit:]]{32}\S*/) do |tok| @@ -66,24 +65,16 @@ class Arvados::V1::CollectionsControllerTest < ActionController::TestCase "past version not included on index") end - test "collections.get returns signed locators, and no unsigned_manifest_text" do + test "collections.get returns unsigned locators, and no unsigned_manifest_text" do permit_unsigned_manifests authorize_with :active get :show, params: {id: collections(:foo_file).uuid} assert_response :success - assert_signed_manifest json_response['manifest_text'], 'foo_file' + assert_unsigned_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( @@ -98,11 +89,11 @@ class Arvados::V1::CollectionsControllerTest < ActionController::TestCase }, } assert_response :success - assert_signed_manifest json_response['manifest_text'], 'updated', token: token + assert_unsigned_manifest json_response['manifest_text'], 'updated' end end - test "index with manifest_text selected returns signed locators" do + test "index with manifest_text selected returns unsigned locators" do columns = %w(uuid owner_uuid manifest_text) authorize_with :active get :index, params: {select: columns} @@ -112,7 +103,7 @@ class Arvados::V1::CollectionsControllerTest < ActionController::TestCase json_response["items"].each do |coll| assert_equal(coll.keys - ['kind'], columns, "Collections index did not respect selected columns") - assert_signed_manifest coll['manifest_text'], coll['uuid'] + assert_unsigned_manifest coll['manifest_text'], coll['uuid'] end end @@ -125,7 +116,8 @@ class Arvados::V1::CollectionsControllerTest < ActionController::TestCase json_response["items"].each do |coll| assert_equal(coll.keys - ['kind'], ['unsigned_manifest_text'], "Collections index did not respect selected columns") - locs += assert_unsigned_manifest coll, coll['uuid'] + assert_nil coll['manifest_text'] + locs += assert_unsigned_manifest coll['unsigned_manifest_text'], coll['uuid'] end assert_operator locs, :>, 0, "no locators found in any manifests" end @@ -338,7 +330,7 @@ EOS assert_not_nil assigns(:object) resp = assigns(:object) assert_equal foo_collection[:portable_data_hash], resp[:portable_data_hash] - assert_signed_manifest resp[:manifest_text] + assert_unsigned_manifest resp[:manifest_text] # The manifest in the response will have had permission hints added. # Remove any permission hints in the response before comparing it to the source. @@ -382,13 +374,31 @@ EOS "Expected 'duplicate key' error in #{response_errors.first}") end + [false, true].each do |ensure_unique_name| + test "create failure with duplicate name, ensure_unique_name #{ensure_unique_name}" do + authorize_with :active + post :create, params: { + collection: { + owner_uuid: users(:active).uuid, + manifest_text: "", + name: "this...............................................................................................................................................................................................................................................................name is too long" + }, + ensure_unique_name: ensure_unique_name + } + assert_response 422 + # check the real error isn't masked by an + # ensure_unique_name-related error (#19698) + assert_match /value too long for type/, json_response['errors'][0] + end + end + [false, true].each do |unsigned| test "create with duplicate name, ensure_unique_name, unsigned=#{unsigned}" do permit_unsigned_manifests unsigned authorize_with :active manifest_text = ". acbd18db4cc2f85cedef654fccc4a4d8+3 0:0:foo.txt\n" if !unsigned - manifest_text = Collection.sign_manifest manifest_text, api_token(:active) + manifest_text = Collection.sign_manifest_only_for_tests manifest_text, api_token(:active) end post :create, params: { collection: { @@ -594,10 +604,10 @@ EOS assert_not_nil assigns(:object) resp = JSON.parse(@response.body) assert_equal manifest_uuid, resp['portable_data_hash'] - # All of the locators in the output must be signed. + # All of the signatures in the output must be valid. resp['manifest_text'].lines.each do |entry| m = /([[:xdigit:]]{32}\+\S+)/.match(entry) - if m + if m && m[0].index('+A') assert Blob.verify_signature m[0], signing_opts end end @@ -641,10 +651,10 @@ EOS assert_not_nil assigns(:object) resp = JSON.parse(@response.body) assert_equal manifest_uuid, resp['portable_data_hash'] - # All of the locators in the output must be signed. + # All of the signatures in the output must be valid. resp['manifest_text'].lines.each do |entry| m = /([[:xdigit:]]{32}\+\S+)/.match(entry) - if m + if m && m[0].index('+A') assert Blob.verify_signature m[0], signing_opts end end @@ -746,50 +756,6 @@ EOS assert_equal manifest_text, stripped_manifest end - test "multiple signed locators per line" do - permit_unsigned_manifests - authorize_with :active - locators = %w( - d41d8cd98f00b204e9800998ecf8427e+0 - acbd18db4cc2f85cedef654fccc4a4d8+3 - ea10d51bcf88862dbcc36eb292017dfd+45) - - signing_opts = { - key: Rails.configuration.Collections.BlobSigningKey, - api_token: api_token(:active), - } - - unsigned_manifest = [".", *locators, "0:0:foo.txt\n"].join(" ") - manifest_uuid = Digest::MD5.hexdigest(unsigned_manifest) + - '+' + - unsigned_manifest.length.to_s - - signed_locators = locators.map { |loc| Blob.sign_locator loc, signing_opts } - signed_manifest = [".", *signed_locators, "0:0:foo.txt\n"].join(" ") - - post :create, params: { - collection: { - manifest_text: signed_manifest, - portable_data_hash: manifest_uuid, - } - } - assert_response :success - assert_not_nil assigns(:object) - resp = JSON.parse(@response.body) - assert_equal manifest_uuid, resp['portable_data_hash'] - # All of the locators in the output must be signed. - # Each line is of the form "path locator locator ... 0:0:file.txt" - # entry.split[1..-2] will yield just the tokens in the middle of the line - returned_locator_count = 0 - resp['manifest_text'].lines.each do |entry| - entry.split[1..-2].each do |tok| - returned_locator_count += 1 - assert Blob.verify_signature tok, signing_opts - end - end - assert_equal locators.count, returned_locator_count - end - test 'Reject manifest with unsigned blob' do permit_unsigned_manifests false authorize_with :active @@ -1128,18 +1094,24 @@ EOS end end - test 'get trashed collection with include_trash' do - uuid = 'zzzzz-4zz18-mto52zx1s7sn3ih' # expired_collection - authorize_with :active - get :show, params: { - id: uuid, - include_trash: true, - } - assert_response 200 + [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 + test "get trashed collection via filters and #{user} user without including its past versions" do uuid = 'zzzzz-4zz18-mto52zx1s7sn3ih' # expired_collection authorize_with user get :index, params: { @@ -1382,6 +1354,16 @@ EOS json_response['name'] end + test 'can get old version collection by PDH' do + authorize_with :active + get :show, params: { + id: collections(:collection_owned_by_active_past_version_1).portable_data_hash, + } + assert_response :success + assert_equal collections(:collection_owned_by_active_past_version_1).portable_data_hash, + json_response['portable_data_hash'] + end + test 'version and current_version_uuid are ignored at creation time' do permit_unsigned_manifests authorize_with :active @@ -1439,4 +1421,114 @@ EOS assert_response :success assert_equal col.version, json_response['version'], 'Trashing a collection should not create a new version' end + + [['<', :<], + ['<=', :<=], + ['>', :>], + ['>=', :>=], + ['=', :==]].each do |op, rubyop| + test "filter collections by replication_desired #{op} replication_confirmed" do + authorize_with(:active) + get :index, params: { + filters: [["(replication_desired #{op} replication_confirmed)", "=", true]], + } + assert_response :success + json_response["items"].each do |c| + assert_operator(c["replication_desired"], rubyop, c["replication_confirmed"]) + end + end + end + + ["(replication_desired < bogus)", + "replication_desired < replication_confirmed", + "(replication_desired < replication_confirmed", + "(replication_desired ! replication_confirmed)", + "(replication_desired <)", + "(replication_desired < manifest_text)", + "(manifest_text < manifest_text)", # currently only numeric attrs are supported + "(replication_desired < 2)", # currently only attrs are supported, not literals + "(1 < 2)", + ].each do |expr| + test "invalid filter expression #{expr}" do + authorize_with(:active) + get :index, params: { + filters: [[expr, "=", true]], + } + assert_response 422 + end + end + + test "invalid op/arg with filter expression" do + authorize_with(:active) + get :index, params: { + filters: [["replication_desired < replication_confirmed", "!=", false]], + } + assert_response 422 + end + + ["storage_classes_desired", "storage_classes_confirmed"].each do |attr| + test "filter collections by #{attr}" do + authorize_with(:active) + get :index, params: { + filters: [[attr, "=", '["default"]']] + } + assert_response :success + assert_not_equal 0, json_response["items"].length + json_response["items"].each do |c| + assert_equal ["default"], c[attr] + end + end + end + + test "select param is respected in 'show' response" do + authorize_with :active + get :show, params: { + id: collections(:collection_owned_by_active).uuid, + select: ["name"], + } + assert_response :success + assert_raises ActiveModel::MissingAttributeError do + assigns(:object).manifest_text + end + assert_nil json_response["manifest_text"] + assert_nil json_response["properties"] + assert_equal collections(:collection_owned_by_active).name, json_response["name"] + end + + test "select param is respected in 'update' response" do + authorize_with :active + post :update, params: { + id: collections(:collection_owned_by_active).uuid, + collection: { + manifest_text: ". d41d8cd98f00b204e9800998ecf8427e+0 0:0:foobar.txt\n", + }, + select: ["name"], + } + assert_response :success + assert_nil json_response["manifest_text"] + assert_nil json_response["properties"] + assert_equal collections(:collection_owned_by_active).name, json_response["name"] + end + + [nil, + [], + ["is_trashed", "trash_at"], + ["is_trashed", "trash_at", "portable_data_hash"], + ["portable_data_hash"], + ["portable_data_hash", "manifest_text"], + ].each do |select| + test "select=#{select.inspect} param is respected in 'get by pdh' response" do + authorize_with :active + get :show, params: { + id: collections(:collection_owned_by_active).portable_data_hash, + select: select, + } + assert_response :success + if !select || select.index("manifest_text") + assert_not_nil json_response["manifest_text"] + else + assert_nil json_response["manifest_text"] + end + end + end end