jam-cloud/ruby/spec/jam_ruby/resque/audiomixer_spec.rb

317 lines
11 KiB
Ruby

require 'spec_helper'
require 'fileutils'
# 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.subscription_exchange = double("subscription_exchange")
MQRouter.client_exchange.should_receive(:publish).any_number_of_times
MQRouter.user_exchange.should_receive(:publish).any_number_of_times
MQRouter.subscription_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
=begin
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(:active_music_session, :creator => @user, :musician_access => true)
# @music_session.connections << @connection
@music_session.save
@connection.join_the_session(@music_session, true, [@track], @user, 10)
@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_ogg_filename = JSON.parse(File.read(manifest_file))['output']['filename']
FileUtils.touch output_ogg_filename
output_mp3_filename = JSON.parse(File.read(manifest_file))['output']['filename_mp3']
FileUtils.touch output_mp3_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, 'ogg'), @mix.sign_url(60 * 60 * 24, 'mp3'))
@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
@mix.mp3_length.should == 0
@mix.mp3_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, 'ogg'), @mix.sign_url(60 * 60 * 24, 'mp3')) }.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_ogg = JSON.parse(File.read(manifest_file))['output']['filename']
FileUtils.touch output_filename_ogg
output_filename_mp3 = JSON.parse(File.read(manifest_file))['output']['filename_mp3']
FileUtils.touch output_filename_mp3
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.ogg_length.should == 0
@mix.ogg_md5.should == 'd41d8cd98f00b204e9800998ecf8427e' # that's the md5 of a touched file, which is what the stubbed :execute does
@mix.mp3_length.should == 0
@mix.mp3_md5.should == 'd41d8cd98f00b204e9800998ecf8427e' # that's the md5 of a touched file, which is what the stubbed :execute does
end
end
end
=end
end