Disable ClientWebSocketTest.cs (for mobile) until the type itself is added to the...
[mono.git] / mcs / class / System / Test / System.Net.WebSockets / ClientWebSocketTest.cs
1 #if NET_4_5 && !MOBILE
2 using System;
3 using System.Net;
4 using System.Threading;
5 using System.Threading.Tasks;
6 using System.Collections.Generic;
7 using System.Net.WebSockets;
8 using System.Reflection;
9 using System.Text;
10
11 using NUnit.Framework;
12
13
14 namespace MonoTests.System.Net.WebSockets
15 {
16         [TestFixture]
17         public class ClientWebSocketTest
18         {
19                 const string EchoServerUrl = "ws://echo.websocket.org";
20                 const int Port = 42123;
21                 HttpListener listener;
22                 ClientWebSocket socket;
23                 MethodInfo headerSetMethod;
24
25                 [SetUp]
26                 public void Setup ()
27                 {
28                         listener = new HttpListener ();
29                         listener.Prefixes.Add ("http://localhost:" + Port + "/");
30                         listener.Start ();
31                         socket = new ClientWebSocket ();
32                 }
33
34                 [TearDown]
35                 public void Teardown ()
36                 {
37                         if (listener != null) {
38                                 listener.Stop ();
39                                 listener = null;
40                         }
41                         if (socket != null) {
42                                 if (socket.State == WebSocketState.Open)
43                                         socket.CloseAsync (WebSocketCloseStatus.NormalClosure, string.Empty, CancellationToken.None).Wait ();
44                                 socket.Dispose ();
45                                 socket = null;
46                         }
47                 }
48
49                 [Test]
50                 public void ServerHandshakeReturnCrapStatusCodeTest ()
51                 {
52                         HandleHttpRequestAsync ((req, resp) => resp.StatusCode = 418);
53                         try {
54                                 socket.ConnectAsync (new Uri ("ws://localhost:" + Port), CancellationToken.None).Wait ();
55                         } catch (AggregateException e) {
56                                 AssertWebSocketException (e, WebSocketError.Success, typeof (WebException));
57                                 return;
58                         }
59                         Assert.Fail ("Should have thrown");
60                 }
61
62                 [Test]
63                 public void ServerHandshakeReturnWrongUpgradeHeader ()
64                 {
65                         HandleHttpRequestAsync ((req, resp) => {
66                                         resp.StatusCode = 101;
67                                         resp.Headers["Upgrade"] = "gtfo";
68                                 });
69                         try {
70                                 socket.ConnectAsync (new Uri ("ws://localhost:" + Port), CancellationToken.None).Wait ();
71                         } catch (AggregateException e) {
72                                 AssertWebSocketException (e, WebSocketError.Success);
73                                 return;
74                         }
75                         Assert.Fail ("Should have thrown");
76                 }
77
78                 [Test]
79                 public void ServerHandshakeReturnWrongConnectionHeader ()
80                 {
81                         HandleHttpRequestAsync ((req, resp) => {
82                                         resp.StatusCode = 101;
83                                         resp.Headers["Upgrade"] = "websocket";
84                                         // Mono http request doesn't like the forcing, test still valid since the default connection header value is empty
85                                         //ForceSetHeader (resp.Headers, "Connection", "Foo");
86                                 });
87                         try {
88                                 socket.ConnectAsync (new Uri ("ws://localhost:" + Port), CancellationToken.None).Wait ();
89                         } catch (AggregateException e) {
90                                 AssertWebSocketException (e, WebSocketError.Success);
91                                 return;
92                         }
93                         Assert.Fail ("Should have thrown");
94                 }
95
96                 [Test]
97                 public void EchoTest ()
98                 {
99                         const string Payload = "This is a websocket test";
100
101                         Assert.AreEqual (WebSocketState.None, socket.State);
102                         socket.ConnectAsync (new Uri (EchoServerUrl), CancellationToken.None).Wait ();
103                         Assert.AreEqual (WebSocketState.Open, socket.State);
104
105                         var sendBuffer = Encoding.ASCII.GetBytes (Payload);
106                         socket.SendAsync (new ArraySegment<byte> (sendBuffer), WebSocketMessageType.Text, true, CancellationToken.None).Wait ();
107
108                         var receiveBuffer = new byte[Payload.Length];
109                         var resp = socket.ReceiveAsync (new ArraySegment<byte> (receiveBuffer), CancellationToken.None).Result;
110
111                         Assert.AreEqual (Payload.Length, resp.Count);
112                         Assert.IsTrue (resp.EndOfMessage);
113                         Assert.AreEqual (WebSocketMessageType.Text, resp.MessageType);
114                         Assert.AreEqual (Payload, Encoding.ASCII.GetString (receiveBuffer, 0, resp.Count));
115
116                         socket.CloseAsync (WebSocketCloseStatus.NormalClosure, string.Empty, CancellationToken.None).Wait ();
117                         Assert.AreEqual (WebSocketState.Closed, socket.State);
118                 }
119
120                 [Test]
121                 public void CloseOutputAsyncTest ()
122                 {
123                         socket.ConnectAsync (new Uri (EchoServerUrl), CancellationToken.None).Wait ();
124                         Assert.AreEqual (WebSocketState.Open, socket.State);
125
126                         socket.CloseOutputAsync (WebSocketCloseStatus.NormalClosure, string.Empty, CancellationToken.None).Wait ();
127                         Assert.AreEqual (WebSocketState.CloseSent, socket.State);
128
129                         var resp = socket.ReceiveAsync (new ArraySegment<byte> (new byte[0]), CancellationToken.None).Result;
130                         Assert.AreEqual (WebSocketState.Closed, socket.State);
131                         Assert.AreEqual (WebSocketMessageType.Close, resp.MessageType);
132                         Assert.AreEqual (WebSocketCloseStatus.NormalClosure, resp.CloseStatus);
133                         Assert.AreEqual (string.Empty, resp.CloseStatusDescription);
134                 }
135
136                 [Test]
137                 public void CloseAsyncTest ()
138                 {
139                         socket.ConnectAsync (new Uri (EchoServerUrl), CancellationToken.None).Wait ();
140                         Assert.AreEqual (WebSocketState.Open, socket.State);
141
142                         socket.CloseAsync (WebSocketCloseStatus.NormalClosure, string.Empty, CancellationToken.None).Wait ();
143                         Assert.AreEqual (WebSocketState.Closed, socket.State);
144                 }
145
146                 [Test, ExpectedException (typeof (InvalidOperationException))]
147                 public void SendAsyncArgTest_NotConnected ()
148                 {
149                         socket.SendAsync (new ArraySegment<byte> (new byte[0]), WebSocketMessageType.Text, true, CancellationToken.None);
150                 }
151
152                 [Test, ExpectedException (typeof (ArgumentNullException))]
153                 public void SendAsyncArgTest_NoArray ()
154                 {
155                         socket.ConnectAsync (new Uri (EchoServerUrl), CancellationToken.None).Wait ();
156                         socket.SendAsync (new ArraySegment<byte> (), WebSocketMessageType.Text, true, CancellationToken.None);
157                 }
158
159                 [Test, ExpectedException (typeof (InvalidOperationException))]
160                 public void ReceiveAsyncArgTest_NotConnected ()
161                 {
162                         socket.ReceiveAsync (new ArraySegment<byte> (new byte[0]), CancellationToken.None);
163                 }
164
165                 [Test, ExpectedException (typeof (ArgumentNullException))]
166                 public void ReceiveAsyncArgTest_NoArray ()
167                 {
168                         socket.ConnectAsync (new Uri (EchoServerUrl), CancellationToken.None).Wait ();
169                         socket.ReceiveAsync (new ArraySegment<byte> (), CancellationToken.None);
170                 }
171
172                 [Test]
173                 public void ReceiveAsyncWrongState_Closed ()
174                 {
175                         try {
176                                 socket.ConnectAsync (new Uri (EchoServerUrl), CancellationToken.None).Wait ();
177                                 socket.CloseAsync (WebSocketCloseStatus.NormalClosure, string.Empty, CancellationToken.None).Wait ();
178                                 socket.ReceiveAsync (new ArraySegment<byte> (new byte[0]), CancellationToken.None).Wait ();
179                         } catch (AggregateException e) {
180                                 AssertWebSocketException (e, WebSocketError.Success);
181                                 return;
182                         }
183                         Assert.Fail ("Should have thrown");
184                 }
185
186                 [Test]
187                 public void SendAsyncWrongState_Closed ()
188                 {
189                         try {
190                                 socket.ConnectAsync (new Uri (EchoServerUrl), CancellationToken.None).Wait ();
191                                 socket.CloseAsync (WebSocketCloseStatus.NormalClosure, string.Empty, CancellationToken.None).Wait ();
192                                 socket.SendAsync (new ArraySegment<byte> (new byte[0]), WebSocketMessageType.Text, true, CancellationToken.None).Wait ();
193                         } catch (AggregateException e) {
194                                 AssertWebSocketException (e, WebSocketError.Success);
195                                 return;
196                         }
197                         Assert.Fail ("Should have thrown");
198                 }
199
200                 [Test]
201                 public void SendAsyncWrongState_CloseSent ()
202                 {
203                         try {
204                                 socket.ConnectAsync (new Uri (EchoServerUrl), CancellationToken.None).Wait ();
205                                 socket.CloseOutputAsync (WebSocketCloseStatus.NormalClosure, string.Empty, CancellationToken.None).Wait ();
206                                 socket.SendAsync (new ArraySegment<byte> (new byte[0]), WebSocketMessageType.Text, true, CancellationToken.None).Wait ();
207                         } catch (AggregateException e) {
208                                 AssertWebSocketException (e, WebSocketError.Success);
209                                 return;
210                         }
211                         Assert.Fail ("Should have thrown");
212                 }
213
214                 async Task HandleHttpRequestAsync (Action<HttpListenerRequest, HttpListenerResponse> handler)
215                 {
216                         var ctx = await listener.GetContextAsync ();
217                         handler (ctx.Request, ctx.Response);
218                         ctx.Response.Close ();
219                 }
220
221                 void AssertWebSocketException (AggregateException e, WebSocketError error, Type inner = null)
222                 {
223                         var wsEx = e.InnerException as WebSocketException;
224                         Console.WriteLine (e.InnerException.ToString ());
225                         Assert.IsNotNull (wsEx, "Not a websocketexception");
226                         Assert.AreEqual (error, wsEx.WebSocketErrorCode);
227                         if (inner != null) {
228                                 Assert.IsNotNull (wsEx.InnerException);
229                                 Assert.IsInstanceOfType (inner, wsEx.InnerException);
230                         }
231                 }
232
233                 void ForceSetHeader (WebHeaderCollection headers, string name, string value)
234                 {
235                         if (headerSetMethod == null)
236                                 headerSetMethod = typeof (WebHeaderCollection).GetMethod ("AddValue", BindingFlags.NonPublic);
237                         headerSetMethod.Invoke (headers, new[] { name, value });
238                 }
239         }
240 }
241
242 #endif