CI test fixes (#3609)

* Test fix


Logs

* Add test logs

* Test change

* Use async overloads in CanPayWithTwoCurrencies test

* Bump NBXplorer

* More test updates

* More logs

* More waiting

* More waiting

* Update GoToUrl calls

* Log request status

* More logs

* More logs, more waits, idk

* Click checkboxes using JS

* Go to url directly

* Double timeout
This commit is contained in:
d11n
2022-04-08 11:58:01 +02:00
committed by GitHub
parent b9602243d3
commit 6bd7fb64ab
6 changed files with 92 additions and 65 deletions

View File

@@ -475,11 +475,11 @@ namespace BTCPayServer.Tests
tester.ActivateLTC();
await tester.StartAsync();
var user = tester.NewAccount();
user.GrantAccess();
await user.GrantAccessAsync();
user.RegisterDerivationScheme("BTC");
// First we try payment with a merchant having only BTC
var invoice = user.BitPay.CreateInvoice(
new Invoice()
var invoice = await user.BitPay.CreateInvoiceAsync(
new Invoice
{
Price = 5000.0m,
Currency = "USD",
@@ -490,10 +490,10 @@ namespace BTCPayServer.Tests
}, Facade.Merchant);
var cashCow = tester.ExplorerNode;
cashCow.Generate(2); // get some money in case
await cashCow.GenerateAsync(2); // get some money in case
var invoiceAddress = BitcoinAddress.Create(invoice.BitcoinAddress, cashCow.Network);
var firstPayment = Money.Coins(0.04m);
cashCow.SendToAddress(invoiceAddress, firstPayment);
await cashCow.SendToAddressAsync(invoiceAddress, firstPayment);
TestUtils.Eventually(() =>
{
invoice = user.BitPay.GetInvoice(invoice.Id);
@@ -523,8 +523,8 @@ namespace BTCPayServer.Tests
// Retry now with LTC enabled
user.RegisterDerivationScheme("LTC");
invoice = user.BitPay.CreateInvoice(
new Invoice()
invoice = await user.BitPay.CreateInvoiceAsync(
new Invoice
{
Price = 5000.0m,
Currency = "USD",
@@ -537,7 +537,7 @@ namespace BTCPayServer.Tests
cashCow = tester.ExplorerNode;
invoiceAddress = BitcoinAddress.Create(invoice.BitcoinAddress, cashCow.Network);
firstPayment = Money.Coins(0.04m);
cashCow.SendToAddress(invoiceAddress, firstPayment);
await cashCow.SendToAddressAsync(invoiceAddress, firstPayment);
TestLogs.LogInformation("First payment sent to " + invoiceAddress);
TestUtils.Eventually(() =>
{
@@ -550,8 +550,8 @@ namespace BTCPayServer.Tests
Assert.NotNull(ltcCryptoInfo);
invoiceAddress = BitcoinAddress.Create(ltcCryptoInfo.Address, cashCow.Network);
var secondPayment = Money.Coins(decimal.Parse(ltcCryptoInfo.Due, CultureInfo.InvariantCulture));
cashCow.Generate(4); // LTC is not worth a lot, so just to make sure we have money...
cashCow.SendToAddress(invoiceAddress, secondPayment);
await cashCow.GenerateAsync(4); // LTC is not worth a lot, so just to make sure we have money...
await cashCow.SendToAddressAsync(invoiceAddress, secondPayment);
TestLogs.LogInformation("Second payment sent to " + invoiceAddress);
TestUtils.Eventually(() =>
{
@@ -570,7 +570,6 @@ namespace BTCPayServer.Tests
Assert.Equal(2, checkout.AvailableCryptos.Count);
Assert.Equal("LTC", checkout.CryptoCode);
Assert.Equal(2, invoice.PaymentCodes.Count());
Assert.Equal(2, invoice.SupportedTransactionCurrencies.Count());
Assert.Equal(2, invoice.SupportedTransactionCurrencies.Count());
@@ -581,11 +580,10 @@ namespace BTCPayServer.Tests
Assert.True(invoice.SupportedTransactionCurrencies["LTC"].Enabled);
Assert.True(invoice.PaymentSubtotals.ContainsKey("LTC"));
Assert.True(invoice.PaymentTotals.ContainsKey("LTC"));
// Check if we can disable LTC
invoice = user.BitPay.CreateInvoice(
new Invoice()
invoice = await user.BitPay.CreateInvoiceAsync(
new Invoice
{
Price = 5000.0m,
Currency = "USD",

View File

@@ -11,6 +11,7 @@ using BTCPayServer.Views.Manage;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using OpenQA.Selenium;
using OpenQA.Selenium.Support.Extensions;
using Xunit;
using Xunit.Abstractions;
using StoreData = BTCPayServer.Data.StoreData;
@@ -19,7 +20,7 @@ namespace BTCPayServer.Tests
{
public class ApiKeysTests : UnitTestBase
{
public const int TestTimeout = TestUtils.TestTimeout;
public const int TestTimeout = 120_000;
public const string TestApiPath = "api/test/apikey";
public ApiKeysTests(ITestOutputHelper helper) : base(helper)
@@ -98,7 +99,7 @@ namespace BTCPayServer.Tests
var option = dropdown.FindElement(By.TagName("option"));
var storeId = option.GetAttribute("value");
option.Click();
s.Driver.FindElement(By.Id("Generate")).Click();
s.Driver.WaitForAndClick(By.Id("Generate"));
var selectiveStoreApiKey = s.FindAlertMessage().FindElement(By.TagName("code")).Text;
TestLogs.LogInformation("Checking CanModifyStoreSettings with StoreId permissions");
@@ -106,12 +107,13 @@ namespace BTCPayServer.Tests
await TestApiAgainstAccessToken(selectiveStoreApiKey, tester, user,
Permission.Create(Policies.CanModifyStoreSettings, storeId).ToString());
s.Driver.FindElement(By.Id("AddApiKey")).Click();
s.Driver.FindElement(By.Id("Generate")).Click();
TestLogs.LogInformation("Adding API key for no permissions");
s.Driver.WaitForAndClick(By.Id("AddApiKey"));
TestLogs.LogInformation("Generating API key for no permissions");
s.Driver.WaitForAndClick(By.Id("Generate"));
var noPermissionsApiKey = s.FindAlertMessage().FindElement(By.TagName("code")).Text;
TestLogs.LogInformation("Checking no permissions");
TestLogs.LogInformation($"Checking no permissions: {noPermissionsApiKey}");
await TestApiAgainstAccessToken(noPermissionsApiKey, tester, user);
await Assert.ThrowsAnyAsync<HttpRequestException>(async () =>
@@ -135,26 +137,35 @@ namespace BTCPayServer.Tests
var callbackUrl = s.ServerUri + "postredirect-callback-test";
var authUrl = BTCPayServerClient.GenerateAuthorizeUri(s.ServerUri,
new[] { Policies.CanModifyStoreSettings, Policies.CanModifyServerSettings }, applicationDetails: (appidentifier, new Uri(callbackUrl))).ToString();
s.Driver.Navigate().GoToUrl(authUrl);
TestLogs.LogInformation($"Going to auth URL {authUrl}");
s.GoToUrl(authUrl);
Assert.Contains(appidentifier, s.Driver.PageSource);
Assert.Equal("hidden", s.Driver.FindElement(By.Id("btcpay.store.canmodifystoresettings")).GetAttribute("type").ToLowerInvariant());
Assert.Equal("true", s.Driver.FindElement(By.Id("btcpay.store.canmodifystoresettings")).GetAttribute("value").ToLowerInvariant());
Assert.Equal("hidden", s.Driver.FindElement(By.Id("btcpay.server.canmodifyserversettings")).GetAttribute("type").ToLowerInvariant());
Assert.Equal("true", s.Driver.FindElement(By.Id("btcpay.server.canmodifyserversettings")).GetAttribute("value").ToLowerInvariant());
Assert.DoesNotContain("change-store-mode", s.Driver.PageSource);
s.Driver.FindElement(By.Id("consent-yes")).Click();
TestLogs.LogInformation("Going to callback URL");
s.Driver.WaitForAndClick(By.Id("consent-yes"));
Assert.Equal(callbackUrl, s.Driver.Url);
TestLogs.LogInformation("On callback URL");
var apiKeyRepo = s.Server.PayTester.GetService<APIKeyRepository>();
var accessToken = GetAccessTokenFromCallbackResult(s.Driver);
TestLogs.LogInformation($"Access token: {accessToken}");
await TestApiAgainstAccessToken(accessToken, tester, user,
(await apiKeyRepo.GetKey(accessToken)).GetBlob().Permissions);
authUrl = BTCPayServerClient.GenerateAuthorizeUri(s.ServerUri,
new[] { Policies.CanModifyStoreSettings, Policies.CanModifyServerSettings }, false, true, applicationDetails: (null, new Uri(callbackUrl))).ToString();
s.Driver.Navigate().GoToUrl(authUrl);
TestLogs.LogInformation($"Going to auth URL 2 {authUrl}");
s.GoToUrl(authUrl);
TestLogs.LogInformation("On auth URL 2");
Assert.DoesNotContain("kukksappname", s.Driver.PageSource);
Assert.Equal("checkbox", s.Driver.FindElement(By.Id("btcpay.store.canmodifystoresettings")).GetAttribute("type").ToLowerInvariant());
@@ -164,11 +175,14 @@ namespace BTCPayServer.Tests
s.Driver.SetCheckbox(By.Id("btcpay.server.canmodifyserversettings"), false);
Assert.Contains("change-store-mode", s.Driver.PageSource);
s.Driver.FindElement(By.Id("consent-yes")).Click();
TestLogs.LogInformation("Going to callback URL 2");
s.Driver.WaitForAndClick(By.Id("consent-yes"));
Assert.Equal(callbackUrl, s.Driver.Url);
TestLogs.LogInformation("On callback URL 2");
accessToken = GetAccessTokenFromCallbackResult(s.Driver);
TestLogs.LogInformation($"Access token: {accessToken}");
TestLogs.LogInformation("Checking authorized permissions");
await TestApiAgainstAccessToken(accessToken, tester, user,
@@ -179,39 +193,43 @@ namespace BTCPayServer.Tests
new[] { Policies.CanModifyStoreSettings, Policies.CanModifyServerSettings }, false, true, (appidentifier, new Uri(callbackUrl))).ToString();
//if it's the same, go to the confirm page
s.Driver.Navigate().GoToUrl(authUrl);
s.Driver.FindElement(By.Id("continue")).Click();
TestLogs.LogInformation($"Going to auth URL 3 {authUrl}");
s.GoToUrl(authUrl);
TestLogs.LogInformation("On auth URL 3");
s.Driver.WaitForAndClick(By.Id("continue"));
TestLogs.LogInformation("Going to callback URL 3");
Assert.Equal(callbackUrl, s.Driver.Url);
TestLogs.LogInformation("On callback URL 3");
//same app but different redirect = nono
authUrl = BTCPayServerClient.GenerateAuthorizeUri(s.ServerUri,
new[] { Policies.CanModifyStoreSettings, Policies.CanModifyServerSettings }, false, true, (appidentifier, new Uri("https://international.local/callback"))).ToString();
s.Driver.Navigate().GoToUrl(authUrl);
TestLogs.LogInformation($"Going to auth URL 4 {authUrl}");
s.GoToUrl(authUrl);
TestLogs.LogInformation("On auth URL 4");
Assert.False(s.Driver.Url.StartsWith("https://international.com/callback"));
// Make sure we can check all permissions when not an admin
TestLogs.LogInformation("Make sure we can check all permissions when not an admin");
await user.MakeAdmin(false);
s.Logout();
s.GoToLogin();
s.LogIn(user.RegisterDetails.Email, user.RegisterDetails.Password);
s.GoToProfile(ManageNavPages.APIKeys);
s.Driver.FindElement(By.Id("AddApiKey")).Click();
int checkedPermissionCount = 0;
foreach (var checkbox in s.Driver.FindElements(By.ClassName("form-check-input")))
{
checkedPermissionCount++;
s.Driver.ScrollTo(checkbox);
checkbox.Click();
}
TestLogs.LogInformation("Go to API Keys page");
s.GoToUrl("/account/apikeys");
TestLogs.LogInformation("On API Keys page");
s.Driver.WaitForAndClick(By.Id("AddApiKey"));
int checkedPermissionCount = s.Driver.FindElements(By.ClassName("form-check-input")).Count;
TestLogs.LogInformation($"Adding API key: {checkedPermissionCount} permissions");
s.Driver.ExecuteJavaScript("document.querySelectorAll('#Permissions .form-check-input').forEach(i => i.click())");
TestLogs.LogInformation($"Clicked {checkedPermissionCount}");
var generate = s.Driver.FindElement(By.Id("Generate"));
s.Driver.ScrollTo(generate);
generate.Click();
TestLogs.LogInformation("Generating API key");
s.Driver.WaitForAndClick(By.Id("Generate"));
var allAPIKey = s.FindAlertMessage().FindElement(By.TagName("code")).Text;
TestLogs.LogInformation("Checking API key permissions");
TestLogs.LogInformation($"Checking API key permissions: {allAPIKey}");
var apikeydata = await TestApiAgainstAccessToken<ApiKeyData>(allAPIKey, "api/v1/api-keys/current", tester.PayTester.HttpClient);
Assert.Equal(checkedPermissionCount, apikeydata.Permissions.Length);
}
@@ -223,12 +241,14 @@ namespace BTCPayServer.Tests
expectedPermissions ??= new Permission[0];
var apikeydata = await TestApiAgainstAccessToken<ApiKeyData>(accessToken, $"api/v1/api-keys/current", tester.PayTester.HttpClient);
var permissions = apikeydata.Permissions;
TestLogs.LogInformation($"TestApiAgainstAccessToken: Permissions {permissions.Length}");
Assert.Equal(expectedPermissions.Length, permissions.Length);
foreach (var expectPermission in expectedPermissions)
{
Assert.True(permissions.Any(p => p == expectPermission), $"Missing expected permission {expectPermission}");
}
TestLogs.LogInformation("Testing CanViewProfile");
if (permissions.Contains(Permission.Create(Policies.CanViewProfile)))
{
var resultUser = await TestApiAgainstAccessToken<string>(accessToken, $"{TestApiPath}/me/id", tester.PayTester.HttpClient);
@@ -241,14 +261,17 @@ namespace BTCPayServer.Tests
await TestApiAgainstAccessToken<string>(accessToken, $"{TestApiPath}/me/id", tester.PayTester.HttpClient);
});
}
//create a second user to see if any of its data gets messed upin our results.
//create a second user to see if any of its data gets messed up in our results.
TestLogs.LogInformation("Testing second user");
var secondUser = tester.NewAccount();
secondUser.GrantAccess();
await secondUser.GrantAccessAsync();
var canModifyAllStores = Permission.Create(Policies.CanModifyStoreSettings, null);
var canModifyServer = Permission.Create(Policies.CanModifyServerSettings, null);
var unrestricted = Permission.Create(Policies.Unrestricted, null);
var selectiveStorePermissions = permissions.Where(p => p.Scope != null && p.Policy == Policies.CanModifyStoreSettings);
TestLogs.LogInformation("Testing can edit store for first user");
if (permissions.Contains(canModifyAllStores) || selectiveStorePermissions.Any())
{
var resultStores =
@@ -308,7 +331,6 @@ namespace BTCPayServer.Tests
}
else if (!permissions.Contains(unrestricted))
{
await Assert.ThrowsAnyAsync<HttpRequestException>(async () =>
{
await TestApiAgainstAccessToken<bool>(accessToken,
@@ -323,6 +345,7 @@ namespace BTCPayServer.Tests
tester.PayTester.HttpClient);
}
TestLogs.LogInformation("Testing can edit store for second user");
if (!permissions.Contains(unrestricted))
{
await Assert.ThrowsAnyAsync<HttpRequestException>(async () =>
@@ -336,7 +359,9 @@ namespace BTCPayServer.Tests
await TestApiAgainstAccessToken<bool>(accessToken, $"{TestApiPath}/me/stores/{secondUser.StoreId}/can-edit",
tester.PayTester.HttpClient);
}
TestLogs.LogInformation("Testing can edit store for second user expectation met");
TestLogs.LogInformation($"Testing CanModifyServer with {permissions.Contains(canModifyServer)}");
if (permissions.Contains(canModifyServer))
{
Assert.True(await TestApiAgainstAccessToken<bool>(accessToken,
@@ -352,17 +377,21 @@ namespace BTCPayServer.Tests
tester.PayTester.HttpClient);
});
}
TestLogs.LogInformation("Testing CanModifyServer expectation met");
}
public async Task<T> TestApiAgainstAccessToken<T>(string apikey, string url, HttpClient client)
{
var httpRequest = new HttpRequestMessage(HttpMethod.Get,
new Uri(client.BaseAddress, url));
var uri = new Uri(client.BaseAddress, url);
var httpRequest = new HttpRequestMessage(HttpMethod.Get, uri);
httpRequest.Headers.Authorization = new AuthenticationHeaderValue("token", apikey);
TestLogs.LogInformation($"Testing {uri}");
var result = await client.SendAsync(httpRequest);
TestLogs.LogInformation($"Testing {uri} status: {result.StatusCode}");
result.EnsureSuccessStatusCode();
var rawJson = await result.Content.ReadAsStringAsync();
TestLogs.LogInformation($"Testing {uri} result: {rawJson}");
if (typeof(T).IsPrimitive || typeof(T) == typeof(string))
{
return (T)Convert.ChangeType(rawJson, typeof(T));

View File

@@ -458,11 +458,11 @@ namespace BTCPayServer.Tests
public void GoToProfile(ManageNavPages navPages = ManageNavPages.Index)
{
Driver.FindElement(By.Id("Nav-Account")).Click();
Driver.FindElement(By.Id("Nav-ManageAccount")).Click();
Driver.WaitForAndClick(By.Id("Nav-Account"));
Driver.WaitForAndClick(By.Id("Nav-ManageAccount"));
if (navPages != ManageNavPages.Index)
{
Driver.FindElement(By.Id($"SectionNav-{navPages.ToString()}")).Click();
Driver.WaitForAndClick(By.Id($"SectionNav-{navPages.ToString()}"));
}
}

View File

@@ -1,4 +1,4 @@
version: "3"
version: "3"
# Run `docker-compose up dev` for bootstrapping your development environment
# Doing so will expose NBXplorer, Bitcoind RPC and postgres port to the host so that tests can Run,
@@ -35,7 +35,7 @@ services:
links:
- dev
- selenium
extra_hosts:
extra_hosts:
- "tests:127.0.0.1"
volumes:
- "sshd_datadir:/root/.ssh"
@@ -43,7 +43,7 @@ services:
- "merchant_lightningd_datadir:/etc/merchant_lightningd_datadir"
# The dev container is not actually used, it is just handy to run `docker-compose up dev` to start all services
dev:
dev:
image: alpine:3.7
command: [ "/bin/sh", "-c", "trap : TERM INT; while :; do echo Ready to code and debug like a rockstar!!!; sleep 2073600; done & wait" ]
links:
@@ -69,7 +69,7 @@ services:
volumes:
- "sshd_datadir:/root/.ssh"
devlnd:
devlnd:
image: btcpayserver/bitcoin:22.0
environment:
BITCOIN_NETWORK: regtest
@@ -93,7 +93,7 @@ services:
restart: unless-stopped
ports:
- "32838:32838"
expose:
expose:
- "32838"
environment:
NBXPLORER_NETWORK: regtest
@@ -141,7 +141,7 @@ services:
zmqpubrawtx=tcp://0.0.0.0:28333
deprecatedrpc=signrawtransaction
fallbackfee=0.0002
ports:
ports:
- "43782:43782"
- "39388:39388"
expose:
@@ -156,7 +156,7 @@ services:
image: btcpayserver/lightning:v0.10.1-1-dev
stop_signal: SIGKILL
restart: unless-stopped
environment:
environment:
EXPOSE_TCP: "true"
LIGHTNINGD_CHAIN: "btc"
LIGHTNINGD_NETWORK: "regtest"
@@ -204,7 +204,7 @@ services:
merchant_lightningd:
image: btcpayserver/lightning:v0.10.1-1-dev
stop_signal: SIGKILL
environment:
environment:
EXPOSE_TCP: "true"
LIGHTNINGD_CHAIN: "btc"
LIGHTNINGD_NETWORK: "regtest"
@@ -337,7 +337,7 @@ services:
volumes:
- "./monero_wallet:/wallet"
depends_on:
- monerod
- monerod
litecoind:
restart: unless-stopped
image: btcpayserver/litecoin:0.18.1
@@ -351,12 +351,12 @@ services:
rpcbind=0.0.0.0:43782
port=39388
whitelist=0.0.0.0/0
ports:
ports:
- "43783:43782"
expose:
- "43782" # RPC
- "39388" # P2P
elementsd-liquid:
restart: always
container_name: btcpayserver_elementsd_liquid

View File

@@ -5,7 +5,7 @@
}
<div class="row">
<div class="col-xl-8 col-xxl-constrain">
<div class="col-xl-10 col-xxl-constrain">
<div class="d-flex align-items-center justify-content-between mb-3">
<h3 class="mb-0">@ViewData["Title"]</h3>
<a class="btn btn-primary" asp-action="AddApiKey" id="AddApiKey">

View File

@@ -28,10 +28,10 @@
<h3 class="mb-3">@ViewData["Title"]</h3>
<div class="row">
<div class="col-xl-8 col-xxl-constrain">
<div class="col-xl-10 col-xxl-constrain">
<p>Generate a new api key to use BTCPay through its API.</p>
<form method="post" asp-action="AddApiKey">
<form method="post" asp-action="AddApiKey" id="Permissions">
<div asp-validation-summary="All" class="text-danger"></div>
<div class="form-group">