Skip to content

Commit

Permalink
Added more unit tests for IMAP's NOTIFY feature
Browse files Browse the repository at this point in the history
  • Loading branch information
jstedfast committed Sep 14, 2023
1 parent f1c5f83 commit 91d7cd2
Show file tree
Hide file tree
Showing 2 changed files with 241 additions and 89 deletions.
127 changes: 38 additions & 89 deletions UnitTests/Net/Imap/ImapClientTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -208,13 +208,8 @@ public void TestArgumentExceptions ()
Assert.ThrowsAsync<ArgumentNullException> (async () => await client.NotifyAsync (true, null));
Assert.Throws<ArgumentException> (() => client.Notify (true, Array.Empty<ImapEventGroup> ()));
Assert.ThrowsAsync<ArgumentException> (async () => await client.NotifyAsync (true, Array.Empty<ImapEventGroup> ()));
Assert.Throws<ArgumentNullException> (() => new ImapEventGroup (null, new List<ImapEvent> ()));
Assert.Throws<ArgumentNullException> (() => new ImapEventGroup (ImapMailboxFilter.Selected, null));
Assert.Throws<ArgumentNullException> (() => new ImapMailboxFilter.Subtree (null));
Assert.Throws<ArgumentException> (() => new ImapMailboxFilter.Subtree (new List<IMailFolder> ()));

Assert.Throws<ArgumentException> (() => new ImapMailboxFilter.Subtree (client.Inbox, null));
Assert.Throws<ArgumentNullException> (() => new ImapMailboxFilter.Mailboxes (null));
Assert.Throws<ArgumentException> (() => new ImapMailboxFilter.Mailboxes (new List<IMailFolder> ()));
Assert.Throws<ArgumentException> (() => new ImapMailboxFilter.Mailboxes (client.Inbox, null));

Assert.Throws<ArgumentNullException> (() => client.GetFolder ((string) null));
Expand Down Expand Up @@ -5504,9 +5499,7 @@ public void TestGMail ()

Assert.Throws<NotSupportedException> (() => client.EnableQuickResync ());
Assert.Throws<NotSupportedException> (() => client.Notify (true, new List<ImapEventGroup> {
new ImapEventGroup (ImapMailboxFilter.Inboxes, new List<ImapEvent> {
ImapEvent.FlagChange
})
new ImapEventGroup (ImapMailboxFilter.Inboxes, ImapEvent.FlagChange, new ImapEvent.MessageNew (), ImapEvent.MessageExpunge)
}));
Assert.Throws<NotSupportedException> (() => client.DisableNotify ());

Expand Down Expand Up @@ -5669,9 +5662,7 @@ public async Task TestGMailAsync ()

Assert.ThrowsAsync<NotSupportedException> (async () => await client.EnableQuickResyncAsync ());
Assert.ThrowsAsync<NotSupportedException> (async () => await client.NotifyAsync (true, new List<ImapEventGroup> {
new ImapEventGroup (ImapMailboxFilter.Inboxes, new List<ImapEvent> {
ImapEvent.FlagChange
})
new ImapEventGroup (ImapMailboxFilter.Inboxes, ImapEvent.FlagChange, new ImapEvent.MessageNew (), ImapEvent.MessageExpunge)
}));
Assert.ThrowsAsync<NotSupportedException> (async () => await client.DisableNotifyAsync ());

Expand Down Expand Up @@ -6316,7 +6307,9 @@ static List<ImapReplayCommand> CreateNotifyCommands ()
new ImapReplayCommand ("A00000006 IDLE\r\n", "dovecot.notify-idle.txt"),
new ImapReplayCommand ("A00000006", "DONE\r\n", "dovecot.notify-idle-done.txt"),
new ImapReplayCommand ("A00000007 NOTIFY NONE\r\n", ImapReplayCommandResponse.OK),
new ImapReplayCommand ("A00000008 LOGOUT\r\n", "gmail.logout.txt")
new ImapReplayCommand ("A00000008 NOTIFY SET STATUS (SELECTED (MessageNew (UID FLAGS ENVELOPE BODYSTRUCTURE MODSEQ BODY.PEEK[HEADER.FIELDS (REFERENCES)]) MessageExpunge FlagChange)) (MAILBOXES INBOX (MessageNew MessageExpunge MailboxMetadataChange ServerMetadataChange))\r\n", "dovecot.notify.txt"),
new ImapReplayCommand ("A00000009 NOTIFY NONE\r\n", ImapReplayCommandResponse.OK),
new ImapReplayCommand ("A00000010 LOGOUT\r\n", "gmail.logout.txt")
};
}

Expand Down Expand Up @@ -6347,45 +6340,6 @@ public void TestNotify ()

folder.Open (FolderAccess.ReadOnly);

// Test some InvalidOperationExceptions

// This fires due to non-message events for a Selected mailbox filter
Assert.Throws<InvalidOperationException> (() => client.Notify (true, new List<ImapEventGroup> {
new ImapEventGroup (ImapMailboxFilter.Selected, new List<ImapEvent> {
ImapEvent.MailboxName,
})
}));

// This fires due to having MessageNew, but not MessageExpunged
Assert.Throws<InvalidOperationException> (() => client.Notify (true, new List<ImapEventGroup> {
new ImapEventGroup (ImapMailboxFilter.Selected, new List<ImapEvent> {
new ImapEvent.MessageNew (items, new HashSet<HeaderId> ())
})
}));

// This fires due to having MessageNew, but not MessageExpunged
Assert.Throws<InvalidOperationException> (() => client.Notify (true, new List<ImapEventGroup> {
new ImapEventGroup (ImapMailboxFilter.Selected, new List<ImapEvent> {
new ImapEvent.MessageNew (items, new HashSet<string> ())
})
}));

// This fires due to having FlagsChanged but not MessageNew and MessageExpunged
Assert.Throws<InvalidOperationException> (() => client.Notify (true, new List<ImapEventGroup> {
new ImapEventGroup (ImapMailboxFilter.Selected, new List<ImapEvent> {
ImapEvent.AnnotationChange, ImapEvent.FlagChange
})
}));

// This fires due to MessageNew being aded to a non-Selected folder
Assert.Throws<InvalidOperationException> (() => client.Notify (true, new List<ImapEventGroup> {
new ImapEventGroup (ImapMailboxFilter.Personal, new List<ImapEvent> {
new ImapEvent.MessageNew (items, new HashSet<string> ())
})
}));

Assert.Throws<ArgumentNullException> (() => new ImapEvent.MessageNew (null));

client.Notify (true, new List<ImapEventGroup> {
new ImapEventGroup (ImapMailboxFilter.Personal, new List<ImapEvent> {
ImapEvent.MailboxName,
Expand Down Expand Up @@ -6518,6 +6472,22 @@ public void TestNotify ()

client.DisableNotify ();

client.Notify (true, new List<ImapEventGroup> {
new ImapEventGroup (ImapMailboxFilter.Selected, new List<ImapEvent> {
new ImapEvent.MessageNew (items | MessageSummaryItems.References),
ImapEvent.MessageExpunge,
ImapEvent.FlagChange
}),
new ImapEventGroup (new ImapMailboxFilter.Mailboxes (inbox), new List<ImapEvent> {
new ImapEvent.MessageNew (),
ImapEvent.MessageExpunge,
ImapEvent.MailboxMetadataChange,
ImapEvent.ServerMetadataChange
}),
});

client.DisableNotify ();

client.Disconnect (true);
}
}
Expand Down Expand Up @@ -6549,43 +6519,6 @@ public async Task TestNotifyAsync ()

await folder.OpenAsync (FolderAccess.ReadOnly);

// Test some InvalidOperationExceptions

// This fires due to non-message events for a Selected mailbox filter
Assert.ThrowsAsync<InvalidOperationException> (async () => await client.NotifyAsync (true, new List<ImapEventGroup> {
new ImapEventGroup (ImapMailboxFilter.Selected, new List<ImapEvent> {
ImapEvent.MailboxName,
})
}));

// This fires due to having MessageNew, but not MessageExpunged
Assert.ThrowsAsync<InvalidOperationException> (async () => await client.NotifyAsync (true, new List<ImapEventGroup> {
new ImapEventGroup (ImapMailboxFilter.Selected, new List<ImapEvent> {
new ImapEvent.MessageNew (items, new HashSet<HeaderId> ())
})
}));

// This fires due to having MessageNew, but not MessageExpunged
Assert.ThrowsAsync<InvalidOperationException> (async () => await client.NotifyAsync (true, new List<ImapEventGroup> {
new ImapEventGroup (ImapMailboxFilter.Selected, new List<ImapEvent> {
new ImapEvent.MessageNew (items, new HashSet<string> ())
})
}));

// This fires due to having FlagsChanged but not MessageNew and MessageExpunged
Assert.ThrowsAsync<InvalidOperationException> (async () => await client.NotifyAsync (true, new List<ImapEventGroup> {
new ImapEventGroup (ImapMailboxFilter.Selected, new List<ImapEvent> {
ImapEvent.AnnotationChange, ImapEvent.FlagChange
})
}));

// This fires due to MessageNew being aded to a non-Selected folder
Assert.ThrowsAsync<InvalidOperationException> (async () => await client.NotifyAsync (true, new List<ImapEventGroup> {
new ImapEventGroup (ImapMailboxFilter.Personal, new List<ImapEvent> {
new ImapEvent.MessageNew (items, new HashSet<string> ())
})
}));

await client.NotifyAsync (true, new List<ImapEventGroup> {
new ImapEventGroup (ImapMailboxFilter.Personal, new List<ImapEvent> {
ImapEvent.MailboxName,
Expand Down Expand Up @@ -6718,6 +6651,22 @@ public async Task TestNotifyAsync ()

await client.DisableNotifyAsync ();

await client.NotifyAsync (true, new List<ImapEventGroup> {
new ImapEventGroup (ImapMailboxFilter.Selected, new List<ImapEvent> {
new ImapEvent.MessageNew (items | MessageSummaryItems.References),
ImapEvent.MessageExpunge,
ImapEvent.FlagChange
}),
new ImapEventGroup (new ImapMailboxFilter.Mailboxes (inbox), new List<ImapEvent> {
new ImapEvent.MessageNew (),
ImapEvent.MessageExpunge,
ImapEvent.MailboxMetadataChange,
ImapEvent.ServerMetadataChange
}),
});

await client.DisableNotifyAsync ();

await client.DisconnectAsync (true);
}
}
Expand Down
203 changes: 203 additions & 0 deletions UnitTests/Net/Imap/ImapEventGroupTests.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,203 @@
//
// ImapEventGroupTests.cs
//
// Author: Jeffrey Stedfast <jestedfa@microsoft.com>
//
// Copyright (c) 2013-2023 .NET Foundation and Contributors
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
//

using System.Text;

using MailKit;
using MailKit.Net.Imap;

using MimeKit;

namespace UnitTests.Net.Imap {
[TestFixture]
public class ImapEventGroupTests
{
[Test]
public void TestArgumentExceptions ()
{
Assert.Throws<ArgumentNullException> (() => new ImapEventGroup (null, new List<ImapEvent> ()));
Assert.Throws<ArgumentNullException> (() => new ImapEventGroup (ImapMailboxFilter.Selected, (IList<ImapEvent>) null));

Assert.Throws<ArgumentNullException> (() => new ImapEventGroup (null));
Assert.Throws<ArgumentNullException> (() => new ImapEventGroup (ImapMailboxFilter.Selected, null));

Assert.Throws<ArgumentNullException> (() => new ImapMailboxFilter.Mailboxes (null));
Assert.Throws<ArgumentException> (() => new ImapMailboxFilter.Mailboxes (Array.Empty<IMailFolder> ()));

Assert.Throws<ArgumentNullException> (() => new ImapMailboxFilter.Subtree (null));
Assert.Throws<ArgumentException> (() => new ImapMailboxFilter.Subtree (Array.Empty<IMailFolder> ()));

Assert.Throws<ArgumentNullException> (() => new ImapEvent.MessageNew (null));
}

static void AssertFormatEventGroup (ImapEventGroup eventGroup, string expected, bool expectedNotify)
{
using var engine = new ImapEngine (null);
bool notifySelectedNewExpunge = false;
var command = new StringBuilder ();
var args = new List<object> ();

if (expected == null) {
Assert.Throws<InvalidOperationException> (() => eventGroup.Format (engine, command, args, ref notifySelectedNewExpunge));
} else {
eventGroup.Format (engine, command, args, ref notifySelectedNewExpunge);

Assert.AreEqual (expected, command.ToString ());
Assert.AreEqual (expectedNotify, notifySelectedNewExpunge, "notifySelectedNewExpunge");
}
}

[Test]
public void TestFormatEventGroup_None ()
{
var eventGroup = new ImapEventGroup (ImapMailboxFilter.Inboxes, Array.Empty<ImapEvent> ());

AssertFormatEventGroup (eventGroup, "(INBOXES NONE)", false);
}

[Test]
public void TestFormatEventGroup_AnnotationChange_Requires_MessageNew_And_MessageExpunge ()
{
var eventGroup = new ImapEventGroup (ImapMailboxFilter.Inboxes, ImapEvent.AnnotationChange);

AssertFormatEventGroup (eventGroup, null, false);
}

[Test]
public void TestFormatEventGroup_AnnotationChange_MessageNew_Requires_MessageExpunge ()
{
var eventGroup = new ImapEventGroup (ImapMailboxFilter.Inboxes, ImapEvent.AnnotationChange, new ImapEvent.MessageNew (MessageSummaryItems.None));

AssertFormatEventGroup (eventGroup, null, false);
}

[Test]
public void TestFormatEventGroup_AnnotationChange_MessageExpunge_Requires_MessageNew ()
{
var eventGroup = new ImapEventGroup (ImapMailboxFilter.Inboxes, ImapEvent.AnnotationChange, ImapEvent.MessageExpunge);

AssertFormatEventGroup (eventGroup, null, false);
}

[Test]
public void TestFormatEventGroup_FlagChange_Requires_MessageNew_And_MessageExpunge ()
{
var eventGroup = new ImapEventGroup (ImapMailboxFilter.Inboxes, ImapEvent.FlagChange);

AssertFormatEventGroup (eventGroup, null, false);
}

[Test]
public void TestFormatEventGroup_FlagChange_MessageNew_Requires_MessageExpunge ()
{
var eventGroup = new ImapEventGroup (ImapMailboxFilter.Inboxes, ImapEvent.FlagChange, new ImapEvent.MessageNew (MessageSummaryItems.None));

AssertFormatEventGroup (eventGroup, null, false);
}

[Test]
public void TestFormatEventGroup_FlagChange_MessageExpunge_Requires_MessageNew ()
{
var eventGroup = new ImapEventGroup (ImapMailboxFilter.Inboxes, ImapEvent.FlagChange, ImapEvent.MessageExpunge);

AssertFormatEventGroup (eventGroup, null, false);
}

[Test]
public void TestFormatEventGroup_FlagChange_MessageNew_MessageExpunge_AnnotationChange ()
{
var eventGroup = new ImapEventGroup (ImapMailboxFilter.Inboxes, ImapEvent.FlagChange, new ImapEvent.MessageNew (MessageSummaryItems.None), ImapEvent.MessageExpunge, ImapEvent.AnnotationChange);

AssertFormatEventGroup (eventGroup, "(INBOXES (FlagChange MessageNew MessageExpunge AnnotationChange))", false);
}

[Test]
public void TestFormatEventGroup_MessageExpunge_Requires_MessageNew ()
{
var eventGroup = new ImapEventGroup (ImapMailboxFilter.Inboxes, ImapEvent.MessageExpunge);

AssertFormatEventGroup (eventGroup, null, false);
}

[Test]
public void TestFormatEventGroup_MessageNew_Requires_MessageExpunge ()
{
var eventGroup = new ImapEventGroup (ImapMailboxFilter.Inboxes, new ImapEvent.MessageNew (MessageSummaryItems.None));

AssertFormatEventGroup (eventGroup, null, false);
}

[Test]
public void TestFormatEventGroup_MessageNew_MessageExpunge ()
{
var eventGroup = new ImapEventGroup (ImapMailboxFilter.Inboxes, new ImapEvent.MessageNew (MessageSummaryItems.None), ImapEvent.MessageExpunge);

AssertFormatEventGroup (eventGroup, "(INBOXES (MessageNew MessageExpunge))", false);
}

[Test]
public void TestFormatEventGroup_MessageNew_Headers_Requires_Selected ()
{
var headers = new HashSet<HeaderId> (new HeaderId[] { HeaderId.From, HeaderId.Subject, HeaderId.Date });
var eventGroup = new ImapEventGroup (ImapMailboxFilter.Inboxes, new ImapEvent.MessageNew (MessageSummaryItems.None, headers), ImapEvent.MessageExpunge);

AssertFormatEventGroup (eventGroup, null, false);
}

[Test]
public void TestFormatEventGroup_MessageNew_Items_Requires_Selected ()
{
var eventGroup = new ImapEventGroup (ImapMailboxFilter.Inboxes, new ImapEvent.MessageNew (MessageSummaryItems.Full), ImapEvent.MessageExpunge);

AssertFormatEventGroup (eventGroup, null, false);
}

[Test]
public void TestFormatEventGroup_MessageNew_WithSpecificHeaderIds ()
{
var headers = new HashSet<HeaderId> (new HeaderId[] { HeaderId.From, HeaderId.Subject, HeaderId.Date });
var eventGroup = new ImapEventGroup (ImapMailboxFilter.Selected, new ImapEvent.MessageNew (MessageSummaryItems.None, headers), ImapEvent.MessageExpunge);

AssertFormatEventGroup (eventGroup, "(SELECTED (MessageNew (BODY.PEEK[HEADER.FIELDS (FROM SUBJECT DATE)]) MessageExpunge))", true);
}

[Test]
public void TestFormatEventGroup_Selected_Requires_OnlyMessageEvents ()
{
var eventGroup = new ImapEventGroup (ImapMailboxFilter.Selected, ImapEvent.ServerMetadataChange);

AssertFormatEventGroup (eventGroup, null, false);
}

[Test]
public void TestFormatEventGroup_SelectedDelayed_Requires_OnlyMessageEvents ()
{
var eventGroup = new ImapEventGroup (ImapMailboxFilter.SelectedDelayed, ImapEvent.ServerMetadataChange);

AssertFormatEventGroup (eventGroup, null, false);
}
}
}

0 comments on commit 91d7cd2

Please sign in to comment.