2023-07-21 21:54:03 +00:00
|
|
|
//
|
|
|
|
// NDBIterTests.swift
|
|
|
|
// damusTests
|
|
|
|
//
|
|
|
|
// Created by William Casarin on 2023-07-21.
|
|
|
|
//
|
|
|
|
|
|
|
|
import XCTest
|
|
|
|
@testable import damus
|
|
|
|
|
2023-09-10 22:50:27 +00:00
|
|
|
func test_ndb_dir() -> String? {
|
|
|
|
do {
|
|
|
|
let fileManager = FileManager.default
|
|
|
|
let tempDir = fileManager.temporaryDirectory.appendingPathComponent(UUID().uuidString)
|
|
|
|
try fileManager.createDirectory(at: tempDir, withIntermediateDirectories: true, attributes: nil)
|
|
|
|
return remove_file_prefix(tempDir.absoluteString)
|
|
|
|
} catch {
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-07-21 21:54:03 +00:00
|
|
|
final class NdbTests: XCTestCase {
|
2023-09-10 22:50:27 +00:00
|
|
|
var db_dir: String = ""
|
2023-07-21 21:54:03 +00:00
|
|
|
|
|
|
|
override func setUpWithError() throws {
|
2023-09-10 22:50:27 +00:00
|
|
|
guard let db = test_ndb_dir() else {
|
|
|
|
XCTFail("Could not create temp directory")
|
|
|
|
return
|
|
|
|
}
|
|
|
|
db_dir = db
|
2023-07-21 21:54:03 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
override func tearDownWithError() throws {
|
|
|
|
// Put teardown code here. This method is called after the invocation of each test method in the class.
|
|
|
|
}
|
|
|
|
|
2023-07-26 15:46:44 +00:00
|
|
|
func test_decode_eose() throws {
|
|
|
|
let json = "[\"EOSE\",\"DC268DBD-55DA-458A-B967-540925AF3497\"]"
|
|
|
|
let resp = decode_nostr_event(txt: json)
|
|
|
|
XCTAssertNotNil(resp)
|
|
|
|
}
|
|
|
|
|
|
|
|
func test_decode_command_result() throws {
|
|
|
|
let json = "[\"OK\",\"b1d8f68d39c07ce5c5ea10c235100d529b2ed2250140b36a35d940b712dc6eff\",true,\"\"]"
|
|
|
|
let resp = decode_nostr_event(txt: json)
|
|
|
|
XCTAssertNotNil(resp)
|
|
|
|
|
|
|
|
}
|
|
|
|
|
2023-08-28 14:52:59 +00:00
|
|
|
func test_profile_creation() {
|
|
|
|
let profile = make_test_profile()
|
|
|
|
XCTAssertEqual(profile.name, "jb55")
|
|
|
|
}
|
|
|
|
|
2023-08-26 01:13:42 +00:00
|
|
|
func test_ndb_init() {
|
|
|
|
|
|
|
|
do {
|
2023-12-04 20:42:45 +00:00
|
|
|
let ndb = Ndb(path: db_dir)!
|
2023-08-26 01:13:42 +00:00
|
|
|
let ok = ndb.process_events(test_wire_events)
|
|
|
|
XCTAssertTrue(ok)
|
|
|
|
}
|
|
|
|
|
|
|
|
do {
|
2023-12-04 20:42:45 +00:00
|
|
|
let ndb = Ndb(path: db_dir)!
|
2023-08-27 03:45:59 +00:00
|
|
|
let id = NoteId(hex: "d12c17bde3094ad32f4ab862a6cc6f5c289cfe7d5802270bdf34904df585f349")!
|
2024-01-10 23:38:21 +00:00
|
|
|
guard let txn = NdbTxn(ndb: ndb) else { return XCTAssert(false) }
|
2023-09-10 22:50:27 +00:00
|
|
|
let note = ndb.lookup_note_with_txn(id: id, txn: txn)
|
2023-08-26 01:13:42 +00:00
|
|
|
XCTAssertNotNil(note)
|
|
|
|
guard let note else { return }
|
2023-08-27 03:45:59 +00:00
|
|
|
let pk = Pubkey(hex: "32e1827635450ebb3c5a7d12c1f8e7b2b514439ac10a67eef3d9fd9c5c68e245")!
|
|
|
|
XCTAssertEqual(note.pubkey, pk)
|
|
|
|
|
2023-09-10 22:50:27 +00:00
|
|
|
let profile = ndb.lookup_profile_with_txn(pk, txn: txn)
|
2023-08-27 03:45:59 +00:00
|
|
|
XCTAssertNotNil(profile)
|
|
|
|
guard let profile else { return }
|
|
|
|
|
2023-08-28 14:52:59 +00:00
|
|
|
XCTAssertEqual(profile.profile?.name, "jb55")
|
2023-09-10 22:50:27 +00:00
|
|
|
XCTAssertEqual(profile.lnurl, nil)
|
2023-08-26 01:13:42 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
2023-12-02 23:05:15 +00:00
|
|
|
func test_ndb_seach() throws {
|
|
|
|
do {
|
2023-12-04 20:42:45 +00:00
|
|
|
let ndb = Ndb(path: db_dir)!
|
2023-12-02 23:05:15 +00:00
|
|
|
let ok = ndb.process_events(test_wire_events)
|
|
|
|
XCTAssertTrue(ok)
|
|
|
|
}
|
|
|
|
|
|
|
|
do {
|
2023-12-04 20:42:45 +00:00
|
|
|
let ndb = Ndb(path: db_dir)!
|
2023-12-02 23:05:15 +00:00
|
|
|
let note_ids = ndb.text_search(query: "barked")
|
|
|
|
XCTAssertEqual(note_ids.count, 1)
|
|
|
|
let expected_note_id = NoteId(hex: "b17a540710fe8495b16bfbaf31c6962c4ba8387f3284a7973ad523988095417e")!
|
2024-01-10 23:38:21 +00:00
|
|
|
let note_id = ndb.lookup_note_by_key(note_ids[0])?.map({ n in n?.id }).value
|
2023-12-02 23:05:15 +00:00
|
|
|
XCTAssertEqual(note_id, .some(expected_note_id))
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-07-21 21:54:03 +00:00
|
|
|
func test_ndb_note() throws {
|
|
|
|
let note = NdbNote.owned_from_json(json: test_contact_list_json)
|
|
|
|
XCTAssertNotNil(note)
|
|
|
|
guard let note else { return }
|
|
|
|
|
2023-07-26 15:46:44 +00:00
|
|
|
let id = NoteId(hex: "20d0ff27d6fcb13de8366328c5b1a7af26bcac07f2e558fbebd5e9242e608c09")!
|
|
|
|
let pubkey = Pubkey(hex: "32e1827635450ebb3c5a7d12c1f8e7b2b514439ac10a67eef3d9fd9c5c68e245")!
|
|
|
|
|
2023-07-25 15:58:06 +00:00
|
|
|
XCTAssertEqual(note.id, id)
|
|
|
|
XCTAssertEqual(note.pubkey, pubkey)
|
2023-07-21 21:54:03 +00:00
|
|
|
|
2023-08-28 14:52:59 +00:00
|
|
|
XCTAssertEqual(note.count, 34328)
|
2023-07-23 00:13:51 +00:00
|
|
|
XCTAssertEqual(note.kind, 3)
|
|
|
|
XCTAssertEqual(note.created_at, 1689904312)
|
2023-07-21 21:54:03 +00:00
|
|
|
|
2023-07-23 18:55:36 +00:00
|
|
|
let expected_count: UInt16 = 786
|
2023-07-24 20:08:18 +00:00
|
|
|
XCTAssertEqual(note.tags.count, expected_count)
|
|
|
|
XCTAssertEqual(note.tags.reduce(0, { sum, _ in sum + 1 }), expected_count)
|
2023-07-23 18:55:36 +00:00
|
|
|
|
|
|
|
var tags = 0
|
|
|
|
var total_count_stored = 0
|
|
|
|
var total_count_iter = 0
|
2023-07-21 21:54:03 +00:00
|
|
|
//let tags = note.tags()
|
2023-07-24 20:08:18 +00:00
|
|
|
for tag in note.tags {
|
2023-07-23 18:55:36 +00:00
|
|
|
total_count_stored += Int(tag.count)
|
|
|
|
|
|
|
|
if tags == 0 || tags == 1 || tags == 2 {
|
|
|
|
XCTAssertEqual(tag.count, 3)
|
|
|
|
}
|
|
|
|
|
|
|
|
if tags == 6 {
|
|
|
|
XCTAssertEqual(tag.count, 2)
|
|
|
|
}
|
|
|
|
|
|
|
|
if tags == 7 {
|
2023-07-25 23:22:25 +00:00
|
|
|
XCTAssertEqual(tag[2].string(), "wss://nostr-pub.wellorder.net")
|
2023-07-23 18:55:36 +00:00
|
|
|
}
|
|
|
|
|
2023-07-21 21:54:03 +00:00
|
|
|
for elem in tag {
|
2023-07-23 18:55:36 +00:00
|
|
|
print("tag[\(tags)][\(elem.index)]")
|
|
|
|
total_count_iter += 1
|
2023-07-21 21:54:03 +00:00
|
|
|
}
|
2023-07-23 18:55:36 +00:00
|
|
|
|
|
|
|
tags += 1
|
2023-07-21 21:54:03 +00:00
|
|
|
}
|
|
|
|
|
2023-07-23 18:55:36 +00:00
|
|
|
XCTAssertEqual(tags, 786)
|
|
|
|
XCTAssertEqual(total_count_stored, total_count_iter)
|
2023-07-21 21:54:03 +00:00
|
|
|
}
|
2023-08-15 21:33:47 +00:00
|
|
|
|
|
|
|
/// Based on https://github.com/damus-io/damus/issues/1468
|
|
|
|
/// Tests whether a JSON with optional escaped slash characters is correctly unescaped (In accordance to https://datatracker.ietf.org/doc/html/rfc8259#section-7)
|
|
|
|
func test_decode_json_with_escaped_slashes() {
|
|
|
|
let testJSONWithEscapedSlashes = "{\"tags\":[],\"pubkey\":\"f8e6c64342f1e052480630e27e1016dce35fc3a614e60434fef4aa2503328ca9\",\"content\":\"https:\\/\\/cdn.nostr.build\\/i\\/5c1d3296f66c2630131bf123106486aeaf051ed8466031c0e0532d70b33cddb2.jpg\",\"created_at\":1691864981,\"kind\":1,\"sig\":\"fc0033aa3d4df50b692a5b346fa816fdded698de2045e36e0642a021391468c44ca69c2471adc7e92088131872d4aaa1e90ea6e1ad97f3cc748f4aed96dfae18\",\"id\":\"e8f6eca3b161abba034dac9a02bb6930ecde9fd2fb5d6c5f22a05526e11382cb\"}"
|
|
|
|
let testNote = NdbNote.owned_from_json(json: testJSONWithEscapedSlashes)!
|
|
|
|
XCTAssertEqual(testNote.content, "https://cdn.nostr.build/i/5c1d3296f66c2630131bf123106486aeaf051ed8466031c0e0532d70b33cddb2.jpg")
|
|
|
|
}
|
2023-12-04 19:52:39 +00:00
|
|
|
|
|
|
|
func test_inherited_transactions() throws {
|
|
|
|
let ndb = Ndb(path: db_dir)!
|
|
|
|
do {
|
2024-01-10 23:38:21 +00:00
|
|
|
guard let txn1 = NdbTxn(ndb: ndb) else { return XCTAssert(false) }
|
|
|
|
|
2023-12-04 19:52:39 +00:00
|
|
|
let ntxn = (Thread.current.threadDictionary.value(forKey: "ndb_txn") as? ndb_txn)!
|
|
|
|
XCTAssertEqual(txn1.txn.lmdb, ntxn.lmdb)
|
|
|
|
XCTAssertEqual(txn1.txn.mdb_txn, ntxn.mdb_txn)
|
|
|
|
|
2024-01-10 23:38:21 +00:00
|
|
|
guard let txn2 = NdbTxn(ndb: ndb) else { return XCTAssert(false) }
|
2023-12-04 19:52:39 +00:00
|
|
|
|
|
|
|
XCTAssertEqual(txn1.inherited, false)
|
|
|
|
XCTAssertEqual(txn2.inherited, true)
|
|
|
|
}
|
|
|
|
|
|
|
|
let ndb_txn = Thread.current.threadDictionary.value(forKey: "ndb_txn")
|
|
|
|
XCTAssertNil(ndb_txn)
|
|
|
|
}
|
2023-07-21 21:54:03 +00:00
|
|
|
|
2023-07-23 18:55:36 +00:00
|
|
|
func test_decode_perf() throws {
|
2023-07-21 21:54:03 +00:00
|
|
|
// This is an example of a performance test case.
|
|
|
|
self.measure {
|
2023-07-23 18:55:36 +00:00
|
|
|
_ = NdbNote.owned_from_json(json: test_contact_list_json)
|
2023-07-21 21:54:03 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-07-24 17:55:34 +00:00
|
|
|
func test_perf_old_decoding() {
|
|
|
|
self.measure {
|
|
|
|
let event = decode_nostr_event_json(test_contact_list_json)
|
|
|
|
XCTAssertNotNil(event)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func test_perf_old_iter() {
|
|
|
|
self.measure {
|
|
|
|
let event = decode_nostr_event_json(test_contact_list_json)
|
|
|
|
XCTAssertNotNil(event)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func longer_iter(_ n: Int = 1000) -> XCTMeasureOptions {
|
|
|
|
let opts = XCTMeasureOptions()
|
|
|
|
opts.iterationCount = n
|
|
|
|
return opts
|
|
|
|
}
|
|
|
|
|
|
|
|
func test_perf_interp_evrefs_old() {
|
|
|
|
guard let event = decode_nostr_event_json(test_reply_json) else {
|
|
|
|
return
|
|
|
|
}
|
|
|
|
self.measure(options: longer_iter()) {
|
2023-08-30 23:22:04 +00:00
|
|
|
let blocks = event.blocks(test_keypair).blocks
|
2023-07-24 17:55:34 +00:00
|
|
|
let xs = interpret_event_refs(blocks: blocks, tags: event.tags)
|
|
|
|
XCTAssertEqual(xs.count, 1)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func test_perf_interp_evrefs_ndb() {
|
|
|
|
guard let note = NdbNote.owned_from_json(json: test_reply_json) else {
|
|
|
|
return
|
|
|
|
}
|
|
|
|
self.measure(options: longer_iter()) {
|
2023-08-30 23:22:04 +00:00
|
|
|
let blocks = note.blocks(test_keypair).blocks
|
2023-07-24 20:08:18 +00:00
|
|
|
let xs = interpret_event_refs_ndb(blocks: blocks, tags: note.tags)
|
2023-07-24 17:55:34 +00:00
|
|
|
XCTAssertEqual(xs.count, 1)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func test_decoded_events_are_equal() {
|
|
|
|
let event = decode_nostr_event_json(test_reply_json)
|
|
|
|
let note = NdbNote.owned_from_json(json: test_reply_json)
|
|
|
|
|
|
|
|
XCTAssertNotNil(note)
|
|
|
|
XCTAssertNotNil(event)
|
|
|
|
guard let note else { return }
|
|
|
|
guard let event else { return }
|
|
|
|
|
|
|
|
XCTAssertEqual(note.content_len, UInt32(event.content.utf8.count))
|
2023-07-25 15:58:06 +00:00
|
|
|
XCTAssertEqual(note.pubkey, event.pubkey)
|
|
|
|
XCTAssertEqual(note.id, event.id)
|
2023-07-24 17:55:34 +00:00
|
|
|
|
2023-08-30 23:22:04 +00:00
|
|
|
let ev_blocks = event.blocks(test_keypair)
|
|
|
|
let note_blocks = note.blocks(test_keypair)
|
2023-07-24 17:55:34 +00:00
|
|
|
|
|
|
|
XCTAssertEqual(ev_blocks, note_blocks)
|
|
|
|
|
|
|
|
let event_refs = interpret_event_refs(blocks: ev_blocks.blocks, tags: event.tags)
|
2023-07-24 20:08:18 +00:00
|
|
|
let note_refs = interpret_event_refs_ndb(blocks: note_blocks.blocks, tags: note.tags)
|
2023-07-24 17:55:34 +00:00
|
|
|
|
|
|
|
XCTAssertEqual(event_refs, note_refs)
|
|
|
|
}
|
|
|
|
|
2023-07-23 18:55:36 +00:00
|
|
|
func test_iteration_perf() throws {
|
|
|
|
guard let note = NdbNote.owned_from_json(json: test_contact_list_json) else {
|
|
|
|
XCTAssert(false)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
2023-07-23 19:21:36 +00:00
|
|
|
|
|
|
|
self.measure {
|
|
|
|
var count = 0
|
|
|
|
var char_count = 0
|
|
|
|
|
2023-07-24 20:08:18 +00:00
|
|
|
for tag in note.tags {
|
2023-07-23 19:21:36 +00:00
|
|
|
for elem in tag {
|
|
|
|
print("iter_elem \(elem.string())")
|
|
|
|
for c in elem {
|
|
|
|
if char_count == 0 {
|
|
|
|
let ac = AsciiCharacter(c)
|
|
|
|
XCTAssertEqual(ac, "p")
|
|
|
|
} else if char_count == 0 {
|
|
|
|
XCTAssertEqual(c, 0x6c)
|
|
|
|
}
|
|
|
|
char_count += 1
|
|
|
|
}
|
2023-07-23 18:55:36 +00:00
|
|
|
}
|
2023-07-23 19:21:36 +00:00
|
|
|
count += 1
|
2023-07-23 18:55:36 +00:00
|
|
|
}
|
2023-07-23 19:21:36 +00:00
|
|
|
|
|
|
|
XCTAssertEqual(count, 786)
|
|
|
|
XCTAssertEqual(char_count, 24370)
|
2023-07-23 18:55:36 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
2023-07-21 21:54:03 +00:00
|
|
|
}
|
2023-07-23 18:55:36 +00:00
|
|
|
|