libeufin

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

commit 4dc2291775e2eaca3c82ca943338962285051b68
parent a43fd507072d18eb559420e271587db5690b3d8d
Author: Antoine A <>
Date:   Mon, 23 Oct 2023 10:04:10 +0000

Fix /monitor

Diffstat:
Mbank/src/main/kotlin/tech/libeufin/bank/Database.kt | 60++++++++++++++++++++++++++++++++++--------------------------
Mbank/src/main/kotlin/tech/libeufin/bank/Main.kt | 4++--
Mbank/src/main/kotlin/tech/libeufin/bank/TalerMessage.kt | 8++++----
Mbank/src/main/kotlin/tech/libeufin/bank/helpers.kt | 2+-
Mbank/src/test/kotlin/StatsTest.kt | 10+++++-----
Mbank/src/test/kotlin/helpers.kt | 2+-
Mdatabase-versioning/procedures.sql | 12+++++++-----
7 files changed, 54 insertions(+), 44 deletions(-)

diff --git a/bank/src/main/kotlin/tech/libeufin/bank/Database.kt b/bank/src/main/kotlin/tech/libeufin/bank/Database.kt @@ -96,7 +96,7 @@ private fun PreparedStatement.executeUpdateViolation(): Boolean { } } -class Database(dbConfig: String, private val bankCurrency: String, private val fiatCurrency: String): java.io.Closeable { +class Database(dbConfig: String, private val bankCurrency: String, private val fiatCurrency: String?): java.io.Closeable { val dbPool: HikariDataSource private val notifWatcher: NotificationWatcher @@ -1486,7 +1486,7 @@ class Database(dbConfig: String, private val bankCurrency: String, private val f ,internal_taler_payments_count ,(internal_taler_payments_volume).val as internal_taler_payments_volume_val ,(internal_taler_payments_volume).frac as internal_taler_payments_volume_frac - FROM stats_get_frame(?::stat_timeframe_enum, ?) + FROM stats_get_frame(now()::timestamp, ?::stat_timeframe_enum, ?) """) stmt.setString(1, params.timeframe.name) if (params.which != null) { @@ -1496,18 +1496,22 @@ class Database(dbConfig: String, private val bankCurrency: String, private val f } stmt.oneOrNull { MonitorResponse( - cashinCount = it.getLong("cashin_count"), - cashinExternalVolume = TalerAmount( - value = it.getLong("cashin_volume_in_fiat_val"), - frac = it.getInt("cashin_volume_in_fiat_frac"), - currency = fiatCurrency - ), - cashoutCount = it.getLong("cashout_count"), - cashoutExternalVolume = TalerAmount( - value = it.getLong("cashout_volume_in_fiat_val"), - frac = it.getInt("cashout_volume_in_fiat_frac"), - currency = fiatCurrency - ), + cashinCount = fiatCurrency?.run { it.getLong("cashin_count") }, + cashinExternalVolume = fiatCurrency?.run { + TalerAmount( + value = it.getLong("cashin_volume_in_fiat_val"), + frac = it.getInt("cashin_volume_in_fiat_frac"), + currency = this + ) + }, + cashoutCount = fiatCurrency?.run { it.getLong("cashout_count") }, + cashoutExternalVolume = fiatCurrency?.run { + TalerAmount( + value = it.getLong("cashout_volume_in_fiat_val"), + frac = it.getInt("cashout_volume_in_fiat_frac"), + currency = this + ) + }, talerPayoutCount = it.getLong("internal_taler_payments_count"), talerPayoutInternalVolume = TalerAmount( value = it.getLong("internal_taler_payments_volume_val"), @@ -1516,18 +1520,22 @@ class Database(dbConfig: String, private val bankCurrency: String, private val f ) ) } ?: MonitorResponse( - cashinCount = 0, - cashinExternalVolume = TalerAmount( - value = 0, - frac = 0, - currency = fiatCurrency - ), - cashoutCount = 0, - cashoutExternalVolume = TalerAmount( - value = 0, - frac = 0, - currency = fiatCurrency - ), + cashinCount = fiatCurrency?.run { 0 }, + cashinExternalVolume = fiatCurrency?.run { + TalerAmount( + value = 0, + frac = 0, + currency = this + ) + }, + cashoutCount = fiatCurrency?.run { 0 }, + cashoutExternalVolume = fiatCurrency?.run { + TalerAmount( + value = 0, + frac = 0, + currency = this + ) + }, talerPayoutCount = 0, talerPayoutInternalVolume = TalerAmount( value = 0, diff --git a/bank/src/main/kotlin/tech/libeufin/bank/Main.kt b/bank/src/main/kotlin/tech/libeufin/bank/Main.kt @@ -344,7 +344,7 @@ class ServeBank : CliktCommand("Run libeufin-bank HTTP server", name = "serve") logger.info("Can only serve libeufin-bank via TCP") exitProcess(1) } - val db = Database(dbCfg.dbConnStr, ctx.currency, "TODO") + val db = Database(dbCfg.dbConnStr, ctx.currency, null) runBlocking { if (!maybeCreateAdminAccount(db, ctx)) // logs provided by the helper exitProcess(1) @@ -367,7 +367,7 @@ class ChangePw : CliktCommand("Change account password", name = "passwd") { val cfg = talerConfig(configFile) val ctx = cfg.loadBankApplicationContext() val dbCfg = cfg.loadDbConfig() - val db = Database(dbCfg.dbConnStr, ctx.currency, "TODO") + val db = Database(dbCfg.dbConnStr, ctx.currency, null) runBlocking { if (!maybeCreateAdminAccount(db, ctx)) // logs provided by the helper exitProcess(1) diff --git a/bank/src/main/kotlin/tech/libeufin/bank/TalerMessage.kt b/bank/src/main/kotlin/tech/libeufin/bank/TalerMessage.kt @@ -108,10 +108,10 @@ data class TokenRequest( @Serializable data class MonitorResponse( - val cashinCount: Long, - val cashinExternalVolume: TalerAmount, - val cashoutCount: Long, - val cashoutExternalVolume: TalerAmount, + val cashinCount: Long? = null, + val cashinExternalVolume: TalerAmount? = null, + val cashoutCount: Long? = null, + val cashoutExternalVolume: TalerAmount? = null, val talerPayoutCount: Long, val talerPayoutInternalVolume: TalerAmount ) diff --git a/bank/src/main/kotlin/tech/libeufin/bank/helpers.kt b/bank/src/main/kotlin/tech/libeufin/bank/helpers.kt @@ -196,7 +196,7 @@ data class MonitorParams( ) { companion object { fun extract(params: Parameters): MonitorParams { - val timeframe = Timeframe.valueOf(params["timeframe"] ?: throw MissingRequestParameterException(parameterName = "timeframe")) + val timeframe = Timeframe.valueOf(params["timeframe"] ?: "hour") val which = try { params["which"]?.toInt() } catch (e: Exception) { diff --git a/bank/src/test/kotlin/StatsTest.kt b/bank/src/test/kotlin/StatsTest.kt @@ -34,7 +34,7 @@ class StatsTest { @Test fun internalTalerPayment() = bankSetup { db -> db.conn { conn -> - val stmt = conn.prepareStatement("CALL stats_register_internal_taler_payment((?, ?)::taler_amount)") + val stmt = conn.prepareStatement("CALL stats_register_internal_taler_payment(now()::timestamp, (?, ?)::taler_amount)") suspend fun register(amount: TalerAmount) { stmt.setLong(1, amount.value) @@ -42,7 +42,7 @@ class StatsTest { stmt.executeUpdate() } - client.get("/monitor?timeframe=hour") { + client.get("/monitor") { basicAuth("admin", "admin-password") }.assertOk().run { val resp = Json.decodeFromString<MonitorResponse>(bodyAsText()) @@ -51,7 +51,7 @@ class StatsTest { } register(TalerAmount("KUDOS:10.0")) - client.get("/monitor?timeframe=hour") { + client.get("/monitor") { basicAuth("admin", "admin-password") }.assertOk().run { val resp = Json.decodeFromString<MonitorResponse>(bodyAsText()) @@ -60,7 +60,7 @@ class StatsTest { } register(TalerAmount("KUDOS:30.5")) - client.get("/monitor?timeframe=hour") { + client.get("/monitor") { basicAuth("admin", "admin-password") }.assertOk().run { val resp = Json.decodeFromString<MonitorResponse>(bodyAsText()) @@ -68,7 +68,7 @@ class StatsTest { assertEquals(TalerAmount("KUDOS:40.5"), resp.talerPayoutInternalVolume) } - // TODO Test timeframe logic using now() mocking + // TODO Test timeframe logic with different timestamps } } } \ No newline at end of file diff --git a/bank/src/test/kotlin/helpers.kt b/bank/src/test/kotlin/helpers.kt @@ -58,7 +58,7 @@ fun setup( resetDatabaseTables(dbCfg, "libeufin-bank") initializeDatabaseTables(dbCfg, "libeufin-bank") val ctx = config.loadBankApplicationContext() - Database(dbCfg.dbConnStr, ctx.currency, "TODO").use { + Database(dbCfg.dbConnStr, ctx.currency, null).use { runBlocking { lambda(it, ctx) } diff --git a/database-versioning/procedures.sql b/database-versioning/procedures.sql @@ -1020,6 +1020,7 @@ BEGIN END $$; CREATE OR REPLACE FUNCTION stats_get_frame( + IN now TIMESTAMP, IN timeframe stat_timeframe_enum, IN which INTEGER, OUT cashin_count BIGINT, @@ -1040,15 +1041,16 @@ LANGUAGE sql AS $$ FROM regional_stats AS s WHERE s.timeframe = timeframe AND start_time = CASE - WHEN which IS NULL THEN date_trunc(timeframe::text, now()) - WHEN timeframe = 'hour' THEN date_trunc('day', now()) + '1 hour'::interval * which - WHEN timeframe = 'day' THEN date_trunc('month', now()) + '1 day'::interval * which - WHEN timeframe = 'month' THEN date_trunc('year', now()) + '1 month'::interval * which + WHEN which IS NULL THEN date_trunc(timeframe::text, now) + WHEN timeframe = 'hour' THEN date_trunc('day', now) + '1 hour'::interval * which + WHEN timeframe = 'day' THEN date_trunc('month', now) + '1 day'::interval * which + WHEN timeframe = 'month' THEN date_trunc('year', now) + '1 month'::interval * which WHEN timeframe = 'year' THEN make_date(which, 1, 1)::TIMESTAMP END $$; CREATE OR REPLACE PROCEDURE stats_register_internal_taler_payment( + IN now TIMESTAMP, IN amount taler_amount ) LANGUAGE plpgsql AS $$ @@ -1068,7 +1070,7 @@ BEGIN ) VALUES ( frame - ,date_trunc(frame::text, now()) + ,date_trunc(frame::text, now) ,0 ,(0, 0)::taler_amount ,0