Skip to content

Commit 602f853

Browse files
authored
Merge cec557f into 57ce5be
2 parents 57ce5be + cec557f commit 602f853

9 files changed

Lines changed: 421 additions & 493 deletions

File tree

Rnwood.Smtp4dev.Tests/Server/MailboxRouterTests.cs

Lines changed: 167 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -694,5 +694,172 @@ public void FindMailboxForRecipient_SourceHeaderAndRecipient_AllMustMatch()
694694
}
695695

696696
#endregion
697+
698+
#region AuthenticatedUsers Pattern Tests
699+
700+
[Fact]
701+
public void MatchesRecipientPattern_AuthenticatedUsers_MatchesWhenUserAuthenticated()
702+
{
703+
// Test that AuthenticatedUsers pattern matches when user is authenticated
704+
// and the mailbox name matches the user's default mailbox
705+
var mailbox = new MailboxOptions { Name = "UserMailbox", Recipients = "AuthenticatedUsers" };
706+
707+
bool result = router.MatchesRecipientPattern(
708+
"anyone@example.com",
709+
"AuthenticatedUsers",
710+
authenticatedUsername: "testuser",
711+
userDefaultMailbox: "UserMailbox",
712+
mailbox: mailbox);
713+
714+
Assert.True(result);
715+
}
716+
717+
[Fact]
718+
public void MatchesRecipientPattern_AuthenticatedUsers_NoMatchWhenNotAuthenticated()
719+
{
720+
// Test that AuthenticatedUsers pattern doesn't match when user is not authenticated
721+
var mailbox = new MailboxOptions { Name = "UserMailbox", Recipients = "AuthenticatedUsers" };
722+
723+
bool result = router.MatchesRecipientPattern(
724+
"anyone@example.com",
725+
"AuthenticatedUsers",
726+
authenticatedUsername: null,
727+
userDefaultMailbox: null,
728+
mailbox: mailbox);
729+
730+
Assert.False(result);
731+
}
732+
733+
[Fact]
734+
public void MatchesRecipientPattern_AuthenticatedUsers_NoMatchWhenWrongMailbox()
735+
{
736+
// Test that AuthenticatedUsers pattern doesn't match when mailbox name
737+
// doesn't match the user's default mailbox
738+
var mailbox = new MailboxOptions { Name = "WrongMailbox", Recipients = "AuthenticatedUsers" };
739+
740+
bool result = router.MatchesRecipientPattern(
741+
"anyone@example.com",
742+
"AuthenticatedUsers",
743+
authenticatedUsername: "testuser",
744+
userDefaultMailbox: "UserMailbox",
745+
mailbox: mailbox);
746+
747+
Assert.False(result);
748+
}
749+
750+
[Fact]
751+
public void MatchesRecipientPattern_AuthenticatedUsers_CaseInsensitive()
752+
{
753+
// Test that AuthenticatedUsers pattern is case-insensitive
754+
var mailbox = new MailboxOptions { Name = "UserMailbox", Recipients = "authenticatedusers" };
755+
756+
bool result = router.MatchesRecipientPattern(
757+
"anyone@example.com",
758+
"authenticatedusers",
759+
authenticatedUsername: "testuser",
760+
userDefaultMailbox: "usermailbox",
761+
mailbox: mailbox);
762+
763+
Assert.True(result);
764+
}
765+
766+
[Fact]
767+
public void FindMailboxForRecipient_AuthenticatedUsers_BeforeDefaultMailbox()
768+
{
769+
// Test that authenticated user routing works in the mailbox order
770+
var mailboxes = new[]
771+
{
772+
new MailboxOptions { Name = "UserMailbox", Recipients = "AuthenticatedUsers" },
773+
new MailboxOptions { Name = "Default", Recipients = "*" }
774+
};
775+
776+
// Authenticated user should go to UserMailbox
777+
var result = router.FindMailboxForRecipient(
778+
"test@example.com",
779+
mailboxes,
780+
"client.example.com",
781+
"192.168.1.1",
782+
null,
783+
authenticatedUsername: "testuser",
784+
userDefaultMailbox: "UserMailbox");
785+
786+
Assert.Equal("UserMailbox", result.Name);
787+
788+
// Non-authenticated user should go to Default
789+
result = router.FindMailboxForRecipient(
790+
"test@example.com",
791+
mailboxes,
792+
"client.example.com",
793+
"192.168.1.1",
794+
null,
795+
authenticatedUsername: null,
796+
userDefaultMailbox: null);
797+
798+
Assert.Equal("Default", result.Name);
799+
}
800+
801+
[Fact]
802+
public void FindMailboxForRecipient_HeaderFilterTakesPrecedenceOverAuthenticatedUsers()
803+
{
804+
// Test that header filters are checked before AuthenticatedUsers pattern
805+
// This is the key use case from the issue
806+
var headers = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase)
807+
{
808+
{ "X-Application", "srs" }
809+
};
810+
811+
var mailboxes = new[]
812+
{
813+
new MailboxOptions
814+
{
815+
Name = "SRS",
816+
Recipients = "*",
817+
HeaderFilters = new[]
818+
{
819+
new HeaderFilterOptions { Header = "X-Application", Pattern = "srs" }
820+
}
821+
},
822+
new MailboxOptions { Name = "USOSapi", Recipients = "AuthenticatedUsers" },
823+
new MailboxOptions { Name = "Default", Recipients = "*" }
824+
};
825+
826+
// Message WITH header from authenticated user should go to SRS (header filter wins)
827+
var result = router.FindMailboxForRecipient(
828+
"test@example.com",
829+
mailboxes,
830+
"client.example.com",
831+
"192.168.1.1",
832+
headers,
833+
authenticatedUsername: "USOSapi",
834+
userDefaultMailbox: "USOSapi");
835+
836+
Assert.Equal("SRS", result.Name);
837+
838+
// Message WITHOUT header from authenticated user should go to USOSapi
839+
result = router.FindMailboxForRecipient(
840+
"test@example.com",
841+
mailboxes,
842+
"client.example.com",
843+
"192.168.1.1",
844+
new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase),
845+
authenticatedUsername: "USOSapi",
846+
userDefaultMailbox: "USOSapi");
847+
848+
Assert.Equal("USOSapi", result.Name);
849+
850+
// Message WITHOUT header from non-authenticated user should go to Default
851+
result = router.FindMailboxForRecipient(
852+
"test@example.com",
853+
mailboxes,
854+
"client.example.com",
855+
"192.168.1.1",
856+
new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase),
857+
authenticatedUsername: null,
858+
userDefaultMailbox: null);
859+
860+
Assert.Equal("Default", result.Name);
861+
}
862+
863+
#endregion
697864
}
698865
}

0 commit comments

Comments
 (0)