commit 1541b50689decb3c74abfb58c7d47e9dc9d05bc8
parent 348a6945996eed2c180ff0d115ef00dbb32a659a
Author: Antoine A <>
Date: Mon, 20 Nov 2023 17:11:28 +0000
Common history test routine
Diffstat:
4 files changed, 271 insertions(+), 435 deletions(-)
diff --git a/bank/src/test/kotlin/CoreBankApiTest.kt b/bank/src/test/kotlin/CoreBankApiTest.kt
@@ -548,70 +548,39 @@ class CoreBankTransactionsApiTest {
// 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("/accounts/customer/transactions", method = HttpMethod.Get)
+ 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
@@ -1281,70 +1250,25 @@ class CoreBankCashoutApiTest {
@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)
+ 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)
+ 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
@@ -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)
+ 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
@@ -169,115 +169,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)
- }
- }
- 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)
+ 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")
}
- }
- 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()
+ ),
+ ignored = listOf(
+ {
+ // Ignore malformed incoming transaction
+ tx("merchant", "KUDOS:10", "exchange", "ignored")
+ },
+ {
+ // Ignore malformed outgoing transaction
+ tx("exchange", "KUDOS:10", "merchant", "ignored")
}
- }
- 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 +207,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)
+ 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.
diff --git a/bank/src/test/kotlin/routines.kt b/bank/src/test/kotlin/routines.kt
@@ -0,0 +1,156 @@
+/*
+ * 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 kotlinx.coroutines.*
+
+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