diff --git a/src/test/kotlin/org/briarproject/briar/desktop/testdata/Conversations.kt b/src/test/kotlin/org/briarproject/briar/desktop/testdata/Conversations.kt new file mode 100644 index 0000000000000000000000000000000000000000..bbcf0d92b064f2c44bd55c739d6ec9fdc6468bef --- /dev/null +++ b/src/test/kotlin/org/briarproject/briar/desktop/testdata/Conversations.kt @@ -0,0 +1,24 @@ +package org.briarproject.briar.desktop.testdata + +import java.time.LocalDateTime + +data class Conversations( + val persons: List<Conversation> +) + +data class Conversation( + val name: String, + var messages: List<Message> +) + +data class Message( + val text: String, + val direction: Direction, + val date: LocalDateTime, + val read: Boolean +) + +enum class Direction { + INCOMING, + OUTGOING +} diff --git a/src/test/kotlin/org/briarproject/briar/desktop/testdata/ConversationsData.kt b/src/test/kotlin/org/briarproject/briar/desktop/testdata/ConversationsData.kt new file mode 100644 index 0000000000000000000000000000000000000000..38cdea48a56f0b3c3c8d44f62e42c914181f2b50 --- /dev/null +++ b/src/test/kotlin/org/briarproject/briar/desktop/testdata/ConversationsData.kt @@ -0,0 +1,55 @@ +package org.briarproject.briar.desktop.testdata + +import java.time.LocalDateTime.of as dt + +val conversations = conversations { + conversation { + contactName = "Bob" + outgoing { + text = "Hi, Bob" + read = true + date = "2020-12-24 20:10:15" + } + incoming { + text = "What's up?" + read = true + date = "2020-12-24 20:11:05" + } + outgoing { + text = "Nothing much, lately" + read = false + date = "2020-12-24 20:12:34" + } + } + conversation { + contactName = "Chuck" + val start = dt(2020, 1, 12, 19, 43, 17) + outgoing { + text = "Hey Chuck!" + read = true + date = start + } + incoming { + text = "Good evening, Alice" + read = true + date = start.plusSeconds(100) + } + } + conversation { + contactName = "Dan" + outgoing { + text = "Welcome to Briar!" + read = true + date = "2019-02-13 13:15:00" + } + } +} + +fun main(args: Array<String>) { + for (conversation in conversations.persons) { + println("conversation with: ${conversation.name}") + for (message in conversation.messages) { + println(" ${message.direction} ${message.text} ${message.read} ${message.date}") + } + } +} diff --git a/src/test/kotlin/org/briarproject/briar/desktop/testdata/ConversationsDsl.kt b/src/test/kotlin/org/briarproject/briar/desktop/testdata/ConversationsDsl.kt new file mode 100644 index 0000000000000000000000000000000000000000..3a815a70a67abd27fd32c5beceab10dc0ae66dfd --- /dev/null +++ b/src/test/kotlin/org/briarproject/briar/desktop/testdata/ConversationsDsl.kt @@ -0,0 +1,62 @@ +package org.briarproject.briar.desktop.testdata + +import org.briarproject.briar.desktop.testdata.Direction.INCOMING +import org.briarproject.briar.desktop.testdata.Direction.OUTGOING +import java.time.LocalDateTime +import java.time.format.DateTimeFormatter + +@DslMarker +annotation class ConversationsDsl + +fun conversations(block: ConversationsBuilder.() -> Unit): Conversations = ConversationsBuilder().apply(block).build() + +@ConversationsDsl +class ConversationsBuilder { + + private val conversations = mutableListOf<Conversation>() + + fun conversation(block: ConversationBuilder.() -> Unit) { + conversations.add(ConversationBuilder().apply(block).build()) + } + + fun build(): Conversations = Conversations(conversations) +} + +@ConversationsDsl +class ConversationBuilder { + + var contactName: String = "" + + private val messages = mutableListOf<Message>() + + fun incoming(block: MessageBuilder.() -> Unit) { + messages.add(MessageBuilder(INCOMING).apply(block).build()) + } + + fun outgoing(block: MessageBuilder.() -> Unit) { + messages.add(MessageBuilder(OUTGOING).apply(block).build()) + } + + fun build(): Conversation = Conversation(contactName, messages) +} + +var formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss") + +@ConversationsDsl +class MessageBuilder(private val direction: Direction) { + + var text: String = "" + var read: Boolean = false + + private var sent: LocalDateTime = LocalDateTime.now() + var date: Any = "" + set(value) { + if (value is String) { + sent = LocalDateTime.parse(value, formatter) + } else if (value is LocalDateTime) { + sent = value + } + } + + fun build(): Message = Message(text, direction, sent, read) +} diff --git a/src/test/kotlin/org/briarproject/briar/desktop/testdata/DeterministicTestDataCreator.kt b/src/test/kotlin/org/briarproject/briar/desktop/testdata/DeterministicTestDataCreator.kt index af242ba5d3b3ded57a67fb91b5587c00b8bde166..e1670964cf97435bbc716a8b7e0bf13a79ab9e2b 100644 --- a/src/test/kotlin/org/briarproject/briar/desktop/testdata/DeterministicTestDataCreator.kt +++ b/src/test/kotlin/org/briarproject/briar/desktop/testdata/DeterministicTestDataCreator.kt @@ -18,5 +18,5 @@ interface DeterministicTestDataCreator { @IoExecutor @Throws(DbException::class) - fun addContact(name: String?, alias: Boolean, avatar: Boolean): Contact? + fun addContact(name: String?, alias: String?, avatar: Boolean): Contact? } diff --git a/src/test/kotlin/org/briarproject/briar/desktop/testdata/DeterministicTestDataCreatorImpl.kt b/src/test/kotlin/org/briarproject/briar/desktop/testdata/DeterministicTestDataCreatorImpl.kt index 72cdd1d4509771cd74b698eb45abe32f52e41d78..5d6a340012aab82f37594c9daa01f066217ebb23 100644 --- a/src/test/kotlin/org/briarproject/briar/desktop/testdata/DeterministicTestDataCreatorImpl.kt +++ b/src/test/kotlin/org/briarproject/briar/desktop/testdata/DeterministicTestDataCreatorImpl.kt @@ -32,22 +32,25 @@ import org.briarproject.briar.api.avatar.AvatarMessageEncoder import org.briarproject.briar.api.messaging.MessagingManager import org.briarproject.briar.api.messaging.PrivateMessageFactory import org.briarproject.briar.api.test.TestAvatarCreator -import org.briarproject.briar.test.TestData import java.io.IOException import java.io.InputStream +import java.time.ZoneOffset import java.util.Random import java.util.UUID import java.util.concurrent.Executor import java.util.logging.Level import java.util.logging.Logger import javax.inject.Inject +import kotlin.math.min class DeterministicTestDataCreatorImpl @Inject internal constructor( - private val authorFactory: AuthorFactory, private val clock: Clock, + private val authorFactory: AuthorFactory, + private val clock: Clock, private val groupFactory: GroupFactory, private val privateMessageFactory: PrivateMessageFactory, private val db: DatabaseComponent, - private val identityManager: IdentityManager, private val contactManager: ContactManager, + private val identityManager: IdentityManager, + private val contactManager: ContactManager, private val transportPropertyManager: TransportPropertyManager, private val messagingManager: MessagingManager, private val testAvatarCreator: TestAvatarCreator, @@ -58,7 +61,8 @@ class DeterministicTestDataCreatorImpl @Inject internal constructor( private val random = Random() private val localAuthors: MutableMap<Contact, LocalAuthor> = HashMap() override fun createTestData( - numContacts: Int, numPrivateMsgs: Int, + numContacts: Int, + numPrivateMsgs: Int, avatarPercent: Int ) { require(numContacts != 0) @@ -66,7 +70,7 @@ class DeterministicTestDataCreatorImpl @Inject internal constructor( ioExecutor.execute { try { createTestDataOnIoExecutor( - numContacts, numPrivateMsgs, + min(numContacts, conversations.persons.size), numPrivateMsgs, avatarPercent ) } catch (e: DbException) { @@ -78,7 +82,8 @@ class DeterministicTestDataCreatorImpl @Inject internal constructor( @IoExecutor @Throws(DbException::class) private fun createTestDataOnIoExecutor( - numContacts: Int, numPrivateMsgs: Int, + numContacts: Int, + numPrivateMsgs: Int, avatarPercent: Int ) { val contacts = createContacts(numContacts, avatarPercent) @@ -89,12 +94,11 @@ class DeterministicTestDataCreatorImpl @Inject internal constructor( private fun createContacts(numContacts: Int, avatarPercent: Int): List<Contact> { val contacts: MutableList<Contact> = ArrayList(numContacts) val localAuthor = identityManager.localAuthor + for (i in 0 until numContacts) { - val remote = randomAuthor - val contact = addContact( - localAuthor.id, remote, - random.nextBoolean(), avatarPercent - ) + val person = conversations.persons[i] + val remote = authorFactory.createLocalAuthor(person.name) + val contact = addContact(localAuthor.id, remote, null, avatarPercent) contacts.add(contact) } return contacts @@ -102,8 +106,10 @@ class DeterministicTestDataCreatorImpl @Inject internal constructor( @Throws(DbException::class) private fun addContact( - localAuthorId: AuthorId, remote: LocalAuthor, - alias: Boolean, avatarPercent: Int + localAuthorId: AuthorId, + remote: LocalAuthor, + alias: String?, + avatarPercent: Int ): Contact { // prepare to add contact val secretKey = secretKey @@ -114,44 +120,30 @@ class DeterministicTestDataCreatorImpl @Inject internal constructor( val props = randomTransportProperties val contact = db.transactionWithResult<Contact, RuntimeException>(false) { txn: Transaction? -> val contactId = contactManager.addContact( - txn, remote, - localAuthorId, secretKey, timestamp, true, verified, true + txn, remote, localAuthorId, secretKey, timestamp, true, verified, true ) - if (alias) { - contactManager.setContactAlias( - txn, contactId, - randomAuthorName - ) + if (alias != null) { + contactManager.setContactAlias(txn, contactId, alias) } transportPropertyManager.addRemoteProperties(txn, contactId, props) db.getContact(txn, contactId) } if (random.nextInt(100) + 1 <= avatarPercent) addAvatar(contact) if (LOG.isLoggable(Level.INFO)) { - LOG.info( - "Added contact " + remote.name + - " with transport properties: " + props - ) + LOG.info("Added contact ${remote.name} with transport properties: $props") } localAuthors[contact] = remote return contact } @Throws(DbException::class) - override fun addContact(name: String?, alias: Boolean, avatar: Boolean): Contact? { + override fun addContact(name: String?, alias: String?, avatar: Boolean): Contact? { val localAuthor = identityManager.localAuthor val remote = authorFactory.createLocalAuthor(name) val avatarPercent = if (avatar) 100 else 0 return addContact(localAuthor.id, remote, alias, avatarPercent) } - private val randomAuthorName: String - private get() { - val i = random.nextInt(TestData.AUTHOR_NAMES.size) - return TestData.AUTHOR_NAMES[i] - } - private val randomAuthor: LocalAuthor - private get() = authorFactory.createLocalAuthor(randomAuthorName) private val secretKey: SecretKey private get() { val b = ByteArray(SecretKey.LENGTH) @@ -289,29 +281,29 @@ class DeterministicTestDataCreatorImpl @Inject internal constructor( contacts: List<Contact>, numPrivateMsgs: Int ) { - for (contact in contacts) { + for (i in contacts.indices) { + val contact = contacts[i] + val person = conversations.persons[i] val group = messagingManager.getContactGroup(contact) shareGroup(contact.id, group.id) - for (i in 0 until numPrivateMsgs) { - createRandomPrivateMessage(contact.id, group.id, i) + for (k in 0 until min(numPrivateMsgs, person.messages.size)) { + createPrivateMessage(contact.id, group.id, person.messages[k]) } } if (LOG.isLoggable(Level.INFO)) { - LOG.info( - "Created " + numPrivateMsgs + - " private messages per contact." - ) + LOG.info("Created $numPrivateMsgs private messages per contact.") } } @Throws(DbException::class) - private fun createRandomPrivateMessage( + private fun createPrivateMessage( contactId: ContactId, - groupId: GroupId, num: Int + groupId: GroupId, + message: org.briarproject.briar.desktop.testdata.Message ) { - val timestamp = clock.currentTimeMillis() - num * 60 * 1000 - val text = randomText - val local = random.nextBoolean() + val timestamp = message.date.toEpochSecond(ZoneOffset.UTC) + val text = message.text + val local = message.direction == Direction.OUTGOING val autoDelete = random.nextBoolean() createPrivateMessage( contactId, groupId, text, timestamp, local, @@ -321,8 +313,12 @@ class DeterministicTestDataCreatorImpl @Inject internal constructor( @Throws(DbException::class) private fun createPrivateMessage( - contactId: ContactId, groupId: GroupId, - text: String, timestamp: Long, local: Boolean, autoDelete: Boolean + contactId: ContactId, + groupId: GroupId, + text: String, + timestamp: Long, + local: Boolean, + autoDelete: Boolean ) { val timer = if (autoDelete) AutoDeleteConstants.MIN_AUTO_DELETE_TIMER_MS else AutoDeleteConstants.NO_AUTO_DELETE_TIMER