aboutsummaryrefslogtreecommitdiffstats
path: root/activestorage/test/service
diff options
context:
space:
mode:
Diffstat (limited to 'activestorage/test/service')
-rw-r--r--activestorage/test/service/azure_storage_service_test.rb22
-rw-r--r--activestorage/test/service/configurations.example.yml30
-rw-r--r--activestorage/test/service/configurations.yml.encbin0 -> 2864 bytes
-rw-r--r--activestorage/test/service/configurator_test.rb16
-rw-r--r--activestorage/test/service/disk_service_test.rb14
-rw-r--r--activestorage/test/service/gcs_service_test.rb55
-rw-r--r--activestorage/test/service/mirror_service_test.rb66
-rw-r--r--activestorage/test/service/s3_service_test.rb59
-rw-r--r--activestorage/test/service/shared_service_tests.rb96
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
new file mode 100644
index 0000000000..df11aac161
--- /dev/null
+++ b/activestorage/test/service/configurations.yml.enc
Binary files differ
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