Skip to content

Commit 1ae5455

Browse files
committed
Add unhappy scenario integration test with razor and context fixes
1 parent cdfdb2c commit 1ae5455

8 files changed

Lines changed: 175 additions & 18 deletions

File tree

.github/workflows/dotnet.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ jobs:
3131
run: dotnet clean
3232

3333
- name: Build projects
34-
run: dotnet build -c Release --no-restore
34+
run: dotnet build -maxcpucount:1 -c Release --no-restore
3535

3636
- name: Deterministic build check
3737
run: |

BTCPayServer.Plugins.IntegrationTests/BTCPayServer.Plugins.IntegrationTests.csproj

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -8,9 +8,10 @@
88
</PropertyGroup>
99

1010
<ItemGroup>
11-
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.14.1"/>
12-
<PackageReference Include="Microsoft.Playwright" Version="1.52.0"/>
13-
<PackageReference Include="xunit" Version="2.9.3"/>
11+
<PackageReference Include="Docker.DotNet" Version="3.125.15" />
12+
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.14.1" />
13+
<PackageReference Include="Microsoft.Playwright" Version="1.52.0" />
14+
<PackageReference Include="xunit" Version="2.9.3" />
1415
<PackageReference Include="xunit.runner.visualstudio" Version="3.1.1">
1516
<PrivateAssets>all</PrivateAssets>
1617
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
@@ -26,8 +27,8 @@
2627
</ItemGroup>
2728

2829
<ItemGroup>
29-
<ProjectReference Include="..\submodules\btcpayserver\BTCPayServer.Abstractions\BTCPayServer.Abstractions.csproj"/>
30-
<ProjectReference Include="..\submodules\btcpayserver\BTCPayServer.Tests\BTCPayServer.Tests.csproj"/>
30+
<ProjectReference Include="..\submodules\btcpayserver\BTCPayServer.Abstractions\BTCPayServer.Abstractions.csproj" />
31+
<ProjectReference Include="..\submodules\btcpayserver\BTCPayServer.Tests\BTCPayServer.Tests.csproj" />
3132
<ProjectReference Include="..\Plugins\Monero\BTCPayServer.Plugins.Monero.csproj" />
3233
</ItemGroup>
3334

BTCPayServer.Plugins.IntegrationTests/Monero/MoneroPluginIntegrationTest.cs

Lines changed: 102 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,9 @@
1+
using System.Diagnostics;
2+
3+
using BTCPayServer.Plugins.Monero.Services;
14
using BTCPayServer.Rating;
25
using BTCPayServer.Services.Rates;
6+
using BTCPayServer.Tests;
37
using BTCPayServer.Tests.Mocks;
48

59
using Xunit;
@@ -36,20 +40,25 @@ public async Task EnableMoneroPluginSuccessfully()
3640
await s.RegisterNewUser(true);
3741
await s.CreateNewStore(preferredExchange: "Kraken");
3842
await s.Page.Locator("a.nav-link[href*='monerolike/XMR']").ClickAsync();
39-
await s.Page.Locator("input#PrimaryAddress").FillAsync("43Pnj6ZKGFTJhaLhiecSFfLfr64KPJZw7MyGH73T6PTDekBBvsTAaWEUSM4bmJqDuYLizhA13jQkMRPpz9VXBCBqQQb6y5L");
40-
await s.Page.Locator("input#PrivateViewKey").FillAsync("1bfa03b0c78aa6bc8292cf160ec9875657d61e889c41d0ebe5c54fd3a2c4b40e");
43+
await s.Page.Locator("input#PrimaryAddress")
44+
.FillAsync(
45+
"43Pnj6ZKGFTJhaLhiecSFfLfr64KPJZw7MyGH73T6PTDekBBvsTAaWEUSM4bmJqDuYLizhA13jQkMRPpz9VXBCBqQQb6y5L");
46+
await s.Page.Locator("input#PrivateViewKey")
47+
.FillAsync("1bfa03b0c78aa6bc8292cf160ec9875657d61e889c41d0ebe5c54fd3a2c4b40e");
4148
await s.Page.Locator("input#RestoreHeight").FillAsync("0");
4249
await s.Page.Locator("input#WalletPassword").FillAsync("pass123");
4350
await s.Page.ClickAsync("button[name='command'][value='set-wallet-details']");
4451
await s.Page.CheckAsync("#Enabled");
4552
await s.Page.SelectOptionAsync("#SettlementConfirmationThresholdChoice", "2");
4653
await s.Page.ClickAsync("#SaveButton");
47-
var classList = await s.Page.Locator("svg.icon-checkmark").GetAttributeAsync("class");
54+
var classList = await s.Page
55+
.Locator("svg.icon-checkmark")
56+
.GetAttributeAsync("class");
4857
Assert.Contains("text-success", classList);
4958

5059
// Set rate provider
51-
await s.Page.Locator("#StoreNav-General").ClickAsync();
52-
await s.Page.Locator("#mainNav #StoreNav-Rates").ClickAsync();
60+
await s.Page.Locator("#menu-item-General").ClickAsync();
61+
await s.Page.Locator("#menu-item-Rates").ClickAsync();
5362
await s.Page.FillAsync("#DefaultCurrencyPairs", "BTC_USD,XMR_USD,XMR_BTC");
5463
await s.Page.SelectOptionAsync("#PrimarySource_PreferredExchange", "kraken");
5564
await s.Page.Locator("#page-primary").ClickAsync();
@@ -69,7 +78,9 @@ public async Task EnableMoneroPluginSuccessfully()
6978
await s.Page.ClickAsync("#DetailsToggle");
7079

7180
// Verify the total fiat amount is $4.20
72-
var totalFiat = await s.Page.Locator("#PaymentDetails-TotalFiat dd.clipboard-button").InnerTextAsync();
81+
var totalFiat = await s.Page
82+
.Locator("#PaymentDetails-TotalFiat dd.clipboard-button")
83+
.InnerTextAsync();
7384
Assert.Equal("$4.20", totalFiat);
7485

7586
await s.Page.GoBackAsync();
@@ -92,5 +103,90 @@ public async Task EnableMoneroPluginSuccessfully()
92103
// Select confirmation time to 0
93104
await s.Page.SelectOptionAsync("#SettlementConfirmationThresholdChoice", "3");
94105
await s.Page.ClickAsync("#SaveButton");
106+
107+
await CleanUp(s);
108+
}
109+
110+
[Fact]
111+
public async Task ShouldFailWhenWrongPrimaryAddress()
112+
{
113+
await using var s = CreatePlaywrightTester();
114+
await s.StartAsync();
115+
116+
await s.RegisterNewUser(true);
117+
await s.CreateNewStore();
118+
await s.Page.Locator("a.nav-link[href*='monerolike/XMR']").ClickAsync();
119+
await s.Page.Locator("input#PrimaryAddress")
120+
.FillAsync("wrongprimaryaddressfSF6ZKGFT7MyGH73T6PTDekBBvsTAaWEUSM4bmJqDuYLizhA13jQkMRPpz9VXBCBqQQb6y5L");
121+
await s.Page.Locator("input#PrivateViewKey")
122+
.FillAsync("1bfa03b0c78aa6bc8292cf160ec9875657d61e889c41d0ebe5c54fd3a2c4b40e");
123+
await s.Page.Locator("input#RestoreHeight").FillAsync("0");
124+
await s.Page.Locator("input#WalletPassword").FillAsync("pass123");
125+
await s.Page.ClickAsync("button[name='command'][value='set-wallet-details']");
126+
var errorText = await s.Page
127+
.Locator("div.validation-summary-errors li")
128+
.InnerTextAsync();
129+
130+
Assert.Equal("Could not generate view wallet from keys: Failed to parse public address", errorText);
131+
132+
await CleanUp(s);
133+
}
134+
135+
private static async Task CleanUp(PlaywrightTester playwrightTester)
136+
{
137+
MoneroRPCProvider moneroRpcProvider = playwrightTester.Server.PayTester.GetService<MoneroRPCProvider>();
138+
if (moneroRpcProvider.IsAvailable("XMR"))
139+
{
140+
await moneroRpcProvider.CloseWallet("XMR");
141+
await moneroRpcProvider.UpdateSummary("XMR");
142+
}
143+
144+
if (playwrightTester.Server.PayTester.InContainer)
145+
{
146+
moneroRpcProvider.DeleteWallet();
147+
}
148+
else
149+
{
150+
await RemoveWalletFromLocalDocker();
151+
}
152+
}
153+
154+
static async Task RemoveWalletFromLocalDocker()
155+
{
156+
try
157+
{
158+
var removeWalletFromDocker = new ProcessStartInfo
159+
{
160+
FileName = "docker",
161+
Arguments = "exec xmr_wallet sh -c \"rm -rf /wallet/*\"",
162+
RedirectStandardOutput = true,
163+
RedirectStandardError = true
164+
};
165+
166+
using var process = Process.Start(removeWalletFromDocker);
167+
if (process is null)
168+
{
169+
return;
170+
}
171+
172+
var stdout = await process.StandardOutput.ReadToEndAsync();
173+
var stderr = await process.StandardError.ReadToEndAsync();
174+
175+
await process.WaitForExitAsync();
176+
177+
if (!string.IsNullOrWhiteSpace(stdout))
178+
{
179+
Console.WriteLine(stdout);
180+
}
181+
182+
if (!string.IsNullOrWhiteSpace(stderr))
183+
{
184+
Console.WriteLine(stderr);
185+
}
186+
}
187+
catch (Exception ex)
188+
{
189+
Console.WriteLine($"Cleanup failed: {ex}");
190+
}
95191
}
96192
}

BTCPayServer.Plugins.IntegrationTests/docker-compose.yml

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ services:
2222
- "tests:127.0.0.1"
2323
volumes:
2424
- ../coverage:/coverage
25+
- xmr_wallet:/wallet
2526

2627
# The dev container is not used, it is just handy to run `docker-compose up dev` to start all services
2728
dev:
@@ -89,7 +90,7 @@ services:
8990
- "bitcoin_datadir:/data"
9091

9192
monerod:
92-
image: btcpayserver/monero:0.18.4.2
93+
image: btcpayserver/monero:0.18.4.3
9394
restart: unless-stopped
9495
container_name: monerod
9596
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:
99100
- "18081:18081"
100101

101102
xmr_wallet:
102-
image: btcpayserver/monero:0.18.4.2
103+
image: btcpayserver/monero:0.18.4.3
103104
restart: unless-stopped
104105
container_name: xmr_wallet
105106
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"

Plugins/Monero/BTCPayServer.Plugins.Monero.csproj

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -39,10 +39,7 @@
3939
<!-- Deterministic build -->
4040
<ItemGroup>
4141
<PackageReference Include="DotNet.ReproducibleBuilds" Version="1.2.25" PrivateAssets="All"/>
42-
<PackageReference Include="DotNet.ReproducibleBuilds.Isolated" Version="1.2.25" />
43-
<PackageReference Include="Microsoft.NETFramework.ReferenceAssemblies" Version="1.0.3" PrivateAssets="All" />
4442
<PackageReference Include="Microsoft.SourceLink.GitHub" Version="8.0.0" PrivateAssets="All" />
45-
<EmbeddedFiles Include="$(GeneratedAssemblyInfoFile)"/>
4643
</ItemGroup>
4744

4845
<!-- If you need Entity Framework, you can uncomment this. This will make it usable in your project without publishing assemblies

Plugins/Monero/Services/MoneroRPCProvider.cs

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,16 @@
11
using System;
22
using System.Collections.Concurrent;
33
using System.Collections.Immutable;
4+
using System.IO;
45
using System.Net.Http;
56
using System.Threading.Tasks;
67

78
using BTCPayServer.Plugins.Monero.Configuration;
89
using BTCPayServer.Plugins.Monero.RPC;
910
using BTCPayServer.Plugins.Monero.RPC.Models;
1011

12+
using Microsoft.Extensions.Logging;
13+
1114
using NBitcoin;
1215

1316
namespace BTCPayServer.Plugins.Monero.Services
@@ -18,17 +21,20 @@ public class MoneroRPCProvider
1821
private readonly EventAggregator _eventAggregator;
1922
public ImmutableDictionary<string, JsonRpcClient> DaemonRpcClients;
2023
public ImmutableDictionary<string, JsonRpcClient> WalletRpcClients;
24+
private readonly ILogger<MoneroRPCProvider> _logger;
2125

2226
private readonly ConcurrentDictionary<string, MoneroLikeSummary> _summaries = new();
2327

2428
public ConcurrentDictionary<string, MoneroLikeSummary> Summaries => _summaries;
2529

2630
public MoneroRPCProvider(MoneroLikeConfiguration moneroLikeConfiguration,
2731
EventAggregator eventAggregator,
32+
ILogger<MoneroRPCProvider> logger,
2833
IHttpClientFactory httpClientFactory)
2934
{
3035
_moneroLikeConfiguration = moneroLikeConfiguration;
3136
_eventAggregator = eventAggregator;
37+
_logger = logger;
3238
DaemonRpcClients =
3339
_moneroLikeConfiguration.MoneroLikeConfigurationItems.ToImmutableDictionary(pair => pair.Key,
3440
pair => new JsonRpcClient(pair.Value.DaemonRpcUri, pair.Value.Username, pair.Value.Password,
@@ -52,6 +58,56 @@ private bool IsAvailable(MoneroLikeSummary summary)
5258
summary.WalletAvailable;
5359
}
5460

61+
public async Task CloseWallet(string cryptoCode)
62+
{
63+
if (!WalletRpcClients.TryGetValue(cryptoCode.ToUpperInvariant(), out var walletRpcClient))
64+
{
65+
throw new InvalidOperationException($"Wallet RPC client not found for {cryptoCode}");
66+
}
67+
68+
await walletRpcClient.SendCommandAsync<JsonRpcClient.NoRequestModel, object>(
69+
"close_wallet", JsonRpcClient.NoRequestModel.Instance);
70+
}
71+
72+
public void DeleteWallet()
73+
{
74+
if (!_moneroLikeConfiguration.MoneroLikeConfigurationItems.TryGetValue("XMR", out var configItem))
75+
{
76+
_logger.LogWarning("DeleteWallet: No XMR configuration found.");
77+
return;
78+
}
79+
80+
if (string.IsNullOrEmpty(configItem.WalletDirectory))
81+
{
82+
_logger.LogWarning("DeleteWallet: WalletDirectory is null or empty for XMR configuration.");
83+
return;
84+
}
85+
try
86+
{
87+
var walletFile = Path.Combine(configItem.WalletDirectory, "view_wallet");
88+
var keysFile = walletFile + ".keys";
89+
var passwordFile = Path.Combine(configItem.WalletDirectory, "password");
90+
91+
if (File.Exists(walletFile))
92+
{
93+
File.Delete(walletFile);
94+
}
95+
if (File.Exists(keysFile))
96+
{
97+
File.Delete(keysFile);
98+
}
99+
if (File.Exists(passwordFile))
100+
{
101+
File.Delete(passwordFile);
102+
}
103+
}
104+
catch (Exception ex)
105+
{
106+
_logger.LogError(ex, "Failed to delete wallet files in directory {Dir}",
107+
configItem.WalletDirectory);
108+
}
109+
}
110+
55111
public async Task<MoneroLikeSummary> UpdateSummary(string cryptoCode)
56112
{
57113
if (!DaemonRpcClients.TryGetValue(cryptoCode.ToUpperInvariant(), out var daemonRpcClient) ||

global.json

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
{
2+
"sdk": {
3+
"version": "8.0.416",
4+
"rollForward": "latestFeature"
5+
}
6+
}

submodules/btcpayserver

Submodule btcpayserver updated 545 files

0 commit comments

Comments
 (0)