using System; using System.Linq; using System.Net; using System.Net.Http; using System.Threading; using System.Threading.Tasks; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; using PolyTrader.Core.Modularity; using PolyTrader.Web.Configuration; using PolyTrader.Web.Security; using PolyTraderSharp.Models; using PolyTraderSharp.Services; using Xunit; namespace PolyTrader.Tests.WebUi { /// /// Zugangssperre, Module, Jobs und Supervisor ueber echte HTTP-Aufrufe (#568). /// Ersetzt zwei Tests, die nicht fehlschlagen konnten: einer pruefte, ob ein Array seine eigenen /// Elemente enthaelt, der andere die Portbegrenzung an einer im Test nachgebauten Lambda. /// public class ModulesAndSettingsEndpointsTests { private sealed class FakeModule : IPolyTraderModule { public FakeModule(string name) => Name = name; public string Name { get; } public string DbPrefix => "fake_"; public void RegisterServices(IServiceCollection services, IConfiguration configuration) { } public void RegisterUi(IModuleUiHost host, IServiceProvider services) { } public Task StartAsync(CancellationToken cancellationToken) => Task.CompletedTask; public Task StopAsync(CancellationToken cancellationToken) => Task.CompletedTask; } // ---- Zugangssperre --------------------------------------------------- [Fact] public async Task Api_ohne_Token_wird_abgewiesen() { await using var web = await WebUiTestHost.StartAsync(); using var res = await web.Anonymous.GetAsync("/api/modules"); Assert.Equal(HttpStatusCode.Unauthorized, res.StatusCode); } [Fact] public async Task Api_mit_falschem_Token_wird_abgewiesen() { await using var web = await WebUiTestHost.StartAsync(); using var req = new HttpRequestMessage(HttpMethod.Get, "/api/modules"); req.Headers.Add(TokenAuthMiddleware.TokenHeaderName, "falsch"); using var res = await web.Anonymous.SendAsync(req); Assert.Equal(HttpStatusCode.Unauthorized, res.StatusCode); } [Fact] public async Task Ohne_konfiguriertes_Token_ist_alles_gesperrt() { await using var web = await WebUiTestHost.StartAsync(configureOptions: o => o.AuthToken = ""); using var res = await web.Client.GetAsync("/api/modules"); Assert.Equal(HttpStatusCode.Unauthorized, res.StatusCode); } // ---- Module ---------------------------------------------------------- [Fact] public async Task Module_zeigt_alle_bekannten_und_markiert_die_geladenen() { await using var web = await WebUiTestHost.StartAsync(s => s.AddSingleton(new FakeModule("CopyTrading"))); var modules = await web.GetJsonAsync("/api/modules"); var byName = modules.EnumerateArray().ToDictionary( m => m.GetProperty("name").GetString()!, m => m.GetProperty("isActive").GetBoolean()); Assert.Equal(new[] { "Accounting", "CopyTrading", "ResolutionFarming", "Supervisor" }, byName.Keys.OrderBy(k => k).ToArray()); Assert.True(byName["CopyTrading"]); Assert.False(byName["Supervisor"]); } // ---- Jobs ------------------------------------------------------------ [Fact] public async Task Job_umschalten_aendert_den_Zustand_und_unbekannter_Job_liefert_404() { await using var web = await WebUiTestHost.StartAsync(); var row = new JobStatusRow { JobName = "Trader Analytics", IsEnabled = true }; web.Jobs.Jobs.Add(row); var (status, body) = await web.PostJsonAsync("/api/jobs/Trader%20Analytics/toggle"); Assert.Equal(200, status); Assert.False(body.GetProperty("isEnabled").GetBoolean()); Assert.False(row.IsEnabled); var (unknown, _) = await web.PostJsonAsync("/api/jobs/GibtEsNicht/toggle"); Assert.Equal(404, unknown); } // ---- Supervisor ------------------------------------------------------ [Fact] public async Task Supervisor_lehnt_leere_Frage_ab_bevor_ein_Modell_gefragt_wird() { await using var web = await WebUiTestHost.StartAsync(); var (status, _) = await web.PostJsonAsync("/api/modules/supervisor/ask", new { question = " " }); Assert.Equal(400, status); } // ---- Hilfsfunktionen, die schon echten Code pruefen ------------------ [Fact] public void Settings_GenerateSecureToken_ProducesCryptographicallyStrongString() { string token1 = WebUiConfigManager.GenerateSecureToken(); string token2 = WebUiConfigManager.GenerateSecureToken(); Assert.NotEmpty(token1); Assert.NotEqual(token1, token2); Assert.True(token1.Length >= 32); } [Fact] public void Logs_TerminalLogger_FiltersHistoryByTimeSpan() { var logger = new TerminalLogger(); logger.Info("Testnachricht 1 vor 5 Minuten"); logger.Warning("Testnachricht 2"); var recentMsgs = logger.GetHistory(TimeSpan.FromMinutes(10)).Select(h => h.Message).ToList(); Assert.Contains("Testnachricht 1 vor 5 Minuten", recentMsgs); Assert.Contains("Testnachricht 2", recentMsgs); } } }