PageRenderTime 46ms CodeModel.GetById 19ms RepoModel.GetById 0ms app.codeStats 0ms

/tests/Microsoft.AspNet.SignalR.Tests/Server/Connections/DisconnectFacts.cs

https://github.com/mip1983/SignalR
C# | 240 lines | 189 code | 47 blank | 4 comment | 2 complexity | 121188f4fe591b34f7a185ec5111b32a MD5 | raw file
Possible License(s): Apache-2.0, CC-BY-SA-3.0
  1. using Microsoft.AspNet.SignalR.Hosting.Memory;
  2. using Microsoft.AspNet.SignalR.Hubs;
  3. using Microsoft.AspNet.SignalR.Infrastructure;
  4. using System;
  5. using System.Collections.Generic;
  6. using System.Diagnostics;
  7. using System.Linq;
  8. using System.Threading;
  9. using System.Threading.Tasks;
  10. using Xunit;
  11. using IClientRequest = Microsoft.AspNet.SignalR.Client.Http.IRequest;
  12. using IClientResponse = Microsoft.AspNet.SignalR.Client.Http.IResponse;
  13. using Moq;
  14. namespace Microsoft.AspNet.SignalR.Tests
  15. {
  16. public class DisconnectFacts : IDisposable
  17. {
  18. [Fact]
  19. public void DisconnectFiresForPersistentConnectionWhenClientGoesAway()
  20. {
  21. var host = new MemoryHost();
  22. host.MapConnection<MyConnection>("/echo");
  23. host.Configuration.DisconnectTimeout = TimeSpan.Zero;
  24. host.Configuration.HeartBeatInterval = TimeSpan.FromSeconds(5);
  25. var connectWh = new ManualResetEventSlim();
  26. var disconnectWh = new ManualResetEventSlim();
  27. host.DependencyResolver.Register(typeof(MyConnection), () => new MyConnection(connectWh, disconnectWh));
  28. var connection = new Client.Connection("http://foo/echo");
  29. // Maximum wait time for disconnect to fire (3 heart beat intervals)
  30. var disconnectWait = TimeSpan.FromTicks(host.Configuration.HeartBeatInterval.Ticks * 3);
  31. connection.Start(host).Wait();
  32. Assert.True(connectWh.Wait(TimeSpan.FromSeconds(10)), "Connect never fired");
  33. connection.Stop();
  34. Assert.True(disconnectWh.Wait(disconnectWait), "Disconnect never fired");
  35. }
  36. [Fact]
  37. public void DisconnectFiresForHubsWhenConnectionGoesAway()
  38. {
  39. var host = new MemoryHost();
  40. host.MapHubs();
  41. host.Configuration.DisconnectTimeout = TimeSpan.Zero;
  42. host.Configuration.HeartBeatInterval = TimeSpan.FromSeconds(5);
  43. var connectWh = new ManualResetEventSlim();
  44. var disconnectWh = new ManualResetEventSlim();
  45. host.DependencyResolver.Register(typeof(MyHub), () => new MyHub(connectWh, disconnectWh));
  46. var connection = new Client.Hubs.HubConnection("http://foo/");
  47. connection.CreateHubProxy("MyHub");
  48. // Maximum wait time for disconnect to fire (3 heart beat intervals)
  49. var disconnectWait = TimeSpan.FromTicks(host.Configuration.HeartBeatInterval.Ticks * 3);
  50. connection.Start(host).Wait();
  51. Assert.True(connectWh.Wait(TimeSpan.FromSeconds(10)), "Connect never fired");
  52. connection.Stop();
  53. Assert.True(disconnectWh.Wait(disconnectWait), "Disconnect never fired");
  54. }
  55. [Fact]
  56. public void FarmDisconnectOnlyRaisesEventOnce()
  57. {
  58. // Each node shares the same bus but are indepenent servers
  59. var counters = new SignalR.Infrastructure.PerformanceCounterManager();
  60. var bus = new MessageBus(new TraceManager(), counters);
  61. var nodeCount = 3;
  62. var nodes = new List<ServerNode>();
  63. for (int i = 0; i < nodeCount; i++)
  64. {
  65. nodes.Add(new ServerNode(bus));
  66. }
  67. var timeout = TimeSpan.FromSeconds(5);
  68. foreach (var node in nodes)
  69. {
  70. node.Server.Configuration.HeartBeatInterval = timeout;
  71. node.Server.Configuration.DisconnectTimeout = TimeSpan.Zero;
  72. node.Server.MapConnection<FarmConnection>("/echo");
  73. }
  74. var loadBalancer = new LoadBalancer(nodes.Select(f => f.Server).ToArray());
  75. var transport = new Client.Transports.LongPollingTransport(loadBalancer);
  76. var connection = new Client.Connection("http://goo/echo");
  77. connection.Start(transport).Wait();
  78. for (int i = 0; i < nodes.Count; i++)
  79. {
  80. nodes[i].Broadcast(String.Format("From Node {0}: {1}", i, i + 1));
  81. Thread.Sleep(TimeSpan.FromSeconds(1));
  82. }
  83. connection.Stop();
  84. Thread.Sleep(TimeSpan.FromTicks(timeout.Ticks * nodes.Count));
  85. Assert.Equal(1, nodes.Sum(n => n.Connection.DisconnectCount));
  86. }
  87. private class ServerNode
  88. {
  89. public MemoryHost Server { get; private set; }
  90. public FarmConnection Connection { get; private set; }
  91. private IConnection _connection;
  92. public ServerNode(IMessageBus bus)
  93. {
  94. // Give each server it's own dependency resolver
  95. Server = new MemoryHost(new DefaultDependencyResolver());
  96. Connection = new FarmConnection();
  97. Server.DependencyResolver.Register(typeof(FarmConnection), () => Connection);
  98. Server.DependencyResolver.Register(typeof(IMessageBus), () => bus);
  99. var context = Server.ConnectionManager.GetConnectionContext<FarmConnection>();
  100. _connection = context.Connection;
  101. }
  102. public void Broadcast(string message)
  103. {
  104. _connection.Broadcast(message).Wait();
  105. }
  106. }
  107. private class LoadBalancer : SignalR.Client.Http.IHttpClient
  108. {
  109. private int _counter;
  110. private readonly SignalR.Client.Http.IHttpClient[] _servers;
  111. public LoadBalancer(params SignalR.Client.Http.IHttpClient[] servers)
  112. {
  113. _servers = servers;
  114. }
  115. public Task<IClientResponse> GetAsync(string url, Action<IClientRequest> prepareRequest)
  116. {
  117. Debug.WriteLine("Server {0}: GET {1}", _counter, url);
  118. int index = _counter;
  119. _counter = (_counter + 1) % _servers.Length;
  120. return _servers[index].GetAsync(url, prepareRequest);
  121. }
  122. public Task<IClientResponse> PostAsync(string url, Action<IClientRequest> prepareRequest, Dictionary<string, string> postData)
  123. {
  124. Debug.WriteLine("Server {0}: POST {1}", _counter, url);
  125. int index = _counter;
  126. _counter = (_counter + 1) % _servers.Length;
  127. return _servers[index].PostAsync(url, prepareRequest, postData);
  128. }
  129. }
  130. private class FarmConnection : PersistentConnection
  131. {
  132. public int DisconnectCount { get; set; }
  133. protected override Task OnDisconnectAsync(IRequest request, string connectionId)
  134. {
  135. DisconnectCount++;
  136. return base.OnDisconnectAsync(request, connectionId);
  137. }
  138. protected override Task OnReceivedAsync(IRequest request, string connectionId, string data)
  139. {
  140. return Connection.Broadcast(data);
  141. }
  142. }
  143. public class MyHub : Hub
  144. {
  145. private ManualResetEventSlim _connectWh;
  146. private ManualResetEventSlim _disconnectWh;
  147. public MyHub(ManualResetEventSlim connectWh, ManualResetEventSlim disconnectWh)
  148. {
  149. _connectWh = connectWh;
  150. _disconnectWh = disconnectWh;
  151. }
  152. public override Task OnDisconnected()
  153. {
  154. _disconnectWh.Set();
  155. return null;
  156. }
  157. public override Task OnConnected()
  158. {
  159. _connectWh.Set();
  160. return TaskAsyncHelper.Empty;
  161. }
  162. public override Task OnReconnected()
  163. {
  164. return TaskAsyncHelper.Empty;
  165. }
  166. }
  167. private class MyConnection : PersistentConnection
  168. {
  169. private ManualResetEventSlim _connectWh;
  170. private ManualResetEventSlim _disconnectWh;
  171. public MyConnection(ManualResetEventSlim connectWh, ManualResetEventSlim disconnectWh)
  172. {
  173. _connectWh = connectWh;
  174. _disconnectWh = disconnectWh;
  175. }
  176. protected override Task OnConnectedAsync(IRequest request, string connectionId)
  177. {
  178. _connectWh.Set();
  179. return base.OnConnectedAsync(request, connectionId);
  180. }
  181. protected override Task OnDisconnectAsync(IRequest request, string connectionId)
  182. {
  183. _disconnectWh.Set();
  184. return base.OnDisconnectAsync(request, connectionId);
  185. }
  186. }
  187. public void Dispose()
  188. {
  189. GC.Collect();
  190. GC.WaitForPendingFinalizers();
  191. }
  192. }
  193. }