diff --git a/BTCPayServer.Tests/CustomerHttpServer.cs b/BTCPayServer.Tests/CustomerHttpServer.cs index 24f73c8ef..34cbdefdc 100644 --- a/BTCPayServer.Tests/CustomerHttpServer.cs +++ b/BTCPayServer.Tests/CustomerHttpServer.cs @@ -8,30 +8,27 @@ using Microsoft.AspNetCore.Builder; using System.Threading.Tasks; using System.Threading; using Microsoft.AspNetCore.Hosting.Server.Features; +using System.Threading.Channels; +using System.IO; +using Newtonsoft.Json.Linq; +using Newtonsoft.Json; namespace BTCPayServer.Tests { public class CustomServer : IDisposable { - TaskCompletionSource _Evt = null; IWebHost _Host = null; CancellationTokenSource _Closed = new CancellationTokenSource(); + Channel _Requests = Channel.CreateUnbounded(); public CustomServer() - { + { var port = Utils.FreeTcpPort(); _Host = new WebHostBuilder() .Configure(app => { app.Run(req => { - while (_Act == null) - { - Thread.Sleep(10); - _Closed.Token.ThrowIfCancellationRequested(); - } - _Act(req); - _Act = null; - _Evt.TrySetResult(true); + _Requests.Writer.WriteAsync(JsonConvert.DeserializeObject(new StreamReader(req.Request.Body).ReadToEnd()), _Closed.Token); req.Response.StatusCode = 200; return Task.CompletedTask; }); @@ -47,22 +44,24 @@ namespace BTCPayServer.Tests return new Uri(_Host.ServerFeatures.Get().Addresses.First()); } - Action _Act; - public void ProcessNextRequest(Action act) + public async Task GetNextRequest() { - var source = new TaskCompletionSource(); - CancellationTokenSource cancellation = new CancellationTokenSource(20000); - cancellation.Token.Register(() => source.TrySetCanceled()); - source = new TaskCompletionSource(); - _Evt = source; - _Act = act; - try + using (CancellationTokenSource cancellation = new CancellationTokenSource(2000000)) { - _Evt.Task.GetAwaiter().GetResult(); - } - catch (TaskCanceledException) - { - throw new Xunit.Sdk.XunitException("Callback to the webserver was expected, check if the callback url is accessible from internet"); + try + { + JObject req = null; + while(!await _Requests.Reader.WaitToReadAsync(cancellation.Token) || + !_Requests.Reader.TryRead(out req)) + { + + } + return req; + } + catch (TaskCanceledException) + { + throw new Xunit.Sdk.XunitException("Callback to the webserver was expected, check if the callback url is accessible from internet"); + } } } diff --git a/BTCPayServer.Tests/TestAccount.cs b/BTCPayServer.Tests/TestAccount.cs index 16c91bd2b..bfe337b52 100644 --- a/BTCPayServer.Tests/TestAccount.cs +++ b/BTCPayServer.Tests/TestAccount.cs @@ -60,10 +60,17 @@ namespace BTCPayServer.Tests } public void SetNetworkFeeMode(NetworkFeeMode mode) + { + ModifyStore((store) => + { + store.NetworkFeeMode = mode; + }); + } + public void ModifyStore(Action modify) { var storeController = GetController(); StoreViewModel store = (StoreViewModel)((ViewResult)storeController.UpdateStore()).Model; - store.NetworkFeeMode = mode; + modify(store); storeController.UpdateStore(store).GetAwaiter().GetResult(); } diff --git a/BTCPayServer.Tests/UnitTest1.cs b/BTCPayServer.Tests/UnitTest1.cs index 12f1ad5f7..6c94c1115 100644 --- a/BTCPayServer.Tests/UnitTest1.cs +++ b/BTCPayServer.Tests/UnitTest1.cs @@ -486,7 +486,7 @@ namespace BTCPayServer.Tests [Fact] [Trait("Integration", "Integration")] - public void CanSendIPN() + public async Task CanSendIPN() { using (var callbackServer = new CustomServer()) { @@ -496,7 +496,7 @@ namespace BTCPayServer.Tests var acc = tester.NewAccount(); acc.GrantAccess(); acc.RegisterDerivationScheme("BTC"); - acc.SetNetworkFeeMode(NetworkFeeMode.Always); + acc.ModifyStore(s => s.SpeedPolicy = SpeedPolicy.LowSpeed); var invoice = acc.BitPay.CreateInvoice(new Invoice() { Price = 5.0m, @@ -509,13 +509,43 @@ namespace BTCPayServer.Tests ExtendedNotifications = true }); BitcoinUrlBuilder url = new BitcoinUrlBuilder(invoice.PaymentUrls.BIP21); - tester.ExplorerNode.SendToAddress(url.Address, url.Amount); - Thread.Sleep(5000); - callbackServer.ProcessNextRequest((ctx) => + bool receivedPayment = false; + bool paid = false; + bool confirmed = false; + bool completed = false; + while (!completed || !confirmed) { - var ipn = new StreamReader(ctx.Request.Body).ReadToEnd(); - JsonConvert.DeserializeObject(ipn); //can deserialize - }); + var request = await callbackServer.GetNextRequest(); + if (request.ContainsKey("event")) + { + var evtName = request["event"]["name"].Value(); + switch (evtName) + { + case "invoice_created": + tester.ExplorerNode.SendToAddress(url.Address, url.Amount); + break; + case "invoice_receivedPayment": + receivedPayment = true; + break; + case "invoice_paidInFull": + Assert.True(receivedPayment); + tester.ExplorerNode.Generate(6); + paid = true; + break; + case "invoice_confirmed": + Assert.True(paid); + confirmed = true; + break; + case "invoice_completed": + Assert.True(paid); //TODO: Fix, out of order event mean we can receive invoice_confirmed after invoice_complete + completed = true; + break; + default: + Assert.False(true, $"{evtName} was not expected"); + break; + } + } + } var invoice2 = acc.BitPay.GetInvoice(invoice.Id); Assert.NotNull(invoice2); }