提交 c2a61cc9 编写于 作者: D David Heinemeier Hansson

Merge branch 'master' into variants

engines:
rubocop:
enabled: true
ratings:
paths:
- "**.rb"
AllCops:
TargetRubyVersion: 2.3
# RuboCop has a bunch of cops enabled by default. This setting tells RuboCop
# to ignore them, so only the ones explicitly set in this file are enabled.
DisabledByDefault: true
Exclude:
- '**/templates/**/*'
- '**/vendor/**/*'
- 'actionpack/lib/action_dispatch/journey/parser.rb'
# Prefer &&/|| over and/or.
Style/AndOr:
Enabled: true
# Do not use braces for hash literals when they are the last argument of a
# method call.
Style/BracesAroundHashParameters:
Enabled: true
EnforcedStyle: context_dependent
# Align `when` with `case`.
Style/CaseIndentation:
Enabled: true
# Align comments with method definitions.
Style/CommentIndentation:
Enabled: true
# No extra empty lines.
Style/EmptyLines:
Enabled: false
# In a regular class definition, no empty lines around the body.
Style/EmptyLinesAroundClassBody:
Enabled: true
# In a regular method definition, no empty lines around the body.
Style/EmptyLinesAroundMethodBody:
Enabled: true
# In a regular module definition, no empty lines around the body.
Style/EmptyLinesAroundModuleBody:
Enabled: true
# Use Ruby >= 1.9 syntax for hashes. Prefer { a: :b } over { :a => :b }.
Style/HashSyntax:
Enabled: true
# Method definitions after `private` or `protected` isolated calls need one
# extra level of indentation.
Style/IndentationConsistency:
Enabled: true
EnforcedStyle: rails
# Two spaces, no tabs (for indentation).
Style/IndentationWidth:
Enabled: true
Style/SpaceAfterColon:
Enabled: true
Style/SpaceAfterComma:
Enabled: true
Style/SpaceAroundEqualsInParameterDefault:
Enabled: true
Style/SpaceAroundKeyword:
Enabled: true
Style/SpaceAroundOperators:
Enabled: true
Style/SpaceBeforeFirstArg:
Enabled: true
# Defining a method with parameters needs parentheses.
Style/MethodDefParentheses:
Enabled: true
# Use `foo {}` not `foo{}`.
Style/SpaceBeforeBlockBraces:
Enabled: true
# Use `foo { bar }` not `foo {bar}`.
Style/SpaceInsideBlockBraces:
Enabled: true
# Use `{ a: 1 }` not `{a:1}`.
Style/SpaceInsideHashLiteralBraces:
Enabled: true
Style/SpaceInsideParens:
Enabled: true
# Check quotes usage according to lint rule below.
Style/StringLiterals:
Enabled: true
EnforcedStyle: double_quotes
# Detect hard tabs, no hard tabs.
Style/Tab:
Enabled: true
# Blank lines should not have any spaces.
Style/TrailingBlankLines:
Enabled: true
# No trailing whitespace.
Style/TrailingWhitespace:
Enabled: true
# Use quotes for string literals when they are enough.
Style/UnneededPercentQ:
Enabled: true
# Align `end` with the matching keyword or starting expression except for
# assignments, where it should be aligned with the LHS.
Lint/EndAlignment:
Enabled: true
EnforcedStyleAlignWith: variable
# Use my_method(my_arg) not my_method( my_arg ) or my_method my_arg.
Lint/RequireParentheses:
Enabled: true
source 'https://rubygems.org'
source "https://rubygems.org"
git_source(:github) { |repo_path| "https://github.com/#{repo_path}.git" }
gemspec
gem 'rake'
gem 'byebug'
gem "activesupport", github: "rails/rails"
gem "activerecord", github: "rails/rails"
gem "actionpack", github: "rails/rails"
gem "activejob", github: "rails/rails"
gem "rake"
gem "byebug"
gem 'sqlite3'
gem 'httparty'
gem "sqlite3"
gem "httparty"
gem "aws-sdk", "~> 2", require: false
gem "google-cloud-storage", "~> 1.3", require: false
gem 'aws-sdk', '~> 2', require: false
gem 'google-cloud-storage', require: false
gem 'mini_magick'
gem "rubocop", require: false
PATH
remote: .
specs:
activestorage (0.1)
actionpack (>= 5.1)
activejob (>= 5.1)
activerecord (>= 5.1)
activesupport (>= 5.1)
GEM
remote: https://rubygems.org/
GIT
remote: https://github.com/rails/rails.git
revision: 5c16dd35a23f75038baf1527143ee44accf081ff
specs:
actionpack (5.1.1)
actionview (= 5.1.1)
activesupport (= 5.1.1)
actionpack (5.2.0.alpha)
actionview (= 5.2.0.alpha)
activesupport (= 5.2.0.alpha)
rack (~> 2.0)
rack-test (~> 0.6.3)
rails-dom-testing (~> 2.0)
rails-html-sanitizer (~> 1.0, >= 1.0.2)
actionview (5.1.1)
activesupport (= 5.1.1)
actionview (5.2.0.alpha)
activesupport (= 5.2.0.alpha)
builder (~> 3.1)
erubi (~> 1.4)
rails-dom-testing (~> 2.0)
rails-html-sanitizer (~> 1.0, >= 1.0.3)
activejob (5.1.1)
activesupport (= 5.1.1)
activejob (5.2.0.alpha)
activesupport (= 5.2.0.alpha)
globalid (>= 0.3.6)
activemodel (5.1.1)
activesupport (= 5.1.1)
activerecord (5.1.1)
activemodel (= 5.1.1)
activesupport (= 5.1.1)
activemodel (5.2.0.alpha)
activesupport (= 5.2.0.alpha)
activerecord (5.2.0.alpha)
activemodel (= 5.2.0.alpha)
activesupport (= 5.2.0.alpha)
arel (~> 8.0)
activesupport (5.1.1)
activesupport (5.2.0.alpha)
concurrent-ruby (~> 1.0, >= 1.0.2)
i18n (~> 0.7)
minitest (~> 5.1)
tzinfo (~> 1.1)
PATH
remote: .
specs:
activestorage (0.1)
actionpack (>= 5.2.0.alpha)
activejob (>= 5.2.0.alpha)
activerecord (>= 5.2.0.alpha)
activesupport (>= 5.2.0.alpha)
GEM
remote: https://rubygems.org/
specs:
addressable (2.5.1)
public_suffix (~> 2.0, >= 2.0.2)
arel (8.0.0)
ast (2.3.0)
aws-sdk (2.10.7)
aws-sdk-resources (= 2.10.7)
aws-sdk-core (2.10.7)
......@@ -54,7 +60,7 @@ GEM
declarative (0.0.9)
declarative-option (0.1.0)
digest-crc (0.4.1)
erubi (1.6.0)
erubi (1.6.1)
faraday (0.12.1)
multipart-post (>= 1.2, < 3)
globalid (0.4.0)
......@@ -69,9 +75,9 @@ GEM
google-cloud-core (1.0.0)
google-cloud-env (~> 1.0)
googleauth (~> 0.5.1)
google-cloud-env (1.0.0)
google-cloud-env (1.0.1)
faraday (~> 0.11)
google-cloud-storage (1.2.0)
google-cloud-storage (1.3.0)
digest-crc (~> 0.4)
google-api-client (~> 0.13.0)
google-cloud-core (~> 1.0)
......@@ -86,7 +92,7 @@ GEM
httparty (0.15.5)
multi_xml (>= 0.5.2)
httpclient (2.8.3)
i18n (0.8.4)
i18n (0.8.6)
jmespath (1.3.1)
jwt (1.5.6)
little-plugger (1.1.4)
......@@ -100,14 +106,18 @@ GEM
mime-types-data (~> 3.2015)
mime-types-data (3.2016.0521)
mini_magick (4.8.0)
mini_portile2 (2.1.0)
mini_portile2 (2.2.0)
minitest (5.10.2)
multi_json (1.12.1)
multi_xml (0.6.0)
multipart-post (2.0.0)
nokogiri (1.7.2)
mini_portile2 (~> 2.1.0)
nokogiri (1.8.0)
mini_portile2 (~> 2.2.0)
os (0.9.6)
parallel (1.11.2)
parser (2.4.0.0)
ast (~> 2.2)
powerpack (0.1.1)
public_suffix (2.0.5)
rack (2.0.3)
rack-test (0.6.3)
......@@ -117,12 +127,22 @@ GEM
nokogiri (>= 1.6)
rails-html-sanitizer (1.0.3)
loofah (~> 2.0)
rainbow (2.2.2)
rake
rake (12.0.0)
representable (3.0.4)
declarative (< 0.1.0)
declarative-option (< 0.2.0)
uber (< 0.2.0)
retriable (3.0.2)
rubocop (0.49.1)
parallel (~> 1.10)
parser (>= 2.3.3.1, < 3.0)
powerpack (~> 0.1)
rainbow (>= 1.99.1, < 3.0)
ruby-progressbar (~> 1.7)
unicode-display_width (~> 1.0, >= 1.0.1)
ruby-progressbar (1.8.1)
signet (0.7.3)
addressable (~> 2.3)
faraday (~> 0.9)
......@@ -133,19 +153,25 @@ GEM
tzinfo (1.2.3)
thread_safe (~> 0.1)
uber (0.1.0)
unicode-display_width (1.3.0)
PLATFORMS
ruby
DEPENDENCIES
actionpack!
activejob!
activerecord!
activestorage!
activesupport!
aws-sdk (~> 2)
bundler (~> 1.15)
byebug
google-cloud-storage
google-cloud-storage (~> 1.3)
httparty
mini_magick
rake
rubocop
sqlite3
BUNDLED WITH
......
......@@ -9,13 +9,13 @@
s.required_ruby_version = ">= 2.3.0"
s.add_dependency "activesupport", ">= 5.1"
s.add_dependency "activerecord", ">= 5.1"
s.add_dependency "actionpack", ">= 5.1"
s.add_dependency "activejob", ">= 5.1"
s.add_dependency "activesupport", ">= 5.2.0.alpha"
s.add_dependency "activerecord", ">= 5.2.0.alpha"
s.add_dependency "actionpack", ">= 5.2.0.alpha"
s.add_dependency "activejob", ">= 5.2.0.alpha"
s.add_development_dependency "bundler", "~> 1.15"
s.files = `git ls-files`.split("\n")
s.test_files = `git ls-files -- test/*`.split("\n")
s.files = `git ls-files`.split("\n")
s.test_files = `git ls-files -- test/*`.split("\n")
end
......@@ -56,8 +56,8 @@ def upload(io)
service.upload(key, io, checksum: checksum)
end
def download
service.download key
def download(&block)
service.download key, &block
end
......
......@@ -33,6 +33,6 @@ def decode_verified_key
end
def disposition_param
params[:disposition].presence_in(%w( inline attachment )) || 'inline'
params[:disposition].presence_in(%w( inline attachment )) || "inline"
end
end
......@@ -14,7 +14,7 @@ class ActiveStorage::Download
application/xhtml+xml
)
BINARY_CONTENT_TYPE = 'application/octet-stream'
BINARY_CONTENT_TYPE = "application/octet-stream"
def initialize(stored_file)
@stored_file = stored_file
......@@ -22,11 +22,11 @@ def initialize(stored_file)
def headers(force_attachment: false)
{
x_accel_redirect: '/reproxy',
x_accel_redirect: "/reproxy",
x_reproxy_url: reproxy_url,
content_type: content_type,
content_disposition: content_disposition(force_attachment),
x_frame_options: 'SAMEORIGIN'
x_frame_options: "SAMEORIGIN"
}
end
......
......@@ -2,9 +2,9 @@
class ActiveStorage::LogSubscriber < ActiveSupport::LogSubscriber
def service_upload(event)
message = color("Uploaded file to key: #{key_in(event)}", GREEN)
message << color(" (checksum: #{event.payload[:checksum]})", GREEN) if event.payload[:checksum]
info event, message
message = "Uploaded file to key: #{key_in(event)}"
message << " (checksum: #{event.payload[:checksum]})" if event.payload[:checksum]
info event, color(message, GREEN)
end
def service_download(event)
......
......@@ -85,7 +85,7 @@ def url_for_direct_upload(key, expires_in:, content_type:, content_length:)
private
def instrument(operation, key, payload = {}, &block)
ActiveSupport::Notifications.instrument(
"service_#{operation}.active_storage",
"service_#{operation}.active_storage",
payload.merge(key: key, service: service_name), &block)
end
......
......@@ -20,8 +20,8 @@ def upload(key, io, checksum: nil)
def download(key)
if block_given?
instrument :streaming_download, key do
File.open(path_for(key)) do |file|
while data = file.binread(64.kilobytes)
File.open(path_for(key), "rb") do |file|
while data = file.read(64.kilobytes)
yield data
end
end
......@@ -55,7 +55,7 @@ def url(key, expires_in:, disposition:, filename:)
instrument :url, key do |payload|
verified_key_with_expiration = ActiveStorage::VerifiedKeyWithExpiration.encode(key, expires_in: expires_in)
generated_url =
generated_url =
if defined?(Rails) && defined?(Rails.application)
Rails.application.routes.url_helpers.rails_disk_blob_path(verified_key_with_expiration, disposition: disposition, filename: filename)
else
......@@ -63,7 +63,7 @@ def url(key, expires_in:, disposition:, filename:)
end
payload[:url] = generated_url
generated_url
end
end
......
......@@ -44,11 +44,22 @@ def exist?(key)
def url(key, expires_in:, disposition:, filename:)
instrument :url, key do |payload|
generated_url = file_for(key).signed_url(expires: expires_in) + "&" +
{ "response-content-disposition" => "#{disposition}; filename=\"#{filename}\"" }.to_query
query = { "response-content-disposition" => "#{disposition}; filename=\"#{filename}\"" }
generated_url = file_for(key).signed_url(expires: expires_in, query: query)
payload[:url] = generated_url
generated_url
end
end
def url_for_direct_upload(key, expires_in:, content_type:, content_length:)
instrument :url, key do |payload|
generated_url = bucket.signed_url key, method: "PUT", expires: expires_in,
content_type: content_type
payload[:url] = generated_url
generated_url
end
end
......
......@@ -2,17 +2,19 @@
require "active_support/core_ext/numeric/bytes"
class ActiveStorage::Service::S3Service < ActiveStorage::Service
attr_reader :client, :bucket
attr_reader :client, :bucket, :upload_options
def initialize(access_key_id:, secret_access_key:, region:, bucket:)
@client = Aws::S3::Resource.new(access_key_id: access_key_id, secret_access_key: secret_access_key, region: region)
def initialize(access_key_id:, secret_access_key:, region:, bucket:, upload: {}, **options)
@client = Aws::S3::Resource.new(access_key_id: access_key_id, secret_access_key: secret_access_key, region: region, **options)
@bucket = @client.bucket(bucket)
@upload_options = upload
end
def upload(key, io, checksum: nil)
instrument :upload, key, checksum: checksum do
begin
object_for(key).put(body: io, content_md5: checksum)
object_for(key).put(upload_options.merge(body: io, content_md5: checksum))
rescue Aws::S3::Errors::BadDigest
raise ActiveStorage::IntegrityError
end
......@@ -49,9 +51,9 @@ def url(key, expires_in:, disposition:, filename:)
instrument :url, key do |payload|
generated_url = object_for(key).presigned_url :get, expires_in: expires_in,
response_content_disposition: "#{disposition}; filename=\"#{filename}\""
payload[:url] = generated_url
generated_url
end
end
......@@ -60,9 +62,9 @@ def url_for_direct_upload(key, expires_in:, content_type:, content_length:)
instrument :url, key do |payload|
generated_url = object_for(key).presigned_url :put, expires_in: expires_in,
content_type: content_type, content_length: content_length
payload[:url] = generated_url
generated_url
end
end
......
......@@ -9,8 +9,8 @@ local:
# Use rails secrets:edit to set the AWS secrets (as shared:aws:access_key_id|secret_access_key)
amazon:
service: S3
access_key_id: <%= Rails.application.secrets.aws[:access_key_id] %>
secret_access_key: <%= Rails.application.secrets.aws[:secret_access_key] %>
access_key_id: <%= Rails.application.secrets.dig(:aws, :access_key_id) %>
secret_access_key: <%= Rails.application.secrets.dig(:aws, :secret_access_key) %>
region: us-east-1
bucket: your_own_bucket
......
......@@ -7,7 +7,7 @@ namespace :activestorage do
FileUtils.mkdir_p Rails.root.join("tmp/storage")
puts "Made storage and tmp/storage directories for development and testing"
FileUtils.cp File.expand_path("../../active_storage/storage_services.yml", __FILE__), Rails.root.join("config")
FileUtils.cp File.expand_path("../../active_storage/storage_services.yml", __FILE__), Rails.root.join("config")
puts "Copied default configuration to config/storage_services.yml"
migration_file_path = "db/migrate/#{Time.now.utc.strftime("%Y%m%d%H%M%S")}_active_storage_create_tables.rb"
......
......@@ -66,7 +66,7 @@ class ActiveStorage::AttachmentsTest < ActiveSupport::TestCase
test "attach new blobs" do
@user.highlights.attach(
{ io: StringIO.new("STUFF"), filename: "town.jpg", content_type: "image/jpg" },
{ io: StringIO.new("STUFF"), filename: "town.jpg", content_type: "image/jpg" },
{ io: StringIO.new("IT"), filename: "country.jpg", content_type: "image/jpg" })
assert_equal "town.jpg", @user.highlights.first.filename.to_s
......@@ -76,7 +76,7 @@ class ActiveStorage::AttachmentsTest < ActiveSupport::TestCase
test "purge attached blobs" do
@user.highlights.attach create_blob(filename: "funky.jpg"), create_blob(filename: "wonky.jpg")
highlight_keys = @user.highlights.collect(&:key)
@user.highlights.purge
assert_not @user.highlights.attached?
assert_not ActiveStorage::Blob.service.exist?(highlight_keys.first)
......
......@@ -12,10 +12,23 @@ class ActiveStorage::BlobTest < ActiveSupport::TestCase
assert_equal Digest::MD5.base64digest(data), blob.checksum
end
test "download yields chunks" do
blob = create_blob data: "a" * 75.kilobytes
chunks = []
blob.download do |chunk|
chunks << chunk
end
assert_equal 2, chunks.size
assert_equal "a" * 64.kilobytes, chunks.first
assert_equal "a" * 11.kilobytes, chunks.second
end
test "urls expiring in 5 minutes" do
blob = create_blob
travel_to Time.now do
freeze_time do
assert_equal expected_url_for(blob), blob.url
assert_equal expected_url_for(blob, disposition: :attachment), blob.url(disposition: :attachment)
end
......
require "active_storage/migration"
require_relative "create_users_migration"
ActiveRecord::Base.establish_connection(adapter: 'sqlite3', database: ':memory:')
ActiveRecord::Base.establish_connection(adapter: "sqlite3", database: ":memory:")
ActiveStorageCreateTables.migrate(:up)
ActiveStorageCreateUsers.migrate(:up)
......@@ -7,7 +7,7 @@
require "active_storage/direct_uploads_controller"
if SERVICE_CONFIGURATIONS[:s3]
class ActiveStorage::DirectUploadsControllerTest < ActionController::TestCase
class ActiveStorage::S3DirectUploadsControllerTest < ActionController::TestCase
setup do
@blob = create_blob
@routes = Routes
......@@ -27,10 +27,40 @@ class ActiveStorage::DirectUploadsControllerTest < ActionController::TestCase
details = JSON.parse(@response.body)
assert_match /rails-activestorage\.s3.amazonaws\.com/, details["url"]
assert_match /#{SERVICE_CONFIGURATIONS[:s3][:bucket]}\.s3.(\S+)?amazonaws\.com/, details["url"]
assert_equal "hello.txt", GlobalID::Locator.locate_signed(details["sgid"]).filename.to_s
end
end
else
puts "Skipping Direct Upload tests because no S3 configuration was supplied"
puts "Skipping S3 Direct Upload tests because no S3 configuration was supplied"
end
if SERVICE_CONFIGURATIONS[:gcs]
class ActiveStorage::GCSDirectUploadsControllerTest < ActionController::TestCase
setup do
@blob = create_blob
@routes = Routes
@controller = ActiveStorage::DirectUploadsController.new
@config = SERVICE_CONFIGURATIONS[:gcs]
@old_service = ActiveStorage::Blob.service
ActiveStorage::Blob.service = ActiveStorage::Service.configure(:gcs, SERVICE_CONFIGURATIONS)
end
teardown do
ActiveStorage::Blob.service = @old_service
end
test "creating new direct upload" do
post :create, params: { blob: {
filename: "hello.txt", byte_size: 6, checksum: Digest::MD5.base64digest("Hello"), content_type: "text/plain" } }
details = JSON.parse(@response.body)
assert_match %r{storage\.googleapis\.com/#{@config[:bucket]}}, details["url"]
assert_equal "hello.txt", GlobalID::Locator.locate_signed(details["sgid"]).filename.to_s
end
end
else
puts "Skipping GCS Direct Upload tests because no GCS configuration was supplied"
end
......@@ -4,8 +4,8 @@ class ActiveStorage::FilenameTest < ActiveSupport::TestCase
test "sanitize" do
"%$|:;/\t\r\n\\".each_char do |character|
filename = ActiveStorage::Filename.new("foo#{character}bar.pdf")
assert_equal 'foo-bar.pdf', filename.sanitized
assert_equal 'foo-bar.pdf', filename.to_s
assert_equal "foo-bar.pdf", filename.sanitized
assert_equal "foo-bar.pdf", filename.to_s
end
end
......@@ -23,14 +23,14 @@ class ActiveStorage::FilenameTest < ActiveSupport::TestCase
test "strips RTL override chars used to spoof unsafe executables as docs" do
# Would be displayed in Windows as "evilexe.pdf" due to the right-to-left
# (RTL) override char!
assert_equal 'evil-fdp.exe', ActiveStorage::Filename.new("evil\u{202E}fdp.exe").sanitized
assert_equal "evil-fdp.exe", ActiveStorage::Filename.new("evil\u{202E}fdp.exe").sanitized
end
test "compare case-insensitively" do
assert_operator ActiveStorage::Filename.new('foobar.pdf'), :==, ActiveStorage::Filename.new('FooBar.PDF')
assert_operator ActiveStorage::Filename.new("foobar.pdf"), :==, ActiveStorage::Filename.new("FooBar.PDF")
end
test "compare sanitized" do
assert_operator ActiveStorage::Filename.new('foo-bar.pdf'), :==, ActiveStorage::Filename.new("foo\tbar.pdf")
assert_operator ActiveStorage::Filename.new("foo-bar.pdf"), :==, ActiveStorage::Filename.new("foo\tbar.pdf")
end
end
......@@ -12,4 +12,3 @@ class ActiveStorage::Service::ConfiguratorTest < ActiveSupport::TestCase
end
end
end
......@@ -7,6 +7,6 @@ class ActiveStorage::Service::DiskServiceTest < ActiveSupport::TestCase
test "url generation" do
assert_match /rails\/active_storage\/disk\/.*\/avatar\.png\?disposition=inline/,
@service.url(FIXTURE_KEY, expires_in: 5.minutes, disposition: :inline, filename: "avatar.png")
@service.url(FIXTURE_KEY, expires_in: 5.minutes, disposition: :inline, filename: "avatar.png")
end
end
require "service/shared_service_tests"
require "httparty"
if SERVICE_CONFIGURATIONS[:gcs]
class ActiveStorage::Service::GCSServiceTest < ActiveSupport::TestCase
......@@ -6,8 +7,27 @@ class ActiveStorage::Service::GCSServiceTest < ActiveSupport::TestCase
include ActiveStorage::Service::SharedServiceTests
test "direct upload" do
begin
key = SecureRandom.base58(24)
data = "Something else entirely!"
direct_upload_url = @service.url_for_direct_upload(key, expires_in: 5.minutes, content_type: "text/plain", content_length: data.size)
HTTParty.put(
direct_upload_url,
body: data,
headers: { "Content-Type" => "text/plain" },
debug_output: STDOUT
)
assert_equal data, @service.download(key)
ensure
@service.delete key
end
end
test "signed URL generation" do
travel_to Time.now do
freeze_time do
url = SERVICE.bucket.signed_url(FIXTURE_KEY, expires: 120) +
"&response-content-disposition=inline%3B+filename%3D%22test.txt%22"
......
......@@ -8,7 +8,7 @@ class ActiveStorage::Service::MirrorServiceTest < ActiveSupport::TestCase
end.to_h
config = mirror_config.merge \
mirror: { service: "Mirror", primary: 'primary', mirrors: mirror_config.keys },
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
......@@ -45,7 +45,7 @@ class ActiveStorage::Service::MirrorServiceTest < ActiveSupport::TestCase
end
test "URL generation in primary service" do
travel_to Time.now do
freeze_time do
assert_equal SERVICE.primary.url(FIXTURE_KEY, expires_in: 2.minutes, disposition: :inline, filename: "test.txt"),
@service.url(FIXTURE_KEY, expires_in: 2.minutes, disposition: :inline, filename: "test.txt")
end
......
require "service/shared_service_tests"
require "httparty"
require "uri"
if SERVICE_CONFIGURATIONS[:s3]
class ActiveStorage::Service::S3ServiceTest < ActiveSupport::TestCase
......@@ -9,37 +8,45 @@ class ActiveStorage::Service::S3ServiceTest < ActiveSupport::TestCase
include ActiveStorage::Service::SharedServiceTests
test "direct upload" do
# FIXME: This test is failing because of a mismatched request signature, but it works in the browser.
skip
begin
key = SecureRandom.base58(24)
data = "Something else entirely!"
direct_upload_url = @service.url_for_direct_upload(key, expires_in: 5.minutes, content_type: "text/plain", content_length: data.size)
url = URI.parse(direct_upload_url).to_s.split("?").first
query = CGI::parse(URI.parse(direct_upload_url).query).collect { |(k, v)| [ k, v.first ] }.to_h
url = @service.url_for_direct_upload(key, expires_in: 5.minutes, content_type: "text/plain", content_length: data.size)
HTTParty.post(
HTTParty.put(
url,
query: query,
body: data,
headers: {
"Content-Type": "text/plain",
"Origin": "http://localhost:3000"
},
headers: { "Content-Type" => "text/plain" },
debug_output: STDOUT
)
assert_equal data, @service.download(key)
ensure
@service.delete key
end
end
test "signed URL generation" do
assert_match /rails-activestorage\.s3\.amazonaws\.com.*response-content-disposition=inline.*avatar\.png/,
@service.url(FIXTURE_KEY, expires_in: 5.minutes, disposition: :inline, filename: "avatar.png")
assert_match /#{SERVICE_CONFIGURATIONS[:s3][:bucket]}\.s3.(\S+)?amazonaws.com.*response-content-disposition=inline.*avatar\.png/,
@service.url(FIXTURE_KEY, expires_in: 5.minutes, disposition: :inline, filename: "avatar.png")
end
test "uploading with server-side encryption" do
config = {}
config[:s3] = SERVICE_CONFIGURATIONS[:s3].merge \
upload: { server_side_encryption: "AES256" }
sse_service = ActiveStorage::Service.configure(:s3, config)
begin
key = SecureRandom.base58(24)
data = "Something else entirely!"
sse_service.upload(key, StringIO.new(data), checksum: Digest::MD5.base64digest(data))
assert_equal "AES256", sse_service.bucket.object(key).server_side_encryption
ensure
sse_service.delete key
end
end
end
else
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册