discourse/spec/tasks/uploads_spec.rb
Michael K Johnson 81e6bc7a0f
FEATURE: Add uploads:batch_migrate_from_s3 task to limit total posts migrated at once (#9933)
Allow limiting the number of migrations to do at once, both to do migrations that
have impact limited to multiple off-peak usage hours to reduce user impact from
a migration, and to allow tests that do only a very small number for test
purposes. ("Give me a ping, Vasili. One ping only, please.")
2020-06-04 09:48:11 +10:00

320 lines
10 KiB
Ruby

# frozen_string_literal: true
require 'rails_helper'
RSpec.describe "tasks/uploads" do
before do
Rake::Task.clear
Discourse::Application.load_tasks
SiteSetting.authorized_extensions += "|pdf"
end
describe "uploads:secure_upload_analyse_and_update" do
let!(:uploads) do
[
multi_post_upload1,
upload1,
upload2,
upload3
]
end
let(:multi_post_upload1) { Fabricate(:upload_s3) }
let(:upload1) { Fabricate(:upload_s3) }
let(:upload2) { Fabricate(:upload_s3) }
let(:upload3) { Fabricate(:upload_s3, original_filename: 'test.pdf', extension: 'pdf') }
let!(:post1) { Fabricate(:post) }
let!(:post2) { Fabricate(:post) }
let!(:post3) { Fabricate(:post) }
before do
PostUpload.create(post: post1, upload: multi_post_upload1)
PostUpload.create(post: post2, upload: multi_post_upload1)
PostUpload.create(post: post2, upload: upload1)
PostUpload.create(post: post3, upload: upload2)
PostUpload.create(post: post3, upload: upload3)
end
def invoke_task
capture_stdout do
Rake::Task['uploads:secure_upload_analyse_and_update'].invoke
end
end
context "when the store is internal" do
it "does nothing; this is for external store only" do
Upload.expects(:transaction).never
expect { invoke_task }.to raise_error(SystemExit)
end
end
context "when store is external" do
before do
enable_s3_uploads(uploads)
end
context "when secure media is enabled" do
before do
SiteSetting.secure_media = true
end
it "sets an access_control_post for each post upload, using the first linked post in the case of multiple links" do
invoke_task
expect(multi_post_upload1.reload.access_control_post).to eq(post1)
expect(upload1.reload.access_control_post).to eq(post2)
expect(upload2.reload.access_control_post).to eq(post3)
expect(upload3.reload.access_control_post).to eq(post3)
end
it "sets the uploads that are media and attachments in the read restricted topic category to secure" do
post3.topic.update(category: Fabricate(:private_category, group: Fabricate(:group)))
invoke_task
expect(upload2.reload.secure).to eq(true)
expect(upload1.reload.secure).to eq(false)
expect(upload3.reload.secure).to eq(true)
end
it "sets the upload in the PM topic to secure" do
post3.topic.update(archetype: 'private_message', category: nil)
invoke_task
expect(upload2.reload.secure).to eq(true)
expect(upload1.reload.secure).to eq(false)
end
it "rebakes the posts attached for uploads that change secure status" do
post3.topic.update(category: Fabricate(:private_category, group: Fabricate(:group)))
freeze_time
post1.update_columns(baked_at: 1.week.ago)
post2.update_columns(baked_at: 1.week.ago)
post3.update_columns(baked_at: 1.week.ago)
invoke_task
expect(post1.reload.baked_at).to eq_time(1.week.ago)
expect(post2.reload.baked_at).to eq_time(1.week.ago)
expect(post3.reload.baked_at).not_to eq_time(1.week.ago)
end
context "for an upload that is already secure and does not need to change" do
before do
post3.topic.update(archetype: 'private_message', category: nil)
upload2.update(access_control_post: post3)
upload2.update_secure_status
upload3.update(access_control_post: post3)
upload3.update_secure_status
end
it "does not rebake the associated post" do
freeze_time
post3.update_columns(baked_at: 1.week.ago)
invoke_task
expect(post3.reload.baked_at).to eq_time(1.week.ago)
end
it "does not attempt to update the acl" do
Discourse.store.expects(:update_upload_ACL).with(upload2).never
invoke_task
end
end
context "for an upload that is already secure and is changing to not secure" do
it "changes the upload to not secure and updates the ACL" do
upload_to_mark_not_secure = Fabricate(:upload_s3, secure: true)
post_for_upload = Fabricate(:post)
PostUpload.create(post: post_for_upload, upload: upload_to_mark_not_secure)
enable_s3_uploads(uploads.concat([upload_to_mark_not_secure]))
invoke_task
expect(upload_to_mark_not_secure.reload.secure).to eq(false)
end
end
end
end
end
describe "uploads:batch_migrate_from_s3" do
let!(:uploads) do
[
upload1,
upload2,
]
end
let(:upload1) { Fabricate(:upload_s3) }
let(:upload2) { Fabricate(:upload_s3) }
let!(:url1) { "upload://#{upload1.base62_sha1}.jpg" }
let!(:url2) { "upload://#{upload2.base62_sha1}.jpg" }
let(:post1) { Fabricate(:post, raw: "[foo](#{url1})") }
let(:post2) { Fabricate(:post, raw: "[foo](#{url2})") }
before do
global_setting :s3_bucket, 'file-uploads/folder'
global_setting :s3_region, 'us-east-1'
enable_s3_uploads(uploads)
upload1.url = "//#{SiteSetting.s3_upload_bucket}.amazonaws.com/original/1X/#{upload1.base62_sha1}.png"
upload1.save!
upload2.url = "//#{SiteSetting.s3_upload_bucket}.amazonaws.com/original/1X/#{upload2.base62_sha1}.png"
upload2.save!
PostUpload.create(post: post1, upload: upload1)
PostUpload.create(post: post2, upload: upload2)
SiteSetting.enable_s3_uploads = false
end
def invoke_task
capture_stdout do
Rake::Task['uploads:batch_migrate_from_s3'].invoke('1')
end
end
it "applies the limit" do
FileHelper.stubs(:download).returns(file_from_fixtures("logo.png")).once()
freeze_time
post1.update_columns(baked_at: 1.week.ago)
post2.update_columns(baked_at: 1.week.ago)
invoke_task
expect(post1.reload.baked_at).not_to eq_time(1.week.ago)
expect(post2.reload.baked_at).to eq_time(1.week.ago)
end
end
describe "uploads:migrate_from_s3" do
let!(:uploads) do
[
upload1,
upload2,
]
end
let(:upload1) { Fabricate(:upload_s3) }
let(:upload2) { Fabricate(:upload_s3) }
let!(:url1) { "upload://#{upload1.base62_sha1}.jpg" }
let!(:url2) { "upload://#{upload2.base62_sha1}.jpg" }
let(:post1) { Fabricate(:post, raw: "[foo](#{url1})") }
let(:post2) { Fabricate(:post, raw: "[foo](#{url2})") }
before do
global_setting :s3_bucket, 'file-uploads/folder'
global_setting :s3_region, 'us-east-1'
enable_s3_uploads(uploads)
upload1.url = "//#{SiteSetting.s3_upload_bucket}.amazonaws.com/original/1X/#{upload1.base62_sha1}.png"
upload1.save!
upload2.url = "//#{SiteSetting.s3_upload_bucket}.amazonaws.com/original/1X/#{upload2.base62_sha1}.png"
upload2.save!
PostUpload.create(post: post1, upload: upload1)
PostUpload.create(post: post2, upload: upload2)
SiteSetting.enable_s3_uploads = false
end
def invoke_task
capture_stdout do
Rake::Task['uploads:migrate_from_s3'].invoke
end
end
it "fails if s3 uploads are still enabled" do
SiteSetting.enable_s3_uploads = true
expect { invoke_task }.to raise_error(SystemExit)
end
it "does not apply a limit" do
FileHelper.stubs(:download).with("http:#{upload1.url}", max_file_size: 4194304, tmp_file_name: "from_s3", follow_redirect: true).returns(file_from_fixtures("logo.png")).once()
FileHelper.stubs(:download).with("http:#{upload2.url}", max_file_size: 4194304, tmp_file_name: "from_s3", follow_redirect: true).returns(file_from_fixtures("logo.png")).once()
freeze_time
post1.update_columns(baked_at: 1.week.ago)
post2.update_columns(baked_at: 1.week.ago)
invoke_task
expect(post1.reload.baked_at).not_to eq_time(1.week.ago)
expect(post2.reload.baked_at).not_to eq_time(1.week.ago)
end
end
describe "uploads:disable_secure_media" do
def invoke_task
capture_stdout do
Rake::Task['uploads:disable_secure_media'].invoke
end
end
before do
enable_s3_uploads(uploads)
SiteSetting.secure_media = true
PostUpload.create(post: post1, upload: upload1)
PostUpload.create(post: post1, upload: upload2)
PostUpload.create(post: post2, upload: upload3)
PostUpload.create(post: post2, upload: upload4)
end
let!(:uploads) do
[
upload1, upload2, upload3, upload4, upload5
]
end
let(:post1) { Fabricate(:post) }
let(:post2) { Fabricate(:post) }
let(:upload1) { Fabricate(:upload_s3, secure: true, access_control_post: post1) }
let(:upload2) { Fabricate(:upload_s3, secure: true, access_control_post: post1) }
let(:upload3) { Fabricate(:upload_s3, secure: true, access_control_post: post2) }
let(:upload4) { Fabricate(:upload_s3, secure: true, access_control_post: post2) }
let(:upload5) { Fabricate(:upload_s3, secure: false) }
it "disables the secure media setting" do
invoke_task
expect(SiteSetting.secure_media).to eq(false)
end
it "updates all secure uploads to secure: false" do
invoke_task
[upload1, upload2, upload3, upload4].each do |upl|
expect(upl.reload.secure).to eq(false)
end
end
it "rebakes the associated posts" do
freeze_time
post1.update_columns(baked_at: 1.week.ago)
post2.update_columns(baked_at: 1.week.ago)
invoke_task
expect(post1.reload.baked_at).not_to eq_time(1.week.ago)
expect(post2.reload.baked_at).not_to eq_time(1.week.ago)
end
it "updates the affected ACLs" do
FileStore::S3Store.any_instance.expects(:update_upload_ACL).times(4)
invoke_task
end
end
def enable_s3_uploads(uploads)
SiteSetting.enable_s3_uploads = true
SiteSetting.s3_upload_bucket = "s3-upload-bucket"
SiteSetting.s3_access_key_id = "some key"
SiteSetting.s3_secret_access_key = "some secrets3_region key"
stub_request(:head, "https://#{SiteSetting.s3_upload_bucket}.s3.amazonaws.com/")
uploads.each do |upload|
stub_request(
:put,
"https://#{SiteSetting.s3_upload_bucket}.s3.amazonaws.com/original/1X/#{upload.sha1}.#{upload.extension}?acl"
)
end
end
end