Skip to content

Commit

Permalink
add fork tests to client section
Browse files Browse the repository at this point in the history
  • Loading branch information
cameronvoell committed Dec 13, 2024
1 parent 54c2a4c commit 05f4253
Showing 1 changed file with 206 additions and 2 deletions.
208 changes: 206 additions & 2 deletions example/src/tests/clientTests.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
import { Wallet } from 'ethers'
import RNFS from 'react-native-fs'

import { Test, assert, createClients } from './test-utils'
import { Client } from '../../../src/index'
import { Test, assert, createClients, delayToPropogate } from './test-utils'
import { Client, Group } from '../../../src/index'

Check warning on line 5 in example/src/tests/clientTests.ts

View workflow job for this annotation

GitHub Actions / lint

There should be at least one empty line between import groups
import { DefaultContentTypes } from 'xmtp-react-native-sdk/lib/types/DefaultContentType'

Check warning on line 6 in example/src/tests/clientTests.ts

View workflow job for this annotation

GitHub Actions / lint

`xmtp-react-native-sdk/lib/types/DefaultContentType` import should occur before import of `./test-utils`

export const clientTests: Test[] = []
let counter = 1
Expand All @@ -13,6 +14,209 @@ function test(name: string, perform: () => Promise<boolean>) {
})
}

test('groups cannot fork', async () => {
const [alix, bo, caro] = await createClients(3)
// Create group with 3 users
const { id: groupId } = await alix.conversations.newGroup([
bo.address,
caro.address,
])

const getGroupForClient = async (client: Client) => {
// Always sync the client before getting the group
await client.conversations.sync()
const group = await client.conversations.findGroup(groupId)
assert(group !== undefined, `Group not found for ${client.address}`)
return group as Group<DefaultContentTypes>
}

const syncClientAndGroup = async (client: Client) => {
const group = await getGroupForClient(client)
await group.sync()
}

const addMemberToGroup = async (fromClient: Client, addresses: string[]) => {
await syncClientAndGroup(fromClient)
const group = await getGroupForClient(fromClient)
await group.addMembers(addresses)
await delayToPropogate(500)
}

const removeMemberFromGroup = async (
fromClient: Client,
addresses: string[]
) => {
await syncClientAndGroup(fromClient)
const group = await getGroupForClient(fromClient)
await group.removeMembers(addresses)
await delayToPropogate(500)
}

// Helper to send a message from a bunch of senders and make sure it is received by all receivers
const testMessageSending = async (senderClient: Client, receiver: Client) => {
// for (const senderClient of senders) {
const messageContent = Math.random().toString(36)
await syncClientAndGroup(senderClient)
const senderGroup = await getGroupForClient(senderClient)
await senderGroup.send(messageContent)

await delayToPropogate(500)
await senderGroup.sync()

await syncClientAndGroup(receiver)

const receiverGroupToCheck = await getGroupForClient(receiver)
await receiverGroupToCheck.sync()

const messages = await receiverGroupToCheck.messages({
direction: 'DESCENDING',
})
const lastMessage = messages[0]
// console.log(lastMessage);
console.log(
`${receiverGroupToCheck.client.address} sees ${messages.length} messages in group`
)
assert(
lastMessage !== undefined &&
lastMessage.nativeContent.text === messageContent,
`${receiverGroupToCheck.client.address} should have received the message, FORK? ${lastMessage?.nativeContent.text} !== ${messageContent}`
)
// }
}

console.log('Testing that messages sent by alix are received by bo')
await testMessageSending(alix, bo)
console.log('Alix & Bo are not forked at the beginning')

// Test adding members one by one
// console.log('Testing adding members one by one...')
const newClients = await createClients(2)

// Add back several members
console.log('Adding new members to the group...')
for (const client of newClients) {
console.log(`Adding member ${client.address}...`)
await addMemberToGroup(alix, [client.address])
}
await delayToPropogate()

await alix.conversations.sync()
await syncClientAndGroup(alix)

// NB => if we don't use Promise.all but a loop, we don't get a fork
const REMOVE_MEMBERS_IN_PARALLEL = true
if (REMOVE_MEMBERS_IN_PARALLEL) {
console.log('Removing members in parallel')

await Promise.all(
newClients.map((client) => {
console.log(`Removing member ${client.address}...`)
return removeMemberFromGroup(alix, [client.address])
})
)
} else {
console.log('Removing members one by one')

for (const client of newClients) {
console.log(`Removing member ${client.address}...`)
await removeMemberFromGroup(alix, [client.address])
}
}

await delayToPropogate(1000)

// When forked, it stays forked even if we try 5 times
// but sometimes it is not forked and works 5/5 times
let forkCount = 0
const tryCount = 5
for (let i = 0; i < tryCount; i++) {
console.log(`Checking fork status ${i+1}/${tryCount}`)

Check warning on line 133 in example/src/tests/clientTests.ts

View workflow job for this annotation

GitHub Actions / lint

Replace `+` with `·+·`
try {
await syncClientAndGroup(alix)
await syncClientAndGroup(bo)
await delayToPropogate(500)
await testMessageSending(alix, bo)
console.log('Not forked!')
} catch (e: any) {
console.log('Forked!')
console.log(e)
forkCount++
}
}

assert(forkCount === 0, `Forked ${forkCount}/${tryCount} times`)

return true
})

test('groups cannot fork short version', async () => {
const [alix, bo, new_one, new_two] = await createClients(4)
// Create group with 2 users
const alixGroup = await alix.conversations.newGroup([
bo.address,
new_one.address,
new_two.address,
])

// sync clients
await alix.conversations.sync()
await bo.conversations.sync()
const boGroup: Group<DefaultContentTypes> = (await bo.conversations.findGroup(alixGroup.id))!

Check warning on line 164 in example/src/tests/clientTests.ts

View workflow job for this annotation

GitHub Actions / lint

Replace `alixGroup.id` with `⏎····alixGroup.id⏎··`

// Remove two members in parallel
// NB => if we don't use Promise.all but a loop, we don't get a fork
console.log('*************libxmtp*********************: Removing members in parallel')

Check warning on line 168 in example/src/tests/clientTests.ts

View workflow job for this annotation

GitHub Actions / lint

Replace `'*************libxmtp*********************:·Removing·members·in·parallel'` with `⏎····'*************libxmtp*********************:·Removing·members·in·parallel'⏎··`
await Promise.all([
alixGroup.removeMembers([new_one.address]),
alixGroup.removeMembers([new_two.address])

Check warning on line 171 in example/src/tests/clientTests.ts

View workflow job for this annotation

GitHub Actions / lint

Insert `,`
])

// Helper to send a message from a bunch of senders and make sure it is received by all receivers
const testMessageSending = async (senderGroup: Group<DefaultContentTypes>, receiverGroup: Group<DefaultContentTypes>) => {

Check warning on line 175 in example/src/tests/clientTests.ts

View workflow job for this annotation

GitHub Actions / lint

Replace `senderGroup:·Group<DefaultContentTypes>,·receiverGroup:·Group<DefaultContentTypes>` with `⏎····senderGroup:·Group<DefaultContentTypes>,⏎····receiverGroup:·Group<DefaultContentTypes>⏎··`
const messageContent = Math.random().toString(36)
await senderGroup.sync()
await alixGroup.send(messageContent)

await delayToPropogate(500)
await alixGroup.sync()
await receiverGroup.sync()

const messages = await receiverGroup.messages({
direction: 'DESCENDING',
})
const lastMessage = messages[0]
console.log(
`${receiverGroup.client.address} sees ${messages.length} messages in group`
)
assert(
lastMessage !== undefined &&
lastMessage.nativeContent.text === messageContent,
`${receiverGroup.client.address} should have received the message, FORK? ${lastMessage?.nativeContent.text} !== ${messageContent}`
)
}
// When forked, it stays forked even if we try 5 times
// but sometimes it is not forked and works 5/5 times
let forkCount = 0
const tryCount = 5
for (let i = 0; i < tryCount; i++) {
console.log(`Checking fork status ${i+1}/${tryCount}`)

Check warning on line 202 in example/src/tests/clientTests.ts

View workflow job for this annotation

GitHub Actions / lint

Replace `+` with `·+·`
try {
await alixGroup.sync()
await boGroup.sync()
await delayToPropogate(500)
await testMessageSending(alixGroup, boGroup)
console.log('Not forked!')
} catch (e: any) {
console.log('Forked!')
console.log(e)
forkCount++
}
}
assert(forkCount === 0, `Forked ${forkCount}/${tryCount} times`)

return true
})

test('can make a client', async () => {
// eslint-disable-next-line @typescript-eslint/no-unused-vars
const keyBytes = new Uint8Array([
Expand Down

0 comments on commit 05f4253

Please sign in to comment.