require 'spec_helper' require 'fileutils' =begin # these tests avoid the use of ActiveRecord and FactoryGirl to do blackbox, non test-instrumented tests describe AudioMixer do include UsesTempFiles let(:audiomixer) { AudioMixer.new } let(:manifest) { {} } let(:valid_manifest) { make_manifest(manifest) } def valid_files(manifest) manifest["files"] = [ {"codec" => "vorbis", "offset" => 0, "filename" => "/some/path"} ] end def valid_output(manifest) manifest["output"] = { "codec" => "vorbis" } end def valid_timeline(manifest) manifest["timeline"] = [] end def valid_recording(manifest) manifest["recording_id"] = "record1" end def valid_mix(manifest) manifest["mix_id"] = "mix1" end def make_manifest(manifest) valid_files(manifest) valid_output(manifest) valid_timeline(manifest) valid_recording(manifest) valid_mix(manifest) return manifest end before(:each) do stub_const("APP_CONFIG", app_config) module EM @next_tick_queue = [] end MQRouter.client_exchange = double("client_exchange") MQRouter.user_exchange = double("user_exchange") MQRouter.client_exchange.should_receive(:publish).any_number_of_times MQRouter.user_exchange.should_receive(:publish).any_number_of_times end describe "validate" do it "no manifest" do expect { audiomixer.validate }.to raise_error("no manifest specified") end it "no files specified" do audiomixer.manifest = manifest expect { audiomixer.validate }.to raise_error("no files specified") end it "no codec specified" do audiomixer.manifest = { "files" => [ {"offset" => 0, "filename" => "/some/path"} ] } expect { audiomixer.validate }.to raise_error("no codec specified") end it "no offset specified" do audiomixer.manifest = { "files" => [ {"codec" => "vorbis", "filename" => "/some/path"} ] } expect { audiomixer.validate }.to raise_error("no offset specified") end it "no output specified" do valid_files(manifest) audiomixer.manifest = manifest audiomixer.manifest = { "files" => [ {"codec" => "vorbis", "offset" => 0, "filename" => "/some/path"} ] } expect { audiomixer.validate }.to raise_error("no output specified") end it "no recording_id specified" do valid_files(manifest) valid_output(manifest) valid_timeline(manifest) valid_mix(manifest) audiomixer.manifest = manifest expect { audiomixer.validate }.to raise_error("no recording_id specified") end it "no mix_id specified" do valid_files(manifest) valid_output(manifest) valid_timeline(manifest) valid_recording(manifest) audiomixer.manifest = manifest expect { audiomixer.validate }.to raise_error("no mix_id specified") end end describe "fetch_audio_files" do it "get upset if file doesn't exist" do audiomixer.manifest = { "files" => [ {"codec" => "vorbis", "offset" => 0, "filename" => "/some/bogus/path"} ] } expect { audiomixer.fetch_audio_files }.to raise_error("no file located at: /some/bogus/path") end end describe "prepare_manifest" do it "writes manifest as json to file" do audiomixer.manifest = valid_manifest audiomixer.prepare_manifest File.read(audiomixer.manifest_file).should == valid_manifest.to_json end end describe "prepare_output" do it "can be written to" do audiomixer.manifest = valid_manifest audiomixer.prepare_output File.open(audiomixer.manifest[:output][:filename] ,"w") do |f| f.write("tickle") end File.read(audiomixer.manifest[:output][:filename]).should == "tickle" end end describe "prepare_error_out" do it "can be written to" do audiomixer.manifest = valid_manifest audiomixer.prepare_error_out File.open(audiomixer.manifest[:error_out] ,"w") do |f| f.write("some_error") end File.read(audiomixer.manifest[:error_out]).should == "some_error" end end describe "integration" do sample_ogg='sample.ogg' in_directory_with_file(sample_ogg) before(:each) do content_for_file("ogg goodness") @user = FactoryGirl.create(:user) @connection = FactoryGirl.create(:connection, :user => @user) @instrument = FactoryGirl.create(:instrument, :description => 'a great instrument') @track = FactoryGirl.create(:track, :connection => @connection, :instrument => @instrument) @music_session = FactoryGirl.create(:music_session, :creator => @user, :musician_access => true) # @music_session.connections << @connection @music_session.save @connection.join_the_session(@music_session, true, nil) @recording = Recording.start(@music_session, @user) @recording.stop @recording.claim(@user, "name", "description", Genre.first, true) @recording.errors.any?.should be_false end describe "simulated" do let (:local_files_manifest) { { :files => [ { :codec => :vorbis, :offset => 0, :filename => sample_ogg} ], :output => { :codec => :vorbis }, :timeline => [ {:timestamp => 0, :mix => [{:balance => 0, :level => 100}]} ], :recording_id => "recording1" } } # stub out methods that are environmentally sensitive (so as to skip s3, and not run an actual audiomixer) before(:each) do AudioMixer.any_instance.stub(:execute) do |manifest_file| output_filename = JSON.parse(File.read(manifest_file))['output']['filename'] FileUtils.touch output_filename end AudioMixer.any_instance.stub(:postback) # don't actually post resulting off file up end describe "perform" do # this case does not talk to redis, does not run the real audiomixer, and does not actually talk with s3 # but it does talk to the database and verifies all the other logic it "success" do Mix.any_instance.stub(:manifest).and_return(local_files_manifest) # don't actually post resulting off file up @mix = Mix.schedule(@recording) @mix.reload @mix.started_at.should_not be_nil AudioMixer.perform(@mix.id, @mix.sign_url(60 * 60 * 24)) @mix.reload @mix.completed.should be_true @mix.length.should == 0 @mix.md5.should == 'd41d8cd98f00b204e9800998ecf8427e' # that's the md5 of a touched file end it "errored" do local_files_manifest[:files][0][:filename] = '/some/path/to/nowhere' Mix.any_instance.stub(:manifest).and_return(local_files_manifest) @mix = Mix.schedule(@recording) expect{ AudioMixer.perform(@mix.id, @mix.sign_url(60 * 60 * 24)) }.to raise_error @mix.reload @mix.completed.should be_false @mix.error_count.should == 1 @mix.error_reason.should == "unhandled-job-exception" @mix.error_detail.should == "no file located at: /some/path/to/nowhere" end end describe "with resque-spec" do before(:each) do ResqueSpec.reset! end it "should have been enqueued because mix got scheduled" do Mix.any_instance.stub(:manifest).and_return(local_files_manifest) @mix = Mix.schedule(@recording) AudioMixer.should have_queue_size_of(1) end it "should actually run the job" do with_resque do Mix.any_instance.stub(:manifest).and_return(local_files_manifest) @mix = Mix.schedule(@recording) end @mix.reload @mix.completed.should be_true @mix.ogg_length.should == 0 @mix.ogg_md5.should == 'd41d8cd98f00b204e9800998ecf8427e' # that's the md5 of a touched file, which is what the stubbed :execute does end it "bails out with no error if already completed" do with_resque do Mix.any_instance.stub(:manifest).and_return(local_files_manifest) @mix = Mix.schedule(@recording) end @mix.reload @mix.completed.should be_true with_resque do @mix.enqueue end @mix.reload @mix.completed.should be_true end end end # these tests try to run the job with minimal faking. Here's what we still fake: # we don't run audiomixer. audiomixer is tested already # we don't run redis and actual resque, because that's tested by resque/resque-spec describe "full", :aws => true do let (:s3_manifest) { { :files => [ { :codec => :vorbis, :offset => 0, :filename => @s3_sample } ], :output => { :codec => :vorbis }, :timeline => [ {:timestamp => 0, :mix => [{:balance => 0, :level => 100}]} ], :recording_id => @recording.id } } before(:each) do test_config = app_config key = "audiomixer/#{sample_ogg}" @s3_manager = S3Manager.new(test_config.aws_bucket, test_config.aws_access_key_id, test_config.aws_secret_access_key) # put a file in s3 @s3_manager.upload(key, sample_ogg) # create a signed url that the job will use to fetch it back down @s3_sample = @s3_manager.sign_url(key, :secure => false) AudioMixer.any_instance.stub(:execute) do |manifest_file| output_filename = JSON.parse(File.read(manifest_file))['output']['filename'] FileUtils.touch output_filename end end it "completes" do with_resque do Mix.any_instance.stub(:manifest).and_return(s3_manifest) @mix = Mix.schedule(@recording) end @mix.reload @mix.completed.should be_true @mix.length.should == 0 @mix.md5.should == 'd41d8cd98f00b204e9800998ecf8427e' # that's the md5 of a touched file, which is what the stubbed :execute does end it "fails" do with_resque do s3_manifest[:files][0][:filename] = @s3_manager.url('audiomixer/bogus.ogg', :secure => false) # take off some of the trailing chars of the url Mix.any_instance.stub(:manifest).and_return(s3_manifest) expect{ Mix.schedule(@recording) }.to raise_error end @mix = Mix.order('id desc').limit(1).first() @mix.reload @mix.completed.should be_false @mix.error_reason.should == "unable to download" #ResqueFailedJobMailer::Mailer.deliveries.count.should == 1 end end end end =end