Add SQL test for GetMonitoredInvoices

This commit is contained in:
nicolas.dorier 2024-09-24 22:07:02 +09:00
parent 9d3f8672d9
commit c97c9d4ece
No known key found for this signature in database
GPG key ID: 6618763EF09186FE
4 changed files with 126 additions and 13 deletions

View file

@ -5,6 +5,7 @@ using System.Linq;
using System.Threading.Tasks;
using BTCPayServer.Abstractions.Models;
using BTCPayServer.Data;
using BTCPayServer.Services.Invoices;
using BTCPayServer.Tests.Logging;
using Dapper;
using Microsoft.EntityFrameworkCore;
@ -42,6 +43,13 @@ namespace BTCPayServer.Tests
}), _loggerFactory);
}
public InvoiceRepository GetInvoiceRepository()
{
var logs = new BTCPayServer.Logging.Logs();
logs.Configure(_loggerFactory);
return new InvoiceRepository(CreateContextFactory(), new EventAggregator(logs));
}
public ApplicationDbContext CreateContext() => CreateContextFactory().CreateContext();
public async Task MigrateAsync()
@ -59,18 +67,21 @@ namespace BTCPayServer.Tests
await conn.ExecuteAsync($"CREATE DATABASE \"{dbname}\";");
}
public async Task MigrateUntil(string migration)
public async Task MigrateUntil(string migration = null)
{
using var ctx = CreateContext();
var db = ctx.Database.GetDbConnection();
await EnsureCreatedAsync();
var migrations = ctx.Database.GetMigrations().ToArray();
var untilMigrationIdx = Array.IndexOf(migrations, migration);
if (untilMigrationIdx == -1)
throw new InvalidOperationException($"Migration {migration} not found");
notAppliedMigrations = migrations[untilMigrationIdx..];
await db.ExecuteAsync("CREATE TABLE IF NOT EXISTS \"__EFMigrationsHistory\" (\"MigrationId\" TEXT, \"ProductVersion\" TEXT)");
await db.ExecuteAsync("INSERT INTO \"__EFMigrationsHistory\" VALUES (@migration, '8.0.0')", notAppliedMigrations.Select(m => new { migration = m }).ToArray());
if (migration is not null)
{
var untilMigrationIdx = Array.IndexOf(migrations, migration);
if (untilMigrationIdx == -1)
throw new InvalidOperationException($"Migration {migration} not found");
notAppliedMigrations = migrations[untilMigrationIdx..];
await db.ExecuteAsync("CREATE TABLE IF NOT EXISTS \"__EFMigrationsHistory\" (\"MigrationId\" TEXT, \"ProductVersion\" TEXT)");
await db.ExecuteAsync("INSERT INTO \"__EFMigrationsHistory\" VALUES (@migration, '8.0.0')", notAppliedMigrations.Select(m => new { migration = m }).ToArray());
}
await ctx.Database.MigrateAsync();
}

View file

@ -3,7 +3,9 @@ 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;
@ -18,6 +20,110 @@ namespace BTCPayServer.Tests
{
}
[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()
{

View file

@ -32,7 +32,7 @@ namespace BTCPayServer.Data
#nullable enable
public static PayoutMethodId? GetClosestPayoutMethodId(this InvoiceData invoice, IEnumerable<PayoutMethodId> pmids)
{
var paymentMethodIds = invoice.Payments.Select(o => o.GetPaymentMethodId()).ToArray();
var paymentMethodIds = invoice.Payments.Select(o => PaymentMethodId.Parse(o.PaymentMethodId)).ToArray();
if (paymentMethodIds.Length == 0)
paymentMethodIds = invoice.GetBlob().GetPaymentPrompts().Select(p => p.PaymentMethodId).ToArray();
return PaymentMethodId.GetSimilarities(pmids, paymentMethodIds)

View file

@ -38,16 +38,12 @@ namespace BTCPayServer.Data
paymentData.Blob2 = JToken.FromObject(blob, InvoiceDataExtensions.DefaultSerializer).ToString(Newtonsoft.Json.Formatting.None);
return paymentData;
}
public static PaymentMethodId GetPaymentMethodId(this PaymentData paymentData)
{
return PaymentMethodId.Parse(paymentData.PaymentMethodId);
}
public static PaymentEntity GetBlob(this PaymentData paymentData)
{
var entity = JToken.Parse(paymentData.Blob2).ToObject<PaymentEntity>(InvoiceDataExtensions.DefaultSerializer) ?? throw new FormatException($"Invalid {nameof(PaymentEntity)}");
entity.Status = paymentData.Status!.Value;
entity.Currency = paymentData.Currency;
entity.PaymentMethodId = GetPaymentMethodId(paymentData);
entity.PaymentMethodId = PaymentMethodId.Parse(paymentData.PaymentMethodId);
entity.Value = paymentData.Amount!.Value;
entity.Id = paymentData.Id;
entity.ReceivedTime = paymentData.Created!.Value;