Files
damus/damusTests/NostrFilterTests.swift
Daniel D’Aquino 46185c55d1 Chunk home filters to avoid hitting max filter item limits
When a user is following several accounts, they may get a stale feed
caused by the subscription request being rejected by relays (due to max filter item limits).

This commit implements a fix that gets around the issue by
creating several chunked filters for the home feed event and contact
metadata subscriptions.

This is a short to medium-term practical fix, where we get around the
practical limitations imposed by most relays. In the future we should
work on longer-term solutions, which will likely require protocol improvements

Main Test
---------

Procedure:
1. Login with Elsat's npub (Or some account that follows about 2K people)
2. Check the home feed. There should be fresh notes.

REPRO:
Device: iPhone 15 simulator
iOS: 17.4
Damus: 1.9 (3) (0d9954290a)
Results:
- No fresh notes, most recent post is from several hours ago (Feed is stale)

FIX TEST:
Device: iPhone 15 simulator
iOS: 17.4
Damus: This commit
Results:
- Fresh notes appear, most recent post is from a few seconds ago.

Other testing:
--------------

- New automated test passing
- All other automated tests passing
- Tested scrolling down the feed on these conditions:
  - Device: iPhone 13 Mini
  - iOS: 17.4.1
  - Accounts:
    - One with about 160 contacts and 10 relays (Daniel D’Aquino)
    - One with about 1K+ contacts and 9 relays (Freedom Smuggler)
    - One with about 981 contacts and 6 relays (jb55)
    - Elsat's account (2K+ accounts and 8 relays)
  - Result: None of those were stale

Changelog-Fixed: Fix stale feed issue when follow list is too big
Closes: https://github.com/damus-io/damus/issues/2194
Signed-off-by: Daniel D’Aquino <daniel@daquino.me>
Reviewed-by: William Casarin <jb55@jb55.com>
2024-05-13 10:56:15 -07:00

78 lines
4.8 KiB
Swift
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
//
// NostrFilterTests.swift
// damusTests
//
// Created by Daniel DAquino on 2024-05-10.
//
import XCTest
@testable import damus
final class NostrFilterTests: XCTestCase {
func testChunkedWithPubKeys() {
// Given a NostrFilter with a list of pubkeys
let test_pubkey_1 = Pubkey(hex: "760f108754eb415561239d4079e71766d87e23f7e71c8e5b00d759e54dd8d082")!
let test_pubkey_2 = Pubkey(hex: "065eab63e939ea2f2f72f2305886b13e5e301302da67b5fe8a18022b278fe872")!
let test_pubkey_3 = Pubkey(hex: "aa146d7c6618ebe993702a74c561f54fc046c8a16e388b828cb2f631a1ed9602")!
let test_pubkey_4 = Pubkey(hex: "2f7108dcd33fb484be3e09cea24a1e96868fbc0842e691ca19db63781801089e")!
let test_pubkey_5 = Pubkey(hex: "1cc7c458e6b565a856d7c3791f4eb5ca5890b1f2433f452ed7a917f9aa0e5250")!
let test_pubkey_6 = Pubkey(hex: "2ee1f46a847b6613c33fd766db1e64c7f727c63774fa3ee952261d2c03b81cf2")!
let test_pubkey_7 = Pubkey(hex: "214664a7ca3236b9dd5f76550d322f390fd70cc12908a2e3ff2cdf50085d4ef2")!
let test_pubkey_8 = Pubkey(hex: "40255b02f3d8ccd6178d50f5ce1c1ac2867b3d919832176957b021c1816fce2f")!
let pubkeys: [Pubkey] = [test_pubkey_1, test_pubkey_2, test_pubkey_3, test_pubkey_4]
let authors: [Pubkey] = [test_pubkey_5, test_pubkey_6, test_pubkey_7, test_pubkey_8]
let filter = NostrFilter(
pubkeys: pubkeys,
authors: authors
)
let chunked_pubkeys_filters_size_2 = filter.chunked(on: .pubkeys, into: 2)
XCTAssertEqual(chunked_pubkeys_filters_size_2.count, 2)
XCTAssertEqual(chunked_pubkeys_filters_size_2[0].pubkeys, [test_pubkey_1, test_pubkey_2])
XCTAssertEqual(chunked_pubkeys_filters_size_2[1].pubkeys, [test_pubkey_3, test_pubkey_4])
XCTAssertEqual(chunked_pubkeys_filters_size_2[0].authors, authors)
XCTAssertEqual(chunked_pubkeys_filters_size_2[1].authors, authors)
let chunked_pubkeys_filters_size_3 = filter.chunked(on: .pubkeys, into: 3)
XCTAssertEqual(chunked_pubkeys_filters_size_3.count, 2)
XCTAssertEqual(chunked_pubkeys_filters_size_3[0].pubkeys, [test_pubkey_1, test_pubkey_2, test_pubkey_3])
XCTAssertEqual(chunked_pubkeys_filters_size_3[1].pubkeys, [test_pubkey_4])
XCTAssertEqual(chunked_pubkeys_filters_size_3[0].authors, authors)
XCTAssertEqual(chunked_pubkeys_filters_size_3[1].authors, authors)
let chunked_pubkeys_filters_size_4 = filter.chunked(on: .pubkeys, into: 4)
XCTAssertEqual(chunked_pubkeys_filters_size_4.count, 1)
XCTAssertEqual(chunked_pubkeys_filters_size_4[0].pubkeys, [test_pubkey_1, test_pubkey_2, test_pubkey_3, test_pubkey_4])
XCTAssertEqual(chunked_pubkeys_filters_size_4[0].authors, authors)
let chunked_pubkeys_filters_size_5 = filter.chunked(on: .pubkeys, into: 5)
XCTAssertEqual(chunked_pubkeys_filters_size_5.count, 1)
XCTAssertEqual(chunked_pubkeys_filters_size_5[0].pubkeys, [test_pubkey_1, test_pubkey_2, test_pubkey_3, test_pubkey_4])
XCTAssertEqual(chunked_pubkeys_filters_size_5[0].authors, authors)
let chunked_authors_filters_size_2 = filter.chunked(on: .authors, into: 2)
XCTAssertEqual(chunked_authors_filters_size_2.count, 2)
XCTAssertEqual(chunked_authors_filters_size_2[0].authors, [test_pubkey_5, test_pubkey_6])
XCTAssertEqual(chunked_authors_filters_size_2[1].authors, [test_pubkey_7, test_pubkey_8])
XCTAssertEqual(chunked_authors_filters_size_2[0].pubkeys, pubkeys)
XCTAssertEqual(chunked_authors_filters_size_2[1].pubkeys, pubkeys)
let chunked_authors_filters_size_3 = filter.chunked(on: .authors, into: 3)
XCTAssertEqual(chunked_authors_filters_size_3.count, 2)
XCTAssertEqual(chunked_authors_filters_size_3[0].authors, [test_pubkey_5, test_pubkey_6, test_pubkey_7])
XCTAssertEqual(chunked_authors_filters_size_3[1].authors, [test_pubkey_8])
XCTAssertEqual(chunked_authors_filters_size_3[0].pubkeys, pubkeys)
XCTAssertEqual(chunked_authors_filters_size_3[1].pubkeys, pubkeys)
let chunked_authors_filters_size_4 = filter.chunked(on: .authors, into: 4)
XCTAssertEqual(chunked_authors_filters_size_4.count, 1)
XCTAssertEqual(chunked_authors_filters_size_4[0].authors, [test_pubkey_5, test_pubkey_6, test_pubkey_7, test_pubkey_8])
XCTAssertEqual(chunked_authors_filters_size_4[0].pubkeys, pubkeys)
let chunked_authors_filters_size_5 = filter.chunked(on: .authors, into: 5)
XCTAssertEqual(chunked_authors_filters_size_5.count, 1)
XCTAssertEqual(chunked_authors_filters_size_5[0].authors, [test_pubkey_5, test_pubkey_6, test_pubkey_7, test_pubkey_8])
XCTAssertEqual(chunked_authors_filters_size_5[0].pubkeys, pubkeys)
}
}