using System.Net; using System.Text.Json; using Microsoft.Extensions.Options; using ROLAC.API.Services.Notifications; using Xunit; namespace ROLAC.API.Tests.Services.Notifications; public class LineMessageChannelTests { // Captures the outgoing request and returns a canned response. private sealed class CapturingHandler : HttpMessageHandler { public HttpRequestMessage? LastRequest { get; private set; } public string? LastBody { get; private set; } public HttpStatusCode StatusCode { get; set; } = HttpStatusCode.OK; public string ResponseBody { get; set; } = "{}"; protected override async Task SendAsync( HttpRequestMessage request, CancellationToken cancellationToken) { LastRequest = request; LastBody = request.Content is null ? null : await request.Content.ReadAsStringAsync(cancellationToken); return new HttpResponseMessage(StatusCode) { Content = new StringContent(ResponseBody) }; } } private static LineMessageChannel BuildChannel(CapturingHandler handler) { var http = new HttpClient(handler); var options = Options.Create(new LineOptions { ChannelAccessToken = "tok", ChannelSecret = "sec" }); return new LineMessageChannel(http, options); } [Fact] public async Task PushToUserAsync_PostsTextMessage_WithBearerToken() { var handler = new CapturingHandler(); var channel = BuildChannel(handler); var result = await channel.PushToUserAsync("U123", "hello"); Assert.True(result.Success); Assert.Equal("https://api.line.me/v2/bot/message/push", handler.LastRequest!.RequestUri!.ToString()); Assert.Equal("Bearer", handler.LastRequest.Headers.Authorization!.Scheme); Assert.Equal("tok", handler.LastRequest.Headers.Authorization.Parameter); using var doc = JsonDocument.Parse(handler.LastBody!); Assert.Equal("U123", doc.RootElement.GetProperty("to").GetString()); Assert.Equal("hello", doc.RootElement.GetProperty("messages")[0].GetProperty("text").GetString()); } [Fact] public async Task ReplyAsync_PostsToReplyEndpoint_WithReplyToken() { var handler = new CapturingHandler(); var channel = BuildChannel(handler); await channel.ReplyAsync("RTOKEN", "hi back"); Assert.Equal("https://api.line.me/v2/bot/message/reply", handler.LastRequest!.RequestUri!.ToString()); using var doc = JsonDocument.Parse(handler.LastBody!); Assert.Equal("RTOKEN", doc.RootElement.GetProperty("replyToken").GetString()); } [Fact] public async Task PushToUserAsync_ReturnsFailure_OnNonSuccessStatus() { var handler = new CapturingHandler { StatusCode = HttpStatusCode.TooManyRequests, ResponseBody = "quota" }; var channel = BuildChannel(handler); var result = await channel.PushToUserAsync("U123", "hello"); Assert.False(result.Success); Assert.Contains("429", result.Error); } }