315 lines
11 KiB
Ruby
315 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.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
|
|
=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
|