mirror of
https://github.com/permissionlesstech/bitchat.git
synced 2026-07-25 17:25:20 +00:00
210 lines
7.3 KiB
Swift
210 lines
7.3 KiB
Swift
import BitFoundation
|
|
import Foundation
|
|
import Testing
|
|
@testable import bitchat
|
|
|
|
struct BLEFanoutSelectorTests {
|
|
@Test
|
|
func directedSendUsesAllNonIngressLinks() {
|
|
let selection = BLEFanoutSelector.selectLinks(
|
|
peripheralIDs: ["p1", "p2"],
|
|
centralIDs: ["c1", "c2"],
|
|
ingressLink: .central("c1"),
|
|
directedPeerHint: PeerID(str: "1122334455667788"),
|
|
packetType: MessageType.noiseEncrypted.rawValue,
|
|
messageID: "message-1"
|
|
)
|
|
|
|
#expect(selection.peripheralIDs == Set(["p1", "p2"]))
|
|
#expect(selection.centralIDs == Set(["c2"]))
|
|
}
|
|
|
|
@Test
|
|
func directedSendUsesOnlyBoundPeripheralLinkWhenAvailable() {
|
|
let target = PeerID(str: "1122334455667788")
|
|
let bystander = PeerID(str: "8877665544332211")
|
|
let selection = BLEFanoutSelector.selectLinks(
|
|
peripheralIDs: ["target-p", "bystander-p"],
|
|
centralIDs: ["target-c", "bystander-c"],
|
|
ingressLink: nil,
|
|
peripheralPeerBindings: [
|
|
"target-p": target,
|
|
"bystander-p": bystander
|
|
],
|
|
centralPeerBindings: [
|
|
"target-c": target,
|
|
"bystander-c": bystander
|
|
],
|
|
directedPeerHint: target,
|
|
packetType: MessageType.courierEnvelope.rawValue,
|
|
messageID: "message-1"
|
|
)
|
|
|
|
#expect(selection.peripheralIDs == Set(["target-p"]))
|
|
#expect(selection.centralIDs.isEmpty)
|
|
}
|
|
|
|
@Test
|
|
func directedSendUsesBoundCentralLinkWhenNoPeripheralLinkExists() {
|
|
let target = PeerID(str: "1122334455667788")
|
|
let bystander = PeerID(str: "8877665544332211")
|
|
let selection = BLEFanoutSelector.selectLinks(
|
|
peripheralIDs: ["bystander-p"],
|
|
centralIDs: ["target-c", "bystander-c"],
|
|
ingressLink: nil,
|
|
peripheralPeerBindings: [
|
|
"bystander-p": bystander
|
|
],
|
|
centralPeerBindings: [
|
|
"target-c": target,
|
|
"bystander-c": bystander
|
|
],
|
|
directedPeerHint: target,
|
|
packetType: MessageType.courierEnvelope.rawValue,
|
|
messageID: "message-1"
|
|
)
|
|
|
|
#expect(selection.peripheralIDs.isEmpty)
|
|
#expect(selection.centralIDs == Set(["target-c"]))
|
|
}
|
|
|
|
@Test
|
|
func directedSendToKnownPeerDoesNotFallBackWhenOnlyDirectLinkIsExcluded() {
|
|
let target = PeerID(str: "1122334455667788")
|
|
let bystander = PeerID(str: "8877665544332211")
|
|
let selection = BLEFanoutSelector.selectLinks(
|
|
peripheralIDs: ["bystander-p"],
|
|
centralIDs: ["target-c", "bystander-c"],
|
|
ingressLink: .central("target-c"),
|
|
peripheralPeerBindings: [
|
|
"bystander-p": bystander
|
|
],
|
|
centralPeerBindings: [
|
|
"target-c": target,
|
|
"bystander-c": bystander
|
|
],
|
|
directedPeerHint: target,
|
|
packetType: MessageType.courierEnvelope.rawValue,
|
|
messageID: "message-1"
|
|
)
|
|
|
|
#expect(selection.peripheralIDs.isEmpty)
|
|
#expect(selection.centralIDs.isEmpty)
|
|
}
|
|
|
|
@Test
|
|
func directedSendExcludesAllLinksToIngressPeer() {
|
|
let selection = BLEFanoutSelector.selectLinks(
|
|
peripheralIDs: ["p1", "p2"],
|
|
centralIDs: ["c1", "c2"],
|
|
ingressLink: .central("c1"),
|
|
excludedLinks: [.peripheral("p2"), .central("c2")],
|
|
directedPeerHint: PeerID(str: "1122334455667788"),
|
|
packetType: MessageType.noiseEncrypted.rawValue,
|
|
messageID: "message-1"
|
|
)
|
|
|
|
#expect(selection.peripheralIDs == Set(["p1"]))
|
|
#expect(selection.centralIDs.isEmpty)
|
|
}
|
|
|
|
@Test
|
|
func controlPacketsUseAllNonIngressLinks() {
|
|
let selection = BLEFanoutSelector.selectLinks(
|
|
peripheralIDs: ["p1", "p2", "p3"],
|
|
centralIDs: ["c1", "c2", "c3"],
|
|
ingressLink: .peripheral("p2"),
|
|
directedPeerHint: nil,
|
|
packetType: MessageType.requestSync.rawValue,
|
|
messageID: "message-1"
|
|
)
|
|
|
|
#expect(selection.peripheralIDs == Set(["p1", "p3"]))
|
|
#expect(selection.centralIDs == Set(["c1", "c2", "c3"]))
|
|
}
|
|
|
|
@Test
|
|
func broadcastPacketsUseDeterministicSubsetAfterIngressExclusion() {
|
|
let peripherals = (1...8).map { "p\($0)" }
|
|
let centrals = (1...8).map { "c\($0)" }
|
|
|
|
let first = BLEFanoutSelector.selectLinks(
|
|
peripheralIDs: peripherals,
|
|
centralIDs: centrals,
|
|
ingressLink: .peripheral("p4"),
|
|
directedPeerHint: nil,
|
|
packetType: MessageType.message.rawValue,
|
|
messageID: "message-1"
|
|
)
|
|
let second = BLEFanoutSelector.selectLinks(
|
|
peripheralIDs: peripherals,
|
|
centralIDs: centrals,
|
|
ingressLink: .peripheral("p4"),
|
|
directedPeerHint: nil,
|
|
packetType: MessageType.message.rawValue,
|
|
messageID: "message-1"
|
|
)
|
|
|
|
#expect(first == second)
|
|
#expect(!first.peripheralIDs.contains("p4"))
|
|
#expect(first.peripheralIDs.count == 4)
|
|
#expect(first.centralIDs.count == 4)
|
|
}
|
|
|
|
@Test
|
|
func dualLinkPeerRelaysOnSingleLinkPreferringPeripheral() {
|
|
// A dual-role pair holds two live links to the same peer; relays must
|
|
// not transmit the same packet down both. The peripheral (write) link
|
|
// wins because it has per-link flow control.
|
|
let peer = PeerID(str: "1122334455667788")
|
|
let selection = BLEFanoutSelector.selectLinks(
|
|
peripheralIDs: ["p1"],
|
|
centralIDs: ["c1"],
|
|
ingressLink: nil,
|
|
peripheralPeerBindings: ["p1": peer],
|
|
centralPeerBindings: ["c1": peer],
|
|
directedPeerHint: nil,
|
|
packetType: MessageType.fragment.rawValue,
|
|
messageID: "message-1"
|
|
)
|
|
|
|
#expect(selection.peripheralIDs == Set(["p1"]))
|
|
#expect(selection.centralIDs.isEmpty)
|
|
}
|
|
|
|
@Test
|
|
func unboundLinksSurviveDuplicatePeerCollapse() {
|
|
// Links whose peer is not yet known (pre-announce) must keep
|
|
// receiving broadcasts alongside a deduplicated bound pair.
|
|
let peer = PeerID(str: "1122334455667788")
|
|
let selection = BLEFanoutSelector.selectLinks(
|
|
peripheralIDs: ["p1"],
|
|
centralIDs: ["c-bound", "c-unbound"],
|
|
ingressLink: nil,
|
|
peripheralPeerBindings: ["p1": peer],
|
|
centralPeerBindings: ["c-bound": peer],
|
|
directedPeerHint: nil,
|
|
packetType: MessageType.fragment.rawValue,
|
|
messageID: "message-1"
|
|
)
|
|
|
|
#expect(selection.peripheralIDs == Set(["p1"]))
|
|
#expect(selection.centralIDs == Set(["c-unbound"]))
|
|
}
|
|
|
|
@Test
|
|
func broadcastWithTwoLinksKeepsBothAfterIngressExclusion() {
|
|
let selection = BLEFanoutSelector.selectLinks(
|
|
peripheralIDs: ["p1", "p2"],
|
|
centralIDs: ["c1", "c2"],
|
|
ingressLink: nil,
|
|
directedPeerHint: nil,
|
|
packetType: MessageType.message.rawValue,
|
|
messageID: "message-1"
|
|
)
|
|
|
|
#expect(selection.peripheralIDs == Set(["p1", "p2"]))
|
|
#expect(selection.centralIDs == Set(["c1", "c2"]))
|
|
}
|
|
}
|