jam-cloud/ruby/spec/jam_ruby/models/icecast_mount_spec.rb

368 lines
14 KiB
Ruby
Raw Permalink Normal View History

2014-01-10 21:02:52 +00:00
require 'spec_helper'
describe IcecastMount do
let(:icecast_mount) { FactoryGirl.create(:icecast_mount) }
let(:output) { StringIO.new }
let(:builder) { ::Builder::XmlMarkup.new(:target => output, :indent => 1) }
2014-01-10 21:02:52 +00:00
it "save error" do
mount = IcecastMount.new
mount.save.should be_false
mount.errors[:name].should == ["can't be blank", "must start with /"]
2014-01-10 21:02:52 +00:00
end
2014-01-14 21:22:05 +00:00
2014-01-10 21:02:52 +00:00
it "save" do
mount = IcecastMount.new
mount.name = "/" + Faker::Lorem.characters(10)
mount.stream_name = Faker::Lorem.characters(10)
mount.stream_description = Faker::Lorem.characters(10)
mount.stream_url = Faker::Lorem.characters(10)
mount.genre = Faker::Lorem.characters(10)
mount.source_username = Faker::Lorem.characters(10)
mount.source_pass = Faker::Lorem.characters(10)
mount.intro = Faker::Lorem.characters(10)
mount.fallback_mount = Faker::Lorem.characters(10)
mount.on_connect = Faker::Lorem.characters(10)
mount.on_disconnect = Faker::Lorem.characters(10)
mount.fallback_override = true
mount.fallback_when_full = true
mount.max_listeners = 1000
mount.max_listener_duration = 3600
mount.authentication = FactoryGirl.create(:icecast_user_authentication)
mount.server = FactoryGirl.create(:icecast_server_with_overrides)
2014-01-14 21:22:05 +00:00
mount.save!
2014-01-14 21:22:05 +00:00
mount.dumpXml(builder)
2014-01-14 21:22:05 +00:00
output.rewind
2014-01-14 21:22:05 +00:00
xml = Nokogiri::XML(output)
xml.css('mount mount-name').text.should == mount.name
xml.css('mount username').text.should == mount.source_username
xml.css('mount password').text.should == mount.source_pass
xml.css('mount max-listeners').text.should == mount.max_listeners.to_s
xml.css('mount max-listener-duration').text.should == mount.max_listener_duration.to_s
xml.css('mount intro').text.should == mount.intro
xml.css('mount fallback-mount').text.should == mount.fallback_mount
xml.css('mount fallback-override').text.should == mount.fallback_override.to_s
xml.css('mount fallback-when-full').text.should == mount.fallback_when_full.to_s
xml.css('mount stream-name').text.should == mount.stream_name
xml.css('mount stream-description').text.should == mount.stream_description
xml.css('mount stream-url').text.should == mount.stream_url
xml.css('mount genre').text.should == mount.genre
xml.css('mount bitrate').length.should == 0
xml.css('mount charset').text == mount.charset
xml.css('mount public').text == mount.is_public.to_s
xml.css('mount type').text == mount.mime_type
xml.css('mount subtype').text == mount.subtype
xml.css('mount burst-size').length.should == 0
xml.css('mount mp3-metadata-interval').length.should == 0
xml.css('mount hidden').text.should == mount.hidden.to_s
xml.css('mount on-connect').text.should == mount.on_connect
xml.css('mount on-disconnect').text.should == mount.on_disconnect
xml.css('mount dump-file').length.should == 0
xml.css('mount authentication').length.should == 1 # no reason to test futher; it's tested in that model
end
describe "override xml over mount template" do
let(:mount) {FactoryGirl.create(:iceast_mount_with_template)}
it "should allow override by mount" do
mount.dumpXml(builder)
output.rewind
xml = Nokogiri::XML(output)
xml.css('mount mount-name').text.should == mount.name
xml.css('mount username').text.should == mount.source_username
xml.css('mount bitrate').text.should == mount.bitrate.to_s
xml.css('mount type').text.should == mount.mount_template.mime_type
xml.css('mount stream-url').text.should == mount.stream_url
# now see the stream_url, and bitrate, go back to the template's value because we set it to nil
mount.bitrate = nil
mount.stream_url = nil
mount.save!
output = StringIO.new
builder = ::Builder::XmlMarkup.new(:target => output, :indent => 1)
mount.dumpXml(builder)
output.rewind
xml = Nokogiri::XML(output)
xml.css('mount bitrate').text.should == mount.mount_template.bitrate.to_s
xml.css('mount stream-url').text.should == mount.mount_template.stream_url
end
end
describe "poke configs" do
let(:server) { a = FactoryGirl.create(:icecast_server_with_overrides); a.config_updated; IcecastServer.find(a.id) }
2014-01-14 21:22:05 +00:00
before(:each) do
server.mounts << FactoryGirl.create(:icecast_mount, server: server)
server.save!
server.config_updated
server.reload
server.config_changed.should == 0
end
it "success via server" do
server.mounts.first.save!
server.reload
server.config_changed.should == 1
end
it "success when deleted" do
server.mounts.first.destroy
server.reload
server.config_changed.should == 1
end
2014-01-10 21:02:52 +00:00
end
2014-01-14 21:22:05 +00:00
describe "icecast server callbacks" do
it "source up" do
icecast_mount.source_up
end
end
describe "listener/source" do
let(:mount) {FactoryGirl.create(:iceast_mount_with_template)}
describe "listeners" do
it "listener_add" do
mount.listener_add
mount.listeners.should == 1
end
it "listener_remove when at 0" do
mount.listener_remove
mount.listeners.should == 0
end
it "listener_remove" do
mount.listener_add
mount.listener_remove
mount.listeners.should == 0
end
end
describe "sources" do
it "source_up" do
mount.source_up
mount.sourced.should == true
end
end
describe "sources" do
it "source_down" do
mount.source_up
mount.source_down
mount.sourced.should == false
end
end
end
describe "build_session_mount" do
let(:server1) {FactoryGirl.create(:icecast_server_minimal)}
let(:server2) {FactoryGirl.create(:icecast_server_with_overrides)}
let(:server3) {FactoryGirl.create(:icecast_server_with_overrides)}
2014-05-06 13:34:38 +00:00
let(:hidden_music_session) { FactoryGirl.create(:active_music_session, :fan_access => false)}
let(:public_music_session) { FactoryGirl.create(:active_music_session, :fan_access => true)}
let(:public_music_session2) { FactoryGirl.create(:active_music_session, :fan_access => true)}
let(:public_music_session3) { FactoryGirl.create(:active_music_session, :fan_access => true)}
before(:each) do
end
it "no fan access means no mount" do
2014-05-06 22:50:41 +00:00
mount = IcecastMount.build_session_mount(hidden_music_session.music_session, hidden_music_session, IcecastServer.find_best_server_for_user(hidden_music_session.creator))
mount.should be_nil
end
it "with no servers" do
IcecastServer.count.should == 0
2014-05-06 22:50:41 +00:00
mount = IcecastMount.build_session_mount(public_music_session.music_session, public_music_session, IcecastServer.find_best_server_for_user(public_music_session.creator))
mount.should be_nil
end
it "with a server that has a mount template" do
server1.mount_template.should_not be_nil
2014-05-06 22:50:41 +00:00
mount = IcecastMount.build_session_mount(public_music_session.music_session, public_music_session, IcecastServer.find_best_server_for_user(public_music_session.creator))
mount.should_not be_nil
mount.save!
end
it "with a server that already has an associated mount" do
server1.mount_template.should_not be_nil
2014-05-06 22:50:41 +00:00
mount = IcecastMount.build_session_mount(public_music_session.music_session, public_music_session, IcecastServer.find_best_server_for_user(public_music_session.creator))
mount.save!
2014-05-06 22:50:41 +00:00
mount = IcecastMount.build_session_mount(public_music_session2.music_session, public_music_session2, IcecastServer.find_best_server_for_user(public_music_session2.creator))
mount.save!
server1.reload
server1.mounts.length.should == 2
end
it "picks a second server once the 1st has been chosen" do
server1.touch
2014-05-06 22:50:41 +00:00
mount = IcecastMount.build_session_mount(public_music_session.music_session, public_music_session, IcecastServer.find_best_server_for_user(public_music_session.creator))
mount.listeners = 1 # affect the weight
mount.save!
server2.touch
2014-05-06 22:50:41 +00:00
mount = IcecastMount.build_session_mount(public_music_session2.music_session, public_music_session2, IcecastServer.find_best_server_for_user(public_music_session2.creator))
mount.save!
server1.reload
server1.mounts.length.should == 1
server2.reload
server2.mounts.length.should == 1
end
it "picks the 1st server again once the 2nd has higher weight" do
server1.touch
2014-05-06 22:50:41 +00:00
mount = IcecastMount.build_session_mount(public_music_session.music_session, public_music_session, IcecastServer.find_best_server_for_user(public_music_session.creator))
mount.listeners = 1 # affect the weight
mount.save!
server2.touch
2014-05-06 22:50:41 +00:00
mount = IcecastMount.build_session_mount(public_music_session2.music_session, public_music_session2, IcecastServer.find_best_server_for_user(public_music_session2.creator))
mount.sourced = 1
mount.save!
2014-05-06 22:50:41 +00:00
mount = IcecastMount.build_session_mount(public_music_session3.music_session, public_music_session3, IcecastServer.find_best_server_for_user(public_music_session3.creator))
mount.listeners = 1
mount.save!
server1.reload
server1.mounts.length.should == 2
server2.reload
server2.mounts.length.should == 1
end
end
describe "source_changes are deleted if source_direction transitions" do
it "no change if same source_direction" do
mount = FactoryGirl.create(:iceast_mount_with_music_session, source_direction: true)
change1 = FactoryGirl.create(:icecast_source_change, mount: mount, source_direction: true, success:true)
mount.source_changes.size.should == 1
mount.source_direction = true
mount.save!
mount = IcecastMount.find(mount.id)
mount.source_changes.size.should == 1
end
it "NOT deleted on transition to down" do
mount = FactoryGirl.create(:iceast_mount_with_music_session, source_direction: true)
change1 = FactoryGirl.create(:icecast_source_change, mount: mount, source_direction: true, success:true)
mount.source_changes.size.should == 1
mount.source_direction = false
mount.save!
mount = IcecastMount.find(mount.id)
mount.source_changes.size.should == 1
end
it "not deleted on transition to up" do
mount = FactoryGirl.create(:iceast_mount_with_music_session, source_direction: false)
change1 = FactoryGirl.create(:icecast_source_change, mount: mount, source_direction: true, success:true)
mount.source_changes.size.should == 1
mount.source_direction = true
mount.save!
mount.reload
mount.source_changes.size.should == 1
end
end
describe "state" do
def success_state(reason, detail = nil)
{success: true, reason: reason, detail:detail}
end
def fail_state(reason, detail = nil)
{success: false, reason: reason, detail:detail}
end
let(:sourced_mount) {FactoryGirl.create(:iceast_mount_with_music_session, sourced: true, sourced_needs_changing_at: nil, listeners: 1)}
let(:mount_needing_source) {FactoryGirl.create(:iceast_mount_with_music_session, sourced: false, sourced_needs_changing_at: Time.now, listeners: 1)}
it "happy sourced mount" do
sourced_mount.state.should == success_state('source_up')
end
it "just transitioned" do
mount_needing_source.state.should == success_state('transition_down', 'initial')
end
it "transition timeout" do
#change1 = FactoryGirl.create(:icecast_source_change, mount: mount, source_direction: true, success:true)
mount_needing_source.sourced_needs_changing_at = (APP_CONFIG.source_changes_missing_secs + 1).seconds.ago
mount_needing_source.save!
mount_needing_source.state.should == fail_state('transition_timeout_down', 'initial')
end
describe "client attempted transition and" do
let!(:change1) { FactoryGirl.create(:icecast_source_change, mount: mount_needing_source, source_direction: true, success:true) }
it "happy sourced mount" do
mount_needing_source.sourced = true
mount_needing_source.save!
mount_needing_source.state.should == success_state('source_up', change1.user.id)
end
it "succeeded recently in correct transition" do
mount_needing_source.state.should == success_state('transition_down')
end
it "succeeded a while ago in correct transition" do
change1.update_attribute(:created_at, (APP_CONFIG.source_changes_missing_secs + 1).seconds.ago)
mount_needing_source.state.should == fail_state('transition_timeout_down')
end
it "failed recently in correct transition" do
change1.success = false
change1.reason = 'bleh'
change1.source_direction = true
change1.save!
mount_needing_source.state.should == fail_state('source_wrong_down', change1.reason)
end
it "failed a while ago in correct transition" do
change1.success = false
change1.reason = 'bleh'
change1.source_direction = true
change1.created_at = (APP_CONFIG.source_changes_missing_secs + 1).seconds.ago
change1.save!
mount_needing_source.state.should == fail_state('source_wrong_down', change1.reason)
end
it "failed recently in wrong transition" do
change1.success = false
change1.reason = 'bleh'
change1.source_direction = false
change1.save!
mount_needing_source.state.should == fail_state('transition_down')
end
it "failed a while ago in wrong transition" do
change1.success = false
change1.reason = 'bleh'
change1.source_direction = false
change1.save!
mount_needing_source.sourced_needs_changing_at = (APP_CONFIG.source_changes_missing_secs + 1).seconds.ago
mount_needing_source.save!
mount_needing_source.state.should == fail_state('source_wrong_down', 'no_client')
end
end
end
2014-01-10 21:02:52 +00:00
end