Skip to content

Commit 3847d87

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

9 files changed

Lines changed: 159 additions & 56 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: |

.gitmodules

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,3 @@
11
[submodule "submodules/btcpayserver"]
2-
path = submodules/btcpayserver
3-
url = https://github.com/btcpayserver/btcpayserver
2+
path = submodules/btcpayserver
3+
url = https://github.com/btcpayserver/btcpayserver

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

Lines changed: 130 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -1,23 +1,68 @@
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;
610
using Xunit.Abstractions;
711

812
namespace BTCPayServer.Plugins.IntegrationTests.Monero;
913

10-
public class MoneroPluginIntegrationTest(ITestOutputHelper helper) : MoneroAndBitcoinIntegrationTestBase(helper)
14+
public class MoneroPluginIntegrationTest(ITestOutputHelper helper) : MoneroAndBitcoinIntegrationTestBase(helper), IAsyncLifetime
1115
{
16+
public Task InitializeAsync() => Task.CompletedTask;
17+
18+
public async Task DisposeAsync()
19+
{
20+
try
21+
{
22+
var removeWalletFromDocker = new ProcessStartInfo
23+
{
24+
FileName = "docker",
25+
Arguments = "exec xmr_wallet sh -c \"rm -rf /wallet/*\"",
26+
RedirectStandardOutput = true,
27+
RedirectStandardError = true
28+
};
29+
30+
using var process = Process.Start(removeWalletFromDocker);
31+
if (process is null)
32+
{
33+
return;
34+
}
35+
36+
var stdout = await process.StandardOutput.ReadToEndAsync();
37+
var stderr = await process.StandardError.ReadToEndAsync();
38+
39+
await process.WaitForExitAsync();
40+
41+
if (!string.IsNullOrWhiteSpace(stdout))
42+
{
43+
Console.WriteLine(stdout);
44+
}
45+
46+
if (!string.IsNullOrWhiteSpace(stderr))
47+
{
48+
Console.WriteLine(stderr);
49+
}
50+
}
51+
catch (Exception ex)
52+
{
53+
Console.WriteLine($"Cleanup failed: {ex}");
54+
}
55+
}
56+
1257
[Fact]
1358
public async Task EnableMoneroPluginSuccessfully()
1459
{
15-
await using var s = CreatePlaywrightTester();
16-
await s.StartAsync();
60+
await using var playwrightTester = CreatePlaywrightTester();
61+
await playwrightTester.StartAsync();
1762

18-
if (s.Server.PayTester.MockRates)
63+
if (playwrightTester.Server.PayTester.MockRates)
1964
{
20-
var rateProviderFactory = s.Server.PayTester.GetService<RateProviderFactory>();
65+
var rateProviderFactory = playwrightTester.Server.PayTester.GetService<RateProviderFactory>();
2166
rateProviderFactory.Providers.Clear();
2267

2368
var coinAverageMock = new MockRateProvider();
@@ -33,64 +78,107 @@ public async Task EnableMoneroPluginSuccessfully()
3378
rateProviderFactory.Providers.Add("kraken", kraken);
3479
}
3580

36-
await s.RegisterNewUser(true);
37-
await s.CreateNewStore(preferredExchange: "Kraken");
38-
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");
41-
await s.Page.Locator("input#RestoreHeight").FillAsync("0");
42-
await s.Page.Locator("input#WalletPassword").FillAsync("pass123");
43-
await s.Page.ClickAsync("button[name='command'][value='set-wallet-details']");
44-
await s.Page.CheckAsync("#Enabled");
45-
await s.Page.SelectOptionAsync("#SettlementConfirmationThresholdChoice", "2");
46-
await s.Page.ClickAsync("#SaveButton");
47-
var classList = await s.Page.Locator("svg.icon-checkmark").GetAttributeAsync("class");
81+
await playwrightTester.RegisterNewUser(true);
82+
await playwrightTester.CreateNewStore(preferredExchange: "Kraken");
83+
await playwrightTester.Page.Locator("a.nav-link[href*='monerolike/XMR']").ClickAsync();
84+
await playwrightTester.Page.Locator("input#PrimaryAddress")
85+
.FillAsync("43Pnj6ZKGFTJhaLhiecSFfLfr64KPJZw7MyGH73T6PTDekBBvsTAaWEUSM4bmJqDuYLizhA13jQkMRPpz9VXBCBqQQb6y5L");
86+
await playwrightTester.Page.Locator("input#PrivateViewKey")
87+
.FillAsync("1bfa03b0c78aa6bc8292cf160ec9875657d61e889c41d0ebe5c54fd3a2c4b40e");
88+
await playwrightTester.Page.Locator("input#RestoreHeight").FillAsync("0");
89+
await playwrightTester.Page.Locator("input#WalletPassword").FillAsync("pass123");
90+
await playwrightTester.Page.ClickAsync("button[name='command'][value='set-wallet-details']");
91+
await playwrightTester.Page.CheckAsync("#Enabled");
92+
await playwrightTester.Page.SelectOptionAsync("#SettlementConfirmationThresholdChoice", "2");
93+
await playwrightTester.Page.ClickAsync("#SaveButton");
94+
var classList = await playwrightTester.Page
95+
.Locator("svg.icon-checkmark")
96+
.GetAttributeAsync("class");
4897
Assert.Contains("text-success", classList);
4998

5099
// Set rate provider
51-
await s.Page.Locator("#StoreNav-General").ClickAsync();
52-
await s.Page.Locator("#mainNav #StoreNav-Rates").ClickAsync();
53-
await s.Page.FillAsync("#DefaultCurrencyPairs", "BTC_USD,XMR_USD,XMR_BTC");
54-
await s.Page.SelectOptionAsync("#PrimarySource_PreferredExchange", "kraken");
55-
await s.Page.Locator("#page-primary").ClickAsync();
100+
await playwrightTester.Page.Locator("#menu-item-General").ClickAsync();
101+
await playwrightTester.Page.Locator("#menu-item-Rates").ClickAsync();
102+
await playwrightTester.Page.FillAsync("#DefaultCurrencyPairs", "BTC_USD,XMR_USD,XMR_BTC");
103+
await playwrightTester.Page.SelectOptionAsync("#PrimarySource_PreferredExchange", "kraken");
104+
await playwrightTester.Page.Locator("#page-primary").ClickAsync();
56105

57106
// Generate a new invoice
58-
await s.Page.Locator("a.nav-link[href*='invoices']").ClickAsync();
59-
await s.Page.Locator("#page-primary").ClickAsync();
60-
await s.Page.FillAsync("#Amount", "4.20");
61-
await s.Page.FillAsync("#BuyerEmail", "monero@monero.com");
107+
await playwrightTester.Page.Locator("a.nav-link[href*='invoices']").ClickAsync();
108+
await playwrightTester.Page.Locator("#page-primary").ClickAsync();
109+
await playwrightTester.Page.FillAsync("#Amount", "4.20");
110+
await playwrightTester.Page.FillAsync("#BuyerEmail", "monero@monero.com");
62111
await Task.Delay(TimeSpan.FromSeconds(25)); // wallet-rpc needs some time to sync. refactor this later
63-
await s.Page.Locator("#page-primary").ClickAsync();
112+
await playwrightTester.Page.Locator("#page-primary").ClickAsync();
64113

65114
// View the invoice
66-
var href = await s.Page.Locator("a[href^='/i/']").GetAttributeAsync("href");
115+
var href = await playwrightTester.Page.Locator("a[href^='/i/']").GetAttributeAsync("href");
67116
var invoiceId = href?.Split("/i/").Last();
68-
await s.Page.Locator($"a[href='/i/{invoiceId}']").ClickAsync();
69-
await s.Page.ClickAsync("#DetailsToggle");
117+
await playwrightTester.Page.Locator($"a[href='/i/{invoiceId}']").ClickAsync();
118+
await playwrightTester.Page.ClickAsync("#DetailsToggle");
70119

71120
// Verify the total fiat amount is $4.20
72-
var totalFiat = await s.Page.Locator("#PaymentDetails-TotalFiat dd.clipboard-button").InnerTextAsync();
121+
var totalFiat = await playwrightTester.Page
122+
.Locator("#PaymentDetails-TotalFiat dd.clipboard-button")
123+
.InnerTextAsync();
73124
Assert.Equal("$4.20", totalFiat);
74125

75-
await s.Page.GoBackAsync();
76-
await s.Page.Locator("a.nav-link[href*='monerolike/XMR']").ClickAsync();
126+
await playwrightTester.Page.GoBackAsync();
127+
await playwrightTester.Page.Locator("a.nav-link[href*='monerolike/XMR']").ClickAsync();
77128

78129
// Create a new account label
79-
await s.Page.FillAsync("#NewAccountLabel", "tst-account");
80-
await s.Page.ClickAsync("button[name='command'][value='add-account']");
130+
await playwrightTester.Page.FillAsync("#NewAccountLabel", "tst-account");
131+
await playwrightTester.Page.ClickAsync("button[name='command'][value='add-account']");
81132

82133
// Select primary Account Index
83-
await s.Page.Locator("a.nav-link[href*='monerolike/XMR']").ClickAsync();
84-
await s.Page.SelectOptionAsync("#AccountIndex", "1");
85-
await s.Page.ClickAsync("#SaveButton");
134+
await playwrightTester.Page.Locator("a.nav-link[href*='monerolike/XMR']").ClickAsync();
135+
await playwrightTester.Page.SelectOptionAsync("#AccountIndex", "1");
136+
await playwrightTester.Page.ClickAsync("#SaveButton");
86137

87138
// Verify selected account index
88-
await s.Page.Locator("a.nav-link[href*='monerolike/XMR']").ClickAsync();
89-
var selectedValue = await s.Page.Locator("#AccountIndex").InputValueAsync();
139+
await playwrightTester.Page.Locator("a.nav-link[href*='monerolike/XMR']").ClickAsync();
140+
var selectedValue = await playwrightTester.Page.Locator("#AccountIndex").InputValueAsync();
90141
Assert.Equal("1", selectedValue);
91142

92143
// Select confirmation time to 0
93-
await s.Page.SelectOptionAsync("#SettlementConfirmationThresholdChoice", "3");
94-
await s.Page.ClickAsync("#SaveButton");
144+
await playwrightTester.Page.SelectOptionAsync("#SettlementConfirmationThresholdChoice", "3");
145+
await playwrightTester.Page.ClickAsync("#SaveButton");
146+
147+
await CleanUp(playwrightTester);
148+
}
149+
150+
[Fact]
151+
public async Task ShouldFailWhenWrongPrimaryAddress()
152+
{
153+
await using var playwrightTester = CreatePlaywrightTester();
154+
await playwrightTester.StartAsync();
155+
156+
await playwrightTester.RegisterNewUser(true);
157+
await playwrightTester.CreateNewStore();
158+
await playwrightTester.Page.Locator("a.nav-link[href*='monerolike/XMR']").ClickAsync();
159+
await playwrightTester.Page.Locator("input#PrimaryAddress")
160+
.FillAsync("wrongprimaryaddressfSF6ZKGFT7MyGH73T6PTDekBBvsTAaWEUSM4bmJqDuYLizhA13jQkMRPpz9VXBCBqQQb6y5L");
161+
await playwrightTester.Page.Locator("input#PrivateViewKey")
162+
.FillAsync("1bfa03b0c78aa6bc8292cf160ec9875657d61e889c41d0ebe5c54fd3a2c4b40e");
163+
await playwrightTester.Page.Locator("input#RestoreHeight").FillAsync("0");
164+
await playwrightTester.Page.Locator("input#WalletPassword").FillAsync("pass123");
165+
await playwrightTester.Page.ClickAsync("button[name='command'][value='set-wallet-details']");
166+
var errorText = await playwrightTester.Page
167+
.Locator("div.validation-summary-errors li")
168+
.InnerTextAsync();
169+
170+
Assert.Equal("Could not generate view wallet from keys: Failed to parse public address", errorText);
171+
172+
await CleanUp(playwrightTester);
173+
}
174+
175+
private static async Task CleanUp(PlaywrightTester playwrightTester)
176+
{
177+
MoneroRPCProvider moneroRpcProvider = playwrightTester.Server.PayTester.GetService<MoneroRPCProvider>();
178+
if (moneroRpcProvider.IsAvailable("XMR"))
179+
{
180+
await moneroRpcProvider.CloseWallet("XMR");
181+
await moneroRpcProvider.UpdateSummary("XMR");
182+
}
95183
}
96184
}

BTCPayServer.Plugins.IntegrationTests/docker-compose.yml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -89,7 +89,7 @@ services:
8989
- "bitcoin_datadir:/data"
9090

9191
monerod:
92-
image: btcpayserver/monero:0.18.4.2
92+
image: btcpayserver/monero:0.18.4.3
9393
restart: unless-stopped
9494
container_name: monerod
9595
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 +99,7 @@ services:
9999
- "18081:18081"
100100

101101
xmr_wallet:
102-
image: btcpayserver/monero:0.18.4.2
102+
image: btcpayserver/monero:0.18.4.3
103103
restart: unless-stopped
104104
container_name: xmr_wallet
105105
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: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,17 @@ private bool IsAvailable(MoneroLikeSummary summary)
5252
summary.WalletAvailable;
5353
}
5454

55+
public async Task CloseWallet(string cryptoCode)
56+
{
57+
if (!WalletRpcClients.TryGetValue(cryptoCode.ToUpperInvariant(), out var walletRpcClient))
58+
{
59+
throw new InvalidOperationException($"Wallet RPC client not found for {cryptoCode}");
60+
}
61+
62+
await walletRpcClient.SendCommandAsync<JsonRpcClient.NoRequestModel, object>(
63+
"close_wallet", JsonRpcClient.NoRequestModel.Instance);
64+
}
65+
5566
public async Task<MoneroLikeSummary> UpdateSummary(string cryptoCode)
5667
{
5768
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)