libeufin

Integration and sandbox testing for FinTech APIs and data formats
Log | Files | Refs | Submodules | README | LICENSE

commit 48d2df00c3e631763f5f0fb7ad9803bd4a999d2a
parent 553ce68abdb4c73e486994594bae2bcc6cfdef2d
Author: MS <ms@taler.net>
Date:   Mon, 23 Oct 2023 03:57:45 +0200

nexus db: switching submitted state of payments.

Diffstat:
Mnexus/src/main/kotlin/tech/libeufin/nexus/Database.kt | 20++++++++++++++------
Mnexus/src/test/kotlin/Common.kt | 16++++++++++++++--
Mnexus/src/test/kotlin/DatabaseTest.kt | 52++++++++++++++++++++++++++++++++++++++++------------
3 files changed, 68 insertions(+), 20 deletions(-)

diff --git a/nexus/src/main/kotlin/tech/libeufin/nexus/Database.kt b/nexus/src/main/kotlin/tech/libeufin/nexus/Database.kt @@ -45,8 +45,9 @@ enum class PaymentInitiationOutcome { /** * Performs a INSERT, UPDATE, or DELETE operation. * - * @return true on success, false on unique constraint violation, - * rethrows on any other issue. + * @return true if at least one row was affected by this operation, + * false on unique constraint violation or no rows were affected. + * */ private fun PreparedStatement.maybeUpdate(): Boolean { try { @@ -56,7 +57,7 @@ private fun PreparedStatement.maybeUpdate(): Boolean { if (e.sqlState == "23505") return false // unique_violation throw e // rethrowing, not to hide other types of errors. } - return true + return updateCount > 0 } /** @@ -100,10 +101,17 @@ class Database(dbConfig: String): java.io.Closeable { * Sets payment initiation as submitted. * * @param rowId row ID of the record to set. - * @return true on success, false otherwise. + * @return true on success, false if no payment was affected. */ - suspend fun initiatedPaymentSetSubmitted(rowId: Long): Boolean { - throw NotImplementedError() + suspend fun initiatedPaymentSetSubmitted(rowId: Long): Boolean = runConn { conn -> + val stmt = conn.prepareStatement(""" + UPDATE initiated_outgoing_transactions + SET submitted = true + WHERE initiated_outgoing_transaction_id=? + """ + ) + stmt.setLong(1, rowId) + return@runConn stmt.maybeUpdate() } /** diff --git a/nexus/src/test/kotlin/Common.kt b/nexus/src/test/kotlin/Common.kt @@ -8,6 +8,7 @@ import tech.libeufin.util.DatabaseConfig import tech.libeufin.util.initializeDatabaseTables import tech.libeufin.util.resetDatabaseTables import java.security.interfaces.RSAPrivateCrtKey +import java.time.Instant val j = Json { this.serializersModule = SerializersModule { @@ -54,6 +55,7 @@ fun getMockedClient( } } +// Partial config to talk to PostFinance. fun getPofiConfig(userId: String, partnerId: String) = """ [nexus-ebics] CURRENCY = KUDOS @@ -67,4 +69,14 @@ fun getPofiConfig(userId: String, partnerId: String) = """ CLIENT_PRIVATE_KEYS_FILE = /tmp/my-private-keys.json ACCOUNT_META_DATA_FILE = /tmp/ebics-meta.json BANK_DIALECT = postfinance -""".trimIndent() -\ No newline at end of file +""".trimIndent() + +// Generates a payment initiation, given its subject. +fun genInitPay(subject: String, rowUuid: String? = null) = + InitiatedPayment( + amount = TalerAmount(44, 0, "KUDOS"), + creditPaytoUri = "payto://iban/not-used", + wireTransferSubject = subject, + initiationTime = Instant.now(), + clientRequestUuid = rowUuid + ) +\ No newline at end of file diff --git a/nexus/src/test/kotlin/DatabaseTest.kt b/nexus/src/test/kotlin/DatabaseTest.kt @@ -7,10 +7,45 @@ import tech.libeufin.nexus.TalerAmount import tech.libeufin.util.connectWithSchema import java.time.Instant import kotlin.test.assertEquals +import kotlin.test.assertFalse import kotlin.test.assertTrue class DatabaseTest { + // Tests the flagging of payments as submitted. + @Test + fun paymentInitiationSetAsSubmitted() { + val db = prepDb(TalerConfig(NEXUS_CONFIG_SOURCE)) + val getRowOne = """ + SELECT submitted + FROM initiated_outgoing_transactions + WHERE initiated_outgoing_transaction_id=1 + """ + runBlocking { + // Creating the record first. Defaults to submitted == false. + assertEquals( + db.initiatedPaymentCreate(genInitPay("not submitted, has row ID == 1")), + PaymentInitiationOutcome.SUCCESS + ) + // Asserting on the false default submitted state. + db.runConn { conn -> + val isSubmitted = conn.execSQLQuery(getRowOne) + assertTrue(isSubmitted.next()) + assertFalse(isSubmitted.getBoolean("submitted")) + } + // Switching the submitted state to true. + assertTrue(db.initiatedPaymentSetSubmitted(1)) + + // Asserting on the submitted state being TRUE now. + db.runConn { conn -> + val isSubmitted = conn.execSQLQuery(getRowOne) + assertTrue(isSubmitted.next()) + assertTrue(isSubmitted.getBoolean("submitted")) + } + } + } + // Tests creation, unique constraint violation handling, and + // retrieving only one non-submitted payment. @Test fun paymentInitiation() { val db = prepDb(TalerConfig(NEXUS_CONFIG_SOURCE)) @@ -37,26 +72,17 @@ class DatabaseTest { } } - /** - * Tests how the fetch method gets the list of - * multiple unsubmitted payment initiations. - */ + // Tests how the fetch method gets the list of + // multiple unsubmitted payment initiations. @Test fun paymentInitiationsMultiple() { val db = prepDb(TalerConfig(NEXUS_CONFIG_SOURCE)) - fun genInitPay(subject: String, rowUuid: String? = null) = - InitiatedPayment( - amount = TalerAmount(44, 0, "KUDOS"), - creditPaytoUri = "payto://iban/not-used", - wireTransferSubject = subject, - initiationTime = Instant.now(), - clientRequestUuid = rowUuid - ) runBlocking { assertEquals(db.initiatedPaymentCreate(genInitPay("#1")), PaymentInitiationOutcome.SUCCESS) assertEquals(db.initiatedPaymentCreate(genInitPay("#2")), PaymentInitiationOutcome.SUCCESS) assertEquals(db.initiatedPaymentCreate(genInitPay("#3")), PaymentInitiationOutcome.SUCCESS) assertEquals(db.initiatedPaymentCreate(genInitPay("#4")), PaymentInitiationOutcome.SUCCESS) + // Marking one as submitted, hence not expecting it in the results. db.runConn { conn -> conn.execSQLUpdate(""" @@ -65,6 +91,8 @@ class DatabaseTest { WHERE initiated_outgoing_transaction_id=3; """.trimIndent()) } + + // Expecting all the payments BUT the #3 in the result. db.initiatedPaymentsUnsubmittedGet("KUDOS").apply { assertEquals(3, this.size) assertEquals("#1", this[1]?.wireTransferSubject)