diff options
Diffstat (limited to 'activestorage/test/service')
-rw-r--r-- | activestorage/test/service/azure_storage_service_test.rb | 22 | ||||
-rw-r--r-- | activestorage/test/service/configurations.example.yml | 30 | ||||
-rw-r--r-- | activestorage/test/service/configurations.yml.enc | bin | 0 -> 2864 bytes | |||
-rw-r--r-- | activestorage/test/service/configurator_test.rb | 16 | ||||
-rw-r--r-- | activestorage/test/service/disk_service_test.rb | 14 | ||||
-rw-r--r-- | activestorage/test/service/gcs_service_test.rb | 55 | ||||
-rw-r--r-- | activestorage/test/service/mirror_service_test.rb | 66 | ||||
-rw-r--r-- | activestorage/test/service/s3_service_test.rb | 59 | ||||
-rw-r--r-- | activestorage/test/service/shared_service_tests.rb | 96 |
9 files changed, 358 insertions, 0 deletions
diff --git a/activestorage/test/service/azure_storage_service_test.rb b/activestorage/test/service/azure_storage_service_test.rb new file mode 100644 index 0000000000..be31bbe858 --- /dev/null +++ b/activestorage/test/service/azure_storage_service_test.rb @@ -0,0 +1,22 @@ +# frozen_string_literal: true + +require "service/shared_service_tests" +require "uri" + +if SERVICE_CONFIGURATIONS[:azure] + class ActiveStorage::Service::AzureStorageServiceTest < ActiveSupport::TestCase + SERVICE = ActiveStorage::Service.configure(:azure, SERVICE_CONFIGURATIONS) + + include ActiveStorage::Service::SharedServiceTests + + test "signed URL generation" do + url = @service.url(FIXTURE_KEY, expires_in: 5.minutes, + disposition: :inline, filename: ActiveStorage::Filename.new("avatar.png"), content_type: "image/png") + + assert_match(/(\S+)&rscd=inline%3B\+filename%3D%22avatar\.png%22%3B\+filename\*%3DUTF-8%27%27avatar\.png&rsct=image%2Fpng/, url) + assert_match SERVICE_CONFIGURATIONS[:azure][:container], url + end + end +else + puts "Skipping Azure Storage Service tests because no Azure configuration was supplied" +end diff --git a/activestorage/test/service/configurations.example.yml b/activestorage/test/service/configurations.example.yml new file mode 100644 index 0000000000..43cc013bc8 --- /dev/null +++ b/activestorage/test/service/configurations.example.yml @@ -0,0 +1,30 @@ +# s3: +# service: S3 +# access_key_id: "" +# secret_access_key: "" +# region: "" +# bucket: "" +# +# gcs: +# service: GCS +# credentials: { +# type: "service_account", +# project_id: "", +# private_key_id: "", +# private_key: "", +# client_email: "", +# client_id: "", +# auth_uri: "https://accounts.google.com/o/oauth2/auth", +# token_uri: "https://accounts.google.com/o/oauth2/token", +# auth_provider_x509_cert_url: "https://www.googleapis.com/oauth2/v1/certs", +# client_x509_cert_url: "" +# } +# project: +# bucket: +# +# azure: +# service: AzureStorage +# path: "" +# storage_account_name: "" +# storage_access_key: "" +# container: "" diff --git a/activestorage/test/service/configurations.yml.enc b/activestorage/test/service/configurations.yml.enc Binary files differnew file mode 100644 index 0000000000..df11aac161 --- /dev/null +++ b/activestorage/test/service/configurations.yml.enc diff --git a/activestorage/test/service/configurator_test.rb b/activestorage/test/service/configurator_test.rb new file mode 100644 index 0000000000..a2fd035e02 --- /dev/null +++ b/activestorage/test/service/configurator_test.rb @@ -0,0 +1,16 @@ +# frozen_string_literal: true + +require "service/shared_service_tests" + +class ActiveStorage::Service::ConfiguratorTest < ActiveSupport::TestCase + test "builds correct service instance based on service name" do + service = ActiveStorage::Service::Configurator.build(:foo, foo: { service: "Disk", root: "path" }) + assert_instance_of ActiveStorage::Service::DiskService, service + end + + test "raises error when passing non-existent service name" do + assert_raise RuntimeError do + ActiveStorage::Service::Configurator.build(:bigfoot, {}) + end + end +end diff --git a/activestorage/test/service/disk_service_test.rb b/activestorage/test/service/disk_service_test.rb new file mode 100644 index 0000000000..4a6361b920 --- /dev/null +++ b/activestorage/test/service/disk_service_test.rb @@ -0,0 +1,14 @@ +# frozen_string_literal: true + +require "service/shared_service_tests" + +class ActiveStorage::Service::DiskServiceTest < ActiveSupport::TestCase + SERVICE = ActiveStorage::Service::DiskService.new(root: File.join(Dir.tmpdir, "active_storage")) + + include ActiveStorage::Service::SharedServiceTests + + test "url generation" do + assert_match(/rails\/active_storage\/disk\/.*\/avatar\.png\?content_type=image%2Fpng&disposition=inline/, + @service.url(FIXTURE_KEY, expires_in: 5.minutes, disposition: :inline, filename: ActiveStorage::Filename.new("avatar.png"), content_type: "image/png")) + end +end diff --git a/activestorage/test/service/gcs_service_test.rb b/activestorage/test/service/gcs_service_test.rb new file mode 100644 index 0000000000..7efcd60fb7 --- /dev/null +++ b/activestorage/test/service/gcs_service_test.rb @@ -0,0 +1,55 @@ +# frozen_string_literal: true + +require "service/shared_service_tests" +require "net/http" + +if SERVICE_CONFIGURATIONS[:gcs] + class ActiveStorage::Service::GCSServiceTest < ActiveSupport::TestCase + SERVICE = ActiveStorage::Service.configure(:gcs, SERVICE_CONFIGURATIONS) + + include ActiveStorage::Service::SharedServiceTests + + test "direct upload" do + begin + key = SecureRandom.base58(24) + data = "Something else entirely!" + checksum = Digest::MD5.base64digest(data) + url = @service.url_for_direct_upload(key, expires_in: 5.minutes, content_type: "text/plain", content_length: data.size, checksum: checksum) + + uri = URI.parse url + request = Net::HTTP::Put.new uri.request_uri + request.body = data + request.add_field "Content-Type", "text/plain" + request.add_field "Content-MD5", checksum + Net::HTTP.start(uri.host, uri.port, use_ssl: true) do |http| + http.request request + end + + assert_equal data, @service.download(key) + ensure + @service.delete key + end + end + + test "signed URL generation" do + assert_match(/storage\.googleapis\.com\/.*response-content-disposition=inline.*test\.txt.*response-content-type=text%2Fplain/, + @service.url(FIXTURE_KEY, expires_in: 2.minutes, disposition: :inline, filename: ActiveStorage::Filename.new("test.txt"), content_type: "text/plain")) + end + + test "signed URL response headers" do + begin + key = SecureRandom.base58(24) + data = "Something else entirely!" + @service.upload(key, StringIO.new(data), checksum: Digest::MD5.base64digest(data)) + + url = @service.url(key, expires_in: 2.minutes, disposition: :inline, filename: ActiveStorage::Filename.new("test.txt"), content_type: "text/plain") + response = Net::HTTP.get_response(URI(url)) + assert_equal "text/plain", response.header["Content-Type"] + ensure + @service.delete key + end + end + end +else + puts "Skipping GCS Service tests because no GCS configuration was supplied" +end diff --git a/activestorage/test/service/mirror_service_test.rb b/activestorage/test/service/mirror_service_test.rb new file mode 100644 index 0000000000..92101b1282 --- /dev/null +++ b/activestorage/test/service/mirror_service_test.rb @@ -0,0 +1,66 @@ +# frozen_string_literal: true + +require "service/shared_service_tests" + +class ActiveStorage::Service::MirrorServiceTest < ActiveSupport::TestCase + mirror_config = (1..3).map do |i| + [ "mirror_#{i}", + service: "Disk", + root: Dir.mktmpdir("active_storage_tests_mirror_#{i}") ] + end.to_h + + config = mirror_config.merge \ + mirror: { service: "Mirror", primary: "primary", mirrors: mirror_config.keys }, + primary: { service: "Disk", root: Dir.mktmpdir("active_storage_tests_primary") } + + SERVICE = ActiveStorage::Service.configure :mirror, config + + include ActiveStorage::Service::SharedServiceTests + + test "uploading to all services" do + begin + data = "Something else entirely!" + key = upload(data, to: @service) + + assert_equal data, SERVICE.primary.download(key) + SERVICE.mirrors.each do |mirror| + assert_equal data, mirror.download(key) + end + ensure + @service.delete key + end + end + + test "downloading from primary service" do + data = "Something else entirely!" + key = upload(data, to: SERVICE.primary) + + assert_equal data, @service.download(key) + end + + test "deleting from all services" do + @service.delete FIXTURE_KEY + assert_not SERVICE.primary.exist?(FIXTURE_KEY) + SERVICE.mirrors.each do |mirror| + assert_not mirror.exist?(FIXTURE_KEY) + end + end + + test "URL generation in primary service" do + filename = ActiveStorage::Filename.new("test.txt") + + freeze_time do + assert_equal SERVICE.primary.url(FIXTURE_KEY, expires_in: 2.minutes, disposition: :inline, filename: filename, content_type: "text/plain"), + @service.url(FIXTURE_KEY, expires_in: 2.minutes, disposition: :inline, filename: filename, content_type: "text/plain") + end + end + + private + def upload(data, to:) + SecureRandom.base58(24).tap do |key| + io = StringIO.new(data).tap(&:read) + @service.upload key, io, checksum: Digest::MD5.base64digest(data) + assert io.eof? + end + end +end diff --git a/activestorage/test/service/s3_service_test.rb b/activestorage/test/service/s3_service_test.rb new file mode 100644 index 0000000000..c3818422aa --- /dev/null +++ b/activestorage/test/service/s3_service_test.rb @@ -0,0 +1,59 @@ +# frozen_string_literal: true + +require "service/shared_service_tests" +require "net/http" + +if SERVICE_CONFIGURATIONS[:s3] && SERVICE_CONFIGURATIONS[:s3][:access_key_id].present? + class ActiveStorage::Service::S3ServiceTest < ActiveSupport::TestCase + SERVICE = ActiveStorage::Service.configure(:s3, SERVICE_CONFIGURATIONS) + + include ActiveStorage::Service::SharedServiceTests + + test "direct upload" do + begin + key = SecureRandom.base58(24) + data = "Something else entirely!" + checksum = Digest::MD5.base64digest(data) + url = @service.url_for_direct_upload(key, expires_in: 5.minutes, content_type: "text/plain", content_length: data.size, checksum: checksum) + + uri = URI.parse url + request = Net::HTTP::Put.new uri.request_uri + request.body = data + request.add_field "Content-Type", "text/plain" + request.add_field "Content-MD5", checksum + Net::HTTP.start(uri.host, uri.port, use_ssl: true) do |http| + http.request request + end + + assert_equal data, @service.download(key) + ensure + @service.delete key + end + end + + test "signed URL generation" do + url = @service.url(FIXTURE_KEY, expires_in: 5.minutes, + disposition: :inline, filename: ActiveStorage::Filename.new("avatar.png"), content_type: "image/png") + + assert_match(/s3\.(\S+)?amazonaws.com.*response-content-disposition=inline.*avatar\.png.*response-content-type=image%2Fpng/, url) + assert_match SERVICE_CONFIGURATIONS[:s3][:bucket], url + end + + test "uploading with server-side encryption" do + config = SERVICE_CONFIGURATIONS.deep_merge(s3: { upload: { server_side_encryption: "AES256" } }) + service = ActiveStorage::Service.configure(:s3, config) + + begin + key = SecureRandom.base58(24) + data = "Something else entirely!" + service.upload key, StringIO.new(data), checksum: Digest::MD5.base64digest(data) + + assert_equal "AES256", service.bucket.object(key).server_side_encryption + ensure + service.delete key + end + end + end +else + puts "Skipping S3 Service tests because no S3 configuration was supplied" +end diff --git a/activestorage/test/service/shared_service_tests.rb b/activestorage/test/service/shared_service_tests.rb new file mode 100644 index 0000000000..ce28c4393a --- /dev/null +++ b/activestorage/test/service/shared_service_tests.rb @@ -0,0 +1,96 @@ +# frozen_string_literal: true + +require "test_helper" +require "active_support/core_ext/securerandom" + +module ActiveStorage::Service::SharedServiceTests + extend ActiveSupport::Concern + + FIXTURE_KEY = SecureRandom.base58(24) + FIXTURE_DATA = "\211PNG\r\n\032\n\000\000\000\rIHDR\000\000\000\020\000\000\000\020\001\003\000\000\000%=m\"\000\000\000\006PLTE\000\000\000\377\377\377\245\331\237\335\000\000\0003IDATx\234c\370\377\237\341\377_\206\377\237\031\016\2603\334?\314p\1772\303\315\315\f7\215\031\356\024\203\320\275\317\f\367\201R\314\f\017\300\350\377\177\000Q\206\027(\316]\233P\000\000\000\000IEND\256B`\202".dup.force_encoding(Encoding::BINARY) + + included do + setup do + @service = self.class.const_get(:SERVICE) + @service.upload FIXTURE_KEY, StringIO.new(FIXTURE_DATA) + end + + teardown do + @service.delete FIXTURE_KEY + end + + test "uploading with integrity" do + begin + key = SecureRandom.base58(24) + data = "Something else entirely!" + @service.upload(key, StringIO.new(data), checksum: Digest::MD5.base64digest(data)) + + assert_equal data, @service.download(key) + ensure + @service.delete key + end + end + + test "uploading without integrity" do + begin + key = SecureRandom.base58(24) + data = "Something else entirely!" + + assert_raises(ActiveStorage::IntegrityError) do + @service.upload(key, StringIO.new(data), checksum: Digest::MD5.base64digest("bad data")) + end + + assert_not @service.exist?(key) + ensure + @service.delete key + end + end + + test "downloading" do + assert_equal FIXTURE_DATA, @service.download(FIXTURE_KEY) + end + + test "downloading in chunks" do + chunks = [] + + @service.download(FIXTURE_KEY) do |chunk| + chunks << chunk + end + + assert_equal [ FIXTURE_DATA ], chunks + end + + test "existing" do + assert @service.exist?(FIXTURE_KEY) + assert_not @service.exist?(FIXTURE_KEY + "nonsense") + end + + test "deleting" do + @service.delete FIXTURE_KEY + assert_not @service.exist?(FIXTURE_KEY) + end + + test "deleting nonexistent key" do + assert_nothing_raised do + @service.delete SecureRandom.base58(24) + end + end + + test "deleting by prefix" do + begin + @service.upload("a/a/a", StringIO.new(FIXTURE_DATA)) + @service.upload("a/a/b", StringIO.new(FIXTURE_DATA)) + @service.upload("a/b/a", StringIO.new(FIXTURE_DATA)) + + @service.delete_prefixed("a/a/") + assert_not @service.exist?("a/a/a") + assert_not @service.exist?("a/a/b") + assert @service.exist?("a/b/a") + ensure + @service.delete("a/a/a") + @service.delete("a/a/b") + @service.delete("a/b/a") + end + end + end +end |