ClientWebSocketTest.cs 8.0 KB

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