Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Performance tests #472

Merged
merged 4 commits into from
Feb 21, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion Package.swift
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ let package = Package(
.package(url: "https://github.com/bufbuild/connect-swift", exact: "1.0.0"),
.package(url: "https://github.com/apple/swift-docc-plugin.git", from: "1.4.3"),
.package(url: "https://github.com/krzyzanowskim/CryptoSwift.git", exact: "1.8.3"),
.package(url: "https://github.com/xmtp/libxmtp-swift.git", exact: "3.0.27")
.package(url: "https://github.com/xmtp/libxmtp-swift.git", exact: "3.0.28")
],
targets: [
.target(
Expand Down
17 changes: 12 additions & 5 deletions Sources/XMTPTestHelpers/TestHelpers.swift
Original file line number Diff line number Diff line change
Expand Up @@ -68,16 +68,18 @@
public var boClient: Client!
public var caro: PrivateKey!
public var caroClient: Client!
public var davon: PrivateKey!
public var davonClient: Client!

init() async throws {
init(clientOptions: ClientOptions.Api) async throws {
alix = try PrivateKey.generate()
bo = try PrivateKey.generate()
caro = try PrivateKey.generate()
davon = try PrivateKey.generate()

let key = try Crypto.secureRandomBytes(count: 32)
let clientOptions: ClientOptions = ClientOptions(
api: ClientOptions.Api(
env: XMTPEnvironment.local, isSecure: false),
api: clientOptions,
dbEncryptionKey: key
)

Expand All @@ -87,13 +89,18 @@
account: bo, options: clientOptions)
caroClient = try await Client.create(
account: caro, options: clientOptions)
davonClient = try await Client.create(
account: davon, options: clientOptions)
}
}

extension XCTestCase {
@available(iOS 15, *)
public func fixtures() async throws -> Fixtures {
return try await Fixtures()
public func fixtures(
clientOptions: ClientOptions.Api = ClientOptions.Api(
env: XMTPEnvironment.local, isSecure: false)
) async throws -> Fixtures {
return try await Fixtures(clientOptions: clientOptions)
}
}
#endif
78 changes: 2 additions & 76 deletions Sources/XMTPiOS/Client.swift
Original file line number Diff line number Diff line change
Expand Up @@ -108,7 +108,8 @@ public final class Client {
private static let apiCache = ApiClientCache()

public lazy var conversations: Conversations = .init(
client: self, ffiConversations: ffiClient.conversations())
client: self, ffiConversations: ffiClient.conversations(),
ffiClient: ffiClient)
public lazy var preferences: PrivatePreferences = .init(
client: self, ffiClient: ffiClient)

Expand Down Expand Up @@ -506,81 +507,6 @@ public final class Client {
}
}

public func findGroup(groupId: String) throws -> Group? {
do {
return Group(
ffiGroup: try ffiClient.conversation(
conversationId: groupId.hexToData),
client: self)
} catch {
return nil
}
}

public func findConversation(conversationId: String) async throws
-> Conversation?
{
do {
let conversation = try ffiClient.conversation(
conversationId: conversationId.hexToData)
return try await conversation.toConversation(client: self)
} catch {
return nil
}
}

public func findConversationByTopic(topic: String) async throws
-> Conversation?
{
do {
let regexPattern = #"/xmtp/mls/1/g-(.*?)/proto"#
if let regex = try? NSRegularExpression(pattern: regexPattern) {
let range = NSRange(location: 0, length: topic.utf16.count)
if let match = regex.firstMatch(
in: topic, options: [], range: range)
{
let conversationId = (topic as NSString).substring(
with: match.range(at: 1))
let conversation = try ffiClient.conversation(
conversationId: conversationId.hexToData)
return try await conversation.toConversation(client: self)
}
}
} catch {
return nil
}
return nil
}

public func findDmByInboxId(inboxId: String) throws -> Dm? {
do {
let conversation = try ffiClient.dmConversation(
targetInboxId: inboxId)
return Dm(
ffiConversation: conversation, client: self)
} catch {
return nil
}
}

public func findDmByAddress(address: String) async throws -> Dm? {
guard let inboxId = try await inboxIdFromAddress(address: address)
else {
throw ClientError.creationError("No inboxId present")
}
return try findDmByInboxId(inboxId: inboxId)
}

public func findMessage(messageId: String) throws -> Message? {
do {
return Message.create(
ffiMessage: try ffiClient.message(
messageId: messageId.hexToData))
} catch {
return nil
}
}

public func inboxState(refreshFromNetwork: Bool) async throws -> InboxState
{
return InboxState(
Expand Down
83 changes: 82 additions & 1 deletion Sources/XMTPiOS/Conversations.swift
Original file line number Diff line number Diff line change
Expand Up @@ -66,10 +66,91 @@ actor FfiStreamActor {
public actor Conversations {
var client: Client
var ffiConversations: FfiConversations
var ffiClient: FfiXmtpClient

init(client: Client, ffiConversations: FfiConversations) {
init(
client: Client, ffiConversations: FfiConversations,
ffiClient: FfiXmtpClient
) {
self.client = client
self.ffiConversations = ffiConversations
self.ffiClient = ffiClient
}

public func findGroup(groupId: String) throws -> Group? {
do {
return Group(
ffiGroup: try ffiClient.conversation(
conversationId: groupId.hexToData),
client: client)
} catch {
return nil
}
}

public func findConversation(conversationId: String) async throws
-> Conversation?
{
do {
let conversation = try ffiClient.conversation(
conversationId: conversationId.hexToData)
return try await conversation.toConversation(client: client)
} catch {
return nil
}
}

public func findConversationByTopic(topic: String) async throws
-> Conversation?
{
do {
let regexPattern = #"/xmtp/mls/1/g-(.*?)/proto"#
if let regex = try? NSRegularExpression(pattern: regexPattern) {
let range = NSRange(location: 0, length: topic.utf16.count)
if let match = regex.firstMatch(
in: topic, options: [], range: range)
{
let conversationId = (topic as NSString).substring(
with: match.range(at: 1))
let conversation = try ffiClient.conversation(
conversationId: conversationId.hexToData)
return try await conversation.toConversation(client: client)
}
}
} catch {
return nil
}
return nil
}

public func findDmByInboxId(inboxId: String) throws -> Dm? {
do {
let conversation = try ffiClient.dmConversation(
targetInboxId: inboxId)
return Dm(
ffiConversation: conversation, client: client)
} catch {
return nil
}
}

public func findDmByAddress(address: String) async throws -> Dm? {
guard
let inboxId = try await client.inboxIdFromAddress(address: address)
else {
throw ClientError.creationError("No inboxId present")
}
return try findDmByInboxId(inboxId: inboxId)
}

public func findMessage(messageId: String) throws -> Message? {
do {
return Message.create(
ffiMessage: try ffiClient.message(
messageId: messageId.hexToData))
} catch {
return nil
}
}

public func sync() async throws {
Expand Down
88 changes: 0 additions & 88 deletions Tests/XMTPTests/ClientTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -570,92 +570,4 @@ class ClientTests: XCTestCase {
installationId: alixInstallationId
))
}

func testCreatesADevClientPerformance() async throws {
let key = try Crypto.secureRandomBytes(count: 32)
let fakeWallet = try PrivateKey.generate()

// Measure time to create the client
let start = Date()
let client = try await Client.create(
account: fakeWallet,
options: ClientOptions(
api: ClientOptions.Api(env: .dev, isSecure: true),
dbEncryptionKey: key
)
)
let end = Date()
let time1 = end.timeIntervalSince(start)
print("PERF: Created a client in \(time1)s")

// Measure time to build a client
let start2 = Date()
let buildClient1 = try await Client.build(
address: fakeWallet.address,
options: ClientOptions(
api: ClientOptions.Api(env: .dev, isSecure: true),
dbEncryptionKey: key
)
)
let end2 = Date()
let time2 = end2.timeIntervalSince(start2)
print("PERF: Built a client in \(time2)s")

// Measure time to build a client with an inboxId
let start3 = Date()
let buildClient2 = try await Client.build(
address: fakeWallet.address,
options: ClientOptions(
api: ClientOptions.Api(env: .dev, isSecure: true),
dbEncryptionKey: key
),
inboxId: client.inboxID
)
let end3 = Date()
let time3 = end3.timeIntervalSince(start3)
print("PERF: Built a client with inboxId in \(time3)s")

// Measure time to build a client with an inboxId and apiClient
try await Client.connectToApiBackend(
api: ClientOptions.Api(env: .dev, isSecure: true))
let start4 = Date()
try await Client.create(
account: fakeWallet,
options: ClientOptions(
api: ClientOptions.Api(env: .dev, isSecure: true),
dbEncryptionKey: key
)
)
let end4 = Date()
let time4 = end4.timeIntervalSince(start4)
print("PERF: Create a client with prebuild in \(time4)s")

// Assert performance comparisons
XCTAssertTrue(
time2 < time1,
"Building a client should be faster than creating one.")
XCTAssertTrue(
time3 < time1,
"Building a client with inboxId should be faster than creating one."
)
XCTAssertTrue(
time3 < time2,
"Building a client with inboxId should be faster than building one without."
)
XCTAssertTrue(
time4 < time1,
"Creating a client with apiClient should be faster than creating one without."
)

// Assert that inbox IDs match
XCTAssertEqual(
client.inboxID, buildClient1.inboxID,
"Inbox ID of the created client and first built client should match."
)
XCTAssertEqual(
client.inboxID, buildClient2.inboxID,
"Inbox ID of the created client and second built client should match."
)
}

}
Loading
Loading