2019-04-29 20:27:42 -04:00
|
|
|
# frozen_string_literal: true
|
|
|
|
|
2017-08-02 22:56:55 -04:00
|
|
|
RSpec.describe FileStore::BaseStore do
|
2022-10-25 03:29:09 -04:00
|
|
|
fab!(:upload) do
|
|
|
|
Upload.delete(9999) # In case of any collisions
|
|
|
|
Fabricate(:upload, id: 9999, sha1: Digest::SHA1.hexdigest("9999"))
|
|
|
|
end
|
2017-08-02 22:56:55 -04:00
|
|
|
|
|
|
|
describe "#get_path_for_upload" do
|
2021-05-27 11:42:25 -04:00
|
|
|
def expect_correct_path(expected_path)
|
|
|
|
expect(described_class.new.get_path_for_upload(upload)).to eq(expected_path)
|
2017-08-02 22:56:55 -04:00
|
|
|
end
|
|
|
|
|
2022-07-27 12:14:14 -04:00
|
|
|
context "with empty URL" do
|
2021-05-27 11:42:25 -04:00
|
|
|
before { upload.update!(url: "") }
|
|
|
|
|
2017-08-02 22:56:55 -04:00
|
|
|
it "should return the right path" do
|
2021-05-27 11:42:25 -04:00
|
|
|
expect_correct_path("original/2X/4/4170ac2a2782a1516fe9e13d7322ae482c1bd594.png")
|
|
|
|
end
|
2017-08-02 22:56:55 -04:00
|
|
|
|
2021-05-27 11:42:25 -04:00
|
|
|
describe "when Upload#extension has not been set" do
|
|
|
|
it "should return the right path" do
|
|
|
|
upload.update!(extension: nil)
|
|
|
|
expect_correct_path("original/2X/4/4170ac2a2782a1516fe9e13d7322ae482c1bd594.png")
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
describe "when id is negative" do
|
|
|
|
it "should return the right depth" do
|
|
|
|
upload.update!(id: -999)
|
|
|
|
expect_correct_path("original/1X/4170ac2a2782a1516fe9e13d7322ae482c1bd594.png")
|
|
|
|
end
|
2017-08-02 22:56:55 -04:00
|
|
|
end
|
|
|
|
end
|
2019-01-02 02:29:17 -05:00
|
|
|
|
2022-07-27 12:14:14 -04:00
|
|
|
context "with existing URL" do
|
|
|
|
context "with regular site" do
|
2021-05-27 11:42:25 -04:00
|
|
|
it "returns the correct path for files stored on local storage" do
|
|
|
|
upload.update!(
|
|
|
|
url: "/uploads/default/original/1X/63b76551662ccea1a594e161c37dd35188d77657.jpeg",
|
|
|
|
)
|
|
|
|
expect_correct_path("original/1X/63b76551662ccea1a594e161c37dd35188d77657.jpeg")
|
|
|
|
|
|
|
|
upload.update!(
|
|
|
|
url: "/uploads/default/original/3X/63/63b76551662ccea1a594e161c37dd35188d77657.jpeg",
|
|
|
|
)
|
|
|
|
expect_correct_path("original/3X/63/63b76551662ccea1a594e161c37dd35188d77657.jpeg")
|
|
|
|
end
|
|
|
|
|
|
|
|
it "returns the correct path for files stored on S3" do
|
|
|
|
upload.update!(
|
|
|
|
url:
|
|
|
|
"//bucket-name.s3.dualstack.us-west-2.amazonaws.com/original/1X/63b76551662ccea1a594e161c37dd35188d77657.jpeg",
|
|
|
|
)
|
|
|
|
expect_correct_path("original/1X/63b76551662ccea1a594e161c37dd35188d77657.jpeg")
|
|
|
|
|
|
|
|
upload.update!(
|
|
|
|
url:
|
|
|
|
"//bucket-name.s3.dualstack.us-west-2.amazonaws.com/original/3X/63/63b76551662ccea1a594e161c37dd35188d77657.jpeg",
|
|
|
|
)
|
|
|
|
expect_correct_path("original/3X/63/63b76551662ccea1a594e161c37dd35188d77657.jpeg")
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2022-07-27 12:14:14 -04:00
|
|
|
context "with multisite" do
|
2021-05-27 11:42:25 -04:00
|
|
|
it "returns the correct path for files stored on local storage" do
|
|
|
|
upload.update!(
|
|
|
|
url: "/uploads/foo/original/1X/63b76551662ccea1a594e161c37dd35188d77657.jpeg",
|
|
|
|
)
|
|
|
|
expect_correct_path("original/1X/63b76551662ccea1a594e161c37dd35188d77657.jpeg")
|
|
|
|
|
|
|
|
upload.update!(
|
|
|
|
url: "/uploads/foo/original/3X/63/63b76551662ccea1a594e161c37dd35188d77657.jpeg",
|
|
|
|
)
|
|
|
|
expect_correct_path("original/3X/63/63b76551662ccea1a594e161c37dd35188d77657.jpeg")
|
|
|
|
end
|
|
|
|
|
|
|
|
it "returns the correct path for files stored on S3" do
|
|
|
|
upload.update!(
|
|
|
|
url:
|
|
|
|
"//bucket-name.s3.dualstack.us-west-2.amazonaws.com/uploads/foo/original/1X/63b76551662ccea1a594e161c37dd35188d77657.jpeg",
|
|
|
|
)
|
|
|
|
expect_correct_path("original/1X/63b76551662ccea1a594e161c37dd35188d77657.jpeg")
|
|
|
|
|
|
|
|
upload.update!(
|
|
|
|
url:
|
|
|
|
"//bucket-name.s3.dualstack.us-west-2.amazonaws.com/uploads/foo/original/3X/63/63b76551662ccea1a594e161c37dd35188d77657.jpeg",
|
|
|
|
)
|
|
|
|
expect_correct_path("original/3X/63/63b76551662ccea1a594e161c37dd35188d77657.jpeg")
|
|
|
|
end
|
|
|
|
|
|
|
|
it "returns the correct path when the site name is 'original'" do
|
|
|
|
upload.update!(
|
|
|
|
url: "/uploads/original/original/1X/63b76551662ccea1a594e161c37dd35188d77657.jpeg",
|
|
|
|
)
|
|
|
|
expect_correct_path("original/1X/63b76551662ccea1a594e161c37dd35188d77657.jpeg")
|
2019-01-02 02:29:17 -05:00
|
|
|
|
2021-05-27 11:42:25 -04:00
|
|
|
upload.update!(
|
|
|
|
url:
|
|
|
|
"//bucket-name.s3.dualstack.us-west-2.amazonaws.com/uploads/original/original/1X/63b76551662ccea1a594e161c37dd35188d77657.jpeg",
|
|
|
|
)
|
|
|
|
expect_correct_path("original/1X/63b76551662ccea1a594e161c37dd35188d77657.jpeg")
|
|
|
|
end
|
2019-01-02 02:29:17 -05:00
|
|
|
end
|
|
|
|
end
|
2017-08-02 22:56:55 -04:00
|
|
|
end
|
2019-01-11 08:05:38 -05:00
|
|
|
|
|
|
|
describe "#get_path_for_optimized_image" do
|
2021-05-27 11:42:25 -04:00
|
|
|
let!(:upload) { Fabricate.build(:upload, id: 100) }
|
|
|
|
let!(:optimized_path) { "optimized/1X/#{upload.sha1}_1_100x200.png" }
|
2019-01-11 08:05:38 -05:00
|
|
|
|
2022-07-27 12:14:14 -04:00
|
|
|
context "with empty URL" do
|
2021-05-27 11:42:25 -04:00
|
|
|
it "should return the right path" do
|
|
|
|
optimized = Fabricate.build(:optimized_image, upload: upload, version: 1)
|
|
|
|
expect(FileStore::BaseStore.new.get_path_for_optimized_image(optimized)).to eq(
|
|
|
|
optimized_path,
|
|
|
|
)
|
|
|
|
end
|
|
|
|
|
|
|
|
it "should return the right path for `nil` version" do
|
|
|
|
optimized = Fabricate.build(:optimized_image, upload: upload, version: nil)
|
|
|
|
expect(FileStore::BaseStore.new.get_path_for_optimized_image(optimized)).to eq(
|
|
|
|
optimized_path,
|
|
|
|
)
|
|
|
|
end
|
2019-01-11 08:05:38 -05:00
|
|
|
end
|
|
|
|
|
2022-07-27 12:14:14 -04:00
|
|
|
context "with existing URL" do
|
2021-05-27 11:42:25 -04:00
|
|
|
let!(:optimized) { Fabricate.build(:optimized_image, upload: upload, version: 1) }
|
|
|
|
let!(:optimized_path) { "optimized/1X/#{upload.sha1}_1_100x200.jpg" }
|
|
|
|
|
|
|
|
def expect_correct_optimized_path
|
|
|
|
expect(described_class.new.get_path_for_optimized_image(optimized)).to eq(optimized_path)
|
|
|
|
end
|
|
|
|
|
2022-07-27 12:14:14 -04:00
|
|
|
context "with regular site" do
|
2021-05-27 11:42:25 -04:00
|
|
|
it "returns the correct path for files stored on local storage" do
|
|
|
|
optimized.update!(url: "/uploads/default/optimized/1X/#{upload.sha1}_1_100x200.jpg")
|
|
|
|
expect_correct_optimized_path
|
|
|
|
end
|
|
|
|
|
|
|
|
it "returns the correct path for files stored on S3" do
|
|
|
|
optimized.update!(
|
|
|
|
url:
|
|
|
|
"//bucket-name.s3.dualstack.us-west-2.amazonaws.com/optimized/1X/#{upload.sha1}_1_100x200.jpg",
|
|
|
|
)
|
|
|
|
expect_correct_optimized_path
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2022-07-27 12:14:14 -04:00
|
|
|
context "with multisite" do
|
2021-05-27 11:42:25 -04:00
|
|
|
it "returns the correct path for files stored on local storage" do
|
|
|
|
optimized.update!(url: "/uploads/foo/optimized/1X/#{upload.sha1}_1_100x200.jpg")
|
|
|
|
expect_correct_optimized_path
|
|
|
|
end
|
|
|
|
|
|
|
|
it "returns the correct path for files stored on S3" do
|
|
|
|
optimized.update!(
|
|
|
|
url:
|
|
|
|
"//bucket-name.s3.dualstack.us-west-2.amazonaws.com/uploads/foo/optimized/1X/#{upload.sha1}_1_100x200.jpg",
|
|
|
|
)
|
|
|
|
expect_correct_optimized_path
|
|
|
|
end
|
|
|
|
|
|
|
|
it "returns the correct path when the site name is 'optimized'" do
|
|
|
|
optimized.update!(url: "/uploads/optimized/optimized/1X/#{upload.sha1}_1_100x200.jpg")
|
|
|
|
expect_correct_optimized_path
|
|
|
|
|
|
|
|
optimized.update!(
|
|
|
|
url:
|
|
|
|
"//bucket-name.s3.dualstack.us-west-2.amazonaws.com/uploads/optimized/optimized/1X/#{upload.sha1}_1_100x200.jpg",
|
|
|
|
)
|
|
|
|
expect_correct_optimized_path
|
|
|
|
end
|
|
|
|
end
|
2019-01-11 08:05:38 -05:00
|
|
|
end
|
|
|
|
end
|
2019-05-17 06:26:08 -04:00
|
|
|
|
|
|
|
describe "#download" do
|
|
|
|
before do
|
2020-09-14 07:32:25 -04:00
|
|
|
setup_s3
|
2019-05-17 06:26:08 -04:00
|
|
|
stub_request(:get, upload_s3.url).to_return(status: 200, body: "Hello world")
|
|
|
|
end
|
|
|
|
|
|
|
|
let(:upload_s3) { Fabricate(:upload_s3) }
|
2019-06-06 09:47:19 -04:00
|
|
|
let(:store) { FileStore::BaseStore.new }
|
2019-05-17 06:26:08 -04:00
|
|
|
|
|
|
|
it "should return consistent encodings for fresh and cached downloads" do
|
|
|
|
# Net::HTTP always returns binary ASCII-8BIT encoding. File.read auto-detects the encoding
|
|
|
|
# Make sure we File.read after downloading a file for consistency
|
|
|
|
|
2023-05-11 05:27:27 -04:00
|
|
|
first_encoding = store.download(upload_s3, print_deprecation: false).read.encoding
|
2019-05-17 06:26:08 -04:00
|
|
|
|
2023-05-11 05:27:27 -04:00
|
|
|
second_encoding = store.download(upload_s3, print_deprecation: false).read.encoding
|
2019-05-17 06:26:08 -04:00
|
|
|
|
|
|
|
expect(first_encoding).to eq(Encoding::UTF_8)
|
|
|
|
expect(second_encoding).to eq(Encoding::UTF_8)
|
|
|
|
end
|
2019-06-06 09:47:19 -04:00
|
|
|
|
|
|
|
it "should return the file" do
|
2023-05-11 05:27:27 -04:00
|
|
|
file = store.download(upload_s3, print_deprecation: false)
|
2019-06-06 09:47:19 -04:00
|
|
|
|
|
|
|
expect(file.class).to eq(File)
|
|
|
|
end
|
|
|
|
|
|
|
|
it "should return the file when s3 cdn enabled" do
|
2020-09-14 07:32:25 -04:00
|
|
|
SiteSetting.s3_cdn_url = "https://cdn.s3.#{SiteSetting.s3_region}.amazonaws.com"
|
2019-06-06 09:47:19 -04:00
|
|
|
stub_request(:get, Discourse.store.cdn_url(upload_s3.url)).to_return(
|
|
|
|
status: 200,
|
|
|
|
body: "Hello world",
|
|
|
|
)
|
|
|
|
|
2023-05-11 05:27:27 -04:00
|
|
|
file = store.download(upload_s3, print_deprecation: true)
|
2019-06-06 09:47:19 -04:00
|
|
|
|
|
|
|
expect(file.class).to eq(File)
|
|
|
|
end
|
2019-11-17 20:25:42 -05:00
|
|
|
|
2022-09-28 19:24:33 -04:00
|
|
|
it "should return the file when secure uploads are enabled" do
|
2019-11-17 20:25:42 -05:00
|
|
|
SiteSetting.login_required = true
|
2022-09-28 19:24:33 -04:00
|
|
|
SiteSetting.secure_uploads = true
|
2019-11-17 20:25:42 -05:00
|
|
|
|
2020-09-14 07:32:25 -04:00
|
|
|
stub_request(:head, "https://s3-upload-bucket.s3.#{SiteSetting.s3_region}.amazonaws.com/")
|
2019-11-17 20:25:42 -05:00
|
|
|
signed_url = Discourse.store.signed_url_for_path(upload_s3.url)
|
|
|
|
stub_request(:get, signed_url).to_return(status: 200, body: "Hello world")
|
|
|
|
|
2023-05-11 05:27:27 -04:00
|
|
|
file = store.download(upload_s3, print_deprecation: false)
|
2019-11-17 20:25:42 -05:00
|
|
|
|
|
|
|
expect(file.class).to eq(File)
|
|
|
|
end
|
2019-05-17 06:26:08 -04:00
|
|
|
end
|
2023-05-11 05:27:27 -04:00
|
|
|
|
|
|
|
describe "#download!" do
|
|
|
|
before do
|
|
|
|
setup_s3
|
|
|
|
stub_request(:get, upload_s3.url).to_return(status: 200, body: "Hello world")
|
|
|
|
end
|
|
|
|
|
|
|
|
let(:upload_s3) { Fabricate(:upload_s3) }
|
|
|
|
let(:store) { FileStore::BaseStore.new }
|
|
|
|
|
|
|
|
it "does not raise an error when download fails" do
|
|
|
|
FileHelper.stubs(:download).raises(OpenURI::HTTPError.new("400 error", anything))
|
|
|
|
|
|
|
|
expect { store.download!(upload_s3) }.to raise_error(FileStore::DownloadError)
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
describe "#download_safe" do
|
|
|
|
before do
|
|
|
|
setup_s3
|
|
|
|
stub_request(:get, upload_s3.url).to_return(status: 200, body: "Hello world")
|
|
|
|
end
|
|
|
|
|
|
|
|
let(:upload_s3) { Fabricate(:upload_s3) }
|
|
|
|
let(:store) { FileStore::BaseStore.new }
|
|
|
|
|
|
|
|
it "does not raise an error when download fails" do
|
|
|
|
FileHelper.stubs(:download).raises(OpenURI::HTTPError.new("400 error", anything))
|
|
|
|
|
|
|
|
expect(store.download_safe(upload_s3)).to eq(nil)
|
|
|
|
end
|
|
|
|
end
|
2017-08-02 22:56:55 -04:00
|
|
|
end
|