Merge pull request #5198 from BrzVlad/fix-binprot-stats
[mono.git] / mcs / class / System / Test / System.Net / WebClientTestAsync.cs
1 //
2 // System.Net.WebClientTestAsync
3 //
4 // Authors:
5 //      Martin Baulig (martin.baulig@googlemail.com)
6 //
7 // Copyright 2012 Xamarin Inc. (http://www.xamarin.com)
8 //
9 //
10 // Permission is hereby granted, free of charge, to any person obtaining
11 // a copy of this software and associated documentation files (the
12 // "Software"), to deal in the Software without restriction, including
13 // without limitation the rights to use, copy, modify, merge, publish,
14 // distribute, sublicense, and/or sell copies of the Software, and to
15 // permit persons to whom the Software is furnished to do so, subject to
16 // the following conditions:
17 // 
18 // The above copyright notice and this permission notice shall be
19 // included in all copies or substantial portions of the Software.
20 // 
21 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
22 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
23 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
24 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
25 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
26 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
27 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
28 //
29 using System;
30 using System.IO;
31 using System.Collections.Generic;
32 using System.Threading;
33 using System.Threading.Tasks;
34 using System.Reflection;
35 using System.Net;
36 using NUnit.Framework;
37
38 namespace MonoTests.System.Net
39 {
40         [TestFixture]
41         public class WebClientTestAsync
42         {
43                 [Test]
44                 [Category("Async")]
45                 [Category("AndroidNotWorking")] // Attempts to access the test dll which won't work on Android
46                 public void DownloadData ()
47                 {
48                         WebClient wc;
49                         bool progress_changed = false;
50                         bool completed = false;
51                         bool progress_changed_error = false;
52                         bool completed_error = false;
53
54                         int thread_id = Thread.CurrentThread.ManagedThreadId;
55
56                         wc = new WebClient ();
57
58                         wc.DownloadProgressChanged += delegate {
59                                 progress_changed = true;
60                                 if (Thread.CurrentThread.ManagedThreadId != thread_id)
61                                         progress_changed_error = true;
62                         };
63                         wc.DownloadDataCompleted += delegate {
64                                 completed = true;
65                                 if (Thread.CurrentThread.ManagedThreadId != thread_id)
66                                         completed_error = true;
67                         };
68
69                         MessagePumpSyncContext.Run (async () => {
70                                 var url = Assembly.GetExecutingAssembly ().CodeBase;
71                                 await wc.DownloadDataTaskAsync (url);
72                                 Assert.AreEqual (Thread.CurrentThread.ManagedThreadId, thread_id);
73                         }, () => progress_changed && completed, 10000);
74
75                         Assert.IsTrue (progress_changed, "#1");
76                         Assert.IsFalse (progress_changed_error, "#2");
77                         Assert.IsTrue (completed, "#3");
78                         Assert.IsFalse (completed_error, "#4");
79                 }
80
81                 [Test]
82                 public void DownloadFileTaskAsync ()
83                 {
84                         WebClient wc = new WebClient ();
85                         string filename = Path.GetTempFileName ();
86
87                         var task = wc.DownloadFileTaskAsync ("http://www.mono-project.com/", filename);
88                         Assert.IsTrue (task.Wait (15000));
89                         Assert.IsTrue (task.IsCompleted);
90                         
91                         File.Delete (filename);
92                 }
93
94                 [Test]
95                 [Category ("NotWorking")] // Fails when ran as part of the entire BCL test suite. Works when only this fixture is ran
96                 public void Cancellation ()
97                 {
98                         WebClient wc = new WebClient ();
99                         var progress = new ManualResetEvent (false);
100                         wc.DownloadProgressChanged += delegate {
101                                 progress.Set ();
102                         };
103
104                         // Try downloading some large file, so we don't finish early.
105                         var url = "http://download.mono-project.com/archive/2.10.9/macos-10-x86/11/MonoFramework-MDK-2.10.9_11.macos10.xamarin.x86.dmg";
106                         var task = wc.DownloadDataTaskAsync (url);
107                         Assert.IsTrue (progress.WaitOne (15000), "#1");
108                         wc.CancelAsync ();
109
110                         try {
111                                 task.Wait ();
112                                 Assert.Fail ("#2");
113                         } catch (Exception ex) {
114                                 if (ex is AggregateException)
115                                         ex = ((AggregateException)ex).InnerException;
116                                 Assert.That (ex is WebException || ex is OperationCanceledException, "#4");
117                                 Assert.IsTrue (task.IsCanceled || task.IsFaulted, "#5");
118                         }
119                 }
120
121                 [Test]
122                 [Category ("NotWorking")] // Fails when ran as part of the entire BCL test suite. Works when only this fixture is ran
123                 public void DownloadMultiple ()
124                 {
125                         WebClient wc = new WebClient ();
126                         var t1 = wc.OpenReadTaskAsync ("http://www.google.com/");
127                         Assert.That (t1.Wait (15000));
128                         Assert.IsTrue (t1.IsCompleted, "#1");
129
130                         var t2 = wc.OpenReadTaskAsync ("http://www.mono-project.com/");
131                         Assert.That (t2.Wait (15000));
132                         Assert.IsTrue (t2.IsCompleted, "#2");
133
134                         var t3 = wc.DownloadStringTaskAsync ("http://www.google.com/");
135                         Assert.That (t3.Wait (15000));
136                         Assert.IsTrue (t3.IsCompleted, "#3");
137                 }
138
139                 [Test]
140                 [Category ("NotWorking")] // Fails when ran as part of the entire BCL test suite. Works when only this fixture is ran
141                 public void DownloadMultiple2 ()
142                 {
143                         WebClient wc = new WebClient ();
144
145                         MessagePumpSyncContext.Run (async () => {
146                                 await wc.DownloadStringTaskAsync ("http://www.google.com/");
147                                 await wc.DownloadDataTaskAsync ("http://www.mono-project.com/");
148                         }, null, 15000);
149                 }
150
151                 [Test]
152                 [Category ("NotWorking")] // Fails when ran as part of the entire BCL test suite. Works when only this fixture is ran
153                 public void DownloadMultiple3 ()
154                 {
155                         WebClient wc = new WebClient ();
156                         int thread_id = Thread.CurrentThread.ManagedThreadId;
157                         bool data_completed = false;
158                         bool string_completed = false;
159                         bool error = false;
160
161                         wc.DownloadDataCompleted += delegate {
162                                 if (data_completed || (Thread.CurrentThread.ManagedThreadId != thread_id))
163                                         error = true;
164                                 data_completed = true;
165                         };
166                         wc.DownloadStringCompleted += delegate {
167                                 if (string_completed || (Thread.CurrentThread.ManagedThreadId != thread_id))
168                                         error = true;
169                                 string_completed = true;
170                         };
171
172                         MessagePumpSyncContext.Run (async () => {
173                                 await wc.DownloadStringTaskAsync ("http://www.google.com/");
174                                 await wc.DownloadDataTaskAsync ("http://www.mono-project.com/");
175                         }, () => data_completed && string_completed, 15000);
176
177                         Assert.IsTrue (data_completed, "#1");
178                         Assert.IsTrue (string_completed, "#2");
179                         Assert.IsFalse (error, "#3");
180                 }
181
182                 public sealed class MessagePumpSyncContext : SynchronizationContext
183                 {
184                         private delegate void MyAction ();
185
186                         private readonly Queue<MyAction> queue = new Queue<MyAction> ();
187                         private readonly object sync = new object ();
188                         private readonly Func<bool> completed;
189                         private readonly int timeout;
190                         private bool running = true;
191
192                         MessagePumpSyncContext (Func<bool> completed, int timeout)
193                         {
194                                 this.completed = completed;
195                                 this.timeout = timeout;
196                         }
197
198                         public override void Send (SendOrPostCallback d, object state)
199                         {
200                                 throw new InvalidOperationException ();
201                         }
202
203                         public override void Post (SendOrPostCallback d, object state)
204                         {
205                                 lock (sync) {
206                                         queue.Enqueue (() => d (state));
207                                         Monitor.Pulse (sync);
208                                 }
209                         }
210
211                         bool IsCompleted {
212                                 get {
213                                         if (running)
214                                                 return false;
215                                         if (completed != null)
216                                                 return completed ();
217                                         return true;
218                                 }
219                         }
220
221                         void RunMessagePump ()
222                         {
223                                 while (running) {
224                                         MyAction action;
225                                         lock (sync) {
226                                                 while (queue.Count == 0) {
227                                                         if (IsCompleted)
228                                                                 return;
229                                                         if (!Monitor.Wait (sync, timeout))
230                                                                 throw new TimeoutException ();
231                                                 }
232                                                 action = queue.Dequeue ();
233                                         }
234                                         action ();
235                                 }
236                         }
237
238                         public void Cancel ()
239                         {
240                                 lock (sync) {
241                                         running = false;
242                                         Monitor.Pulse (sync);
243                                 }
244                         }
245
246                         public static void Run (Func<Task> action, Func<bool> completed, int timeout)
247                         {
248                                 var old_ctx = SynchronizationContext.Current;
249
250                                 var ctx = new MessagePumpSyncContext (completed, timeout);
251                                 try {
252                                         SynchronizationContext.SetSynchronizationContext (ctx);
253
254                                         var thread_id = Thread.CurrentThread.ManagedThreadId;
255
256                                         var task = action ();
257                                         task.ContinueWith ((t) => {
258                                                 ctx.running = false;
259                                         }, TaskScheduler.FromCurrentSynchronizationContext ());
260
261                                         ctx.RunMessagePump ();
262
263                                         if (task.IsFaulted)
264                                                 throw task.Exception;
265                                 } finally {
266                                         SynchronizationContext.SetSynchronizationContext (old_ctx);
267                                 }
268                         }
269
270                 }
271         }
272 }