Skip to content

Commit aec77dd

Browse files
rzikmCopilot
andauthored
Add more tests for SmtpClient (#114690)
* Add STARTTLS tests * Partition tests from SmtpClientTest class by area * Add more tests * Update src/libraries/System.Net.Mail/tests/Functional/SmtpClientAttachmentTest.cs Co-authored-by: Copilot <[email protected]> * Fix nondeterministic test --------- Co-authored-by: Copilot <[email protected]>
1 parent 8c3a2e1 commit aec77dd

11 files changed

+1308
-327
lines changed
Lines changed: 179 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,179 @@
1+
// Licensed to the .NET Foundation under one or more agreements.
2+
// The .NET Foundation licenses this file to you under the MIT license.
3+
4+
using System.Net.NetworkInformation;
5+
using System.Net.Security;
6+
using System.Security.Authentication;
7+
using System.Security.Cryptography;
8+
using System.Security.Cryptography.X509Certificates;
9+
using System.Net.Mail.Tests;
10+
using System.Threading;
11+
using System.Threading.Tasks;
12+
using Xunit;
13+
using Xunit.Sdk;
14+
using Xunit.Abstractions;
15+
16+
namespace System.Net.Mail.Tests
17+
{
18+
public enum SendMethod
19+
{
20+
Send,
21+
SendAsync,
22+
SendMailAsync
23+
}
24+
25+
public interface ISendMethodProvider
26+
{
27+
static abstract SendMethod SendMethod { get; }
28+
}
29+
30+
public struct SyncSendMethod : ISendMethodProvider
31+
{
32+
public static SendMethod SendMethod => SendMethod.Send;
33+
}
34+
35+
public struct AsyncSendMethod : ISendMethodProvider
36+
{
37+
public static SendMethod SendMethod => SendMethod.SendAsync;
38+
}
39+
40+
public struct SendMailAsyncMethod : ISendMethodProvider
41+
{
42+
public static SendMethod SendMethod => SendMethod.SendMailAsync;
43+
}
44+
45+
public abstract class LoopbackServerTestBase<T> : IDisposable
46+
where T : ISendMethodProvider
47+
{
48+
protected LoopbackSmtpServer Server { get; private set; }
49+
protected ITestOutputHelper Output { get; private set; }
50+
51+
private SmtpClient _smtp;
52+
53+
protected SmtpClient Smtp
54+
{
55+
get
56+
{
57+
return _smtp ??= Server.CreateClient();
58+
}
59+
}
60+
61+
public LoopbackServerTestBase(ITestOutputHelper output)
62+
{
63+
Output = output;
64+
Server = new LoopbackSmtpServer(Output);
65+
}
66+
67+
private Task<Exception?> SendMailInternal(MailMessage msg, CancellationToken cancellationToken, bool? asyncExpectDirectException)
68+
{
69+
switch (T.SendMethod)
70+
{
71+
case SendMethod.Send:
72+
try
73+
{
74+
Smtp.Send(msg);
75+
return Task.FromResult<Exception>(null);
76+
}
77+
catch (Exception ex)
78+
{
79+
return Task.FromResult(ex);
80+
}
81+
82+
case SendMethod.SendAsync:
83+
TaskCompletionSource<Exception?> tcs = new TaskCompletionSource<Exception?>();
84+
SendCompletedEventHandler handler = null!;
85+
handler = (s, e) =>
86+
{
87+
Smtp.SendCompleted -= handler;
88+
89+
if (e.Error != null)
90+
{
91+
tcs.SetResult(e.Error);
92+
}
93+
else if (e.Cancelled)
94+
{
95+
tcs.SetResult(new OperationCanceledException("The operation was canceled."));
96+
}
97+
else
98+
{
99+
tcs.SetResult(null);
100+
}
101+
};
102+
Smtp.SendCompleted += handler;
103+
try
104+
{
105+
Smtp.SendAsync(msg, tcs);
106+
107+
if (asyncExpectDirectException == true)
108+
{
109+
Assert.Fail($"No exception thrown");
110+
}
111+
112+
return tcs.Task;
113+
}
114+
catch (Exception ex) when (ex is not XunitException)
115+
{
116+
Smtp.SendCompleted -= handler;
117+
118+
if (asyncExpectDirectException == false)
119+
{
120+
Assert.Fail($"Expected exception via callback, got direct: {ex}");
121+
}
122+
123+
return Task.FromResult(ex);
124+
}
125+
126+
case SendMethod.SendMailAsync:
127+
try
128+
{
129+
Task task = Smtp.SendMailAsync(msg, cancellationToken);
130+
131+
if (asyncExpectDirectException == true)
132+
{
133+
Assert.Fail($"No exception thrown");
134+
}
135+
136+
return task.ContinueWith(t => t.Exception?.InnerException);
137+
}
138+
catch (Exception ex) when (ex is not XunitException)
139+
{
140+
if (asyncExpectDirectException == false)
141+
{
142+
Assert.Fail($"Expected stored exception, got direct: {ex}");
143+
}
144+
145+
return Task.FromResult(ex);
146+
}
147+
148+
default:
149+
throw new ArgumentOutOfRangeException();
150+
}
151+
}
152+
153+
protected async Task SendMail(MailMessage msg, CancellationToken cancellationToken = default)
154+
{
155+
Exception? ex = await SendMailInternal(msg, cancellationToken, null);
156+
Assert.Null(ex);
157+
}
158+
159+
protected async Task<TException> SendMail<TException>(MailMessage msg, CancellationToken cancellationToken = default, bool unwrapException = true, bool asyncDirectException = false) where TException : Exception
160+
{
161+
Exception? ex = await SendMailInternal(msg, cancellationToken, asyncDirectException);
162+
163+
if (unwrapException && T.SendMethod != SendMethod.Send && typeof(TException) != typeof(SmtpException))
164+
{
165+
ex = Assert.IsType<SmtpException>(ex).InnerException;
166+
}
167+
168+
return Assert.IsType<TException>(ex);
169+
}
170+
171+
protected static string GetClientDomain() => IPGlobalProperties.GetIPGlobalProperties().HostName.Trim().ToLower();
172+
173+
public virtual void Dispose()
174+
{
175+
_smtp?.Dispose();
176+
Server?.Dispose();
177+
}
178+
}
179+
}

0 commit comments

Comments
 (0)