Skip to content

Commit 694378e

Browse files
committed
test: add mainnet probe devtools
1 parent 87c788e commit 694378e

2 files changed

Lines changed: 96 additions & 1 deletion

File tree

app/src/debug/java/to/bitkit/dev/DevToolsProvider.kt

Lines changed: 83 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,9 +15,12 @@ import kotlinx.serialization.Serializable
1515
import kotlinx.serialization.json.Json
1616
import to.bitkit.async.ServiceQueue
1717
import to.bitkit.repositories.LightningRepo
18+
import to.bitkit.repositories.ProbeOutcome
1819
import to.bitkit.utils.Logger
20+
import kotlin.time.Duration.Companion.seconds
1921

2022
private const val TAG = "DevToolsProvider"
23+
private val DEV_JSON = Json { encodeDefaults = true }
2124

2225
class DevToolsProvider : ContentProvider() {
2326

@@ -56,6 +59,7 @@ private sealed interface DevCommand {
5659
companion object {
5760
fun parse(method: String, arg: String?): DevCommand? = when (method) {
5861
CreateInvoice.METHOD -> CreateInvoice.parse(arg)
62+
ProbeInvoice.METHOD -> ProbeInvoice.parse(arg)
5963
else -> null
6064
}
6165
}
@@ -80,6 +84,44 @@ private sealed interface DevCommand {
8084
},
8185
)
8286
}
87+
88+
data class ProbeInvoice(val args: Args) : DevCommand {
89+
companion object {
90+
const val METHOD = "probeInvoice"
91+
fun parse(arg: String?) = ProbeInvoice(arg.deserialize<Args>())
92+
}
93+
94+
@Serializable
95+
data class Args(
96+
val targetName: String? = null,
97+
val bolt11: String,
98+
val amountMsat: ULong? = null,
99+
val amountSats: ULong? = null,
100+
val timeoutSeconds: Long = 90,
101+
)
102+
103+
override suspend fun execute(deps: DevToolsProvider.Dependencies): DevResult {
104+
val amountSats = args.amountSats ?: args.amountMsat?.div(1_000u)
105+
val timeout = args.timeoutSeconds.coerceAtLeast(1).seconds
106+
107+
Logger.info(
108+
"Sending probe for target '${args.targetName ?: "unknown"}' amountSats='${amountSats ?: "invoice"}'",
109+
context = TAG,
110+
)
111+
112+
return deps.lightningRepo().sendProbeForInvoice(args.bolt11, amountSats)
113+
.fold(
114+
onSuccess = {
115+
deps.lightningRepo().waitForProbeOutcome(it.paymentIds, timeout)
116+
.fold(
117+
onSuccess = { outcome -> outcome.toDevResult(it.paymentIds) },
118+
onFailure = { error -> DevResult.ProbeFailure.from(error, it.paymentIds) },
119+
)
120+
},
121+
onFailure = { DevResult.ProbeFailure.from(it) },
122+
)
123+
}
124+
}
83125
}
84126

85127
@Serializable
@@ -91,9 +133,49 @@ private sealed interface DevResult {
91133

92134
@Serializable data class Invoice(val bolt11: String) : DevResult
93135

136+
@Serializable
137+
data class ProbeSuccess(
138+
val success: Boolean = true,
139+
val paymentId: String,
140+
val paymentHash: String,
141+
val paymentIds: List<String>,
142+
) : DevResult
143+
144+
@Serializable
145+
data class ProbeFailure(
146+
val success: Boolean = false,
147+
val message: String? = null,
148+
val paymentId: String? = null,
149+
val paymentHash: String? = null,
150+
val shortChannelId: ULong? = null,
151+
val paymentIds: List<String> = emptyList(),
152+
) : DevResult {
153+
companion object {
154+
fun from(error: Throwable, paymentIds: Set<String> = emptySet()) = ProbeFailure(
155+
message = error.message,
156+
paymentIds = paymentIds.toList(),
157+
)
158+
}
159+
}
160+
94161
@Serializable data class Error(val message: String? = null) : DevResult
95162

96-
fun toBundle() = bundleOf(KEY_RESULT to Json.encodeToString(this))
163+
fun toBundle() = bundleOf(KEY_RESULT to DEV_JSON.encodeToString(this))
164+
}
165+
166+
private fun ProbeOutcome.toDevResult(paymentIds: Set<String>): DevResult = when (this) {
167+
is ProbeOutcome.Success -> DevResult.ProbeSuccess(
168+
paymentId = paymentId,
169+
paymentHash = paymentHash,
170+
paymentIds = paymentIds.toList(),
171+
)
172+
is ProbeOutcome.Failure -> DevResult.ProbeFailure(
173+
message = "Probe failed",
174+
paymentId = paymentId,
175+
paymentHash = paymentHash,
176+
shortChannelId = shortChannelId,
177+
paymentIds = paymentIds.toList(),
178+
)
97179
}
98180

99181
private inline fun <reified T> String?.deserialize(): T =

app/src/test/java/to/bitkit/repositories/LightningRepoTest.kt

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1267,6 +1267,19 @@ class LightningRepoTest : BaseUnitTest() {
12671267
assertEquals(setOf(probePaymentA, probePaymentB), result.getOrThrow().paymentIds)
12681268
}
12691269

1270+
@Test
1271+
fun `sendProbeForInvoice delegates amount probes when sats are provided`() = test {
1272+
startNodeForTesting()
1273+
whenever(lightningService.sendProbesUsingAmount("lnbc1", 42_000uL))
1274+
.thenReturn(Result.success(setOf(probePaymentA)))
1275+
1276+
val result = sut.sendProbeForInvoice("lnbc1", amountSats = 42uL)
1277+
1278+
assertTrue(result.isSuccess)
1279+
assertEquals(setOf(probePaymentA), result.getOrThrow().paymentIds)
1280+
verifyBlocking(lightningService) { sendProbesUsingAmount("lnbc1", 42_000uL) }
1281+
}
1282+
12701283
@Test
12711284
fun `sendProbeForNode delegates to keysend probe and returns payment IDs`() = test {
12721285
startNodeForTesting()

0 commit comments

Comments
 (0)