2 // System.Net.WebClientTestAsync
5 // Martin Baulig (martin.baulig@googlemail.com)
7 // Copyright 2012 Xamarin Inc. (http://www.xamarin.com)
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:
18 // The above copyright notice and this permission notice shall be
19 // included in all copies or substantial portions of the Software.
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.
31 using System.Collections.Generic;
32 using System.Threading;
33 using System.Threading.Tasks;
34 using System.Reflection;
36 using NUnit.Framework;
38 namespace MonoTests.System.Net
41 public class WebClientTestAsync
45 [Category("AndroidNotWorking")] // Attempts to access the test dll which won't work on Android
46 public void DownloadData ()
49 bool progress_changed = false;
50 bool completed = false;
51 bool progress_changed_error = false;
52 bool completed_error = false;
54 int thread_id = Thread.CurrentThread.ManagedThreadId;
56 wc = new WebClient ();
58 wc.DownloadProgressChanged += delegate {
59 progress_changed = true;
60 if (Thread.CurrentThread.ManagedThreadId != thread_id)
61 progress_changed_error = true;
63 wc.DownloadDataCompleted += delegate {
65 if (Thread.CurrentThread.ManagedThreadId != thread_id)
66 completed_error = true;
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);
75 Assert.IsTrue (progress_changed, "#1");
76 Assert.IsFalse (progress_changed_error, "#2");
77 Assert.IsTrue (completed, "#3");
78 Assert.IsFalse (completed_error, "#4");
82 [Category("InetAccess")]
83 public void DownloadFileTaskAsync ()
85 WebClient wc = new WebClient ();
86 string filename = Path.GetTempFileName ();
88 var task = wc.DownloadFileTaskAsync ("http://www.mono-project.com/", filename);
89 Assert.IsTrue (task.Wait (15000));
90 Assert.IsTrue (task.IsCompleted);
92 File.Delete (filename);
96 [Category("InetAccess")]
97 [Category ("AndroidNotWorking")] // Fails when ran as part of the entire BCL test suite. Works when only this fixture is ran
98 public void Cancellation ()
100 WebClient wc = new WebClient ();
101 var progress = new ManualResetEvent (false);
102 wc.DownloadProgressChanged += delegate {
106 // Try downloading some large file, so we don't finish early.
107 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";
108 var task = wc.DownloadDataTaskAsync (url);
109 Assert.IsTrue (progress.WaitOne (15000), "#1");
115 } catch (Exception ex) {
116 if (ex is AggregateException)
117 ex = ((AggregateException)ex).InnerException;
118 Assert.That (ex is WebException || ex is OperationCanceledException, "#4");
119 Assert.IsTrue (task.IsCanceled || task.IsFaulted, "#5");
124 [Category("InetAccess")]
125 [Category ("AndroidNotWorking")] // Fails when ran as part of the entire BCL test suite. Works when only this fixture is ran
126 public void DownloadMultiple ()
128 WebClient wc = new WebClient ();
129 var t1 = wc.OpenReadTaskAsync ("http://www.google.com/");
130 Assert.That (t1.Wait (15000));
131 Assert.IsTrue (t1.IsCompleted, "#1");
133 var t2 = wc.OpenReadTaskAsync ("http://www.mono-project.com/");
134 Assert.That (t2.Wait (15000));
135 Assert.IsTrue (t2.IsCompleted, "#2");
137 var t3 = wc.DownloadStringTaskAsync ("http://www.google.com/");
138 Assert.That (t3.Wait (15000));
139 Assert.IsTrue (t3.IsCompleted, "#3");
143 [Category("InetAccess")]
144 [Category ("AndroidNotWorking")] // Fails when ran as part of the entire BCL test suite. Works when only this fixture is ran
145 public void DownloadMultiple2 ()
147 WebClient wc = new WebClient ();
149 MessagePumpSyncContext.Run (async () => {
150 await wc.DownloadStringTaskAsync ("http://www.google.com/");
151 await wc.DownloadDataTaskAsync ("http://www.mono-project.com/");
156 [Category("InetAccess")]
157 [Category ("AndroidNotWorking")] // Fails when ran as part of the entire BCL test suite. Works when only this fixture is ran
158 public void DownloadMultiple3 ()
160 WebClient wc = new WebClient ();
161 int thread_id = Thread.CurrentThread.ManagedThreadId;
162 bool data_completed = false;
163 bool string_completed = false;
166 wc.DownloadDataCompleted += delegate {
167 if (data_completed || (Thread.CurrentThread.ManagedThreadId != thread_id))
169 data_completed = true;
171 wc.DownloadStringCompleted += delegate {
172 if (string_completed || (Thread.CurrentThread.ManagedThreadId != thread_id))
174 string_completed = true;
177 MessagePumpSyncContext.Run (async () => {
178 await wc.DownloadStringTaskAsync ("http://www.google.com/");
179 await wc.DownloadDataTaskAsync ("http://www.mono-project.com/");
180 }, () => data_completed && string_completed, 15000);
182 Assert.IsTrue (data_completed, "#1");
183 Assert.IsTrue (string_completed, "#2");
184 Assert.IsFalse (error, "#3");
187 public sealed class MessagePumpSyncContext : SynchronizationContext
189 private delegate void MyAction ();
191 private readonly Queue<MyAction> queue = new Queue<MyAction> ();
192 private readonly object sync = new object ();
193 private readonly Func<bool> completed;
194 private readonly int timeout;
195 private bool running = true;
197 MessagePumpSyncContext (Func<bool> completed, int timeout)
199 this.completed = completed;
200 this.timeout = timeout;
203 public override void Send (SendOrPostCallback d, object state)
205 throw new InvalidOperationException ();
208 public override void Post (SendOrPostCallback d, object state)
211 queue.Enqueue (() => d (state));
212 Monitor.Pulse (sync);
220 if (completed != null)
226 void RunMessagePump ()
231 while (queue.Count == 0) {
234 if (!Monitor.Wait (sync, timeout))
235 throw new TimeoutException ();
237 action = queue.Dequeue ();
243 public void Cancel ()
247 Monitor.Pulse (sync);
251 public static void Run (Func<Task> action, Func<bool> completed, int timeout)
253 var old_ctx = SynchronizationContext.Current;
255 var ctx = new MessagePumpSyncContext (completed, timeout);
257 SynchronizationContext.SetSynchronizationContext (ctx);
259 var thread_id = Thread.CurrentThread.ManagedThreadId;
261 var task = action ();
262 task.ContinueWith ((t) => {
264 }, TaskScheduler.FromCurrentSynchronizationContext ());
266 ctx.RunMessagePump ();
269 throw task.Exception;
271 SynchronizationContext.SetSynchronizationContext (old_ctx);