gnunet-svn
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[libeufin] branch master updated (348a6945 -> 1d08ec59)


From: gnunet
Subject: [libeufin] branch master updated (348a6945 -> 1d08ec59)
Date: Mon, 20 Nov 2023 18:45:44 +0100

This is an automated email from the git hooks/post-receive script.

antoine pushed a change to branch master
in repository libeufin.

    from 348a6945 Apply new spec
     new 1541b506 Common history test routine
     new 1d08ec59 Common auth test routine

The 2 revisions listed above as "new" are entirely new to this
repository and will be described in separate emails.  The revisions
listed as "add" were already present in the repository and have only
been added to this reference.


Summary of changes:
 bank/src/test/kotlin/CoreBankApiTest.kt    | 256 +++++++-----------------
 bank/src/test/kotlin/RevenueApiTest.kt     | 129 +++---------
 bank/src/test/kotlin/WireGatewayApiTest.kt | 307 +++++------------------------
 bank/src/test/kotlin/routines.kt           | 212 ++++++++++++++++++++
 4 files changed, 359 insertions(+), 545 deletions(-)
 create mode 100644 bank/src/test/kotlin/routines.kt

diff --git a/bank/src/test/kotlin/CoreBankApiTest.kt 
b/bank/src/test/kotlin/CoreBankApiTest.kt
index 1d99f995..beb35ca6 100644
--- a/bank/src/test/kotlin/CoreBankApiTest.kt
+++ b/bank/src/test/kotlin/CoreBankApiTest.kt
@@ -45,15 +45,11 @@ class CoreBankConfigTest {
     // GET /monitor
     @Test
     fun monitor() = bankSetup { _ -> 
+        authRoutine(HttpMethod.Get, "/monitor", requireAdmin = true)
         // Check OK
         client.get("/monitor?timeframe=hour") {
             pwAuth("admin")
         }.assertOk()
-
-        // Check only admin
-        client.get("/monitor") {
-            pwAuth("exchange")
-        }.assertUnauthorized()
     }
 }
 
@@ -61,10 +57,7 @@ class CoreBankTokenApiTest {
     // POST /accounts/USERNAME/token
     @Test
     fun post() = bankSetup { db -> 
-        // Wrong user
-        client.post("/accounts/merchant/token") {
-            pwAuth("exchange")
-        }.assertUnauthorized()
+        authRoutine(HttpMethod.Post, "/accounts/merchant/token")
 
         // New default token
         client.postA("/accounts/merchant/token") {
@@ -259,19 +252,14 @@ class CoreBankAccountsApiTest {
     // Test admin-only account creation
     @Test
     fun createAccountRestrictedTest() = bankSetup(conf = "test_restrict.conf") 
{ _ -> 
-        val req = obj {
-            "username" to "baz"
-            "password" to "xyz"
-            "name" to "Mallory"
-        }
-
-        client.post("/accounts") {
-            pwAuth("merchant")
-            json(req)
-        }.assertUnauthorized()
+        authRoutine(HttpMethod.Post, "/accounts", requireAdmin = true)
         client.post("/accounts") {
             pwAuth("admin")
-            json(req)
+            json {
+                "username" to "baz"
+                "password" to "xyz"
+                "name" to "Mallory"
+            }
         }.assertCreated()
     }
 
@@ -321,6 +309,8 @@ class CoreBankAccountsApiTest {
     // PATCH /accounts/USERNAME
     @Test
     fun accountReconfig() = bankSetup { _ -> 
+        authRoutine(HttpMethod.Patch, "/accounts/merchant", withAdmin = true)
+
         // Successful attempt now.
         val cashout = IbanPayTo(genIbanPaytoUri())
         val req = obj {
@@ -390,6 +380,8 @@ class CoreBankAccountsApiTest {
     // PATCH /accounts/USERNAME/auth
     @Test
     fun passwordChangeTest() = bankSetup { _ -> 
+        authRoutine(HttpMethod.Patch, "/accounts/merchant/auth", withAdmin = 
true)
+
         // Changing the password.
         client.patch("/accounts/customer/auth") {
             basicAuth("customer", "customer-password")
@@ -441,6 +433,7 @@ class CoreBankAccountsApiTest {
     // GET /public-accounts and GET /accounts
     @Test
     fun accountsListTest() = bankSetup { _ -> 
+        authRoutine(HttpMethod.Get, "/accounts", requireAdmin = true)
         // Remove default accounts
         listOf("merchant", "exchange", "customer").forEach {
             client.delete("/accounts/$it") {
@@ -502,122 +495,57 @@ class CoreBankAccountsApiTest {
     // GET /accounts/USERNAME
     @Test
     fun getAccountTest() = bankSetup { _ -> 
+        authRoutine(HttpMethod.Get, "/accounts/merchant", withAdmin = true)
         // Check ok
         client.getA("/accounts/merchant").assertOkJson<AccountData> {
             assertEquals("Merchant", it.name)
         }
-
-        // Check admin ok
-        client.get("/accounts/merchant") {
-            pwAuth("admin")
-        }.assertOk()
-
-        // Check wrong user
-        client.get("/accounts/exchange") {
-            pwAuth("merchant")
-        }.assertUnauthorized()
     }
 }
 
 class CoreBankTransactionsApiTest {
-    // Test endpoint is correctly authenticated 
-    suspend fun ApplicationTestBuilder.authRoutine(path: String, withAdmin: 
Boolean = true, method: HttpMethod = HttpMethod.Post) {
-        // No body when authentication must happen before parsing the body
-        
-        // Unknown account
-        client.request(path) {
-            this.method = method
-            basicAuth("unknown", "password")
-        }.assertUnauthorized()
-
-        // Wrong password
-        client.request(path) {
-            this.method = method
-            basicAuth("merchant", "wrong-password")
-        }.assertUnauthorized()
-
-        // Wrong account
-        client.request(path) {
-            this.method = method
-            basicAuth("exchange", "merchant-password")
-        }.assertUnauthorized()
-
-        // TODO check admin rights
-    }
-
     // GET /transactions
     @Test
     fun testHistory() = bankSetup { _ -> 
-        suspend fun HttpResponse.assertHistory(size: Int) {
-            assertHistoryIds<BankAccountTransactionsResponse>(size) {
-                it.transactions.map { it.row_id }
-            }
-        }
-
-        authRoutine("/accounts/merchant/transactions", method = HttpMethod.Get)
-
-        // Check error when no transactions
-        client.get("/accounts/merchant/transactions") {
-            pwAuth("merchant")
-        }.assertNoContent()
-        
-        // Gen three transactions from merchant to exchange
-        repeat(3) {
-            tx("merchant", "KUDOS:0.$it", "customer")
-        }
-        // Gen two transactions from exchange to merchant
-        repeat(2) {
-            tx("customer", "KUDOS:0.$it", "merchant")
-        }
-
-        // Check no useless polling
-        assertTime(0, 100) {
-            
client.get("/accounts/merchant/transactions?delta=-6&start=11&long_poll_ms=1000")
 {
-                pwAuth("merchant")
-            }.assertHistory(5)
-        }
-
-        // Check no polling when find transaction
-        assertTime(0, 100) {
-            
client.getA("/accounts/merchant/transactions?delta=6&long_poll_ms=1000") 
-                .assertHistory(5)
-        }
-
-        coroutineScope {
-            launch { // Check polling succeed
-                assertTime(100, 200) {
-                    
client.getA("/accounts/merchant/transactions?delta=2&start=10&long_poll_ms=1000")
-                        .assertHistory(1)
+        authRoutine(HttpMethod.Get, "/accounts/merchant/transactions")
+        historyRoutine<BankAccountTransactionsResponse>(
+            url = "/accounts/customer/transactions",
+            ids = { it.transactions.map { it.row_id } },
+            registered = listOf(
+                { 
+                    // Transactions from merchant to exchange
+                    tx("merchant", "KUDOS:0.1", "customer")
+                },
+                { 
+                    // Transactions from exchange to merchant
+                    tx("customer", "KUDOS:0.1", "merchant")
+                },
+                { 
+                    // Transactions from merchant to exchange
+                    tx("merchant", "KUDOS:0.1", "customer")
+                },
+                { 
+                    // Cashout from merchant
+                    cashout("KUDOS:0.1")
                 }
-            }
-            launch { // Check polling timeout
-                assertTime(200, 300) {
-                    
client.getA("/accounts/merchant/transactions?delta=1&start=11&long_poll_ms=200")
-                        .assertNoContent()
+            ),
+            ignored = listOf(
+                {
+                    // Ignore transactions of other accounts
+                    tx("merchant", "KUDOS:0.1", "exchange")
+                },
+                {
+                    // Ignore transactions of other accounts
+                    tx("exchange", "KUDOS:0.1", "merchant",)
                 }
-            }
-            delay(100)
-            tx("merchant", "KUDOS:4.2", "customer")
-        }
-
-        // Testing ranges. 
-        repeat(30) {
-            tx("merchant", "KUDOS:0.001", "customer")
-        }
-
-        // forward range:
-        client.getA("/accounts/merchant/transactions?delta=10&start=20")
-            .assertHistory(10)
-
-        // backward range:
-        client.getA("/accounts/merchant/transactions?delta=-10&start=25")
-            .assertHistory(10)
+            )
+        )
     }
 
     // GET /transactions/T_ID
     @Test
     fun testById() = bankSetup { _ -> 
-        authRoutine("/accounts/merchant/transactions/1", method = 
HttpMethod.Get)
+        authRoutine(HttpMethod.Get, "/accounts/merchant/transactions/42")
 
         // Create transaction
         tx("merchant", "KUDOS:0.3", "exchange", "tx")
@@ -638,13 +566,13 @@ class CoreBankTransactionsApiTest {
     // POST /transactions
     @Test
     fun create() = bankSetup { _ -> 
+        authRoutine(HttpMethod.Post, "/accounts/merchant/transactions")
+
         val valid_req = obj {
             "payto_uri" to "$exchangePayto?message=payout"
             "amount" to "KUDOS:0.3"
         }
 
-        authRoutine("/accounts/merchant/transactions")
-
         // Check OK
         client.postA("/accounts/merchant/transactions") {
             json(valid_req)
@@ -763,6 +691,8 @@ class CoreBankWithdrawalApiTest {
     // POST /accounts/USERNAME/withdrawals
     @Test
     fun create() = bankSetup { _ ->
+        authRoutine(HttpMethod.Post, "/accounts/merchant/withdrawals")
+        
         // Check OK
         client.postA("/accounts/merchant/withdrawals") {
             json { "amount" to "KUDOS:9.0" } 
@@ -925,7 +855,8 @@ class CoreBankCashoutApiTest {
     // POST /accounts/{USERNAME}/cashouts
     @Test
     fun create() = bankSetup { _ ->
-        // TODO auth routine
+        authRoutine(HttpMethod.Post, "/accounts/merchant/cashouts")
+
         val req = obj {
             "request_uid" to randShortHashCode()
             "amount_debit" to "KUDOS:1"
@@ -1025,7 +956,8 @@ class CoreBankCashoutApiTest {
     // POST /accounts/{USERNAME}/cashouts/{CASHOUT_ID}/abort
     @Test
     fun abort() = bankSetup { _ ->
-        // TODO auth routine
+        authRoutine(HttpMethod.Post, "/accounts/merchant/cashouts/42/abort")
+
         fillCashoutInfo("customer")
         
         val req = obj {
@@ -1088,7 +1020,8 @@ class CoreBankCashoutApiTest {
     // POST /accounts/{USERNAME}/cashouts/{CASHOUT_ID}/confirm
     @Test
     fun confirm() = bankSetup { db -> 
-        // TODO auth routine
+        authRoutine(HttpMethod.Post, "/accounts/merchant/cashouts/42/confirm")
+
         client.patchA("/accounts/customer") {
             json {
                 "challenge_contact_data" to obj {
@@ -1208,7 +1141,7 @@ class CoreBankCashoutApiTest {
     // GET /accounts/{USERNAME}/cashouts/{CASHOUT_ID}
     @Test
     fun get() = bankSetup { _ ->
-        // TODO auth routine
+        authRoutine(HttpMethod.Get, "/accounts/merchant/cashouts/42")
         fillCashoutInfo("customer")
 
         val amountDebit = TalerAmount("KUDOS:1.5")
@@ -1280,71 +1213,26 @@ class CoreBankCashoutApiTest {
     // GET /accounts/{USERNAME}/cashouts
     @Test
     fun history() = bankSetup { _ ->
-        // TODO auth routine
-
-        suspend fun HttpResponse.assertHistory(size: Int) {
-            assertHistoryIds<Cashouts>(size) {
-                it.cashouts.map { it.cashout_id }
-            }
-        }
-
-        // Empty
-        client.getA("/accounts/customer/cashouts")
-            .assertNoContent()
-
-        // Testing ranges. 
-        repeat(30) {
-            cashout("KUDOS:0.${it+1}")
-        }
-
-        // Default
-        client.getA("/accounts/customer/cashouts")
-            .assertHistory(20)
-
-        // Forward range:
-        client.getA("/accounts/customer/cashouts?delta=10&start=20")
-            .assertHistory(10)
-
-        // Fackward range:
-        client.getA("/accounts/customer/cashouts?delta=-10&start=25")
-            .assertHistory(10)
+        authRoutine(HttpMethod.Get, "/accounts/merchant/cashouts")
+        historyRoutine<Cashouts>(
+            url = "/accounts/customer/cashouts",
+            ids = { it.cashouts.map { it.cashout_id } },
+            registered = listOf({ cashout("KUDOS:0.1") }),
+            polling = false
+        )
     }
 
     // GET /cashouts
     @Test
     fun globalHistory() = bankSetup { _ ->
-        // TODO admin auth routine
-
-        suspend fun HttpResponse.assertHistory(size: Int) {
-            assertHistoryIds<GlobalCashouts>(size) {
-                it.cashouts.map { it.cashout_id }
-            }
-        }
-
-        // Empty
-        client.get("/cashouts") {
-            pwAuth("admin")
-        }.assertNoContent()
-
-        // Testing ranges. 
-        repeat(30) {
-            cashout("KUDOS:0.${it+1}")
-        }
-
-        // Default
-        client.get("/cashouts") {
-            pwAuth("admin")
-        }.assertHistory(20)
-
-        // Forward range:
-        client.get("/cashouts?delta=10&start=20") {
-            pwAuth("admin")
-        }.assertHistory(10)
-
-        // Fackward range:
-        client.get("/cashouts?delta=-10&start=25") {
-            pwAuth("admin")
-        }.assertHistory(10)
+        authRoutine(HttpMethod.Get, "/cashouts", requireAdmin = true)
+        historyRoutine<GlobalCashouts>(
+            url = "/cashouts",
+            ids = { it.cashouts.map { it.cashout_id } },
+            registered = listOf({ cashout("KUDOS:0.1") }),
+            polling = false,
+            auth = "admin"
+        )
     }
 
     @Test
diff --git a/bank/src/test/kotlin/RevenueApiTest.kt 
b/bank/src/test/kotlin/RevenueApiTest.kt
index e54ab7e4..4432ce54 100644
--- a/bank/src/test/kotlin/RevenueApiTest.kt
+++ b/bank/src/test/kotlin/RevenueApiTest.kt
@@ -33,113 +33,30 @@ class RevenueApiTest {
     @Test
     fun history() = bankSetup {
         setMaxDebt("exchange", TalerAmount("KUDOS:1000000"))
-
-        suspend fun HttpResponse.assertHistory(size: Int) {
-            assertHistoryIds<MerchantIncomingHistory>(size) {
-                it.incoming_transactions.map { it.row_id }
-            }
-        }
-
-        suspend fun latestId(): Long {
-            return 
client.getA("/accounts/merchant/taler-revenue/history?delta=-1")
-                
.assertOkJson<MerchantIncomingHistory>().incoming_transactions[0].row_id
-        }
-
-        suspend fun testTrigger(trigger: suspend () -> Unit) {
-            coroutineScope {
-                val id = latestId()
-                launch {
-                    assertTime(100, 200) {
-                        
client.getA("/accounts/merchant/taler-revenue/history?delta=7&start=$id&long_poll_ms=1000")
 
-                            .assertHistory(1)
-                    }
-                }
-                delay(100)
-                trigger()
-            }
-        }
-
-        // TODO auth routine
-
-        // Check error when no transactions
-        client.getA("/accounts/merchant/taler-revenue/history?delta=7")
-            .assertNoContent()
-
-        // Gen three transactions using clean transfer logic
-        repeat(3) {
-            transfer("KUDOS:10")
-        }
-        // Should not show up in the revenue API history
-        tx("exchange", "KUDOS:10", "merchant", "bogus")
-        // Merchant pays customer once, but that should not appear in the 
result
-        addIncoming("KUDOS:10")
-        // Gen two transactions using raw bank transaction logic
-        repeat(2) {
-            tx("exchange", "KUDOS:10", "merchant", 
OutgoingTxMetadata(randShortHashCode(), 
ExchangeUrl("http://exchange.example.com/";)).encode())
-        }
-
-        // Check ignore bogus subject
-        client.getA("/accounts/merchant/taler-revenue/history?delta=7")
-            .assertHistory(5)
-        
-        // Check skip bogus subject
-        client.getA("/accounts/merchant/taler-revenue/history?delta=5")
-            .assertHistory(5)
-
-        // Check no useless polling
-        assertTime(0, 100) {
-            
client.getA("/accounts/merchant/taler-revenue/history?delta=-6&long_poll_ms=1000")
-                .assertHistory(5)
-        }
-
-        // Check no polling when find transaction
-        assertTime(0, 100) {
-            
client.getA("/accounts/merchant/taler-revenue/history?delta=6&long_poll_ms=1000")
-                .assertHistory(5)
-        }
-
-        coroutineScope {
-            val id = latestId()
-            launch {  // Check polling succeed forward
-                assertTime(100, 200) {
-                    
client.getA("/accounts/merchant/taler-revenue/history?delta=2&start=$id&long_poll_ms=1000")
-                        .assertHistory(1)
+        authRoutine(HttpMethod.Get, "/accounts/merchant/taler-revenue/history")
+        historyRoutine<MerchantIncomingHistory>(
+            url = "/accounts/merchant/taler-revenue/history",
+            ids = { it.incoming_transactions.map { it.row_id } },
+            registered = listOf(
+                { 
+                    // Transactions using clean add incoming logic
+                    transfer("KUDOS:10")
+                },
+                { 
+                    // Transactions using raw bank transaction logic
+                    tx("exchange", "KUDOS:10", "merchant", 
OutgoingTxMetadata(randShortHashCode(), 
ExchangeUrl("http://exchange.example.com/";)).encode())
                 }
-            }
-            launch {  // Check polling timeout forward
-                assertTime(200, 300) {
-                    
client.getA("/accounts/merchant/taler-revenue/history?delta=1&start=${id+3}&long_poll_ms=200")
-                        .assertNoContent()
+            ),
+            ignored = listOf(
+                {
+                    // Ignore malformed incoming transaction
+                    tx("merchant", "KUDOS:10", "exchange", "ignored")
+                },
+                {
+                    // Ignore malformed outgoing transaction
+                    tx("exchange", "KUDOS:10", "merchant", "ignored")
                 }
-            }
-            delay(100)
-            transfer("KUDOS:10")
-        }
-
-        // Test trigger by raw transaction
-        testTrigger { 
-            tx("exchange", "KUDOS:10", "merchant", 
OutgoingTxMetadata(randShortHashCode(), 
ExchangeUrl("http://exchange.example.com/";)).encode())
-        } 
-        // Test trigger by outgoing
-        testTrigger { transfer("KUDOS:9") }
-
-        // Testing ranges.
-        repeat(5) {
-            transfer("KUDOS:10")
-        }
-
-        val id = latestId()
-
-        // forward range:
-        client.getA("/accounts/merchant/taler-revenue/history?delta=10")
-            .assertHistory(10)
-        
client.getA("/accounts/merchant/taler-revenue/history?delta=10&start=4")
-            .assertHistory(10)
-
-        // backward range:
-        client.getA("/accounts/merchant/taler-revenue/history?delta=-10")
-            .assertHistory(10)
-        
client.getA("/accounts/merchant/taler-revenue/history?delta=-10&start=${id-4}")
-            .assertHistory(10)
+            )
+        )
     }
 }
\ No newline at end of file
diff --git a/bank/src/test/kotlin/WireGatewayApiTest.kt 
b/bank/src/test/kotlin/WireGatewayApiTest.kt
index c25b6c73..7d90fd69 100644
--- a/bank/src/test/kotlin/WireGatewayApiTest.kt
+++ b/bank/src/test/kotlin/WireGatewayApiTest.kt
@@ -30,47 +30,6 @@ import org.junit.Test
 import tech.libeufin.bank.*
 
 class WireGatewayApiTest {
-    // Test endpoint is correctly authenticated 
-    suspend fun ApplicationTestBuilder.authRoutine(path: String, body: 
JsonObject? = null, method: HttpMethod = HttpMethod.Post, requireAdmin: Boolean 
= false) {
-        // No body when authentication must happen before parsing the body
-        
-        // Unknown account
-        client.request(path) {
-            this.method = method
-            basicAuth("unknown", "password")
-        }.assertUnauthorized()
-
-        // Wrong password
-        client.request(path) {
-            this.method = method
-            basicAuth("merchant", "wrong-password")
-        }.assertUnauthorized()
-
-        // Wrong account
-        client.request(path) {
-            this.method = method
-            basicAuth("exchange", "merchant-password")
-        }.assertUnauthorized()
-
-        if (requireAdmin) {
-             // Not exchange account
-            client.request(path) {
-                this.method = method
-                if (body != null) json(body)
-                pwAuth("merchant")
-            }.assertUnauthorized()
-        }
-
-        // Not exchange account
-        client.request(path) {
-            this.method = method
-            if (body != null) json(body)
-            if (requireAdmin)
-                pwAuth("admin")
-            else pwAuth("merchant")
-        }.assertConflict(TalerErrorCode.BANK_ACCOUNT_IS_NOT_EXCHANGE)
-    }
-
     // Testing the POST /transfer call from the TWG API.
     @Test
     fun transfer() = bankSetup { _ -> 
@@ -82,7 +41,7 @@ class WireGatewayApiTest {
             "credit_account" to merchantPayto
         };
 
-        authRoutine("/accounts/merchant/taler-wire-gateway/transfer", 
valid_req)
+        authRoutine(HttpMethod.Post, 
"/accounts/merchant/taler-wire-gateway/transfer", valid_req)
 
         // Checking exchange debt constraint.
         client.postA("/accounts/exchange/taler-wire-gateway/transfer") {
@@ -169,115 +128,35 @@ class WireGatewayApiTest {
     fun historyIncoming() = bankSetup { 
         // Give Foo reasonable debt allowance:
         setMaxDebt("merchant", TalerAmount("KUDOS:1000"))
-
-        suspend fun HttpResponse.assertHistory(size: Int) {
-            assertHistoryIds<IncomingHistory>(size) {
-                it.incoming_transactions.map { it.row_id }
-            }
-        }
-
-        suspend fun latestId(): Long {
-            return 
client.getA("/accounts/exchange/taler-wire-gateway/history/incoming?delta=-1")
-                
.assertOkJson<IncomingHistory>().incoming_transactions[0].row_id
-        }
-
-        suspend fun testTrigger(trigger: suspend () -> Unit) {
-            coroutineScope {
-                val id = latestId()
-                launch {
-                    assertTime(100, 200) {
-                        
client.getA("/accounts/exchange/taler-wire-gateway/history/incoming?delta=7&start=$id&long_poll_ms=1000")
 
-                            .assertHistory(1)
-                    }
+        authRoutine(HttpMethod.Get, 
"/accounts/merchant/taler-wire-gateway/history/incoming")
+        historyRoutine<IncomingHistory>(
+            url = "/accounts/exchange/taler-wire-gateway/history/incoming",
+            ids = { it.incoming_transactions.map { it.row_id } },
+            registered = listOf(
+                { 
+                    // Transactions using clean add incoming logic
+                    addIncoming("KUDOS:10") 
+                },
+                { 
+                    // Transactions using raw bank transaction logic
+                    tx("merchant", "KUDOS:10", "exchange", 
IncomingTxMetadata(randShortHashCode()).encode())
+                },
+                {
+                    // Transaction using withdraw logic
+                    withdrawal("KUDOS:9")
                 }
-                delay(100)
-                trigger()
-            }
-        }
-
-        
authRoutine("/accounts/merchant/taler-wire-gateway/history/incoming?delta=7", 
method = HttpMethod.Get)
-
-        // Check error when no transactions
-        
client.getA("/accounts/exchange/taler-wire-gateway/history/incoming?delta=7")
-            .assertNoContent()
-
-        // Gen three transactions using clean add incoming logic
-        repeat(3) {
-            addIncoming("KUDOS:10")
-        }
-        // Should not show up in the taler wire gateway API history
-        tx("merchant", "KUDOS:10", "exchange", "bogus")
-        // Exchange pays merchant once, but that should not appear in the 
result
-        tx("exchange", "KUDOS:10", "merchant", "ignored")
-        // Gen one transaction using raw bank transaction logic
-        tx("merchant", "KUDOS:10", "exchange", 
IncomingTxMetadata(randShortHashCode()).encode())
-        // Gen one transaction using withdraw logic
-        withdrawal("KUDOS:9")
-
-        // Check ignore bogus subject
-        
client.getA("/accounts/exchange/taler-wire-gateway/history/incoming?delta=7") 
-            .assertHistory(5)
-        
-        // Check skip bogus subject
-        
client.getA("/accounts/exchange/taler-wire-gateway/history/incoming?delta=5")
-            .assertHistory(5)
-        
-        // Check no useless polling
-        assertTime(0, 100) {
-            
client.getA("/accounts/exchange/taler-wire-gateway/history/incoming?delta=-6&long_poll_ms=1000")
-                .assertHistory(5)
-        }
-
-        // Check no polling when find transaction
-        assertTime(0, 100) {
-            
client.getA("/accounts/exchange/taler-wire-gateway/history/incoming?delta=6&long_poll_ms=1000")
-                .assertHistory(5)
-        }
-
-        coroutineScope {
-            val id = latestId()
-            launch {  // Check polling succeed
-                assertTime(100, 200) {
-                    
client.getA("/accounts/exchange/taler-wire-gateway/history/incoming?delta=2&start=$id&long_poll_ms=1000")
-                        .assertHistory(1)
+            ),
+            ignored = listOf(
+                {
+                    // Ignore malformed incoming transaction
+                    tx("merchant", "KUDOS:10", "exchange", "ignored")
+                },
+                {
+                    // Ignore malformed outgoing transaction
+                    tx("exchange", "KUDOS:10", "merchant", "ignored")
                 }
-            }
-            launch {  // Check polling timeout
-                assertTime(200, 300) {
-                    
client.getA("/accounts/exchange/taler-wire-gateway/history/incoming?delta=1&start=${id+2}&long_poll_ms=200")
-                        .assertNoContent()
-                }
-            }
-            delay(100)
-            addIncoming("KUDOS:10")
-        }
-
-        // Test trigger by raw transaction
-        testTrigger { 
-            tx("merchant", "KUDOS:10", "exchange", 
IncomingTxMetadata(randShortHashCode()).encode())
-        } 
-        // Test trigger by withdraw operation
-        testTrigger { withdrawal("KUDOS:9") }
-        // Test trigger by incoming
-        testTrigger { addIncoming("KUDOS:9") }
-
-        // Testing ranges.
-        repeat(5) {
-            addIncoming("KUDOS:10")
-        }
-        val id = latestId()
-
-        // forward range:
-        
client.getA("/accounts/exchange/taler-wire-gateway/history/incoming?delta=10")
-            .assertHistory(10)
-        
client.getA("/accounts/exchange/taler-wire-gateway/history/incoming?delta=10&start=4")
-            .assertHistory(10)
-
-        // backward range:
-        
client.getA("/accounts/exchange/taler-wire-gateway/history/incoming?delta=-10")
-            .assertHistory(10)
-        
client.getA("/accounts/exchange/taler-wire-gateway/history/incoming?delta=-10&start=${id-4}")
-            .assertHistory(10)
+            )
+        )
     }
 
     
@@ -287,113 +166,31 @@ class WireGatewayApiTest {
     @Test
     fun historyOutgoing() = bankSetup {
         setMaxDebt("exchange", TalerAmount("KUDOS:1000000"))
-
-        suspend fun HttpResponse.assertHistory(size: Int) {
-            assertHistoryIds<OutgoingHistory>(size) {
-                it.outgoing_transactions.map { it.row_id }
-            }
-        }
-
-        suspend fun latestId(): Long {
-            return 
client.getA("/accounts/exchange/taler-wire-gateway/history/outgoing?delta=-1")
-                
.assertOkJson<OutgoingHistory>().outgoing_transactions[0].row_id
-        }
-
-        suspend fun testTrigger(trigger: suspend () -> Unit) {
-            coroutineScope {
-                val id = latestId()
-                launch {
-                    assertTime(100, 200) {
-                        
client.getA("/accounts/exchange/taler-wire-gateway/history/outgoing?delta=7&start=$id&long_poll_ms=1000")
 
-                            .assertHistory(1)
-                    }
-                }
-                delay(100)
-                trigger()
-            }
-        }
-
-        
authRoutine("/accounts/merchant/taler-wire-gateway/history/outgoing?delta=7", 
method = HttpMethod.Get)
-
-        // Check error when no transactions
-        
client.getA("/accounts/exchange/taler-wire-gateway/history/outgoing?delta=7")
-            .assertNoContent()
-
-        // Gen three transactions using clean transfer logic
-        repeat(3) {
-            transfer("KUDOS:10")
-        }
-        // Should not show up in the taler wire gateway API history
-        tx("exchange", "KUDOS:10", "merchant", "bogus")
-        // Merchant pays exchange once, but that should not appear in the 
result
-        tx("merchant", "KUDOS:10", "exchange", "ignored")
-        // Gen two transactions using raw bank transaction logic
-        repeat(2) {
-            tx("exchange", "KUDOS:10", "merchant", 
OutgoingTxMetadata(randShortHashCode(), 
ExchangeUrl("http://exchange.example.com/";)).encode())
-        }
-
-        // Check ignore bogus subject
-        
client.getA("/accounts/exchange/taler-wire-gateway/history/outgoing?delta=7") 
-            .assertHistory(5)
-        
-        // Check skip bogus subject
-        
client.getA("/accounts/exchange/taler-wire-gateway/history/outgoing?delta=5")
-            .assertHistory(5)
-
-        // Check no useless polling
-        assertTime(0, 100) {
-            
client.getA("/accounts/exchange/taler-wire-gateway/history/outgoing?delta=-6&long_poll_ms=1000")
-                .assertHistory(5)
-        }
-
-        // Check no polling when find transaction
-        assertTime(0, 100) {
-            
client.getA("/accounts/exchange/taler-wire-gateway/history/outgoing?delta=6&long_poll_ms=1000")
-                .assertHistory(5)
-        }
-
-        coroutineScope {
-            val id = latestId()
-            launch {  // Check polling succeed forward
-                assertTime(100, 200) {
-                    
client.getA("/accounts/exchange/taler-wire-gateway/history/outgoing?delta=2&start=$id&long_poll_ms=1000")
-                        .assertHistory(1)
+        authRoutine(HttpMethod.Get, 
"/accounts/merchant/taler-wire-gateway/history/outgoing")
+        historyRoutine<OutgoingHistory>(
+            url = "/accounts/exchange/taler-wire-gateway/history/outgoing",
+            ids = { it.outgoing_transactions.map { it.row_id } },
+            registered = listOf(
+                { 
+                    // Transactions using clean add incoming logic
+                    transfer("KUDOS:10")
+                },
+                { 
+                    // Transactions using raw bank transaction logic
+                    tx("exchange", "KUDOS:10", "merchant", 
OutgoingTxMetadata(randShortHashCode(), 
ExchangeUrl("http://exchange.example.com/";)).encode())
                 }
-            }
-            launch {  // Check polling timeout forward
-                assertTime(200, 300) {
-                    
client.getA("/accounts/exchange/taler-wire-gateway/history/outgoing?delta=1&start=${id+2}&long_poll_ms=200")
-                        .assertNoContent()
+            ),
+            ignored = listOf(
+                {
+                    // Ignore malformed incoming transaction
+                    tx("merchant", "KUDOS:10", "exchange", "ignored")
+                },
+                {
+                    // Ignore malformed outgoing transaction
+                    tx("exchange", "KUDOS:10", "merchant", "ignored")
                 }
-            }
-            delay(100)
-            transfer("KUDOS:10")
-        }
-
-        // Test trigger by raw transaction
-        testTrigger { 
-            tx("exchange", "KUDOS:10", "merchant", 
OutgoingTxMetadata(randShortHashCode(), 
ExchangeUrl("http://exchange.example.com/";)).encode())
-        } 
-        // Test trigger by outgoing
-        testTrigger { transfer("KUDOS:9") }
-
-        // Testing ranges
-        repeat(5) {
-            transfer("KUDOS:10")
-        }
-        val id = latestId()
-
-        // forward range:
-        
client.getA("/accounts/exchange/taler-wire-gateway/history/outgoing?delta=10")
-            .assertHistory(10)
-        
client.getA("/accounts/exchange/taler-wire-gateway/history/outgoing?delta=10&start=4")
-            .assertHistory(10)
-
-        // backward range:
-        
client.getA("/accounts/exchange/taler-wire-gateway/history/outgoing?delta=-10")
-            .assertHistory(10)
-        
client.getA("/accounts/exchange/taler-wire-gateway/history/outgoing?delta=-10&start=${id-4}")
-            .assertHistory(10)
+            )
+        )
     }
 
     // Testing the /admin/add-incoming call from the TWG API.
@@ -405,7 +202,7 @@ class WireGatewayApiTest {
             "debit_account" to merchantPayto
         };
 
-        
authRoutine("/accounts/merchant/taler-wire-gateway/admin/add-incoming", 
valid_req, requireAdmin = true)
+        authRoutine(HttpMethod.Post, 
"/accounts/merchant/taler-wire-gateway/admin/add-incoming", valid_req, 
requireAdmin = true)
 
         // Checking exchange debt constraint.
         
client.postA("/accounts/exchange/taler-wire-gateway/admin/add-incoming") {
diff --git a/bank/src/test/kotlin/routines.kt b/bank/src/test/kotlin/routines.kt
new file mode 100644
index 00000000..c2eb3d04
--- /dev/null
+++ b/bank/src/test/kotlin/routines.kt
@@ -0,0 +1,212 @@
+/*
+ * This file is part of LibEuFin.
+ * Copyright (C) 2023 Taler Systems S.A.
+
+ * LibEuFin is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation; either version 3, or
+ * (at your option) any later version.
+
+ * LibEuFin is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Affero General
+ * Public License for more details.
+
+ * You should have received a copy of the GNU Affero General Public
+ * License along with LibEuFin; see the file COPYING.  If not, see
+ * <http://www.gnu.org/licenses/>
+ */
+
+import tech.libeufin.bank.*
+import io.ktor.client.statement.HttpResponse
+import io.ktor.server.testing.ApplicationTestBuilder
+import io.ktor.client.request.*
+import io.ktor.http.*
+import kotlinx.coroutines.*
+import kotlinx.serialization.json.*
+import net.taler.common.errorcodes.TalerErrorCode
+
+// Test endpoint is correctly authenticated 
+suspend fun ApplicationTestBuilder.authRoutine(
+    method: HttpMethod, 
+    path: String, 
+    body: JsonObject? = null, 
+    requireExchange: Boolean = false, 
+    requireAdmin: Boolean = false,
+    withAdmin: Boolean = false
+) {
+    // No body when authentication must happen before parsing the body
+    
+    // Unknown account
+    client.request(path) {
+        this.method = method
+        basicAuth("unknown", "password")
+    }.assertUnauthorized()
+
+    // Wrong password
+    client.request(path) {
+        this.method = method
+        basicAuth("merchant", "wrong-password")
+    }.assertUnauthorized()
+
+    // Wrong account
+    client.request(path) {
+        this.method = method
+        basicAuth("exchange", "merchant-password")
+    }.assertUnauthorized()
+
+    if (requireAdmin) {
+         // Not exchange account
+        client.request(path) {
+            this.method = method
+            pwAuth("merchant")
+        }.assertUnauthorized()
+    } else if (!withAdmin) {
+        // Check no admin
+        client.request(path) {
+            this.method = method
+            pwAuth("admin")
+        }.assertUnauthorized()
+    }
+
+    if (requireExchange) {
+        // Not exchange account
+        client.request(path) {
+            this.method = method
+            if (body != null) json(body)
+            pwAuth(if (requireAdmin) "admin" else "merchant")
+        }.assertConflict(TalerErrorCode.BANK_ACCOUNT_IS_NOT_EXCHANGE)
+    }
+}
+
+inline suspend fun <reified B> ApplicationTestBuilder.historyRoutine(
+    url: String,
+    crossinline ids: (B) -> List<Long>,
+    registered: List<suspend () -> Unit>,
+    ignored: List<suspend () -> Unit> = listOf(),
+    polling: Boolean = true,
+    auth: String? = null
+) {
+    // Get history 
+    val history: suspend (String) -> HttpResponse = { params: String ->
+        client.get("$url?$params") {
+            pwAuth(auth)
+        }
+    }
+    // Check history is following specs
+    val assertHistory: suspend HttpResponse.(Int) -> Unit = { size: Int ->
+        assertHistoryIds<B>(size, ids)
+    }
+    // Get latest registered id
+    val latestId: suspend () -> Long = {
+        history("delta=-1").assertOkJson<B>().run { ids(this)[0] }
+    }
+
+    // Check error when no transactions
+    history("delta=7").assertNoContent()
+
+    // Run interleaved registered and ignore transactions
+    val registered_iter = registered.iterator()
+    val ignored_iter = ignored.iterator()
+    while (registered_iter.hasNext() || ignored_iter.hasNext()) {
+        if (registered_iter.hasNext()) registered_iter.next()()
+        if (ignored_iter.hasNext()) ignored_iter.next()()
+    }
+
+
+    val nbRegistered = registered.size
+    val nbIgnored = ignored.size
+    val nbTotal = nbRegistered + nbIgnored
+
+    println(nbRegistered)
+
+    println("simple")
+
+    // Check ignored
+    history("delta=$nbTotal").assertHistory(nbRegistered)
+    // Check skip ignored
+    history("delta=$nbRegistered").assertHistory(nbRegistered)
+
+    if (polling) {
+        // Check no polling when we cannot have more transactions
+        assertTime(0, 100) {
+            history("delta=-${nbRegistered+1}&long_poll_ms=1000")
+                .assertHistory(nbRegistered)
+        }
+        // Check no polling when already find transactions even if less than 
delta
+        assertTime(0, 100) {
+            history("delta=${nbRegistered+1}&long_poll_ms=1000")
+                .assertHistory(nbRegistered)
+        }
+
+        println("polling")
+
+        // Check polling
+        coroutineScope {
+            val id = latestId()
+            launch {  // Check polling succeed
+                assertTime(100, 200) {
+                    history("delta=2&start=$id&long_poll_ms=1000")
+                        .assertHistory(1)
+                }
+            }
+            launch {  // Check polling timeout
+                assertTime(200, 300) {
+                    history("delta=1&start=${id+10}&long_poll_ms=200")
+                        .assertNoContent()
+                }
+            }
+            delay(100)
+            println(registered.size)
+            registered[0]()
+        }
+
+        println("triggers")
+
+        // Test triggers
+        for (register in registered) {
+            coroutineScope {
+                val id = latestId()
+                launch {
+                    assertTime(100, 200) {
+                        history("delta=7&start=$id&long_poll_ms=1000") 
+                            .assertHistory(1)
+                    }
+                }
+                delay(100)
+                register()
+            }
+        }
+
+        // Test doesn't trigger
+        coroutineScope {
+            val id = latestId()
+            launch {
+                assertTime(200, 300) {
+                    history("delta=7&start=$id&long_poll_ms=200") 
+                        .assertNoContent()
+                }
+            }
+            delay(100)
+            for (ignore in ignored) {
+                ignore()
+            }
+        }
+    }
+
+    println("range")
+
+    // Testing ranges.
+    repeat(20) {
+        registered[0]()
+    }
+    val id = latestId()
+    // Default
+    history("").assertHistory(20)
+    // forward range:
+    history("delta=10").assertHistory(10)
+    history("delta=10&start=4").assertHistory(10)
+    // backward range:
+    history("delta=-10").assertHistory(10)
+    history("delta=-10&start=${id-4}").assertHistory(10)
+}
\ No newline at end of file

-- 
To stop receiving notification emails like this one, please contact
gnunet@gnunet.org.



reply via email to

[Prev in Thread] Current Thread [Next in Thread]