Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
101 changes: 101 additions & 0 deletions payjoin-ffi/csharp/UnitTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -254,6 +254,107 @@
}
}

public class PersisterLoadAndCloseTests
{
private static readonly byte[] OhttpKeysData = new byte[]
{
0x01, 0x00, 0x16, 0x04, 0xba, 0x48, 0xc4, 0x9c, 0x3d, 0x4a,
0x92, 0xa3, 0xad, 0x00, 0xec, 0xc6, 0x3a, 0x02, 0x4d, 0xa1,
0x0c, 0xed, 0x02, 0x18, 0x0c, 0x73, 0xec, 0x12, 0xd8, 0xa7,
0xad, 0x2c, 0xc9, 0x1b, 0xb4, 0x83, 0x82, 0x4f, 0xe2, 0xbe,
0xe8, 0xd2, 0x8b, 0xfe, 0x2e, 0xb2, 0xfc, 0x64, 0x53, 0xbc,
0x4d, 0x31, 0xcd, 0x85, 0x1e, 0x8a, 0x65, 0x40, 0xe8, 0x6c,
0x53, 0x82, 0xaf, 0x58, 0x8d, 0x37, 0x09, 0x57, 0x00, 0x04,
0x00, 0x01, 0x00, 0x03,
};

[Fact]
public void ReceiverLoadAndClose()
{
var persister = new InMemoryReceiverPersister();
var address = "tb1q6d3a2w975yny0asuvd9a67ner4nks58ff0q8g4";
var ohttpKeys = OhttpKeys.Decode(OhttpKeysData);

var initialized = new ReceiverBuilder(address, "https://example.com", ohttpKeys)
.Build()
.Save(persister);
Assert.Equal(1, persister.Load().Length);

Check warning on line 281 in payjoin-ffi/csharp/UnitTests.cs

View workflow job for this annotation

GitHub Actions / Build and test csharp (windows)

Do not use Assert.Equal() to check for collection size. Use Assert.Single instead. (https://xunit.net/xunit.analyzers/rules/xUnit2013)
Assert.False(persister.Closed);

// Cancelling is terminal, so saving it must close the persister.
initialized.Cancel().Save(persister);

Assert.True(persister.Closed);
Assert.Equal(2, persister.Load().Length);
}

[Fact]
public async Task ReceiverLoadAndCloseAsync()
{
var persister = new InMemoryReceiverPersisterAsync();
var address = "tb1q6d3a2w975yny0asuvd9a67ner4nks58ff0q8g4";
var ohttpKeys = OhttpKeys.Decode(OhttpKeysData);

var initialized = await new ReceiverBuilder(address, "https://example.com", ohttpKeys)
.Build()
.SaveAsync(persister);
Assert.Equal(1, (await persister.Load()).Length);

Check warning on line 301 in payjoin-ffi/csharp/UnitTests.cs

View workflow job for this annotation

GitHub Actions / Build and test csharp (windows)

Do not use Assert.Equal() to check for collection size. Use Assert.Single instead. (https://xunit.net/xunit.analyzers/rules/xUnit2013)
Assert.False(persister.Closed);

await initialized.Cancel().SaveAsync(persister);

Assert.True(persister.Closed);
Assert.Equal(2, (await persister.Load()).Length);
}

[Fact]
public void SenderLoadAndClose()
{
var address = "2MuyMrZHkbHbfjudmKUy45dU4P17pjG2szK";
var ohttpKeys = OhttpKeys.Decode(OhttpKeysData);
var receiver = new ReceiverBuilder(address, "https://example.com", ohttpKeys)
.Build()
.Save(new InMemoryReceiverPersister());

var persister = new InMemorySenderPersister();
var withReplyKey = new SenderBuilder(PayjoinMethods.OriginalPsbt(), receiver.PjUri())
.BuildRecommended(1000)
.Save(persister);
var pendingFallback = withReplyKey.Cancel().Save(persister);
Assert.Equal(2, persister.Load().Length);
Assert.False(persister.Closed);

// Closing the fallback is terminal, so saving it must close the persister.
pendingFallback.Close().Save(persister);

Assert.True(persister.Closed);
Assert.Equal(3, persister.Load().Length);
}

[Fact]
public async Task SenderLoadAndCloseAsync()
{
var address = "2MuyMrZHkbHbfjudmKUy45dU4P17pjG2szK";
var ohttpKeys = OhttpKeys.Decode(OhttpKeysData);
var receiver = await new ReceiverBuilder(address, "https://example.com", ohttpKeys)
.Build()
.SaveAsync(new InMemoryReceiverPersisterAsync());

var persister = new InMemorySenderPersisterAsync();
var withReplyKey = await new SenderBuilder(PayjoinMethods.OriginalPsbt(), receiver.PjUri())
.BuildRecommended(1000)
.SaveAsync(persister);
var pendingFallback = await withReplyKey.Cancel().SaveAsync(persister);
Assert.Equal(2, (await persister.Load()).Length);
Assert.False(persister.Closed);

await pendingFallback.Close().SaveAsync(persister);

Assert.True(persister.Closed);
Assert.Equal(3, (await persister.Load()).Length);
}
}

public class ValidationTests
{
private static readonly byte[] OhttpKeysData = new byte[]
Expand Down
127 changes: 127 additions & 0 deletions payjoin-ffi/dart/test/test_payjoin_unit_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -253,6 +253,133 @@ void main() {
});
});

group("Test Persister Load And Close", () {
test("Test receiver load and close", () {
var persister = InMemoryReceiverPersister();
var initialized = payjoin.ReceiverBuilder(
address: "tb1q6d3a2w975yny0asuvd9a67ner4nks58ff0q8g4",
directory: "https://example.com",
ohttpKeys: payjoin.OhttpKeys.decode(
bytes: Uint8List.fromList(
hex.decode(
"01001604ba48c49c3d4a92a3ad00ecc63a024da10ced02180c73ec12d8a7ad2cc91bb483824fe2bee8d28bfe2eb2fc6453bc4d31cd851e8a6540e86c5382af588d370957000400010003",
),
),
),
).build().save(persister: persister);
expect(persister.load().length, 1);
expect(persister.closed, isFalse);

// Cancelling is terminal, so saving it must close the persister.
initialized.cancel().save(persister: persister);

expect(persister.closed, isTrue);
expect(
persister.load().length,
2,
reason: "load should still return every event after close",
);
});

test("Test receiver load and close async", () async {
var persister = InMemoryReceiverPersisterAsync();
var initialized = await payjoin.ReceiverBuilder(
address: "tb1q6d3a2w975yny0asuvd9a67ner4nks58ff0q8g4",
directory: "https://example.com",
ohttpKeys: payjoin.OhttpKeys.decode(
bytes: Uint8List.fromList(
hex.decode(
"01001604ba48c49c3d4a92a3ad00ecc63a024da10ced02180c73ec12d8a7ad2cc91bb483824fe2bee8d28bfe2eb2fc6453bc4d31cd851e8a6540e86c5382af588d370957000400010003",
),
),
),
).build().saveAsync(persister: persister);
expect((await persister.load()).length, 1);
expect(persister.closed, isFalse);

await initialized.cancel().saveAsync(persister: persister);

expect(persister.closed, isTrue);
expect(
(await persister.load()).length,
2,
reason: "load should still return every event after close",
);
});

test("Test sender load and close", () {
// Create a receiver to just get the pj uri
var receiver = payjoin.ReceiverBuilder(
address: "2MuyMrZHkbHbfjudmKUy45dU4P17pjG2szK",
directory: "https://example.com",
ohttpKeys: payjoin.OhttpKeys.decode(
bytes: Uint8List.fromList(
hex.decode(
"01001604ba48c49c3d4a92a3ad00ecc63a024da10ced02180c73ec12d8a7ad2cc91bb483824fe2bee8d28bfe2eb2fc6453bc4d31cd851e8a6540e86c5382af588d370957000400010003",
),
),
),
).build().save(persister: InMemoryReceiverPersister());

var persister = InMemorySenderPersister();
var withReplyKey = payjoin.SenderBuilder(
psbt: payjoin.originalPsbt(),
uri: receiver.pjUri(),
).buildRecommended(minFeeRateSatPerKwu: 1000).save(persister: persister);
var pendingFallback = withReplyKey.cancel().save(persister: persister);
expect(persister.load().length, 2);
expect(persister.closed, isFalse);

// Closing the fallback is terminal, so saving it must close the persister.
pendingFallback!.close().save(persister: persister);

expect(persister.closed, isTrue);
expect(
persister.load().length,
3,
reason: "load should still return every event after close",
);
});

test("Test sender load and close async", () async {
// Create a receiver to just get the pj uri
var receiver = await payjoin.ReceiverBuilder(
address: "2MuyMrZHkbHbfjudmKUy45dU4P17pjG2szK",
directory: "https://example.com",
ohttpKeys: payjoin.OhttpKeys.decode(
bytes: Uint8List.fromList(
hex.decode(
"01001604ba48c49c3d4a92a3ad00ecc63a024da10ced02180c73ec12d8a7ad2cc91bb483824fe2bee8d28bfe2eb2fc6453bc4d31cd851e8a6540e86c5382af588d370957000400010003",
),
),
),
).build().saveAsync(persister: InMemoryReceiverPersisterAsync());

var persister = InMemorySenderPersisterAsync();
var withReplyKey =
await payjoin.SenderBuilder(
psbt: payjoin.originalPsbt(),
uri: receiver.pjUri(),
)
.buildRecommended(minFeeRateSatPerKwu: 1000)
.saveAsync(persister: persister);
var pendingFallback = await withReplyKey.cancel().saveAsync(
persister: persister,
);
expect((await persister.load()).length, 2);
expect(persister.closed, isFalse);

await pendingFallback!.close().saveAsync(persister: persister);

expect(persister.closed, isTrue);
expect(
(await persister.load()).length,
3,
reason: "load should still return every event after close",
);
});
});

group("Test Async Persistence", () {
test("Test receiver async persistence", () async {
var persister = InMemoryReceiverPersisterAsync();
Expand Down
121 changes: 121 additions & 0 deletions payjoin-ffi/javascript/test/unit.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -284,6 +284,127 @@ function runUnitTests(name: string, payjoin: typeof nodejsPayjoin) {
});
});

describe(`[${name}] Persister load and close tests`, () => {
test("receiver load and close", () => {
const persister = new InMemoryReceiverPersister();
const ohttpKeys = payjoin.OhttpKeys.decode(OHTTP_KEYS);

const initialized = new payjoin.ReceiverBuilder(
"tb1q6d3a2w975yny0asuvd9a67ner4nks58ff0q8g4",
"https://example.com",
ohttpKeys,
)
.build()
.save(persister);
assert.strictEqual(persister.load().length, 1);
assert.strictEqual(persister.closed, false);

// Cancelling is terminal, so saving it must close the persister.
initialized.cancel().save(persister);

assert.strictEqual(persister.closed, true);
assert.strictEqual(
persister.load().length,
2,
"load should still return every event after close",
);
});

test("receiver load and close async", async () => {
const persister = new InMemoryReceiverPersisterAsync();
const ohttpKeys = payjoin.OhttpKeys.decode(OHTTP_KEYS);

const initialized = await new payjoin.ReceiverBuilder(
"tb1q6d3a2w975yny0asuvd9a67ner4nks58ff0q8g4",
"https://example.com",
ohttpKeys,
)
.build()
.saveAsync(persister);
assert.strictEqual((await persister.load()).length, 1);
assert.strictEqual(persister.closed, false);

await initialized.cancel().saveAsync(persister);

assert.strictEqual(persister.closed, true);
assert.strictEqual(
(await persister.load()).length,
2,
"load should still return every event after close",
);
});

test("sender load and close", () => {
const receiverPersister = new InMemoryReceiverPersister();
const ohttpKeys = payjoin.OhttpKeys.decode(OHTTP_KEYS);
const uri = new payjoin.ReceiverBuilder(
"2MuyMrZHkbHbfjudmKUy45dU4P17pjG2szK",
"https://example.com",
ohttpKeys,
)
.build()
.save(receiverPersister)
.pjUri();

const persister = new InMemorySenderPersister();
const pendingFallback = new payjoin.SenderBuilder(
ORIGINAL_PSBT,
uri,
)
.buildRecommended(BigInt(1000))
.save(persister)
.cancel()
.save(persister);
assert.strictEqual(persister.load().length, 2);
assert.strictEqual(persister.closed, false);

// Closing the fallback is terminal, so saving it must close the
// persister.
pendingFallback.close().save(persister);

assert.strictEqual(persister.closed, true);
assert.strictEqual(
persister.load().length,
3,
"load should still return every event after close",
);
});

test("sender load and close async", async () => {
const receiverPersister = new InMemoryReceiverPersisterAsync();
const ohttpKeys = payjoin.OhttpKeys.decode(OHTTP_KEYS);
const receiver = await new payjoin.ReceiverBuilder(
"2MuyMrZHkbHbfjudmKUy45dU4P17pjG2szK",
"https://example.com",
ohttpKeys,
)
.build()
.saveAsync(receiverPersister);

const persister = new InMemorySenderPersisterAsync();
const withReplyKey = await new payjoin.SenderBuilder(
ORIGINAL_PSBT,
receiver.pjUri(),
)
.buildRecommended(BigInt(1000))
.saveAsync(persister);
const pendingFallback = await withReplyKey
.cancel()
.saveAsync(persister);
assert.strictEqual((await persister.load()).length, 2);
assert.strictEqual(persister.closed, false);

await pendingFallback.close().saveAsync(persister);

assert.strictEqual(persister.closed, true);
assert.strictEqual(
(await persister.load()).length,
3,
"load should still return every event after close",
);
});
});

describe(`[${name}] Async Persistence tests`, () => {
test("receiver async persistence", async () => {
const persister = new InMemoryReceiverPersisterAsync();
Expand Down
Loading
Loading