Files
jobtrackingapp/JobTrackerApi.Tests/GmailControllerTests.cs
T

579 lines
26 KiB
C#

using System.Security.Claims;
using JobTrackerApi.Controllers;
using JobTrackerApi.Data;
using JobTrackerApi.Models;
using JobTrackerApi.Services;
using JobTrackerApi.Tests.TestSupport;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Configuration;
using Moq;
using Xunit;
namespace JobTrackerApi.Tests;
public sealed class GmailControllerTests
{
[Fact]
public async Task Status_returns_sync_state_fields_for_connected_account()
{
await using var db = CreateDb();
var gmail = new Mock<IGmailOAuthService>();
gmail.Setup(service => service.GetConnectionAsync("user-1", It.IsAny<CancellationToken>()))
.ReturnsAsync(new GmailConnection
{
OwnerUserId = "user-1",
GmailAddress = "user@example.test",
ConnectedAt = DateTimeOffset.UtcNow.AddDays(-3),
LastSyncedAt = DateTimeOffset.UtcNow.AddMinutes(-10),
LastSyncAttemptedAt = DateTimeOffset.UtcNow.AddMinutes(-5),
LastSyncSucceededAt = DateTimeOffset.UtcNow.AddMinutes(-10),
LastSyncMode = "list-messages",
LastSyncSource = "custom-query",
LastSyncStatus = "error",
LastSyncError = "Token refresh failed"
});
var controller = CreateController(db, gmail.Object, "user-1");
var result = await controller.Status(CancellationToken.None);
var ok = Assert.IsType<OkObjectResult>(result.Result);
var payload = Assert.IsType<GmailController.GmailConnectionStatusDto>(ok.Value);
Assert.True(payload.Connected);
Assert.Equal("user@example.test", payload.GmailAddress);
Assert.Equal("list-messages", payload.LastSyncMode);
Assert.Equal("custom-query", payload.LastSyncSource);
Assert.Equal("error", payload.LastSyncStatus);
Assert.Equal("Token refresh failed", payload.LastSyncError);
}
[Fact]
public async Task Import_thread_rejects_missing_message_ids()
{
await using var db = CreateDb();
var controller = CreateController(db, Mock.Of<IGmailOAuthService>(), "user-1");
var result = await controller.ImportThread(new GmailController.ImportGmailThreadRequest(1, "thread-1", Array.Empty<string>()), CancellationToken.None);
var badRequest = Assert.IsType<BadRequestObjectResult>(result.Result);
Assert.Equal("At least one messageId is required.", badRequest.Value);
}
[Fact]
public async Task Job_candidates_rejects_invalid_job_id()
{
await using var db = CreateDb();
var gmail = new Mock<IGmailOAuthService>(MockBehavior.Strict);
var controller = CreateController(db, gmail.Object, "user-1");
var result = await controller.JobCandidates(0, null, 6, CancellationToken.None);
var badRequest = Assert.IsType<BadRequestObjectResult>(result.Result);
Assert.Equal("Valid jobApplicationId is required.", badRequest.Value);
gmail.Verify(service => service.ListJobCandidateMessagesAsync(It.IsAny<string>(), It.IsAny<IEnumerable<string>>(), It.IsAny<int>(), It.IsAny<CancellationToken>()), Times.Never);
}
[Fact]
public async Task Job_candidates_returns_ranked_threads_with_match_reasons_query_hits_and_import_flags()
{
await using var db = CreateDb();
var company = new Company
{
Name = "Acme",
RecruiterName = "Maria Recruiter",
RecruiterEmail = "maria@acme.test",
OwnerUserId = "user-1"
};
db.Companies.Add(company);
await db.SaveChangesAsync();
var job = new JobApplication
{
JobTitle = "Backend Developer",
CompanyId = company.Id,
OwnerUserId = "user-1"
};
db.JobApplications.Add(job);
await db.SaveChangesAsync();
db.Correspondences.Add(new Correspondence
{
JobApplicationId = job.Id,
From = "Company",
Subject = "Backend Developer interview",
ExternalMessageId = "msg-imported",
ExternalThreadId = "thread-top",
Content = "Earlier imported thread"
});
await db.SaveChangesAsync();
var overrideQuery = "label:important";
var gmail = new Mock<IGmailOAuthService>();
gmail.Setup(service => service.ListJobCandidateMessagesAsync("user-1", It.IsAny<IEnumerable<string>>(), 6, It.IsAny<CancellationToken>()))
.ReturnsAsync(new[]
{
new GmailQueryMatchedMessage(
new GmailMessageSummary(
"msg-top",
"thread-top",
"Backend Developer interview",
"Maria Recruiter <maria@acme.test>",
"user@example.test",
DateTimeOffset.UtcNow.AddDays(-2),
"Acme wants to schedule a backend developer interview."),
new[]
{
overrideQuery,
"\"Acme\" \"Backend Developer\" newer_than:365d"
}),
new GmailQueryMatchedMessage(
new GmailMessageSummary(
"msg-imported",
"thread-top",
"Backend Developer interview",
"Maria Recruiter <maria@acme.test>",
"user@example.test",
DateTimeOffset.UtcNow.AddDays(-4),
"Already imported message."),
new[]
{
"(from:maria@acme.test OR to:maria@acme.test) newer_than:365d"
}),
new GmailQueryMatchedMessage(
new GmailMessageSummary(
"msg-low",
"thread-low",
"Backend update",
"alerts@example.test",
"user@example.test",
DateTimeOffset.UtcNow.AddDays(-90),
"A generic backend role update without recruiter context."),
new[]
{
"subject:\"Backend Developer\" newer_than:365d"
})
});
var controller = CreateController(db, gmail.Object, "user-1");
var result = await controller.JobCandidates(job.Id, overrideQuery, 6, CancellationToken.None);
var ok = Assert.IsType<OkObjectResult>(result.Result);
var payload = Assert.IsType<GmailController.GmailJobMatchesResponseDto>(ok.Value);
Assert.Equal(job.Id, payload.JobApplicationId);
Assert.Contains(overrideQuery, payload.Queries);
Assert.Equal(3, payload.CandidateMessageCount);
Assert.Equal(2, payload.CandidateThreadCount);
Assert.Equal(2, payload.Threads.Count);
var topThread = payload.Threads[0];
Assert.Equal("thread-top", topThread.ThreadId);
Assert.Equal("high", topThread.Confidence);
Assert.True(topThread.HasImportedMessages);
Assert.Equal(1, topThread.ImportedMessageCount);
Assert.Equal(2, topThread.MessageCount);
Assert.Contains(overrideQuery, topThread.MatchedQueries);
Assert.Contains(topThread.MatchReasons, reason => reason.Label == "company" && reason.Value == "Acme" && reason.Points == 18);
Assert.Contains(topThread.MatchReasons, reason => reason.Label == "recruiterEmail" && reason.Value == "maria@acme.test" && reason.Points == 20);
Assert.Contains(topThread.MatchReasons, reason => reason.Label == "queryHits" && reason.Value == "2" && reason.Points == 8);
var importedMessage = Assert.Single(topThread.Messages, message => message.Id == "msg-imported");
Assert.True(importedMessage.AlreadyImported);
Assert.Contains(importedMessage.MatchReasons, reason => reason.Label == "status" && reason.Value == "already-imported" && reason.Points == 0);
var freshMessage = Assert.Single(topThread.Messages, message => message.Id == "msg-top");
Assert.False(freshMessage.AlreadyImported);
Assert.Contains(overrideQuery, freshMessage.MatchedQueries);
Assert.Contains(freshMessage.MatchReasons, reason => reason.Label == "status" && reason.Value == "thread-already-imported" && reason.Points == 0);
var lowThread = payload.Threads[1];
Assert.Equal("thread-low", lowThread.ThreadId);
Assert.Equal("low", lowThread.Confidence);
}
[Fact]
public async Task Job_candidates_returns_empty_threads_when_gmail_has_no_matches()
{
await using var db = CreateDb();
var company = new Company
{
Name = "Acme",
OwnerUserId = "user-1"
};
db.Companies.Add(company);
await db.SaveChangesAsync();
var job = new JobApplication
{
JobTitle = "Backend Developer",
CompanyId = company.Id,
OwnerUserId = "user-1"
};
db.JobApplications.Add(job);
await db.SaveChangesAsync();
var gmail = new Mock<IGmailOAuthService>();
gmail.Setup(service => service.ListJobCandidateMessagesAsync("user-1", It.IsAny<IEnumerable<string>>(), 6, It.IsAny<CancellationToken>()))
.ReturnsAsync(Array.Empty<GmailQueryMatchedMessage>());
var controller = CreateController(db, gmail.Object, "user-1");
var result = await controller.JobCandidates(job.Id, null, 6, CancellationToken.None);
var ok = Assert.IsType<OkObjectResult>(result.Result);
var payload = Assert.IsType<GmailController.GmailJobMatchesResponseDto>(ok.Value);
Assert.NotEmpty(payload.Queries);
Assert.Equal(0, payload.CandidateMessageCount);
Assert.Equal(0, payload.CandidateThreadCount);
Assert.Empty(payload.Threads);
}
[Fact]
public async Task Import_returns_message_metadata_and_skips_repeat_message_imports()
{
await using var db = CreateDb();
var company = new Company { Name = "Acme", OwnerUserId = "user-1" };
db.Companies.Add(company);
await db.SaveChangesAsync();
var job = new JobApplication
{
JobTitle = "Backend Developer",
CompanyId = company.Id,
OwnerUserId = "user-1"
};
db.JobApplications.Add(job);
await db.SaveChangesAsync();
var gmail = new Mock<IGmailOAuthService>();
gmail.Setup(service => service.GetConnectionAsync("user-1", It.IsAny<CancellationToken>()))
.ReturnsAsync(new GmailConnection { OwnerUserId = "user-1", GmailAddress = "user@example.test", EncryptedRefreshToken = "ignored", Scope = "scope", ConnectedAt = DateTimeOffset.UtcNow });
gmail.Setup(service => service.GetMessageAsync("user-1", "msg-1", It.IsAny<CancellationToken>()))
.ReturnsAsync(new GmailMessageDetail(
"msg-1",
"thread-1",
"Interview update",
"Maria Recruiter <maria@acme.test>",
"user@example.test",
DateTimeOffset.UtcNow.AddDays(-1),
"Snippet",
"Body text",
null,
new[] { "INBOX", "IMPORTANT" },
new[] { new GmailMessageAttachment("cv.pdf", "application/pdf", 2048, "att-1", false) }));
var controller = CreateController(db, gmail.Object, "user-1");
var first = await controller.Import(new GmailController.ImportGmailMessageRequest(job.Id, "msg-1"), CancellationToken.None);
var firstOk = Assert.IsType<OkObjectResult>(first.Result);
var firstPayload = Assert.IsType<GmailController.GmailImportMessageResultDto>(firstOk.Value);
Assert.Equal(1, firstPayload.Imported);
Assert.Equal(0, firstPayload.Skipped);
Assert.Equal("thread-1", firstPayload.ThreadId);
Assert.NotNull(firstPayload.Message);
Assert.Equal("thread-1", firstPayload.Message!.ExternalThreadId);
Assert.Equal("Maria Recruiter <maria@acme.test>", firstPayload.Message.ExternalFrom);
Assert.Equal("user@example.test", firstPayload.Message.ExternalTo);
Assert.Equal("inbound", firstPayload.Message.Direction);
Assert.Contains("IMPORTANT", firstPayload.Message.ExternalLabels);
Assert.Single(firstPayload.Message.AttachmentMetadata);
Assert.Equal("cv.pdf", firstPayload.Message.AttachmentMetadata[0].FileName);
var second = await controller.Import(new GmailController.ImportGmailMessageRequest(job.Id, "msg-1"), CancellationToken.None);
var secondOk = Assert.IsType<OkObjectResult>(second.Result);
var secondPayload = Assert.IsType<GmailController.GmailImportMessageResultDto>(secondOk.Value);
Assert.Equal(0, secondPayload.Imported);
Assert.Equal(1, secondPayload.Skipped);
Assert.Equal("thread-1", secondPayload.ThreadId);
var storedMessages = await db.Correspondences.Where(message => message.JobApplicationId == job.Id).ToListAsync();
Assert.Single(storedMessages);
gmail.Verify(service => service.GetMessageAsync("user-1", "msg-1", It.IsAny<CancellationToken>()), Times.Once);
}
[Fact]
public async Task Import_thread_reports_imported_and_skipped_counts_for_repeat_calls()
{
await using var db = CreateDb();
var company = new Company { Name = "Acme", OwnerUserId = "user-1" };
db.Companies.Add(company);
await db.SaveChangesAsync();
var job = new JobApplication
{
JobTitle = "Backend Developer",
CompanyId = company.Id,
OwnerUserId = "user-1"
};
db.JobApplications.Add(job);
await db.SaveChangesAsync();
var gmail = new Mock<IGmailOAuthService>();
gmail.Setup(service => service.GetConnectionAsync("user-1", It.IsAny<CancellationToken>()))
.ReturnsAsync(new GmailConnection { OwnerUserId = "user-1", GmailAddress = "user@example.test", EncryptedRefreshToken = "ignored", Scope = "scope", ConnectedAt = DateTimeOffset.UtcNow });
gmail.Setup(service => service.GetMessageAsync("user-1", "msg-1", It.IsAny<CancellationToken>()))
.ReturnsAsync(new GmailMessageDetail(
"msg-1",
"thread-1",
"Interview update",
"Maria Recruiter <maria@acme.test>",
"user@example.test",
DateTimeOffset.UtcNow.AddDays(-1),
"Snippet 1",
"Body text 1",
null,
Array.Empty<string>(),
Array.Empty<GmailMessageAttachment>()));
gmail.Setup(service => service.GetMessageAsync("user-1", "msg-2", It.IsAny<CancellationToken>()))
.ReturnsAsync(new GmailMessageDetail(
"msg-2",
"thread-1",
"Interview follow-up",
"user@example.test",
"Maria Recruiter <maria@acme.test>",
DateTimeOffset.UtcNow,
"Snippet 2",
"Body text 2",
null,
Array.Empty<string>(),
Array.Empty<GmailMessageAttachment>()));
var controller = CreateController(db, gmail.Object, "user-1");
var request = new GmailController.ImportGmailThreadRequest(job.Id, "thread-1", new[] { "msg-1", "msg-2" });
var first = await controller.ImportThread(request, CancellationToken.None);
var firstOk = Assert.IsType<OkObjectResult>(first.Result);
var firstPayload = Assert.IsType<GmailController.GmailImportResultDto>(firstOk.Value);
Assert.Equal(2, firstPayload.Imported);
Assert.Equal(0, firstPayload.Skipped);
Assert.Equal("thread-1", firstPayload.ThreadId);
var second = await controller.ImportThread(request, CancellationToken.None);
var secondOk = Assert.IsType<OkObjectResult>(second.Result);
var secondPayload = Assert.IsType<GmailController.GmailImportResultDto>(secondOk.Value);
Assert.Equal(0, secondPayload.Imported);
Assert.Equal(2, secondPayload.Skipped);
var storedMessages = await db.Correspondences.Where(message => message.JobApplicationId == job.Id).OrderBy(message => message.ExternalMessageId).ToListAsync();
Assert.Equal(2, storedMessages.Count);
Assert.All(storedMessages, message => Assert.Equal("thread-1", message.ExternalThreadId));
}
[Fact]
public async Task Refresh_linked_threads_imports_new_messages_for_known_thread_ids()
{
await using var db = CreateDb();
var company = new Company { Name = "Acme", OwnerUserId = "user-1" };
db.Companies.Add(company);
await db.SaveChangesAsync();
var job = new JobApplication
{
JobTitle = "Backend Developer",
CompanyId = company.Id,
OwnerUserId = "user-1"
};
db.JobApplications.Add(job);
await db.SaveChangesAsync();
db.Correspondences.Add(new Correspondence
{
JobApplicationId = job.Id,
From = "Company",
Subject = "Initial recruiter note",
ExternalMessageId = "msg-1",
ExternalThreadId = "thread-1",
ExternalFrom = "Maria Recruiter <maria@acme.test>",
ExternalTo = "user@example.test",
Content = "Existing import"
});
await db.SaveChangesAsync();
var gmail = new Mock<IGmailOAuthService>();
gmail.Setup(service => service.GetConnectionAsync("user-1", It.IsAny<CancellationToken>()))
.ReturnsAsync(new GmailConnection { OwnerUserId = "user-1", GmailAddress = "user@example.test", EncryptedRefreshToken = "ignored", Scope = "scope", ConnectedAt = DateTimeOffset.UtcNow });
gmail.Setup(service => service.ListThreadMessagesAsync("user-1", "thread-1", It.IsAny<CancellationToken>()))
.ReturnsAsync(new[]
{
new GmailMessageSummary("msg-1", "thread-1", "Initial recruiter note", "Maria Recruiter <maria@acme.test>", "user@example.test", DateTimeOffset.UtcNow.AddDays(-2), "Old message"),
new GmailMessageSummary("msg-2", "thread-1", "Follow-up reply", "user@example.test", "Maria Recruiter <maria@acme.test>", DateTimeOffset.UtcNow, "New reply")
});
gmail.Setup(service => service.GetMessageAsync("user-1", "msg-2", It.IsAny<CancellationToken>()))
.ReturnsAsync(new GmailMessageDetail(
"msg-2",
"thread-1",
"Follow-up reply",
"user@example.test",
"Maria Recruiter <maria@acme.test>",
DateTimeOffset.UtcNow,
"New reply",
"Reply body",
null,
Array.Empty<string>(),
Array.Empty<GmailMessageAttachment>()));
var controller = CreateController(db, gmail.Object, "user-1");
var result = await controller.RefreshLinkedThreads(new GmailController.RefreshLinkedThreadsRequest(job.Id), CancellationToken.None);
var ok = Assert.IsType<OkObjectResult>(result.Result);
var payload = Assert.IsType<GmailController.GmailThreadRefreshResultDto>(ok.Value);
Assert.Equal(job.Id, payload.JobApplicationId);
Assert.Equal(1, payload.ThreadsChecked);
Assert.Equal(1, payload.Imported);
Assert.Equal(1, payload.Skipped);
Assert.True(payload.HasLinkedThreads);
var thread = Assert.Single(payload.Threads);
Assert.Equal("thread-1", thread.ThreadId);
Assert.Equal("imported-new-messages", thread.Status);
Assert.Equal(2, thread.TotalMessages);
var stored = await db.Correspondences.Where(message => message.JobApplicationId == job.Id).OrderBy(message => message.ExternalMessageId).ToListAsync();
Assert.Equal(2, stored.Count);
Assert.Equal("msg-2", stored[1].ExternalMessageId);
Assert.Equal("thread-1", stored[1].ExternalThreadId);
}
[Fact]
public async Task Refresh_linked_threads_reports_empty_and_disconnected_states()
{
await using var db = CreateDb();
var company = new Company { Name = "Acme", OwnerUserId = "user-1" };
db.Companies.Add(company);
await db.SaveChangesAsync();
var linkedJob = new JobApplication { JobTitle = "Backend Developer", CompanyId = company.Id, OwnerUserId = "user-1" };
var emptyJob = new JobApplication { JobTitle = "Backend Developer II", CompanyId = company.Id, OwnerUserId = "user-1" };
db.JobApplications.AddRange(linkedJob, emptyJob);
await db.SaveChangesAsync();
db.Correspondences.Add(new Correspondence
{
JobApplicationId = linkedJob.Id,
From = "Company",
Subject = "Initial recruiter note",
ExternalMessageId = "msg-1",
ExternalThreadId = "thread-1",
Content = "Existing import"
});
await db.SaveChangesAsync();
var disconnectedGmail = new Mock<IGmailOAuthService>(MockBehavior.Strict);
disconnectedGmail.Setup(service => service.GetConnectionAsync("user-1", It.IsAny<CancellationToken>())).ReturnsAsync((GmailConnection?)null);
var disconnectedController = CreateController(db, disconnectedGmail.Object, "user-1");
var disconnectedResult = await disconnectedController.RefreshLinkedThreads(new GmailController.RefreshLinkedThreadsRequest(linkedJob.Id), CancellationToken.None);
var conflict = Assert.IsType<ConflictObjectResult>(disconnectedResult.Result);
Assert.Equal("Connect Gmail before refreshing linked threads.", conflict.Value);
var gmail = new Mock<IGmailOAuthService>();
gmail.Setup(service => service.GetConnectionAsync("user-1", It.IsAny<CancellationToken>()))
.ReturnsAsync(new GmailConnection { OwnerUserId = "user-1", GmailAddress = "user@example.test", EncryptedRefreshToken = "ignored", Scope = "scope", ConnectedAt = DateTimeOffset.UtcNow });
var controller = CreateController(db, gmail.Object, "user-1");
var emptyResult = await controller.RefreshLinkedThreads(new GmailController.RefreshLinkedThreadsRequest(emptyJob.Id), CancellationToken.None);
var ok = Assert.IsType<OkObjectResult>(emptyResult.Result);
var payload = Assert.IsType<GmailController.GmailThreadRefreshResultDto>(ok.Value);
Assert.Equal(0, payload.ThreadsChecked);
Assert.Equal(0, payload.Imported);
Assert.Equal(0, payload.Skipped);
Assert.False(payload.HasLinkedThreads);
Assert.Empty(payload.Threads);
gmail.Verify(service => service.ListThreadMessagesAsync(It.IsAny<string>(), It.IsAny<string>(), It.IsAny<CancellationToken>()), Times.Never);
}
[Fact]
public async Task Refresh_linked_threads_rejects_invalid_job_id()
{
await using var db = CreateDb();
var gmail = new Mock<IGmailOAuthService>(MockBehavior.Strict);
var controller = CreateController(db, gmail.Object, "user-1");
var result = await controller.RefreshLinkedThreads(new GmailController.RefreshLinkedThreadsRequest(0), CancellationToken.None);
var badRequest = Assert.IsType<BadRequestObjectResult>(result.Result);
Assert.Equal("Valid jobApplicationId is required.", badRequest.Value);
}
[Fact]
public async Task Refresh_linked_threads_respects_owned_job_scope()
{
await using var db = CreateDb();
var company = new Company { Name = "OtherCo", OwnerUserId = "user-2" };
db.Companies.Add(company);
await db.SaveChangesAsync();
var foreignJob = new JobApplication
{
JobTitle = "Hidden job",
CompanyId = company.Id,
OwnerUserId = "user-2"
};
db.JobApplications.Add(foreignJob);
await db.SaveChangesAsync();
var gmail = new Mock<IGmailOAuthService>(MockBehavior.Strict);
var controller = CreateController(db, gmail.Object, "user-1");
var result = await controller.RefreshLinkedThreads(new GmailController.RefreshLinkedThreadsRequest(foreignJob.Id), CancellationToken.None);
var notFound = Assert.IsType<NotFoundObjectResult>(result.Result);
Assert.Equal("Job application not found.", notFound.Value);
gmail.Verify(service => service.GetConnectionAsync(It.IsAny<string>(), It.IsAny<CancellationToken>()), Times.Never);
}
[Fact]
public async Task Job_candidates_respects_owned_job_scope()
{
await using var db = CreateDb();
var company = new Company { Name = "OtherCo", OwnerUserId = "user-2" };
db.Companies.Add(company);
await db.SaveChangesAsync();
var foreignJob = new JobApplication
{
JobTitle = "Hidden job",
CompanyId = company.Id,
OwnerUserId = "user-2"
};
db.JobApplications.Add(foreignJob);
await db.SaveChangesAsync();
var gmail = new Mock<IGmailOAuthService>(MockBehavior.Strict);
var controller = CreateController(db, gmail.Object, "user-1");
var result = await controller.JobCandidates(foreignJob.Id, null, 6, CancellationToken.None);
var notFound = Assert.IsType<NotFoundObjectResult>(result.Result);
Assert.Equal("Job application not found.", notFound.Value);
gmail.Verify(service => service.ListJobCandidateMessagesAsync(It.IsAny<string>(), It.IsAny<IEnumerable<string>>(), It.IsAny<int>(), It.IsAny<CancellationToken>()), Times.Never);
}
private static GmailController CreateController(JobTrackerContext db, IGmailOAuthService gmail, string userId)
{
var controller = new GmailController(gmail, new GmailJobMatchingService(), db, BuildConfig())
{
ControllerContext = new ControllerContext
{
HttpContext = new DefaultHttpContext
{
User = new ClaimsPrincipal(new ClaimsIdentity(new[]
{
new Claim(ClaimTypes.NameIdentifier, userId)
}, "test"))
}
}
};
return controller;
}
private static JobTrackerContext CreateDb()
{
return TestHostFactory.CreateInMemoryDb();
}
private static Microsoft.Extensions.Configuration.IConfiguration BuildConfig()
{
return new Microsoft.Extensions.Configuration.ConfigurationBuilder()
.AddInMemoryCollection(new Dictionary<string, string?>())
.Build();
}
}