Merge pull request #3328 from BrzVlad/finalizer-thread-exited2
[mono.git] / mcs / class / System / Test / System.Net.Mail / SmtpClientTest.cs
index 641b787988ea5e4894c2ee87db5739ea97813fd9..909beb4988c8873dc7a6cd85d2b383443f1b290a 100644 (file)
@@ -16,6 +16,7 @@ using System.Threading;
 namespace MonoTests.System.Net.Mail
 {
        [TestFixture]
+       [Category ("RequiresBSDSockets")]
        public class SmtpClientTest
        {
                SmtpClient smtp;
@@ -392,20 +393,48 @@ namespace MonoTests.System.Net.Mail
                [Test]
                public void Deliver_Async ()
                {
-                       var server = new SmtpServer ();
-                       var client = new SmtpClient ("localhost", server.EndPoint.Port);
-                       var msg = new MailMessage ("foo@example.com", "bar@example.com", "hello", "howdydoo\r\n");
-
-                       Thread t = new Thread (server.Run);
-                       t.Start ();
-                       var task = client.SendMailAsync (msg);
-                       t.Join ();
+                       // SmtpClient uses BackgroundWorker and listens for the RunWorkerCompleted
+                       // to mark an async task as completed. The problem is that BackgroundWorker uses
+                       // System.ComponentModel.AsyncOperationManager to get the synchronization
+                       // context, and in monotouch that returns by default a synchronization
+                       // context for the main thread. Since tests are also run on the main thread,
+                       // we'll block the main thread while waiting for the async send to complete,
+                       // while the async completion is waiting for the main thread to process it.
+                       // So instead use a SynchronizationContext that uses the threadpool instead
+                       // of the main thread.
+                       var existing_context = global::System.ComponentModel.AsyncOperationManager.SynchronizationContext;
+                       global::System.ComponentModel.AsyncOperationManager.SynchronizationContext = new ThreadPoolSynchronizationContext ();
+                       try {
+                               var server = new SmtpServer ();
+                               var client = new SmtpClient ("localhost", server.EndPoint.Port);
+                               var msg = new MailMessage ("foo@example.com", "bar@example.com", "hello", "howdydoo\r\n");
+
+                               Thread t = new Thread (server.Run);
+                               t.Start ();
+                               var task = client.SendMailAsync (msg);
+                               t.Join ();
+
+                               Assert.AreEqual ("<foo@example.com>", server.mail_from);
+                               Assert.AreEqual ("<bar@example.com>", server.rcpt_to);
+
+                               Assert.IsTrue (task.Wait (1000));
+                               Assert.IsTrue (task.IsCompleted, "task");
+                       } finally {
+                               global::System.ComponentModel.AsyncOperationManager.SynchronizationContext = existing_context;
+                       }
+               }
 
-                       Assert.AreEqual ("<foo@example.com>", server.mail_from);
-                       Assert.AreEqual ("<bar@example.com>", server.rcpt_to);
+               internal class ThreadPoolSynchronizationContext : SynchronizationContext
+               {
+                       public override void Post (SendOrPostCallback d, object state)
+                       {
+                               ThreadPool.QueueUserWorkItem ((v) => d (state));
+                       }
 
-                       Assert.IsTrue (task.IsCompleted, "task");
+                       public override void Send (SendOrPostCallback d, object state)
+                       {
+                               d (state);
+                       }
                }
-
        }
 }