about summary refs log tree commit diff
path: root/spec/lib
diff options
context:
space:
mode:
Diffstat (limited to 'spec/lib')
-rw-r--r--spec/lib/activitypub/activity/create_spec.rb10
-rw-r--r--spec/lib/delivery_failure_tracker_spec.rb71
-rw-r--r--spec/lib/feed_manager_spec.rb109
3 files changed, 187 insertions, 3 deletions
diff --git a/spec/lib/activitypub/activity/create_spec.rb b/spec/lib/activitypub/activity/create_spec.rb
index cdd499150..3c3991c13 100644
--- a/spec/lib/activitypub/activity/create_spec.rb
+++ b/spec/lib/activitypub/activity/create_spec.rb
@@ -290,7 +290,9 @@ RSpec.describe ActivityPub::Activity::Create do
           tag: [
             {
               type: 'Emoji',
-              href: 'http://example.com/emoji.png',
+              icon: {
+                url: 'http://example.com/emoji.png',
+              },
               name: 'tinking',
             },
           ],
@@ -314,7 +316,9 @@ RSpec.describe ActivityPub::Activity::Create do
           tag: [
             {
               type: 'Emoji',
-              href: 'http://example.com/emoji.png',
+              icon: {
+                url: 'http://example.com/emoji.png',
+              },
             },
           ],
         }
@@ -326,7 +330,7 @@ RSpec.describe ActivityPub::Activity::Create do
       end
     end
 
-    context 'with emojis missing href' do
+    context 'with emojis missing icon' do
       let(:object_json) do
         {
           id: 'bar',
diff --git a/spec/lib/delivery_failure_tracker_spec.rb b/spec/lib/delivery_failure_tracker_spec.rb
new file mode 100644
index 000000000..39c8c7aaf
--- /dev/null
+++ b/spec/lib/delivery_failure_tracker_spec.rb
@@ -0,0 +1,71 @@
+# frozen_string_literal: true
+
+require 'rails_helper'
+
+describe DeliveryFailureTracker do
+  subject { described_class.new('http://example.com/inbox') }
+
+  describe '#track_success!' do
+    before do
+      subject.track_failure!
+      subject.track_success!
+    end
+
+    it 'marks URL as available again' do
+      expect(described_class.available?('http://example.com/inbox')).to be true
+    end
+
+    it 'resets days to 0' do
+      expect(subject.days).to be_zero
+    end
+  end
+
+  describe '#track_failure!' do
+    it 'marks URL as unavailable after 7 days of being called' do
+      6.times { |i| Redis.current.sadd('exhausted_deliveries:http://example.com/inbox', i) }
+      subject.track_failure!
+
+      expect(subject.days).to eq 7
+      expect(described_class.unavailable?('http://example.com/inbox')).to be true
+    end
+
+    it 'repeated calls on the same day do not count' do
+      subject.track_failure!
+      subject.track_failure!
+
+      expect(subject.days).to eq 1
+    end
+  end
+
+  describe '.filter' do
+    before do
+      Redis.current.sadd('unavailable_inboxes', 'http://example.com/unavailable/inbox')
+    end
+
+    it 'removes URLs that are unavailable' do
+      result = described_class.filter(['http://example.com/good/inbox', 'http://example.com/unavailable/inbox'])
+
+      expect(result).to include('http://example.com/good/inbox')
+      expect(result).to_not include('http://example.com/unavailable/inbox')
+    end
+  end
+
+  describe '.track_inverse_success!' do
+    let(:from_account) { Fabricate(:account, inbox_url: 'http://example.com/inbox', shared_inbox_url: 'http://example.com/shared/inbox') }
+
+    before do
+      Redis.current.sadd('unavailable_inboxes', 'http://example.com/inbox')
+      Redis.current.sadd('unavailable_inboxes', 'http://example.com/shared/inbox')
+
+      described_class.track_inverse_success!(from_account)
+    end
+
+    it 'marks inbox URL as available again' do
+      expect(described_class.available?('http://example.com/inbox')).to be true
+    end
+
+    it 'marks shared inbox URL as available again' do
+      expect(described_class.available?('http://example.com/shared/inbox')).to be true
+    end
+  end
+end
diff --git a/spec/lib/feed_manager_spec.rb b/spec/lib/feed_manager_spec.rb
index 22439cf35..923894ccb 100644
--- a/spec/lib/feed_manager_spec.rb
+++ b/spec/lib/feed_manager_spec.rb
@@ -1,6 +1,10 @@
 require 'rails_helper'
 
 RSpec.describe FeedManager do
+  it 'tracks at least as many statuses as reblogs' do
+    expect(FeedManager::REBLOG_FALLOFF).to be <= FeedManager::MAX_ITEMS
+  end
+
   describe '#key' do
     subject { FeedManager.instance.key(:home, 1) }
 
@@ -150,5 +154,110 @@ RSpec.describe FeedManager do
 
       expect(Redis.current.zcard("feed:type:#{account.id}")).to eq FeedManager::MAX_ITEMS
     end
+
+    it 'sends push updates for non-home timelines' do
+      account = Fabricate(:account)
+      status = Fabricate(:status)
+      allow(Redis.current).to receive_messages(publish: nil)
+
+      FeedManager.instance.push('type', account, status)
+
+      expect(Redis.current).to have_received(:publish).with("timeline:#{account.id}", any_args).at_least(:once)
+    end
+
+    context 'reblogs' do
+      it 'saves reblogs of unseen statuses' do
+        account = Fabricate(:account)
+        reblogged = Fabricate(:status)
+        reblog = Fabricate(:status, reblog: reblogged)
+
+        expect(FeedManager.instance.push('type', account, reblog)).to be true
+      end
+
+      it 'does not save a new reblog of a recent status' do
+        account = Fabricate(:account)
+        reblogged = Fabricate(:status)
+        reblog = Fabricate(:status, reblog: reblogged)
+
+        FeedManager.instance.push('type', account, reblogged)
+
+        expect(FeedManager.instance.push('type', account, reblog)).to be false
+      end
+
+      it 'saves a new reblog of an old status' do
+        account = Fabricate(:account)
+        reblogged = Fabricate(:status)
+        reblog = Fabricate(:status, reblog: reblogged)
+
+        FeedManager.instance.push('type', account, reblogged)
+
+        # Fill the feed with intervening statuses
+        FeedManager::REBLOG_FALLOFF.times do
+          FeedManager.instance.push('type', account, Fabricate(:status))
+        end
+
+        expect(FeedManager.instance.push('type', account, reblog)).to be true
+      end
+
+      it 'does not save a new reblog of a recently-reblogged status' do
+        account = Fabricate(:account)
+        reblogged = Fabricate(:status)
+        reblogs = 2.times.map { Fabricate(:status, reblog: reblogged) }
+
+        # The first reblog will be accepted
+        FeedManager.instance.push('type', account, reblogs.first)
+
+        # The second reblog should be ignored
+        expect(FeedManager.instance.push('type', account, reblogs.last)).to be false
+      end
+
+      it 'saves a new reblog of a long-ago-reblogged status' do
+        account = Fabricate(:account)
+        reblogged = Fabricate(:status)
+        reblogs = 2.times.map { Fabricate(:status, reblog: reblogged) }
+
+        # The first reblog will be accepted
+        FeedManager.instance.push('type', account, reblogs.first)
+
+        # Fill the feed with intervening statuses
+        FeedManager::REBLOG_FALLOFF.times do
+          FeedManager.instance.push('type', account, Fabricate(:status))
+        end
+
+        # The second reblog should also be accepted
+        expect(FeedManager.instance.push('type', account, reblogs.last)).to be true
+      end
+    end
+  end
+
+  describe '#unpush' do
+    it 'leaves a reblogged status when deleting the reblog' do
+      account = Fabricate(:account)
+      reblogged = Fabricate(:status)
+      status = Fabricate(:status, reblog: reblogged)
+
+      FeedManager.instance.push('type', account, status)
+
+      # The reblogging status should show up under normal conditions.
+      expect(Redis.current.zrange("feed:type:#{account.id}", 0, -1)).to eq [status.id.to_s]
+
+      FeedManager.instance.unpush('type', account, status)
+
+      # Because we couldn't tell if the status showed up any other way,
+      # we had to stick the reblogged status in by itself.
+      expect(Redis.current.zrange("feed:type:#{account.id}", 0, -1)).to eq [reblogged.id.to_s]
+    end
+
+    it 'sends push updates' do
+      account = Fabricate(:account)
+      status = Fabricate(:status)
+      FeedManager.instance.push('type', account, status)
+
+      allow(Redis.current).to receive_messages(publish: nil)
+      FeedManager.instance.unpush('type', account, status)
+
+      deletion = Oj.dump(event: :delete, payload: status.id.to_s)
+      expect(Redis.current).to have_received(:publish).with("timeline:#{account.id}", deletion)
+    end
   end
 end