diff --git a/example/src/TestScreen.tsx b/example/src/TestScreen.tsx index afe520c53..9fc4be99a 100644 --- a/example/src/TestScreen.tsx +++ b/example/src/TestScreen.tsx @@ -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' @@ -108,6 +109,7 @@ export enum TestCategory { group = 'group', restartStreans = 'restartStreams', groupPermissions = 'groupPermissions', + groupPerformance = 'groupPerformance', } export default function TestScreen(): JSX.Element { @@ -121,6 +123,7 @@ export default function TestScreen(): JSX.Element { ...groupTests, ...restartStreamTests, ...groupPermissionsTests, + ...groupPerformanceTests, ] let activeTests, title switch (params.testSelection) { @@ -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' @@ -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 ( diff --git a/example/src/tests/groupPerformanceTests.ts b/example/src/tests/groupPerformanceTests.ts new file mode 100644 index 000000000..7ee2ac8d4 --- /dev/null +++ b/example/src/tests/groupPerformanceTests.ts @@ -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) { + groupPerformanceTests.push({ + name: String(counter++) + '. ' + name, + run: perform, + }) +} + +async function createGroups( + client: Client, + peers: Client[], + numGroups: number, + numMessages: number +): Promise { + 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 +}) diff --git a/example/src/tests/test-utils.ts b/example/src/tests/test-utils.ts index 5a293573f..6d1023938 100644 --- a/example/src/tests/test-utils.ts +++ b/example/src/tests/test-utils.ts @@ -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 @@ -29,13 +29,13 @@ export async function createClients(numClients: number): Promise { 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 } diff --git a/example/src/types/react-native-config.d.ts b/example/src/types/react-native-config.d.ts index 49de92285..cfd3947a9 100644 --- a/example/src/types/react-native-config.d.ts +++ b/example/src/types/react-native-config.d.ts @@ -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