Compare commits
25 Commits
Author | SHA1 | Date | |
---|---|---|---|
a82f181126 | |||
be0139a46f | |||
4db5b4f2b1 | |||
93cefced80 | |||
85f586f623 | |||
2be1f97419 | |||
63014231ab | |||
3ac37497ab | |||
d0cafb020f | |||
d3b3198b68 | |||
c1f17ff63b | |||
dafd958f69 | |||
f51af6c61c | |||
254db22063 | |||
8be4256278 | |||
8e8669d63f | |||
4625ff92f1 | |||
6aa84326af | |||
9a384d81fe | |||
0cbe36c048 | |||
7f16aa8c7e | |||
872f8a6229 | |||
9b261daa6d | |||
c46c15c258 | |||
a8ba1ed1ed |
29
.circleci/config.yml
Normal file
29
.circleci/config.yml
Normal file
@ -0,0 +1,29 @@
|
||||
version: 2
|
||||
jobs:
|
||||
build:
|
||||
machine:
|
||||
docker_layer_caching: true
|
||||
steps:
|
||||
- checkout
|
||||
test:
|
||||
machine: true
|
||||
steps:
|
||||
- checkout
|
||||
- run:
|
||||
command: |
|
||||
lsb_release -a
|
||||
wget -q https://packages.microsoft.com/config/ubuntu/14.04/packages-microsoft-prod.deb
|
||||
sudo dpkg -i packages-microsoft-prod.deb
|
||||
sudo apt-get install apt-transport-https
|
||||
sudo apt-get update
|
||||
sudo apt-get install dotnet-sdk-2.1
|
||||
dotnet build /p:TreatWarningsAsErrors=true
|
||||
cd BTCPayServer.Tests
|
||||
dotnet test --filter Fast=Fast
|
||||
docker-compose up -d dev
|
||||
dotnet test --filter Integration=Integration
|
||||
workflows:
|
||||
version: 2
|
||||
build_and_test:
|
||||
jobs:
|
||||
- test
|
@ -10,8 +10,8 @@
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="15.9.0" />
|
||||
<PackageReference Include="xunit" Version="2.4.0" />
|
||||
<PackageReference Include="xunit.runner.visualstudio" Version="2.4.0">
|
||||
<PackageReference Include="xunit" Version="2.4.1" />
|
||||
<PackageReference Include="xunit.runner.visualstudio" Version="2.4.1">
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers</IncludeAssets>
|
||||
</PackageReference>
|
||||
@ -24,6 +24,9 @@
|
||||
<None Update="docker-compose.yml">
|
||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||
</None>
|
||||
<None Update="xunit.runner.json">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</None>
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
|
@ -1,4 +1,6 @@
|
||||
using BTCPayServer.Configuration;
|
||||
using System.Linq;
|
||||
using BTCPayServer.HostedServices;
|
||||
using BTCPayServer.Hosting;
|
||||
using BTCPayServer.Payments;
|
||||
using BTCPayServer.Payments.Lightning;
|
||||
@ -138,6 +140,11 @@ namespace BTCPayServer.Tests
|
||||
_Host.Start();
|
||||
InvoiceRepository = (InvoiceRepository)_Host.Services.GetService(typeof(InvoiceRepository));
|
||||
StoreRepository = (StoreRepository)_Host.Services.GetService(typeof(StoreRepository));
|
||||
var dashBoard = (NBXplorerDashboard)_Host.Services.GetService(typeof(NBXplorerDashboard));
|
||||
while(!dashBoard.IsFullySynched())
|
||||
{
|
||||
Thread.Sleep(10);
|
||||
}
|
||||
|
||||
if (MockRates)
|
||||
{
|
||||
|
@ -28,6 +28,7 @@ namespace BTCPayServer.Tests
|
||||
}
|
||||
|
||||
[Fact]
|
||||
[Trait("Integration", "Integration")]
|
||||
public async void CanSetChangellyPaymentMethod()
|
||||
{
|
||||
using (var tester = ServerTester.Create())
|
||||
@ -68,6 +69,7 @@ namespace BTCPayServer.Tests
|
||||
|
||||
|
||||
[Fact]
|
||||
[Trait("Integration", "Integration")]
|
||||
public async void CanToggleChangellyPaymentMethod()
|
||||
{
|
||||
using (var tester = ServerTester.Create())
|
||||
@ -83,6 +85,7 @@ namespace BTCPayServer.Tests
|
||||
ApiKey = "key",
|
||||
ApiUrl = "http://gozo.com",
|
||||
ChangellyMerchantId = "aaa",
|
||||
Enabled = true
|
||||
};
|
||||
Assert.Equal("UpdateStore", Assert.IsType<RedirectToActionResult>(
|
||||
await controller.UpdateChangellySettings(user.StoreId, updateModel, "save")).ActionName);
|
||||
@ -104,6 +107,7 @@ namespace BTCPayServer.Tests
|
||||
}
|
||||
|
||||
[Fact]
|
||||
[Trait("Integration", "Integration")]
|
||||
public async void CannotUseChangellyApiWithoutChangellyPaymentMethodSet()
|
||||
{
|
||||
using (var tester = ServerTester.Create())
|
||||
@ -114,16 +118,13 @@ namespace BTCPayServer.Tests
|
||||
var changellyController =
|
||||
tester.PayTester.GetController<ChangellyController>(user.UserId, user.StoreId);
|
||||
changellyController.IsTest = true;
|
||||
|
||||
|
||||
//test non existing payment method
|
||||
Assert.IsType<BitpayErrorModel>(Assert
|
||||
.IsType<BadRequestObjectResult>(await changellyController.GetCurrencyList(user.StoreId))
|
||||
.Value);
|
||||
|
||||
var updateModel = new UpdateChangellySettingsViewModel
|
||||
{
|
||||
Enabled = false
|
||||
};
|
||||
var updateModel = CreateDefaultChangellyParams(false);
|
||||
var storesController = tester.PayTester.GetController<StoresController>(user.UserId, user.StoreId);
|
||||
//set payment method but disabled
|
||||
|
||||
@ -142,7 +143,6 @@ namespace BTCPayServer.Tests
|
||||
Assert.Equal("UpdateStore", Assert.IsType<RedirectToActionResult>(
|
||||
await storesController.UpdateChangellySettings(user.StoreId, updateModel, "save")).ActionName);
|
||||
|
||||
|
||||
|
||||
Assert.IsNotType<BitpayErrorModel>(Assert
|
||||
.IsType<OkObjectResult>(await changellyController.GetCurrencyList(user.StoreId))
|
||||
@ -150,8 +150,19 @@ namespace BTCPayServer.Tests
|
||||
}
|
||||
}
|
||||
|
||||
UpdateChangellySettingsViewModel CreateDefaultChangellyParams(bool enabled)
|
||||
{
|
||||
return new UpdateChangellySettingsViewModel()
|
||||
{
|
||||
ApiKey = "6ed02cdf1b614d89a8c0ceb170eebb61",
|
||||
ApiSecret = "8fbd66a2af5fd15a6b5f8ed0159c5842e32a18538521ffa145bd6c9e124d3483",
|
||||
ChangellyMerchantId = "804298eb5753",
|
||||
Enabled = enabled
|
||||
};
|
||||
}
|
||||
|
||||
[Fact]
|
||||
[Trait("Integration", "Integration")]
|
||||
public async void CanGetCurrencyListFromChangelly()
|
||||
{
|
||||
using (var tester = ServerTester.Create())
|
||||
@ -161,32 +172,30 @@ namespace BTCPayServer.Tests
|
||||
user.GrantAccess();
|
||||
|
||||
//save changelly settings
|
||||
var updateModel = new UpdateChangellySettingsViewModel()
|
||||
{
|
||||
Enabled = true
|
||||
};
|
||||
var updateModel = CreateDefaultChangellyParams(true);
|
||||
var storesController = tester.PayTester.GetController<StoresController>(user.UserId, user.StoreId);
|
||||
|
||||
//confirm saved
|
||||
Assert.Equal("UpdateStore", Assert.IsType<RedirectToActionResult>(
|
||||
await storesController.UpdateChangellySettings(user.StoreId, updateModel, "save")).ActionName);
|
||||
|
||||
|
||||
var factory = UnitTest1.CreateBTCPayRateFactory();
|
||||
var fetcher = new RateFetcher(factory);
|
||||
var httpClientFactory = new MockHttpClientFactory();
|
||||
var changellyController = new ChangellyController(
|
||||
new ChangellyClientProvider(tester.PayTester.StoreRepository,httpClientFactory), tester.NetworkProvider, fetcher);
|
||||
new ChangellyClientProvider(tester.PayTester.StoreRepository, httpClientFactory),
|
||||
tester.NetworkProvider, fetcher);
|
||||
changellyController.IsTest = true;
|
||||
var result = Assert
|
||||
.IsType<OkObjectResult>(await changellyController.GetCurrencyList(user.StoreId))
|
||||
.Value as IEnumerable<CurrencyFull>;
|
||||
Assert.True(result.Any());
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
[Fact]
|
||||
[Trait("Integration", "Integration")]
|
||||
public async void CanCalculateToAmountForChangelly()
|
||||
{
|
||||
using (var tester = ServerTester.Create())
|
||||
@ -195,10 +204,7 @@ namespace BTCPayServer.Tests
|
||||
var user = tester.NewAccount();
|
||||
user.GrantAccess();
|
||||
|
||||
var updateModel = new UpdateChangellySettingsViewModel()
|
||||
{
|
||||
Enabled = true
|
||||
};
|
||||
var updateModel = CreateDefaultChangellyParams(true);
|
||||
var storesController = tester.PayTester.GetController<StoresController>(user.UserId, user.StoreId);
|
||||
|
||||
Assert.Equal("UpdateStore", Assert.IsType<RedirectToActionResult>(
|
||||
@ -208,20 +214,40 @@ namespace BTCPayServer.Tests
|
||||
var fetcher = new RateFetcher(factory);
|
||||
var httpClientFactory = new MockHttpClientFactory();
|
||||
var changellyController = new ChangellyController(
|
||||
new ChangellyClientProvider(tester.PayTester.StoreRepository,httpClientFactory), tester.NetworkProvider, fetcher);
|
||||
new ChangellyClientProvider(tester.PayTester.StoreRepository, httpClientFactory),
|
||||
tester.NetworkProvider, fetcher);
|
||||
changellyController.IsTest = true;
|
||||
Assert.IsType<decimal>(Assert
|
||||
.IsType<OkObjectResult>(await changellyController.CalculateAmount(user.StoreId, "ltc", "btc", 1.0m)).Value);
|
||||
|
||||
.IsType<OkObjectResult>(await changellyController.CalculateAmount(user.StoreId, "ltc", "btc", 1.0m))
|
||||
.Value);
|
||||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
[Trait("Integration", "Integration")]
|
||||
public void CanComputeBaseAmount()
|
||||
{
|
||||
Assert.Equal(1, ChangellyCalculationHelper.ComputeBaseAmount(1, 1));
|
||||
Assert.Equal(0.5m, ChangellyCalculationHelper.ComputeBaseAmount(1, 0.5m));
|
||||
Assert.Equal(2, ChangellyCalculationHelper.ComputeBaseAmount(0.5m, 1));
|
||||
Assert.Equal(4m, ChangellyCalculationHelper.ComputeBaseAmount(1, 4));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
[Trait("Integration", "Integration")]
|
||||
public void CanComputeCorrectAmount()
|
||||
{
|
||||
Assert.Equal(1, ChangellyCalculationHelper.ComputeCorrectAmount(0.5m, 1, 2));
|
||||
Assert.Equal(0.25m, ChangellyCalculationHelper.ComputeCorrectAmount(0.5m, 1, 0.5m));
|
||||
Assert.Equal(20, ChangellyCalculationHelper.ComputeCorrectAmount(10, 1, 2));
|
||||
}
|
||||
}
|
||||
|
||||
public class MockHttpClientFactory : IHttpClientFactory
|
||||
{
|
||||
public HttpClient CreateClient(string name)
|
||||
{
|
||||
return new HttpClient();
|
||||
return new HttpClient();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,4 +1,4 @@
|
||||
FROM microsoft/dotnet:2.1.300-sdk-alpine3.7
|
||||
FROM microsoft/dotnet:2.1.403-sdk-alpine3.7
|
||||
WORKDIR /app
|
||||
# caches restore result by copying csproj file separately
|
||||
COPY BTCPayServer.Tests/BTCPayServer.Tests.csproj BTCPayServer.Tests/BTCPayServer.Tests.csproj
|
||||
|
@ -11,6 +11,7 @@ namespace BTCPayServer.Tests
|
||||
public class RateRulesTest
|
||||
{
|
||||
[Fact]
|
||||
[Trait("Fast", "Fast")]
|
||||
public void SecondDuplicatedRuleIsIgnored()
|
||||
{
|
||||
StringBuilder builder = new StringBuilder();
|
||||
@ -24,6 +25,7 @@ namespace BTCPayServer.Tests
|
||||
}
|
||||
|
||||
[Fact]
|
||||
[Trait("Fast", "Fast")]
|
||||
public void CanParseRateRules()
|
||||
{
|
||||
// Check happy path
|
||||
|
@ -84,7 +84,7 @@ namespace BTCPayServer.Tests
|
||||
/// Connect a customer LN node to the merchant LN node
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public Task EnsureConnectedToDestinations()
|
||||
public Task EnsureChannelsSetup()
|
||||
{
|
||||
return BTCPayServer.Lightning.Tests.ConnectChannels.ConnectAll(ExplorerNode, GetLightningSenderClients(), GetLightningDestClients());
|
||||
}
|
||||
|
@ -44,6 +44,7 @@ using BTCPayServer.Lightning;
|
||||
using BTCPayServer.Models.WalletViewModels;
|
||||
using System.Security.Claims;
|
||||
using BTCPayServer.Security;
|
||||
using NBXplorer.Models;
|
||||
|
||||
namespace BTCPayServer.Tests
|
||||
{
|
||||
@ -56,6 +57,7 @@ namespace BTCPayServer.Tests
|
||||
}
|
||||
|
||||
[Fact]
|
||||
[Trait("Fast", "Fast")]
|
||||
public void CanHandleUriValidation()
|
||||
{
|
||||
var attribute = new UriAttribute();
|
||||
@ -77,6 +79,7 @@ namespace BTCPayServer.Tests
|
||||
}
|
||||
|
||||
[Fact]
|
||||
[Trait("Fast", "Fast")]
|
||||
public void CanCalculateCryptoDue2()
|
||||
{
|
||||
var dummy = new Key().PubKey.GetAddress(Network.RegTest).ToString();
|
||||
@ -134,6 +137,7 @@ namespace BTCPayServer.Tests
|
||||
}
|
||||
|
||||
[Fact]
|
||||
[Trait("Fast", "Fast")]
|
||||
public void CanCalculateCryptoDue()
|
||||
{
|
||||
var entity = new InvoiceEntity();
|
||||
@ -258,6 +262,7 @@ namespace BTCPayServer.Tests
|
||||
}
|
||||
|
||||
[Fact]
|
||||
[Trait("Integration", "Integration")]
|
||||
public void CanAcceptInvoiceWithTolerance()
|
||||
{
|
||||
var entity = new InvoiceEntity();
|
||||
@ -285,6 +290,7 @@ namespace BTCPayServer.Tests
|
||||
}
|
||||
|
||||
[Fact]
|
||||
[Trait("Integration", "Integration")]
|
||||
public void CanAcceptInvoiceWithTolerance2()
|
||||
{
|
||||
using (var tester = ServerTester.Create())
|
||||
@ -325,6 +331,7 @@ namespace BTCPayServer.Tests
|
||||
}
|
||||
|
||||
[Fact]
|
||||
[Trait("Fast", "Fast")]
|
||||
public void RoundupCurrenciesCorrectly()
|
||||
{
|
||||
foreach (var test in new[]
|
||||
@ -341,6 +348,7 @@ namespace BTCPayServer.Tests
|
||||
}
|
||||
|
||||
[Fact]
|
||||
[Trait("Integration", "Integration")]
|
||||
public void CanPayUsingBIP70()
|
||||
{
|
||||
using (var tester = ServerTester.Create())
|
||||
@ -391,11 +399,13 @@ namespace BTCPayServer.Tests
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void CanSetLightningServer()
|
||||
[Trait("Integration", "Integration")]
|
||||
public async Task CanSetLightningServer()
|
||||
{
|
||||
using (var tester = ServerTester.Create())
|
||||
{
|
||||
tester.Start();
|
||||
await tester.EnsureChannelsSetup();
|
||||
var user = tester.NewAccount();
|
||||
user.GrantAccess();
|
||||
var storeController = user.GetController<StoresController>();
|
||||
@ -427,18 +437,21 @@ namespace BTCPayServer.Tests
|
||||
}
|
||||
|
||||
[Fact]
|
||||
[Trait("Integration", "Integration")]
|
||||
public async Task CanSendLightningPaymentCLightning()
|
||||
{
|
||||
await ProcessLightningPayment(LightningConnectionType.CLightning);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
[Trait("Integration", "Integration")]
|
||||
public async Task CanSendLightningPaymentCharge()
|
||||
{
|
||||
await ProcessLightningPayment(LightningConnectionType.Charge);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
[Trait("Integration", "Integration")]
|
||||
public async Task CanSendLightningPaymentLnd()
|
||||
{
|
||||
await ProcessLightningPayment(LightningConnectionType.LndREST);
|
||||
@ -452,13 +465,12 @@ namespace BTCPayServer.Tests
|
||||
using (var tester = ServerTester.Create())
|
||||
{
|
||||
tester.Start();
|
||||
await tester.EnsureChannelsSetup();
|
||||
var user = tester.NewAccount();
|
||||
user.GrantAccess();
|
||||
user.RegisterLightningNode("BTC", type);
|
||||
user.RegisterDerivationScheme("BTC");
|
||||
|
||||
await tester.EnsureConnectedToDestinations();
|
||||
|
||||
await CanSendLightningPaymentCore(tester, user);
|
||||
|
||||
await Task.WhenAll(Enumerable.Range(0, 5)
|
||||
@ -469,10 +481,6 @@ namespace BTCPayServer.Tests
|
||||
|
||||
async Task CanSendLightningPaymentCore(ServerTester tester, TestAccount user)
|
||||
{
|
||||
// TODO: If this parameter is less than 1 second we start having concurrency problems
|
||||
await Task.Delay(TimeSpan.FromMilliseconds(1000));
|
||||
//
|
||||
|
||||
var invoice = await user.BitPay.CreateInvoiceAsync(new Invoice()
|
||||
{
|
||||
Price = 0.01m,
|
||||
@ -481,6 +489,7 @@ namespace BTCPayServer.Tests
|
||||
OrderId = "orderId",
|
||||
ItemDesc = "Some description"
|
||||
});
|
||||
await Task.Delay(TimeSpan.FromMilliseconds(1000)); // Give time to listen the new invoices
|
||||
await tester.SendLightningPaymentAsync(invoice);
|
||||
await EventuallyAsync(async () =>
|
||||
{
|
||||
@ -491,6 +500,7 @@ namespace BTCPayServer.Tests
|
||||
}
|
||||
|
||||
[Fact]
|
||||
[Trait("Integration", "Integration")]
|
||||
public void CanUseServerInitiatedPairingCode()
|
||||
{
|
||||
using (var tester = ServerTester.Create())
|
||||
@ -516,6 +526,7 @@ namespace BTCPayServer.Tests
|
||||
}
|
||||
|
||||
[Fact]
|
||||
[Trait("Integration", "Integration")]
|
||||
public void CanSendIPN()
|
||||
{
|
||||
using (var callbackServer = new CustomServer())
|
||||
@ -552,6 +563,7 @@ namespace BTCPayServer.Tests
|
||||
}
|
||||
|
||||
[Fact]
|
||||
[Trait("Integration", "Integration")]
|
||||
public void CantPairTwiceWithSamePubkey()
|
||||
{
|
||||
using (var tester = ServerTester.Create())
|
||||
@ -573,6 +585,7 @@ namespace BTCPayServer.Tests
|
||||
}
|
||||
|
||||
[Fact]
|
||||
[Trait("Integration", "Integration")]
|
||||
public void CanRescanWallet()
|
||||
{
|
||||
using (var tester = ServerTester.Create())
|
||||
@ -639,6 +652,7 @@ namespace BTCPayServer.Tests
|
||||
}
|
||||
|
||||
[Fact]
|
||||
[Trait("Integration", "Integration")]
|
||||
public void CanListInvoices()
|
||||
{
|
||||
using (var tester = ServerTester.Create())
|
||||
@ -680,6 +694,7 @@ namespace BTCPayServer.Tests
|
||||
}
|
||||
|
||||
[Fact]
|
||||
[Trait("Integration", "Integration")]
|
||||
public void CanGetRates()
|
||||
{
|
||||
using (var tester = ServerTester.Create())
|
||||
@ -727,6 +742,7 @@ namespace BTCPayServer.Tests
|
||||
}
|
||||
|
||||
[Fact]
|
||||
[Trait("Integration", "Integration")]
|
||||
public void CanRBFPayment()
|
||||
{
|
||||
using (var tester = ServerTester.Create())
|
||||
@ -742,6 +758,7 @@ namespace BTCPayServer.Tests
|
||||
}, Facade.Merchant);
|
||||
var payment1 = invoice.BtcDue + Money.Coins(0.0001m);
|
||||
var payment2 = invoice.BtcDue;
|
||||
|
||||
var tx1 = new uint256(tester.ExplorerNode.SendCommand("sendtoaddress", new object[]
|
||||
{
|
||||
invoice.BitcoinAddress,
|
||||
@ -751,8 +768,10 @@ namespace BTCPayServer.Tests
|
||||
false, //subtractfeefromamount
|
||||
true, //replaceable
|
||||
}).ResultString);
|
||||
Logs.Tester.LogInformation($"Let's send a first payment of {payment1} for the {invoice.BtcDue} invoice ({tx1})");
|
||||
var invoiceAddress = BitcoinAddress.Create(invoice.BitcoinAddress, user.SupportedNetwork.NBitcoinNetwork);
|
||||
|
||||
Logs.Tester.LogInformation($"The invoice should be paidOver");
|
||||
Eventually(() =>
|
||||
{
|
||||
invoice = user.BitPay.GetInvoice(invoice.Id);
|
||||
@ -770,9 +789,17 @@ namespace BTCPayServer.Tests
|
||||
var output = tx.Outputs.First(o => o.Value == payment1);
|
||||
output.Value = payment2;
|
||||
output.ScriptPubKey = invoiceAddress.ScriptPubKey;
|
||||
var replaced = tester.ExplorerNode.SignRawTransaction(tx);
|
||||
tester.ExplorerNode.SendRawTransaction(replaced);
|
||||
var test = tester.ExplorerClient.GetUTXOs(user.DerivationScheme, null);
|
||||
|
||||
using(var cts = new CancellationTokenSource(10000))
|
||||
using (var listener = tester.ExplorerClient.CreateNotificationSession())
|
||||
{
|
||||
listener.ListenAllDerivationSchemes();
|
||||
var replaced = tester.ExplorerNode.SignRawTransaction(tx);
|
||||
var tx2 = tester.ExplorerNode.SendRawTransaction(replaced);
|
||||
Logs.Tester.LogInformation($"Let's RBF with a payment of {payment2} ({tx2}), waiting for NBXplorer to pick it up");
|
||||
Assert.Equal(tx2, ((NewTransactionEvent)listener.NextEvent(cts.Token)).TransactionData.TransactionHash);
|
||||
}
|
||||
Logs.Tester.LogInformation($"The invoice should now not be paidOver anymore");
|
||||
Eventually(() =>
|
||||
{
|
||||
invoice = user.BitPay.GetInvoice(invoice.Id);
|
||||
@ -783,6 +810,7 @@ namespace BTCPayServer.Tests
|
||||
}
|
||||
|
||||
[Fact]
|
||||
[Trait("Fast", "Fast")]
|
||||
public void CanParseFilter()
|
||||
{
|
||||
var filter = "storeid:abc status:abed blabhbalh ";
|
||||
@ -804,6 +832,7 @@ namespace BTCPayServer.Tests
|
||||
}
|
||||
|
||||
[Fact]
|
||||
[Trait("Fast", "Fast")]
|
||||
public void CanParseFingerprint()
|
||||
{
|
||||
Assert.True(SSH.SSHFingerprint.TryParse("4e343c6fc6cfbf9339c02d06a151e1dd", out var unused));
|
||||
@ -820,6 +849,7 @@ namespace BTCPayServer.Tests
|
||||
}
|
||||
|
||||
[Fact]
|
||||
[Trait("Integration", "Integration")]
|
||||
public void TestAccessBitpayAPI()
|
||||
{
|
||||
using (var tester = ServerTester.Create())
|
||||
@ -886,6 +916,7 @@ namespace BTCPayServer.Tests
|
||||
}
|
||||
|
||||
[Fact]
|
||||
[Trait("Integration", "Integration")]
|
||||
public void CanUseExchangeSpecificRate()
|
||||
{
|
||||
using (var tester = ServerTester.Create())
|
||||
@ -928,6 +959,7 @@ namespace BTCPayServer.Tests
|
||||
}
|
||||
|
||||
[Fact]
|
||||
[Trait("Integration", "Integration")]
|
||||
public void CanTweakRate()
|
||||
{
|
||||
using (var tester = ServerTester.Create())
|
||||
@ -972,6 +1004,7 @@ namespace BTCPayServer.Tests
|
||||
}
|
||||
|
||||
[Fact]
|
||||
[Trait("Integration", "Integration")]
|
||||
public void CanHaveLTCOnlyStore()
|
||||
{
|
||||
using (var tester = ServerTester.Create())
|
||||
@ -1036,6 +1069,7 @@ namespace BTCPayServer.Tests
|
||||
}
|
||||
|
||||
[Fact]
|
||||
[Trait("Integration", "Integration")]
|
||||
public void CanModifyRates()
|
||||
{
|
||||
using (var tester = ServerTester.Create())
|
||||
@ -1096,6 +1130,7 @@ namespace BTCPayServer.Tests
|
||||
}
|
||||
|
||||
[Fact]
|
||||
[Trait("Integration", "Integration")]
|
||||
public void CanPayWithTwoCurrencies()
|
||||
{
|
||||
using (var tester = ServerTester.Create())
|
||||
@ -1207,6 +1242,7 @@ namespace BTCPayServer.Tests
|
||||
}
|
||||
|
||||
[Fact]
|
||||
[Trait("Fast", "Fast")]
|
||||
public void CanParseCurrencyValue()
|
||||
{
|
||||
Assert.True(CurrencyValue.TryParse("1.50USD", out var result));
|
||||
@ -1227,6 +1263,7 @@ namespace BTCPayServer.Tests
|
||||
}
|
||||
|
||||
[Fact]
|
||||
[Trait("Fast", "Fast")]
|
||||
public void CanParseDerivationScheme()
|
||||
{
|
||||
var parser = new DerivationSchemeParser(Network.TestNet);
|
||||
@ -1267,6 +1304,7 @@ namespace BTCPayServer.Tests
|
||||
}
|
||||
|
||||
[Fact]
|
||||
[Trait("Integration", "Integration")]
|
||||
public void CanDisablePaymentMethods()
|
||||
{
|
||||
using (var tester = ServerTester.Create())
|
||||
@ -1325,11 +1363,13 @@ namespace BTCPayServer.Tests
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void CanSetPaymentMethodLimits()
|
||||
[Trait("Integration", "Integration")]
|
||||
public async Task CanSetPaymentMethodLimits()
|
||||
{
|
||||
using (var tester = ServerTester.Create())
|
||||
{
|
||||
tester.Start();
|
||||
await tester.EnsureChannelsSetup();
|
||||
var user = tester.NewAccount();
|
||||
user.GrantAccess();
|
||||
user.RegisterDerivationScheme("BTC");
|
||||
@ -1368,6 +1408,7 @@ namespace BTCPayServer.Tests
|
||||
}
|
||||
|
||||
[Fact]
|
||||
[Trait("Integration", "Integration")]
|
||||
public void CanUsePoSApp()
|
||||
{
|
||||
using (var tester = ServerTester.Create())
|
||||
@ -1412,6 +1453,7 @@ namespace BTCPayServer.Tests
|
||||
}
|
||||
|
||||
[Fact]
|
||||
[Trait("Integration", "Integration")]
|
||||
public void CanCreateAndDeleteApps()
|
||||
{
|
||||
using (var tester = ServerTester.Create())
|
||||
@ -1448,6 +1490,7 @@ namespace BTCPayServer.Tests
|
||||
}
|
||||
|
||||
[Fact]
|
||||
[Trait("Integration", "Integration")]
|
||||
public void InvoiceFlowThroughDifferentStatesCorrectly()
|
||||
{
|
||||
using (var tester = ServerTester.Create())
|
||||
@ -1604,6 +1647,7 @@ namespace BTCPayServer.Tests
|
||||
}
|
||||
|
||||
[Fact]
|
||||
[Trait("Integration", "Integration")]
|
||||
public void CheckQuadrigacxRateProvider()
|
||||
{
|
||||
var quadri = new QuadrigacxRateProvider();
|
||||
@ -1617,6 +1661,7 @@ namespace BTCPayServer.Tests
|
||||
}
|
||||
|
||||
[Fact]
|
||||
[Trait("Integration", "Integration")]
|
||||
public void CanQueryDirectProviders()
|
||||
{
|
||||
var factory = CreateBTCPayRateFactory();
|
||||
@ -1647,6 +1692,7 @@ namespace BTCPayServer.Tests
|
||||
}
|
||||
|
||||
[Fact]
|
||||
[Trait("Integration", "Integration")]
|
||||
public void CanGetRateCryptoCurrenciesByDefault()
|
||||
{
|
||||
var provider = new BTCPayNetworkProvider(NetworkType.Mainnet);
|
||||
@ -1662,7 +1708,8 @@ namespace BTCPayServer.Tests
|
||||
foreach (var value in result)
|
||||
{
|
||||
var rateResult = value.Value.GetAwaiter().GetResult();
|
||||
Assert.NotNull(rateResult.BidAsk);
|
||||
Logs.Tester.LogInformation($"Testing {value.Key.ToString()}");
|
||||
Assert.True(rateResult.BidAsk != null, $"Impossible to get the rate {rateResult.EvaluatedRule}");
|
||||
}
|
||||
}
|
||||
|
||||
@ -1700,6 +1747,7 @@ namespace BTCPayServer.Tests
|
||||
}
|
||||
|
||||
[Fact]
|
||||
[Trait("Fast", "Fast")]
|
||||
public void CheckRatesProvider()
|
||||
{
|
||||
var spy = new SpyRateProvider();
|
||||
|
@ -69,7 +69,7 @@ services:
|
||||
|
||||
|
||||
nbxplorer:
|
||||
image: nicolasdorier/nbxplorer:1.1.0.4
|
||||
image: nicolasdorier/nbxplorer:1.1.0.8
|
||||
restart: unless-stopped
|
||||
ports:
|
||||
- "32838:32838"
|
||||
|
3
BTCPayServer.Tests/xunit.runner.json
Normal file
3
BTCPayServer.Tests/xunit.runner.json
Normal file
@ -0,0 +1,3 @@
|
||||
{
|
||||
"parallelizeTestCollections": false
|
||||
}
|
@ -2,7 +2,7 @@
|
||||
<PropertyGroup>
|
||||
<OutputType>Exe</OutputType>
|
||||
<TargetFramework>netcoreapp2.1</TargetFramework>
|
||||
<Version>1.0.3.0</Version>
|
||||
<Version>1.0.3.4</Version>
|
||||
<NoWarn>NU1701,CA1816,CA1308,CA1810,CA2208</NoWarn>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup>
|
||||
@ -36,34 +36,39 @@
|
||||
<PackageReference Include="BTCPayServer.Lightning.All" Version="1.1.0.1" />
|
||||
<PackageReference Include="BuildBundlerMinifier" Version="2.7.385" />
|
||||
<PackageReference Include="DigitalRuby.ExchangeSharp" Version="0.5.3" />
|
||||
<PackageReference Include="Hangfire" Version="1.6.19" />
|
||||
<PackageReference Include="Hangfire" Version="1.6.20" />
|
||||
<PackageReference Include="Hangfire.MemoryStorage" Version="1.5.2" />
|
||||
<PackageReference Include="Hangfire.PostgreSql" Version="1.4.8.2" />
|
||||
<PackageReference Include="LedgerWallet" Version="2.0.0.2" />
|
||||
<PackageReference Include="Meziantou.AspNetCore.BundleTagHelpers" Version="2.0.0" />
|
||||
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite" Version="2.1.0" />
|
||||
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite" Version="2.1.4" />
|
||||
<PackageReference Include="Microsoft.Extensions.Logging.Filter" Version="1.1.2" />
|
||||
<PackageReference Include="Microsoft.NetCore.Analyzers" Version="2.6.0" />
|
||||
<PackageReference Include="Microsoft.NetCore.Analyzers" Version="2.6.2">
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers</IncludeAssets>
|
||||
</PackageReference>
|
||||
<PackageReference Include="NBitcoin" Version="4.1.1.66" />
|
||||
<PackageReference Include="NBitpayClient" Version="1.0.0.30" />
|
||||
<PackageReference Include="DBreeze" Version="1.87.0" />
|
||||
<PackageReference Include="NBXplorer.Client" Version="1.0.3.3" />
|
||||
<PackageReference Include="DBreeze" Version="1.92.0" />
|
||||
<PackageReference Include="NBXplorer.Client" Version="1.0.3.4" />
|
||||
<PackageReference Include="NicolasDorier.CommandLine" Version="1.0.0.2" />
|
||||
<PackageReference Include="NicolasDorier.CommandLine.Configuration" Version="1.0.0.3" />
|
||||
<PackageReference Include="NicolasDorier.RateLimits" Version="1.0.0.3" />
|
||||
<PackageReference Include="NicolasDorier.StandardConfiguration" Version="1.0.0.18" />
|
||||
<PackageReference Include="Npgsql.EntityFrameworkCore.PostgreSQL" Version="2.1.0" />
|
||||
<PackageReference Include="Npgsql.EntityFrameworkCore.PostgreSQL" Version="2.1.2" />
|
||||
<PackageReference Include="Pomelo.EntityFrameworkCore.MySql" Version="2.1.2" />
|
||||
<PackageReference Include="Serilog" Version="2.7.1" />
|
||||
<PackageReference Include="Serilog.AspNetCore" Version="2.1.1" />
|
||||
<PackageReference Include="Serilog.Sinks.File" Version="4.0.0" />
|
||||
<PackageReference Include="SSH.NET" Version="2016.1.0" />
|
||||
<PackageReference Include="System.Xml.XmlSerializer" Version="4.3.0" />
|
||||
<PackageReference Include="Text.Analyzers" Version="2.6.0" />
|
||||
<PackageReference Include="Text.Analyzers" Version="2.6.2">
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers</IncludeAssets>
|
||||
</PackageReference>
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.AspNetCore.App" Version="2.1.4" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.App" Version="2.1.5" />
|
||||
<PackageReference Include="YamlDotNet" Version="5.2.1" />
|
||||
</ItemGroup>
|
||||
|
||||
|
@ -61,8 +61,8 @@ namespace BTCPayServer.Controllers
|
||||
}
|
||||
|
||||
var callCounter = 0;
|
||||
var response1 = await client.GetExchangeAmount(fromCurrency, toCurrency, 1);
|
||||
var currentAmount = response1;
|
||||
var baseRate = await client.GetExchangeAmount(fromCurrency, toCurrency, 1);
|
||||
var currentAmount = ChangellyCalculationHelper.ComputeBaseAmount(baseRate, toCurrencyAmount);
|
||||
while (true)
|
||||
{
|
||||
if (callCounter > 10)
|
||||
@ -70,13 +70,13 @@ namespace BTCPayServer.Controllers
|
||||
BadRequest();
|
||||
}
|
||||
|
||||
var response2 = await client.GetExchangeAmount(fromCurrency, toCurrency, currentAmount);
|
||||
var computedAmount = await client.GetExchangeAmount(fromCurrency, toCurrency, currentAmount);
|
||||
callCounter++;
|
||||
if (response2 < toCurrencyAmount)
|
||||
if (computedAmount < toCurrencyAmount)
|
||||
{
|
||||
var newCurrentAmount = ((toCurrencyAmount / response2) * 1m) * currentAmount;
|
||||
|
||||
currentAmount = newCurrentAmount;
|
||||
currentAmount =
|
||||
ChangellyCalculationHelper.ComputeCorrectAmount(currentAmount, computedAmount,
|
||||
toCurrencyAmount);
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -114,4 +114,6 @@ namespace BTCPayServer.Controllers
|
||||
|
||||
public bool IsTest { get; set; } = false;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
@ -5,7 +5,6 @@ using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using Hangfire;
|
||||
using Hangfire.MemoryStorage;
|
||||
using Hangfire.PostgreSql;
|
||||
using Microsoft.EntityFrameworkCore.Migrations;
|
||||
using Npgsql.EntityFrameworkCore.PostgreSQL.Migrations;
|
||||
using JetBrains.Annotations;
|
||||
|
@ -43,6 +43,7 @@ using BTCPayServer.Security;
|
||||
using Microsoft.AspNetCore.Mvc.ModelBinding;
|
||||
using NBXplorer.DerivationStrategy;
|
||||
using NicolasDorier.RateLimits;
|
||||
using Npgsql;
|
||||
|
||||
namespace BTCPayServer.Hosting
|
||||
{
|
||||
@ -200,7 +201,7 @@ namespace BTCPayServer.Hosting
|
||||
|
||||
static void Retry(Action act)
|
||||
{
|
||||
CancellationTokenSource cts = new CancellationTokenSource(10000);
|
||||
CancellationTokenSource cts = new CancellationTokenSource(1000);
|
||||
while (true)
|
||||
{
|
||||
try
|
||||
@ -208,7 +209,9 @@ namespace BTCPayServer.Hosting
|
||||
act();
|
||||
return;
|
||||
}
|
||||
catch when(!cts.IsCancellationRequested)
|
||||
// Starting up
|
||||
catch (PostgresException ex) when (ex.SqlState == "57P03") { Thread.Sleep(1000); }
|
||||
catch when (!cts.IsCancellationRequested)
|
||||
{
|
||||
Thread.Sleep(100);
|
||||
}
|
||||
|
@ -8,14 +8,14 @@ namespace BTCPayServer.Models.StoreViewModels
|
||||
{
|
||||
public class UpdateChangellySettingsViewModel
|
||||
{
|
||||
[Required] public string ApiKey { get; set; } = "6ed02cdf1b614d89a8c0ceb170eebb61";
|
||||
[Required] public string ApiKey { get; set; }
|
||||
|
||||
[Required] public string ApiSecret { get; set; } = "8fbd66a2af5fd15a6b5f8ed0159c5842e32a18538521ffa145bd6c9e124d3483";
|
||||
[Required] public string ApiSecret { get; set; }
|
||||
|
||||
[Required] public string ApiUrl { get; set; } = "https://api.changelly.com";
|
||||
|
||||
[Display(Name = "Optional, Changelly Merchant Id")]
|
||||
public string ChangellyMerchantId { get; set; } = "804298eb5753";
|
||||
public string ChangellyMerchantId { get; set; }
|
||||
|
||||
[Display(Name = "Show Fiat Currencies as option in conversion")]
|
||||
public bool ShowFiat { get; set; } = true;
|
||||
@ -26,7 +26,7 @@ namespace BTCPayServer.Models.StoreViewModels
|
||||
"Percentage to multiply amount requested at Changelly to avoid underpaid situations due to Changelly not guaranteeing rates. ")]
|
||||
public decimal AmountMarkupPercentage { get; set; } = new decimal(2);
|
||||
|
||||
public bool Enabled { get; set; } = true;
|
||||
public bool Enabled { get; set; }
|
||||
|
||||
public string StatusMessage { get; set; }
|
||||
}
|
||||
|
@ -149,8 +149,7 @@ namespace BTCPayServer.Payments.Bitcoin
|
||||
foreach (var output in evt.Outputs)
|
||||
{
|
||||
foreach (var txCoin in evt.TransactionData.Transaction.Outputs.AsCoins()
|
||||
.Where(o => o.ScriptPubKey == output.ScriptPubKey)
|
||||
.Select(o => output.Redeem == null ? o : o.ToScriptCoin(output.Redeem)))
|
||||
.Where(o => o.ScriptPubKey == output.ScriptPubKey))
|
||||
{
|
||||
var invoice = await _InvoiceRepository.GetInvoiceFromScriptPubKey(output.ScriptPubKey, network.CryptoCode);
|
||||
if (invoice != null)
|
||||
|
@ -0,0 +1,16 @@
|
||||
namespace BTCPayServer.Payments.Changelly
|
||||
{
|
||||
public static class ChangellyCalculationHelper
|
||||
{
|
||||
public static decimal ComputeBaseAmount(decimal baseRate, decimal toAmount)
|
||||
{
|
||||
return (1m / baseRate) * toAmount;
|
||||
}
|
||||
|
||||
public static decimal ComputeCorrectAmount(decimal currentFromAmount, decimal currentAmount,
|
||||
decimal expectedAmount)
|
||||
{
|
||||
return (currentFromAmount / currentAmount) * expectedAmount;
|
||||
}
|
||||
}
|
||||
}
|
@ -90,10 +90,10 @@ namespace BTCPayServer.Payments.Lightning
|
||||
throw new PaymentMethodUnavailableException($"No lightning node public address has been configured");
|
||||
}
|
||||
|
||||
var blocksGap = Math.Abs(info.BlockHeight - summary.Status.ChainHeight);
|
||||
var blocksGap = summary.Status.ChainHeight - info.BlockHeight;
|
||||
if (blocksGap > 10)
|
||||
{
|
||||
throw new PaymentMethodUnavailableException($"The lightning is not synched ({blocksGap} blocks)");
|
||||
throw new PaymentMethodUnavailableException($"The lightning node is not synched ({blocksGap} blocks left)");
|
||||
}
|
||||
|
||||
return info.NodeInfo;
|
||||
|
@ -102,6 +102,8 @@ namespace BTCPayServer.Services.Rates
|
||||
Providers.Add("bittrex", new ExchangeSharpRateProvider("bittrex", new ExchangeBittrexAPI(), true));
|
||||
Providers.Add("poloniex", new ExchangeSharpRateProvider("poloniex", new ExchangePoloniexAPI(), true));
|
||||
Providers.Add("hitbtc", new ExchangeSharpRateProvider("hitbtc", new ExchangeHitbtcAPI(), false));
|
||||
|
||||
// Cryptopia is often not available
|
||||
Providers.Add("cryptopia", new ExchangeSharpRateProvider("cryptopia", new ExchangeCryptopiaAPI(), false));
|
||||
|
||||
// Handmade providers
|
||||
@ -118,6 +120,8 @@ namespace BTCPayServer.Services.Rates
|
||||
|
||||
foreach (var provider in Providers.ToArray())
|
||||
{
|
||||
if (provider.Key == "cryptopia") // Shitty exchange, rate often unavailable, it spams the logs
|
||||
continue;
|
||||
var prov = new BackgroundFetcherRateProvider(Providers[provider.Key]);
|
||||
if(provider.Key == CoinAverageRateProvider.CoinAverageName)
|
||||
{
|
||||
|
@ -42,6 +42,7 @@
|
||||
}
|
||||
</td>
|
||||
<td style="text-align:right">
|
||||
<a asp-action="ListInvoices" asp-controller="Invoice" asp-route-searchTerm="storeid:@store.Id">Invoices</a><span> - </span>
|
||||
@if (store.IsOwner)
|
||||
{
|
||||
<a asp-action="UpdateStore" asp-controller="Stores" asp-route-storeId="@store.Id">Settings</a><span> - </span>
|
||||
|
@ -92,7 +92,7 @@ else
|
||||
{
|
||||
<div class="row">
|
||||
<div class="col-md-10">
|
||||
<p>Scanning in progress, refresh the page to see the progress...</p>
|
||||
<p>Scanning in progress, refresh the page to see the progress... (Estimated time: @Model.RemainingTime)</p>
|
||||
<div class="progress">
|
||||
<div class="progress-bar" role="progressbar" aria-valuenow="@(Model.Progress.Value)"
|
||||
aria-valuemin="0" aria-valuemax="100" style="white-space: nowrap; overflow: hidden; text-overflow: ellipsis; width:@(Model.Progress.Value)%;">
|
||||
|
@ -1,4 +1,4 @@
|
||||
FROM microsoft/dotnet:2.1.402-sdk-alpine3.7 AS builder
|
||||
FROM microsoft/dotnet:2.1.403-sdk-alpine3.7 AS builder
|
||||
WORKDIR /source
|
||||
COPY BTCPayServer/BTCPayServer.csproj BTCPayServer.csproj
|
||||
# Cache some dependencies
|
||||
@ -6,7 +6,7 @@ RUN dotnet restore
|
||||
COPY BTCPayServer/. .
|
||||
RUN dotnet publish --output /app/ --configuration Release
|
||||
|
||||
FROM microsoft/dotnet:2.1.4-aspnetcore-runtime-alpine3.7
|
||||
FROM microsoft/dotnet:2.1.5-aspnetcore-runtime-alpine3.7
|
||||
|
||||
ENV DOTNET_SYSTEM_GLOBALIZATION_INVARIANT false
|
||||
RUN apk add --no-cache icu-libs
|
||||
|
@ -3,6 +3,7 @@
|
||||
|
||||
[](https://hub.docker.com/r/nicolasdorier/btcpayserver/)
|
||||
[](https://portal.azure.com/#create/Microsoft.Template/uri/https%3A%2F%2Fraw.githubusercontent.com%2Fbtcpayserver%2Fbtcpayserver-azure%2Fmaster%2Fazuredeploy.json)
|
||||
[](https://circleci.com/gh/btcpayserver/btcpayserver)
|
||||
|
||||
# BTCPay Server
|
||||
|
||||
|
@ -1,5 +1,5 @@
|
||||
{
|
||||
"sdk": {
|
||||
"version": "2.1.402"
|
||||
"version": "2.1.403"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Reference in New Issue
Block a user