Skip to content

Commit

Permalink
Merge pull request #457 from xmtp/np/performance-benchmarking
Browse files Browse the repository at this point in the history
Performance testing groups
  • Loading branch information
nplasterer authored Sep 11, 2024
2 parents 045ce5b + 9bcba0c commit 5a0c1ca
Show file tree
Hide file tree
Showing 4 changed files with 286 additions and 12 deletions.
11 changes: 7 additions & 4 deletions example/src/TestScreen.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import { useRoute } from '@react-navigation/native'
import React, { useEffect, useState } from 'react'
import { View, Text, Button, ScrollView } from 'react-native'

import { groupPerformanceTests } from './tests/groupPerformanceTests'
import { groupPermissionsTests } from './tests/groupPermissionsTests'
import { groupTests } from './tests/groupTests'
import { restartStreamTests } from './tests/restartStreamsTests'
Expand Down Expand Up @@ -108,6 +109,7 @@ export enum TestCategory {
group = 'group',
restartStreans = 'restartStreams',
groupPermissions = 'groupPermissions',
groupPerformance = 'groupPerformance',
}

export default function TestScreen(): JSX.Element {
Expand All @@ -121,6 +123,7 @@ export default function TestScreen(): JSX.Element {
...groupTests,
...restartStreamTests,
...groupPermissionsTests,
...groupPerformanceTests,
]
let activeTests, title
switch (params.testSelection) {
Expand All @@ -136,10 +139,6 @@ export default function TestScreen(): JSX.Element {
activeTests = groupTests
title = 'Group Unit Tests'
break
case TestCategory.createdAt:
activeTests = createdAtTests
title = 'Created At Unit Tests'
break
case TestCategory.restartStreans:
activeTests = restartStreamTests
title = 'Restart Streams Unit Tests'
Expand All @@ -148,6 +147,10 @@ export default function TestScreen(): JSX.Element {
activeTests = groupPermissionsTests
title = 'Group Permissions Unit Tests'
break
case TestCategory.groupPerformance:
activeTests = groupPerformanceTests
title = 'Group Performance Unit Tests'
break
}

return (
Expand Down
270 changes: 270 additions & 0 deletions example/src/tests/groupPerformanceTests.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,270 @@
/* eslint-disable @typescript-eslint/no-extra-non-null-assertion */
import { Client, Group } from 'xmtp-react-native-sdk'

import { Test, assert, createClients } from './test-utils'

export const groupPerformanceTests: Test[] = []
let counter = 1
function test(name: string, perform: () => Promise<boolean>) {
groupPerformanceTests.push({
name: String(counter++) + '. ' + name,
run: perform,
})
}

async function createGroups(
client: Client,
peers: Client[],
numGroups: number,
numMessages: number
): Promise<Group[]> {
const groups = []
const addresses: string[] = peers.map((client) => client.address)
for (let i = 0; i < numGroups; i++) {
const group = await client.conversations.newGroup(addresses, {
name: `group ${i}`,
imageUrlSquare: `www.group${i}.com`,
description: `group ${i}`,
})
groups.push(group)
for (let i = 0; i < numMessages; i++) {
await group.send({ text: `Alix message ${i}` })
}
}
return groups
}

let alixClient: Client
let boClient: Client
let initialPeers: Client[]
let initialGroups: Group[]

async function beforeAll(
groupSize: number = 1,
groupMessages: number = 1,
peersSize: number = 1
) {
;[alixClient] = await createClients(1)

initialPeers = await createClients(peersSize)
boClient = initialPeers[0]

initialGroups = await createGroups(
alixClient,
initialPeers,
groupSize,
groupMessages
)
}

test('testing large group listings', async () => {
await beforeAll(1000)

let start = Date.now()
let groups = await alixClient.conversations.listGroups()
let end = Date.now()
console.log(`Alix loaded ${groups.length} groups in ${end - start}ms`)
assert(
end - start < 3000,
'listing 1000 groups should take less than a 3 second'
)

start = Date.now()
await alixClient.conversations.syncGroups()
end = Date.now()
console.log(`Alix synced ${groups.length} groups in ${end - start}ms`)
assert(
end - start < 100,
'syncing 1000 cached groups should take less than a .1 second'
)

start = Date.now()
await boClient.conversations.syncGroups()
end = Date.now()
console.log(`Bo synced ${groups.length} groups in ${end - start}ms`)
assert(
end - start < 6000,
'syncing 1000 groups should take less than a 6 second'
)

start = Date.now()
groups = await boClient.conversations.listGroups()
end = Date.now()
console.log(`Bo loaded ${groups.length} groups in ${end - start}ms`)
assert(
end - start < 3000,
'loading 1000 groups should take less than a 3 second'
)

return true
})

test('testing large message listings', async () => {
await beforeAll(1, 2000)

const alixGroup = initialGroups[0]
let start = Date.now()
let messages = await alixGroup.messages()
let end = Date.now()
console.log(`Alix loaded ${messages.length} messages in ${end - start}ms`)
assert(
end - start < 1000,
'listing 2000 self messages should take less than a 1 second'
)

start = Date.now()
await alixGroup.sync()
end = Date.now()
console.log(`Alix synced ${messages.length} messages in ${end - start}ms`)
assert(
end - start < 100,
'syncing 2000 self messages should take less than a .1 second'
)

await boClient.conversations.syncGroups()
const boGroup = await boClient.conversations.findGroup(alixGroup.id)
start = Date.now()
await boGroup!.sync()
end = Date.now()
console.log(`Bo synced ${messages.length} messages in ${end - start}ms`)
assert(
end - start < 3000,
'syncing 2000 messages should take less than a 3 second'
)

start = Date.now()
messages = await boGroup!.messages()
end = Date.now()
console.log(`Bo loaded ${messages.length} messages in ${end - start}ms`)
assert(
end - start < 1000,
'loading 2000 messages should take less than a 1 second'
)

return true
})

test('testing large member listings', async () => {
await beforeAll(1, 1, 50)

const alixGroup = initialGroups[0]
let start = Date.now()
let members = await alixGroup.members
let end = Date.now()
console.log(`Alix loaded ${members.length} members in ${end - start}ms`)
assert(
end - start < 100,
'listing 50 members should take less than a .1 second'
)

start = Date.now()
await alixGroup.sync()
end = Date.now()
console.log(`Alix synced ${members.length} members in ${end - start}ms`)
assert(
end - start < 100,
'syncing 50 members should take less than a .1 second'
)

await boClient.conversations.syncGroups()
const boGroup = await boClient.conversations.findGroup(alixGroup.id)
start = Date.now()
await boGroup!.sync()
end = Date.now()
console.log(`Bo synced ${members.length} members in ${end - start}ms`)
assert(
end - start < 100,
'syncing 50 members should take less than a .1 second'
)

start = Date.now()
members = await boGroup!.members
end = Date.now()
console.log(`Bo loaded ${members.length} members in ${end - start}ms`)
assert(
end - start < 100,
'loading 50 members should take less than a .1 second'
)

const [davonClient] = await createClients(1)

start = Date.now()
await alixGroup.addMembers([davonClient.address])
end = Date.now()
console.log(`Alix added 1 member in ${end - start}ms`)
assert(end - start < 100, 'adding 1 member should take less than a .1 second')

start = Date.now()
members = await alixGroup.members
end = Date.now()
console.log(`Alix loaded ${members.length} members in ${end - start}ms`)
assert(
end - start < 100,
'loading 50 member should take less than a .1 second'
)

start = Date.now()
await boGroup!.sync()
end = Date.now()
console.log(`Bo synced ${members.length} members in ${end - start}ms`)
assert(
end - start < 100,
'syncing 50 member should take less than a .1 second'
)

start = Date.now()
members = await boGroup!.members
end = Date.now()
console.log(`Bo loaded ${members.length} members in ${end - start}ms`)
assert(
end - start < 100,
'loading 50 member should take less than a .1 second'
)

return true
})

test('testing sending message in large group', async () => {
await beforeAll(1, 2000, 100)

const alixGroup = initialGroups[0]
let start = Date.now()
await alixGroup.send({ text: `Alix message` })
let end = Date.now()
console.log(`Alix sent a message in ${end - start}ms`)
assert(
end - start < 200,
'sending a message should take less than a .2 second'
)

await boClient.conversations.syncGroups()
const boGroup = await boClient.conversations.findGroup(alixGroup.id)
start = Date.now()
await boGroup!.prepareMessage({ text: `Bo message` })
end = Date.now()
console.log(`Bo sent a message in ${end - start}ms`)
assert(
end - start < 100,
'preparing a message should take less than a .1 second'
)

start = Date.now()
await boGroup!.sync()
end = Date.now()
console.log(`Bo synced messages in ${end - start}ms`)
assert(
end - start < 9000,
'syncing 2000 messages should take less than a 9 second'
)

start = Date.now()
await boGroup!.send({ text: `Bo message 2` })
end = Date.now()
console.log(`Bo sent a message in ${end - start}ms`)
assert(
end - start < 100,
'sending a message should take less than a .1 second'
)

return true
})
16 changes: 8 additions & 8 deletions example/src/tests/test-utils.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { Platform } from 'expo-modules-core'
import { Client } from 'xmtp-react-native-sdk'
import { Client, GroupUpdatedCodec } from 'xmtp-react-native-sdk'

export type Test = {
name: string
Expand Down Expand Up @@ -29,13 +29,13 @@ export async function createClients(numClients: number): Promise<Client[]> {
166, 83, 208, 224, 254, 44, 205, 227, 175, 49, 234, 129, 74, 252, 135,
145,
])
clients.push(
await Client.createRandom({
env: 'local',
enableV3: true,
dbEncryptionKey: keyBytes,
})
)
const client = await Client.createRandom({
env: 'local',
enableV3: true,
dbEncryptionKey: keyBytes,
})
client.register(new GroupUpdatedCodec())
clients.push(client)
}
return clients
}
1 change: 1 addition & 0 deletions example/src/types/react-native-config.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ declare module 'react-native-config' {
export interface NativeConfig {
THIRD_WEB_CLIENT_ID?: string
TEST_PRIVATE_KEY?: string
TEST_V3_PRIVATE_KEY?: string
}

export const Config: NativeConfig
Expand Down

0 comments on commit 5a0c1ca

Please sign in to comment.