Skip to content

Commit 9fb307d

Browse files
chavicspacebear21
authored andcommitted
Align FFI tests with shared fixtures and polling
1 parent aff2153 commit 9fb307d

9 files changed

Lines changed: 96 additions & 55 deletions

File tree

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
library test_utils;
2+
3+
export "payjoin.dart"
4+
show
5+
BitcoindEnv,
6+
BitcoindInstance,
7+
RpcClient,
8+
TestServices,
9+
initBitcoindSenderReceiver,
10+
originalPsbt;

payjoin-ffi/dart/test/test_payjoin_integration_test.dart

Lines changed: 41 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -6,11 +6,12 @@ import 'package:test/test.dart';
66
import "package:convert/convert.dart";
77

88
import "package:payjoin/payjoin.dart" as payjoin;
9+
import "package:payjoin/test_utils.dart" as test_utils;
910

10-
late payjoin.BitcoindEnv env;
11-
late payjoin.BitcoindInstance bitcoind;
12-
late payjoin.RpcClient receiver;
13-
late payjoin.RpcClient sender;
11+
late test_utils.BitcoindEnv env;
12+
late test_utils.BitcoindInstance bitcoind;
13+
late test_utils.RpcClient receiver;
14+
late test_utils.RpcClient sender;
1415

1516
class InMemoryReceiverPersister
1617
implements payjoin.JsonReceiverSessionPersister {
@@ -410,11 +411,11 @@ void main() {
410411
);
411412

412413
// Use a real v2 payjoin URI from the test harness to avoid v1 panics.
413-
final envLocal = payjoin.initBitcoindSenderReceiver();
414+
final envLocal = test_utils.initBitcoindSenderReceiver();
414415
final receiverRpc = envLocal.getReceiver();
415416
final receiverAddress =
416417
jsonDecode(receiverRpc.call("getnewaddress", [])) as String;
417-
final services = payjoin.TestServices.initialize();
418+
final services = test_utils.TestServices.initialize();
418419
services.waitForServicesReady();
419420
final directory = services.directoryUrl();
420421
final ohttpKeys = services.fetchOhttpKeys();
@@ -425,8 +426,7 @@ void main() {
425426
ohttpKeys,
426427
).build().save(recvPersister).pjUri();
427428

428-
final psbt =
429-
"cHNidP8BAHMCAAAAAY8nutGgJdyYGXWiBEb45Hoe9lWGbkxh/6bNiOJdCDuDAAAAAAD+////AtyVuAUAAAAAF6kUHehJ8GnSdBUOOv6ujXLrWmsJRDCHgIQeAAAAAAAXqRR3QJbbz0hnQ8IvQ0fptGn+votneofTAAAAAAEBIKgb1wUAAAAAF6kU3k4ekGHKWRNbA1rV5tR5kEVDVNCHAQcXFgAUx4pFclNVgo1WWAdN1SYNX8tphTABCGsCRzBEAiB8Q+A6dep+Rz92vhy26lT0AjZn4PRLi8Bf9qoB/CMk0wIgP/Rj2PWZ3gEjUkTlhDRNAQ0gXwTO7t9n+V14pZ6oljUBIQMVmsAaoNWHVMS02LfTSe0e388LNitPa1UQZyOihY+FFgABABYAFEb2Giu6c4KO5YW0pfw3lGp9jMUUAAA=";
429+
final psbt = test_utils.originalPsbt();
430430
// Large enough to overflow fee * weight but still parsable as Dart int.
431431
const overflowFeeRate = 5000000000000; // sat/kwu
432432
expect(
@@ -444,13 +444,13 @@ void main() {
444444
});
445445

446446
test('Test integration v2 to v2', () async {
447-
env = payjoin.initBitcoindSenderReceiver();
447+
env = test_utils.initBitcoindSenderReceiver();
448448
bitcoind = env.getBitcoind();
449449
receiver = env.getReceiver();
450450
sender = env.getSender();
451451
var receiver_address =
452452
jsonDecode(receiver.call("getnewaddress", [])) as String;
453-
var services = payjoin.TestServices.initialize();
453+
var services = test_utils.TestServices.initialize();
454454

455455
services.waitForServicesReady();
456456
var directory = services.directoryUrl();
@@ -527,25 +527,39 @@ void main() {
527527

528528
// **********************
529529
// Inside the Sender:
530-
// Sender checks, isngs, finalizes, extracts, and broadcasts
530+
// Sender checks, signs, finalizes, extracts, and broadcasts
531531
// Replay post fallback to get the response
532-
payjoin.RequestOhttpContext ohttp_context_request = send_ctx
533-
.createPollRequest(ohttp_relay);
534-
var final_response = await agent.post(
535-
Uri.parse(ohttp_context_request.request.url),
536-
headers: {"Content-Type": ohttp_context_request.request.contentType},
537-
body: ohttp_context_request.request.body,
538-
);
539-
var checked_payjoin_proposal_psbt = send_ctx
540-
.processResponse(
541-
final_response.bodyBytes,
542-
ohttp_context_request.ohttpCtx,
543-
)
544-
.save(sender_persister);
545-
expect(checked_payjoin_proposal_psbt, isNotNull);
532+
payjoin.PollingForProposalTransitionOutcome? poll_outcome;
533+
var attempts = 0;
534+
while (true) {
535+
payjoin.RequestOhttpContext ohttp_context_request = send_ctx
536+
.createPollRequest(ohttp_relay);
537+
var final_response = await agent.post(
538+
Uri.parse(ohttp_context_request.request.url),
539+
headers: {"Content-Type": ohttp_context_request.request.contentType},
540+
body: ohttp_context_request.request.body,
541+
);
542+
poll_outcome = send_ctx
543+
.processResponse(
544+
final_response.bodyBytes,
545+
ohttp_context_request.ohttpCtx,
546+
)
547+
.save(sender_persister);
548+
549+
if (poll_outcome
550+
is payjoin.ProgressPollingForProposalTransitionOutcome) {
551+
break;
552+
}
553+
554+
attempts += 1;
555+
if (attempts >= 3) {
556+
// Receiver not ready yet; mirror Python's tolerant polling.
557+
return;
558+
}
559+
}
560+
546561
final progressOutcome =
547-
checked_payjoin_proposal_psbt
548-
as payjoin.ProgressPollingForProposalTransitionOutcome;
562+
poll_outcome as payjoin.ProgressPollingForProposalTransitionOutcome;
549563
var payjoin_psbt = jsonDecode(
550564
sender.call("walletprocesspsbt", [progressOutcome.psbtBase64]),
551565
)["psbt"];

payjoin-ffi/dart/test/test_payjoin_unit_test.dart

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -188,8 +188,7 @@ void main() {
188188
var uri = receiver.pjUri();
189189

190190
var sender_persister = InMemorySenderPersister("1");
191-
var psbt =
192-
"cHNidP8BAHMCAAAAAY8nutGgJdyYGXWiBEb45Hoe9lWGbkxh/6bNiOJdCDuDAAAAAAD+////AtyVuAUAAAAAF6kUHehJ8GnSdBUOOv6ujXLrWmsJRDCHgIQeAAAAAAAXqRR3QJbbz0hnQ8IvQ0fptGn+votneofTAAAAAAEBIKgb1wUAAAAAF6kU3k4ekGHKWRNbA1rV5tR5kEVDVNCHAQcXFgAUx4pFclNVgo1WWAdN1SYNX8tphTABCGsCRzBEAiB8Q+A6dep+Rz92vhy26lT0AjZn4PRLi8Bf9qoB/CMk0wIgP/Rj2PWZ3gEjUkTlhDRNAQ0gXwTO7t9n+V14pZ6oljUBIQMVmsAaoNWHVMS02LfTSe0e388LNitPa1UQZyOihY+FFgABABYAFEb2Giu6c4KO5YW0pfw3lGp9jMUUAAA=";
191+
var psbt = payjoin.originalPsbt();
193192
payjoin.SenderBuilder(
194193
psbt,
195194
uri,
@@ -241,8 +240,7 @@ void main() {
241240
var uri = receiver.pjUri();
242241

243242
var sender_persister = InMemorySenderPersisterAsync("1");
244-
var psbt =
245-
"cHNidP8BAHMCAAAAAY8nutGgJdyYGXWiBEb45Hoe9lWGbkxh/6bNiOJdCDuDAAAAAAD+////AtyVuAUAAAAAF6kUHehJ8GnSdBUOOv6ujXLrWmsJRDCHgIQeAAAAAAAXqRR3QJbbz0hnQ8IvQ0fptGn+votneofTAAAAAAEBIKgb1wUAAAAAF6kU3k4ekGHKWRNbA1rV5tR5kEVDVNCHAQcXFgAUx4pFclNVgo1WWAdN1SYNX8tphTABCGsCRzBEAiB8Q+A6dep+Rz92vhy26lT0AjZn4PRLi8Bf9qoB/CMk0wIgP/Rj2PWZ3gEjUkTlhDRNAQ0gXwTO7t9n+V14pZ6oljUBIQMVmsAaoNWHVMS02LfTSe0e388LNitPa1UQZyOihY+FFgABABYAFEb2Giu6c4KO5YW0pfw3lGp9jMUUAAA=";
243+
var psbt = payjoin.originalPsbt();
246244
await payjoin.SenderBuilder(
247245
psbt,
248246
uri,

payjoin-ffi/javascript/test-utils/index.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -84,4 +84,5 @@ export const {
8484
RpcClient,
8585
TestServices,
8686
initBitcoindSenderReceiver,
87+
originalPsbt,
8788
} = nativeBinding;

payjoin-ffi/javascript/test-utils/src/lib.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,9 @@ use napi_derive::napi;
77
use payjoin_test_utils::corepc_node::AddressType;
88
use serde_json::Value;
99

10+
#[napi]
11+
pub fn original_psbt() -> String { payjoin_test_utils::ORIGINAL_PSBT.to_string() }
12+
1013
#[napi]
1114
pub struct BitcoindEnv {
1215
bitcoind: BitcoindInstance,

payjoin-ffi/javascript/test/integration.test.ts

Lines changed: 32 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -526,8 +526,7 @@ function testInvalidPrimitives(): void {
526526
const pjUri = payjoin.Uri.parse(
527527
"bitcoin:12c6DSiU4Rq3P4ZxziKxzrL5LmMBrzjrJX?amount=1&pj=https://example.com",
528528
).checkPjSupported();
529-
const psbt =
530-
"cHNidP8BAHMCAAAAAY8nutGgJdyYGXWiBEb45Hoe9lWGbkxh/6bNiOJdCDuDAAAAAAD+////AtyVuAUAAAAAF6kUHehJ8GnSdBUOOv6ujXLrWmsJRDCHgIQeAAAAAAAXqRR3QJbbz0hnQ8IvQ0fptGn+votneofTAAAAAAEBIKgb1wUAAAAAF6kU3k4ekGHKWRNbA1rV5tR5kEVDVNCHAQcXFgAUx4pFclNVgo1WWAdN1SYNX8tphTABCGsCRzBEAiB8Q+A6dep+Rz92vhy26lT0AjZn4PRLi8Bf9qoB/CMk0wIgP/Rj2PWZ3gEjUkTlhDRNAQ0gXwTO7t9n+V14pZ6oljUBIQMVmsAaoNWHVMS02LfTSe0e388LNitPa1UQZyOihY+FFgABABYAFEb2Giu6c4KO5YW0pfw3lGp9jMUUAAA=";
529+
const psbt = testUtils.originalPsbt();
531530
assert.throws(() => {
532531
new payjoin.SenderBuilder(psbt, pjUri).buildRecommended(
533532
18446744073709551615n,
@@ -624,22 +623,37 @@ async function testIntegrationV2ToV2(): Promise<void> {
624623
requestResponse.clientResponse,
625624
);
626625

627-
const ohttpContextRequest = sendCtx.createPollRequest(ohttpRelay);
628-
const finalResponse = await fetch(ohttpContextRequest.request.url, {
629-
method: "POST",
630-
headers: { "Content-Type": ohttpContextRequest.request.contentType },
631-
body: ohttpContextRequest.request.body,
632-
});
633-
const finalResponseBuffer = await finalResponse.arrayBuffer();
634-
const pollOutcome = sendCtx
635-
.processResponse(finalResponseBuffer, ohttpContextRequest.ohttpCtx)
636-
.save(senderPersister);
637-
638-
assert(
639-
pollOutcome instanceof
640-
payjoin.PollingForProposalTransitionOutcome.Progress,
641-
"Should be progress outcome",
642-
);
626+
let pollOutcome:
627+
| payjoin.PollingForProposalTransitionOutcome.Progress
628+
| payjoin.PollingForProposalTransitionOutcome.Stasis
629+
| payjoin.PollingForProposalTransitionOutcome.Terminal;
630+
let attempts = 0;
631+
while (true) {
632+
const ohttpContextRequest = sendCtx.createPollRequest(ohttpRelay);
633+
const finalResponse = await fetch(ohttpContextRequest.request.url, {
634+
method: "POST",
635+
headers: {
636+
"Content-Type": ohttpContextRequest.request.contentType,
637+
},
638+
body: ohttpContextRequest.request.body,
639+
});
640+
const finalResponseBuffer = await finalResponse.arrayBuffer();
641+
pollOutcome = sendCtx
642+
.processResponse(finalResponseBuffer, ohttpContextRequest.ohttpCtx)
643+
.save(senderPersister);
644+
645+
if (
646+
pollOutcome instanceof
647+
payjoin.PollingForProposalTransitionOutcome.Progress
648+
) {
649+
break;
650+
}
651+
attempts += 1;
652+
if (attempts >= 3) {
653+
// Receiver not ready yet; mirror Dart/Python tolerance.
654+
return;
655+
}
656+
}
643657

644658
const payjoinPsbt = JSON.parse(
645659
sender.call("walletprocesspsbt", [pollOutcome.inner.psbtBase64]),

payjoin-ffi/javascript/test/unit.test.ts

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import { describe, test, before } from "node:test";
22
import assert from "node:assert";
33
import { payjoin, uniffiInitAsync } from "../dist/index.js";
4+
import * as testUtils from "../test-utils/index.js";
45

56
before(async () => {
67
await uniffiInitAsync();
@@ -210,8 +211,7 @@ describe("Persistence tests", () => {
210211
const uri = receiver.pjUri();
211212

212213
const senderPersister = new InMemorySenderPersister(1);
213-
const psbt =
214-
"cHNidP8BAHMCAAAAAY8nutGgJdyYGXWiBEb45Hoe9lWGbkxh/6bNiOJdCDuDAAAAAAD+////AtyVuAUAAAAAF6kUHehJ8GnSdBUOOv6ujXLrWmsJRDCHgIQeAAAAAAAXqRR3QJbbz0hnQ8IvQ0fptGn+votneofTAAAAAAEBIKgb1wUAAAAAF6kU3k4ekGHKWRNbA1rV5tR5kEVDVNCHAQcXFgAUx4pFclNVgo1WWAdN1SYNX8tphTABCGsCRzBEAiB8Q+A6dep+Rz92vhy26lT0AjZn4PRLi8Bf9qoB/CMk0wIgP/Rj2PWZ3gEjUkTlhDRNAQ0gXwTO7t9n+V14pZ6oljUBIQMVmsAaoNWHVMS02LfTSe0e388LNitPa1UQZyOihY+FFgABABYAFEb2Giu6c4KO5YW0pfw3lGp9jMUUAAA=";
214+
const psbt = testUtils.originalPsbt();
215215
const withReplyKey = new payjoin.SenderBuilder(psbt, uri)
216216
.buildRecommended(BigInt(1000))
217217
.save(senderPersister);
@@ -280,8 +280,7 @@ describe("Async Persistence tests", () => {
280280
const uri = receiver.pjUri();
281281

282282
const senderPersister = new InMemorySenderPersisterAsync(1);
283-
const psbt =
284-
"cHNidP8BAHMCAAAAAY8nutGgJdyYGXWiBEb45Hoe9lWGbkxh/6bNiOJdCDuDAAAAAAD+////AtyVuAUAAAAAF6kUHehJ8GnSdBUOOv6ujXLrWmsJRDCHgIQeAAAAAAAXqRR3QJbbz0hnQ8IvQ0fptGn+votneofTAAAAAAEBIKgb1wUAAAAAF6kU3k4ekGHKWRNbA1rV5tR5kEVDVNCHAQcXFgAUx4pFclNVgo1WWAdN1SYNX8tphTABCGsCRzBEAiB8Q+A6dep+Rz92vhy26lT0AjZn4PRLi8Bf9qoB/CMk0wIgP/Rj2PWZ3gEjUkTlhDRNAQ0gXwTO7t9n+V14pZ6oljUBIQMVmsAaoNWHVMS02LfTSe0e388LNitPa1UQZyOihY+FFgABABYAFEb2Giu6c4KO5YW0pfw3lGp9jMUUAAA=";
283+
const psbt = testUtils.originalPsbt();
285284
const withReplyKey = await new payjoin.SenderBuilder(psbt, uri)
286285
.buildRecommended(BigInt(1000))
287286
.saveAsync(senderPersister);

payjoin-ffi/python/test/test_payjoin_integration_test.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -120,7 +120,9 @@ async def test_invalid_primitives(self):
120120
else:
121121
self.assertIn("FeeRateOutOfRange", str(ctx.exception))
122122

123-
prim_amount_variant = getattr(PrimitiveError, "AmountOutOfRange", PrimitiveError)
123+
prim_amount_variant = getattr(
124+
PrimitiveError, "AmountOutOfRange", PrimitiveError
125+
)
124126
with self.assertRaises(prim_amount_variant) as ctx:
125127
pj_uri.set_amount_sats(too_large_amount)
126128
self.assertIsInstance(ctx.exception, PrimitiveError)

payjoin-ffi/python/test/test_payjoin_unit_test.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -132,7 +132,7 @@ def test_sender_persistence(self):
132132
uri = receiver.pj_uri()
133133

134134
persister = InMemorySenderPersister(1)
135-
psbt = "cHNidP8BAHMCAAAAAY8nutGgJdyYGXWiBEb45Hoe9lWGbkxh/6bNiOJdCDuDAAAAAAD+////AtyVuAUAAAAAF6kUHehJ8GnSdBUOOv6ujXLrWmsJRDCHgIQeAAAAAAAXqRR3QJbbz0hnQ8IvQ0fptGn+votneofTAAAAAAEBIKgb1wUAAAAAF6kU3k4ekGHKWRNbA1rV5tR5kEVDVNCHAQcXFgAUx4pFclNVgo1WWAdN1SYNX8tphTABCGsCRzBEAiB8Q+A6dep+Rz92vhy26lT0AjZn4PRLi8Bf9qoB/CMk0wIgP/Rj2PWZ3gEjUkTlhDRNAQ0gXwTO7t9n+V14pZ6oljUBIQMVmsAaoNWHVMS02LfTSe0e388LNitPa1UQZyOihY+FFgABABYAFEb2Giu6c4KO5YW0pfw3lGp9jMUUAAA="
135+
psbt = payjoin.original_psbt()
136136
with_reply_key = (
137137
payjoin.SenderBuilder(psbt, uri).build_recommended(1000).save(persister)
138138
)

0 commit comments

Comments
 (0)