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);
}
}
}