diff --git a/mailbox-core/src/main/java/org/briarproject/mailbox/core/db/Database.kt b/mailbox-core/src/main/java/org/briarproject/mailbox/core/db/Database.kt index 0d899a75faf449b156edba5c7f6427851a5826ab..858b612887bdbf9c345ec20b8718e2a796763e70 100644 --- a/mailbox-core/src/main/java/org/briarproject/mailbox/core/db/Database.kt +++ b/mailbox-core/src/main/java/org/briarproject/mailbox/core/db/Database.kt @@ -26,6 +26,10 @@ interface Database : TransactionManager { @Throws(DbException::class) fun mergeSettings(txn: Transaction, s: Settings, namespace: String) + /** + * Adds a contact to the database. It is the callers responsibility to use [getContact] before + * to check if a contact with the same ID already exists. + */ @Throws(DbException::class) fun addContact(txn: Transaction, contact: Contact) diff --git a/mailbox-core/src/main/java/org/briarproject/mailbox/core/db/JdbcDatabase.kt b/mailbox-core/src/main/java/org/briarproject/mailbox/core/db/JdbcDatabase.kt index fe61611bcf7ac2f461e05248838b7da3814edbf5..0d3ffe3bea9b09f39a2f4ad439155f4a688fe0ab 100644 --- a/mailbox-core/src/main/java/org/briarproject/mailbox/core/db/JdbcDatabase.kt +++ b/mailbox-core/src/main/java/org/briarproject/mailbox/core/db/JdbcDatabase.kt @@ -45,7 +45,8 @@ abstract class JdbcDatabase(private val dbTypes: DatabaseTypes, private val cloc (contactId INT NOT NULL, token _STRING NOT NULL, inbox _STRING NOT NULL, - outbox _STRING NOT NULL) + outbox _STRING NOT NULL, + PRIMARY KEY (contactId)) """.trimIndent() } diff --git a/mailbox-core/src/test/java/org/briarproject/mailbox/core/contacts/ContactsManagerIntegrationTest.kt b/mailbox-core/src/test/java/org/briarproject/mailbox/core/contacts/ContactsManagerIntegrationTest.kt index cc606b857fed7af0c3e6777b409b02cdd4ebf370..acfd7ef9d5d97fa331ad47552471735e476861bf 100644 --- a/mailbox-core/src/test/java/org/briarproject/mailbox/core/contacts/ContactsManagerIntegrationTest.kt +++ b/mailbox-core/src/test/java/org/briarproject/mailbox/core/contacts/ContactsManagerIntegrationTest.kt @@ -21,6 +21,8 @@ import org.briarproject.mailbox.core.server.IntegrationTest import org.junit.jupiter.api.AfterEach import org.junit.jupiter.api.BeforeEach import org.junit.jupiter.api.Test +import kotlin.math.max +import kotlin.math.min import kotlin.test.assertEquals class ContactsManagerIntegrationTest : IntegrationTest() { @@ -57,7 +59,7 @@ class ContactsManagerIntegrationTest : IntegrationTest() { val response: HttpResponse = httpClient.get("$baseUrl/contacts") { authenticateWithToken(ownerToken) } - assertJson("""{ "contacts": [ ${contact1.contactId}, ${contact2.contactId} ] }""", response) + assertJson("""{ "contacts": ${getJsonArray(contact1, contact2)} }""", response) } @Test @@ -154,7 +156,7 @@ class ContactsManagerIntegrationTest : IntegrationTest() { authenticateWithToken(ownerToken) } assertJson( - """{ "contacts": [ ${contact1.contactId}, ${contact2.contactId} ] }""", + """{ "contacts": ${getJsonArray(contact1, contact2)} }""", response2 ) } @@ -194,7 +196,7 @@ class ContactsManagerIntegrationTest : IntegrationTest() { authenticateWithToken(ownerToken) } assertJson( - """{ "contacts": [ ${contact1.contactId}, ${contact2.contactId} ] }""", + """{ "contacts": ${getJsonArray(contact1, contact2)} }""", response2 ) } @@ -263,4 +265,14 @@ class ContactsManagerIntegrationTest : IntegrationTest() { assertEquals(BadRequest, response.status) assertEquals("Bad request: Invalid value for parameter contactId", response.readText()) } + + /** + * Getting contacts with a PRIMARY KEY seems to automatically order them by that key. + * So we need to sort the JSON array for a proper comparison. + */ + private fun getJsonArray(c1: Contact, c2: Contact): String { + val lowId = min(c1.contactId, c2.contactId) + val highId = max(c1.contactId, c2.contactId) + return "[ $lowId, $highId ]" + } } diff --git a/mailbox-core/src/test/java/org/briarproject/mailbox/core/db/JdbcDatabaseTest.kt b/mailbox-core/src/test/java/org/briarproject/mailbox/core/db/JdbcDatabaseTest.kt index d24afe2de61d1b8c71bbc7e5ea5d2ecb72e40769..d28009e730bfe29c9e51fcb940949eadf139ab7b 100644 --- a/mailbox-core/src/test/java/org/briarproject/mailbox/core/db/JdbcDatabaseTest.kt +++ b/mailbox-core/src/test/java/org/briarproject/mailbox/core/db/JdbcDatabaseTest.kt @@ -1,11 +1,13 @@ package org.briarproject.mailbox.core.db import org.briarproject.mailbox.core.TestUtils.deleteTestDirectory +import org.briarproject.mailbox.core.TestUtils.getNewRandomContact import org.briarproject.mailbox.core.contacts.Contact import org.briarproject.mailbox.core.settings.Settings import org.briarproject.mailbox.core.system.Clock import org.briarproject.mailbox.core.system.RandomIdManager import org.junit.jupiter.api.Test +import org.junit.jupiter.api.assertThrows import org.junit.jupiter.api.io.TempDir import java.io.File import kotlin.test.assertEquals @@ -86,6 +88,17 @@ abstract class JdbcDatabaseTest { db.close() } + @Test + fun `test that there can not be two contacts with same ID`() { + val db: Database = open(false) + db.write { txn -> + db.addContact(txn, getNewRandomContact(id = 1)) + assertThrows<DbException> { + db.addContact(txn, getNewRandomContact(id = 1)) + } + } + } + @Test @Throws(java.lang.Exception::class) open fun testMergeSettings() { diff --git a/mailbox-core/src/test/java/org/briarproject/mailbox/core/settings/MetadataRouteManagerTest.kt b/mailbox-core/src/test/java/org/briarproject/mailbox/core/settings/MetadataRouteManagerTest.kt index d758217f86d36d3581d142ea09cfc87988afe4ef..2e1a25b145e48abdc628e3ff583de98748f9cbd8 100644 --- a/mailbox-core/src/test/java/org/briarproject/mailbox/core/settings/MetadataRouteManagerTest.kt +++ b/mailbox-core/src/test/java/org/briarproject/mailbox/core/settings/MetadataRouteManagerTest.kt @@ -6,6 +6,7 @@ import io.ktor.client.statement.readText import io.ktor.http.HttpStatusCode import kotlinx.coroutines.runBlocking import org.briarproject.mailbox.core.server.IntegrationTest +import org.junit.jupiter.api.AfterEach import org.junit.jupiter.api.BeforeEach import org.junit.jupiter.api.Test import kotlin.test.assertEquals @@ -19,6 +20,13 @@ class MetadataRouteManagerTest : IntegrationTest() { addContact(contact2) } + @AfterEach + fun clearDb() { + db.write { txn -> + db.clearDatabase(txn) + } + } + @Test fun `owner can access status`(): Unit = runBlocking { val response: HttpResponse = httpClient.get("$baseUrl/status") {