libeufin

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

GcTest.kt (6884B)


      1 /*
      2  * This file is part of LibEuFin.
      3  * Copyright (C) 2024-2025 Taler Systems S.A.
      4 
      5  * LibEuFin is free software; you can redistribute it and/or modify
      6  * it under the terms of the GNU Affero General Public License as
      7  * published by the Free Software Foundation; either version 3, or
      8  * (at your option) any later version.
      9 
     10  * LibEuFin is distributed in the hope that it will be useful, but
     11  * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
     12  * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Affero General
     13  * Public License for more details.
     14 
     15  * You should have received a copy of the GNU Affero General Public
     16  * License along with LibEuFin; see the file COPYING.  If not, see
     17  * <http://www.gnu.org/licenses/>
     18  */
     19 
     20 import io.ktor.client.request.*
     21 import org.junit.Test
     22 import tech.libeufin.bank.*
     23 import tech.libeufin.bank.db.CashoutDAO.CashoutCreationResult
     24 import tech.libeufin.bank.db.ExchangeDAO.TransferResult
     25 import tech.libeufin.bank.db.TransactionDAO.BankTransactionResult
     26 import tech.libeufin.bank.db.WithdrawalDAO.*
     27 import tech.libeufin.common.*
     28 import tech.libeufin.common.test.*
     29 import tech.libeufin.common.db.*
     30 import java.time.Duration
     31 import java.time.Instant
     32 import java.util.*
     33 import kotlin.test.assertEquals
     34 import kotlin.test.assertIs
     35 
     36 class GcTest {
     37     @Test
     38     fun gc() = bankSetup { db -> db.conn { conn ->
     39         fun assertNb(nb: Int, stmt: String) {
     40             assertEquals(nb, conn.talerStatement(stmt).one { it.getInt(1) })
     41         }
     42         fun assertNbAccount(nb: Int) = assertNb(nb, "SELECT count(*) from bank_accounts")
     43         fun assertNbTokens(nb: Int) = assertNb(nb, "SELECT count(*) from bearer_tokens")
     44         fun assertNbTan(nb: Int) = assertNb(nb, "SELECT count(*) from tan_challenges")
     45         fun assertNbCashout(nb: Int) = assertNb(nb, "SELECT count(*) from cashout_operations")
     46         fun assertNbWithdrawal(nb: Int) = assertNb(nb, "SELECT count(*) from taler_withdrawal_operations")
     47         fun assertNbBankTx(nb: Int) = assertNb(nb, "SELECT count(*) from bank_transaction_operations")
     48         fun assertNbTx(nb: Int) = assertNb(nb, "SELECT count(*) from bank_account_transactions")
     49         fun assertNbIncoming(nb: Int) = assertNb(nb, "SELECT count(*) from taler_exchange_incoming")
     50         fun assertNbOutgoing(nb: Int) = assertNb(nb, "SELECT count(*) from taler_exchange_outgoing")
     51 
     52         val ZERO = TalerAmount.zero("KUDOS")
     53         val MAX = TalerAmount.max("KUDOS")
     54 
     55         // Time calculation
     56         val abortAfter = Duration.ofMinutes(15)
     57         val cleanAfter = Duration.ofDays(14)
     58         val deleteAfter = Duration.ofDays(350)
     59         val now = Instant.now()
     60         val abort = now.minus(abortAfter)
     61         val clean = now.minus(cleanAfter)
     62         val delete = now.minus(deleteAfter)
     63 
     64         // Create test accounts
     65         val payto = IbanPayto.rand()
     66         client.post("/accounts") {
     67             json {
     68                 "username" to "old_account"
     69                 "password" to "old_account-password"
     70                 "name" to "Old Account"
     71                 "cashout_payto_uri" to payto
     72             }
     73         }.assertOkJson<RegisterAccountResponse>().internal_payto_uri
     74         client.post("/accounts") {
     75             json {
     76                 "username" to "recent_account"
     77                 "password" to "recent_account-password"
     78                 "name" to "Recent Account"
     79                 "cashout_payto_uri" to payto
     80             }
     81 
     82         }.assertOkJson<RegisterAccountResponse>().internal_payto_uri
     83         assertNbAccount(6)
     84 
     85         // Create test tokens
     86         for (time in listOf(now, clean)) {
     87             for (account in listOf("old_account", "recent_account")) {
     88                 db.token.create(account, ByteArray(32).rand(), time, time, TokenScope.readonly, false, null, true)
     89                 db.tan.new(account, Operation.cashout, Base32Crockford64B.rand(), Base32Crockford16B.rand(), "", time, 0, Duration.ZERO, TanChannel.sms, "")
     90             }
     91         }
     92         assertNbTokens(5)
     93         assertNbTan(4)
     94 
     95         // Create test operations
     96         val from = TalerAmount("KUDOS:1")
     97         val to = convert("KUDOS:1")
     98         for ((account, times) in listOf(
     99             Pair("old_account", listOf(delete)),
    100             Pair("recent_account", listOf(now, abort, clean, delete))
    101         )) {
    102             for (time in times) {
    103                 val uuid = UUID.randomUUID()
    104                 assertEquals(
    105                     db.withdrawal.create(account, uuid, from, null, false, time, ZERO, ZERO, MAX),
    106                     WithdrawalCreationResult.Success
    107                 )
    108                 assertIs<WithdrawalSelectionResult.Success>(
    109                     db.withdrawal.setDetails(uuid, exchangePayto, EddsaPublicKey.rand(), null, ZERO, ZERO, MAX)
    110                 )
    111                 assertEquals(
    112                     db.withdrawal.confirm(account, uuid, time, null, false, ZERO, ZERO, MAX),
    113                     WithdrawalConfirmationResult.Success
    114                 )
    115                 assertIs<CashoutCreationResult.Success>(
    116                     db.cashout.create(account, ShortHashCode.rand(), from, to, "", time, false),
    117                 )
    118                 assertIs<BankTransactionResult.Success>(
    119                     db.transaction.create(customerPayto, account, "", from, time, false, ShortHashCode.rand(), ZERO, ZERO, MAX),
    120                 )
    121             }
    122             for (time in listOf(now, abort, clean, delete)) {
    123                 assertEquals(
    124                     db.withdrawal.create(account, UUID.randomUUID(), from, null, false, time, ZERO, ZERO, MAX),
    125                     WithdrawalCreationResult.Success
    126                 )
    127             }
    128         }
    129         for (time in listOf(now, abort, clean, delete)) {
    130             assertIs<TransferResult.Success>(
    131                 db.exchange.transfer(
    132                     TransferRequest(HashCode.rand(), from, BaseURL.parse("http://localhost/"), ShortHashCode.rand(), customerPayto),
    133                     "exchange", time, false
    134                 )
    135             )
    136         }
    137         assertNbTx(38)
    138         assertNbCashout(5)
    139         assertNbBankTx(5)
    140         assertNbWithdrawal(13)
    141         assertNbIncoming(5)
    142         assertNbOutgoing(4)
    143 
    144         // Check soft delete
    145         conn.execSQLUpdate("UPDATE bank_accounts SET balance = (0, 0)::taler_amount")
    146         for (account in listOf("old_account", "recent_account")) {
    147             client.deleteA("/accounts/$account").assertNoContent()
    148         }
    149         assertNbAccount(6)
    150 
    151         db.gc.collect(
    152             Instant.now(),
    153             abortAfter,
    154             cleanAfter,
    155             deleteAfter
    156         )
    157         // Check hard delete
    158         assertNbAccount(5)
    159         assertNbTokens(3)
    160         assertNbTan(1)
    161         assertNbTx(24)
    162         assertNbCashout(3)
    163         assertNbBankTx(3)
    164         assertNbWithdrawal(4)
    165         assertNbIncoming(3)
    166         assertNbOutgoing(3)
    167     }}
    168 }