Add unhappy scenario integration test with razor and context fixes
This commit is contained in:
parent
a3d7dd795f
commit
2aad169dce
8 changed files with 175 additions and 18 deletions
2
.github/workflows/dotnet.yml
vendored
2
.github/workflows/dotnet.yml
vendored
|
|
@ -31,7 +31,7 @@ jobs:
|
|||
run: dotnet clean
|
||||
|
||||
- name: Build projects
|
||||
run: dotnet build -c Release --no-restore
|
||||
run: dotnet build -maxcpucount:1 -c Release --no-restore
|
||||
|
||||
- name: Deterministic build check
|
||||
run: |
|
||||
|
|
|
|||
|
|
@ -8,9 +8,10 @@
|
|||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.14.1"/>
|
||||
<PackageReference Include="Microsoft.Playwright" Version="1.52.0"/>
|
||||
<PackageReference Include="xunit" Version="2.9.3"/>
|
||||
<PackageReference Include="Docker.DotNet" Version="3.125.15" />
|
||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.14.1" />
|
||||
<PackageReference Include="Microsoft.Playwright" Version="1.52.0" />
|
||||
<PackageReference Include="xunit" Version="2.9.3" />
|
||||
<PackageReference Include="xunit.runner.visualstudio" Version="3.1.1">
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||
|
|
@ -26,8 +27,8 @@
|
|||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\submodules\btcpayserver\BTCPayServer.Abstractions\BTCPayServer.Abstractions.csproj"/>
|
||||
<ProjectReference Include="..\submodules\btcpayserver\BTCPayServer.Tests\BTCPayServer.Tests.csproj"/>
|
||||
<ProjectReference Include="..\submodules\btcpayserver\BTCPayServer.Abstractions\BTCPayServer.Abstractions.csproj" />
|
||||
<ProjectReference Include="..\submodules\btcpayserver\BTCPayServer.Tests\BTCPayServer.Tests.csproj" />
|
||||
<ProjectReference Include="..\Plugins\Monero\BTCPayServer.Plugins.Monero.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
|
|
|
|||
|
|
@ -1,5 +1,9 @@
|
|||
using System.Diagnostics;
|
||||
|
||||
using BTCPayServer.Plugins.Monero.Services;
|
||||
using BTCPayServer.Rating;
|
||||
using BTCPayServer.Services.Rates;
|
||||
using BTCPayServer.Tests;
|
||||
using BTCPayServer.Tests.Mocks;
|
||||
|
||||
using Xunit;
|
||||
|
|
@ -36,20 +40,25 @@ public class MoneroPluginIntegrationTest(ITestOutputHelper helper) : MoneroAndBi
|
|||
await s.RegisterNewUser(true);
|
||||
await s.CreateNewStore(preferredExchange: "Kraken");
|
||||
await s.Page.Locator("a.nav-link[href*='monerolike/XMR']").ClickAsync();
|
||||
await s.Page.Locator("input#PrimaryAddress").FillAsync("43Pnj6ZKGFTJhaLhiecSFfLfr64KPJZw7MyGH73T6PTDekBBvsTAaWEUSM4bmJqDuYLizhA13jQkMRPpz9VXBCBqQQb6y5L");
|
||||
await s.Page.Locator("input#PrivateViewKey").FillAsync("1bfa03b0c78aa6bc8292cf160ec9875657d61e889c41d0ebe5c54fd3a2c4b40e");
|
||||
await s.Page.Locator("input#PrimaryAddress")
|
||||
.FillAsync(
|
||||
"43Pnj6ZKGFTJhaLhiecSFfLfr64KPJZw7MyGH73T6PTDekBBvsTAaWEUSM4bmJqDuYLizhA13jQkMRPpz9VXBCBqQQb6y5L");
|
||||
await s.Page.Locator("input#PrivateViewKey")
|
||||
.FillAsync("1bfa03b0c78aa6bc8292cf160ec9875657d61e889c41d0ebe5c54fd3a2c4b40e");
|
||||
await s.Page.Locator("input#RestoreHeight").FillAsync("0");
|
||||
await s.Page.Locator("input#WalletPassword").FillAsync("pass123");
|
||||
await s.Page.ClickAsync("button[name='command'][value='set-wallet-details']");
|
||||
await s.Page.CheckAsync("#Enabled");
|
||||
await s.Page.SelectOptionAsync("#SettlementConfirmationThresholdChoice", "2");
|
||||
await s.Page.ClickAsync("#SaveButton");
|
||||
var classList = await s.Page.Locator("svg.icon-checkmark").GetAttributeAsync("class");
|
||||
var classList = await s.Page
|
||||
.Locator("svg.icon-checkmark")
|
||||
.GetAttributeAsync("class");
|
||||
Assert.Contains("text-success", classList);
|
||||
|
||||
// Set rate provider
|
||||
await s.Page.Locator("#StoreNav-General").ClickAsync();
|
||||
await s.Page.Locator("#mainNav #StoreNav-Rates").ClickAsync();
|
||||
await s.Page.Locator("#menu-item-General").ClickAsync();
|
||||
await s.Page.Locator("#menu-item-Rates").ClickAsync();
|
||||
await s.Page.FillAsync("#DefaultCurrencyPairs", "BTC_USD,XMR_USD,XMR_BTC");
|
||||
await s.Page.SelectOptionAsync("#PrimarySource_PreferredExchange", "kraken");
|
||||
await s.Page.Locator("#page-primary").ClickAsync();
|
||||
|
|
@ -69,7 +78,9 @@ public class MoneroPluginIntegrationTest(ITestOutputHelper helper) : MoneroAndBi
|
|||
await s.Page.ClickAsync("#DetailsToggle");
|
||||
|
||||
// Verify the total fiat amount is $4.20
|
||||
var totalFiat = await s.Page.Locator("#PaymentDetails-TotalFiat dd.clipboard-button").InnerTextAsync();
|
||||
var totalFiat = await s.Page
|
||||
.Locator("#PaymentDetails-TotalFiat dd.clipboard-button")
|
||||
.InnerTextAsync();
|
||||
Assert.Equal("$4.20", totalFiat);
|
||||
|
||||
await s.Page.GoBackAsync();
|
||||
|
|
@ -92,5 +103,90 @@ public class MoneroPluginIntegrationTest(ITestOutputHelper helper) : MoneroAndBi
|
|||
// Select confirmation time to 0
|
||||
await s.Page.SelectOptionAsync("#SettlementConfirmationThresholdChoice", "3");
|
||||
await s.Page.ClickAsync("#SaveButton");
|
||||
|
||||
await CleanUp(s);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task ShouldFailWhenWrongPrimaryAddress()
|
||||
{
|
||||
await using var s = CreatePlaywrightTester();
|
||||
await s.StartAsync();
|
||||
|
||||
await s.RegisterNewUser(true);
|
||||
await s.CreateNewStore();
|
||||
await s.Page.Locator("a.nav-link[href*='monerolike/XMR']").ClickAsync();
|
||||
await s.Page.Locator("input#PrimaryAddress")
|
||||
.FillAsync("wrongprimaryaddressfSF6ZKGFT7MyGH73T6PTDekBBvsTAaWEUSM4bmJqDuYLizhA13jQkMRPpz9VXBCBqQQb6y5L");
|
||||
await s.Page.Locator("input#PrivateViewKey")
|
||||
.FillAsync("1bfa03b0c78aa6bc8292cf160ec9875657d61e889c41d0ebe5c54fd3a2c4b40e");
|
||||
await s.Page.Locator("input#RestoreHeight").FillAsync("0");
|
||||
await s.Page.Locator("input#WalletPassword").FillAsync("pass123");
|
||||
await s.Page.ClickAsync("button[name='command'][value='set-wallet-details']");
|
||||
var errorText = await s.Page
|
||||
.Locator("div.validation-summary-errors li")
|
||||
.InnerTextAsync();
|
||||
|
||||
Assert.Equal("Could not generate view wallet from keys: Failed to parse public address", errorText);
|
||||
|
||||
await CleanUp(s);
|
||||
}
|
||||
|
||||
private static async Task CleanUp(PlaywrightTester playwrightTester)
|
||||
{
|
||||
MoneroRPCProvider moneroRpcProvider = playwrightTester.Server.PayTester.GetService<MoneroRPCProvider>();
|
||||
if (moneroRpcProvider.IsAvailable("XMR"))
|
||||
{
|
||||
await moneroRpcProvider.CloseWallet("XMR");
|
||||
await moneroRpcProvider.UpdateSummary("XMR");
|
||||
}
|
||||
|
||||
if (playwrightTester.Server.PayTester.InContainer)
|
||||
{
|
||||
moneroRpcProvider.DeleteWallet();
|
||||
}
|
||||
else
|
||||
{
|
||||
await RemoveWalletFromLocalDocker();
|
||||
}
|
||||
}
|
||||
|
||||
static async Task RemoveWalletFromLocalDocker()
|
||||
{
|
||||
try
|
||||
{
|
||||
var removeWalletFromDocker = new ProcessStartInfo
|
||||
{
|
||||
FileName = "docker",
|
||||
Arguments = "exec xmr_wallet sh -c \"rm -rf /wallet/*\"",
|
||||
RedirectStandardOutput = true,
|
||||
RedirectStandardError = true
|
||||
};
|
||||
|
||||
using var process = Process.Start(removeWalletFromDocker);
|
||||
if (process is null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var stdout = await process.StandardOutput.ReadToEndAsync();
|
||||
var stderr = await process.StandardError.ReadToEndAsync();
|
||||
|
||||
await process.WaitForExitAsync();
|
||||
|
||||
if (!string.IsNullOrWhiteSpace(stdout))
|
||||
{
|
||||
Console.WriteLine(stdout);
|
||||
}
|
||||
|
||||
if (!string.IsNullOrWhiteSpace(stderr))
|
||||
{
|
||||
Console.WriteLine(stderr);
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Console.WriteLine($"Cleanup failed: {ex}");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -22,6 +22,7 @@ services:
|
|||
- "tests:127.0.0.1"
|
||||
volumes:
|
||||
- ../coverage:/coverage
|
||||
- xmr_wallet:/wallet
|
||||
|
||||
# The dev container is not used, it is just handy to run `docker-compose up dev` to start all services
|
||||
dev:
|
||||
|
|
@ -89,7 +90,7 @@ services:
|
|||
- "bitcoin_datadir:/data"
|
||||
|
||||
monerod:
|
||||
image: btcpayserver/monero:0.18.4.2
|
||||
image: btcpayserver/monero:0.18.4.3
|
||||
restart: unless-stopped
|
||||
container_name: monerod
|
||||
command: monerod --fixed-difficulty 1 --log-level=2 --rpc-bind-ip=0.0.0.0 --confirm-external-bind --rpc-bind-port=18081 --block-notify="/bin/sh ./scripts/notifier.sh -k -X GET https://host.docker.internal:14142/monerolikedaemoncallback/block?cryptoCode=xmr&hash=%s" --regtest --no-igd --hide-my-port --offline --non-interactive
|
||||
|
|
@ -99,7 +100,7 @@ services:
|
|||
- "18081:18081"
|
||||
|
||||
xmr_wallet:
|
||||
image: btcpayserver/monero:0.18.4.2
|
||||
image: btcpayserver/monero:0.18.4.3
|
||||
restart: unless-stopped
|
||||
container_name: xmr_wallet
|
||||
command: monero-wallet-rpc --log-level 2 --allow-mismatched-daemon-version --rpc-bind-ip=0.0.0.0 --disable-rpc-login --confirm-external-bind --rpc-bind-port=18082 --non-interactive --trusted-daemon --daemon-address=monerod:18081 --wallet-dir=/wallet --tx-notify="/bin/sh ./scripts/notifier.sh -k -X GET https://host.docker.internal:14142/monerolikedaemoncallback/tx?cryptoCode=xmr&hash=%s"
|
||||
|
|
|
|||
|
|
@ -39,10 +39,7 @@
|
|||
<!-- Deterministic build -->
|
||||
<ItemGroup>
|
||||
<PackageReference Include="DotNet.ReproducibleBuilds" Version="1.2.25" PrivateAssets="All"/>
|
||||
<PackageReference Include="DotNet.ReproducibleBuilds.Isolated" Version="1.2.25" />
|
||||
<PackageReference Include="Microsoft.NETFramework.ReferenceAssemblies" Version="1.0.3" PrivateAssets="All" />
|
||||
<PackageReference Include="Microsoft.SourceLink.GitHub" Version="8.0.0" PrivateAssets="All" />
|
||||
<EmbeddedFiles Include="$(GeneratedAssemblyInfoFile)"/>
|
||||
</ItemGroup>
|
||||
|
||||
<!-- If you need Entity Framework, you can uncomment this. This will make it usable in your project without publishing assemblies
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
using System;
|
||||
using System.Collections.Concurrent;
|
||||
using System.Collections.Immutable;
|
||||
using System.IO;
|
||||
using System.Net.Http;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
|
|
@ -8,6 +9,8 @@ using BTCPayServer.Plugins.Monero.Configuration;
|
|||
using BTCPayServer.Plugins.Monero.RPC;
|
||||
using BTCPayServer.Plugins.Monero.RPC.Models;
|
||||
|
||||
using Microsoft.Extensions.Logging;
|
||||
|
||||
using NBitcoin;
|
||||
|
||||
namespace BTCPayServer.Plugins.Monero.Services
|
||||
|
|
@ -18,6 +21,7 @@ namespace BTCPayServer.Plugins.Monero.Services
|
|||
private readonly EventAggregator _eventAggregator;
|
||||
public ImmutableDictionary<string, JsonRpcClient> DaemonRpcClients;
|
||||
public ImmutableDictionary<string, JsonRpcClient> WalletRpcClients;
|
||||
private readonly ILogger<MoneroRPCProvider> _logger;
|
||||
|
||||
private readonly ConcurrentDictionary<string, MoneroLikeSummary> _summaries = new();
|
||||
|
||||
|
|
@ -25,10 +29,12 @@ namespace BTCPayServer.Plugins.Monero.Services
|
|||
|
||||
public MoneroRPCProvider(MoneroLikeConfiguration moneroLikeConfiguration,
|
||||
EventAggregator eventAggregator,
|
||||
ILogger<MoneroRPCProvider> logger,
|
||||
IHttpClientFactory httpClientFactory)
|
||||
{
|
||||
_moneroLikeConfiguration = moneroLikeConfiguration;
|
||||
_eventAggregator = eventAggregator;
|
||||
_logger = logger;
|
||||
DaemonRpcClients =
|
||||
_moneroLikeConfiguration.MoneroLikeConfigurationItems.ToImmutableDictionary(pair => pair.Key,
|
||||
pair => new JsonRpcClient(pair.Value.DaemonRpcUri, pair.Value.Username, pair.Value.Password,
|
||||
|
|
@ -52,6 +58,56 @@ namespace BTCPayServer.Plugins.Monero.Services
|
|||
summary.WalletAvailable;
|
||||
}
|
||||
|
||||
public async Task CloseWallet(string cryptoCode)
|
||||
{
|
||||
if (!WalletRpcClients.TryGetValue(cryptoCode.ToUpperInvariant(), out var walletRpcClient))
|
||||
{
|
||||
throw new InvalidOperationException($"Wallet RPC client not found for {cryptoCode}");
|
||||
}
|
||||
|
||||
await walletRpcClient.SendCommandAsync<JsonRpcClient.NoRequestModel, object>(
|
||||
"close_wallet", JsonRpcClient.NoRequestModel.Instance);
|
||||
}
|
||||
|
||||
public void DeleteWallet()
|
||||
{
|
||||
if (!_moneroLikeConfiguration.MoneroLikeConfigurationItems.TryGetValue("XMR", out var configItem))
|
||||
{
|
||||
_logger.LogWarning("DeleteWallet: No XMR configuration found.");
|
||||
return;
|
||||
}
|
||||
|
||||
if (string.IsNullOrEmpty(configItem.WalletDirectory))
|
||||
{
|
||||
_logger.LogWarning("DeleteWallet: WalletDirectory is null or empty for XMR configuration.");
|
||||
return;
|
||||
}
|
||||
try
|
||||
{
|
||||
var walletFile = Path.Combine(configItem.WalletDirectory, "view_wallet");
|
||||
var keysFile = walletFile + ".keys";
|
||||
var passwordFile = Path.Combine(configItem.WalletDirectory, "password");
|
||||
|
||||
if (File.Exists(walletFile))
|
||||
{
|
||||
File.Delete(walletFile);
|
||||
}
|
||||
if (File.Exists(keysFile))
|
||||
{
|
||||
File.Delete(keysFile);
|
||||
}
|
||||
if (File.Exists(passwordFile))
|
||||
{
|
||||
File.Delete(passwordFile);
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.LogError(ex, "Failed to delete wallet files in directory {Dir}",
|
||||
configItem.WalletDirectory);
|
||||
}
|
||||
}
|
||||
|
||||
public async Task<MoneroLikeSummary> UpdateSummary(string cryptoCode)
|
||||
{
|
||||
if (!DaemonRpcClients.TryGetValue(cryptoCode.ToUpperInvariant(), out var daemonRpcClient) ||
|
||||
|
|
|
|||
6
global.json
Normal file
6
global.json
Normal file
|
|
@ -0,0 +1,6 @@
|
|||
{
|
||||
"sdk": {
|
||||
"version": "8.0.416",
|
||||
"rollForward": "latestFeature"
|
||||
}
|
||||
}
|
||||
|
|
@ -1 +1 @@
|
|||
Subproject commit 22f06893b9e11e88042f253099b76295c1f99fef
|
||||
Subproject commit 5a487985f4c1b6f4b80a5618fa4d8e8a82069adb
|
||||
Loading…
Add table
Reference in a new issue