Skip to content

Commit

Permalink
put in place the infrastructure
Browse files Browse the repository at this point in the history
  • Loading branch information
nplasterer committed Nov 26, 2024
1 parent 7dc349f commit 1bf65a9
Show file tree
Hide file tree
Showing 3 changed files with 170 additions and 0 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -1298,6 +1298,54 @@ class XMTPModule : Module() {
}
}
}

// FOR TESTING ONLY
AsyncFunction("createRandomWalletKeyForLocalTesting") Coroutine { ->
withContext(Dispatchers.IO) {
val privateKeyBuilder = PrivateKeyBuilder()
val privateKey = privateKeyBuilder.getPrivateKey().toByteArray()
privateKey.map { it.toInt() and 0xFF }
}
}

AsyncFunction("createForLocalTesting") Coroutine { dbEncryptionKey: List<Int>, authParams: String, walletKey: List<Int>? ->
withContext(Dispatchers.IO) {
logV("createForLocalTesting")
val privateKey = if (walletKey != null) {
val walletKeyBytes = walletKey.foldIndexed(ByteArray(walletKey.size)) { i, a, v ->
a.apply { set(i, v.toByte()) }
}
val pk = PrivateKeyBuilder.buildFromPrivateKeyData(walletKeyBytes)
PrivateKeyBuilder(pk)
} else {
PrivateKeyBuilder()
}

val authOptions = AuthParamsWrapper.authParamsFromJson(authParams)
if (authOptions.environment != "local") throw XMTPException("Only enabled on local")
val options = clientOptions(
dbEncryptionKey,
authParams,
)
val randomClient = Client().create(account = privateKey, options = options)

ContentJson.Companion
clients[randomClient.installationId] = randomClient
clients[randomClient.inboxId] = randomClient
ClientWrapper.encodeToObj(randomClient)
}
}

AsyncFunction("localTestingSyncAllConversations") Coroutine { installationId: String ->
withContext(Dispatchers.IO) {
logV("localTestingSyncAllConversations")
val client = clients[installationId] ?: throw XMTPException("No client")
client.conversations.sync()
val numGroupsSyncedInt: Int =
client.conversations.syncAllConversations().toInt()
numGroupsSyncedInt
}
}
}

//
Expand Down
86 changes: 86 additions & 0 deletions example/src/tests/conversationTests.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,16 @@
import RNFS from 'react-native-fs'

Check warning on line 1 in example/src/tests/conversationTests.ts

View workflow job for this annotation

GitHub Actions / lint

There should be at least one empty line between import groups
import { Test, assert, createClients, delayToPropogate } from './test-utils'
import {

Check warning on line 3 in example/src/tests/conversationTests.ts

View workflow job for this annotation

GitHub Actions / lint

There should be at least one empty line between import groups
Client,

Check warning on line 4 in example/src/tests/conversationTests.ts

View workflow job for this annotation

GitHub Actions / lint

'Client' is defined but never used
ConsentRecord,
Conversation,
ConversationId,
ConversationVersion,
createForLocalTesting,
createRandomWalletKeyForLocalTesting,
localTestingSyncAllConversations,
} from '../../../src/index'
import { Wallet } from 'ethers'

Check warning on line 13 in example/src/tests/conversationTests.ts

View workflow job for this annotation

GitHub Actions / lint

`ethers` import should occur before import of `react-native-fs`

Check warning on line 13 in example/src/tests/conversationTests.ts

View workflow job for this annotation

GitHub Actions / lint

'Wallet' is defined but never used

export const conversationTests: Test[] = []
let counter = 1
Expand Down Expand Up @@ -547,3 +554,82 @@ test('can streamAllMessages from multiple clients - swapped', async () => {

return true
})

test('can sync consent', async () => {
const [bo] = await createClients(1)
const keyBytes = new Uint8Array([
233, 120, 198, 96, 154, 65, 132, 17, 132, 96, 250, 40, 103, 35, 125, 64,
166, 83, 208, 224, 254, 44, 205, 227, 175, 49, 234, 129, 74, 252, 135, 145,
])
// eslint-disable-next-line @typescript-eslint/no-unused-vars
const dbDirPath = `${RNFS.DocumentDirectoryPath}/xmtp_db`
const dbDirPath2 = `${RNFS.DocumentDirectoryPath}/xmtp_db2`
const directoryExists = await RNFS.exists(dbDirPath)
if (!directoryExists) {
await RNFS.mkdir(dbDirPath)
}
const directoryExists2 = await RNFS.exists(dbDirPath2)
if (!directoryExists2) {
await RNFS.mkdir(dbDirPath2)
}
const alixWallet = await createRandomWalletKeyForLocalTesting()

const alix = await createForLocalTesting(
keyBytes,
dbDirPath,
undefined,
alixWallet
)

// Create DM conversation
const dm = await alix.conversations.findOrCreateDm(bo.address)
await dm.updateConsent('denied')
const consentState = await dm.consentState()
assert(consentState === 'denied', `Expected 'denied', got ${consentState}`)

await bo.conversations.sync()
const boDm = await bo.conversations.findConversation(dm.id)

const alix2 = await createForLocalTesting(
keyBytes,
dbDirPath2,
undefined,
alixWallet
)

const state = await alix2.inboxState(true)
assert(
state.installations.length === 2,
`Expected 2 installations, got ${state.installations.length}`
)

// Sync conversations
await bo.conversations.sync()
if (boDm) await boDm.sync()
await localTestingSyncAllConversations(alix.installationId)
await localTestingSyncAllConversations(alix2.installationId)
await alix2.preferences.syncConsent()
await localTestingSyncAllConversations(alix.installationId)
await delayToPropogate(2000)
await localTestingSyncAllConversations(alix2.installationId)
await delayToPropogate(2000)

const dm2 = await alix2.conversations.findConversation(dm.id)
const consentState2 = await dm2?.consentState()
assert(consentState2 === 'denied', `Expected 'denied', got ${consentState2}`)

await alix2.preferences.setConsentState(
new ConsentRecord(dm2!.id, 'conversation_id', 'allowed')
)

const convoState = await alix2.preferences.conversationConsentState(dm2!.id)
assert(convoState === 'allowed', `Expected 'allowed', got ${convoState}`)

const updatedConsentState = await dm2?.consentState()
assert(
updatedConsentState === 'allowed',
`Expected 'allowed', got ${updatedConsentState}`
)

return true
})
36 changes: 36 additions & 0 deletions src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1053,6 +1053,42 @@ export async function exportNativeLogs() {
return XMTPModule.exportNativeLogs()
}

export async function createRandomWalletKeyForLocalTesting(): Promise<Uint8Array> {
const walletKey = await XMTPModule.createRandomWalletKeyForLocalTesting()
return new Uint8Array(walletKey)
}

export async function createForLocalTesting(
dbEncryptionKey: Uint8Array,
dbDirectory?: string | undefined,
historySyncUrl?: string | undefined,
walletKey?: Uint8Array
): Promise<Client<DefaultContentTypes>> {
const authParams: AuthParams = {
environment: 'local',
dbDirectory,
historySyncUrl,
}
const privateKey = walletKey ? Array.from(walletKey) : undefined
const client = await XMTPModule.createForLocalTesting(
Array.from(dbEncryptionKey),
JSON.stringify(authParams),
privateKey
)

return new Client(
client['address'],
client['inboxId'],
client['installationId'],
client['dbPath'],
[]
)
}

export async function localTestingSyncAllConversations(installationId: string) {
return XMTPModule.localTestingSyncAllConversations(installationId)
}

export const emitter = new EventEmitter(XMTPModule ?? NativeModulesProxy.XMTP)

interface AuthParams {
Expand Down

0 comments on commit 1bf65a9

Please sign in to comment.