Files
jobtrackingapp/JobTrackerApi.Tests/MicrosoftGraphProviderTests.cs
T
cesnimda e9937accd8
CI and Deploy / test (pull_request) Failing after 1m37s
CI and Deploy / deploy (pull_request) Has been skipped
feat(email): add delivery adapters
Gmail and Graph request explicit send consent and classify provider rejection separately from uncertain transport failure. IMAP remains read-only; no send API is exposed.
2026-08-09 23:47:21 +02:00

96 lines
4.1 KiB
C#

using JobTrackerApi.Services;
using JobTrackerApi.Services.EmailProviders;
using Moq;
using Xunit;
namespace JobTrackerApi.Tests;
public sealed class MicrosoftGraphProviderTests
{
[Fact]
public void ProviderKey_is_microsoft()
{
var provider = new MicrosoftGraphProvider(Mock.Of<IMicrosoftGraphOAuthService>());
Assert.Equal("microsoft", provider.ProviderKey);
}
[Fact]
public async Task GetConnectionAsync_maps_mail_address_onto_neutral_shape()
{
var graph = new Mock<IMicrosoftGraphOAuthService>();
graph.Setup(service => service.GetConnectionAsync("user-1", It.IsAny<CancellationToken>()))
.ReturnsAsync(new JobTrackerApi.Models.MicrosoftGraphConnection { OwnerUserId = "user-1", MailAddress = "user@outlook.test" });
var provider = new MicrosoftGraphProvider(graph.Object);
var connection = await provider.GetConnectionAsync("user-1", CancellationToken.None);
Assert.NotNull(connection);
Assert.Equal("microsoft", connection!.ProviderKey);
Assert.Equal("user@outlook.test", connection.Address);
Assert.False(connection.CanSend);
}
[Fact]
public async Task GetConnectionAsync_reports_send_only_after_mail_send_consent()
{
var graph = new Mock<IMicrosoftGraphOAuthService>();
graph.Setup(service => service.GetConnectionAsync("user-1", It.IsAny<CancellationToken>()))
.ReturnsAsync(new JobTrackerApi.Models.MicrosoftGraphConnection { OwnerUserId = "user-1", MailAddress = "user@outlook.test", Scope = "Mail.Read Mail.Send" });
var connection = await new MicrosoftGraphProvider(graph.Object).GetConnectionAsync("user-1", default);
Assert.True(connection!.CanSend);
}
[Fact]
public async Task GetConnectionAsync_returns_null_when_not_connected()
{
var graph = new Mock<IMicrosoftGraphOAuthService>();
graph.Setup(service => service.GetConnectionAsync("user-1", It.IsAny<CancellationToken>()))
.ReturnsAsync((JobTrackerApi.Models.MicrosoftGraphConnection?)null);
var provider = new MicrosoftGraphProvider(graph.Object);
var connection = await provider.GetConnectionAsync("user-1", CancellationToken.None);
Assert.Null(connection);
}
[Fact]
public async Task SearchAsync_maps_conversation_id_onto_neutral_thread_id()
{
var graph = new Mock<IMicrosoftGraphOAuthService>();
graph.Setup(service => service.ListMessagesAsync("user-1", "recruiter", 10, It.IsAny<CancellationToken>()))
.ReturnsAsync(new List<MicrosoftGraphMessageSummary>
{
new("msg-1", "conv-1", "Interview", "them@company.test", "me@outlook.test", DateTimeOffset.UtcNow, "snippet")
});
var provider = new MicrosoftGraphProvider(graph.Object);
var results = await provider.SearchAsync("user-1", "recruiter", 10, CancellationToken.None);
var summary = Assert.Single(results);
Assert.Equal("msg-1", summary.Id);
Assert.Equal("conv-1", summary.ThreadId);
Assert.Equal("Interview", summary.Subject);
}
[Fact]
public async Task GetMessageAsync_maps_attachment_id_onto_neutral_external_attachment_id()
{
var graph = new Mock<IMicrosoftGraphOAuthService>();
graph.Setup(service => service.GetMessageAsync("user-1", "msg-1", It.IsAny<CancellationToken>()))
.ReturnsAsync(new MicrosoftGraphMessageDetail(
"msg-1", "conv-1", "Offer", "them@company.test", "me@outlook.test", DateTimeOffset.UtcNow, "snippet",
"body text", "<p>body</p>", new List<string> { "Inbox" },
new List<MicrosoftGraphMessageAttachment> { new("resume.pdf", "application/pdf", 1024, "graph-att-1", false) }));
var provider = new MicrosoftGraphProvider(graph.Object);
var detail = await provider.GetMessageAsync("user-1", "msg-1", CancellationToken.None);
Assert.Equal("conv-1", detail.ThreadId);
var attachment = Assert.Single(detail.Attachments);
Assert.Equal("resume.pdf", attachment.FileName);
Assert.Equal("graph-att-1", attachment.ExternalAttachmentId);
}
}