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