454 lines
16 KiB
Ruby
454 lines
16 KiB
Ruby
# Copyright (c) 2010-2011, Diaspora Inc. This file is
|
|
# licensed under the Affero General Public License version 3 or later. See
|
|
# the COPYRIGHT file.
|
|
|
|
require 'spec_helper'
|
|
|
|
describe Post, :type => :model do
|
|
before do
|
|
@user = alice
|
|
@aspect = @user.aspects.create(:name => "winners")
|
|
end
|
|
|
|
describe 'scopes' do
|
|
describe '.owned_or_visible_by_user' do
|
|
before do
|
|
@you = bob
|
|
@public_post = FactoryGirl.create(:status_message, :public => true)
|
|
@your_post = FactoryGirl.create(:status_message, :author => @you.person)
|
|
@post_from_contact = eve.post(:status_message, :text => 'wooo', :to => eve.aspects.where(:name => 'generic').first)
|
|
@post_from_stranger = FactoryGirl.create(:status_message, :public => false)
|
|
end
|
|
|
|
it 'returns post from your contacts' do
|
|
expect(StatusMessage.owned_or_visible_by_user(@you)).to include(@post_from_contact)
|
|
end
|
|
|
|
it 'returns your posts' do
|
|
expect(StatusMessage.owned_or_visible_by_user(@you)).to include(@your_post)
|
|
end
|
|
|
|
it 'returns public posts' do
|
|
expect(StatusMessage.owned_or_visible_by_user(@you)).to include(@public_post)
|
|
end
|
|
|
|
it 'returns public post from your contact' do
|
|
sm = FactoryGirl.create(:status_message, :author => eve.person, :public => true)
|
|
|
|
expect(StatusMessage.owned_or_visible_by_user(@you)).to include(sm)
|
|
end
|
|
|
|
it 'does not return non contacts, non-public post' do
|
|
expect(StatusMessage.owned_or_visible_by_user(@you)).not_to include(@post_from_stranger)
|
|
end
|
|
|
|
it 'should return the three visible posts' do
|
|
expect(StatusMessage.owned_or_visible_by_user(@you).count(:all)).to eq(3)
|
|
end
|
|
end
|
|
|
|
|
|
describe '.for_a_stream' do
|
|
it 'calls #for_visible_shareable_sql' do
|
|
time, order = double, double
|
|
expect(Post).to receive(:for_visible_shareable_sql).with(time, order).and_return(Post)
|
|
Post.for_a_stream(time, order)
|
|
end
|
|
|
|
it 'calls includes_for_a_stream' do
|
|
expect(Post).to receive(:includes_for_a_stream)
|
|
Post.for_a_stream(double, double)
|
|
end
|
|
|
|
it 'calls excluding_blocks if a user is present' do
|
|
expect(Post).to receive(:excluding_blocks).with(alice).and_return(Post)
|
|
Post.for_a_stream(double, double, alice)
|
|
end
|
|
end
|
|
|
|
describe '.excluding_blocks' do
|
|
before do
|
|
@post = FactoryGirl.create(:status_message, :author => alice.person)
|
|
@other_post = FactoryGirl.create(:status_message, :author => eve.person)
|
|
|
|
bob.blocks.create(:person => alice.person)
|
|
end
|
|
|
|
it 'does not included blocked users posts' do
|
|
expect(Post.excluding_blocks(bob)).not_to include(@post)
|
|
end
|
|
|
|
it 'includes not blocked users posts' do
|
|
expect(Post.excluding_blocks(bob)).to include(@other_post)
|
|
end
|
|
|
|
it 'returns posts if you dont have any blocks' do
|
|
expect(Post.excluding_blocks(alice).count).to eq(2)
|
|
end
|
|
end
|
|
|
|
describe '.excluding_hidden_shareables' do
|
|
before do
|
|
@post = FactoryGirl.create(:status_message, :author => alice.person)
|
|
@other_post = FactoryGirl.create(:status_message, :author => eve.person)
|
|
bob.toggle_hidden_shareable(@post)
|
|
end
|
|
it 'excludes posts the user has hidden' do
|
|
expect(Post.excluding_hidden_shareables(bob)).not_to include(@post)
|
|
end
|
|
it 'includes posts the user has not hidden' do
|
|
expect(Post.excluding_hidden_shareables(bob)).to include(@other_post)
|
|
end
|
|
end
|
|
|
|
describe '.excluding_hidden_content' do
|
|
it 'calls excluding_blocks and excluding_hidden_shareables' do
|
|
expect(Post).to receive(:excluding_blocks).and_return(Post)
|
|
expect(Post).to receive(:excluding_hidden_shareables)
|
|
Post.excluding_hidden_content(bob)
|
|
end
|
|
end
|
|
|
|
context 'having some posts' do
|
|
before do
|
|
time_interval = 1000
|
|
time_past = 1000000
|
|
@posts = (1..5).map do |n|
|
|
aspect_to_post = alice.aspects.where(:name => "generic").first
|
|
post = alice.post :status_message, :text => "#{alice.username} - #{n}", :to => aspect_to_post.id
|
|
post.created_at = (post.created_at-time_past) - time_interval
|
|
post.updated_at = (post.updated_at-time_past) + time_interval
|
|
post.save
|
|
time_interval += 1000
|
|
post
|
|
end
|
|
end
|
|
|
|
describe '.by_max_time' do
|
|
|
|
it 'returns the posts ordered and limited by unix time' do
|
|
expect(Post.for_a_stream(Time.now + 1, "created_at")).to eq(@posts)
|
|
expect(Post.for_a_stream(Time.now + 1, "updated_at")).to eq(@posts.reverse)
|
|
end
|
|
end
|
|
|
|
|
|
describe '.for_visible_shareable_sql' do
|
|
it 'calls max_time' do
|
|
time = Time.now + 1
|
|
expect(Post).to receive(:by_max_time).with(time, 'created_at').and_return(Post)
|
|
Post.for_visible_shareable_sql(time, 'created_at')
|
|
end
|
|
|
|
it 'defaults to 15 posts' do
|
|
chain = double.as_null_object
|
|
|
|
allow(Post).to receive(:by_max_time).and_return(chain)
|
|
expect(chain).to receive(:limit).with(15).and_return(Post)
|
|
Post.for_visible_shareable_sql(Time.now + 1, "created_at")
|
|
end
|
|
|
|
end
|
|
end
|
|
end
|
|
|
|
describe 'validations' do
|
|
it 'validates uniqueness of guid and does not throw a db error' do
|
|
message = FactoryGirl.create(:status_message)
|
|
expect(FactoryGirl.build(:status_message, :guid => message.guid)).not_to be_valid
|
|
end
|
|
end
|
|
|
|
describe 'post_type' do
|
|
it 'returns the class constant' do
|
|
status_message = FactoryGirl.create(:status_message)
|
|
expect(status_message.post_type).to eq("StatusMessage")
|
|
end
|
|
end
|
|
|
|
describe 'deletion' do
|
|
it 'should delete a posts comments on delete' do
|
|
post = FactoryGirl.create(:status_message, :author => @user.person)
|
|
@user.comment!(post, "hey")
|
|
post.destroy
|
|
expect(Post.where(:id => post.id).empty?).to eq(true)
|
|
expect(Comment.where(:text => "hey").empty?).to eq(true)
|
|
end
|
|
end
|
|
|
|
describe 'serialization' do
|
|
it 'should serialize the handle and not the sender' do
|
|
post = @user.post :status_message, :text => "hello", :to => @aspect.id
|
|
xml = post.to_diaspora_xml
|
|
|
|
expect(xml.include?("person_id")).to be false
|
|
expect(xml.include?(@user.person.diaspora_handle)).to be true
|
|
end
|
|
end
|
|
|
|
describe '.diaspora_initialize' do
|
|
it 'takes provider_display_name' do
|
|
sm = FactoryGirl.create(:status_message, :provider_display_name => 'mobile')
|
|
expect(StatusMessage.diaspora_initialize(sm.attributes.merge(:author => bob.person)).provider_display_name).to eq('mobile')
|
|
end
|
|
end
|
|
|
|
describe '#mutable?' do
|
|
it 'should be false by default' do
|
|
post = @user.post :status_message, :text => "hello", :to => @aspect.id
|
|
expect(post.mutable?).to eq(false)
|
|
end
|
|
end
|
|
|
|
describe '#subscribers' do
|
|
it 'returns the people contained in the aspects the post appears in' do
|
|
post = @user.post :status_message, :text => "hello", :to => @aspect.id
|
|
|
|
expect(post.subscribers(@user)).to eq([])
|
|
end
|
|
|
|
it 'returns all a users contacts if the post is public' do
|
|
post = @user.post :status_message, :text => "hello", :to => @aspect.id, :public => true
|
|
|
|
expect(post.subscribers(@user).to_set).to eq(@user.contact_people.to_set)
|
|
end
|
|
end
|
|
|
|
describe 'Likeable#update_likes_counter' do
|
|
before do
|
|
@post = bob.post :status_message, :text => "hello", :to => 'all'
|
|
bob.like!(@post)
|
|
end
|
|
it 'does not update updated_at' do
|
|
old_time = Time.zone.now - 10000
|
|
Post.where(:id => @post.id).update_all(:updated_at => old_time)
|
|
expect(@post.reload.updated_at.to_i).to eq(old_time.to_i)
|
|
@post.update_likes_counter
|
|
expect(@post.reload.updated_at.to_i).to eq(old_time.to_i)
|
|
end
|
|
end
|
|
|
|
describe "#receive" do
|
|
it "does not receive if the post does not verify" do
|
|
@post = FactoryGirl.create(:status_message, author: bob.person)
|
|
@known_post = FactoryGirl.create(:status_message, author: eve.person)
|
|
allow(@post).to receive(:persisted_shareable).and_return(@known_post)
|
|
expect(@post).not_to receive(:receive_persisted)
|
|
@post.receive(bob, eve.person)
|
|
end
|
|
|
|
it "receives an update if the post is known" do
|
|
@post = FactoryGirl.create(:status_message, author: bob.person)
|
|
expect(@post).to receive(:receive_persisted)
|
|
@post.receive(bob, eve.person)
|
|
end
|
|
|
|
it "receives a new post if the post is unknown" do
|
|
@post = FactoryGirl.create(:status_message, author: bob.person)
|
|
allow(@post).to receive(:persisted_shareable).and_return(nil)
|
|
expect(@post).to receive(:receive_non_persisted)
|
|
@post.receive(bob, eve.person)
|
|
end
|
|
end
|
|
|
|
describe "#receive_persisted" do
|
|
before do
|
|
@post = FactoryGirl.create(:status_message, author: bob.person)
|
|
@known_post = Post.new
|
|
allow(bob).to receive(:contact_for).with(eve.person).and_return(double(receive_shareable: true))
|
|
end
|
|
|
|
context "user knows about the post" do
|
|
before do
|
|
allow(bob).to receive(:find_visible_shareable_by_id).and_return(@known_post)
|
|
end
|
|
|
|
it "updates attributes only if mutable" do
|
|
allow(@known_post).to receive(:mutable?).and_return(true)
|
|
expect(@known_post).to receive(:update_attributes)
|
|
expect(@post.send(:receive_persisted, bob, eve.person, @known_post)).to eq(true)
|
|
end
|
|
|
|
it "does not update attributes if trying to update a non-mutable object" do
|
|
allow(@known_post).to receive(:mutable?).and_return(false)
|
|
expect(@known_post).not_to receive(:update_attributes)
|
|
@post.send(:receive_persisted, bob, eve.person, @known_post)
|
|
end
|
|
end
|
|
|
|
context "the user does not know about the post" do
|
|
before do
|
|
allow(bob).to receive(:find_visible_shareable_by_id).and_return(nil)
|
|
allow(bob).to receive(:notify_if_mentioned).and_return(true)
|
|
end
|
|
|
|
it "receives the post from the contact of the author" do
|
|
expect(@post.send(:receive_persisted, bob, eve.person, @known_post)).to eq(true)
|
|
end
|
|
|
|
it "notifies the user if they are mentioned" do
|
|
allow(bob).to receive(:contact_for).with(eve.person).and_return(double(receive_shareable: true))
|
|
expect(bob).to receive(:notify_if_mentioned).and_return(true)
|
|
|
|
expect(@post.send(:receive_persisted, bob, eve.person, @known_post)).to eq(true)
|
|
end
|
|
end
|
|
end
|
|
|
|
describe "#receive_non_persisted" do
|
|
context "the user does not know about the post" do
|
|
before do
|
|
@post = FactoryGirl.create(:status_message, author: bob.person)
|
|
allow(bob).to receive(:find_visible_shareable_by_id).and_return(nil)
|
|
allow(bob).to receive(:notify_if_mentioned).and_return(true)
|
|
end
|
|
|
|
it "it receives the post from the contact of the author" do
|
|
expect(bob).to receive(:contact_for).with(eve.person).and_return(double(receive_shareable: true))
|
|
expect(@post.send(:receive_non_persisted, bob, eve.person)).to eq(true)
|
|
end
|
|
|
|
it "notifies the user if they are mentioned" do
|
|
allow(bob).to receive(:contact_for).with(eve.person).and_return(double(receive_shareable: true))
|
|
expect(bob).to receive(:notify_if_mentioned).and_return(true)
|
|
|
|
expect(@post.send(:receive_non_persisted, bob, eve.person)).to eq(true)
|
|
end
|
|
|
|
it "does not create shareable visibility if the post does not save" do
|
|
allow(@post).to receive(:save).and_return(false)
|
|
expect(@post).not_to receive(:receive_shareable_visibility)
|
|
@post.send(:receive_non_persisted, bob, eve.person)
|
|
end
|
|
|
|
it "retries if saving fails with RecordNotUnique error" do
|
|
allow(@post).to receive(:save).and_raise(ActiveRecord::RecordNotUnique.new("Duplicate entry ..."))
|
|
expect(bob).to receive(:contact_for).with(eve.person).and_return(double(receive_shareable: true))
|
|
expect(@post.send(:receive_non_persisted, bob, eve.person)).to eq(true)
|
|
end
|
|
|
|
it "retries if saving fails with RecordNotUnique error and raise again if no persisted shareable found" do
|
|
allow(@post).to receive(:save).and_raise(ActiveRecord::RecordNotUnique.new("Duplicate entry ..."))
|
|
allow(@post).to receive(:persisted_shareable).and_return(nil)
|
|
expect(bob).not_to receive(:contact_for).with(eve.person)
|
|
expect { @post.send(:receive_non_persisted, bob, eve.person) }.to raise_error(ActiveRecord::RecordNotUnique)
|
|
end
|
|
end
|
|
end
|
|
|
|
describe "#receive_public" do
|
|
it "saves the post if the post is unknown" do
|
|
@post = FactoryGirl.create(:status_message, author: bob.person)
|
|
allow(@post).to receive(:persisted_shareable).and_return(nil)
|
|
expect(@post).to receive(:save!)
|
|
@post.receive_public
|
|
end
|
|
|
|
it "does not update the post because not mutable" do
|
|
@post = FactoryGirl.create(:status_message, author: bob.person)
|
|
expect(@post).to receive(:update_existing_sharable).and_call_original
|
|
expect(@post).not_to receive(:update_attributes)
|
|
@post.receive_public
|
|
end
|
|
end
|
|
|
|
describe '#reshares_count' do
|
|
before :each do
|
|
@post = @user.post :status_message, :text => "hello", :to => @aspect.id, :public => true
|
|
expect(@post.reshares.size).to eq(0)
|
|
end
|
|
|
|
describe 'when post has not been reshared' do
|
|
it 'returns zero' do
|
|
expect(@post.reshares_count).to eq(0)
|
|
end
|
|
end
|
|
|
|
describe 'when post has been reshared exactly 1 time' do
|
|
before :each do
|
|
expect(@post.reshares.size).to eq(0)
|
|
@reshare = FactoryGirl.create(:reshare, :root => @post)
|
|
@post.reload
|
|
expect(@post.reshares.size).to eq(1)
|
|
end
|
|
|
|
it 'returns 1' do
|
|
expect(@post.reshares_count).to eq(1)
|
|
end
|
|
end
|
|
|
|
describe 'when post has been reshared more than once' do
|
|
before :each do
|
|
expect(@post.reshares.size).to eq(0)
|
|
FactoryGirl.create(:reshare, :root => @post)
|
|
FactoryGirl.create(:reshare, :root => @post)
|
|
FactoryGirl.create(:reshare, :root => @post)
|
|
@post.reload
|
|
expect(@post.reshares.size).to eq(3)
|
|
end
|
|
|
|
it 'returns the number of reshares' do
|
|
expect(@post.reshares_count).to eq(3)
|
|
end
|
|
end
|
|
end
|
|
|
|
describe "#after_create" do
|
|
it "sets #interacted_at" do
|
|
post = FactoryGirl.create(:status_message)
|
|
expect(post.interacted_at).not_to be_blank
|
|
end
|
|
end
|
|
|
|
describe "#find_public" do
|
|
it "succeeds with an id" do
|
|
post = FactoryGirl.create :status_message, public: true
|
|
expect(Post.find_public post.id).to eq(post)
|
|
end
|
|
|
|
it "succeeds with an guid" do
|
|
post = FactoryGirl.create :status_message, public: true
|
|
expect(Post.find_public post.guid).to eq(post)
|
|
end
|
|
|
|
it "raises ActiveRecord::RecordNotFound for a non-existing id without a user" do
|
|
allow(Post).to receive_messages where: double(includes: double(first: nil))
|
|
expect {
|
|
Post.find_public 123
|
|
}.to raise_error ActiveRecord::RecordNotFound
|
|
end
|
|
|
|
it "raises Diaspora::NonPublic for a private post without a user" do
|
|
post = FactoryGirl.create :status_message
|
|
expect {
|
|
Post.find_public post.id
|
|
}.to raise_error Diaspora::NonPublic
|
|
end
|
|
end
|
|
|
|
describe "#find_non_public_by_guid_or_id_with_user" do
|
|
it "succeeds with an id" do
|
|
post = FactoryGirl.create :status_message_in_aspect
|
|
expect(Post.find_non_public_by_guid_or_id_with_user(post.id, post.author.owner)).to eq(post)
|
|
end
|
|
|
|
it "succeeds with an guid" do
|
|
post = FactoryGirl.create :status_message_in_aspect
|
|
expect(Post.find_non_public_by_guid_or_id_with_user(post.guid, post.author.owner)).to eq(post)
|
|
end
|
|
|
|
it "looks up on the passed user object if it's non-nil" do
|
|
post = FactoryGirl.create :status_message
|
|
user = double
|
|
expect(user).to receive(:find_visible_shareable_by_id).with(Post, post.id, key: :id).and_return(post)
|
|
Post.find_non_public_by_guid_or_id_with_user(post.id, user)
|
|
end
|
|
|
|
it "raises ActiveRecord::RecordNotFound with a non-existing id and a user" do
|
|
user = double(find_visible_shareable_by_id: nil)
|
|
expect {
|
|
Post.find_non_public_by_guid_or_id_with_user(123, user)
|
|
}.to raise_error ActiveRecord::RecordNotFound
|
|
end
|
|
end
|
|
end
|