163 lines
6.6 KiB
Swift
163 lines
6.6 KiB
Swift
//
|
|
// Copyright 2023 Signal Messenger, LLC
|
|
// SPDX-License-Identifier: AGPL-3.0-only
|
|
//
|
|
|
|
import Foundation
|
|
import LibSignalClient
|
|
import XCTest
|
|
|
|
@testable import SignalServiceKit
|
|
|
|
class PhoneNumberChangedMessageInserterTest: XCTestCase {
|
|
func testDidLearnAssociation() {
|
|
let ssaCache = SignalServiceAddressCache()
|
|
|
|
let myAci = Aci.constantForTesting("00000000-0000-4000-8000-000000000000")
|
|
let myPhoneNumber1 = E164("+16505550111")!
|
|
let myPhoneNumber2 = E164("+16505550122")!
|
|
let myAddress1 = ssaCache.makeAddress(serviceId: myAci, phoneNumber: myPhoneNumber1)
|
|
|
|
let aliceAci = Aci.constantForTesting("00000000-0000-4000-8000-00000000000A")
|
|
let alicePhoneNumber1 = E164("+16505550133")!
|
|
let alicePhoneNumber2 = E164("+16505550144")!
|
|
let aliceAddress1 = ssaCache.makeAddress(serviceId: aliceAci, phoneNumber: alicePhoneNumber1)
|
|
|
|
let bobAci = Aci.constantForTesting("00000000-0000-4000-8000-00000000000B")
|
|
let bobPhoneNumber1: E164? = nil
|
|
let bobPhoneNumber2 = E164("+16505550166")!
|
|
let bobPhoneNumber3 = E164("+16505550177")!
|
|
let bobAddress1 = ssaCache.makeAddress(serviceId: bobAci, phoneNumber: bobPhoneNumber1)
|
|
|
|
let groupWithEveryone = TSGroupThread.forUnitTest(groupId: 1, groupMembers: [myAddress1, aliceAddress1, bobAddress1])
|
|
let groupWithoutAlice = TSGroupThread.forUnitTest(groupId: 2, groupMembers: [myAddress1, bobAddress1])
|
|
let groupArchived = TSGroupThread.forUnitTest(groupId: 3, groupMembers: [myAddress1, aliceAddress1, bobAddress1])
|
|
|
|
let myThread = TSContactThread(contactAddress: myAddress1)
|
|
myThread.shouldThreadBeVisible = true
|
|
let aliceThread = TSContactThread(contactAddress: aliceAddress1)
|
|
aliceThread.shouldThreadBeVisible = true
|
|
|
|
let threadStore = MockThreadStore()
|
|
threadStore.insertThreads([groupWithEveryone, groupWithoutAlice, groupArchived, myThread, aliceThread])
|
|
|
|
let mockDB = InMemoryDB()
|
|
|
|
let groupMemberStore = MockGroupMemberStore()
|
|
mockDB.write { tx in
|
|
// Create group members for all of the full members.
|
|
for thread in [groupWithEveryone, groupWithoutAlice, groupArchived] {
|
|
for fullMemberAddress in thread.groupMembership.fullMembers {
|
|
groupMemberStore.insert(
|
|
fullGroupMember: TSGroupMember(
|
|
address: NormalizedDatabaseRecordAddress(address: fullMemberAddress)!,
|
|
groupThreadId: thread.uniqueId,
|
|
lastInteractionTimestamp: 0),
|
|
tx: tx
|
|
)
|
|
}
|
|
}
|
|
}
|
|
|
|
let threadAssociatedDataStore = MockThreadAssociatedDataStore()
|
|
threadAssociatedDataStore.values = Dictionary(uniqueKeysWithValues: threadStore.threads.map {
|
|
($0.uniqueId, ThreadAssociatedData(threadUniqueId: $0.uniqueId))
|
|
})
|
|
threadAssociatedDataStore.values[groupArchived.uniqueId] = ThreadAssociatedData(
|
|
threadUniqueId: groupArchived.uniqueId,
|
|
isArchived: true,
|
|
isMarkedUnread: false,
|
|
mutedUntilTimestamp: 0,
|
|
audioPlaybackRate: 1
|
|
)
|
|
|
|
let interactionStore = MockInteractionStore()
|
|
|
|
let mergeObserver = PhoneNumberChangedMessageInserter(
|
|
groupMemberStore: groupMemberStore,
|
|
interactionStore: interactionStore,
|
|
threadAssociatedDataStore: threadAssociatedDataStore,
|
|
threadStore: threadStore
|
|
)
|
|
|
|
// Alice changes her number.
|
|
interactionStore.insertedInteractions = []
|
|
mockDB.write { tx in
|
|
mergeObserver.didLearnAssociation(
|
|
mergedRecipient: makeRecipient(
|
|
aci: aliceAci,
|
|
oldPhoneNumber: alicePhoneNumber1,
|
|
newPhoneNumber: alicePhoneNumber2,
|
|
isLocalRecipient: false
|
|
),
|
|
tx: tx
|
|
)
|
|
|
|
let threadIds = interactionStore.insertedInteractions.map { $0.uniqueThreadId }
|
|
XCTAssertEqual(Set(threadIds), [groupWithEveryone.uniqueId, aliceThread.uniqueId])
|
|
}
|
|
|
|
// Bob acquires a number for the first time.
|
|
interactionStore.insertedInteractions = []
|
|
mockDB.write { tx in
|
|
mergeObserver.didLearnAssociation(
|
|
mergedRecipient: makeRecipient(
|
|
aci: bobAci,
|
|
oldPhoneNumber: bobPhoneNumber1,
|
|
newPhoneNumber: bobPhoneNumber2,
|
|
isLocalRecipient: false
|
|
),
|
|
tx: tx
|
|
)
|
|
|
|
let threadIds = interactionStore.insertedInteractions.map { $0.uniqueThreadId }
|
|
XCTAssertEqual(Set(threadIds), [])
|
|
}
|
|
|
|
// Bob changes his number.
|
|
interactionStore.insertedInteractions = []
|
|
mockDB.write { tx in
|
|
mergeObserver.didLearnAssociation(
|
|
mergedRecipient: makeRecipient(
|
|
aci: bobAci,
|
|
oldPhoneNumber: bobPhoneNumber2,
|
|
newPhoneNumber: bobPhoneNumber3,
|
|
isLocalRecipient: false
|
|
),
|
|
tx: tx
|
|
)
|
|
|
|
let threadIds = interactionStore.insertedInteractions.map { $0.uniqueThreadId }
|
|
XCTAssertEqual(Set(threadIds), [groupWithEveryone.uniqueId, groupWithoutAlice.uniqueId])
|
|
}
|
|
|
|
// The local user changes their number.
|
|
interactionStore.insertedInteractions = []
|
|
mockDB.write { tx in
|
|
mergeObserver.didLearnAssociation(
|
|
mergedRecipient: makeRecipient(
|
|
aci: myAci,
|
|
oldPhoneNumber: myPhoneNumber1,
|
|
newPhoneNumber: myPhoneNumber2,
|
|
isLocalRecipient: true
|
|
),
|
|
tx: tx
|
|
)
|
|
|
|
let threadIds = interactionStore.insertedInteractions.map { $0.uniqueThreadId }
|
|
XCTAssertEqual(Set(threadIds), [])
|
|
}
|
|
}
|
|
|
|
private func makeRecipient(
|
|
aci: Aci,
|
|
oldPhoneNumber: E164?,
|
|
newPhoneNumber: E164,
|
|
isLocalRecipient: Bool
|
|
) -> MergedRecipient {
|
|
let oldRecipient = SignalRecipient(aci: aci, pni: nil, phoneNumber: oldPhoneNumber)
|
|
let newRecipient = oldRecipient.copyRecipient()
|
|
newRecipient.phoneNumber = .init(stringValue: newPhoneNumber.stringValue, isDiscoverable: true)
|
|
return MergedRecipient(isLocalRecipient: isLocalRecipient, oldRecipient: oldRecipient, newRecipient: newRecipient)
|
|
}
|
|
}
|