Skip to content
Extraits de code Groupes Projets
private_spec.rb 11,61 Kio
#   Copyright (c) 2011, Diaspora Inc.  This file is
#   licensed under the Affero General Public License version 3 or later.  See
#   the COPYRIGHT file.

require 'spec_helper'

require File.join(Rails.root, 'lib/postzord/dispatcher/private')

describe Postzord::Dispatcher::Private do
  before do
    @sm = Factory(:status_message, :public => true, :author => alice.person)
    @subscribers = []
    5.times{@subscribers << Factory(:person)}
    @sm.stub(:subscribers).and_return(@subscribers)
    @xml = @sm.to_diaspora_xml
  end

  describe '.initialize' do
    it 'sets @sender, @object, @xml' do
      zord = Postzord::Dispatcher::Private.new(alice, @sm)
      zord.sender.should == alice
      zord.object.should == @sm
      zord.xml.should == @sm.to_diaspora_xml
    end

    context 'setting @subscribers' do 
      it 'sets @subscribers from object' do
        @sm.should_receive(:subscribers).and_return(@subscribers)
        zord = Postzord::Dispatcher::Private.new(alice, @sm)
        zord.subscribers.should == @subscribers
      end

      it 'accepts additional subscribers from opts' do
        new_person = Factory(:person)

        @sm.should_receive(:subscribers).and_return(@subscribers)
        zord = Postzord::Dispatcher::Private.new(alice, @sm, :additional_subscribers => new_person)
        zord.subscribers.should == @subscribers | [new_person]
      end
    end

    it 'raises and gives you a helpful message if the object can not federate' do
      pending "put this in the base class!"
      expect {
        Postzord::Dispatcher::Private.new(alice, [])
      }.should raise_error /Diaspora::Webhooks/
    end
  end

  context 'instance methods' do
    before do
      @subscribers << bob.person
      @remote_people, @local_people = @subscribers.partition{ |person| person.owner_id.nil? }

      @zord = Postzord::Dispatcher::Private.new(alice, @sm)
    end

    describe '#post' do
      before do
        @zord.stub!(:socket_and_notify_users)
      end
      it 'calls Array#partition on subscribers' do
        @zord.instance_variable_set(:@subscribers, @subscribers)
        @subscribers.should_receive(:partition).and_return([@remote_people, @local_people])
        @zord.post
      end

      it 'calls #deliver_to_local with local people' do
        @zord.should_receive(:deliver_to_local).with(@local_people)
        @zord.post
      end

      it 'calls #deliver_to_remote with remote people' do
        @zord.should_receive(:deliver_to_remote).with(@remote_people)
        @zord.post
      end
    end

    context "comments" do
      before do
        @local_luke, @local_leia, @remote_raphael = set_up_friends
      end

      context "local luke's post is commented on by" do
        before do
          @post = @local_luke.post(:status_message, :text => "hello", :to => @local_luke.aspects.first)
        end
        context "local leia" do
          before do
            @comment = @local_leia.build_comment :text => "yo", :post => @post
            @comment.save
          end
          context "local leia's mailman" do
            before do
              @mailman = Postzord::Dispatcher::Private.new(@local_leia, @comment)
            end
            it 'calls deliver_to_local with local_luke' do
              @mailman.should_receive(:deliver_to_local).with([@local_luke.person])
              @mailman.post
            end
            it 'calls deliver_to_remote with nobody' do
              @mailman.should_receive(:deliver_to_remote).with([])
              @mailman.post
            end
            it 'does not call socket_to_users' do
              @mailman.should_not_receive(:socket_to_users)
              @mailman.post
            end
            it 'does not call notify_users' do
              @mailman.should_not_receive(:notify_users)
              @mailman.post
            end
          end
          context "local luke's mailman" do
            before do
              @mailman = Postzord::Dispatcher::Private.new(@local_luke, @comment)
            end
            it 'does not call deliver_to_local' do
              @mailman.should_not_receive(:deliver_to_local)
              @mailman.post
            end
            it 'calls deliver_to_remote with remote raphael' do
              @mailman.should_receive(:deliver_to_remote).with([@remote_raphael])
              @mailman.post
            end
            it 'calls socket_to_users' do
              @mailman.should_receive(:socket_to_users).with([@local_leia, @local_luke])
              @mailman.post
            end
            it 'calls notify_users' do
              @mailman.should_receive(:notify_users).with([@local_leia])
              @mailman.post
            end
          end
        end

        context "remote raphael" do
          before do
            @comment = Factory.build(:comment, :author => @remote_raphael, :post => @post)
            @comment.save
            @mailman = Postzord::Dispatcher::Private.new(@local_luke, @comment)
          end

          it 'does not call deliver_to_local' do
            @mailman.should_not_receive(:deliver_to_local)
            @mailman.post
          end

          it 'calls deliver_to_remote with remote_raphael' do
            @mailman.should_receive(:deliver_to_remote).with([@remote_raphael])
            @mailman.post
          end

          it 'calls socket_to_users' do
            @mailman.should_receive(:socket_to_users).with([@local_leia])
            @mailman.post
          end

          it 'calls notify_users' do
            @mailman.should_receive(:notify_users).with([@local_leia])
            @mailman.post
          end
        end

        context "local luke" do
          before do
            @comment = @local_luke.build_comment :text => "yo", :post => @post
            @comment.save
            @mailman = Postzord::Dispatcher::Private.new(@local_luke, @comment)
          end

          it 'does not call deliver_to_local' do
            @mailman.should_not_receive(:deliver_to_local)
            @mailman.post
          end

          it 'calls deliver_to_remote with remote_raphael' do
            @mailman.should_receive(:deliver_to_remote).with([@remote_raphael])
            @mailman.post
          end

          it 'calls socket_to_users' do
            @mailman.should_receive(:socket_to_users).with([@local_leia, @local_luke])
            @mailman.post
          end

          it 'calls notify_users' do
            @mailman.should_receive(:notify_users).with([@local_leia])
            @mailman.post
          end
        end
      end

      context "remote raphael's post is commented on by local luke" do
        before do
          @post = Factory(:status_message, :author => @remote_raphael)
          @comment = @local_luke.build_comment :text => "yo", :post => @post
          @comment.save
          @mailman = Postzord::Dispatcher::Private.new(@local_luke, @comment)
        end

        it 'calls deliver_to_remote with remote_raphael' do
          @mailman.should_receive(:deliver_to_remote).with([@remote_raphael])
          @mailman.post
        end

        it 'calls deliver_to_local with nobody' do
          @mailman.should_receive(:deliver_to_local).with([])
          @mailman.post
        end

        it 'does not call socket_to_users' do
          @mailman.should_not_receive(:socket_to_users)
          @mailman.post
        end

        it 'does not call notify_users' do
          @mailman.should_not_receive(:notify_users)
          @mailman.post
        end
      end
    end

    describe '#deliver_to_remote' do
      before do
        @remote_people = []
        @remote_people << alice.person
        @mailman = Postzord::Dispatcher::Private.new(alice, @sm)
        @hydra = mock()
        Typhoeus::Hydra.stub!(:new).and_return(@hydra)
      end

      it 'should queue an HttpPost job for each remote person' do
        Resque.should_receive(:enqueue).with(Job::HttpMulti, alice.id, anything, @remote_people.map{|p| p.id}).once
        @mailman.send(:deliver_to_remote, @remote_people)
      end
    end

    describe '#deliver_to_local' do
      before do
        @mailman = Postzord::Dispatcher::Private.new(alice, @sm)
      end

      it 'queues a batch receive' do
        local_people = []
        local_people << alice.person
        Resque.should_receive(:enqueue).with(Job::ReceiveLocalBatch, @sm.id, [alice.id]).once
        @mailman.send(:deliver_to_local, local_people)
      end

      it 'returns if people are empty' do
        Resque.should_not_receive(:enqueue)
        @mailman.send(:deliver_to_local, [])
      end

      it 'returns if the object is a profile' do
        @mailman.instance_variable_set(:@object, Profile.new)
        Resque.should_not_receive(:enqueue)
        @mailman.send(:deliver_to_local, [1])
      end
    end

    describe '#deliver_to_services' do
      before do
        alice.aspects.create(:name => "whatever")
        @service = Services::Facebook.new(:access_token => "yeah")
        alice.services << @service
      end

      it 'queues a job to notify the hub' do
        Resque.stub!(:enqueue).with(Job::PostToService, anything, anything, anything)
        Resque.should_receive(:enqueue).with(Job::PublishToHub, alice.public_url)
        @zord.send(:deliver_to_services, nil, [])
      end

      it 'does not push to hub for non-public posts' do
       @sm     = Factory(:status_message)
       mailman = Postzord::Dispatcher::Private.new(alice, @sm)

       mailman.should_not_receive(:deliver_to_hub)
       mailman.post(:url => "http://joindiaspora.com/p/123")
      end

      it 'only pushes to specified services' do
       @s1 = Factory.create(:service, :user_id => alice.id)
       alice.services << @s1
       @s2 = Factory.create(:service, :user_id => alice.id)
       alice.services << @s2
       mailman = Postzord::Dispatcher::Private.new(alice, Factory(:status_message))

       Resque.stub!(:enqueue).with(Job::PublishToHub, anything)
       Resque.stub!(:enqueue).with(Job::HttpMulti, anything, anything, anything)
       Resque.should_receive(:enqueue).with(Job::PostToService, @s1.id, anything, anything)
       mailman.post(:url => "http://joindiaspora.com/p/123", :services => [@s1])
      end

      it 'does not push to services if none are specified' do
       mailman = Postzord::Dispatcher::Private.new(alice, Factory(:status_message))

       Resque.stub!(:enqueue).with(Job::PublishToHub, anything)
       Resque.should_not_receive(:enqueue).with(Job::PostToService, anything, anything, anything)
       mailman.post(:url => "http://joindiaspora.com/p/123")
      end
    end

    describe '#socket_and_notify_users' do
      it 'should call object#socket_to_user for each local user' do
        sc = mock()
        SocketsController.should_receive(:new).and_return(sc)
        sc.should_receive(:outgoing).with(bob,
                                          @zord.instance_variable_get(:@object),
                                          :aspect_ids => bob.contact_for(alice.person).aspect_memberships.map{|a| postgres? ? a.aspect_id.to_s : a.aspect_id })
        @zord.send(:socket_and_notify_users, [bob])
      end

      it 'only tries to socket when the object responds to #socket_to_user' do
        f = Request.new
        f.stub!(:subscribers)
        f.stub!(:to_diaspora_xml)
        users = [bob]
        z = Postzord::Dispatcher::Private.new(alice, f)
        z.instance_variable_get(:@object).should_receive(:socket_to_user).once
        z.send(:socket_to_users, users)
      end

      it 'queues Job::NotifyLocalUsers jobs' do
        @zord.instance_variable_get(:@object).should_receive(:socket_to_user).and_return(false)
        Resque.should_receive(:enqueue).with(Job::NotifyLocalUsers, [bob.id], @sm.class.to_s, @sm.id, @sm.author.id)
        @zord.send(:socket_and_notify_users, [bob])
      end
    end
  end
end