using Microsoft.Extensions.Logging.Abstractions; using SameBeat.Application.Interfejsy; using SameBeat.Application.Komendy; using SameBeat.Application.Serwisy; using SameBeat.Domain.Encje; using SameBeat.Domain.Enumy; using SameBeat.Infrastructure.Autoryzacja; using Xunit; namespace SameBeat.Tests.Unit; /// /// Poczatek lancucha bezpieczenstwa "poczekalnia -> scena": POST /api/join musi zwrocic sekret /// sesji JAWNY (raz), a w bazie ma zostac wylacznie jego hash -- ten hash pozniej weryfikuje /// SerwisSceny (patrz SerwisScenyTests) przy statusie i wydawaniu tokenu sceny. /// public class SerwisPoczekalniTests { private sealed class FejkRepozytoriumWydarzen : IRepozytoriumWydarzen { private readonly List _wydarzenia = new(); public Task PobierzOstatnieAsync(CancellationToken token = default) => Task.FromResult(_wydarzenia.LastOrDefault()); public Task ZnajdzPoIdAsync(Guid id, CancellationToken token = default) => Task.FromResult(_wydarzenia.SingleOrDefault(w => w.Id == id)); public void Dodaj(Wydarzenie wydarzenie) => _wydarzenia.Add(wydarzenie); } private sealed class FejkRepozytoriumPoczekalni : IRepozytoriumPoczekalni { public readonly List Uczestnicy = new(); public Task ZnajdzPoIdAsync(Guid id, CancellationToken token = default) => Task.FromResult(Uczestnicy.SingleOrDefault(u => u.Id == id)); public Task> PobierzOczekujacychDlaWydarzeniaAsync(Guid wydarzenieId, CancellationToken token = default) => Task.FromResult(Uczestnicy.Where(u => u.WydarzenieId == wydarzenieId).ToList()); public void Dodaj(UczestnikOczekujacy uczestnik) => Uczestnicy.Add(uczestnik); } private sealed class FejkJednostkaPracy : IJednostkaPracy { public Task ZapiszZmianyAsync(CancellationToken token = default) => Task.FromResult(0); } private sealed class FejkSerwisTokenowLiveKit : ISerwisTokenowLiveKit { public string WygenerujToken(string identity, string nazwaWyswietlana, RolaUzytkownika rola, string nazwaPokoju) => "token-testowy"; } private const string PokojPoczekalnia = "impreza-poczekalnia"; private const string UrlLiveKit = "wss://przyklad.livekit.cloud"; private readonly FejkRepozytoriumWydarzen _repozytoriumWydarzen = new(); private readonly FejkRepozytoriumPoczekalni _repozytoriumPoczekalni = new(); private readonly IUslugaHaszowaniaSekretowSesji _uslugaHaszowaniaSekretowSesji = new UslugaHaszowaniaSekretowSesji(); private readonly SerwisPoczekalni _serwis; public SerwisPoczekalniTests() { _serwis = new SerwisPoczekalni( _repozytoriumWydarzen, _repozytoriumPoczekalni, new FejkSerwisTokenowLiveKit(), _uslugaHaszowaniaSekretowSesji, new FejkJednostkaPracy(), UrlLiveKit, PokojPoczekalnia, NullLogger.Instance); _repozytoriumWydarzen.Dodaj(Wydarzenie.Utworz("Testowa impreza")); } [Fact] public async Task DolaczAsync_ZwracaJawnySekretIZapisujeWylacznieJegoHash() { var wynik = await _serwis.DolaczAsync(new DolaczKomenda("Piotr")); Assert.True(wynik.Sukces); var sekretJawny = wynik.Dane!.SekretSesji; Assert.False(string.IsNullOrWhiteSpace(sekretJawny)); var uczestnik = _repozytoriumPoczekalni.Uczestnicy.Single(); // W bazie nie ma jawnego sekretu -- tylko hash, i to nie jest ten sam string co sekret. Assert.NotNull(uczestnik.SekretSesjiHash); Assert.NotEqual(sekretJawny, uczestnik.SekretSesjiHash); // Ale jawny sekret zwrocony w odpowiedzi faktycznie pasuje do zapisanego hasha. var wynikWeryfikacji = _uslugaHaszowaniaSekretowSesji.Weryfikuj(uczestnik, uczestnik.SekretSesjiHash!, sekretJawny); Assert.Equal(WynikWeryfikacjiHasla.Poprawne, wynikWeryfikacji); } [Fact] public async Task DolaczAsync_KazdeDolaczenieDostajeInnySekret() { var pierwszy = await _serwis.DolaczAsync(new DolaczKomenda("Ala")); var drugi = await _serwis.DolaczAsync(new DolaczKomenda("Bartek")); Assert.NotEqual(pierwszy.Dane!.SekretSesji, drugi.Dane!.SekretSesji); } }