-
Notifications
You must be signed in to change notification settings - Fork 13
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
7e53138
commit 1950c39
Showing
6 changed files
with
1,557 additions
and
388 deletions.
There are no files selected for viewing
382 changes: 382 additions & 0 deletions
382
library/src/androidTest/java/org/xmtp/android/library/DmTest.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,382 @@ | ||
package org.xmtp.android.library | ||
|
||
import androidx.test.ext.junit.runners.AndroidJUnit4 | ||
import androidx.test.platform.app.InstrumentationRegistry | ||
import app.cash.turbine.test | ||
import kotlinx.coroutines.CoroutineScope | ||
import kotlinx.coroutines.Dispatchers | ||
import kotlinx.coroutines.launch | ||
import kotlinx.coroutines.runBlocking | ||
import org.junit.Assert.assertEquals | ||
import org.junit.Assert.assertThrows | ||
import org.junit.Before | ||
import org.junit.Test | ||
import org.junit.runner.RunWith | ||
import org.xmtp.android.library.codecs.ContentTypeReaction | ||
import org.xmtp.android.library.codecs.Reaction | ||
import org.xmtp.android.library.codecs.ReactionAction | ||
import org.xmtp.android.library.codecs.ReactionCodec | ||
import org.xmtp.android.library.codecs.ReactionSchema | ||
import org.xmtp.android.library.messages.DecryptedMessage | ||
import org.xmtp.android.library.messages.MessageDeliveryStatus | ||
import org.xmtp.android.library.messages.PrivateKey | ||
import org.xmtp.android.library.messages.PrivateKeyBuilder | ||
import org.xmtp.android.library.messages.walletAddress | ||
import java.security.SecureRandom | ||
|
||
@RunWith(AndroidJUnit4::class) | ||
class DmTest { | ||
private lateinit var alixWallet: PrivateKeyBuilder | ||
private lateinit var boWallet: PrivateKeyBuilder | ||
private lateinit var caroWallet: PrivateKeyBuilder | ||
private lateinit var alix: PrivateKey | ||
private lateinit var alixClient: Client | ||
private lateinit var bo: PrivateKey | ||
private lateinit var boClient: Client | ||
private lateinit var caro: PrivateKey | ||
private lateinit var caroClient: Client | ||
|
||
@Before | ||
fun setUp() { | ||
val key = SecureRandom().generateSeed(32) | ||
val context = InstrumentationRegistry.getInstrumentation().targetContext | ||
alixWallet = PrivateKeyBuilder() | ||
alix = alixWallet.getPrivateKey() | ||
alixClient = runBlocking { | ||
Client().createV3( | ||
account = alixWallet, | ||
options = ClientOptions( | ||
ClientOptions.Api(XMTPEnvironment.LOCAL, false), | ||
enableV3 = true, | ||
appContext = context, | ||
dbEncryptionKey = key | ||
) | ||
) | ||
} | ||
boWallet = PrivateKeyBuilder() | ||
bo = boWallet.getPrivateKey() | ||
boClient = runBlocking { | ||
Client().createV3( | ||
account = boWallet, | ||
options = ClientOptions( | ||
ClientOptions.Api(XMTPEnvironment.LOCAL, false), | ||
enableV3 = true, | ||
appContext = context, | ||
dbEncryptionKey = key | ||
) | ||
) | ||
} | ||
|
||
caroWallet = PrivateKeyBuilder() | ||
caro = caroWallet.getPrivateKey() | ||
caroClient = runBlocking { | ||
Client().createV3( | ||
account = caroWallet, | ||
options = ClientOptions( | ||
ClientOptions.Api(XMTPEnvironment.LOCAL, false), | ||
enableV3 = true, | ||
appContext = context, | ||
dbEncryptionKey = key | ||
) | ||
) | ||
} | ||
} | ||
|
||
@Test | ||
fun testCanCreateADm() { | ||
runBlocking { | ||
val convo1 = boClient.conversations.findOrCreateDm(alix.walletAddress) | ||
val convo2 = caroClient.conversations.newConversation(alix.walletAddress) | ||
alixClient.conversations.syncConversations() | ||
val sameConvo1 = alixClient.conversations.findOrCreateDm(bo.walletAddress) | ||
val sameConvo2 = alixClient.conversations.newConversation(caro.walletAddress) | ||
assertEquals(convo1.id, sameConvo1.id) | ||
assertEquals(convo2.id, sameConvo2.id) | ||
} | ||
} | ||
|
||
@Test | ||
fun testCanListDmMembers() { | ||
val group = runBlocking { | ||
boClient.conversations.findOrCreateDm( | ||
alix.walletAddress, | ||
) | ||
} | ||
assertEquals( | ||
runBlocking { group.members().map { it.inboxId }.sorted() }, | ||
listOf( | ||
alixClient.inboxId, | ||
boClient.inboxId | ||
).sorted() | ||
) | ||
|
||
assertEquals( | ||
runBlocking { | ||
Conversation.Dm(group).members().map { it.inboxId }.sorted() | ||
}, | ||
listOf( | ||
alixClient.inboxId, | ||
boClient.inboxId | ||
).sorted() | ||
) | ||
|
||
assertEquals( | ||
runBlocking | ||
{ group.peerInboxId() }, | ||
alixClient.inboxId, | ||
) | ||
} | ||
|
||
@Test | ||
fun testDmMetadata() { | ||
val boDm = runBlocking { | ||
boClient.conversations.newConversation(alix.walletAddress) | ||
} | ||
|
||
runBlocking { alixClient.conversations.syncConversations() } | ||
val alixDm = runBlocking { alixClient.conversations.listDms().first() } | ||
runBlocking { | ||
alixDm.sync() | ||
alixDm.updateName("This Is A Great Group") | ||
alixDm.updateImageUrlSquare("thisisanewurl.com") | ||
boDm.sync() | ||
} | ||
assertEquals("This Is A Great Group", boDm.name) | ||
assertEquals("This Is A Great Group", alixDm.name) | ||
assertEquals("thisisanewurl.com", boDm.imageUrlSquare) | ||
assertEquals("thisisanewurl.com", alixDm.imageUrlSquare) | ||
} | ||
|
||
@Test | ||
fun testCannotCreateDmWithMemberNotOnV3() { | ||
val chuxAccount = PrivateKeyBuilder() | ||
val chux: PrivateKey = chuxAccount.getPrivateKey() | ||
runBlocking { Client().create(account = chuxAccount) } | ||
|
||
assertThrows("Recipient not on network", XMTPException::class.java) { | ||
runBlocking { boClient.conversations.findOrCreateDm(chux.walletAddress) } | ||
} | ||
} | ||
|
||
@Test | ||
fun testCannotStartDmWithSelf() { | ||
assertThrows("Recipient is sender", XMTPException::class.java) { | ||
runBlocking { boClient.conversations.findOrCreateDm(bo.walletAddress) } | ||
} | ||
} | ||
|
||
@Test | ||
fun testDmStartsWithAllowedState() { | ||
runBlocking { | ||
val dm = boClient.conversations.findOrCreateDm(alix.walletAddress) | ||
dm.send("howdy") | ||
dm.send("gm") | ||
dm.sync() | ||
assert(boClient.contacts.isGroupAllowed(dm.id)) | ||
assertEquals(boClient.contacts.consentList.groupState(dm.id), ConsentState.ALLOWED) | ||
assertEquals(dm.consentState(), ConsentState.ALLOWED) | ||
} | ||
} | ||
|
||
@Test | ||
fun testCanSendMessageToDm() { | ||
val dm = runBlocking { boClient.conversations.findOrCreateDm(alix.walletAddress) } | ||
runBlocking { dm.send("howdy") } | ||
val messageId = runBlocking { dm.send("gm") } | ||
runBlocking { dm.sync() } | ||
assertEquals(dm.messages().first().body, "gm") | ||
assertEquals(dm.messages().first().id, messageId) | ||
assertEquals(dm.messages().first().deliveryStatus, MessageDeliveryStatus.PUBLISHED) | ||
assertEquals(dm.messages().size, 3) | ||
|
||
runBlocking { alixClient.conversations.syncConversations() } | ||
val sameDm = runBlocking { alixClient.conversations.listDms().last() } | ||
runBlocking { sameDm.sync() } | ||
assertEquals(sameDm.messages().size, 2) | ||
assertEquals(sameDm.messages().first().body, "gm") | ||
} | ||
|
||
@Test | ||
fun testCanListDmMessages() { | ||
val dm = runBlocking { boClient.conversations.findOrCreateDm(alix.walletAddress) } | ||
runBlocking { | ||
dm.send("howdy") | ||
dm.send("gm") | ||
} | ||
|
||
assertEquals(dm.messages().size, 3) | ||
assertEquals(dm.messages(deliveryStatus = MessageDeliveryStatus.PUBLISHED).size, 3) | ||
runBlocking { dm.sync() } | ||
assertEquals(dm.messages().size, 3) | ||
assertEquals(dm.messages(deliveryStatus = MessageDeliveryStatus.UNPUBLISHED).size, 0) | ||
assertEquals(dm.messages(deliveryStatus = MessageDeliveryStatus.PUBLISHED).size, 3) | ||
|
||
runBlocking { alixClient.conversations.syncConversations() } | ||
val sameDm = runBlocking { alixClient.conversations.listDms().last() } | ||
runBlocking { sameDm.sync() } | ||
assertEquals(sameDm.messages(deliveryStatus = MessageDeliveryStatus.PUBLISHED).size, 2) | ||
} | ||
|
||
@Test | ||
fun testCanSendContentTypesToDm() { | ||
Client.register(codec = ReactionCodec()) | ||
|
||
val dm = runBlocking { boClient.conversations.findOrCreateDm(alix.walletAddress) } | ||
runBlocking { dm.send("gm") } | ||
runBlocking { dm.sync() } | ||
val messageToReact = dm.messages()[0] | ||
|
||
val reaction = Reaction( | ||
reference = messageToReact.id, | ||
action = ReactionAction.Added, | ||
content = "U+1F603", | ||
schema = ReactionSchema.Unicode | ||
) | ||
|
||
runBlocking { | ||
dm.send( | ||
content = reaction, | ||
options = SendOptions(contentType = ContentTypeReaction) | ||
) | ||
} | ||
runBlocking { dm.sync() } | ||
|
||
val messages = dm.messages() | ||
assertEquals(messages.size, 3) | ||
val content: Reaction? = messages.first().content() | ||
assertEquals("U+1F603", content?.content) | ||
assertEquals(messageToReact.id, content?.reference) | ||
assertEquals(ReactionAction.Added, content?.action) | ||
assertEquals(ReactionSchema.Unicode, content?.schema) | ||
} | ||
|
||
@Test | ||
fun testCanStreamDmMessages() = kotlinx.coroutines.test.runTest { | ||
val group = boClient.conversations.findOrCreateDm(alix.walletAddress.lowercase()) | ||
alixClient.conversations.syncConversations() | ||
val alixDm = alixClient.findDm(bo.walletAddress) | ||
group.streamMessages().test { | ||
alixDm?.send("hi") | ||
assertEquals("hi", awaitItem().body) | ||
alixDm?.send("hi again") | ||
assertEquals("hi again", awaitItem().body) | ||
} | ||
} | ||
|
||
@Test | ||
fun testCanStreamAllMessages() { | ||
val boDm = runBlocking { boClient.conversations.findOrCreateDm(alix.walletAddress) } | ||
runBlocking { alixClient.conversations.syncConversations() } | ||
|
||
val allMessages = mutableListOf<DecodedMessage>() | ||
|
||
val job = CoroutineScope(Dispatchers.IO).launch { | ||
try { | ||
alixClient.conversations.streamAllMessages().collect { message -> | ||
allMessages.add(message) | ||
} | ||
} catch (e: Exception) { | ||
} | ||
} | ||
Thread.sleep(2500) | ||
|
||
for (i in 0 until 2) { | ||
runBlocking { boDm.send(text = "Message $i") } | ||
Thread.sleep(100) | ||
} | ||
assertEquals(2, allMessages.size) | ||
|
||
val caroDm = | ||
runBlocking { caroClient.conversations.findOrCreateDm(alixClient.address) } | ||
Thread.sleep(2500) | ||
|
||
for (i in 0 until 2) { | ||
runBlocking { caroDm.send(text = "Message $i") } | ||
Thread.sleep(100) | ||
} | ||
|
||
assertEquals(4, allMessages.size) | ||
|
||
job.cancel() | ||
} | ||
|
||
@Test | ||
fun testCanStreamDecryptedDmMessages() = kotlinx.coroutines.test.runTest { | ||
val dm = boClient.conversations.newConversation(alix.walletAddress) | ||
alixClient.conversations.syncConversations() | ||
val alixDm = alixClient.findConversation(dm.id) | ||
dm.streamDecryptedMessages().test { | ||
alixDm?.send("hi") | ||
assertEquals("hi", awaitItem().encodedContent.content.toStringUtf8()) | ||
alixDm?.send("hi again") | ||
assertEquals("hi again", awaitItem().encodedContent.content.toStringUtf8()) | ||
} | ||
} | ||
|
||
@Test | ||
fun testCanStreamAllDecryptedDmMessages() { | ||
val dm = runBlocking { boClient.conversations.newConversation(alix.walletAddress) } | ||
runBlocking { alixClient.conversations.syncConversations() } | ||
|
||
val allMessages = mutableListOf<DecryptedMessage>() | ||
|
||
val job = CoroutineScope(Dispatchers.IO).launch { | ||
try { | ||
alixClient.conversations.streamAllDecryptedMessages().collect { message -> | ||
allMessages.add(message) | ||
} | ||
} catch (e: Exception) { | ||
} | ||
} | ||
Thread.sleep(2500) | ||
|
||
for (i in 0 until 2) { | ||
runBlocking { dm.send(text = "Message $i") } | ||
Thread.sleep(100) | ||
} | ||
assertEquals(2, allMessages.size) | ||
|
||
val caroDm = | ||
runBlocking { caroClient.conversations.findOrCreateDm(alixClient.address) } | ||
Thread.sleep(2500) | ||
|
||
for (i in 0 until 2) { | ||
runBlocking { caroDm.send(text = "Message $i") } | ||
Thread.sleep(100) | ||
} | ||
|
||
assertEquals(4, allMessages.size) | ||
|
||
job.cancel() | ||
} | ||
|
||
@Test | ||
fun testCanStreamConversations() = kotlinx.coroutines.test.runTest { | ||
boClient.conversations.streamConversations().test { | ||
val dm = | ||
alixClient.conversations.findOrCreateDm(bo.walletAddress) | ||
assertEquals(dm.id, awaitItem().id) | ||
val dm2 = | ||
caroClient.conversations.newConversation(bo.walletAddress) | ||
assertEquals(dm2.id, awaitItem().id) | ||
} | ||
} | ||
|
||
@Test | ||
fun testDmConsent() { | ||
runBlocking { | ||
val dm = | ||
boClient.conversations.findOrCreateDm(alix.walletAddress) | ||
assert(boClient.contacts.isGroupAllowed(dm.id)) | ||
assertEquals(dm.consentState(), ConsentState.ALLOWED) | ||
|
||
boClient.contacts.denyGroups(listOf(dm.id)) | ||
assert(boClient.contacts.isGroupDenied(dm.id)) | ||
assertEquals(dm.consentState(), ConsentState.DENIED) | ||
|
||
dm.updateConsentState(ConsentState.ALLOWED) | ||
assert(boClient.contacts.isGroupAllowed(dm.id)) | ||
assertEquals(dm.consentState(), ConsentState.ALLOWED) | ||
} | ||
} | ||
} |
Oops, something went wrong.