Update local HTTPS, layout auth, deps, and add SignalR tests
- Switch FruitBankConstClient.BaseUrl to HTTPS for localhost. - Pin DevExpress.Blazor to 25.1.3 in client project. - Add Microsoft.Extensions.ObjectPool v9 to test project for SignalR. - Reformat App.razor markup; comment out ResourcePreloader. - Render @Body only if logged in or on login page in MainLayout. - Redirect to /Login if not authenticated after auto-login. - Add SandboxEndpointSimpleTests.cs for HTTP/SignalR endpoint tests against local sandbox.
This commit is contained in:
parent
0d9ced990a
commit
056a69ecc8
|
|
@ -7,7 +7,7 @@ public static class FruitBankConstClient
|
|||
{
|
||||
public static string DefaultLocale = "en-US";
|
||||
|
||||
public static string BaseUrl = "http://localhost:59579"; //FrutiBank nop
|
||||
public static string BaseUrl = "https://localhost:59579"; //FrutiBank nop
|
||||
//public static string BaseUrl = "https://shop.fruitbank.hu"; //FrutiBank nop
|
||||
#if RELEASE
|
||||
// public static string BaseUrl = "https://shop.fruitbank.hu"; //FrutiBank nop
|
||||
|
|
|
|||
|
|
@ -72,4 +72,9 @@
|
|||
<PackageReference Update="MSTest.TestFramework" Version="4.0.2" />
|
||||
</ItemGroup>
|
||||
|
||||
<!-- Ensure Microsoft.Extensions.ObjectPool v9 is available at test runtime to satisfy SignalR dependency -->
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.Extensions.ObjectPool" Version="9.0.0" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
|
|
|
|||
|
|
@ -0,0 +1,320 @@
|
|||
using AyCode.Core.Enums;
|
||||
using AyCode.Core.Loggers;
|
||||
using AyCode.Utils.Extensions;
|
||||
using FruitBank.Common;
|
||||
using FruitBank.Common.Dtos;
|
||||
using FruitBank.Common.Entities;
|
||||
using FruitBank.Common.Interfaces;
|
||||
using FruitBank.Common.Loggers;
|
||||
using FruitBankHybrid.Shared.Services.SignalRs;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using FruitBank.Common.SignalRs;
|
||||
using AyCode.Services.SignalRs;
|
||||
|
||||
namespace FruitBankHybrid.Shared.Tests;
|
||||
|
||||
/// <summary>
|
||||
/// Teszt a TestSignalREndpoint-hoz.
|
||||
/// FONTOS: A SANDBOX-ot manuálisan kell elindítani a tesztek futtatása elõtt!
|
||||
/// Indítás: dotnet run --project Mango.Sandbox.EndPoints --urls http://localhost:59579
|
||||
/// </summary>
|
||||
[TestClass]
|
||||
public class SandboxEndpointSimpleTests
|
||||
{
|
||||
private static readonly string SandboxUrl = FruitBankConstClient.BaseUrl; //"http://localhost:59579";
|
||||
private static readonly string HubUrl = $"{SandboxUrl}/fbHub";
|
||||
|
||||
// Teszt SignalR Tags (TestSignalRTags-bõl)
|
||||
private const int PingTag = SignalRTags.PingTag;
|
||||
private const int EchoTag = SignalRTags.EchoTag;
|
||||
private const int GetTestItemsTag = 9003;
|
||||
|
||||
private FruitBankSignalRClient _signalRClient = null!;
|
||||
|
||||
[TestInitialize]
|
||||
public void TestInit()
|
||||
{
|
||||
if (!SandboxUrl.Contains("localhost:")) throw new Exception("NEM LOCALHOST-ON TESZTELÜNK!");
|
||||
|
||||
_signalRClient = new FruitBankSignalRClient(new List<IAcLogWriterClientBase>
|
||||
{
|
||||
//new ConsoleLogWriter(AppType.TestUnit, LogLevel.Detail, nameof(FruitBankClientTests)),
|
||||
new SignaRClientLogItemWriter(AppType.TestUnit, LogLevel.Detail, nameof(SandboxEndpointSimpleTests))
|
||||
});
|
||||
}
|
||||
|
||||
#region HTTP Endpoint Tests
|
||||
|
||||
[TestMethod]
|
||||
public async Task HealthEndpoint_ReturnsSuccess()
|
||||
{
|
||||
using var httpClient = new HttpClient();
|
||||
var response = await httpClient.GetAsync($"{SandboxUrl}/health");
|
||||
Assert.IsTrue(response.IsSuccessStatusCode, $"Health endpoint returned {response.StatusCode}");
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public async Task RootEndpoint_ReturnsSandboxIsRunning()
|
||||
{
|
||||
using var httpClient = new HttpClient();
|
||||
var response = await httpClient.GetStringAsync(SandboxUrl);
|
||||
Assert.AreEqual("SANDBOX is running!", response);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region SignalR Connection Tests
|
||||
|
||||
[TestMethod]
|
||||
public async Task SignalR_Negotiate_ReturnsSuccess()
|
||||
{
|
||||
using var httpClient = new HttpClient();
|
||||
var response = await httpClient.PostAsync($"{HubUrl}/negotiate?negotiateVersion=1", null);
|
||||
Assert.IsTrue(response.IsSuccessStatusCode, $"SignalR negotiate returned {response.StatusCode}");
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public async Task SignalR_Connect_Succeeds()
|
||||
{
|
||||
var testItems = await _signalRClient.GetAllAsync<List<TestItem>>(GetTestItemsTag);
|
||||
Assert.IsNotNull(testItems);
|
||||
}
|
||||
|
||||
public class TestItem
|
||||
{
|
||||
public int Id { get; set; }
|
||||
public string Name { get; set; } = string.Empty;
|
||||
public decimal Value { get; set; }
|
||||
}
|
||||
|
||||
//[TestMethod]
|
||||
//public async Task SignalR_Connect_Succeeds()
|
||||
//{
|
||||
// var connection = new HubConnectionBuilder()
|
||||
// .WithUrl(HubUrl)
|
||||
// .Build();
|
||||
|
||||
// try
|
||||
// {
|
||||
// await connection.StartAsync();
|
||||
// Assert.AreEqual(HubConnectionState.Connected, connection.State);
|
||||
// }
|
||||
// finally
|
||||
// {
|
||||
// await connection.StopAsync();
|
||||
// }
|
||||
//}
|
||||
|
||||
//#endregion
|
||||
|
||||
//#region TestSignalREndpoint Tests
|
||||
|
||||
//[TestMethod]
|
||||
//public async Task SignalR_Ping_ReturnsResponse()
|
||||
//{
|
||||
// var testMessage = "Hello SignalR!";
|
||||
// await TestSignalREndpoint(PingTag, testMessage, "Ping", response =>
|
||||
// {
|
||||
// Assert.IsNotNull(response, "Response should not be null");
|
||||
|
||||
// // Parse JSON response
|
||||
// using var jsonDoc = JsonDocument.Parse(response);
|
||||
// var root = jsonDoc.RootElement;
|
||||
|
||||
// // Ellenõrizzük, hogy van Message property
|
||||
// Assert.IsTrue(root.TryGetProperty("Message", out var messageElement) ||
|
||||
// root.TryGetProperty("message", out messageElement),
|
||||
// "Response should contain 'Message' property");
|
||||
|
||||
// Console.WriteLine($"[Ping] Received message: {messageElement.GetString()}");
|
||||
// });
|
||||
//}
|
||||
|
||||
//[TestMethod]
|
||||
//public async Task SignalR_Echo_ReturnsEchoedData()
|
||||
//{
|
||||
// var request = new { Id = 42, Name = "TestName" };
|
||||
// await TestSignalREndpoint(EchoTag, request, "Echo", response =>
|
||||
// {
|
||||
// Assert.IsNotNull(response, "Response should not be null");
|
||||
|
||||
// using var jsonDoc = JsonDocument.Parse(response);
|
||||
// var root = jsonDoc.RootElement;
|
||||
|
||||
// // Ellenõrizzük az Id-t
|
||||
// Assert.IsTrue(root.TryGetProperty("Id", out var idElement) ||
|
||||
// root.TryGetProperty("id", out idElement),
|
||||
// "Response should contain 'Id' property");
|
||||
// Assert.AreEqual(42, idElement.GetInt32(), "Id should be 42");
|
||||
|
||||
// // Ellenõrizzük a Name-et
|
||||
// Assert.IsTrue(root.TryGetProperty("Name", out var nameElement) ||
|
||||
// root.TryGetProperty("name", out nameElement),
|
||||
// "Response should contain 'Name' property");
|
||||
// Assert.AreEqual("TestName", nameElement.GetString(), "Name should be 'TestName'");
|
||||
|
||||
// Console.WriteLine($"[Echo] Received: Id={idElement.GetInt32()}, Name={nameElement.GetString()}");
|
||||
// });
|
||||
//}
|
||||
|
||||
//[TestMethod]
|
||||
//public async Task SignalR_GetTestItems_ReturnsItemList()
|
||||
//{
|
||||
// await TestSignalREndpoint(GetTestItemsTag, null, "GetTestItems", response =>
|
||||
// {
|
||||
// Assert.IsNotNull(response, "Response should not be null");
|
||||
|
||||
// using var jsonDoc = JsonDocument.Parse(response);
|
||||
// var root = jsonDoc.RootElement;
|
||||
|
||||
// // Ellenõrizzük, hogy tömb-e
|
||||
// Assert.AreEqual(JsonValueKind.Array, root.ValueKind, "Response should be an array");
|
||||
// Assert.IsTrue(root.GetArrayLength() > 0, "Array should have items");
|
||||
|
||||
// Console.WriteLine($"[GetTestItems] Received {root.GetArrayLength()} items");
|
||||
|
||||
// // Ellenõrizzük az elsõ elemet
|
||||
// var firstItem = root[0];
|
||||
// Assert.IsTrue(firstItem.TryGetProperty("Id", out _) || firstItem.TryGetProperty("id", out _),
|
||||
// "Item should have 'Id' property");
|
||||
// Assert.IsTrue(firstItem.TryGetProperty("Name", out _) || firstItem.TryGetProperty("name", out _),
|
||||
// "Item should have 'Name' property");
|
||||
// });
|
||||
//}
|
||||
|
||||
//#endregion
|
||||
|
||||
//#region EREDETI BUSINESS ENDPOINT TESZTEK - KIKOMMENTEZVE
|
||||
|
||||
//// ===========================================
|
||||
//// === Az alábbi tesztek az eredeti 3 endpoint-ot tesztelik ===
|
||||
//// === Visszaállításhoz: töröld a kommenteket és regisztráld az endpoint-okat a Program.cs-ben ===
|
||||
//// ===========================================
|
||||
|
||||
//// [TestMethod]
|
||||
//// public async Task SignalR_GetMeasuringUsers_ReturnsJson()
|
||||
//// {
|
||||
//// await TestSignalREndpoint(GetMeasuringUsersTag, null, "GetMeasuringUsers");
|
||||
//// }
|
||||
|
||||
//// [TestMethod]
|
||||
//// public async Task SignalR_GetStockQuantityHistoryDtos_ReturnsJson()
|
||||
//// {
|
||||
//// await TestSignalREndpoint(GetStockQuantityHistoryDtosTag, null, "GetStockQuantityHistoryDtos");
|
||||
//// }
|
||||
|
||||
//// [TestMethod]
|
||||
//// public async Task SignalR_GetStockQuantityHistoryDtosByProductId_ReturnsJson()
|
||||
//// {
|
||||
//// // ProductId = 10
|
||||
//// await TestSignalREndpoint(GetStockQuantityHistoryDtosByProductIdTag, 10, "GetStockQuantityHistoryDtosByProductId");
|
||||
//// }
|
||||
|
||||
//// [TestMethod]
|
||||
//// public async Task SignalR_GetShippingDocumentsByShippingId_ReturnsJson()
|
||||
//// {
|
||||
//// // ShippingId = 5
|
||||
//// await TestSignalREndpoint(GetShippingDocumentsByShippingIdTag, 5, "GetShippingDocumentsByShippingId");
|
||||
//// }
|
||||
|
||||
//// [TestMethod]
|
||||
//// public async Task SignalR_GetOrderDtoById_ReturnsJson()
|
||||
//// {
|
||||
//// // OrderId = 15
|
||||
//// await TestSignalREndpoint(GetOrderDtoByIdTag, 15, "GetOrderDtoById");
|
||||
//// }
|
||||
|
||||
//// [TestMethod]
|
||||
//// public async Task SignalR_GetStockTakingItemsById_ReturnsJson()
|
||||
//// {
|
||||
//// // StockTakingItemId = 200
|
||||
//// await TestSignalREndpoint(GetStockTakingItemsByIdTag, 200, "GetStockTakingItemsById");
|
||||
//// }
|
||||
|
||||
//#endregion
|
||||
|
||||
//#region Helper Methods
|
||||
|
||||
//private async Task TestSignalREndpoint(int tag, object? parameter, string endpointName, Action<string?>? validateResponse = null)
|
||||
//{
|
||||
// var connection = new HubConnectionBuilder()
|
||||
// .WithUrl(HubUrl)
|
||||
// .Build();
|
||||
|
||||
// string? receivedJson = null;
|
||||
// int receivedTag = -1;
|
||||
// var responseReceived = new TaskCompletionSource<bool>();
|
||||
|
||||
// connection.On<int, byte[]>("ReceiveMessage", (responseTag, data) =>
|
||||
// {
|
||||
// receivedTag = responseTag;
|
||||
// if (data != null && data.Length > 0)
|
||||
// {
|
||||
// receivedJson = Encoding.UTF8.GetString(data);
|
||||
// }
|
||||
// responseReceived.TrySetResult(true);
|
||||
// });
|
||||
|
||||
// try
|
||||
// {
|
||||
// await connection.StartAsync();
|
||||
// Assert.AreEqual(HubConnectionState.Connected, connection.State, $"Failed to connect to SignalR hub for {endpointName}");
|
||||
|
||||
// // Készítsük el a request data-t
|
||||
// // Ha nincs paraméter, null-t küldünk (nem üres byte tömböt!)
|
||||
// byte[]? requestData = parameter != null
|
||||
// ? Encoding.UTF8.GetBytes(JsonSerializer.Serialize(parameter))
|
||||
// : null;
|
||||
|
||||
// // A Hub metódus neve: OnReceiveMessage (3 paraméter: messageTag, messageBytes, requestId)
|
||||
// await connection.InvokeAsync("OnReceiveMessage", tag, requestData, (int?)null);
|
||||
|
||||
// var completed = await Task.WhenAny(responseReceived.Task, Task.Delay(15000));
|
||||
|
||||
// if (completed == responseReceived.Task)
|
||||
// {
|
||||
// Console.WriteLine($"[{endpointName}] Response tag: {receivedTag}");
|
||||
// Console.WriteLine($"[{endpointName}] Response JSON: {receivedJson?.Substring(0, Math.Min(500, receivedJson?.Length ?? 0))}...");
|
||||
|
||||
// // Ellenõrizzük, hogy valid JSON-e (ha van adat)
|
||||
// if (!string.IsNullOrEmpty(receivedJson))
|
||||
// {
|
||||
// try
|
||||
// {
|
||||
// using var jsonDoc = JsonDocument.Parse(receivedJson);
|
||||
// Assert.IsTrue(
|
||||
// jsonDoc.RootElement.ValueKind == JsonValueKind.Array ||
|
||||
// jsonDoc.RootElement.ValueKind == JsonValueKind.Object ||
|
||||
// jsonDoc.RootElement.ValueKind == JsonValueKind.Null,
|
||||
// $"[{endpointName}] Response is not a valid JSON");
|
||||
|
||||
// // Custom validation
|
||||
// validateResponse?.Invoke(receivedJson);
|
||||
// }
|
||||
// catch (JsonException ex)
|
||||
// {
|
||||
// Assert.Fail($"[{endpointName}] Invalid JSON response: {ex.Message}");
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// else
|
||||
// {
|
||||
// Assert.AreEqual(HubConnectionState.Connected, connection.State,
|
||||
// $"[{endpointName}] Connection was closed - check SANDBOX logs for DI errors");
|
||||
// }
|
||||
// }
|
||||
// catch (Exception ex)
|
||||
// {
|
||||
// Assert.Fail($"[{endpointName}] SignalR error: {ex.Message}. Check SANDBOX logs for missing DI registrations.");
|
||||
// }
|
||||
// finally
|
||||
// {
|
||||
// if (connection.State == HubConnectionState.Connected)
|
||||
// {
|
||||
// await connection.StopAsync();
|
||||
// }
|
||||
// }
|
||||
//}
|
||||
|
||||
#endregion
|
||||
}
|
||||
|
|
@ -30,10 +30,12 @@
|
|||
ShowCloseButton="true">
|
||||
</DxToastProvider>
|
||||
<CascadingValue Value="RefreshMainLayoutEventCallback">
|
||||
@* @Body *@
|
||||
@if (LoggedInModel.IsLoggedIn || IsOnLoginPage)
|
||||
{
|
||||
@Body
|
||||
}
|
||||
|
||||
</CascadingValue>
|
||||
</article>
|
||||
</main>
|
||||
|
|
|
|||
|
|
@ -54,7 +54,7 @@ public partial class MainLayout : LayoutComponentBase
|
|||
if (!firstRender) return;
|
||||
|
||||
await LoggedInModel.TryAutoLoginAsync();
|
||||
|
||||
|
||||
if (!LoggedInModel.IsLoggedIn && !IsOnLoginPage)
|
||||
{
|
||||
NavManager.NavigateTo("/Login");
|
||||
|
|
@ -63,7 +63,7 @@ public partial class MainLayout : LayoutComponentBase
|
|||
{
|
||||
StateHasChanged(); // Refresh UI after successful auto-login
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private async Task SignalRClientOnMessageReceived(int messageTag, string? jsonMessage)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -13,7 +13,7 @@
|
|||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="DevExpress.Blazor" Version="25.1.*" />
|
||||
<PackageReference Include="DevExpress.Blazor" Version="25.1.3" />
|
||||
<PackageReference Include="MessagePack" Version="3.1.4" />
|
||||
<PackageReference Include="MessagePack.Annotations" Version="3.1.4" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.Components.WebAssembly" Version="10.0.0" />
|
||||
|
|
|
|||
|
|
@ -5,30 +5,30 @@
|
|||
<html lang="en">
|
||||
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<base href="/" />
|
||||
<meta charset="utf-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<base href="/" />
|
||||
|
||||
<ResourcePreloader />
|
||||
@DxResourceManager.RegisterScripts()
|
||||
@DxResourceManager.RegisterTheme(Themes.Fluent)
|
||||
@* <ResourcePreloader /> *@
|
||||
@DxResourceManager.RegisterScripts()
|
||||
@DxResourceManager.RegisterTheme(Themes.Fluent)
|
||||
|
||||
<link href=@AppendVersion("_content/FruitBankHybrid.Shared/bootstrap/bootstrap.min.css") rel="stylesheet" />
|
||||
<link href=@AppendVersion("_content/FruitBankHybrid.Shared/app.css") rel="stylesheet" />
|
||||
<link href=@AppendVersion("FruitBankHybrid.Web.styles.css") rel="stylesheet" />
|
||||
|
||||
<ImportMap />
|
||||
<link href=@AppendVersion("_content/FruitBankHybrid.Shared/favicon.png") rel="icon" type="image/png" />
|
||||
<HeadOutlet @rendermode="InteractiveWebAssembly" />
|
||||
<link href=@AppendVersion("_content/FruitBankHybrid.Shared/bootstrap/bootstrap.min.css") rel="stylesheet" />
|
||||
<link href=@AppendVersion("_content/FruitBankHybrid.Shared/app.css") rel="stylesheet" />
|
||||
<link href=@AppendVersion("FruitBankHybrid.Web.styles.css") rel="stylesheet" />
|
||||
|
||||
<ImportMap />
|
||||
<link href=@AppendVersion("_content/FruitBankHybrid.Shared/favicon.png") rel="icon" type="image/png" />
|
||||
<HeadOutlet @rendermode="InteractiveWebAssembly" />
|
||||
</head>
|
||||
|
||||
<body class="dxbl-theme-fluent">
|
||||
<Routes @rendermode="InteractiveWebAssembly" />
|
||||
<script src="@Assets["_framework/blazor.web.js"]"></script>
|
||||
<Routes @rendermode="InteractiveWebAssembly" />
|
||||
<script src="@Assets["_framework/blazor.web.js"]"></script>
|
||||
</body>
|
||||
|
||||
</html>
|
||||
|
||||
@code {
|
||||
private string AppendVersion(string path) => FileVersionProvider.AddFileVersionToPath("/", path);
|
||||
private string AppendVersion(string path) => FileVersionProvider.AddFileVersionToPath("/", path);
|
||||
}
|
||||
Loading…
Reference in New Issue