2017-09-13 08:47:34 +02:00
using BTCPayServer.Tests.Logging ;
using System.Linq ;
using NBitcoin ;
using NBitcoin.DataEncoders ;
using NBitcoin.Payment ;
using NBitpayClient ;
using System ;
using System.Threading ;
using Xunit ;
using Xunit.Abstractions ;
using Xunit.Sdk ;
2017-10-20 21:06:37 +02:00
using BTCPayServer.Services.Invoices ;
2017-09-25 18:31:43 +02:00
using Newtonsoft.Json ;
using System.IO ;
using Newtonsoft.Json.Linq ;
2017-10-11 05:20:44 +02:00
using BTCPayServer.Controllers ;
using Microsoft.AspNetCore.Mvc ;
2017-10-13 11:06:46 +02:00
using BTCPayServer.Authentication ;
2017-10-20 21:00:38 +02:00
using System.Diagnostics ;
2017-10-24 18:41:01 +02:00
using Microsoft.EntityFrameworkCore.Extensions ;
using BTCPayServer.Data ;
using Microsoft.EntityFrameworkCore ;
2017-10-27 04:39:11 +02:00
using BTCPayServer.Services.Rates ;
using Microsoft.Extensions.Caching.Memory ;
2018-01-09 02:54:19 +01:00
using System.Collections.Generic ;
2018-01-17 07:59:31 +01:00
using BTCPayServer.Models.StoreViewModels ;
2018-01-18 10:12:01 +01:00
using System.Threading.Tasks ;
2018-02-17 05:18:16 +01:00
using System.Globalization ;
2018-02-18 18:38:03 +01:00
using BTCPayServer.Payments ;
2018-02-19 10:54:21 +01:00
using BTCPayServer.Payments.Bitcoin ;
using BTCPayServer.HostedServices ;
2018-02-25 16:48:12 +01:00
using BTCPayServer.Payments.Lightning ;
2018-04-03 09:53:55 +02:00
using BTCPayServer.Models.AppViewModels ;
using BTCPayServer.Services.Apps ;
2018-04-29 11:28:04 +02:00
using BTCPayServer.Services.Stores ;
using System.Net.Http ;
using System.Text ;
2018-05-29 17:12:07 +02:00
using BTCPayServer.Models ;
2018-05-02 20:32:42 +02:00
using BTCPayServer.Rating ;
2018-05-14 09:32:04 +02:00
using BTCPayServer.Validation ;
2018-05-04 08:35:39 +02:00
using ExchangeSharp ;
2018-07-08 13:58:37 +02:00
using System.Security.Cryptography.X509Certificates ;
2018-08-30 04:50:39 +02:00
using BTCPayServer.Lightning ;
2018-10-26 16:07:39 +02:00
using BTCPayServer.Models.WalletViewModels ;
using System.Security.Claims ;
2018-11-07 14:29:35 +01:00
using BTCPayServer.Models.ServerViewModels ;
2018-10-26 16:07:39 +02:00
using BTCPayServer.Security ;
2018-10-28 15:43:48 +01:00
using NBXplorer.Models ;
2018-11-07 14:29:35 +01:00
using RatesViewModel = BTCPayServer . Models . StoreViewModels . RatesViewModel ;
2017-09-13 08:47:34 +02:00
namespace BTCPayServer.Tests
{
2017-10-27 10:53:04 +02:00
public class UnitTest1
{
public UnitTest1 ( ITestOutputHelper helper )
{
Logs . Tester = new XUnitLog ( helper ) { Name = "Tests" } ;
Logs . LogProvider = new XUnitLogProvider ( helper ) ;
}
2018-05-14 09:32:04 +02:00
[Fact]
2018-10-28 12:59:59 +01:00
[Trait("Fast", "Fast")]
2018-05-14 09:32:04 +02:00
public void CanHandleUriValidation ( )
{
var attribute = new UriAttribute ( ) ;
Assert . True ( attribute . IsValid ( "http://localhost" ) ) ;
Assert . True ( attribute . IsValid ( "http://localhost:1234" ) ) ;
Assert . True ( attribute . IsValid ( "https://localhost" ) ) ;
Assert . True ( attribute . IsValid ( "https://127.0.0.1" ) ) ;
Assert . True ( attribute . IsValid ( "http://127.0.0.1" ) ) ;
Assert . True ( attribute . IsValid ( "http://127.0.0.1:1234" ) ) ;
Assert . True ( attribute . IsValid ( "http://gozo.com" ) ) ;
Assert . True ( attribute . IsValid ( "https://gozo.com" ) ) ;
Assert . True ( attribute . IsValid ( "https://gozo.com:1234" ) ) ;
2018-05-14 09:34:19 +02:00
Assert . True ( attribute . IsValid ( "https://gozo.com:1234/test.css" ) ) ;
Assert . True ( attribute . IsValid ( "https://gozo.com:1234/test.png" ) ) ;
2018-05-14 09:32:04 +02:00
Assert . False ( attribute . IsValid ( "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud e" ) ) ;
Assert . False ( attribute . IsValid ( 2 ) ) ;
Assert . False ( attribute . IsValid ( "http://" ) ) ;
Assert . False ( attribute . IsValid ( "httpdsadsa.com" ) ) ;
}
2018-02-19 10:54:21 +01:00
[Fact]
2018-10-28 12:59:59 +01:00
[Trait("Fast", "Fast")]
2018-02-19 10:54:21 +01:00
public void CanCalculateCryptoDue2 ( )
{
2018-03-13 07:28:39 +01:00
var dummy = new Key ( ) . PubKey . GetAddress ( Network . RegTest ) . ToString ( ) ;
2018-02-19 10:54:21 +01:00
#pragma warning disable CS0618
InvoiceEntity invoiceEntity = new InvoiceEntity ( ) ;
invoiceEntity . Payments = new System . Collections . Generic . List < PaymentEntity > ( ) ;
invoiceEntity . ProductInformation = new ProductInformation ( ) { Price = 100 } ;
PaymentMethodDictionary paymentMethods = new PaymentMethodDictionary ( ) ;
paymentMethods . Add ( new PaymentMethod ( )
{
CryptoCode = "BTC" ,
Rate = 10513.44 m ,
} . SetPaymentMethodDetails ( new BTCPayServer . Payments . Bitcoin . BitcoinLikeOnChainPaymentMethod ( )
{
TxFee = Money . Coins ( 0.00000100 m ) ,
DepositAddress = dummy
} ) ) ;
paymentMethods . Add ( new PaymentMethod ( )
{
CryptoCode = "LTC" ,
Rate = 216.79 m
} . SetPaymentMethodDetails ( new BTCPayServer . Payments . Bitcoin . BitcoinLikeOnChainPaymentMethod ( )
{
TxFee = Money . Coins ( 0.00010000 m ) ,
DepositAddress = dummy
} ) ) ;
invoiceEntity . SetPaymentMethods ( paymentMethods ) ;
var btc = invoiceEntity . GetPaymentMethod ( new PaymentMethodId ( "BTC" , PaymentTypes . BTCLike ) , null ) ;
var accounting = btc . Calculate ( ) ;
invoiceEntity . Payments . Add ( new PaymentEntity ( ) { Accounted = true , CryptoCode = "BTC" } . SetCryptoPaymentData ( new BitcoinLikePaymentData ( )
{
Output = new TxOut ( ) { Value = Money . Coins ( 0.00151263 m ) }
} ) ) ;
accounting = btc . Calculate ( ) ;
invoiceEntity . Payments . Add ( new PaymentEntity ( ) { Accounted = true , CryptoCode = "BTC" } . SetCryptoPaymentData ( new BitcoinLikePaymentData ( )
{
Output = new TxOut ( ) { Value = accounting . Due }
} ) ) ;
accounting = btc . Calculate ( ) ;
Assert . Equal ( Money . Zero , accounting . Due ) ;
Assert . Equal ( Money . Zero , accounting . DueUncapped ) ;
var ltc = invoiceEntity . GetPaymentMethod ( new PaymentMethodId ( "LTC" , PaymentTypes . BTCLike ) , null ) ;
accounting = ltc . Calculate ( ) ;
Assert . Equal ( Money . Zero , accounting . Due ) ;
// LTC might have over paid due to BTC paying above what it should (round 1 satoshi up)
Assert . True ( accounting . DueUncapped < Money . Zero ) ;
var paymentMethod = InvoiceWatcher . GetNearestClearedPayment ( paymentMethods , out var accounting2 , null ) ;
Assert . Equal ( btc . CryptoCode , paymentMethod . CryptoCode ) ;
#pragma warning restore CS0618
}
2017-10-27 10:53:04 +02:00
[Fact]
2018-10-28 12:59:59 +01:00
[Trait("Fast", "Fast")]
2017-10-27 10:53:04 +02:00
public void CanCalculateCryptoDue ( )
{
var entity = new InvoiceEntity ( ) ;
2017-12-21 07:52:04 +01:00
#pragma warning disable CS0618
2018-01-12 09:04:47 +01:00
entity . Payments = new System . Collections . Generic . List < PaymentEntity > ( ) ;
2018-05-02 20:32:42 +02:00
entity . SetPaymentMethod ( new PaymentMethod ( ) { CryptoCode = "BTC" , Rate = 5000 , TxFee = Money . Coins ( 0.1 m ) } ) ;
2018-01-12 09:04:47 +01:00
entity . ProductInformation = new ProductInformation ( ) { Price = 5000 } ;
2018-05-02 20:32:42 +02:00
var paymentMethod = entity . GetPaymentMethods ( null ) . TryGet ( "BTC" , PaymentTypes . BTCLike ) ;
2018-02-19 07:09:05 +01:00
var accounting = paymentMethod . Calculate ( ) ;
2017-12-21 10:01:26 +01:00
Assert . Equal ( Money . Coins ( 1.1 m ) , accounting . Due ) ;
Assert . Equal ( Money . Coins ( 1.1 m ) , accounting . TotalDue ) ;
2017-10-27 10:53:04 +02:00
2017-11-06 09:31:02 +01:00
entity . Payments . Add ( new PaymentEntity ( ) { Output = new TxOut ( Money . Coins ( 0.5 m ) , new Key ( ) ) , Accounted = true } ) ;
2017-10-27 10:53:04 +02:00
2018-02-19 07:09:05 +01:00
accounting = paymentMethod . Calculate ( ) ;
2017-10-27 10:53:04 +02:00
//Since we need to spend one more txout, it should be 1.1 - 0,5 + 0.1
2017-12-21 10:01:26 +01:00
Assert . Equal ( Money . Coins ( 0.7 m ) , accounting . Due ) ;
Assert . Equal ( Money . Coins ( 1.2 m ) , accounting . TotalDue ) ;
2017-10-27 10:53:04 +02:00
2017-11-06 09:31:02 +01:00
entity . Payments . Add ( new PaymentEntity ( ) { Output = new TxOut ( Money . Coins ( 0.2 m ) , new Key ( ) ) , Accounted = true } ) ;
2017-12-21 10:01:26 +01:00
2018-02-19 07:09:05 +01:00
accounting = paymentMethod . Calculate ( ) ;
2017-12-21 10:01:26 +01:00
Assert . Equal ( Money . Coins ( 0.6 m ) , accounting . Due ) ;
Assert . Equal ( Money . Coins ( 1.3 m ) , accounting . TotalDue ) ;
2017-10-27 10:53:04 +02:00
2017-11-06 09:31:02 +01:00
entity . Payments . Add ( new PaymentEntity ( ) { Output = new TxOut ( Money . Coins ( 0.6 m ) , new Key ( ) ) , Accounted = true } ) ;
2017-10-27 10:53:04 +02:00
2018-02-19 07:09:05 +01:00
accounting = paymentMethod . Calculate ( ) ;
2017-12-21 10:01:26 +01:00
Assert . Equal ( Money . Zero , accounting . Due ) ;
Assert . Equal ( Money . Coins ( 1.3 m ) , accounting . TotalDue ) ;
2017-10-27 10:53:04 +02:00
2017-11-06 09:31:02 +01:00
entity . Payments . Add ( new PaymentEntity ( ) { Output = new TxOut ( Money . Coins ( 0.2 m ) , new Key ( ) ) , Accounted = true } ) ;
2017-10-27 10:53:04 +02:00
2018-02-19 07:09:05 +01:00
accounting = paymentMethod . Calculate ( ) ;
2017-12-21 10:01:26 +01:00
Assert . Equal ( Money . Zero , accounting . Due ) ;
Assert . Equal ( Money . Coins ( 1.3 m ) , accounting . TotalDue ) ;
2018-01-09 02:54:19 +01:00
entity = new InvoiceEntity ( ) ;
entity . ProductInformation = new ProductInformation ( ) { Price = 5000 } ;
2018-02-19 07:09:05 +01:00
PaymentMethodDictionary paymentMethods = new PaymentMethodDictionary ( ) ;
paymentMethods . Add ( new PaymentMethod ( )
2018-02-18 18:38:03 +01:00
{
CryptoCode = "BTC" ,
Rate = 1000 ,
TxFee = Money . Coins ( 0.1 m )
} ) ;
2018-02-19 07:09:05 +01:00
paymentMethods . Add ( new PaymentMethod ( )
2018-02-18 18:38:03 +01:00
{
CryptoCode = "LTC" ,
Rate = 500 ,
TxFee = Money . Coins ( 0.01 m )
} ) ;
2018-02-19 07:09:05 +01:00
entity . SetPaymentMethods ( paymentMethods ) ;
2018-01-09 02:54:19 +01:00
entity . Payments = new List < PaymentEntity > ( ) ;
2018-02-19 07:09:05 +01:00
paymentMethod = entity . GetPaymentMethod ( new PaymentMethodId ( "BTC" , PaymentTypes . BTCLike ) , null ) ;
accounting = paymentMethod . Calculate ( ) ;
2018-01-09 02:54:19 +01:00
Assert . Equal ( Money . Coins ( 5.1 m ) , accounting . Due ) ;
2018-02-19 07:09:05 +01:00
paymentMethod = entity . GetPaymentMethod ( new PaymentMethodId ( "LTC" , PaymentTypes . BTCLike ) , null ) ;
accounting = paymentMethod . Calculate ( ) ;
2018-01-09 02:54:19 +01:00
Assert . Equal ( Money . Coins ( 10.01 m ) , accounting . TotalDue ) ;
entity . Payments . Add ( new PaymentEntity ( ) { CryptoCode = "BTC" , Output = new TxOut ( Money . Coins ( 1.0 m ) , new Key ( ) ) , Accounted = true } ) ;
2018-02-19 07:09:05 +01:00
paymentMethod = entity . GetPaymentMethod ( new PaymentMethodId ( "BTC" , PaymentTypes . BTCLike ) , null ) ;
accounting = paymentMethod . Calculate ( ) ;
2018-01-09 02:54:19 +01:00
Assert . Equal ( Money . Coins ( 4.2 m ) , accounting . Due ) ;
Assert . Equal ( Money . Coins ( 1.0 m ) , accounting . CryptoPaid ) ;
Assert . Equal ( Money . Coins ( 1.0 m ) , accounting . Paid ) ;
Assert . Equal ( Money . Coins ( 5.2 m ) , accounting . TotalDue ) ;
2018-02-25 16:48:12 +01:00
Assert . Equal ( 2 , accounting . TxRequired ) ;
2018-01-09 02:54:19 +01:00
2018-02-19 07:09:05 +01:00
paymentMethod = entity . GetPaymentMethod ( new PaymentMethodId ( "LTC" , PaymentTypes . BTCLike ) , null ) ;
accounting = paymentMethod . Calculate ( ) ;
2018-01-09 02:54:19 +01:00
Assert . Equal ( Money . Coins ( 10.01 m + 0.1 m * 2 - 2.0 m /* 8.21m */ ) , accounting . Due ) ;
Assert . Equal ( Money . Coins ( 0.0 m ) , accounting . CryptoPaid ) ;
Assert . Equal ( Money . Coins ( 2.0 m ) , accounting . Paid ) ;
Assert . Equal ( Money . Coins ( 10.01 m + 0.1 m * 2 ) , accounting . TotalDue ) ;
entity . Payments . Add ( new PaymentEntity ( ) { CryptoCode = "LTC" , Output = new TxOut ( Money . Coins ( 1.0 m ) , new Key ( ) ) , Accounted = true } ) ;
2018-02-19 07:09:05 +01:00
paymentMethod = entity . GetPaymentMethod ( new PaymentMethodId ( "BTC" , PaymentTypes . BTCLike ) , null ) ;
accounting = paymentMethod . Calculate ( ) ;
2018-01-09 02:54:19 +01:00
Assert . Equal ( Money . Coins ( 4.2 m - 0.5 m + 0.01 m / 2 ) , accounting . Due ) ;
Assert . Equal ( Money . Coins ( 1.0 m ) , accounting . CryptoPaid ) ;
Assert . Equal ( Money . Coins ( 1.5 m ) , accounting . Paid ) ;
Assert . Equal ( Money . Coins ( 5.2 m + 0.01 m / 2 ) , accounting . TotalDue ) ; // The fee for LTC added
2018-02-25 16:48:12 +01:00
Assert . Equal ( 2 , accounting . TxRequired ) ;
2018-01-09 02:54:19 +01:00
2018-02-19 07:09:05 +01:00
paymentMethod = entity . GetPaymentMethod ( new PaymentMethodId ( "LTC" , PaymentTypes . BTCLike ) , null ) ;
accounting = paymentMethod . Calculate ( ) ;
2018-01-09 02:54:19 +01:00
Assert . Equal ( Money . Coins ( 8.21 m - 1.0 m + 0.01 m ) , accounting . Due ) ;
Assert . Equal ( Money . Coins ( 1.0 m ) , accounting . CryptoPaid ) ;
Assert . Equal ( Money . Coins ( 3.0 m ) , accounting . Paid ) ;
Assert . Equal ( Money . Coins ( 10.01 m + 0.1 m * 2 + 0.01 m ) , accounting . TotalDue ) ;
2018-02-25 16:48:12 +01:00
Assert . Equal ( 2 , accounting . TxRequired ) ;
2018-01-09 02:54:19 +01:00
var remaining = Money . Coins ( 4.2 m - 0.5 m + 0.01 m / 2 ) ;
entity . Payments . Add ( new PaymentEntity ( ) { CryptoCode = "BTC" , Output = new TxOut ( remaining , new Key ( ) ) , Accounted = true } ) ;
2018-02-19 07:09:05 +01:00
paymentMethod = entity . GetPaymentMethod ( new PaymentMethodId ( "BTC" , PaymentTypes . BTCLike ) , null ) ;
accounting = paymentMethod . Calculate ( ) ;
2018-01-09 02:54:19 +01:00
Assert . Equal ( Money . Zero , accounting . Due ) ;
Assert . Equal ( Money . Coins ( 1.0 m ) + remaining , accounting . CryptoPaid ) ;
Assert . Equal ( Money . Coins ( 1.5 m ) + remaining , accounting . Paid ) ;
Assert . Equal ( Money . Coins ( 5.2 m + 0.01 m / 2 ) , accounting . TotalDue ) ;
Assert . Equal ( accounting . Paid , accounting . TotalDue ) ;
2018-02-25 16:48:12 +01:00
Assert . Equal ( 2 , accounting . TxRequired ) ;
2018-01-09 02:54:19 +01:00
2018-02-19 07:09:05 +01:00
paymentMethod = entity . GetPaymentMethod ( new PaymentMethodId ( "LTC" , PaymentTypes . BTCLike ) , null ) ;
accounting = paymentMethod . Calculate ( ) ;
2018-01-09 02:54:19 +01:00
Assert . Equal ( Money . Zero , accounting . Due ) ;
Assert . Equal ( Money . Coins ( 1.0 m ) , accounting . CryptoPaid ) ;
Assert . Equal ( Money . Coins ( 3.0 m ) + remaining * 2 , accounting . Paid ) ;
// Paying 2 BTC fee, LTC fee removed because fully paid
Assert . Equal ( Money . Coins ( 10.01 m + 0.1 m * 2 + 0.1 m * 2 /* + 0.01m no need to pay this fee anymore */ ) , accounting . TotalDue ) ;
2018-02-25 16:48:12 +01:00
Assert . Equal ( 1 , accounting . TxRequired ) ;
2018-01-09 02:54:19 +01:00
Assert . Equal ( accounting . Paid , accounting . TotalDue ) ;
2017-12-21 07:52:04 +01:00
#pragma warning restore CS0618
2017-10-27 10:53:04 +02:00
}
2018-05-05 16:07:22 +02:00
[Fact]
2018-10-28 14:51:02 +01:00
[Trait("Integration", "Integration")]
2018-05-05 16:07:22 +02:00
public void CanAcceptInvoiceWithTolerance ( )
{
var entity = new InvoiceEntity ( ) ;
#pragma warning disable CS0618
entity . Payments = new List < PaymentEntity > ( ) ;
entity . SetPaymentMethod ( new PaymentMethod ( ) { CryptoCode = "BTC" , Rate = 5000 , TxFee = Money . Coins ( 0.1 m ) } ) ;
entity . ProductInformation = new ProductInformation ( ) { Price = 5000 } ;
entity . PaymentTolerance = 0 ;
var paymentMethod = entity . GetPaymentMethods ( null ) . TryGet ( "BTC" , PaymentTypes . BTCLike ) ;
var accounting = paymentMethod . Calculate ( ) ;
Assert . Equal ( Money . Coins ( 1.1 m ) , accounting . Due ) ;
Assert . Equal ( Money . Coins ( 1.1 m ) , accounting . TotalDue ) ;
Assert . Equal ( Money . Coins ( 1.1 m ) , accounting . MinimumTotalDue ) ;
entity . PaymentTolerance = 10 ;
accounting = paymentMethod . Calculate ( ) ;
Assert . Equal ( Money . Coins ( 0.99 m ) , accounting . MinimumTotalDue ) ;
entity . PaymentTolerance = 100 ;
accounting = paymentMethod . Calculate ( ) ;
2018-05-08 10:57:53 +02:00
Assert . Equal ( Money . Satoshis ( 1 ) , accounting . MinimumTotalDue ) ;
2018-05-05 16:07:22 +02:00
}
2018-05-05 17:40:44 +02:00
[Fact]
2018-10-28 14:51:02 +01:00
[Trait("Integration", "Integration")]
2018-05-05 17:40:44 +02:00
public void CanAcceptInvoiceWithTolerance2 ( )
{
using ( var tester = ServerTester . Create ( ) )
{
tester . Start ( ) ;
var user = tester . NewAccount ( ) ;
user . GrantAccess ( ) ;
user . RegisterDerivationScheme ( "BTC" ) ;
2018-05-13 08:09:17 +02:00
2018-05-05 17:40:44 +02:00
// Set tolerance to 50%
var stores = user . GetController < StoresController > ( ) ;
var vm = Assert . IsType < StoreViewModel > ( Assert . IsType < ViewResult > ( stores . UpdateStore ( ) ) . Model ) ;
Assert . Equal ( 0.0 , vm . PaymentTolerance ) ;
vm . PaymentTolerance = 50.0 ;
Assert . IsType < RedirectToActionResult > ( stores . UpdateStore ( vm ) . Result ) ;
var invoice = user . BitPay . CreateInvoice ( new Invoice ( )
{
Buyer = new Buyer ( ) { email = "test@fwf.com" } ,
2018-05-11 15:38:31 +02:00
Price = 5000.0 m ,
2018-05-05 17:40:44 +02:00
Currency = "USD" ,
PosData = "posData" ,
OrderId = "orderId" ,
ItemDesc = "Some description" ,
FullNotifications = true
} , Facade . Merchant ) ;
// Pays 75%
var invoiceAddress = BitcoinAddress . Create ( invoice . CryptoInfo [ 0 ] . Address , tester . ExplorerNode . Network ) ;
tester . ExplorerNode . SendToAddress ( invoiceAddress , Money . Satoshis ( ( decimal ) invoice . BtcDue . Satoshi * 0.75 m ) ) ;
Eventually ( ( ) = >
{
var localInvoice = user . BitPay . GetInvoice ( invoice . Id , Facade . Merchant ) ;
Assert . Equal ( "paid" , localInvoice . Status ) ;
} ) ;
}
}
2018-05-13 08:09:17 +02:00
[Fact]
2018-10-28 12:59:59 +01:00
[Trait("Fast", "Fast")]
2018-05-13 08:09:17 +02:00
public void RoundupCurrenciesCorrectly ( )
{
2018-06-18 16:07:05 +02:00
foreach ( var test in new [ ]
2018-05-13 08:09:17 +02:00
{
( 0.0005 m , "$0.0005 (USD)" ) ,
( 0.001 m , "$0.001 (USD)" ) ,
( 0.01 m , "$0.01 (USD)" ) ,
( 0.1 m , "$0.10 (USD)" ) ,
} )
{
2018-10-09 16:30:06 +02:00
var actual = new CurrencyNameTable ( ) . DisplayFormatCurrency ( test . Item1 , "USD" ) ;
2018-05-13 08:09:17 +02:00
Assert . Equal ( test . Item2 , actual ) ;
}
}
2017-10-27 10:53:04 +02:00
[Fact]
2018-10-28 14:51:02 +01:00
[Trait("Integration", "Integration")]
2017-10-27 10:53:04 +02:00
public void CanPayUsingBIP70 ( )
{
using ( var tester = ServerTester . Create ( ) )
{
tester . Start ( ) ;
var user = tester . NewAccount ( ) ;
user . GrantAccess ( ) ;
2018-02-23 07:21:42 +01:00
user . RegisterDerivationScheme ( "BTC" ) ;
2018-06-06 07:46:41 +02:00
Assert . True ( user . BitPay . TestAccess ( Facade . Merchant ) ) ;
2017-10-27 10:53:04 +02:00
var invoice = user . BitPay . CreateInvoice ( new Invoice ( )
{
Buyer = new Buyer ( ) { email = "test@fwf.com" } ,
2018-05-11 15:38:31 +02:00
Price = 5000.0 m ,
2017-10-27 10:53:04 +02:00
Currency = "USD" ,
PosData = "posData" ,
OrderId = "orderId" ,
//RedirectURL = redirect + "redirect",
//NotificationURL = CallbackUri + "/notification",
ItemDesc = "Some description" ,
FullNotifications = true
} , Facade . Merchant ) ;
Assert . False ( invoice . Refundable ) ;
var url = new BitcoinUrlBuilder ( invoice . PaymentUrls . BIP72 ) ;
var request = url . GetPaymentRequest ( ) ;
var payment = request . CreatePayment ( ) ;
Transaction tx = new Transaction ( ) ;
tx . Outputs . AddRange ( request . Details . Outputs . Select ( o = > new TxOut ( o . Amount , o . Script ) ) ) ;
var cashCow = tester . ExplorerNode ;
tx = cashCow . FundRawTransaction ( tx ) . Transaction ;
tx = cashCow . SignRawTransaction ( tx ) ;
payment . Transactions . Add ( tx ) ;
payment . RefundTo . Add ( new PaymentOutput ( Money . Coins ( 1.0 m ) , new Key ( ) . ScriptPubKey ) ) ;
var ack = payment . SubmitPayment ( ) ;
Assert . NotNull ( ack ) ;
Eventually ( ( ) = >
{
var localInvoice = user . BitPay . GetInvoice ( invoice . Id , Facade . Merchant ) ;
Assert . Equal ( "paid" , localInvoice . Status ) ;
Assert . True ( localInvoice . Refundable ) ;
} ) ;
}
}
2017-12-13 07:49:19 +01:00
[Fact]
2018-10-28 14:51:02 +01:00
[Trait("Integration", "Integration")]
2018-10-28 14:46:03 +01:00
public async Task CanSetLightningServer ( )
2018-02-25 16:48:12 +01:00
{
using ( var tester = ServerTester . Create ( ) )
{
tester . Start ( ) ;
2018-10-28 14:46:03 +01:00
await tester . EnsureChannelsSetup ( ) ;
2018-02-25 16:48:12 +01:00
var user = tester . NewAccount ( ) ;
user . GrantAccess ( ) ;
2018-04-29 19:33:42 +02:00
var storeController = user . GetController < StoresController > ( ) ;
2018-05-03 18:46:52 +02:00
Assert . IsType < ViewResult > ( storeController . UpdateStore ( ) ) ;
2018-04-29 19:33:42 +02:00
Assert . IsType < ViewResult > ( storeController . AddLightningNode ( user . StoreId , "BTC" ) ) ;
2018-02-25 16:48:12 +01:00
var testResult = storeController . AddLightningNode ( user . StoreId , new LightningNodeViewModel ( )
{
2018-07-19 07:49:30 +02:00
ConnectionString = "type=charge;server=" + tester . MerchantCharge . Client . Uri . AbsoluteUri ,
SkipPortTest = true // We can't test this as the IP can't be resolved by the test host :(
2018-03-20 18:48:11 +01:00
} , "test" , "BTC" ) . GetAwaiter ( ) . GetResult ( ) ;
2018-02-25 16:48:12 +01:00
Assert . DoesNotContain ( "Error" , ( ( LightningNodeViewModel ) Assert . IsType < ViewResult > ( testResult ) . Model ) . StatusMessage , StringComparison . OrdinalIgnoreCase ) ;
Assert . True ( storeController . ModelState . IsValid ) ;
Assert . IsType < RedirectToActionResult > ( storeController . AddLightningNode ( user . StoreId , new LightningNodeViewModel ( )
{
2018-07-01 09:10:17 +02:00
ConnectionString = "type=charge;server=" + tester . MerchantCharge . Client . Uri . AbsoluteUri
} , "save" , "BTC" ) . GetAwaiter ( ) . GetResult ( ) ) ;
// Make sure old connection string format does not work
Assert . IsType < ViewResult > ( storeController . AddLightningNode ( user . StoreId , new LightningNodeViewModel ( )
2018-02-25 16:48:12 +01:00
{
2018-07-01 08:45:08 +02:00
ConnectionString = tester . MerchantCharge . Client . Uri . AbsoluteUri
2018-03-20 18:48:11 +01:00
} , "save" , "BTC" ) . GetAwaiter ( ) . GetResult ( ) ) ;
2018-02-25 16:48:12 +01:00
2018-05-03 18:46:52 +02:00
var storeVm = Assert . IsType < Models . StoreViewModels . StoreViewModel > ( Assert . IsType < ViewResult > ( storeController . UpdateStore ( ) ) . Model ) ;
2018-03-20 18:48:11 +01:00
Assert . Single ( storeVm . LightningNodes . Where ( l = > ! string . IsNullOrEmpty ( l . Address ) ) ) ;
2018-02-25 16:48:12 +01:00
}
2017-12-13 07:49:19 +01:00
}
2018-03-20 16:31:19 +01:00
[Fact]
2018-10-28 14:51:02 +01:00
[Trait("Integration", "Integration")]
2018-08-30 04:50:39 +02:00
public async Task CanSendLightningPaymentCLightning ( )
2018-03-20 16:31:19 +01:00
{
2018-08-30 04:50:39 +02:00
await ProcessLightningPayment ( LightningConnectionType . CLightning ) ;
2018-03-20 16:31:19 +01:00
}
2018-02-23 07:21:42 +01:00
[Fact]
2018-10-28 14:51:02 +01:00
[Trait("Integration", "Integration")]
2018-08-30 04:50:39 +02:00
public async Task CanSendLightningPaymentCharge ( )
2018-02-23 07:21:42 +01:00
{
2018-08-30 04:50:39 +02:00
await ProcessLightningPayment ( LightningConnectionType . Charge ) ;
2018-05-25 19:18:47 +02:00
}
2018-02-23 07:21:42 +01:00
2018-05-31 23:07:59 +02:00
[Fact]
2018-10-28 14:51:02 +01:00
[Trait("Integration", "Integration")]
2018-08-30 04:50:39 +02:00
public async Task CanSendLightningPaymentLnd ( )
2018-05-31 23:07:59 +02:00
{
2018-08-30 04:50:39 +02:00
await ProcessLightningPayment ( LightningConnectionType . LndREST ) ;
2018-05-31 23:07:59 +02:00
}
2018-05-25 19:18:47 +02:00
2018-08-30 04:50:39 +02:00
async Task ProcessLightningPayment ( LightningConnectionType type )
2018-05-25 19:18:47 +02:00
{
2018-06-15 20:57:39 +02:00
// For easier debugging and testing
2018-06-16 00:20:56 +02:00
// LightningLikePaymentHandler.LIGHTNING_TIMEOUT = int.MaxValue;
2018-02-23 07:21:42 +01:00
using ( var tester = ServerTester . Create ( ) )
{
tester . Start ( ) ;
2018-10-28 14:46:03 +01:00
await tester . EnsureChannelsSetup ( ) ;
2018-02-25 16:48:12 +01:00
var user = tester . NewAccount ( ) ;
user . GrantAccess ( ) ;
2018-05-25 19:18:47 +02:00
user . RegisterLightningNode ( "BTC" , type ) ;
2018-02-25 16:48:12 +01:00
user . RegisterDerivationScheme ( "BTC" ) ;
2018-07-27 11:04:41 +02:00
2018-08-30 04:50:39 +02:00
await CanSendLightningPaymentCore ( tester , user ) ;
2018-02-26 05:29:23 +01:00
2018-08-30 04:50:39 +02:00
await Task . WhenAll ( Enumerable . Range ( 0 , 5 )
2018-02-26 05:29:23 +01:00
. Select ( _ = > CanSendLightningPaymentCore ( tester , user ) )
. ToArray ( ) ) ;
2018-02-23 07:21:42 +01:00
}
}
2017-12-13 07:49:19 +01:00
2018-02-26 05:29:23 +01:00
async Task CanSendLightningPaymentCore ( ServerTester tester , TestAccount user )
{
var invoice = await user . BitPay . CreateInvoiceAsync ( new Invoice ( )
{
2018-05-11 15:38:31 +02:00
Price = 0.01 m ,
2018-02-26 05:29:23 +01:00
Currency = "USD" ,
PosData = "posData" ,
OrderId = "orderId" ,
ItemDesc = "Some description"
} ) ;
2018-10-28 16:22:30 +01:00
await Task . Delay ( TimeSpan . FromMilliseconds ( 1000 ) ) ; // Give time to listen the new invoices
2018-02-26 05:29:23 +01:00
await tester . SendLightningPaymentAsync ( invoice ) ;
await EventuallyAsync ( async ( ) = >
{
var localInvoice = await user . BitPay . GetInvoiceAsync ( invoice . Id ) ;
Assert . Equal ( "complete" , localInvoice . Status ) ;
Assert . Equal ( "False" , localInvoice . ExceptionStatus . ToString ( ) ) ;
} ) ;
}
2017-10-27 10:53:04 +02:00
[Fact]
2018-10-28 14:51:02 +01:00
[Trait("Integration", "Integration")]
2017-10-27 10:53:04 +02:00
public void CanUseServerInitiatedPairingCode ( )
{
using ( var tester = ServerTester . Create ( ) )
{
tester . Start ( ) ;
var acc = tester . NewAccount ( ) ;
acc . Register ( ) ;
acc . CreateStore ( ) ;
2018-04-29 19:33:42 +02:00
var controller = acc . GetController < StoresController > ( ) ;
2018-04-30 15:00:43 +02:00
var token = ( RedirectToActionResult ) controller . CreateToken ( new Models . StoreViewModels . CreateTokenViewModel ( )
2017-10-27 10:53:04 +02:00
{
Facade = Facade . Merchant . ToString ( ) ,
Label = "bla" ,
PublicKey = null
} ) . GetAwaiter ( ) . GetResult ( ) ;
var pairingCode = ( string ) token . RouteValues [ "pairingCode" ] ;
acc . BitPay . AuthorizeClient ( new PairingCode ( pairingCode ) ) . GetAwaiter ( ) . GetResult ( ) ;
Assert . True ( acc . BitPay . TestAccess ( Facade . Merchant ) ) ;
}
}
[Fact]
2018-10-28 14:51:02 +01:00
[Trait("Integration", "Integration")]
2017-10-27 10:53:04 +02:00
public void CanSendIPN ( )
{
using ( var callbackServer = new CustomServer ( ) )
{
using ( var tester = ServerTester . Create ( ) )
{
tester . Start ( ) ;
var acc = tester . NewAccount ( ) ;
acc . GrantAccess ( ) ;
2018-02-23 07:21:42 +01:00
acc . RegisterDerivationScheme ( "BTC" ) ;
2017-10-27 10:53:04 +02:00
var invoice = acc . BitPay . CreateInvoice ( new Invoice ( )
{
2018-05-11 15:38:31 +02:00
Price = 5.0 m ,
2017-10-27 10:53:04 +02:00
Currency = "USD" ,
PosData = "posData" ,
OrderId = "orderId" ,
NotificationURL = callbackServer . GetUri ( ) . AbsoluteUri ,
ItemDesc = "Some description" ,
2018-01-18 12:56:55 +01:00
FullNotifications = true ,
ExtendedNotifications = true
2017-10-27 10:53:04 +02:00
} ) ;
BitcoinUrlBuilder url = new BitcoinUrlBuilder ( invoice . PaymentUrls . BIP21 ) ;
tester . ExplorerNode . SendToAddress ( url . Address , url . Amount ) ;
Thread . Sleep ( 5000 ) ;
callbackServer . ProcessNextRequest ( ( ctx ) = >
{
var ipn = new StreamReader ( ctx . Request . Body ) . ReadToEnd ( ) ;
JsonConvert . DeserializeObject < InvoicePaymentNotification > ( ipn ) ; //can deserialize
} ) ;
var invoice2 = acc . BitPay . GetInvoice ( invoice . Id ) ;
Assert . NotNull ( invoice2 ) ;
}
}
}
[Fact]
2018-10-28 14:51:02 +01:00
[Trait("Integration", "Integration")]
2017-10-27 10:53:04 +02:00
public void CantPairTwiceWithSamePubkey ( )
{
using ( var tester = ServerTester . Create ( ) )
{
tester . Start ( ) ;
var acc = tester . NewAccount ( ) ;
acc . Register ( ) ;
2018-04-30 15:28:00 +02:00
acc . CreateStore ( ) ;
var store = acc . GetController < StoresController > ( ) ;
2017-10-27 10:53:04 +02:00
var pairingCode = acc . BitPay . RequestClientAuthorization ( "test" , Facade . Merchant ) ;
Assert . IsType < RedirectToActionResult > ( store . Pair ( pairingCode . ToString ( ) , acc . StoreId ) . GetAwaiter ( ) . GetResult ( ) ) ;
pairingCode = acc . BitPay . RequestClientAuthorization ( "test1" , Facade . Merchant ) ;
2018-04-30 15:28:00 +02:00
acc . CreateStore ( ) ;
var store2 = acc . GetController < StoresController > ( ) ;
store2 . Pair ( pairingCode . ToString ( ) , store2 . StoreData . Id ) . GetAwaiter ( ) . GetResult ( ) ;
2018-02-17 05:18:16 +01:00
Assert . Contains ( nameof ( PairingResult . ReusedKey ) , store2 . StatusMessage , StringComparison . CurrentCultureIgnoreCase ) ;
2017-10-27 10:53:04 +02:00
}
}
2018-11-05 04:14:39 +01:00
[Fact]
[Trait("Integration", "Integration")]
public void CanSolveTheDogesRatesOnKraken ( )
{
var provider = new BTCPayNetworkProvider ( NetworkType . Mainnet ) ;
var factory = CreateBTCPayRateFactory ( ) ;
var fetcher = new RateFetcher ( factory ) ;
Assert . True ( RateRules . TryParse ( "X_X=kraken(X_BTC) * kraken(BTC_X)" , out var rule ) ) ;
foreach ( var pair in new [ ] { "DOGE_USD" , "DOGE_CAD" , "DASH_CAD" , "DASH_USD" , "DASH_EUR" } )
{
var result = fetcher . FetchRate ( CurrencyPair . Parse ( pair ) , rule ) . GetAwaiter ( ) . GetResult ( ) ;
Assert . NotNull ( result . BidAsk ) ;
Assert . Empty ( result . Errors ) ;
}
}
2018-10-26 16:07:39 +02:00
[Fact]
2018-10-28 14:51:02 +01:00
[Trait("Integration", "Integration")]
2018-10-26 16:07:39 +02:00
public void CanRescanWallet ( )
{
using ( var tester = ServerTester . Create ( ) )
{
tester . Start ( ) ;
var acc = tester . NewAccount ( ) ;
acc . GrantAccess ( ) ;
2018-11-04 06:59:28 +01:00
acc . RegisterDerivationScheme ( "BTC" , true ) ;
2018-10-26 16:07:39 +02:00
var btcDerivationScheme = acc . DerivationScheme ;
2018-11-04 06:59:28 +01:00
acc . RegisterDerivationScheme ( "LTC" , true ) ;
2018-11-02 06:26:13 +01:00
2018-10-26 16:07:39 +02:00
var walletController = tester . PayTester . GetController < WalletsController > ( acc . UserId ) ;
WalletId walletId = new WalletId ( acc . StoreId , "LTC" ) ;
var rescan = Assert . IsType < RescanWalletModel > ( Assert . IsType < ViewResult > ( walletController . WalletRescan ( walletId ) . Result ) . Model ) ;
Assert . False ( rescan . Ok ) ;
Assert . True ( rescan . IsFullySync ) ;
2018-11-04 06:59:28 +01:00
Assert . True ( rescan . IsSegwit ) ;
2018-10-26 16:07:39 +02:00
Assert . False ( rescan . IsSupportedByCurrency ) ;
Assert . False ( rescan . IsServerAdmin ) ;
walletId = new WalletId ( acc . StoreId , "BTC" ) ;
var serverAdminClaim = new [ ] { new Claim ( Policies . CanModifyServerSettings . Key , "true" ) } ;
walletController = tester . PayTester . GetController < WalletsController > ( acc . UserId , additionalClaims : serverAdminClaim ) ;
rescan = Assert . IsType < RescanWalletModel > ( Assert . IsType < ViewResult > ( walletController . WalletRescan ( walletId ) . Result ) . Model ) ;
Assert . True ( rescan . Ok ) ;
Assert . True ( rescan . IsFullySync ) ;
Assert . True ( rescan . IsSupportedByCurrency ) ;
Assert . True ( rescan . IsServerAdmin ) ;
rescan . GapLimit = 100 ;
// Sending a coin
var txId = tester . ExplorerNode . SendToAddress ( btcDerivationScheme . Derive ( new KeyPath ( "0/90" ) ) . ScriptPubKey , Money . Coins ( 1.0 m ) ) ;
tester . ExplorerNode . Generate ( 1 ) ;
var transactions = Assert . IsType < ListTransactionsViewModel > ( Assert . IsType < ViewResult > ( walletController . WalletTransactions ( walletId ) . Result ) . Model ) ;
Assert . Empty ( transactions . Transactions ) ;
Assert . IsType < RedirectToActionResult > ( walletController . WalletRescan ( walletId , rescan ) . Result ) ;
2018-11-02 06:26:13 +01:00
while ( true )
2018-10-26 16:07:39 +02:00
{
rescan = Assert . IsType < RescanWalletModel > ( Assert . IsType < ViewResult > ( walletController . WalletRescan ( walletId ) . Result ) . Model ) ;
2018-11-02 06:26:13 +01:00
if ( rescan . Progress = = null & & rescan . LastSuccess ! = null )
2018-10-26 16:07:39 +02:00
{
if ( rescan . LastSuccess . Found = = 0 )
continue ;
// Scan over
break ;
}
else
{
Assert . Null ( rescan . TimeOfScan ) ;
Assert . NotNull ( rescan . RemainingTime ) ;
Assert . NotNull ( rescan . Progress ) ;
Thread . Sleep ( 100 ) ;
}
}
Assert . Null ( rescan . PreviousError ) ;
Assert . NotNull ( rescan . TimeOfScan ) ;
Assert . Equal ( 1 , rescan . LastSuccess . Found ) ;
transactions = Assert . IsType < ListTransactionsViewModel > ( Assert . IsType < ViewResult > ( walletController . WalletTransactions ( walletId ) . Result ) . Model ) ;
var tx = Assert . Single ( transactions . Transactions ) ;
Assert . Equal ( tx . Id , txId . ToString ( ) ) ;
}
}
2018-05-06 06:16:39 +02:00
[Fact]
2018-10-28 14:51:02 +01:00
[Trait("Integration", "Integration")]
2018-05-06 06:16:39 +02:00
public void CanListInvoices ( )
{
using ( var tester = ServerTester . Create ( ) )
{
tester . Start ( ) ;
var acc = tester . NewAccount ( ) ;
acc . GrantAccess ( ) ;
acc . RegisterDerivationScheme ( "BTC" ) ;
// First we try payment with a merchant having only BTC
var invoice = acc . BitPay . CreateInvoice ( new Invoice ( )
{
Price = 500 ,
Currency = "USD" ,
PosData = "posData" ,
OrderId = "orderId" ,
ItemDesc = "Some description" ,
FullNotifications = true
} , Facade . Merchant ) ;
2018-05-13 08:09:17 +02:00
2018-05-06 06:16:39 +02:00
var cashCow = tester . ExplorerNode ;
var invoiceAddress = BitcoinAddress . Create ( invoice . CryptoInfo [ 0 ] . Address , cashCow . Network ) ;
var firstPayment = invoice . CryptoInfo [ 0 ] . TotalDue - Money . Satoshis ( 10 ) ;
cashCow . SendToAddress ( invoiceAddress , firstPayment ) ;
Eventually ( ( ) = >
{
invoice = acc . BitPay . GetInvoice ( invoice . Id ) ;
Assert . Equal ( firstPayment , invoice . CryptoInfo [ 0 ] . Paid ) ;
} ) ;
AssertSearchInvoice ( acc , true , invoice . Id , $"storeid:{acc.StoreId}" ) ;
AssertSearchInvoice ( acc , false , invoice . Id , $"storeid:blah" ) ;
AssertSearchInvoice ( acc , true , invoice . Id , $"{invoice.Id}" ) ;
AssertSearchInvoice ( acc , true , invoice . Id , $"exceptionstatus:paidPartial" ) ;
AssertSearchInvoice ( acc , false , invoice . Id , $"exceptionstatus:paidOver" ) ;
AssertSearchInvoice ( acc , true , invoice . Id , $"unusual:true" ) ;
AssertSearchInvoice ( acc , false , invoice . Id , $"unusual:false" ) ;
}
}
2018-05-29 17:12:07 +02:00
[Fact]
2018-10-28 14:51:02 +01:00
[Trait("Integration", "Integration")]
2018-05-29 17:12:07 +02:00
public void CanGetRates ( )
{
using ( var tester = ServerTester . Create ( ) )
{
tester . Start ( ) ;
var acc = tester . NewAccount ( ) ;
acc . GrantAccess ( ) ;
acc . RegisterDerivationScheme ( "BTC" ) ;
acc . RegisterDerivationScheme ( "LTC" ) ;
var rateController = acc . GetController < RateController > ( ) ;
var GetBaseCurrencyRatesResult = JObject . Parse ( ( ( JsonResult ) rateController . GetBaseCurrencyRates ( "BTC" , acc . StoreId )
2018-07-30 16:22:26 +02:00
. GetAwaiter ( ) . GetResult ( ) ) . Value . ToJson ( ) ) . ToObject < DataWrapper < Rate [ ] > > ( ) ;
2018-05-29 17:12:07 +02:00
Assert . NotNull ( GetBaseCurrencyRatesResult ) ;
Assert . NotNull ( GetBaseCurrencyRatesResult . Data ) ;
2018-07-30 16:22:26 +02:00
Assert . Equal ( 2 , GetBaseCurrencyRatesResult . Data . Length ) ;
Assert . Single ( GetBaseCurrencyRatesResult . Data . Where ( o = > o . Code = = "LTC" ) ) ;
2018-05-29 17:12:07 +02:00
var GetRatesResult = JObject . Parse ( ( ( JsonResult ) rateController . GetRates ( null , acc . StoreId )
2018-07-30 16:22:26 +02:00
. GetAwaiter ( ) . GetResult ( ) ) . Value . ToJson ( ) ) . ToObject < DataWrapper < Rate [ ] > > ( ) ;
2018-05-29 17:12:07 +02:00
Assert . NotNull ( GetRatesResult ) ;
Assert . NotNull ( GetRatesResult . Data ) ;
Assert . Equal ( 2 , GetRatesResult . Data . Length ) ;
var GetCurrencyPairRateResult = JObject . Parse ( ( ( JsonResult ) rateController . GetCurrencyPairRate ( "BTC" , "LTC" , acc . StoreId )
2018-07-30 16:22:26 +02:00
. GetAwaiter ( ) . GetResult ( ) ) . Value . ToJson ( ) ) . ToObject < DataWrapper < Rate > > ( ) ;
2018-05-29 17:12:07 +02:00
Assert . NotNull ( GetCurrencyPairRateResult ) ;
Assert . NotNull ( GetCurrencyPairRateResult . Data ) ;
Assert . Equal ( "LTC" , GetCurrencyPairRateResult . Data . Code ) ;
2018-10-15 11:11:20 +02:00
// Should be OK because the request is signed, so we can know the store
var rates = acc . BitPay . GetRates ( ) ;
HttpClient client = new HttpClient ( ) ;
// Unauthentified requests should also be ok
var response = client . GetAsync ( $"http://127.0.0.1:{tester.PayTester.Port}/api/rates?storeId={acc.StoreId}" ) . GetAwaiter ( ) . GetResult ( ) ;
response . EnsureSuccessStatusCode ( ) ;
2018-05-29 17:12:07 +02:00
}
}
2018-05-06 06:16:39 +02:00
private void AssertSearchInvoice ( TestAccount acc , bool expected , string invoiceId , string filter )
{
var result = ( Models . InvoicingModels . InvoicesModel ) ( ( ViewResult ) acc . GetController < InvoiceController > ( ) . ListInvoices ( filter ) . Result ) . Model ;
Assert . Equal ( expected , result . Invoices . Any ( i = > i . InvoiceId = = invoiceId ) ) ;
}
2017-11-06 09:31:02 +01:00
[Fact]
2018-10-28 14:51:02 +01:00
[Trait("Integration", "Integration")]
2017-11-06 09:31:02 +01:00
public void CanRBFPayment ( )
{
using ( var tester = ServerTester . Create ( ) )
{
tester . Start ( ) ;
var user = tester . NewAccount ( ) ;
user . GrantAccess ( ) ;
2018-02-23 07:21:42 +01:00
user . RegisterDerivationScheme ( "BTC" ) ;
2017-11-06 09:31:02 +01:00
var invoice = user . BitPay . CreateInvoice ( new Invoice ( )
{
2018-05-11 15:38:31 +02:00
Price = 5000.0 m ,
2017-11-06 09:31:02 +01:00
Currency = "USD"
} , Facade . Merchant ) ;
2018-02-19 07:09:05 +01:00
var payment1 = invoice . BtcDue + Money . Coins ( 0.0001 m ) ;
var payment2 = invoice . BtcDue ;
2018-10-28 15:43:48 +01:00
2017-11-06 09:31:02 +01:00
var tx1 = new uint256 ( tester . ExplorerNode . SendCommand ( "sendtoaddress" , new object [ ]
{
2018-02-17 05:18:16 +01:00
invoice . BitcoinAddress ,
2017-11-06 09:31:02 +01:00
payment1 . ToString ( ) ,
null , //comment
null , //comment_to
false , //subtractfeefromamount
true , //replaceable
} ) . ResultString ) ;
2018-10-28 15:43:48 +01:00
Logs . Tester . LogInformation ( $"Let's send a first payment of {payment1} for the {invoice.BtcDue} invoice ({tx1})" ) ;
2018-01-11 14:52:28 +01:00
var invoiceAddress = BitcoinAddress . Create ( invoice . BitcoinAddress , user . SupportedNetwork . NBitcoinNetwork ) ;
2017-11-06 09:31:02 +01:00
2018-10-28 15:43:48 +01:00
Logs . Tester . LogInformation ( $"The invoice should be paidOver" ) ;
2017-11-06 09:31:02 +01:00
Eventually ( ( ) = >
{
invoice = user . BitPay . GetInvoice ( invoice . Id ) ;
Assert . Equal ( payment1 , invoice . BtcPaid ) ;
2018-02-19 07:09:05 +01:00
Assert . Equal ( "paid" , invoice . Status ) ;
Assert . Equal ( "paidOver" , invoice . ExceptionStatus . ToString ( ) ) ;
2018-01-11 14:52:28 +01:00
invoiceAddress = BitcoinAddress . Create ( invoice . BitcoinAddress , user . SupportedNetwork . NBitcoinNetwork ) ;
2017-11-06 09:31:02 +01:00
} ) ;
var tx = tester . ExplorerNode . GetRawTransaction ( new uint256 ( tx1 ) ) ;
foreach ( var input in tx . Inputs )
{
input . ScriptSig = Script . Empty ; //Strip signatures
}
var output = tx . Outputs . First ( o = > o . Value = = payment1 ) ;
output . Value = payment2 ;
output . ScriptPubKey = invoiceAddress . ScriptPubKey ;
2018-10-28 15:43:48 +01:00
2018-11-02 06:26:13 +01:00
using ( var cts = new CancellationTokenSource ( 10000 ) )
2018-10-28 15:43:48 +01:00
using ( var listener = tester . ExplorerClient . CreateNotificationSession ( ) )
{
listener . ListenAllDerivationSchemes ( ) ;
var replaced = tester . ExplorerNode . SignRawTransaction ( tx ) ;
2018-10-31 08:57:31 +01:00
Thread . Sleep ( 1000 ) ; // Make sure the replacement has a different timestamp
2018-10-28 15:43:48 +01:00
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" ) ;
2017-11-06 09:31:02 +01:00
Eventually ( ( ) = >
{
invoice = user . BitPay . GetInvoice ( invoice . Id ) ;
Assert . Equal ( payment2 , invoice . BtcPaid ) ;
2018-02-19 07:09:05 +01:00
Assert . Equal ( "False" , invoice . ExceptionStatus . ToString ( ) ) ;
2017-11-06 09:31:02 +01:00
} ) ;
}
}
2017-12-03 15:35:52 +01:00
[Fact]
2018-10-28 12:59:59 +01:00
[Trait("Fast", "Fast")]
2017-12-03 15:35:52 +01:00
public void CanParseFilter ( )
{
var filter = "storeid:abc status:abed blabhbalh " ;
var search = new SearchString ( filter ) ;
Assert . Equal ( "storeid:abc status:abed blabhbalh" , search . ToString ( ) ) ;
Assert . Equal ( "blabhbalh" , search . TextSearch ) ;
2018-04-26 04:01:59 +02:00
Assert . Single ( search . Filters [ "storeid" ] ) ;
Assert . Single ( search . Filters [ "status" ] ) ;
Assert . Equal ( "abc" , search . Filters [ "storeid" ] . First ( ) ) ;
Assert . Equal ( "abed" , search . Filters [ "status" ] . First ( ) ) ;
filter = "status:abed status:abed2" ;
search = new SearchString ( filter ) ;
Assert . Equal ( "status:abed status:abed2" , search . ToString ( ) ) ;
Assert . Throws < KeyNotFoundException > ( ( ) = > search . Filters [ "test" ] ) ;
Assert . Equal ( 2 , search . Filters [ "status" ] . Count ) ;
Assert . Equal ( "abed" , search . Filters [ "status" ] . First ( ) ) ;
Assert . Equal ( "abed2" , search . Filters [ "status" ] . Skip ( 1 ) . First ( ) ) ;
2017-12-03 15:35:52 +01:00
}
2018-08-13 02:43:59 +02:00
[Fact]
2018-10-28 12:59:59 +01:00
[Trait("Fast", "Fast")]
2018-08-13 02:43:59 +02:00
public void CanParseFingerprint ( )
{
Assert . True ( SSH . SSHFingerprint . TryParse ( "4e343c6fc6cfbf9339c02d06a151e1dd" , out var unused ) ) ;
Assert . Equal ( "4e:34:3c:6f:c6:cf:bf:93:39:c0:2d:06:a1:51:e1:dd" , unused . ToString ( ) ) ;
Assert . True ( SSH . SSHFingerprint . TryParse ( "4e:34:3c:6f:c6:cf:bf:93:39:c0:2d:06:a1:51:e1:dd" , out unused ) ) ;
Assert . True ( SSH . SSHFingerprint . TryParse ( "SHA256:Wl7CdRgT4u5T7yPMsxSrlFP+HIJJWwidGkzphJ8di5w" , out unused ) ) ;
Assert . True ( SSH . SSHFingerprint . TryParse ( "SHA256:Wl7CdRgT4u5T7yPMsxSrlFP+HIJJWwidGkzphJ8di5w=" , out unused ) ) ;
Assert . True ( SSH . SSHFingerprint . TryParse ( "Wl7CdRgT4u5T7yPMsxSrlFP+HIJJWwidGkzphJ8di5w=" , out unused ) ) ;
Assert . Equal ( "SHA256:Wl7CdRgT4u5T7yPMsxSrlFP+HIJJWwidGkzphJ8di5w" , unused . ToString ( ) ) ;
Assert . True ( SSH . SSHFingerprint . TryParse ( "Wl7CdRgT4u5T7yPMsxSrlFP+HIJJWwidGkzphJ8di5w=" , out var f1 ) ) ;
Assert . True ( SSH . SSHFingerprint . TryParse ( "SHA256:Wl7CdRgT4u5T7yPMsxSrlFP+HIJJWwidGkzphJ8di5w" , out var f2 ) ) ;
Assert . Equal ( f1 . ToString ( ) , f2 . ToString ( ) ) ;
}
2017-10-27 10:53:04 +02:00
[Fact]
2018-10-28 14:51:02 +01:00
[Trait("Integration", "Integration")]
2018-01-07 18:36:41 +01:00
public void TestAccessBitpayAPI ( )
2017-10-27 10:53:04 +02:00
{
using ( var tester = ServerTester . Create ( ) )
{
tester . Start ( ) ;
var user = tester . NewAccount ( ) ;
Assert . False ( user . BitPay . TestAccess ( Facade . Merchant ) ) ;
user . GrantAccess ( ) ;
2018-02-23 07:21:42 +01:00
user . RegisterDerivationScheme ( "BTC" ) ;
2018-06-06 09:02:37 +02:00
2017-10-27 10:53:04 +02:00
Assert . True ( user . BitPay . TestAccess ( Facade . Merchant ) ) ;
2018-04-29 11:28:04 +02:00
2018-06-06 07:46:41 +02:00
// Test request pairing code client side
var storeController = user . GetController < StoresController > ( ) ;
storeController . CreateToken ( new CreateTokenViewModel ( )
{
Facade = Facade . Merchant . ToString ( ) ,
Label = "test2" ,
StoreId = user . StoreId
} ) . GetAwaiter ( ) . GetResult ( ) ;
Assert . NotNull ( storeController . GeneratedPairingCode ) ;
2018-06-06 09:02:37 +02:00
var k = new Key ( ) ;
var bitpay = new Bitpay ( k , tester . PayTester . ServerUri ) ;
2018-06-06 07:46:41 +02:00
bitpay . AuthorizeClient ( new PairingCode ( storeController . GeneratedPairingCode ) ) . Wait ( ) ;
Assert . True ( bitpay . TestAccess ( Facade . Merchant ) ) ;
Assert . True ( bitpay . TestAccess ( Facade . PointOfSale ) ) ;
2018-06-06 09:02:37 +02:00
// Same with new instance
bitpay = new Bitpay ( k , tester . PayTester . ServerUri ) ;
Assert . True ( bitpay . TestAccess ( Facade . Merchant ) ) ;
Assert . True ( bitpay . TestAccess ( Facade . PointOfSale ) ) ;
2018-06-06 07:46:41 +02:00
2018-04-29 11:28:04 +02:00
// Can generate API Key
var repo = tester . PayTester . GetService < TokenRepository > ( ) ;
Assert . Empty ( repo . GetLegacyAPIKeys ( user . StoreId ) . GetAwaiter ( ) . GetResult ( ) ) ;
2018-04-30 15:00:43 +02:00
Assert . IsType < RedirectToActionResult > ( user . GetController < StoresController > ( ) . GenerateAPIKey ( ) . GetAwaiter ( ) . GetResult ( ) ) ;
2018-04-29 11:28:04 +02:00
var apiKey = Assert . Single ( repo . GetLegacyAPIKeys ( user . StoreId ) . GetAwaiter ( ) . GetResult ( ) ) ;
///////
// Generating a new one remove the previous
2018-04-30 15:00:43 +02:00
Assert . IsType < RedirectToActionResult > ( user . GetController < StoresController > ( ) . GenerateAPIKey ( ) . GetAwaiter ( ) . GetResult ( ) ) ;
2018-04-29 11:28:04 +02:00
var apiKey2 = Assert . Single ( repo . GetLegacyAPIKeys ( user . StoreId ) . GetAwaiter ( ) . GetResult ( ) ) ;
Assert . NotEqual ( apiKey , apiKey2 ) ;
////////
apiKey = apiKey2 ;
// Can create an invoice with this new API Key
HttpClient client = new HttpClient ( ) ;
HttpRequestMessage message = new HttpRequestMessage ( HttpMethod . Post , tester . PayTester . ServerUri . AbsoluteUri + "invoices" ) ;
message . Headers . Authorization = new System . Net . Http . Headers . AuthenticationHeaderValue ( "Basic" , Encoders . Base64 . EncodeData ( Encoders . ASCII . DecodeData ( apiKey ) ) ) ;
var invoice = new Invoice ( )
{
2018-05-11 15:38:31 +02:00
Price = 5000.0 m ,
2018-04-29 11:28:04 +02:00
Currency = "USD"
} ;
message . Content = new StringContent ( JsonConvert . SerializeObject ( invoice ) , Encoding . UTF8 , "application/json" ) ;
var result = client . SendAsync ( message ) . GetAwaiter ( ) . GetResult ( ) ;
result . EnsureSuccessStatusCode ( ) ;
/////////////////////
2018-01-07 18:36:41 +01:00
}
}
2018-01-13 14:01:09 +01:00
2018-04-15 14:18:51 +02:00
[Fact]
2018-10-28 14:51:02 +01:00
[Trait("Integration", "Integration")]
2018-04-15 14:18:51 +02:00
public void CanUseExchangeSpecificRate ( )
{
using ( var tester = ServerTester . Create ( ) )
{
tester . PayTester . MockRates = false ;
tester . Start ( ) ;
var user = tester . NewAccount ( ) ;
user . GrantAccess ( ) ;
user . RegisterDerivationScheme ( "BTC" ) ;
List < decimal > rates = new List < decimal > ( ) ;
rates . Add ( CreateInvoice ( tester , user , "coinaverage" ) ) ;
2018-08-22 17:24:33 +02:00
var bitflyer = CreateInvoice ( tester , user , "bitflyer" , "JPY" ) ;
var bitflyer2 = CreateInvoice ( tester , user , "bitflyer" , "JPY" ) ;
2018-04-15 14:29:44 +02:00
Assert . Equal ( bitflyer , bitflyer2 ) ; // Should be equal because cache
rates . Add ( bitflyer ) ;
2018-04-18 09:07:16 +02:00
2018-04-23 09:44:59 +02:00
foreach ( var rate in rates )
2018-04-15 14:18:51 +02:00
{
Assert . Single ( rates . Where ( r = > r = = rate ) ) ;
}
}
}
2018-08-22 17:24:33 +02:00
private static decimal CreateInvoice ( ServerTester tester , TestAccount user , string exchange , string currency = "USD" )
2018-04-15 14:18:51 +02:00
{
2018-04-29 19:33:42 +02:00
var storeController = user . GetController < StoresController > ( ) ;
2018-05-03 18:46:52 +02:00
var vm = ( RatesViewModel ) ( ( ViewResult ) storeController . Rates ( ) ) . Model ;
2018-04-15 14:18:51 +02:00
vm . PreferredExchange = exchange ;
2018-05-03 18:46:52 +02:00
storeController . Rates ( vm ) . Wait ( ) ;
2018-04-15 14:18:51 +02:00
var invoice2 = user . BitPay . CreateInvoice ( new Invoice ( )
{
2018-05-11 15:38:31 +02:00
Price = 5000.0 m ,
2018-08-22 17:24:33 +02:00
Currency = currency ,
2018-04-15 14:18:51 +02:00
PosData = "posData" ,
OrderId = "orderId" ,
ItemDesc = "Some description" ,
FullNotifications = true
} , Facade . Merchant ) ;
return invoice2 . CryptoInfo [ 0 ] . Rate ;
}
2018-01-17 07:59:31 +01:00
[Fact]
2018-10-28 14:51:02 +01:00
[Trait("Integration", "Integration")]
2018-01-17 07:59:31 +01:00
public void CanTweakRate ( )
{
using ( var tester = ServerTester . Create ( ) )
{
tester . Start ( ) ;
var user = tester . NewAccount ( ) ;
user . GrantAccess ( ) ;
2018-02-23 07:21:42 +01:00
user . RegisterDerivationScheme ( "BTC" ) ;
2018-01-17 07:59:31 +01:00
// First we try payment with a merchant having only BTC
var invoice1 = user . BitPay . CreateInvoice ( new Invoice ( )
{
2018-05-11 15:38:31 +02:00
Price = 5000.0 m ,
2018-01-17 07:59:31 +01:00
Currency = "USD" ,
PosData = "posData" ,
OrderId = "orderId" ,
ItemDesc = "Some description" ,
FullNotifications = true
} , Facade . Merchant ) ;
2018-08-22 17:24:33 +02:00
Assert . Equal ( Money . Coins ( 1.0 m ) , invoice1 . BtcPrice ) ;
2018-01-17 07:59:31 +01:00
2018-04-29 19:33:42 +02:00
var storeController = user . GetController < StoresController > ( ) ;
2018-05-03 18:46:52 +02:00
var vm = ( RatesViewModel ) ( ( ViewResult ) storeController . Rates ( ) ) . Model ;
2018-08-01 11:38:46 +02:00
Assert . Equal ( 0.0 , vm . Spread ) ;
vm . Spread = 40 ;
2018-05-03 18:46:52 +02:00
storeController . Rates ( vm ) . Wait ( ) ;
2018-01-17 07:59:31 +01:00
var invoice2 = user . BitPay . CreateInvoice ( new Invoice ( )
{
2018-05-11 15:38:31 +02:00
Price = 5000.0 m ,
2018-01-17 07:59:31 +01:00
Currency = "USD" ,
PosData = "posData" ,
OrderId = "orderId" ,
ItemDesc = "Some description" ,
FullNotifications = true
} , Facade . Merchant ) ;
2018-08-22 17:24:33 +02:00
var expectedRate = 5000.0 m * 0.6 m ;
var expectedCoins = invoice2 . Price / expectedRate ;
Assert . True ( invoice2 . BtcPrice . Almost ( Money . Coins ( expectedCoins ) , 0.00001 m ) ) ;
2018-01-17 07:59:31 +01:00
}
}
2018-01-13 14:01:09 +01:00
[Fact]
2018-10-28 14:51:02 +01:00
[Trait("Integration", "Integration")]
2018-01-13 14:01:09 +01:00
public void CanHaveLTCOnlyStore ( )
{
using ( var tester = ServerTester . Create ( ) )
{
tester . Start ( ) ;
var user = tester . NewAccount ( ) ;
user . GrantAccess ( ) ;
2018-02-23 07:21:42 +01:00
user . RegisterDerivationScheme ( "LTC" ) ;
2018-01-13 14:01:09 +01:00
// First we try payment with a merchant having only BTC
var invoice = user . BitPay . CreateInvoice ( new Invoice ( )
{
Price = 500 ,
Currency = "USD" ,
PosData = "posData" ,
OrderId = "orderId" ,
ItemDesc = "Some description" ,
FullNotifications = true
} , Facade . Merchant ) ;
Assert . Single ( invoice . CryptoInfo ) ;
Assert . Equal ( "LTC" , invoice . CryptoInfo [ 0 ] . CryptoCode ) ;
2018-05-15 16:18:26 +02:00
Assert . True ( invoice . PaymentCodes . ContainsKey ( "LTC" ) ) ;
Assert . True ( invoice . SupportedTransactionCurrencies . ContainsKey ( "LTC" ) ) ;
Assert . True ( invoice . SupportedTransactionCurrencies [ "LTC" ] . Enabled ) ;
Assert . True ( invoice . PaymentSubtotals . ContainsKey ( "LTC" ) ) ;
Assert . True ( invoice . PaymentTotals . ContainsKey ( "LTC" ) ) ;
2018-01-13 14:01:09 +01:00
var cashCow = tester . LTCExplorerNode ;
var invoiceAddress = BitcoinAddress . Create ( invoice . CryptoInfo [ 0 ] . Address , cashCow . Network ) ;
var firstPayment = Money . Coins ( 0.1 m ) ;
cashCow . SendToAddress ( invoiceAddress , firstPayment ) ;
Eventually ( ( ) = >
{
invoice = user . BitPay . GetInvoice ( invoice . Id ) ;
Assert . Equal ( firstPayment , invoice . CryptoInfo [ 0 ] . Paid ) ;
} ) ;
Assert . Single ( invoice . CryptoInfo ) ; // Only BTC should be presented
var controller = tester . PayTester . GetController < InvoiceController > ( null ) ;
var checkout = ( Models . InvoicingModels . PaymentModel ) ( ( JsonResult ) controller . GetStatus ( invoice . Id , null ) . GetAwaiter ( ) . GetResult ( ) ) . Value ;
Assert . Single ( checkout . AvailableCryptos ) ;
Assert . Equal ( "LTC" , checkout . CryptoCode ) ;
//////////////////////
// Despite it is called BitcoinAddress it should be LTC because BTC is not available
Assert . Null ( invoice . BitcoinAddress ) ;
2018-05-11 15:38:31 +02:00
Assert . NotEqual ( 1.0 m , invoice . Rate ) ;
2018-01-13 14:01:09 +01:00
Assert . NotEqual ( invoice . BtcDue , invoice . CryptoInfo [ 0 ] . Due ) ; // Should be BTC rate
cashCow . SendToAddress ( invoiceAddress , invoice . CryptoInfo [ 0 ] . Due ) ;
Eventually ( ( ) = >
{
invoice = user . BitPay . GetInvoice ( invoice . Id ) ;
Assert . Equal ( "paid" , invoice . Status ) ;
checkout = ( Models . InvoicingModels . PaymentModel ) ( ( JsonResult ) controller . GetStatus ( invoice . Id , null ) . GetAwaiter ( ) . GetResult ( ) ) . Value ;
Assert . Equal ( "paid" , checkout . Status ) ;
} ) ;
}
}
2018-01-07 18:36:41 +01:00
2018-05-03 18:46:52 +02:00
[Fact]
2018-10-28 14:51:02 +01:00
[Trait("Integration", "Integration")]
2018-05-03 18:46:52 +02:00
public void CanModifyRates ( )
{
using ( var tester = ServerTester . Create ( ) )
{
tester . Start ( ) ;
var user = tester . NewAccount ( ) ;
user . GrantAccess ( ) ;
user . RegisterDerivationScheme ( "BTC" ) ;
var store = user . GetController < StoresController > ( ) ;
var rateVm = Assert . IsType < RatesViewModel > ( Assert . IsType < ViewResult > ( store . Rates ( ) ) . Model ) ;
Assert . False ( rateVm . ShowScripting ) ;
Assert . Equal ( "coinaverage" , rateVm . PreferredExchange ) ;
2018-08-01 11:38:46 +02:00
Assert . Equal ( 0.0 , rateVm . Spread ) ;
2018-05-03 18:46:52 +02:00
Assert . Null ( rateVm . TestRateRules ) ;
rateVm . PreferredExchange = "bitflyer" ;
Assert . IsType < RedirectToActionResult > ( store . Rates ( rateVm , "Save" ) . Result ) ;
rateVm = Assert . IsType < RatesViewModel > ( Assert . IsType < ViewResult > ( store . Rates ( ) ) . Model ) ;
Assert . Equal ( "bitflyer" , rateVm . PreferredExchange ) ;
rateVm . ScriptTest = "BTC_JPY,BTC_CAD" ;
2018-08-01 11:38:46 +02:00
rateVm . Spread = 10 ;
2018-05-03 18:46:52 +02:00
store = user . GetController < StoresController > ( ) ;
rateVm = Assert . IsType < RatesViewModel > ( Assert . IsType < ViewResult > ( store . Rates ( rateVm , "Test" ) . Result ) . Model ) ;
Assert . NotNull ( rateVm . TestRateRules ) ;
Assert . Equal ( 2 , rateVm . TestRateRules . Count ) ;
Assert . False ( rateVm . TestRateRules [ 0 ] . Error ) ;
2018-08-01 11:38:46 +02:00
Assert . StartsWith ( "(bitflyer(BTC_JPY)) * (0.9, 1.1) =" , rateVm . TestRateRules [ 0 ] . Rule , StringComparison . OrdinalIgnoreCase ) ;
2018-05-03 18:46:52 +02:00
Assert . True ( rateVm . TestRateRules [ 1 ] . Error ) ;
Assert . IsType < RedirectToActionResult > ( store . Rates ( rateVm , "Save" ) . Result ) ;
Assert . IsType < RedirectToActionResult > ( store . ShowRateRulesPost ( true ) . Result ) ;
Assert . IsType < RedirectToActionResult > ( store . Rates ( rateVm , "Save" ) . Result ) ;
store = user . GetController < StoresController > ( ) ;
rateVm = Assert . IsType < RatesViewModel > ( Assert . IsType < ViewResult > ( store . Rates ( ) ) . Model ) ;
Assert . Equal ( rateVm . DefaultScript , rateVm . Script ) ;
Assert . True ( rateVm . ShowScripting ) ;
rateVm . ScriptTest = "BTC_JPY" ;
rateVm = Assert . IsType < RatesViewModel > ( Assert . IsType < ViewResult > ( store . Rates ( rateVm , "Test" ) . Result ) . Model ) ;
Assert . True ( rateVm . ShowScripting ) ;
2018-08-01 11:38:46 +02:00
Assert . Contains ( "(bitflyer(BTC_JPY)) * (0.9, 1.1) = " , rateVm . TestRateRules [ 0 ] . Rule , StringComparison . OrdinalIgnoreCase ) ;
2018-05-03 18:46:52 +02:00
rateVm . ScriptTest = "BTC_USD,BTC_CAD,DOGE_USD,DOGE_CAD" ;
rateVm . Script = "DOGE_X = bittrex(DOGE_BTC) * BTC_X;\n" +
"X_CAD = quadrigacx(X_CAD);\n" +
2018-08-22 17:24:33 +02:00
"X_X = coinaverage(X_X);" ;
2018-08-01 11:38:46 +02:00
rateVm . Spread = 50 ;
2018-05-03 18:46:52 +02:00
rateVm = Assert . IsType < RatesViewModel > ( Assert . IsType < ViewResult > ( store . Rates ( rateVm , "Test" ) . Result ) . Model ) ;
Assert . True ( rateVm . TestRateRules . All ( t = > ! t . Error ) ) ;
Assert . IsType < RedirectToActionResult > ( store . Rates ( rateVm , "Save" ) . Result ) ;
store = user . GetController < StoresController > ( ) ;
rateVm = Assert . IsType < RatesViewModel > ( Assert . IsType < ViewResult > ( store . Rates ( ) ) . Model ) ;
2018-08-01 11:38:46 +02:00
Assert . Equal ( 50 , rateVm . Spread ) ;
2018-05-03 18:46:52 +02:00
Assert . True ( rateVm . ShowScripting ) ;
Assert . Contains ( "DOGE_X" , rateVm . Script , StringComparison . OrdinalIgnoreCase ) ;
}
}
2018-01-11 09:29:48 +01:00
[Fact]
2018-10-28 14:51:02 +01:00
[Trait("Integration", "Integration")]
2018-01-11 09:29:48 +01:00
public void CanPayWithTwoCurrencies ( )
{
using ( var tester = ServerTester . Create ( ) )
{
tester . Start ( ) ;
var user = tester . NewAccount ( ) ;
user . GrantAccess ( ) ;
2018-02-23 07:21:42 +01:00
user . RegisterDerivationScheme ( "BTC" ) ;
2018-01-11 09:29:48 +01:00
// First we try payment with a merchant having only BTC
var invoice = user . BitPay . CreateInvoice ( new Invoice ( )
{
2018-05-11 15:38:31 +02:00
Price = 5000.0 m ,
2018-01-11 09:29:48 +01:00
Currency = "USD" ,
PosData = "posData" ,
OrderId = "orderId" ,
ItemDesc = "Some description" ,
FullNotifications = true
} , Facade . Merchant ) ;
var cashCow = tester . ExplorerNode ;
2018-01-20 06:09:57 +01:00
cashCow . Generate ( 2 ) ; // get some money in case
2018-01-11 09:29:48 +01:00
var invoiceAddress = BitcoinAddress . Create ( invoice . BitcoinAddress , cashCow . Network ) ;
var firstPayment = Money . Coins ( 0.04 m ) ;
cashCow . SendToAddress ( invoiceAddress , firstPayment ) ;
Eventually ( ( ) = >
{
invoice = user . BitPay . GetInvoice ( invoice . Id ) ;
Assert . True ( invoice . BtcPaid = = firstPayment ) ;
} ) ;
Assert . Single ( invoice . CryptoInfo ) ; // Only BTC should be presented
var controller = tester . PayTester . GetController < InvoiceController > ( null ) ;
var checkout = ( Models . InvoicingModels . PaymentModel ) ( ( JsonResult ) controller . GetStatus ( invoice . Id , null ) . GetAwaiter ( ) . GetResult ( ) ) . Value ;
Assert . Single ( checkout . AvailableCryptos ) ;
Assert . Equal ( "BTC" , checkout . CryptoCode ) ;
2018-05-15 16:25:43 +02:00
Assert . Single ( invoice . PaymentCodes ) ;
Assert . Single ( invoice . SupportedTransactionCurrencies ) ;
Assert . Single ( invoice . SupportedTransactionCurrencies ) ;
Assert . Single ( invoice . PaymentSubtotals ) ;
Assert . Single ( invoice . PaymentTotals ) ;
Assert . True ( invoice . PaymentCodes . ContainsKey ( "BTC" ) ) ;
Assert . True ( invoice . SupportedTransactionCurrencies . ContainsKey ( "BTC" ) ) ;
Assert . True ( invoice . SupportedTransactionCurrencies [ "BTC" ] . Enabled ) ;
Assert . True ( invoice . PaymentSubtotals . ContainsKey ( "BTC" ) ) ;
Assert . True ( invoice . PaymentTotals . ContainsKey ( "BTC" ) ) ;
2018-01-11 09:29:48 +01:00
//////////////////////
// Retry now with LTC enabled
user . RegisterDerivationScheme ( "LTC" ) ;
invoice = user . BitPay . CreateInvoice ( new Invoice ( )
{
2018-05-11 15:38:31 +02:00
Price = 5000.0 m ,
2018-01-11 09:29:48 +01:00
Currency = "USD" ,
PosData = "posData" ,
OrderId = "orderId" ,
ItemDesc = "Some description" ,
FullNotifications = true
} , Facade . Merchant ) ;
cashCow = tester . ExplorerNode ;
invoiceAddress = BitcoinAddress . Create ( invoice . BitcoinAddress , cashCow . Network ) ;
firstPayment = Money . Coins ( 0.04 m ) ;
cashCow . SendToAddress ( invoiceAddress , firstPayment ) ;
2018-01-20 06:09:57 +01:00
Logs . Tester . LogInformation ( "First payment sent to " + invoiceAddress ) ;
2018-01-11 09:29:48 +01:00
Eventually ( ( ) = >
{
invoice = user . BitPay . GetInvoice ( invoice . Id ) ;
Assert . True ( invoice . BtcPaid = = firstPayment ) ;
} ) ;
cashCow = tester . LTCExplorerNode ;
var ltcCryptoInfo = invoice . CryptoInfo . FirstOrDefault ( c = > c . CryptoCode = = "LTC" ) ;
Assert . NotNull ( ltcCryptoInfo ) ;
invoiceAddress = BitcoinAddress . Create ( ltcCryptoInfo . Address , cashCow . Network ) ;
2018-02-17 05:18:16 +01:00
var secondPayment = Money . Coins ( decimal . Parse ( ltcCryptoInfo . Due , CultureInfo . InvariantCulture ) ) ;
2018-01-11 09:29:48 +01:00
cashCow . Generate ( 2 ) ; // LTC is not worth a lot, so just to make sure we have money...
cashCow . SendToAddress ( invoiceAddress , secondPayment ) ;
2018-01-20 06:09:57 +01:00
Logs . Tester . LogInformation ( "Second payment sent to " + invoiceAddress ) ;
2018-01-11 09:29:48 +01:00
Eventually ( ( ) = >
{
invoice = user . BitPay . GetInvoice ( invoice . Id ) ;
Assert . Equal ( Money . Zero , invoice . BtcDue ) ;
var ltcPaid = invoice . CryptoInfo . First ( c = > c . CryptoCode = = "LTC" ) ;
Assert . Equal ( Money . Zero , ltcPaid . Due ) ;
Assert . Equal ( secondPayment , ltcPaid . CryptoPaid ) ;
Assert . Equal ( "paid" , invoice . Status ) ;
Assert . False ( ( bool ) ( ( JValue ) invoice . ExceptionStatus ) . Value ) ;
} ) ;
controller = tester . PayTester . GetController < InvoiceController > ( null ) ;
checkout = ( Models . InvoicingModels . PaymentModel ) ( ( JsonResult ) controller . GetStatus ( invoice . Id , "LTC" ) . GetAwaiter ( ) . GetResult ( ) ) . Value ;
Assert . Equal ( 2 , checkout . AvailableCryptos . Count ) ;
Assert . Equal ( "LTC" , checkout . CryptoCode ) ;
2018-05-15 16:25:43 +02:00
Assert . Equal ( 2 , invoice . PaymentCodes . Count ( ) ) ;
Assert . Equal ( 2 , invoice . SupportedTransactionCurrencies . Count ( ) ) ;
Assert . Equal ( 2 , invoice . SupportedTransactionCurrencies . Count ( ) ) ;
Assert . Equal ( 2 , invoice . PaymentSubtotals . Count ( ) ) ;
Assert . Equal ( 2 , invoice . PaymentTotals . Count ( ) ) ;
Assert . True ( invoice . PaymentCodes . ContainsKey ( "LTC" ) ) ;
Assert . True ( invoice . SupportedTransactionCurrencies . ContainsKey ( "LTC" ) ) ;
Assert . True ( invoice . SupportedTransactionCurrencies [ "LTC" ] . Enabled ) ;
Assert . True ( invoice . PaymentSubtotals . ContainsKey ( "LTC" ) ) ;
Assert . True ( invoice . PaymentTotals . ContainsKey ( "LTC" ) ) ;
2018-01-11 09:29:48 +01:00
}
}
2018-03-25 18:57:44 +02:00
[Fact]
2018-10-28 12:59:59 +01:00
[Trait("Fast", "Fast")]
2018-03-25 18:57:44 +02:00
public void CanParseCurrencyValue ( )
{
Assert . True ( CurrencyValue . TryParse ( "1.50USD" , out var result ) ) ;
Assert . Equal ( "1.50 USD" , result . ToString ( ) ) ;
Assert . True ( CurrencyValue . TryParse ( "1.50 USD" , out result ) ) ;
Assert . Equal ( "1.50 USD" , result . ToString ( ) ) ;
Assert . True ( CurrencyValue . TryParse ( "1.50 usd" , out result ) ) ;
Assert . Equal ( "1.50 USD" , result . ToString ( ) ) ;
Assert . True ( CurrencyValue . TryParse ( "1 usd" , out result ) ) ;
Assert . Equal ( "1 USD" , result . ToString ( ) ) ;
Assert . True ( CurrencyValue . TryParse ( "1usd" , out result ) ) ;
Assert . Equal ( "1 USD" , result . ToString ( ) ) ;
Assert . True ( CurrencyValue . TryParse ( "1.501 usd" , out result ) ) ;
Assert . Equal ( "1.50 USD" , result . ToString ( ) ) ;
Assert . False ( CurrencyValue . TryParse ( "1.501 WTFF" , out result ) ) ;
Assert . False ( CurrencyValue . TryParse ( "1,501 usd" , out result ) ) ;
Assert . False ( CurrencyValue . TryParse ( "1.501" , out result ) ) ;
}
2018-03-24 12:40:26 +01:00
[Fact]
2018-10-28 12:59:59 +01:00
[Trait("Fast", "Fast")]
2018-03-24 12:40:26 +01:00
public void CanParseDerivationScheme ( )
{
2018-04-19 09:54:25 +02:00
var parser = new DerivationSchemeParser ( Network . TestNet ) ;
2018-03-24 12:40:26 +01:00
NBXplorer . DerivationStrategy . DerivationStrategyBase result ;
// Passing electrum stuff
// Native
result = parser . Parse ( "zpub6nL6PUGurpU3DfPDSZaRS6WshpbNc9ctCFFzrCn54cssnheM31SZJZUcFHKtjJJNhAueMbh6ptFMfy1aeiMQJr3RJ4DDt1hAPx7sMTKV48t" ) ;
Assert . Equal ( "tpubD93CJNkmGjLXnsBqE2zGDqfEh1Q8iJ8wueordy3SeWt1RngbbuxXCsqASuVWFywmfoCwUE1rSfNJbaH4cBNcbp8WcyZgPiiRSTazLGL8U9w" , result . ToString ( ) ) ;
// P2SH
result = parser . Parse ( "ypub6QqdH2c5z79681jUgdxjGJzGW9zpL4ryPCuhtZE4GpvrJoZqM823XQN6iSQeVbbbp2uCRQ9UgpeMcwiyV6qjvxTWVcxDn2XEAnioMUwsrQ5" ) ;
Assert . Equal ( "tpubD6NzVbkrYhZ4YWjDJUACG9E8fJx2NqNY1iynTiPKEjJrzzRKAgha3nNnwGXr2BtvCJKJHW4nmG7rRqc2AGGy2AECgt16seMyV2FZivUmaJg-[p2sh]" , result . ToString ( ) ) ;
result = parser . Parse ( "xpub661MyMwAqRbcGeVGU5e5KBcau1HHEUGf9Wr7k4FyLa8yRPNQrrVa7Ndrgg8Afbe2UYXMSL6tJBFd2JewwWASsePPLjkcJFL1tTVEs3UQ23X" ) ;
Assert . Equal ( "tpubD6NzVbkrYhZ4YSg7vGdAX6wxE8NwDrmih9SR6cK7gUtsAg37w5LfFpJgviCxC6bGGT4G3uckqH5fiV9ZLN1gm5qgQLVuymzFUR5ed7U7ksu-[legacy]" , result . ToString ( ) ) ;
////////////////
2018-03-26 06:52:14 +02:00
var tpub = "tpubD6NzVbkrYhZ4Wc65tjhmcKdWFauAo7bGLRTxvggygkNyp6SMGutJp7iociwsinU33jyNBp1J9j2hJH5yQsayfiS3LEU2ZqXodAcnaygra8o" ;
result = parser . Parse ( tpub ) ;
Assert . Equal ( tpub , result . ToString ( ) ) ;
2018-03-24 12:40:26 +01:00
parser . HintScriptPubKey = BitcoinAddress . Create ( "tb1q4s33amqm8l7a07zdxcunqnn3gcsjcfz3xc573l" , parser . Network ) . ScriptPubKey ;
2018-03-26 06:52:14 +02:00
result = parser . Parse ( tpub ) ;
Assert . Equal ( tpub , result . ToString ( ) ) ;
2018-03-24 12:40:26 +01:00
parser . HintScriptPubKey = BitcoinAddress . Create ( "2N2humNio3YTApSfY6VztQ9hQwDnhDvaqFQ" , parser . Network ) . ScriptPubKey ;
2018-03-26 06:52:14 +02:00
result = parser . Parse ( tpub ) ;
Assert . Equal ( $"{tpub}-[p2sh]" , result . ToString ( ) ) ;
2018-03-24 12:40:26 +01:00
parser . HintScriptPubKey = BitcoinAddress . Create ( "mwD8bHS65cdgUf6rZUUSoVhi3wNQFu1Nfi" , parser . Network ) . ScriptPubKey ;
2018-03-26 06:52:14 +02:00
result = parser . Parse ( tpub ) ;
Assert . Equal ( $"{tpub}-[legacy]" , result . ToString ( ) ) ;
2018-03-24 12:40:26 +01:00
parser . HintScriptPubKey = BitcoinAddress . Create ( "2N2humNio3YTApSfY6VztQ9hQwDnhDvaqFQ" , parser . Network ) . ScriptPubKey ;
2018-03-26 06:52:14 +02:00
result = parser . Parse ( $"{tpub}-[legacy]" ) ;
Assert . Equal ( $"{tpub}-[p2sh]" , result . ToString ( ) ) ;
2018-03-24 12:40:26 +01:00
2018-03-26 06:52:14 +02:00
result = parser . Parse ( tpub ) ;
Assert . Equal ( $"{tpub}-[p2sh]" , result . ToString ( ) ) ;
2018-11-16 17:21:34 +01:00
parser = new DerivationSchemeParser ( Network . RegTest ) ;
var parsed = parser . Parse ( "xpub6DG1rMYXiQtCc6CfdLFD9CtxqhzzRh7j6Sq6EdE9abgYy3cfDRrniLLv2AdwqHL1exiLnnKR5XXcaoiiexf3Y9R6J6rxkJtqJHzNzMW9QMZ-[p2sh]" ) ;
Assert . Equal ( "tpubDDdeNbNDRgqestPX5XEJM8ELAq6eR5cne5RPbBHHvWSSiLHNHehsrn1kGCijMnHFSsFFQMqHcdMfGzDL3pWHRasPMhcGRqZ4tFankQ3i4ok-[p2sh]" , parsed . ToString ( ) ) ;
2018-11-16 17:45:59 +01:00
// Let's make sure we can't generate segwit with dogecoin
parser = new DerivationSchemeParser ( NBitcoin . Altcoins . Dogecoin . Instance . Regtest ) ;
parsed = parser . Parse ( "xpub6DG1rMYXiQtCc6CfdLFD9CtxqhzzRh7j6Sq6EdE9abgYy3cfDRrniLLv2AdwqHL1exiLnnKR5XXcaoiiexf3Y9R6J6rxkJtqJHzNzMW9QMZ-[p2sh]" ) ;
Assert . Equal ( "tpubDDdeNbNDRgqestPX5XEJM8ELAq6eR5cne5RPbBHHvWSSiLHNHehsrn1kGCijMnHFSsFFQMqHcdMfGzDL3pWHRasPMhcGRqZ4tFankQ3i4ok-[legacy]" , parsed . ToString ( ) ) ;
2018-11-17 03:35:20 +01:00
parser = new DerivationSchemeParser ( NBitcoin . Altcoins . Dogecoin . Instance . Regtest ) ;
parsed = parser . Parse ( "tpubDDdeNbNDRgqestPX5XEJM8ELAq6eR5cne5RPbBHHvWSSiLHNHehsrn1kGCijMnHFSsFFQMqHcdMfGzDL3pWHRasPMhcGRqZ4tFankQ3i4ok-[p2sh]" ) ;
Assert . Equal ( "tpubDDdeNbNDRgqestPX5XEJM8ELAq6eR5cne5RPbBHHvWSSiLHNHehsrn1kGCijMnHFSsFFQMqHcdMfGzDL3pWHRasPMhcGRqZ4tFankQ3i4ok-[legacy]" , parsed . ToString ( ) ) ;
2018-03-24 12:40:26 +01:00
}
2018-07-30 17:18:58 +02:00
[Fact]
2018-10-28 14:51:02 +01:00
[Trait("Integration", "Integration")]
2018-07-30 17:18:58 +02:00
public void CanDisablePaymentMethods ( )
{
using ( var tester = ServerTester . Create ( ) )
{
tester . Start ( ) ;
var user = tester . NewAccount ( ) ;
user . GrantAccess ( ) ;
user . RegisterDerivationScheme ( "BTC" ) ;
user . RegisterDerivationScheme ( "LTC" ) ;
user . RegisterLightningNode ( "BTC" , LightningConnectionType . CLightning ) ;
var invoice = user . BitPay . CreateInvoice ( new Invoice ( )
{
Price = 1.5 m ,
Currency = "USD" ,
PosData = "posData" ,
OrderId = "orderId" ,
ItemDesc = "Some description" ,
FullNotifications = true
} , Facade . Merchant ) ;
Assert . Equal ( 3 , invoice . CryptoInfo . Length ) ;
var controller = user . GetController < StoresController > ( ) ;
var lightningVM = ( LightningNodeViewModel ) Assert . IsType < ViewResult > ( controller . AddLightningNode ( user . StoreId , "BTC" ) ) . Model ;
Assert . True ( lightningVM . Enabled ) ;
lightningVM . Enabled = false ;
controller . AddLightningNode ( user . StoreId , lightningVM , "save" , "BTC" ) . GetAwaiter ( ) . GetResult ( ) ;
lightningVM = ( LightningNodeViewModel ) Assert . IsType < ViewResult > ( controller . AddLightningNode ( user . StoreId , "BTC" ) ) . Model ;
Assert . False ( lightningVM . Enabled ) ;
var derivationVM = ( DerivationSchemeViewModel ) Assert . IsType < ViewResult > ( controller . AddDerivationScheme ( user . StoreId , "BTC" ) ) . Model ;
Assert . True ( derivationVM . Enabled ) ;
derivationVM . Enabled = false ;
2018-08-01 11:42:28 +02:00
Assert . IsType < RedirectToActionResult > ( controller . AddDerivationScheme ( user . StoreId , derivationVM , "BTC" ) . GetAwaiter ( ) . GetResult ( ) ) ;
derivationVM = ( DerivationSchemeViewModel ) Assert . IsType < ViewResult > ( controller . AddDerivationScheme ( user . StoreId , "BTC" ) ) . Model ;
2018-07-30 17:18:58 +02:00
// Confirmation
controller . AddDerivationScheme ( user . StoreId , derivationVM , "BTC" ) . GetAwaiter ( ) . GetResult ( ) ;
Assert . False ( derivationVM . Enabled ) ;
derivationVM = ( DerivationSchemeViewModel ) Assert . IsType < ViewResult > ( controller . AddDerivationScheme ( user . StoreId , "BTC" ) ) . Model ;
Assert . False ( derivationVM . Enabled ) ;
invoice = user . BitPay . CreateInvoice ( new Invoice ( )
{
Price = 1.5 m ,
Currency = "USD" ,
PosData = "posData" ,
OrderId = "orderId" ,
ItemDesc = "Some description" ,
FullNotifications = true
} , Facade . Merchant ) ;
Assert . Single ( invoice . CryptoInfo ) ;
Assert . Equal ( "LTC" , invoice . CryptoInfo [ 0 ] . CryptoCode ) ;
}
}
2018-04-03 10:39:28 +02:00
[Fact]
2018-10-28 14:51:02 +01:00
[Trait("Integration", "Integration")]
2018-10-28 14:46:03 +01:00
public async Task CanSetPaymentMethodLimits ( )
2018-04-03 10:39:28 +02:00
{
using ( var tester = ServerTester . Create ( ) )
{
tester . Start ( ) ;
2018-10-28 14:46:03 +01:00
await tester . EnsureChannelsSetup ( ) ;
2018-04-03 10:39:28 +02:00
var user = tester . NewAccount ( ) ;
user . GrantAccess ( ) ;
user . RegisterDerivationScheme ( "BTC" ) ;
user . RegisterLightningNode ( "BTC" , LightningConnectionType . Charge ) ;
2018-04-30 15:00:43 +02:00
var vm = Assert . IsType < CheckoutExperienceViewModel > ( Assert . IsType < ViewResult > ( user . GetController < StoresController > ( ) . CheckoutExperience ( ) ) . Model ) ;
2018-04-03 10:39:28 +02:00
vm . LightningMaxValue = "2 USD" ;
vm . OnChainMinValue = "5 USD" ;
2018-04-30 15:00:43 +02:00
Assert . IsType < RedirectToActionResult > ( user . GetController < StoresController > ( ) . CheckoutExperience ( vm ) . Result ) ;
2018-04-03 10:39:28 +02:00
var invoice = user . BitPay . CreateInvoice ( new Invoice ( )
{
2018-05-11 15:38:31 +02:00
Price = 1.5 m ,
2018-04-03 10:39:28 +02:00
Currency = "USD" ,
PosData = "posData" ,
OrderId = "orderId" ,
ItemDesc = "Some description" ,
FullNotifications = true
} , Facade . Merchant ) ;
Assert . Single ( invoice . CryptoInfo ) ;
Assert . Equal ( PaymentTypes . LightningLike . ToString ( ) , invoice . CryptoInfo [ 0 ] . PaymentType ) ;
invoice = user . BitPay . CreateInvoice ( new Invoice ( )
{
2018-05-11 15:38:31 +02:00
Price = 5.5 m ,
2018-04-03 10:39:28 +02:00
Currency = "USD" ,
PosData = "posData" ,
OrderId = "orderId" ,
ItemDesc = "Some description" ,
FullNotifications = true
} , Facade . Merchant ) ;
Assert . Single ( invoice . CryptoInfo ) ;
Assert . Equal ( PaymentTypes . BTCLike . ToString ( ) , invoice . CryptoInfo [ 0 ] . PaymentType ) ;
}
}
2018-04-03 09:53:55 +02:00
[Fact]
2018-10-28 14:51:02 +01:00
[Trait("Integration", "Integration")]
2018-04-03 09:53:55 +02:00
public void CanUsePoSApp ( )
{
using ( var tester = ServerTester . Create ( ) )
{
tester . Start ( ) ;
var user = tester . NewAccount ( ) ;
user . GrantAccess ( ) ;
user . RegisterDerivationScheme ( "BTC" ) ;
var apps = user . GetController < AppsController > ( ) ;
var vm = Assert . IsType < CreateAppViewModel > ( Assert . IsType < ViewResult > ( apps . CreateApp ( ) . Result ) . Model ) ;
vm . Name = "test" ;
vm . SelectedAppType = AppType . PointOfSale . ToString ( ) ;
Assert . IsType < RedirectToActionResult > ( apps . CreateApp ( vm ) . Result ) ;
var appId = Assert . IsType < ListAppsViewModel > ( Assert . IsType < ViewResult > ( apps . ListApps ( ) . Result ) . Model ) . Apps [ 0 ] . Id ;
var vmpos = Assert . IsType < UpdatePointOfSaleViewModel > ( Assert . IsType < ViewResult > ( apps . UpdatePointOfSale ( appId ) . Result ) . Model ) ;
vmpos . Title = "hello" ;
vmpos . Currency = "CAD" ;
vmpos . Template =
"apple:\n" +
" price: 5.0\n" +
" title: good apple\n" +
"orange:\n" +
" price: 10.0\n" ;
Assert . IsType < RedirectToActionResult > ( apps . UpdatePointOfSale ( appId , vmpos ) . Result ) ;
vmpos = Assert . IsType < UpdatePointOfSaleViewModel > ( Assert . IsType < ViewResult > ( apps . UpdatePointOfSale ( appId ) . Result ) . Model ) ;
Assert . Equal ( "hello" , vmpos . Title ) ;
2018-08-30 20:16:46 +02:00
var publicApps = user . GetController < AppsPublicController > ( ) ;
var vmview = Assert . IsType < ViewPointOfSaleViewModel > ( Assert . IsType < ViewResult > ( publicApps . ViewPointOfSale ( appId ) . Result ) . Model ) ;
2018-04-03 09:53:55 +02:00
Assert . Equal ( "hello" , vmview . Title ) ;
Assert . Equal ( 2 , vmview . Items . Length ) ;
Assert . Equal ( "good apple" , vmview . Items [ 0 ] . Title ) ;
Assert . Equal ( "orange" , vmview . Items [ 1 ] . Title ) ;
Assert . Equal ( 10.0 m , vmview . Items [ 1 ] . Price . Value ) ;
Assert . Equal ( "$5.00" , vmview . Items [ 0 ] . Price . Formatted ) ;
2018-08-30 20:16:46 +02:00
Assert . IsType < RedirectResult > ( publicApps . ViewPointOfSale ( appId , 0 , null , null , null , null , "orange" ) . Result ) ;
2018-04-03 09:53:55 +02:00
var invoice = user . BitPay . GetInvoices ( ) . First ( ) ;
2018-05-11 15:38:31 +02:00
Assert . Equal ( 10.00 m , invoice . Price ) ;
2018-04-03 09:53:55 +02:00
Assert . Equal ( "CAD" , invoice . Currency ) ;
Assert . Equal ( "orange" , invoice . ItemDesc ) ;
}
}
[Fact]
2018-10-28 14:51:02 +01:00
[Trait("Integration", "Integration")]
2018-04-03 09:53:55 +02:00
public void CanCreateAndDeleteApps ( )
{
using ( var tester = ServerTester . Create ( ) )
{
tester . Start ( ) ;
var user = tester . NewAccount ( ) ;
user . GrantAccess ( ) ;
var user2 = tester . NewAccount ( ) ;
user2 . GrantAccess ( ) ;
var apps = user . GetController < AppsController > ( ) ;
var apps2 = user2 . GetController < AppsController > ( ) ;
var vm = Assert . IsType < CreateAppViewModel > ( Assert . IsType < ViewResult > ( apps . CreateApp ( ) . Result ) . Model ) ;
Assert . NotNull ( vm . SelectedAppType ) ;
Assert . Null ( vm . Name ) ;
vm . Name = "test" ;
2018-07-08 08:33:42 +02:00
vm . SelectedAppType = AppType . PointOfSale . ToString ( ) ;
2018-04-03 09:53:55 +02:00
var redirectToAction = Assert . IsType < RedirectToActionResult > ( apps . CreateApp ( vm ) . Result ) ;
2018-07-08 08:33:42 +02:00
Assert . Equal ( nameof ( apps . UpdatePointOfSale ) , redirectToAction . ActionName ) ;
2018-04-03 09:53:55 +02:00
var appList = Assert . IsType < ListAppsViewModel > ( Assert . IsType < ViewResult > ( apps . ListApps ( ) . Result ) . Model ) ;
var appList2 = Assert . IsType < ListAppsViewModel > ( Assert . IsType < ViewResult > ( apps2 . ListApps ( ) . Result ) . Model ) ;
Assert . Single ( appList . Apps ) ;
Assert . Empty ( appList2 . Apps ) ;
Assert . Equal ( "test" , appList . Apps [ 0 ] . AppName ) ;
2018-10-09 16:38:56 +02:00
Assert . Equal ( apps . CreatedAppId , appList . Apps [ 0 ] . Id ) ;
2018-04-03 09:53:55 +02:00
Assert . True ( appList . Apps [ 0 ] . IsOwner ) ;
Assert . Equal ( user . StoreId , appList . Apps [ 0 ] . StoreId ) ;
Assert . IsType < NotFoundResult > ( apps2 . DeleteApp ( appList . Apps [ 0 ] . Id ) . Result ) ;
Assert . IsType < ViewResult > ( apps . DeleteApp ( appList . Apps [ 0 ] . Id ) . Result ) ;
redirectToAction = Assert . IsType < RedirectToActionResult > ( apps . DeleteAppPost ( appList . Apps [ 0 ] . Id ) . Result ) ;
Assert . Equal ( nameof ( apps . ListApps ) , redirectToAction . ActionName ) ;
appList = Assert . IsType < ListAppsViewModel > ( Assert . IsType < ViewResult > ( apps . ListApps ( ) . Result ) . Model ) ;
Assert . Empty ( appList . Apps ) ;
}
}
2018-01-07 18:36:41 +01:00
[Fact]
2018-10-28 14:51:02 +01:00
[Trait("Integration", "Integration")]
2018-01-07 18:36:41 +01:00
public void InvoiceFlowThroughDifferentStatesCorrectly ( )
{
using ( var tester = ServerTester . Create ( ) )
{
tester . Start ( ) ;
var user = tester . NewAccount ( ) ;
user . GrantAccess ( ) ;
2018-02-23 07:21:42 +01:00
user . RegisterDerivationScheme ( "BTC" ) ;
2017-10-27 10:53:04 +02:00
var invoice = user . BitPay . CreateInvoice ( new Invoice ( )
{
2018-05-11 15:38:31 +02:00
Price = 5000.0 m ,
2017-10-27 10:53:04 +02:00
Currency = "USD" ,
PosData = "posData" ,
OrderId = "orderId" ,
ItemDesc = "Some description" ,
FullNotifications = true
} , Facade . Merchant ) ;
var repo = tester . PayTester . GetService < InvoiceRepository > ( ) ;
var ctx = tester . PayTester . GetService < ApplicationDbContextFactory > ( ) . CreateContext ( ) ;
2018-02-25 16:48:12 +01:00
Assert . Equal ( 0 , invoice . CryptoInfo [ 0 ] . TxCount ) ;
2018-05-25 15:49:49 +02:00
Assert . True ( invoice . MinerFees . ContainsKey ( "BTC" ) ) ;
2018-11-02 06:26:13 +01:00
Assert . Contains ( invoice . MinerFees [ "BTC" ] . SatoshiPerBytes , new [ ] { 100.0 m , 20.0 m } ) ;
2017-11-12 15:03:33 +01:00
Eventually ( ( ) = >
2017-10-27 10:53:04 +02:00
{
2017-12-16 17:04:20 +01:00
var textSearchResult = tester . PayTester . InvoiceRepository . GetInvoices ( new InvoiceQuery ( )
2017-11-12 15:03:33 +01:00
{
2018-04-26 04:01:59 +02:00
StoreId = new [ ] { user . StoreId } ,
2017-11-12 15:03:33 +01:00
TextSearch = invoice . OrderId
} ) . GetAwaiter ( ) . GetResult ( ) ;
2017-12-21 07:52:04 +01:00
Assert . Single ( textSearchResult ) ;
2017-12-16 17:04:20 +01:00
textSearchResult = tester . PayTester . InvoiceRepository . GetInvoices ( new InvoiceQuery ( )
2017-11-12 15:03:33 +01:00
{
2018-04-26 04:01:59 +02:00
StoreId = new [ ] { user . StoreId } ,
2017-11-12 15:03:33 +01:00
TextSearch = invoice . Id
} ) . GetAwaiter ( ) . GetResult ( ) ;
2017-10-27 10:53:04 +02:00
2017-12-21 07:52:04 +01:00
Assert . Single ( textSearchResult ) ;
2017-11-12 15:03:33 +01:00
} ) ;
2017-10-27 10:53:04 +02:00
invoice = user . BitPay . GetInvoice ( invoice . Id , Facade . Merchant ) ;
Assert . Equal ( Money . Coins ( 0 ) , invoice . BtcPaid ) ;
Assert . Equal ( "new" , invoice . Status ) ;
2017-12-21 07:52:04 +01:00
Assert . False ( ( bool ) ( ( JValue ) invoice . ExceptionStatus ) . Value ) ;
2017-10-27 10:53:04 +02:00
2018-02-16 17:34:40 +01:00
Assert . Single ( user . BitPay . GetInvoices ( invoice . InvoiceTime . UtcDateTime ) ) ;
Assert . Empty ( user . BitPay . GetInvoices ( invoice . InvoiceTime . UtcDateTime + TimeSpan . FromDays ( 2 ) ) ) ;
Assert . Single ( user . BitPay . GetInvoices ( invoice . InvoiceTime . UtcDateTime - TimeSpan . FromDays ( 5 ) ) ) ;
Assert . Single ( user . BitPay . GetInvoices ( invoice . InvoiceTime . UtcDateTime - TimeSpan . FromDays ( 5 ) , invoice . InvoiceTime . DateTime + TimeSpan . FromDays ( 1.0 ) ) ) ;
Assert . Empty ( user . BitPay . GetInvoices ( invoice . InvoiceTime . UtcDateTime - TimeSpan . FromDays ( 5 ) , invoice . InvoiceTime . DateTime - TimeSpan . FromDays ( 1 ) ) ) ;
2017-10-27 10:53:04 +02:00
var firstPayment = Money . Coins ( 0.04 m ) ;
var txFee = Money . Zero ;
var cashCow = tester . ExplorerNode ;
var invoiceAddress = BitcoinAddress . Create ( invoice . BitcoinAddress , cashCow . Network ) ;
var iii = ctx . AddressInvoices . ToArray ( ) ;
Assert . True ( IsMapped ( invoice , ctx ) ) ;
cashCow . SendToAddress ( invoiceAddress , firstPayment ) ;
var invoiceEntity = repo . GetInvoice ( null , invoice . Id , true ) . GetAwaiter ( ) . GetResult ( ) ;
2017-12-21 07:52:04 +01:00
Assert . Single ( invoiceEntity . HistoricalAddresses ) ;
2017-10-27 10:53:04 +02:00
Assert . Null ( invoiceEntity . HistoricalAddresses [ 0 ] . UnAssigned ) ;
Money secondPayment = Money . Zero ;
Eventually ( ( ) = >
{
var localInvoice = user . BitPay . GetInvoice ( invoice . Id , Facade . Merchant ) ;
Assert . Equal ( "new" , localInvoice . Status ) ;
Assert . Equal ( firstPayment , localInvoice . BtcPaid ) ;
txFee = localInvoice . BtcDue - invoice . BtcDue ;
2017-12-21 07:52:04 +01:00
Assert . Equal ( "paidPartial" , localInvoice . ExceptionStatus . ToString ( ) ) ;
2018-02-25 16:48:12 +01:00
Assert . Equal ( 1 , localInvoice . CryptoInfo [ 0 ] . TxCount ) ;
2017-10-27 10:53:04 +02:00
Assert . NotEqual ( localInvoice . BitcoinAddress , invoice . BitcoinAddress ) ; //New address
Assert . True ( IsMapped ( invoice , ctx ) ) ;
Assert . True ( IsMapped ( localInvoice , ctx ) ) ;
invoiceEntity = repo . GetInvoice ( null , invoice . Id , true ) . GetAwaiter ( ) . GetResult ( ) ;
2018-02-17 05:18:16 +01:00
var historical1 = invoiceEntity . HistoricalAddresses . FirstOrDefault ( h = > h . GetAddress ( ) = = invoice . BitcoinAddress ) ;
2017-10-27 10:53:04 +02:00
Assert . NotNull ( historical1 . UnAssigned ) ;
2018-02-17 05:18:16 +01:00
var historical2 = invoiceEntity . HistoricalAddresses . FirstOrDefault ( h = > h . GetAddress ( ) = = localInvoice . BitcoinAddress ) ;
2017-10-27 10:53:04 +02:00
Assert . Null ( historical2 . UnAssigned ) ;
invoiceAddress = BitcoinAddress . Create ( localInvoice . BitcoinAddress , cashCow . Network ) ;
secondPayment = localInvoice . BtcDue ;
} ) ;
cashCow . SendToAddress ( invoiceAddress , secondPayment ) ;
Eventually ( ( ) = >
{
var localInvoice = user . BitPay . GetInvoice ( invoice . Id , Facade . Merchant ) ;
Assert . Equal ( "paid" , localInvoice . Status ) ;
2018-02-25 16:48:12 +01:00
Assert . Equal ( 2 , localInvoice . CryptoInfo [ 0 ] . TxCount ) ;
2017-10-27 10:53:04 +02:00
Assert . Equal ( firstPayment + secondPayment , localInvoice . BtcPaid ) ;
Assert . Equal ( Money . Zero , localInvoice . BtcDue ) ;
Assert . Equal ( localInvoice . BitcoinAddress , invoiceAddress . ToString ( ) ) ; //no new address generated
Assert . True ( IsMapped ( localInvoice , ctx ) ) ;
2017-12-18 00:56:27 +01:00
Assert . False ( ( bool ) ( ( JValue ) localInvoice . ExceptionStatus ) . Value ) ;
2017-10-27 10:53:04 +02:00
} ) ;
cashCow . Generate ( 1 ) ; //The user has medium speed settings, so 1 conf is enough to be confirmed
Eventually ( ( ) = >
{
var localInvoice = user . BitPay . GetInvoice ( invoice . Id , Facade . Merchant ) ;
Assert . Equal ( "confirmed" , localInvoice . Status ) ;
} ) ;
cashCow . Generate ( 5 ) ; //Now should be complete
Eventually ( ( ) = >
{
var localInvoice = user . BitPay . GetInvoice ( invoice . Id , Facade . Merchant ) ;
Assert . Equal ( "complete" , localInvoice . Status ) ;
2018-05-11 15:38:31 +02:00
Assert . NotEqual ( 0.0 m , localInvoice . Rate ) ;
2017-10-27 10:53:04 +02:00
} ) ;
invoice = user . BitPay . CreateInvoice ( new Invoice ( )
{
2018-05-11 15:38:31 +02:00
Price = 5000.0 m ,
2017-10-27 10:53:04 +02:00
Currency = "USD" ,
PosData = "posData" ,
OrderId = "orderId" ,
//RedirectURL = redirect + "redirect",
//NotificationURL = CallbackUri + "/notification",
ItemDesc = "Some description" ,
FullNotifications = true
} , Facade . Merchant ) ;
invoiceAddress = BitcoinAddress . Create ( invoice . BitcoinAddress , cashCow . Network ) ;
2018-11-02 06:26:13 +01:00
var txId = cashCow . SendToAddress ( invoiceAddress , invoice . BtcDue + Money . Coins ( 1 ) ) ;
2017-10-27 10:53:04 +02:00
Eventually ( ( ) = >
{
var localInvoice = user . BitPay . GetInvoice ( invoice . Id , Facade . Merchant ) ;
Assert . Equal ( "paid" , localInvoice . Status ) ;
Assert . Equal ( Money . Zero , localInvoice . BtcDue ) ;
Assert . Equal ( "paidOver" , ( string ) ( ( JValue ) localInvoice . ExceptionStatus ) . Value ) ;
2018-11-02 06:26:13 +01:00
var textSearchResult = tester . PayTester . InvoiceRepository . GetInvoices ( new InvoiceQuery ( )
{
StoreId = new [ ] { user . StoreId } ,
TextSearch = txId . ToString ( )
} ) . GetAwaiter ( ) . GetResult ( ) ;
Assert . Single ( textSearchResult ) ;
2017-10-27 10:53:04 +02:00
} ) ;
cashCow . Generate ( 1 ) ;
Eventually ( ( ) = >
{
var localInvoice = user . BitPay . GetInvoice ( invoice . Id , Facade . Merchant ) ;
Assert . Equal ( "confirmed" , localInvoice . Status ) ;
Assert . Equal ( Money . Zero , localInvoice . BtcDue ) ;
Assert . Equal ( "paidOver" , ( string ) ( ( JValue ) localInvoice . ExceptionStatus ) . Value ) ;
} ) ;
}
}
2018-04-23 09:44:59 +02:00
[Fact]
2018-10-28 14:51:02 +01:00
[Trait("Integration", "Integration")]
2018-04-23 09:44:59 +02:00
public void CheckQuadrigacxRateProvider ( )
{
2018-05-02 20:32:42 +02:00
var quadri = new QuadrigacxRateProvider ( ) ;
2018-04-23 09:44:59 +02:00
var rates = quadri . GetRatesAsync ( ) . GetAwaiter ( ) . GetResult ( ) ;
Assert . NotEmpty ( rates ) ;
2018-05-22 19:18:38 +02:00
Assert . NotEqual ( 0.0 m , rates . First ( ) . BidAsk . Bid ) ;
Assert . NotEqual ( 0.0 m , rates . GetRate ( QuadrigacxRateProvider . QuadrigacxName , CurrencyPair . Parse ( "BTC_CAD" ) ) . Bid ) ;
Assert . NotEqual ( 0.0 m , rates . GetRate ( QuadrigacxRateProvider . QuadrigacxName , CurrencyPair . Parse ( "BTC_USD" ) ) . Bid ) ;
Assert . NotEqual ( 0.0 m , rates . GetRate ( QuadrigacxRateProvider . QuadrigacxName , CurrencyPair . Parse ( "LTC_CAD" ) ) . Bid ) ;
2018-05-02 20:32:42 +02:00
Assert . Null ( rates . GetRate ( QuadrigacxRateProvider . QuadrigacxName , CurrencyPair . Parse ( "LTC_USD" ) ) ) ;
2018-04-23 09:44:59 +02:00
}
2018-05-04 08:35:39 +02:00
[Fact]
2018-10-28 14:51:02 +01:00
[Trait("Integration", "Integration")]
2018-05-04 08:35:39 +02:00
public void CanQueryDirectProviders ( )
{
2018-08-22 09:53:40 +02:00
var factory = CreateBTCPayRateFactory ( ) ;
2018-05-13 08:09:17 +02:00
2018-05-04 08:35:39 +02:00
foreach ( var result in factory
2018-08-22 17:24:33 +02:00
. Providers
. Where ( p = > p . Value is BackgroundFetcherRateProvider )
. Select ( p = > ( ExpectedName : p . Key , ResultAsync : p . Value . GetRatesAsync ( ) , Fetcher : ( BackgroundFetcherRateProvider ) p . Value ) )
2018-05-04 08:35:39 +02:00
. ToList ( ) )
{
2018-08-22 17:24:33 +02:00
result . Fetcher . InvalidateCache ( ) ;
2018-05-04 08:35:39 +02:00
var exchangeRates = result . ResultAsync . Result ;
2018-08-22 17:24:33 +02:00
result . Fetcher . InvalidateCache ( ) ;
2018-05-04 08:35:39 +02:00
Assert . NotNull ( exchangeRates ) ;
Assert . NotEmpty ( exchangeRates ) ;
Assert . NotEmpty ( exchangeRates . ByExchange [ result . ExpectedName ] ) ;
// This check if the currency pair is using right currency pair
2018-05-13 08:09:17 +02:00
Assert . Contains ( exchangeRates . ByExchange [ result . ExpectedName ] ,
e = > ( e . CurrencyPair = = new CurrencyPair ( "BTC" , "USD" ) | |
2018-05-04 08:35:39 +02:00
e . CurrencyPair = = new CurrencyPair ( "BTC" , "EUR" ) | |
e . CurrencyPair = = new CurrencyPair ( "BTC" , "USDT" ) )
2018-05-22 19:18:38 +02:00
& & e . BidAsk . Bid > 1.0 m // 1BTC will always be more than 1USD
2018-05-04 08:35:39 +02:00
) ;
}
2018-08-21 08:59:57 +02:00
// Kraken emit one request only after first GetRates
2018-08-22 17:24:33 +02:00
factory . Providers [ "kraken" ] . GetRatesAsync ( ) . GetAwaiter ( ) . GetResult ( ) ;
2018-05-04 08:35:39 +02:00
}
2018-05-02 20:40:10 +02:00
[Fact]
2018-10-28 14:51:02 +01:00
[Trait("Integration", "Integration")]
2018-05-02 20:40:10 +02:00
public void CanGetRateCryptoCurrenciesByDefault ( )
{
var provider = new BTCPayNetworkProvider ( NetworkType . Mainnet ) ;
2018-08-22 09:53:40 +02:00
var factory = CreateBTCPayRateFactory ( ) ;
var fetcher = new RateFetcher ( factory ) ;
2018-05-02 20:40:10 +02:00
var pairs =
provider . GetAll ( )
. Select ( c = > new CurrencyPair ( c . CryptoCode , "USD" ) )
. ToHashSet ( ) ;
var rules = new StoreBlob ( ) . GetDefaultRateRules ( provider ) ;
2018-08-22 09:53:40 +02:00
var result = fetcher . FetchRates ( pairs , rules ) ;
2018-05-04 08:35:39 +02:00
foreach ( var value in result )
2018-05-02 20:40:10 +02:00
{
var rateResult = value . Value . GetAwaiter ( ) . GetResult ( ) ;
2018-10-31 05:31:03 +01:00
Logs . Tester . LogInformation ( $"Testing {value.Key.ToString()}" ) ;
Assert . True ( rateResult . BidAsk ! = null , $"Impossible to get the rate {rateResult.EvaluatedRule}" ) ;
2018-05-02 20:40:10 +02:00
}
}
2018-11-02 06:26:13 +01:00
public static RateProviderFactory CreateBTCPayRateFactory ( )
2018-05-04 08:35:39 +02:00
{
2018-08-22 17:24:33 +02:00
return new RateProviderFactory ( CreateMemoryCache ( ) , null , new CoinAverageSettings ( ) ) ;
}
private static MemoryCacheOptions CreateMemoryCache ( )
{
return new MemoryCacheOptions ( ) { ExpirationScanFrequency = TimeSpan . FromSeconds ( 1.0 ) } ;
}
class SpyRateProvider : IRateProvider
{
public bool Hit { get ; set ; }
public Task < ExchangeRates > GetRatesAsync ( )
{
Hit = true ;
var rates = new ExchangeRates ( ) ;
rates . Add ( new ExchangeRate ( "coinaverage" , CurrencyPair . Parse ( "BTC_USD" ) , new BidAsk ( 5000 ) ) ) ;
return Task . FromResult ( rates ) ;
}
public void AssertHit ( )
{
Assert . True ( Hit , "Should have hit the provider" ) ;
Hit = false ;
}
public void AssertNotHit ( )
{
Assert . False ( Hit , "Should have not hit the provider" ) ;
Hit = false ;
}
2018-05-04 08:35:39 +02:00
}
2018-11-07 14:29:35 +01:00
[Fact]
[Trait("Integration", "Integration")]
public async Task CheckLogsRoute ( )
{
using ( var tester = ServerTester . Create ( ) )
{
tester . Start ( ) ;
var user = tester . NewAccount ( ) ;
user . GrantAccess ( ) ;
user . RegisterDerivationScheme ( "BTC" ) ;
var serverController = user . GetController < ServerController > ( ) ;
var vm = Assert . IsType < LogsViewModel > ( Assert . IsType < ViewResult > ( await serverController . LogsView ( ) ) . Model ) ;
}
}
2017-10-27 10:53:04 +02:00
[Fact]
2018-10-28 12:59:59 +01:00
[Trait("Fast", "Fast")]
2017-10-27 10:53:04 +02:00
public void CheckRatesProvider ( )
{
2018-08-22 17:24:33 +02:00
var spy = new SpyRateProvider ( ) ;
2018-05-02 20:32:42 +02:00
RateRules . TryParse ( "X_X = coinaverage(X_X);" , out var rateRules ) ;
2018-08-22 09:53:40 +02:00
var factory = CreateBTCPayRateFactory ( ) ;
2018-08-22 17:24:33 +02:00
factory . Providers . Clear ( ) ;
factory . Providers . Add ( "coinaverage" , new CachedRateProvider ( "coinaverage" , spy , new MemoryCache ( CreateMemoryCache ( ) ) ) ) ;
factory . Providers . Add ( "bittrex" , new CachedRateProvider ( "bittrex" , spy , new MemoryCache ( CreateMemoryCache ( ) ) ) ) ;
factory . CacheSpan = TimeSpan . FromSeconds ( 1 ) ;
var fetcher = new RateFetcher ( factory ) ;
2018-05-02 20:32:42 +02:00
2018-08-22 09:53:40 +02:00
var fetchedRate = fetcher . FetchRate ( CurrencyPair . Parse ( "BTC_USD" ) , rateRules ) . GetAwaiter ( ) . GetResult ( ) ;
2018-08-22 17:24:33 +02:00
spy . AssertHit ( ) ;
2018-08-22 09:53:40 +02:00
fetchedRate = fetcher . FetchRate ( CurrencyPair . Parse ( "BTC_USD" ) , rateRules ) . GetAwaiter ( ) . GetResult ( ) ;
2018-08-22 17:24:33 +02:00
spy . AssertNotHit ( ) ;
2018-05-02 20:32:42 +02:00
2018-08-22 17:24:33 +02:00
Thread . Sleep ( 3000 ) ;
2018-08-22 09:53:40 +02:00
fetchedRate = fetcher . FetchRate ( CurrencyPair . Parse ( "BTC_USD" ) , rateRules ) . GetAwaiter ( ) . GetResult ( ) ;
2018-08-22 17:24:33 +02:00
spy . AssertHit ( ) ;
2018-08-22 09:53:40 +02:00
fetchedRate = fetcher . FetchRate ( CurrencyPair . Parse ( "BTC_USD" ) , rateRules ) . GetAwaiter ( ) . GetResult ( ) ;
2018-08-22 17:24:33 +02:00
spy . AssertNotHit ( ) ;
2018-05-02 20:32:42 +02:00
// Should cache at exchange level so this should hit the cache
2018-08-22 09:53:40 +02:00
var fetchedRate2 = fetcher . FetchRate ( CurrencyPair . Parse ( "LTC_USD" ) , rateRules ) . GetAwaiter ( ) . GetResult ( ) ;
2018-08-22 17:24:33 +02:00
spy . AssertNotHit ( ) ;
Assert . Null ( fetchedRate2 . BidAsk ) ;
Assert . Equal ( RateRulesErrors . RateUnavailable , fetchedRate2 . Errors . First ( ) ) ;
2018-05-02 20:32:42 +02:00
// Should cache at exchange level this should not hit the cache as it is different exchange
RateRules . TryParse ( "X_X = bittrex(X_X);" , out rateRules ) ;
2018-08-22 09:53:40 +02:00
fetchedRate = fetcher . FetchRate ( CurrencyPair . Parse ( "BTC_USD" ) , rateRules ) . GetAwaiter ( ) . GetResult ( ) ;
2018-08-22 17:24:33 +02:00
spy . AssertHit ( ) ;
2018-05-02 20:32:42 +02:00
2018-08-22 17:24:33 +02:00
factory . Providers . Clear ( ) ;
var fetch = new BackgroundFetcherRateProvider ( spy ) ;
2018-08-25 08:49:04 +02:00
fetch . DoNotAutoFetchIfExpired = true ;
2018-08-22 17:24:33 +02:00
factory . Providers . Add ( "bittrex" , fetch ) ;
fetchedRate = fetcher . FetchRate ( CurrencyPair . Parse ( "BTC_USD" ) , rateRules ) . GetAwaiter ( ) . GetResult ( ) ;
spy . AssertHit ( ) ;
fetchedRate = fetcher . FetchRate ( CurrencyPair . Parse ( "BTC_USD" ) , rateRules ) . GetAwaiter ( ) . GetResult ( ) ;
spy . AssertNotHit ( ) ;
fetch . UpdateIfNecessary ( ) . GetAwaiter ( ) . GetResult ( ) ;
spy . AssertNotHit ( ) ;
fetch . RefreshRate = TimeSpan . FromSeconds ( 1.0 ) ;
Thread . Sleep ( 1020 ) ;
fetchedRate = fetcher . FetchRate ( CurrencyPair . Parse ( "BTC_USD" ) , rateRules ) . GetAwaiter ( ) . GetResult ( ) ;
spy . AssertNotHit ( ) ;
2018-08-23 06:47:56 +02:00
fetch . ValidatyTime = TimeSpan . FromSeconds ( 1.0 ) ;
2018-08-22 17:24:33 +02:00
fetch . UpdateIfNecessary ( ) . GetAwaiter ( ) . GetResult ( ) ;
spy . AssertHit ( ) ;
2018-08-23 06:47:56 +02:00
fetch . GetRatesAsync ( ) . GetAwaiter ( ) . GetResult ( ) ;
Thread . Sleep ( 1000 ) ;
Assert . Throws < InvalidOperationException > ( ( ) = > fetch . GetRatesAsync ( ) . GetAwaiter ( ) . GetResult ( ) ) ;
2017-10-27 10:53:04 +02:00
}
private static bool IsMapped ( Invoice invoice , ApplicationDbContext ctx )
{
2018-04-10 12:07:57 +02:00
var h = BitcoinAddress . Create ( invoice . BitcoinAddress , Network . RegTest ) . ScriptPubKey . Hash . ToString ( ) ;
2018-02-19 03:31:34 +01:00
return ctx . AddressInvoices . FirstOrDefault ( i = > i . InvoiceDataId = = invoice . Id & & i . GetAddress ( ) = = h ) ! = null ;
2017-10-27 10:53:04 +02:00
}
private void Eventually ( Action act )
{
2018-02-26 05:29:23 +01:00
CancellationTokenSource cts = new CancellationTokenSource ( 20000 ) ;
2017-10-27 10:53:04 +02:00
while ( true )
{
try
{
act ( ) ;
break ;
}
catch ( XunitException ) when ( ! cts . Token . IsCancellationRequested )
{
cts . Token . WaitHandle . WaitOne ( 500 ) ;
}
}
}
2018-02-26 05:29:23 +01:00
private async Task EventuallyAsync ( Func < Task > act )
{
CancellationTokenSource cts = new CancellationTokenSource ( 20000 ) ;
while ( true )
{
try
{
await act ( ) ;
break ;
}
catch ( XunitException ) when ( ! cts . Token . IsCancellationRequested )
{
await Task . Delay ( 500 ) ;
}
}
}
2017-10-27 10:53:04 +02:00
}
2017-09-13 08:47:34 +02:00
}