require 'spec_helper' describe MusicSession do let(:creator) {FactoryGirl.create(:user)} let(:some_user) { FactoryGirl.create(:user) } let(:music_session1) { FactoryGirl.create(:music_session) } let(:music_session2) { FactoryGirl.create(:music_session) } let(:music_session3) { FactoryGirl.create(:music_session) } let(:music_session4) { FactoryGirl.create(:music_session) } describe "validations" do it "genre must be set" do music_session = FactoryGirl.build(:music_session) music_session.genre = nil music_session.save.should be_false music_session.errors[:genre].should == ["can't be blank"] end it "updates the fields of a music session properly" do genre1 = FactoryGirl.create(:genre) genre2 = FactoryGirl.create(:genre) genre3 = FactoryGirl.create(:genre) genre4 = FactoryGirl.create(:genre) creator = FactoryGirl.create(:user) session = FactoryGirl.create(:music_session, :creator => creator, :description => "Session", :genre => genre3) session.update_attributes({:description => "Session2", :genre => genre1}) session.reload session.description.should == "Session2" session.genre.should == genre1 end it "must have legal_terms accepted" do user1 = FactoryGirl.create(:user) music_session = FactoryGirl.build(:music_session, :creator => user1, legal_terms: false) music_session.save music_session.valid?.should be_false music_session.errors["legal_terms"].should == ["is not included in the list"] end it "cannot have profanity in the description" do user1 = FactoryGirl.create(:user) music_session = FactoryGirl.build(:music_session, :creator => user1, legal_terms: false, :description => "fuck you") music_session.save music_session.valid?.should be_false end end describe "nindex" do it "nindex orders two sessions by created_at starting with most recent" do creator = FactoryGirl.create(:user) creator2 = FactoryGirl.create(:user) earlier_session = FactoryGirl.create(:active_music_session, :creator => creator, :description => "Earlier Session") c1 = FactoryGirl.create(:connection, user: creator, music_session: earlier_session, addr: 0x01020304, locidispid: 1) later_session = FactoryGirl.create(:active_music_session, :creator => creator2, :description => "Later Session") c2 = FactoryGirl.create(:connection, user: creator2, music_session: later_session, addr: 0x21020304, locidispid: 2) user = FactoryGirl.create(:user) c3 = FactoryGirl.create(:connection, user: user, locidispid: 3) Score.createx(c1.locidispid, c1.client_id, c1.addr, c3.locidispid, c3.client_id, c3.addr, 20, nil); Score.createx(c2.locidispid, c2.client_id, c2.addr, c3.locidispid, c3.client_id, c3.addr, 30, nil); # scores! #ActiveRecord::Base.logger = Logger.new(STDOUT) music_sessions = ActiveMusicSession.nindex(user, client_id: c3.client_id).take(100) #music_sessions = MusicSession.index(user).take(100) #ActiveRecord::Base.logger = nil music_sessions.length.should == 2 music_sessions[0].id.should == later_session.id music_sessions[1].id.should == earlier_session.id end end it 'uninvited users cant join approval-required sessions without invitation' do user1 = FactoryGirl.create(:user) # in the jam session user2 = FactoryGirl.create(:user) # in the jam session music_session = FactoryGirl.create(:active_music_session, :creator => user1, :musician_access => true, :approval_required => true) connection1 = FactoryGirl.create(:connection, :user => user1, :music_session => music_session) expect { FactoryGirl.create(:connection, :user => user2, :music_session => music_session, :joining_session => true) }.to raise_error(ActiveRecord::RecordInvalid) end it "is_recording? returns false if not recording" do user1 = FactoryGirl.create(:user) music_session = FactoryGirl.build(:active_music_session, :creator => user1) music_session.is_recording?.should be_false end describe "recordings" do before(:each) do @user1 = FactoryGirl.create(:user) @connection = FactoryGirl.create(:connection, :user => @user1) @instrument = FactoryGirl.create(:instrument, :description => 'a great instrument') @track = FactoryGirl.create(:track, :connection => @connection, :instrument => @instrument) @music_session = FactoryGirl.create(:active_music_session, :creator => @user1, :musician_access => true) # @music_session.connections << @connection @music_session.save! @connection.join_the_session(@music_session, true, nil, @user1, 10) end describe "not recording" do it "stop_recording should return nil if not recording" do @music_session.stop_recording.should be_nil end end describe "currently recording" do before(:each) do @recording = FactoryGirl.create(:recording, :music_session => @music_session, :owner => @user1) end it "is_recording? returns true if recording" do @music_session.is_recording?.should be_true end it "stop_recording should return recording object if recording" do @music_session.stop_recording.should == @recording end end describe "claim a recording" do before(:each) do @recording = Recording.start(@music_session, @user1) @recording.errors.any?.should be_false @recording.stop @recording.reload @claimed_recording = @recording.claim(@user1, "name", "description", Genre.first, true) @claimed_recording.errors.any?.should be_false end it "allow a claimed recording to be associated" do @music_session.claimed_recording_start(@user1, @claimed_recording) @music_session.errors.any?.should be_false @music_session.reload @music_session.claimed_recording.should == @claimed_recording @music_session.claimed_recording_initiator.should == @user1 end it "allow a claimed recording to be removed" do @music_session.claimed_recording_start(@user1, @claimed_recording) @music_session.errors.any?.should be_false @music_session.claimed_recording_stop @music_session.errors.any?.should be_false @music_session.reload @music_session.claimed_recording.should be_nil @music_session.claimed_recording_initiator.should be_nil end it "disallow a claimed recording to be started when already started by someone else" do @user2 = FactoryGirl.create(:user) @music_session.claimed_recording_start(@user1, @claimed_recording) @music_session.errors.any?.should be_false @music_session.claimed_recording_start(@user2, @claimed_recording) @music_session.errors.any?.should be_true @music_session.errors[:claimed_recording] == [ValidationMessages::CLAIMED_RECORDING_ALREADY_IN_PROGRESS] end it "allow a claimed recording to be started when already started by self" do @user2 = FactoryGirl.create(:user) @claimed_recording2 = @recording.claim(@user1, "name", "description", Genre.first, true) @music_session.claimed_recording_start(@user1, @claimed_recording) @music_session.errors.any?.should be_false @music_session.claimed_recording_start(@user1, @claimed_recording2) @music_session.errors.any?.should be_false end end end describe "get_connection_ids" do before(:each) do @user1 = FactoryGirl.create(:user) @user2 = FactoryGirl.create(:user) @music_session = FactoryGirl.create(:active_music_session, :creator => @user1, :musician_access => true) @connection1 = FactoryGirl.create(:connection, :user => @user1, :music_session => @music_session, :as_musician => true) @connection2 = FactoryGirl.create(:connection, :user => @user2, :music_session => @music_session, :as_musician => false) end it "get all connections" do @music_session.get_connection_ids().should == [@connection1.client_id, @connection2.client_id] end it "exclude non-musicians" do @music_session.get_connection_ids(as_musician: true).should == [@connection1.client_id] end it "exclude musicians" do @music_session.get_connection_ids(as_musician: false).should == [@connection2.client_id] end it "exclude particular client" do @music_session.get_connection_ids(exclude_client_id: @connection1.client_id).should == [@connection2.client_id] end it "exclude particular client and exclude non-musicians" do @music_session.get_connection_ids(exclude_client_id: @connection2.client_id, as_musician: true).should == [@connection1.client_id] end end describe "scheduled" do it "excludes based on time-range" do session = FactoryGirl.create(:music_session, scheduled_start: Time.now) sessions = MusicSession.scheduled(session.creator) sessions.length.should == 1 session.scheduled_start = 11.hours.ago session.save! sessions = MusicSession.scheduled(session.creator) sessions.length.should == 1 session.scheduled_start = 13.hours.ago session.save! sessions = MusicSession.scheduled(session.creator) sessions.length.should == 0 session.scheduled_start = 13.hours.from_now session.save! sessions = MusicSession.scheduled(session.creator) sessions.length.should == 1 session.scheduled_start = 300.days.from_now session.save! sessions = MusicSession.scheduled(session.creator) sessions.length.should == 1 end end def sms(user, params) ActiveRecord::Base.transaction do return MusicSession.sms_index(user, params) end end describe "sms_index" do describe "simple" do let(:conn) { FactoryGirl.create(:connection, user: creator) } let(:searcher) { FactoryGirl.create(:user) } let(:searcher_conn) { FactoryGirl.create(:connection, user: searcher, ip_address: '2.2.2.2') } let(:default_opts) { {client_id: searcher_conn.client_id} } let(:network_score) { 20 } before(:each) do Score.createx(conn.locidispid, conn.client_id, conn.addr, searcher_conn.locidispid, searcher_conn.client_id, searcher_conn.addr, network_score, nil) end it "no results" do music_sessions, user_scores = sms(searcher, default_opts) music_sessions.length.should == 0 user_scores.length.should == 0 end it "one session with no scheduled_start time" do creator.last_jam_locidispid = conn.locidispid creator.save! music_session = FactoryGirl.create(:music_session, creator: creator, scheduled_start: nil) music_sessions, user_scores = sms(searcher, default_opts) music_sessions.length.should == 1 end it "one session, one RSVP (creator)" do creator.last_jam_locidispid = conn.locidispid creator.save! music_session = FactoryGirl.create(:music_session, creator: creator) music_sessions, user_scores = sms(searcher, default_opts) music_sessions.length.should == 1 music_sessions[0].tag.should == 3 # open session sort music_sessions[0].latency.should == (network_score + searcher.last_jam_audio_latency + creator.last_jam_audio_latency ) / 2 user_scores.length.should == 1 user_scores[creator.id][:latency].should == (network_score + searcher.last_jam_audio_latency + creator.last_jam_audio_latency ) / 2 end it "filters sessions in the past" do music_session = FactoryGirl.create(:music_session, creator: creator) music_sessions, user_scores = sms(searcher, default_opts) music_sessions.length.should == 1 # 15 minutes is the edge of forgiveness music_session.scheduled_start = 16.minutes.ago music_session.save! music_sessions, user_scores = sms(searcher, default_opts) music_sessions.length.should == 0 # this should still fall in time music_session.scheduled_start = 14.minutes.ago music_session.save! music_sessions, user_scores = sms(searcher, default_opts) music_sessions.length.should == 1 end it "one session, one RSVP (creator), one invitation" do creator.last_jam_locidispid = conn.locidispid creator.save! # create an invitee, and friend them with the creator (you have to be friends to send an invite) invitee = FactoryGirl.create(:user, last_jam_audio_latency: 30, last_jam_locidispid: 1) FactoryGirl.create(:friendship, user: creator, friend: invitee) FactoryGirl.create(:friendship, user: invitee, friend: creator) music_session = FactoryGirl.create(:music_session, creator: creator) FactoryGirl.create(:invitation, receiver:invitee, sender:creator, music_session: music_session) # create a score between invitee, and searcher Score.createx(invitee.last_jam_locidispid, 'immaterial', 1, searcher_conn.locidispid, searcher_conn.client_id, searcher_conn.addr, network_score, nil) music_sessions, user_scores = sms(searcher, default_opts) music_sessions.length.should == 1 music_sessions[0].tag.should == 3 # open session sort music_sessions[0].latency.should == (network_score + searcher.last_jam_audio_latency + creator.last_jam_audio_latency ) / 2 user_scores.length.should == 2 # the creator, and the invitee user_scores[creator.id][:latency].should == (network_score + searcher.last_jam_audio_latency + creator.last_jam_audio_latency ) / 2 user_scores[invitee.id][:latency].should == ((network_score + searcher.last_jam_audio_latency + invitee.last_jam_audio_latency ) / 2).ceil #search with the invitee this time. invitee_conn = FactoryGirl.create(:connection, user: invitee, ip_address: '3.3.3.3', locidispid: invitee.last_jam_locidispid) music_sessions, user_scores = sms(invitee, {client_id: invitee_conn.client_id}) music_sessions.length.should == 1 music_sessions[0].tag.should == 2 # invited sort music_sessions[0].latency.should == ((network_score + invitee.last_jam_audio_latency + creator.last_jam_audio_latency ) / 2).ceil user_scores.length.should == 1 # the creator, and the invitee user_scores[creator.id][:latency].should == ((network_score + invitee.last_jam_audio_latency + creator.last_jam_audio_latency ) / 2).ceil end end describe "sorting" do let!(:creator_1) { FactoryGirl.create(:user, last_jam_locidispid: 4, last_jam_audio_latency: 8) } let!(:creator_conn_1) { FactoryGirl.create(:connection, user: creator_1, ip_address: '4.4.4.4', locidispid: 4, addr:4) } let!(:creator_2) { FactoryGirl.create(:user, last_jam_locidispid: 1, last_jam_audio_latency: 10) } let!(:creator_conn_2) { FactoryGirl.create(:connection, user: creator_2, ip_address: '4.4.4.4', locidispid: 1, addr:1) } let!(:creator_3) { FactoryGirl.create(:user, last_jam_locidispid: 2, last_jam_audio_latency: 12) } let!(:creator_conn_3) { FactoryGirl.create(:connection, user: creator_3, ip_address: '5.5.5.5', locidispid: 2, addr:2) } let!(:searcher_1) { FactoryGirl.create(:user, last_jam_locidispid: 5, last_jam_audio_latency: 6) } let!(:searcher_conn_1) { FactoryGirl.create(:connection, user: searcher_1, ip_address: '8.8.8.8', locidispid: 5, addr:5) } let!(:searcher_2) { FactoryGirl.create(:user, last_jam_locidispid: 3, last_jam_audio_latency: 14) } let!(:searcher_conn_2) { FactoryGirl.create(:connection, user: searcher_2, ip_address: '9.9.9.9', locidispid: 3, addr:3) } let!(:music_session_1) { FactoryGirl.create(:music_session, creator: creator_1, genre: Genre.find('african'), language: 'eng', description: "Bunny Jumps") } let!(:music_session_2) { FactoryGirl.create(:music_session, creator: creator_2, genre: Genre.find('ambient'), language: 'spa', description: "Play with us as we jam to beatles and bunnies") } let!(:music_session_3) { FactoryGirl.create(:music_session, creator: creator_3) } let(:good_network_score) { 20 } let(:fair_network_score) { 30 } let(:bad_network_score) { 40 } before(:each) do # add an RSVP for searcher_1 to music_session_1 searcher_rsvp_slot = FactoryGirl.create(:rsvp_slot, music_session: music_session_1, instrument: Instrument.find('piano')) searcher_rsvp_request = FactoryGirl.create(:rsvp_request, user: searcher_1) searcher_rsvp_request_rsvp_slot = FactoryGirl.create(:rsvp_request_rsvp_slot, chosen:true, rsvp_request: searcher_rsvp_request, rsvp_slot: searcher_rsvp_slot) # add an invitation to searcher_1 to music_session_2 FactoryGirl.create(:friendship, user: creator_2, friend: searcher_1) FactoryGirl.create(:friendship, user: searcher_1, friend: creator_2) FactoryGirl.create(:invitation, receiver:searcher_1, sender:creator_2, music_session: music_session_2) end it "searcher_1" do # create a bad score between searcher_1 and creator_1 (but we should still see it sort 1st because it's got an RSVP to the searcher) Score.createx(searcher_conn_1.locidispid, searcher_conn_1.client_id, searcher_conn_1.addr, creator_conn_1.locidispid, creator_conn_1.client_id, creator_conn_1.addr, bad_network_score, nil) # create a fair score between searcher_1 and creator_2 (but we should still see it sort 2st because it's got an invitation to the searcher) Score.createx(searcher_conn_1.locidispid, searcher_conn_1.client_id, searcher_conn_1.addr, creator_conn_2.locidispid, creator_conn_2.client_id, creator_conn_2.addr, fair_network_score, nil) # create a good score between searcher_1 and creator_3 (but we should still see it sort last because it's an open session; no affiliation with the searcher) Score.createx(searcher_conn_1.locidispid, searcher_conn_1.client_id, searcher_conn_1.addr, creator_conn_3.locidispid, creator_conn_3.client_id, creator_conn_3.addr, good_network_score, nil) music_sessions, user_scores = sms(searcher_1, {client_id: searcher_conn_1.client_id}) music_sessions.length.should == 3 music_session = music_sessions[0] music_session.should == music_session_1 music_session.tag.should == 1 # RSVP music_session.latency.should == (bad_network_score + searcher_1.last_jam_audio_latency + creator_1.last_jam_audio_latency ) / 2 music_session = music_sessions[1] music_session.should == music_session_2 music_session.tag.should == 2 # INVITE music_session.latency.should == (fair_network_score + searcher_1.last_jam_audio_latency + creator_2.last_jam_audio_latency ) / 2 music_session = music_sessions[2] music_session.should == music_session_3 music_session.tag.should == 3 # OPEN music_session.latency.should == (good_network_score + searcher_1.last_jam_audio_latency + creator_3.last_jam_audio_latency ) / 2 user_scores.length.should == 3 # the creator, and the invitee user_scores[creator_1.id][:latency].should == (bad_network_score + searcher_1.last_jam_audio_latency + creator_1.last_jam_audio_latency ) / 2 # let's make music_session_3 invisible, and verify the count goes to 2 music_session_3.musician_access = false music_session_3.save! music_sessions, user_scores = sms(searcher_1, {client_id: searcher_conn_1.client_id}) music_sessions.length.should == 2 # let's make music_session_2 invisible, but still the count should be the same (because searcher_1 have an invite) music_session_2.musician_access = false music_session_2.save! music_sessions, user_scores = sms(searcher_1, {client_id: searcher_conn_1.client_id}) music_sessions.length.should == 2 # and lastly with music_session_1, make it invisible, and still it should be visible to the searcher (because searcher_1 has an invite) music_session_1.musician_access = false music_session_1.save! music_sessions, user_scores = sms(searcher_1, {client_id: searcher_conn_1.client_id}) music_sessions.length.should == 2 end end describe "parameters" do let(:creator_1) { FactoryGirl.create(:user, last_jam_locidispid: 4, last_jam_audio_latency: 8) } let(:creator_conn_1) { FactoryGirl.create(:connection, user: creator_1, ip_address: '4.4.4.4', locidispid: 4, addr:4) } let(:creator_2) { FactoryGirl.create(:user, last_jam_locidispid: 1, last_jam_audio_latency: 10) } let(:creator_conn_2) { FactoryGirl.create(:connection, user: creator_2, ip_address: '4.4.4.4', locidispid: 1, addr:1) } let(:creator_3) { FactoryGirl.create(:user, last_jam_locidispid: 2, last_jam_audio_latency: 12) } let(:creator_conn_3) { FactoryGirl.create(:connection, user: creator_3, ip_address: '5.5.5.5', locidispid: 2, addr:2) } let(:searcher_1) { FactoryGirl.create(:user, last_jam_locidispid: 5, last_jam_audio_latency: 6) } let(:searcher_conn_1) { FactoryGirl.create(:connection, user: searcher_1, ip_address: '8.8.8.8', locidispid: 5, addr:5) } let(:searcher_2) { FactoryGirl.create(:user, last_jam_locidispid: 3, last_jam_audio_latency: 14) } let(:searcher_conn_2) { FactoryGirl.create(:connection, user: searcher_2, ip_address: '9.9.9.9', locidispid: 3, addr:3) } let!(:music_session_1) { FactoryGirl.create(:music_session, :creator => creator_1, genre: Genre.find('african'), language: 'eng', description: "Bunny Jumps" ) } let!(:music_session_2) { FactoryGirl.create(:music_session, :creator => creator_2, genre: Genre.find('ambient'), language: 'spa', description: "Play with us as we jam to beatles and bunnies") } let(:good_network_score) { 20 } let(:fair_network_score) { 30 } it "offset/limit" do # set up some scores to control sorting Score.createx(searcher_conn_1.locidispid, searcher_conn_1.client_id, searcher_conn_1.addr, creator_conn_1.locidispid, creator_conn_1.client_id, creator_conn_1.addr, good_network_score, nil) Score.createx(searcher_conn_1.locidispid, searcher_conn_1.client_id, searcher_conn_1.addr, creator_conn_2.locidispid, creator_conn_2.client_id, creator_conn_2.addr, fair_network_score, nil) # verify we can get all 2 sessions music_sessions, user_search = sms(searcher_1, client_id: searcher_conn_1.client_id) music_sessions.length.should == 2 music_sessions[0].should == music_session_1 # grab just the 1st music_sessions, user_search = sms(searcher_1, client_id: searcher_conn_1.client_id, offset:0, limit:1) music_sessions.length.should == 1 music_sessions[0].should == music_session_1 # then the second music_sessions, user_search = sms(searcher_1, client_id: searcher_conn_1.client_id, offset:1, limit:2) music_sessions.length.should == 1 music_sessions[0].should == music_session_2 end it "genre" do # verify we can get all 2 sessions music_sessions, user_search = sms(searcher_1, client_id: searcher_conn_1.client_id) music_sessions.length.should == 2 # get only african music_sessions, user_search = sms(searcher_1, client_id: searcher_conn_1.client_id, genre: 'african') music_sessions.length.should == 1 music_sessions[0].genre.should == Genre.find('african') # get only ambient music_sessions, user_search = sms(searcher_1, client_id: searcher_conn_1.client_id, genre: 'ambient') music_sessions.length.should == 1 music_sessions[0].genre.should == Genre.find('ambient') end it "language" do # verify we can get all 2 sessions music_sessions, user_search = sms(searcher_1, client_id: searcher_conn_1.client_id) music_sessions.length.should == 2 # get only english music_sessions, user_search = sms(searcher_1, client_id: searcher_conn_1.client_id, lang: 'eng') music_sessions.length.should == 1 music_sessions[0].language.should == 'eng' # get only ambient music_sessions, user_search = sms(searcher_1, client_id: searcher_conn_1.client_id, lang: 'spa') music_sessions.length.should == 1 music_sessions[0].language.should == 'spa' end it "keyword" do music_sessions, user_search = sms(searcher_1, client_id: searcher_conn_1.client_id, keyword: 'Jump') music_sessions.length.should == 1 music_sessions[0].should == music_session_1 music_sessions, user_search = sms(searcher_1, client_id: searcher_conn_1.client_id, keyword: 'Bunny') music_sessions.length.should == 2 music_sessions, user_search = sms(searcher_1, client_id: searcher_conn_1.client_id, keyword: 'play') music_sessions.length.should == 1 music_sessions, user_search = sms(searcher_1, client_id: searcher_conn_1.client_id, keyword: 'bun') music_sessions.length.should == 2 end it "date" do music_session_1.scheduled_start = 1.days.ago music_session_1.save! # if no day/timezone_offset specified, then the 15 minute slush rule will still kick in, nixing music_session_1 music_sessions, user_search = sms(searcher_1, client_id: searcher_conn_1.client_id) music_sessions.length.should == 1 music_sessions[0].should == music_session_2 # find today's session music_sessions, user_search = sms(searcher_1, client_id: searcher_conn_1.client_id, day: Date.today.to_s, timezone_offset: DateTime.now.offset.numerator) music_sessions.length.should == 1 music_sessions[0].should == music_session_2 # find yesterday's session... oh wait, you can't find a session for yesterday, because the 15 minute slush rule will still kick in. music_sessions, user_search = sms(searcher_1, client_id: searcher_conn_1.client_id, day: (Date.today - 1).to_s, timezone_offset: DateTime.now.offset.numerator) music_sessions.length.should == 0 # but let's make it tomorrow, so we can test in that direction music_session_1.scheduled_start = 1.day.from_now music_session_1.save! music_sessions, user_search = sms(searcher_1, client_id: searcher_conn_1.client_id, day: (Date.today + 1).to_s, timezone_offset: DateTime.now.offset.numerator) music_sessions.length.should == 1 music_sessions[0].should == music_session_1 end end end end