require 'spec_helper' require 'rack/mock' describe Dragonfly::App do describe ".instance" do it "should create a new instance if it didn't already exist" do app = Dragonfly::App.instance(:images) app.should be_a(Dragonfly::App) end it "should return an existing instance if called by name" do app = Dragonfly::App.instance(:images) Dragonfly::App.instance(:images).should == app end it "has a default instance" do Dragonfly::App.instance.should be_a(Dragonfly::App) end it "returns the default instance if passed nil" do Dragonfly::App.instance(nil).should == Dragonfly::App.instance end end describe ".new" do it "should not be callable" do lambda{ Dragonfly::App.new }.should raise_error(NoMethodError) end end describe "destroy_apps" do it "destroys the dragonfly apps" do Dragonfly::App.instance(:gug) Dragonfly::App.instance(:blug) Dragonfly::App.apps.length.should == 2 Dragonfly::App.destroy_apps Dragonfly::App.apps.length.should == 0 end end describe "mime types" do let(:app) { test_app } describe "#mime_type_for" do it "should return the correct mime type for a symbol" do app.mime_type_for(:png).should == 'image/png' end it "should work for strings" do app.mime_type_for('png').should == 'image/png' end it "should work with uppercase strings" do app.mime_type_for('PNG').should == 'image/png' end it "should work with a dot" do app.mime_type_for('.png').should == 'image/png' end it "should return the fallback if not known" do app.mime_type_for(:mark).should == 'application/octet-stream' end it "should allow for configuring extra mime types" do app.add_mime_type 'mark', 'application/mark' app.mime_type_for(:mark).should == 'application/mark' end it "should override existing mime types when registered" do app.add_mime_type :png, 'ping/pong' app.mime_type_for(:png).should == 'ping/pong' end it "should have a per-app mime-type configuration" do other_app = Dragonfly.app(:other_app) app.add_mime_type(:mark, 'first/one') other_app.add_mime_type(:mark, 'second/one') app.mime_type_for(:mark).should == 'first/one' other_app.mime_type_for(:mark).should == 'second/one' end it "can be added via configure" do app.configure{ mime_type 'mark', 'application/mark' } app.mime_type_for(:mark).should == 'application/mark' end end describe "#ext_for" do it "returns the ext corresponding to a mime_type" do app.ext_for('image/png').should == 'png' end it "returns nil if non-existent" do app.ext_for('big/bum').should be_nil end it "returns txt for text/plain" do app.ext_for('text/plain').should == 'txt' end end end describe "create" do let (:app) { test_app } it "creates a new job with the specified data/meta" do job = app.create("hello", 'a' => 'b') job.should be_a(Dragonfly::Job) job.data.should == 'hello' job.meta['a'].should == 'b' end it "accepts other jobs" do job2 = app.create("other", 'c' => 'd') job = app.create(job2) job.data.should == 'other' job.meta['c'].should == 'd' end it "accepts Attachments" do Car = new_model_class('Car', :make_uid) do dragonfly_accessor :make end car = Car.new(:make => 'jaguar') car.make.meta['a'] = 'b' job = app.create(car.make) job.data.should == 'jaguar' job.meta['a'].should == 'b' end end describe "remote_url_for" do before(:each) do @app = test_app @app.datastore = Object.new end it "should raise an error if the datastore doesn't provide it" do lambda{ @app.remote_url_for('some_uid') }.should raise_error(NotImplementedError) end it "should correctly call it if the datastore provides it" do @app.datastore.should_receive(:url_for).with('some_uid', :some => :opts).and_return 'http://egg.head' @app.remote_url_for('some_uid', :some => :opts).should == 'http://egg.head' end end describe "#store" do let (:app) { test_app } it "should allow just storing content" do app.datastore.should_receive(:write).with( satisfy{|content| content.data == 'HELLO'}, anything ) app.store("HELLO") end it "passes meta and options through too" do app.datastore.should_receive(:write).with( satisfy{|content| content.data == 'HELLO' && content.meta == {'d' => 3} }, {a: :b} ) app.store("HELLO", {'d' => 3}, {:a => :b}) end end describe "url_for" do let (:app) { test_app } let (:job) { app.fetch('eggs') } it "should give the server url by default" do app.url_for(job).should =~ %r{^/\w+} end it "should allow configuring" do app.configure do define_url do |app, job, opts| "doogies" end end app.url_for(job).should == 'doogies' end it "should yield the correct dooberries" do app.define_url do |app, job, opts| [app, job, opts] end app.url_for(job, {'chuddies' => 'margate'}).should == [app, job, {'chuddies' => 'margate'}] end end describe "adding generators" do before(:each) do @app = test_app.configure do generator(:butter){ "BUTTER" } end end it "should return generator methods" do @app.generator_methods.should == [:butter] end end describe "adding processors" do before(:each) do @app = test_app.configure do processor(:double){} end end it "should add a method" do job1 = @app.create("bunga") job2 = job1.double job1.should_not == job2 job1.to_a.should == [] job2.to_a.should == [['p', :double]] end it "should add a bang method" do job = @app.create("bunga") job.double!.should == job job.to_a.should == [['p', :double]] end it "should return processor methods" do @app.processor_methods.should == [:double] end end describe "adding analysers" do before(:each) do @app = test_app.configure do analyser(:length){|content| content.size } end end it "should add a method" do @app.create('123').length.should == 3 end it "should return analyser methods" do @app.analyser_methods.should == [:length] end end describe "response headers" do let (:app) {test_app} it "adds a response header" do app.response_header 'Cache-Control', "private" app.response_headers["Cache-Control"].should == 'private' end it "adds a response header using a block" do app.response_header 'Cache-Control' do "private" end app.response_headers["Cache-Control"].should be_a(Proc) end it "allows calling through the config" do app.configure{ response_header 'Cache-Control', "private" } end end describe "inspect" do it "should give a neat output" do Dragonfly.app(:hello).inspect.should == "" end end describe "configuration" do let(:app){ test_app } describe "datastore" do it "sets the datastore" do store = double('datastore') app.configure{ datastore store } app.datastore.should == store end { :file => Dragonfly::FileDataStore, :memory => Dragonfly::MemoryDataStore }.each do |symbol, klass| it "recognises the #{symbol.inspect} shortcut for S3DataStore" do app.configure{ datastore symbol } app.datastore.should be_a(klass) end end end it "raises an error if it doesn't know the symbol" do expect{ app.configure{ datastore :hello } }.to raise_error(Dragonfly::App::UnregisteredDataStore) end it "passes args through to the initializer if a symbol is given" do app.configure{ datastore :file, :root_path => '/some/path' } app.datastore.root_path.should == '/some/path' end it "complains if extra args are given but first is not a symbol" do store = double('datastore') expect{ app.configure{ datastore store, :some => 'args' } }.to raise_error(ArgumentError) end end describe "define" do let(:app){ test_app } before :each do app.define :exclaim do |n| data.upcase + "!"*n end end it "allows defining methods on jobs" do app.create("snowman").exclaim(3).should == 'SNOWMAN!!!' end it "can be added through configure" do app.configure{ define(:googie){} } app.create("snowman").googie.should be_nil end end describe "shell" do let(:app){ test_app } it "has a shell" do app.shell.should be_a(Dragonfly::Shell) end end describe "env" do let(:app){ test_app } it "stores environment variables" do app.env.should == {} app.env[:doogie] = 'blisto' app.env[:doogie].should == 'blisto' end end describe "deprecations" do it "raises a message when using App#[]" do expect { Dragonfly::App[:images] }.to raise_error(/Dragonfly::App\[:images\] .* Dragonfly\.app /) end it "raises a message when configuring with an old datastore" do expect { Dragonfly.app.use_datastore(double("datastore", :store => "asdf", :retrieve => "ASDF", :destroy => nil)) }.to raise_error(/read/) end it "raises a messages when configuring with a bad parameter" do expect { Dragonfly.app.configure do |c| c.url_format = '/media/:job' end }.to raise_error(/no method.*changed.*docs/) end it "raises a message when calling App#define_macro" do expect { Dragonfly.app.define_macro(Object, :image_accessor) }.to raise_error(/dragonfly_accessor/) end it "raises a message when calling App#define_macro_on_include" do expect { Dragonfly.app.define_macro_on_include(Module.new, :image_accessor) }.to raise_error(/dragonfly_accessor/) end end end