require 'rails_helper' describe "Kithe::Asset promotion hooks", queue_adapter: :inline do temporary_class("TestAsset") do Class.new(Kithe::Asset) do end end let(:unsaved_asset) { TestAsset.new(title: "test", file: File.open(Kithe::Engine.root.join("spec/test_support/images/1x1_pixel.jpg")) ) } describe "before_promotion" do temporary_class("TestAsset") do Class.new(Kithe::Asset) do before_promotion do $metadata_in_before_promotion = self.file.metadata end end end before do $metadata_in_before_promotion = nil end # we have a built-in before_promotion for metadata extraction, # make sure it happens before any additional before_promotions, # so they can eg use it to cancel it "has access to automatic metadata extraction" do unsaved_asset.save! expect($metadata_in_before_promotion).to be_present end end describe "before_promotion cancellation" do temporary_class("TestAsset") do Class.new(Kithe::Asset) do before_promotion do throw :abort end after_promotion do raise "Should not get here" end end end describe "with inline promotion", queue_adapter: :test do before do unsaved_asset.file_attacher.set_promotion_directives(promote: :inline) end it "cancels" do expect_any_instance_of(Kithe::AssetUploader::Attacher).not_to receive(:promote) unsaved_asset.save! unsaved_asset.reload expect(unsaved_asset.reload.stored?).to be(false) end describe "with promotion_directives[:skip_callbacks]" do it "doesn't cancel" do expect_any_instance_of(Kithe::AssetUploader::Attacher).to receive(:promote).and_call_original unsaved_asset.file_attacher.set_promotion_directives(skip_callbacks: true) unsaved_asset.save! unsaved_asset.reload expect(unsaved_asset.stored?).to be(true) end end end describe "with backgrounding promotion", queue_adapter: :inline do it "cancels" do expect_any_instance_of(Kithe::AssetUploader::Attacher).not_to receive(:promote) unsaved_asset.save! unsaved_asset.reload expect(unsaved_asset.stored?).to be(false) end describe "with promotion_directives[:skip_callbacks]" do it "doesn't cancel" do expect_any_instance_of(Kithe::AssetUploader::Attacher).to receive(:promote).and_call_original unsaved_asset.file_attacher.set_promotion_directives(skip_callbacks: true) unsaved_asset.save! unsaved_asset.reload expect(unsaved_asset.stored?).to be(true) end end end describe "assigning directly to store" do temporary_class("TestAsset") do Class.new(Kithe::Asset) do before_promotion do raise "Should not call before_promotion" end after_promotion do raise "Should not call after_promotion" end end end let(:asset) { TestAsset.create(title: "test") } let(:filepath) { Kithe::Engine.root.join("spec/test_support/images/1x1_pixel.jpg") } describe "with inline promoting" do before do asset.file_attacher.set_promotion_directives(promote: :inline) end it "should not call callbacks" do expect_any_instance_of(Kithe::AssetUploader::Attacher).not_to receive(:promote) asset.file_attacher.attach(File.open(filepath)) asset.save! expect(asset.changed?).to be(false) asset.reload expect(asset.file).to be_present expect(asset.stored?).to be(true) end end describe "with background promoting", queue_adapter: :inline do before do asset.file_attacher.set_promotion_directives(promote: :background) end it "should not call callbacks" do expect_any_instance_of(Kithe::AssetUploader::Attacher).not_to receive(:promote) asset.file_attacher.attach(File.open(filepath)) asset.save! expect(asset.changed?).to be(false) asset.reload expect(asset.file).to be_present expect(asset.stored?).to be(true) end end end describe "calling Asset#promote directly", queue_adapter: :inline do before do unsaved_asset.file_attacher.set_promotion_directives(promote: false) unsaved_asset.save! # precondition expect(unsaved_asset.reload.file_attacher.cached?).to be(true) end it "cancels" do expect_any_instance_of(Kithe::AssetUploader::Attacher).not_to receive(:promote) unsaved_asset.promote unsaved_asset.reload expect(unsaved_asset.stored?).to be(false) end describe "with promotion_directives[:skip_callbacks]" do it "doesn't cancel" do expect_any_instance_of(Kithe::AssetUploader::Attacher).to receive(:promote).and_call_original unsaved_asset.file_attacher.set_promotion_directives(skip_callbacks: true) unsaved_asset.promote unsaved_asset.reload expect(unsaved_asset.stored?).to be(true) end end end end describe "after_promotion" do let(:after_promotion_receiver) { proc {} } temporary_class("TestAsset") do receiver = after_promotion_receiver Class.new(Kithe::Asset) do after_promotion do receiver.call(self) end end end it "is called" do expect(after_promotion_receiver).to receive(:call) unsaved_asset.save! end describe "with inline promotion" do before do unsaved_asset.file_attacher.set_promotion_directives(promote: :inline) end # this is actually what's checking for following example... let(:after_promotion_receiver) do proc do |asset| expect(asset.changed?).to be(false) asset.reload expect(asset.stored?).to be(true) end end it "asset has metadata and is finalized" do expect(after_promotion_receiver).to receive(:call).and_call_original unsaved_asset.save! end end describe "with promotion_directives[:skip_callbacks]" do it "doesn't call" do expect(after_promotion_receiver).not_to receive(:call) unsaved_asset.file_attacher.set_promotion_directives(skip_callbacks: true) unsaved_asset.save! end end end describe "around_promotion" do let(:before_receiver) { proc { expect(self.stored?).to be(false) }} let(:after_receiver) { proc { expect(self.stored?).to be(true) }} temporary_class("TestAsset") do Class.new(Kithe::Asset) do around_promotion :my_around_promotion def my_around_promotion yield end end end it "is called" do expect_any_instance_of(TestAsset).to receive(:my_around_promotion).once.and_call_original unsaved_asset.save! unsaved_asset.reload expect(unsaved_asset.stored?).to be(true) end end describe "promotion_directive :promote", queue_adapter: :test do temporary_class("TestUploader") do Class.new(Kithe::AssetUploader) do self::Attacher.define_derivative :test do # no-op, but we need a definition so will be scheduled end end end temporary_class("TestAsset") do Class.new(Kithe::Asset) do set_shrine_uploader(TestUploader) end end it "can cancel promotion" do expect_any_instance_of(Kithe::AssetUploader::Attacher).not_to receive(:promote) unsaved_asset.file_attacher.set_promotion_directives(promote: false) unsaved_asset.save! unsaved_asset.reload expect(unsaved_asset.stored?).to be(false) expect(Kithe::AssetPromoteJob).not_to have_been_enqueued expect(Kithe::CreateDerivativesJob).not_to have_been_enqueued end it "can force promotion in foreground" do unsaved_asset.file_attacher.set_promotion_directives(promote: :inline) unsaved_asset.save! unsaved_asset.reload expect(unsaved_asset.stored?).to be(true) expect(Kithe::AssetPromoteJob).not_to have_been_enqueued expect(Kithe::CreateDerivativesJob).to have_been_enqueued expect(ActiveJob::Base.queue_adapter.performed_jobs.size).to eq(0) end it "raises on unrecgonized value" do unsaved_asset.file_attacher.set_promotion_directives(promote: :something) expect { unsaved_asset.save! }.to raise_error(ArgumentError) end describe ", create_derivatives: false" do it "does not create derivatives" do expect_any_instance_of(Kithe::Asset).not_to receive(:create_derivatives) unsaved_asset.file_attacher.set_promotion_directives(promote: :inline, create_derivatives: false) unsaved_asset.save! unsaved_asset.reload expect(Kithe::AssetPromoteJob).not_to have_been_enqueued expect(Kithe::CreateDerivativesJob).not_to have_been_enqueued expect(ActiveJob::Base.queue_adapter.performed_jobs.size).to eq(0) end end describe ", create_derivatives: :inline" do it "creates derivatives inline" do expect_any_instance_of(Kithe::Asset).to receive(:create_derivatives) unsaved_asset.file_attacher.set_promotion_directives(promote: :inline, create_derivatives: :inline) unsaved_asset.save! unsaved_asset.reload expect(Kithe::AssetPromoteJob).not_to have_been_enqueued expect(Kithe::CreateDerivativesJob).not_to have_been_enqueued expect(ActiveJob::Base.queue_adapter.performed_jobs.size).to eq(0) end end end describe "promotion_directive :delete", queue_adapter: :test do let(:saved_asset) do TestAsset.new(title: "test", file: File.open(Kithe::Engine.root.join("spec/test_support/images/1x1_pixel.jpg")) ).tap do |asset| asset.set_promotion_directives(promote: "inline") asset.save! asset.reload expect(asset.stored?).to be(true) end end let!(:existing_file) { saved_asset.file } it "can cancel deletion" do expect_any_instance_of(Kithe::AssetUploader::Attacher).not_to receive(:destroy) saved_asset.set_promotion_directives(delete: false) saved_asset.destroy! expect(Kithe::AssetDeleteJob).not_to have_been_enqueued expect(existing_file.exists?).to be(true) end it "can force deletion in foreground" do saved_asset.set_promotion_directives(delete: :inline) saved_asset.destroy! expect(existing_file.exists?).to be(false) expect(Kithe::AssetDeleteJob).not_to have_been_enqueued expect(ActiveJob::Base.queue_adapter.performed_jobs.size).to eq(0) end end describe "unrecognized promotion directive" do it "raises" do expect { unsaved_asset.file_attacher.set_promotion_directives(:bad_made_up => true) }.to raise_error(ArgumentError) end end describe "delegated from asset" do around do |example| original_class_settings = Kithe::Asset.promotion_directives example.run Kithe::Asset.promotion_directives = original_class_settings end it "can set from class attribute" do Kithe::Asset.promotion_directives = { promote: :inline } asset = Kithe::Asset.new expect(asset.file_attacher.promotion_directives).to eq("promote" => "inline") end it "can set from instance writer" do asset = Kithe::Asset.new asset.set_promotion_directives(promote: :inline) expect(asset.file_attacher.promotion_directives).to eq("promote" => "inline") expect(asset.promotion_directives).to eq("promote" => "inline") end it "setting from instance writer is aggregative" do Kithe::Asset.promotion_directives = { promote: :inline } asset = Kithe::Asset.new asset.set_promotion_directives(create_derivatives: false) expect(asset.file_attacher.promotion_directives).to eq("promote" => "inline", "create_derivatives" => "false") end it "setting from instance writer survives reload" do asset = Kithe::Asset.create(title: "test") asset.set_promotion_directives(create_derivatives: false) expect(asset.file_attacher.promotion_directives).to eq("create_derivatives" => "false") asset.reload expect(asset.file_attacher.promotion_directives).to eq("create_derivatives" => "false") end end end