mirror of
https://github.com/btcpayserver/btcpayserver.git
synced 2024-11-19 09:54:30 +01:00
218 lines
11 KiB
C#
218 lines
11 KiB
C#
using System.Linq;
|
|
using System.Threading.Tasks;
|
|
using BTCPayServer.Payments;
|
|
using Dapper;
|
|
using Microsoft.EntityFrameworkCore;
|
|
using NBitcoin;
|
|
using NBitcoin.Altcoins;
|
|
using NBitpayClient;
|
|
using Newtonsoft.Json.Linq;
|
|
using Xunit;
|
|
using Xunit.Abstractions;
|
|
|
|
namespace BTCPayServer.Tests
|
|
{
|
|
[Trait("Integration", "Integration")]
|
|
public class DatabaseTests : UnitTestBase
|
|
{
|
|
|
|
public DatabaseTests(ITestOutputHelper helper):base(helper)
|
|
{
|
|
}
|
|
|
|
[Fact]
|
|
public async Task CanQueryMonitoredInvoices()
|
|
{
|
|
var tester = CreateDBTester();
|
|
await tester.MigrateUntil();
|
|
var invoiceRepository = tester.GetInvoiceRepository();
|
|
using var ctx = tester.CreateContext();
|
|
var conn = ctx.Database.GetDbConnection();
|
|
|
|
async Task AddPrompt(string invoiceId, string paymentMethodId, bool activated = true)
|
|
{
|
|
JObject prompt = new JObject();
|
|
if (!activated)
|
|
prompt["inactive"] = true;
|
|
prompt["currency"] = "USD";
|
|
var query = """
|
|
UPDATE "Invoices" SET "Blob2" = jsonb_set('{"prompts": {}}'::JSONB || COALESCE("Blob2",'{}'), ARRAY['prompts','@paymentMethodId'], '@prompt'::JSONB)
|
|
WHERE "Id" = '@invoiceId'
|
|
""";
|
|
query = query.Replace("@paymentMethodId", paymentMethodId);
|
|
query = query.Replace("@prompt", prompt.ToString());
|
|
query = query.Replace("@invoiceId", invoiceId);
|
|
Assert.Equal(1, await conn.ExecuteAsync(query));
|
|
}
|
|
|
|
await conn.ExecuteAsync("""
|
|
INSERT INTO "Invoices" ("Id", "Created", "Status","Currency") VALUES
|
|
('BTCOnly', NOW(), 'New', 'USD'),
|
|
('LTCOnly', NOW(), 'New', 'USD'),
|
|
('LTCAndBTC', NOW(), 'New', 'USD'),
|
|
('LTCAndBTCLazy', NOW(), 'New', 'USD')
|
|
""");
|
|
foreach (var invoiceId in new string[] { "LTCOnly", "LTCAndBTCLazy", "LTCAndBTC" })
|
|
{
|
|
await AddPrompt(invoiceId, "LTC-CHAIN", true);
|
|
}
|
|
foreach (var invoiceId in new string[] { "BTCOnly", "LTCAndBTC" })
|
|
{
|
|
await AddPrompt(invoiceId, "BTC-CHAIN", true);
|
|
}
|
|
await AddPrompt("LTCAndBTCLazy", "BTC-CHAIN", false);
|
|
|
|
var btc = PaymentMethodId.Parse("BTC-CHAIN");
|
|
var ltc = PaymentMethodId.Parse("LTC-CHAIN");
|
|
var invoices = await invoiceRepository.GetMonitoredInvoices(btc);
|
|
Assert.Equal(2, invoices.Length);
|
|
foreach (var invoiceId in new[] { "BTCOnly", "LTCAndBTC" })
|
|
{
|
|
Assert.Contains(invoices, i => i.Id == invoiceId);
|
|
}
|
|
invoices = await invoiceRepository.GetMonitoredInvoices(btc, true);
|
|
Assert.Equal(3, invoices.Length);
|
|
foreach (var invoiceId in new[] { "BTCOnly", "LTCAndBTC", "LTCAndBTCLazy" })
|
|
{
|
|
Assert.Contains(invoices, i => i.Id == invoiceId);
|
|
}
|
|
|
|
invoices = await invoiceRepository.GetMonitoredInvoices(ltc);
|
|
Assert.Equal(3, invoices.Length);
|
|
foreach (var invoiceId in new[] { "LTCAndBTC", "LTCAndBTC", "LTCAndBTCLazy" })
|
|
{
|
|
Assert.Contains(invoices, i => i.Id == invoiceId);
|
|
}
|
|
|
|
await conn.ExecuteAsync("""
|
|
INSERT INTO "Payments" ("Id", "InvoiceDataId", "PaymentMethodId", "Status", "Blob2", "Created", "Amount", "Currency") VALUES
|
|
('1','LTCAndBTC', 'LTC-CHAIN', 'Processing', '{}'::JSONB, NOW(), 123, 'USD'),
|
|
('2','LTCAndBTC', 'BTC-CHAIN', 'Processing', '{}'::JSONB, NOW(), 123, 'USD'),
|
|
('3','LTCAndBTC', 'BTC-CHAIN', 'Processing', '{}'::JSONB, NOW(), 123, 'USD'),
|
|
('4','LTCAndBTC', 'BTC-CHAIN', 'Settled', '{}'::JSONB, NOW(), 123, 'USD');
|
|
|
|
INSERT INTO "AddressInvoices" ("InvoiceDataId", "Address", "PaymentMethodId") VALUES
|
|
('LTCAndBTC', 'BTC1', 'BTC-CHAIN'),
|
|
('LTCAndBTC', 'BTC2', 'BTC-CHAIN'),
|
|
('LTCAndBTC', 'LTC1', 'LTC-CHAIN');
|
|
""");
|
|
|
|
var invoice = Assert.Single(await invoiceRepository.GetMonitoredInvoices(ltc), i => i.Id == "LTCAndBTC");
|
|
var payment = Assert.Single(invoice.GetPayments(false));
|
|
Assert.Equal("1", payment.Id);
|
|
|
|
foreach (var includeNonActivated in new[] { true, false })
|
|
{
|
|
invoices = await invoiceRepository.GetMonitoredInvoices(btc, includeNonActivated);
|
|
invoice = Assert.Single(invoices, i => i.Id == "LTCAndBTC");
|
|
var payments = invoice.GetPayments(false);
|
|
Assert.Equal(3, payments.Count);
|
|
|
|
foreach (var paymentId in new[] { "2", "3", "4" })
|
|
{
|
|
Assert.Contains(payments, p => p.Id == paymentId);
|
|
}
|
|
Assert.Equal(2, invoice.Addresses.Count);
|
|
foreach (var addr in new[] { "BTC1", "BTC2" })
|
|
{
|
|
Assert.Contains(invoice.Addresses, p => p.Address == addr);
|
|
}
|
|
if (!includeNonActivated)
|
|
Assert.DoesNotContain(invoices, i => i.Id == "LTCAndBTCLazy");
|
|
else
|
|
Assert.Contains(invoices, i => i.Id == "LTCAndBTCLazy");
|
|
}
|
|
}
|
|
|
|
[Fact]
|
|
public async Task CanMigrateInvoiceAddresses()
|
|
{
|
|
var tester = CreateDBTester();
|
|
await tester.MigrateUntil("20240919085726_refactorinvoiceaddress");
|
|
using var ctx = tester.CreateContext();
|
|
var conn = ctx.Database.GetDbConnection();
|
|
await conn.ExecuteAsync("INSERT INTO \"Invoices\" (\"Id\", \"Created\") VALUES ('i', NOW())");
|
|
await conn.ExecuteAsync(
|
|
"INSERT INTO \"AddressInvoices\" VALUES ('aaa#BTC', 'i'),('bbb','i'),('ccc#BTC_LNU', 'i'),('ddd#XMR_MoneroLike', 'i'),('eee#ZEC_ZcashLike', 'i')");
|
|
await tester.ContinueMigration();
|
|
foreach (var v in new[] { ("aaa", "BTC-CHAIN"), ("bbb", "BTC-CHAIN"), ("ddd", "XMR-CHAIN") , ("eee", "ZEC-CHAIN") })
|
|
{
|
|
var ok = await conn.ExecuteScalarAsync<bool>("SELECT 't'::BOOLEAN FROM \"AddressInvoices\" WHERE \"Address\"=@a AND \"PaymentMethodId\"=@b", new { a = v.Item1, b = v.Item2 });
|
|
Assert.True(ok);
|
|
}
|
|
var notok = await conn.ExecuteScalarAsync<bool>("SELECT 't'::BOOLEAN FROM \"AddressInvoices\" WHERE \"Address\"='ccc'");
|
|
Assert.False(notok);
|
|
}
|
|
|
|
[Fact]
|
|
public async Task CanMigratePayoutsAndPullPayments()
|
|
{
|
|
var tester = CreateDBTester();
|
|
await tester.MigrateUntil("20240827034505_migratepayouts");
|
|
|
|
using var ctx = tester.CreateContext();
|
|
var conn = ctx.Database.GetDbConnection();
|
|
await conn.ExecuteAsync("INSERT INTO \"Stores\"(\"Id\", \"SpeedPolicy\") VALUES (@store, 0)", new { store = "store1" });
|
|
var param = new
|
|
{
|
|
Id = "pp1",
|
|
StoreId = "store1",
|
|
Blob = "{\"Name\": \"CoinLottery\", \"View\": {\"Email\": null, \"Title\": \"\", \"Description\": \"\", \"EmbeddedCSS\": null, \"CustomCSSLink\": null}, \"Limit\": \"10.00\", \"Period\": null, \"Currency\": \"GBP\", \"Description\": \"\", \"Divisibility\": 0, \"MinimumClaim\": \"0\", \"AutoApproveClaims\": false, \"SupportedPaymentMethods\": [\"BTC\", \"BTC_LightningLike\"]}"
|
|
};
|
|
await conn.ExecuteAsync("INSERT INTO \"PullPayments\"(\"Id\", \"StoreId\", \"Blob\", \"StartDate\", \"Archived\") VALUES (@Id, @StoreId, @Blob::JSONB, NOW(), 'f')", param);
|
|
var parameters = new[]
|
|
{
|
|
new
|
|
{
|
|
Id = "p1",
|
|
StoreId = "store1",
|
|
PullPaymentDataId = "pp1",
|
|
PaymentMethodId = "BTC",
|
|
Blob = "{\"Amount\": \"10.0\", \"Revision\": 0, \"Destination\": \"address\", \"CryptoAmount\": \"0.00012225\", \"MinimumConfirmation\": 1}"
|
|
},
|
|
new
|
|
{
|
|
Id = "p2",
|
|
StoreId = "store1",
|
|
PullPaymentDataId = "pp1",
|
|
PaymentMethodId = "BTC_LightningLike",
|
|
Blob = "{\"Amount\": \"10.0\", \"Revision\": 0, \"Destination\": \"address\", \"CryptoAmount\": null, \"MinimumConfirmation\": 1}"
|
|
},
|
|
new
|
|
{
|
|
Id = "p3",
|
|
StoreId = "store1",
|
|
PullPaymentDataId = null as string,
|
|
PaymentMethodId = "BTC_LightningLike",
|
|
Blob = "{\"Amount\": \"10.0\", \"Revision\": 0, \"Destination\": \"address\", \"CryptoAmount\": null, \"MinimumConfirmation\": 1}"
|
|
},
|
|
new
|
|
{
|
|
Id = "p4",
|
|
StoreId = "store1",
|
|
PullPaymentDataId = null as string,
|
|
PaymentMethodId = "BTC_LightningLike",
|
|
Blob = "{\"Amount\": \"-10.0\", \"Revision\": 0, \"Destination\": \"address\", \"CryptoAmount\": null, \"MinimumConfirmation\": 1}"
|
|
}
|
|
};
|
|
await conn.ExecuteAsync("INSERT INTO \"Payouts\"(\"Id\", \"StoreDataId\", \"PullPaymentDataId\", \"PaymentMethodId\", \"Blob\", \"State\", \"Date\") VALUES (@Id, @StoreId, @PullPaymentDataId, @PaymentMethodId, @Blob::JSONB, 'state', NOW())", parameters);
|
|
await tester.ContinueMigration();
|
|
|
|
var migrated = await conn.ExecuteScalarAsync<bool>("SELECT 't'::BOOLEAN FROM \"PullPayments\" WHERE \"Id\"='pp1' AND \"Limit\"=10.0 AND \"Currency\"='GBP' AND \"Blob\"->>'SupportedPayoutMethods'='[\"BTC-CHAIN\", \"BTC-LN\"]'");
|
|
Assert.True(migrated);
|
|
|
|
migrated = await conn.ExecuteScalarAsync<bool>("SELECT 't'::BOOLEAN FROM \"Payouts\" WHERE \"Id\"='p1' AND \"Amount\"= 0.00012225 AND \"OriginalAmount\"=10.0 AND \"OriginalCurrency\"='GBP' AND \"PayoutMethodId\"='BTC-CHAIN'");
|
|
Assert.True(migrated);
|
|
|
|
migrated = await conn.ExecuteScalarAsync<bool>("SELECT 't'::BOOLEAN FROM \"Payouts\" WHERE \"Id\"='p2' AND \"Amount\" IS NULL AND \"OriginalAmount\"=10.0 AND \"OriginalCurrency\"='GBP' AND \"PayoutMethodId\"='BTC-LN'");
|
|
Assert.True(migrated);
|
|
|
|
migrated = await conn.ExecuteScalarAsync<bool>("SELECT 't'::BOOLEAN FROM \"Payouts\" WHERE \"Id\"='p3' AND \"Amount\" IS NULL AND \"OriginalAmount\"=10.0 AND \"OriginalCurrency\"='BTC'");
|
|
Assert.True(migrated);
|
|
|
|
migrated = await conn.ExecuteScalarAsync<bool>("SELECT 't'::BOOLEAN FROM \"Payouts\" WHERE \"Id\"='p4' AND \"Amount\" IS NULL AND \"OriginalAmount\"=-10.0 AND \"OriginalCurrency\"='BTC' AND \"PayoutMethodId\"='TOPUP'");
|
|
Assert.True(migrated);
|
|
}
|
|
}
|
|
}
|