using System.Net; using System.Text; using Xunit; using ytLive.Models; using ytLive.Services; namespace ytLive.Tests; /// /// The one integration test for ship step 7 (private-only go live): the /// broadcast-insert request must carry privacyStatus "private" — the dialog is /// locked to Private and the service must never send anything else. /// public class YouTubeStreamServiceTests { private sealed class RecordingHandler : HttpMessageHandler { public string? LastBody; public string ResponseBody = """{"id":"BC123","snippet":{"title":"t"}}"""; protected override Task SendAsync( HttpRequestMessage request, CancellationToken cancellationToken) { LastBody = request.Content?.ReadAsStringAsync().GetAwaiter().GetResult(); return Task.FromResult(new HttpResponseMessage(HttpStatusCode.OK) { Content = new StringContent(ResponseBody, Encoding.UTF8, "application/json"), }); } } private static YouTubeAuthService CreateAuth() => new("test-id", "test-secret"); [Fact] public async Task CreateBroadcast_Always_Sends_Private_PrivacyStatus() { var handler = new RecordingHandler(); var auth = CreateAuth(); auth.SetSession(new YouTubeChannel { AccessToken = "acc-123", TokenExpiry = DateTime.UtcNow.AddHours(1), }); var service = new YouTubeStreamService(auth, new HttpClient(handler)); var id = await service.CreateBroadcast("Test Stream", "A description", DateTime.UtcNow); Assert.Equal("BC123", id); Assert.NotNull(handler.LastBody); Assert.Contains("\"privacyStatus\":\"private\"", handler.LastBody); } [Fact] public async Task CreateBroadcast_Without_Session_Returns_Null() { var handler = new RecordingHandler(); var auth = CreateAuth(); // no session var service = new YouTubeStreamService(auth, new HttpClient(handler)); var id = await service.CreateBroadcast("Test Stream", "A description", DateTime.UtcNow); Assert.Null(id); Assert.Null(handler.LastBody); // never reached the API } }