public void NodeDisposeTest() { // Memcache client config var config = new MemcacheClientConfiguration { TransportFactory = (_, __, r, s, ___, ____) => { var transport = new TransportMock(r) { IsAlive = true, Setup = s }; if (s != null) { s(transport); } return(transport); }, PoolSize = 1, }; var node = new MemcacheNode(null, config); // TransportMock does not put back the transport in the pool after the TrySend Assert.IsTrue(node.TrySend(new NoOpRequest(), 5000), "Unable to send a request through the node"); // Dispose the node after a certain delay ThreadPool.QueueUserWorkItem((o) => { Thread.Sleep(500); node.Dispose(); }); // The following TrySend will block because the transport pool is empty Assert.DoesNotThrow(() => node.TrySend(new NoOpRequest(), 1000), "The TrySend should not throw an exception"); }
public void SyncNodeDeadDetection() { bool aliveness = true; var transportMocks = new List <TransportMock>(); var config = new MemcacheClientConfiguration { DeadTimeout = TimeSpan.FromSeconds(1), TransportFactory = (_, __, r, s, ___, ____) => { var transport = new TransportMock(r) { IsAlive = aliveness, Setup = s }; transportMocks.Add(transport); if (s != null) { s(transport); } return(transport); }, PoolSize = 2, }; var node = new MemcacheNode(null, config); CollectionAssert.IsNotEmpty(transportMocks, "No transport has been created by the node"); Assert.IsTrue(node.TrySend(new NoOpRequest(), 5000), "Unable to send a request through the node"); // creation of new transport will set them as dead aliveness = false; foreach (var transport in transportMocks) { transport.IsAlive = false; } Assert.IsFalse(node.TrySend(new NoOpRequest(), 5000), "The node did not failed with all transport deads"); foreach (var transport in transportMocks) { transport.IsAlive = true; } Assert.IsFalse(node.IsDead, "The node is still dead, should be alive now !"); Assert.IsTrue(node.TrySend(new NoOpRequest(), 5000), "Unable to send a request throught the node after it's alive"); }
public void NodeWorkingTransportsTest(int nbOfTransportsPerNode) { int createdTransports = 0; int rememberPort; var mutex = new ManualResetEventSlim(false); Status returnStatus = Status.NoError; MemcacheNode theNode = null; // Memcache client config var config = new MemcacheClientConfiguration { DeadTimeout = TimeSpan.FromSeconds(1), TransportFactory = (_, __, ___, ____, _____, ______) => new MemcacheTransportForTest(_, __, ___, ____, _____, ______, () => { createdTransports++; }, () => { }), NodeFactory = (_, __) => theNode = MemcacheClientConfiguration.DefaultNodeFactory(_, __) as MemcacheNode, PoolSize = nbOfTransportsPerNode, }; MemcacheClient memcacheClient; using (var serverMock1 = new ServerMock()) { config.NodesEndPoints.Add(serverMock1.ListenEndPoint); rememberPort = serverMock1.ListenEndPoint.Port; serverMock1.ResponseBody = new byte[24]; // Create a Memcache client with one node memcacheClient = new MemcacheClient(config); // Check that we hooked to the MemcacheNode Assert.IsNotNull(theNode, "Did not hook to the MemcacheNode while creating the client"); // Check the number of transports that have been created Assert.AreEqual(nbOfTransportsPerNode, createdTransports, "The number of created should be the number of configured transport"); // Check the number of working transports (meaning, connected to the server) and the node state // By default, the transport are marked as being available upon creation of the client Assert.AreEqual(nbOfTransportsPerNode, theNode.WorkingTransports, "The number of working transport should be the number of created transport (1)"); Assert.IsFalse(theNode.IsDead, "The node should be alive (1)"); Assert.AreEqual(1, memcacheClient.AliveNodes, "Number of alive nodes is incorrect (1)"); // Do a get to initialize one of the transports Assert.IsTrue(memcacheClient.Get("whatever", (Status s, byte[] o) => { returnStatus = s; mutex.Set(); }), "The request should be sent correctly (1)"); Assert.IsTrue(mutex.Wait(1000), "Timeout on the get request"); Assert.AreEqual(Status.InternalError, returnStatus, "The status of the request should be InternalError (1)"); mutex.Reset(); // Check the number of working transports and the node state Assert.AreEqual(nbOfTransportsPerNode, theNode.WorkingTransports, "The number of working transport should be the number of created transport (2)"); Assert.IsFalse(theNode.IsDead, "The node should be alive (2)"); Assert.AreEqual(1, memcacheClient.AliveNodes, "Number of alive nodes is incorrect (2)"); } // Wait for the ServerMock to be fully disposed Thread.Sleep(100); // Attempt to send a request to take one of the transports out of the pool // After that the transport should be dead Assert.IsTrue(memcacheClient.Get("whatever", (Status s, byte[] o) => { returnStatus = s; mutex.Set(); }), "The request should be sent correctly (2)"); Assert.IsTrue(mutex.Wait(1000), "Timeout on the get request"); Assert.AreEqual(Status.InternalError, returnStatus, "The status of the request should be InternalError (2)"); mutex.Reset(); // Check the number of working transports and the node state Assert.AreEqual(nbOfTransportsPerNode - 1, theNode.WorkingTransports, "The number of working transport should be the number of created transport minus 1"); if (nbOfTransportsPerNode == 1) { Assert.IsTrue(theNode.IsDead, "The node should be dead (3)"); Assert.AreEqual(0, memcacheClient.AliveNodes, "Number of alive nodes is incorrect (3)"); } else { Assert.IsFalse(theNode.IsDead, "The node should be alive (3)"); Assert.AreEqual(1, memcacheClient.AliveNodes, "Number of alive nodes is incorrect (3)"); } // A new transport has been allocated and is periodically trying to reconnect Assert.AreEqual(nbOfTransportsPerNode + 1, createdTransports, "Expected a new transport to be created to replace the disposed one"); using (var serverMock2 = new ServerMock(rememberPort)) { serverMock2.ResponseBody = new byte[24]; // After some delay, the transport should connect Assert.That(() => theNode.WorkingTransports, new DelayedConstraint(new EqualConstraint(nbOfTransportsPerNode), 4000, 100), "After a while, the transport should manage to connect"); Assert.IsFalse(theNode.IsDead, "The node should be alive (4)"); Assert.AreEqual(1, memcacheClient.AliveNodes, "Number of alive nodes is incorrect (4)"); // Attempt a get Assert.IsTrue(memcacheClient.Get("whatever", (Status s, byte[] o) => { returnStatus = s; mutex.Set(); }), "The request should be sent correctly (4)"); Assert.IsTrue(mutex.Wait(1000), "Timeout on the get request"); Assert.AreEqual(Status.InternalError, returnStatus, "The status of the request should be InternalError (4)"); mutex.Reset(); // Check the number of working transports and the node state Assert.AreEqual(nbOfTransportsPerNode, theNode.WorkingTransports, "The number of working transport should be the number of created transport (5)"); Assert.IsFalse(theNode.IsDead, "The node should be alive (5)"); Assert.AreEqual(1, memcacheClient.AliveNodes, "Number of alive nodes is incorrect (5)"); // Dispose the client memcacheClient.Dispose(); } }