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 CouchbaseCluster(MemcacheClientConfiguration configuration, string bucket, IPEndPoint[] configurationHosts)
        {
            if (configurationHosts.Length == 0)
                throw new ArgumentException("There should be at least one value in the list", "configurationHosts");

            _isInitialized = false;

            _linesStreamReader = null;
            _webResponse = null;

            _configuration = configuration;
            if (_configuration.Authenticator == null)
                _configuration.Authenticator = MemcacheClientConfiguration.SaslPlainAuthenticatorFactory(string.Empty, bucket, string.Empty);

            _bucket = bucket;

            _currentConfigurationHost = 0;
            _configurationHosts = configurationHosts;

            _memcacheNodes = new Dictionary<string, IMemcacheNode>();

            _locator = null;

            _connectionTimer = new Timer(_ => ConnectToConfigurationStream(), null, Timeout.Infinite, Timeout.Infinite);
            _receivedInitialConfigurationBarrier = new ManualResetEventSlim();
        }
        public void TransportDeadThenAliveTest()
        {
            IMemcacheNode theNode   = null;
            FakeTransport transport = new FakeTransport();

            transport.Kill();

            // Memcache client config
            var config = new MemcacheClientConfiguration
            {
                DeadTimeout      = TimeSpan.FromSeconds(1),
                TransportFactory = transport.Factory,
                NodeFactory      = (e, c) => MemcacheClientConfiguration.DefaultNodeFactory(e, c),
                PoolSize         = 1,
            };

            theNode = config.NodeFactory(null, config);
            Assert.IsFalse(theNode.IsDead, "The node should be alive before any failure");

            Assert.IsFalse(theNode.TrySend(null, 1), "The TrySend should fail with a broken transport");
            Assert.IsTrue(theNode.IsDead, "The node should be dead after the first send failed");

            transport.Resurect();
            Assert.IsFalse(theNode.IsDead, "The node should be alive after the transport resurected");
            Assert.IsTrue(theNode.TrySend(null, 1), "The TrySend should be able to send a request after the transport is up again");

            transport.Kill();
            Assert.IsFalse(theNode.TrySend(null, 1), "The TrySend should fail with a killed transport");
            Assert.IsTrue(theNode.IsDead, "The node should be dead after the a send failed");
        }
Example #4
0
        public void SerializationThrows()
        {
            var serializerMoq = new Mock<ISerializer<TestType>>();
            serializerMoq.Setup(s => s.FromBytes(It.IsAny<byte[]>())).Throws(new SerializationException());
            serializerMoq.Setup(s => s.ToBytes(It.IsAny<TestType>())).Throws(new SerializationException());
            serializerMoq.Setup(s => s.TypeFlag).Returns(314);

            Exception raised = null;

            var config = new MemcacheClientConfiguration
            {
                ClusterFactory = c => _clusterMock,
            };
            var serialiserMoqObj = serializerMoq.Object;
            config.SetSerializer(serialiserMoqObj);
            var client = new MemcacheClient(config);
            client.CallbackError += e => raised = e;

            // test that the throws of the serializer is synchronously propagated
            Assert.Throws(typeof(SerializationException), () => client.Set("Hello", new TestType(), TimeSpan.Zero));

            // test that the failing serializer does not synchronously throws but sends a CallbackError event
            _responseHeader = new MemcacheResponseHeader
            {
                ExtraLength = 4,
                TotalBodyLength = 4,
                Opcode = Opcode.Get,
            };
            _extra = new byte[] { 0, 0, 0, 0};
            Assert.True(client.Get("Hello", (Status s, TestType v) => { }));
            Assert.IsNotNull(raised);
            Assert.IsInstanceOf<SerializationException>(raised);
        }
Example #5
0
        public MemcacheNode(EndPoint endPoint, MemcacheClientConfiguration configuration, IOngoingDispose clientDispose)
        {
            if (configuration == null)
            {
                throw new ArgumentException("Client config should not be null");
            }

            _configuration = configuration;
            _endPoint      = endPoint;
            _clientDispose = clientDispose;
            _tokenSource   = new CancellationTokenSource();
            _transportPool = new BlockingCollection <IMemcacheTransport>(new ConcurrentStack <IMemcacheTransport>());

            for (int i = 0; i < configuration.PoolSize; ++i)
            {
                var transport = (configuration.TransportFactory ?? MemcacheTransport.DefaultAllocator)
                                    (endPoint,
                                    configuration,
                                    RegisterEvents,
                                    TransportAvailable,
                                    false,
                                    clientDispose);
                TransportAvailable(transport);
            }
        }
Example #6
0
        public CouchbaseCluster(MemcacheClientConfiguration configuration, string bucket, IPEndPoint[] configurationHosts)
        {
            if (configurationHosts.Length == 0)
            {
                throw new ArgumentException("There should be at least one value in the list", "configurationHosts");
            }

            _isInitialized = false;

            _linesStreamReader = null;
            _webResponse       = null;

            _configuration = configuration;
            if (_configuration.Authenticator == null)
            {
                _configuration.Authenticator = MemcacheClientConfiguration.SaslPlainAuthenticatorFactory(string.Empty, bucket, string.Empty);
            }

            _bucket = bucket;

            _currentConfigurationHost = 0;
            _configurationHosts       = configurationHosts;

            _memcacheNodes = new Dictionary <string, IMemcacheNode>();

            _locator = null;

            _connectionTimer = new Timer(_ => ConnectToConfigurationStream(), null, Timeout.Infinite, Timeout.Infinite);
            _receivedInitialConfigurationBarrier = new ManualResetEventSlim();
        }
        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");
        }
        /// <summary>
        /// Ctor, intialize things ...
        /// </summary>
        /// <param name="endpoint" />
        /// <param name="clientConfig">The client configuration</param>
        /// <param name="registerEvents">Delegate to call to register the transport</param>
        /// <param name="transportAvailable">Delegate to call when the transport is alive</param>
        /// <param name="planToConnect">If true, connect in a timer handler started immediately and call transportAvailable.
        ///                             Otherwise, the transport will connect synchronously at the first request</param>
        /// <param name="nodeClosing">Interface to check if the node is being disposed of</param>
        public MemcacheTransport(EndPoint endpoint, MemcacheClientConfiguration clientConfig, Action<IMemcacheTransport> registerEvents, Action<IMemcacheTransport> transportAvailable, bool planToConnect, Func<bool> nodeClosing)
        {
            if (clientConfig == null)
                throw new ArgumentException("Client config should not be null");

            _endPoint = endpoint;
            _clientConfig = clientConfig;
            _registerEvents = registerEvents;
            _transportAvailable = transportAvailable;
            _nodeClosing = nodeClosing;

            _connectTimer = new Timer(TryConnect);
            _initialized = false;

            _registerEvents(this);

            _pendingRequests = new ConcurrentQueue<IMemcacheRequest>();

            _sendAsynchEvtArgs = new SocketAsyncEventArgs();
            _sendAsynchEvtArgs.Completed += OnSendRequestComplete;

            _receiveHeaderAsynchEvtArgs = new SocketAsyncEventArgs();
            _receiveHeaderAsynchEvtArgs.SetBuffer(new byte[MemcacheResponseHeader.Size], 0, MemcacheResponseHeader.Size);
            _receiveHeaderAsynchEvtArgs.Completed += OnReceiveHeaderComplete;

            _receiveBodyAsynchEvtArgs = new SocketAsyncEventArgs();
            _receiveBodyAsynchEvtArgs.Completed += OnReceiveBodyComplete;

            if (planToConnect)
                _connectTimer.Change(0, Timeout.Infinite);
            else if (transportAvailable != null)
                transportAvailable(this);
            _alive = !planToConnect;
        }
Example #9
0
        /// <summary>
        /// Ctor, intialize things ...
        /// </summary>
        /// <param name="endpoint" />
        /// <param name="clientConfig">The client configuration</param>
        /// <param name="registerEvents">Delegate to call to register the transport</param>
        /// <param name="transportAvailable">Delegate to call when the transport is alive</param>
        /// <param name="planToConnect">If true, connect in a timer handler started immediately and call transportAvailable.
        ///                             Otherwise, the transport will connect synchronously at the first request</param>
        /// <param name="nodeClosing">Interface to check if the node is being disposed of</param>
        public MemcacheTransport(EndPoint endpoint, MemcacheClientConfiguration clientConfig, Action <IMemcacheTransport> registerEvents, Action <IMemcacheTransport> transportAvailable, bool planToConnect, Func <bool> nodeClosing)
        {
            if (clientConfig == null)
            {
                throw new ArgumentException("Client config should not be null");
            }

            _endPoint           = endpoint;
            _clientConfig       = clientConfig;
            _registerEvents     = registerEvents;
            _transportAvailable = transportAvailable;
            _nodeClosing        = nodeClosing;

            _connectTimer = new Timer(TryConnect);
            _initialized  = false;

            _registerEvents(this);

            _pendingRequests = new ConcurrentQueue <IMemcacheRequest>();

            _sendAsynchEvtArgs            = new SocketAsyncEventArgs();
            _sendAsynchEvtArgs.Completed += OnSendRequestComplete;

            _receiveHeaderAsynchEvtArgs = new SocketAsyncEventArgs();
            _receiveHeaderAsynchEvtArgs.SetBuffer(new byte[MemcacheResponseHeader.Size], 0, MemcacheResponseHeader.Size);
            _receiveHeaderAsynchEvtArgs.Completed += OnReceiveHeaderComplete;

            _receiveBodyAsynchEvtArgs            = new SocketAsyncEventArgs();
            _receiveBodyAsynchEvtArgs.Completed += OnReceiveBodyComplete;

            if (planToConnect)
            {
                _connectTimer.Change(0, Timeout.Infinite);
            }
        }
        public MemcacheTransportForTest(EndPoint endpoint, MemcacheClientConfiguration clientConfig, Action<IMemcacheTransport> registerEvents, Action<IMemcacheTransport> transportAvailable, bool planToConnect, Func<bool> nodeClosing, Action onCreate, Action onDispose)
            : base(endpoint, clientConfig, registerEvents, transportAvailable, planToConnect, nodeClosing)
        {
            if (onCreate != null)
                onCreate();

            OnDispose = onDispose;
        }
Example #11
0
        public MemcacheTransportForTest(EndPoint endpoint, MemcacheClientConfiguration clientConfig, Action <IMemcacheTransport> registerEvents, Action <IMemcacheTransport> transportAvailable, bool planToConnect, Func <bool> nodeClosing, Action onCreate, Action onDispose)
            : base(endpoint, clientConfig, registerEvents, transportAvailable, planToConnect, nodeClosing)
        {
            if (onCreate != null)
            {
                onCreate();
            }

            OnDispose = onDispose;
        }
Example #12
0
        public void UnsupportedSerializationThrows()
        {
            var config = new MemcacheClientConfiguration
            {
                ClusterFactory = c => _clusterMock,
            };
            var client = new MemcacheClient(config);

            // assert that both set and get throws NotSupportedException for an unknown type
            Assert.Throws(typeof(NotSupportedException), () => client.Set("Hello", new TestType(), TimeSpan.Zero));
            Assert.Throws(typeof(NotSupportedException), () => client.Get("Hello", (Status s, TestType v) => { }));
        }
Example #13
0
        /// <summary>
        /// The constructor, see @MemcacheClientConfiguration for details
        /// </summary>
        /// <param name="configuration"></param>
        public MemcacheClient(MemcacheClientConfiguration configuration)
        {
            if (configuration == null)
            {
                throw new ArgumentException("Client config should not be null");
            }

            _configuration        = configuration;
            _cluster              = (configuration.ClusterFactory ?? MemcacheClientConfiguration.DefaultClusterFactory)(configuration);
            _cluster.NodeAdded   += RegisterEvents;
            _cluster.NodeRemoved += UnregisterEvents;
            _cluster.Initialize();
        }
Example #14
0
        public MemcacheNode(EndPoint endPoint, MemcacheClientConfiguration configuration)
        {
            if (configuration == null)
                throw new ArgumentException("Client config should not be null");

            _configuration = configuration;
            _endPoint = endPoint;
            _tokenSource = new CancellationTokenSource();
            _transportPool = new BlockingCollection<IMemcacheTransport>(new ConcurrentStack<IMemcacheTransport>());

            for (int i = 0; i < configuration.PoolSize; ++i)
                (configuration.TransportFactory ?? MemcacheTransport.DefaultAllocator)
                    (endPoint, configuration, RegisterEvents, TransportAvailable, false, IsClosing);
        }
 public FakeTransport Factory(EndPoint endPoint,
                              MemcacheClientConfiguration clientConfig,
                              Action <IMemcacheTransport> registerEvents,
                              Action <IMemcacheTransport> transportAvailable,
                              bool autoConnect,
                              Func <bool> nodeClosing)
 {
     registerEvents(this);
     _transportAvailable = transportAvailable;
     if (transportAvailable != null)
     {
         transportAvailable(this);
     }
     return(this);
 }
Example #16
0
        public void MemcacheTransportDisposeBasicTest(int nbOfNodes, int nbOfTransportsPerNode)
        {
            int createdTransports  = 0;
            int disposedTransports = 0;

            // Memcache client config
            var config = new MemcacheClientConfiguration
            {
                DeadTimeout = TimeSpan.FromSeconds(1),
                TransportConnectTimerPeriod = TimeSpan.FromMilliseconds(100),
                TransportFactory            = (_, __, ___, ____, _____, ______) =>
                {
                    return(new MemcacheTransportForTest(_, __, ___, ____, _____, ______, () => { createdTransports++; }, () => { disposedTransports++; }));
                },
                PoolSize = nbOfTransportsPerNode,
            };

            var serverMocks = new List <ServerMock>(nbOfNodes);

            try
            {
                for (int p = 0; p < nbOfNodes; p++)
                {
                    var serverMock = new ServerMock();
                    config.NodesEndPoints.Add(serverMock.ListenEndPoint);
                    serverMocks.Add(serverMock);
                }

                // Create Memcache client
                var memcacheClient = new MemcacheClient(config);

                // Test the number of transports that have been created
                Assert.AreEqual(nbOfNodes * nbOfTransportsPerNode, createdTransports, "Expected number of transports = number of nodes * poolSize");

                // Dispose the client and test that the number of transports is back to zero
                memcacheClient.Dispose();
                Assert.AreEqual(createdTransports, disposedTransports, "Expected all the transports to be disposed");
            }
            finally
            {
                foreach (var mock in serverMocks)
                {
                    mock.Dispose();
                }
            }
        }
        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");
        }
Example #18
0
        public void Setup()
        {
            _configuration = new MemcacheClientConfiguration
            {
                QueueTimeout = 0,
                NodeFactory  = (ipendpoint, config, dispose) => new NodeMock {
                    EndPoint = ipendpoint, DefaultResponse = Status.NoError,
                },
            };

            _configuration.NodesEndPoints.Add(new IPEndPoint(new IPAddress(new byte[] { 192, 168, 18, 1 }), 11211));
            _configuration.NodesEndPoints.Add(new IPEndPoint(new IPAddress(new byte[] { 192, 168, 18, 2 }), 11211));
            _configuration.NodesEndPoints.Add(new IPEndPoint(new IPAddress(new byte[] { 192, 168, 18, 3 }), 11211));
            _configuration.NodesEndPoints.Add(new IPEndPoint(new IPAddress(new byte[] { 192, 168, 18, 4 }), 11211));
            _configuration.NodesEndPoints.Add(new IPEndPoint(new IPAddress(new byte[] { 192, 168, 18, 5 }), 11211));
            _configuration.NodesEndPoints.Add(new IPEndPoint(new IPAddress(new byte[] { 192, 168, 18, 6 }), 11211));
            _configuration.NodesEndPoints.Add(new IPEndPoint(new IPAddress(new byte[] { 192, 168, 18, 7 }), 11211));
            _configuration.NodesEndPoints.Add(new IPEndPoint(new IPAddress(new byte[] { 192, 168, 18, 8 }), 11211));
        }
Example #19
0
        public void TestSetUp()
        {
            _counters  = new TestCounters();
            _mreConfig = new ManualResetEventSlim();

            var config = new MemcacheClientConfiguration()
            {
                TransportConnectTimerPeriod = Timeout.InfiniteTimeSpan,
                NodeFactory = (ipendpoint, _) => new NodeMock {
                    EndPoint = ipendpoint, DefaultResponse = Status.NoError
                },
            };

            _cluster              = new CouchbaseCluster(config, "Some.Bucket", TimeSpan.FromSeconds(30), new[] { new IPEndPoint(0, 0) });
            _cluster.NodeAdded   += _ => _counters.IncrementNodesAdded();
            _cluster.NodeRemoved += _ => _counters.IncrementNodesRemoved();
            _cluster.OnError     += e => { _counters.IncrementErrors(); Console.Error.WriteLine(e.Message); Console.Error.WriteLine(e.StackTrace); };
            _cluster.OnConfig    += () => _mreConfig.Set();
        }
Example #20
0
        public void ExecutionContextShouldFlow()
        {
            var config = new MemcacheClientConfiguration
            {
                ClusterFactory = c => _clusterMock,
            };
            var client = new MemcacheClient(config);

            object value = null;

            _extra = new byte[] { 0, 0, 0, 0 };

            CallContext.LogicalSetData(CallContextKey, "OK");

            client.Get("test", (Status s, byte[] v) =>
            {
                value = CallContext.LogicalGetData("MemcacheClientTest");
            });

            Assert.AreEqual("OK", value, "The execution context didn't flow");
        }
Example #21
0
        /// <summary>
        /// The constructor, see @MemcacheClientConfiguration for details
        /// </summary>
        /// <param name="configuration"></param>
        public MemcacheClient(MemcacheClientConfiguration configuration)
        {
            if (configuration == null)
            {
                throw new ArgumentException("Client config should not be null");
            }

            OngoingDispose = false;

            _configuration = configuration;
            _locator       = configuration.NodeLocator ?? MemcacheClientConfiguration.DefaultLocatorFactory();
            _nodes         = new List <IMemcacheNode>(configuration.NodesEndPoints.Count);

            foreach (var nodeEndPoint in configuration.NodesEndPoints)
            {
                var node = (configuration.NodeFactory ?? MemcacheClientConfiguration.DefaultNodeFactory)(nodeEndPoint, configuration, this);
                _nodes.Add(node);
                RegisterEvents(node);
            }

            _locator.Initialize(_nodes);
        }
Example #22
0
        public void SerializationThrows()
        {
            var serializerMoq = new Mock <ISerializer <TestType> >();

            serializerMoq.Setup(s => s.FromBytes(It.IsAny <byte[]>())).Throws(new SerializationException());
            serializerMoq.Setup(s => s.ToBytes(It.IsAny <TestType>())).Throws(new SerializationException());
            serializerMoq.Setup(s => s.TypeFlag).Returns(314);

            Exception raised = null;

            var config = new MemcacheClientConfiguration
            {
                ClusterFactory = c => _clusterMock,
            };
            var serialiserMoqObj = serializerMoq.Object;

            config.SetSerializer(serialiserMoqObj);
            var client = new MemcacheClient(config);

            client.CallbackError += e => raised = e;

            // test that the throws of the serializer is synchronously propagated
            Assert.Throws(typeof(SerializationException), () => client.Set("Hello", new TestType(), TimeSpan.Zero));

            // test that the failing serializer does not synchronously throws but sends a CallbackError event
            _responseHeader = new MemcacheResponseHeader
            {
                ExtraLength     = 4,
                TotalBodyLength = 4,
                Opcode          = Opcode.Get,
            };
            _extra = new byte[] { 0, 0, 0, 0 };
            Assert.True(client.Get("Hello", (Status s, TestType v) => { }));
            Assert.IsNotNull(raised);
            Assert.IsInstanceOf <SerializationException>(raised);
        }
Example #23
0
        public void MemcacheTransportDisposeBasicTest(int nbOfNodes, int nbOfTransportsPerNode)
        {
            int createdTransports = 0;
            int disposedTransports = 0;

            // Memcache client config
            var config = new MemcacheClientConfiguration
            {
                DeadTimeout = TimeSpan.FromSeconds(1),
                TransportConnectTimerPeriod = TimeSpan.FromMilliseconds(100),
                TransportFactory = (_, __, ___, ____, _____, ______) =>
                    new MemcacheTransportForTest(_, __, ___, ____, _____, ______, () => { createdTransports++; }, () => { disposedTransports++; }),
                PoolSize = nbOfTransportsPerNode,
            };

            var serverMocks = new List<ServerMock>(nbOfNodes);
            try
            {
                for (int p = 0; p < nbOfNodes; p++)
                {
                    var serverMock = new ServerMock();
                    config.NodesEndPoints.Add(serverMock.ListenEndPoint);
                    serverMocks.Add(serverMock);
                }

                // Create Memcache client
                var memcacheClient = new MemcacheClient(config);

                // Test the number of transports that have been created
                Assert.AreEqual(nbOfNodes * nbOfTransportsPerNode, createdTransports, "Expected number of transports = number of nodes * poolSize");

                // Dispose the client and test that the number of transports is back to zero
                memcacheClient.Dispose();
                Assert.AreEqual(createdTransports, disposedTransports, "Expected all the transports to be disposed");
            }
            finally
            {
                foreach (var mock in serverMocks)
                {
                    mock.Dispose();
                }
            }
        }
        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();
            }
        }
        public void ReceiveFailConsistency([Values(true, false)] bool failInBody)
        {
            using (var serverMock = new ServerMock())
            {
                var endpoint = serverMock.ListenEndPoint;
                serverMock.ResponseBody = new byte[24];
                if (failInBody)
                {
                    // the Opaque vs RequestId is check in the body receiving callback
                    // I put 2 different values
                    new MemcacheResponseHeader
                    {
                        Cas             = 8,
                        DataType        = 12,
                        ExtraLength     = 0,
                        KeyLength       = 0,
                        Opaque          = 0,
                        Status          = Status.NoError,
                        Opcode          = Opcode.Set,
                        TotalBodyLength = 0,
                    }.ToData(serverMock.ResponseHeader);
                }
                else
                {
                    // the magic number is checked in the header receiving callback
                    // I corrupt it
                    new MemcacheResponseHeader
                    {
                        Cas             = 8,
                        DataType        = 12,
                        ExtraLength     = 0,
                        KeyLength       = 0,
                        Opaque          = 1,
                        Status          = Status.NoError,
                        Opcode          = Opcode.Set,
                        TotalBodyLength = 0,
                    }.ToData(serverMock.ResponseHeader);
                    serverMock.ResponseHeader.CopyFrom(0, (uint)42);
                }

                var config = new MemcacheClientConfiguration
                {
                    PoolSize = 1,
                };

                var node          = new Memcache.Node.MemcacheNode(endpoint, config);
                var errorMutex    = new ManualResetEventSlim(false);
                var callbackMutex = new ManualResetEventSlim(false);

                Exception expectedException = null;
                node.TransportError += e =>
                {
                    Interlocked.Exchange <Exception>(ref expectedException, e);
                    errorMutex.Set();
                };
                int nodeAliveCount = 0;
                node.NodeAlive += t => ++ nodeAliveCount;
                int nodeDeadCount = 0;
                node.NodeDead += t => ++ nodeDeadCount;

                Status receivedStatus = Status.NoError;
                node.TrySend(
                    new SetRequest
                {
                    RequestOpcode = Opcode.Set,
                    RequestId     = 1,
                    Expire        = TimeSpan.FromSeconds(1),
                    Key           = "Key".Select(c => (byte)c).ToArray(),
                    Message       = new byte[] { 0, 1, 2, 3, 4 },
                    CallBack      = s =>
                    {
                        receivedStatus = s;
                        callbackMutex.Set();
                    },
                }, 1000);
                // must wait before the next test because the TransportError event is fired after the callback call

                // Expected result :
                // * The callback must have been called before 1 sec
                // * The failure callback must have been called, so the received status must be InternalError
                // * An MemcacheException should have been raised by the receive due to the bad response
                // * The node should have exaclty one transport in its pool
                //      more mean that we added it twice after a failure, less means we didn't putted it back in the pool
                // * The node should not be seen has dead yet

                Assert.IsTrue(callbackMutex.Wait(1000), @"The 1st callback has not been received after 1 second");
                Assert.IsTrue(errorMutex.Wait(1000), @"The 1st error has not been received after 1 second");
                Assert.AreEqual(Status.InternalError, receivedStatus, @"A bad response has not sent an InternalError to the request callback");
                Assert.IsInstanceOf <Memcache.Exceptions.MemcacheException>(expectedException, @"A bad response has not triggered a transport error. Expected a MemcacheException.");
                Assert.AreEqual(0, nodeDeadCount, @"The node has been detected has dead before a new send has been made");
                // After a short delay, the transport should be back in the transport pool (node.PoolSize == 1)
                Assert.That(() => node.PoolSize, new DelayedConstraint(new EqualConstraint(1), 2000, 100), "After a while, the transport should be back in the pool");

                new MemcacheResponseHeader
                {
                    Cas         = 8,
                    DataType    = 12,
                    ExtraLength = 0,
                    KeyLength   = 0,
                    // must be the same or it will crash : TODO add a test to ensure we detect this fail
                    Opaque          = 1,
                    Status          = Status.NoError,
                    Opcode          = Opcode.Set,
                    TotalBodyLength = 0,
                }.ToData(serverMock.ResponseHeader);

                serverMock.ResponseBody = null;
                expectedException       = null;
                callbackMutex.Reset();
                receivedStatus = Status.NoError;

                var result = node.TrySend(
                    new SetRequest
                {
                    RequestOpcode = Opcode.Set,
                    RequestId     = 1,
                    Expire        = TimeSpan.FromSeconds(1),
                    Key           = "Key".Select(c => (byte)c).ToArray(),
                    Message       = new byte[] { 0, 1, 2, 3, 4 },
                    CallBack      = s =>
                    {
                        receivedStatus = s;
                        callbackMutex.Set();
                    },
                }, 1000);

                // Expected result :
                // * An SocketException should have been raised by the send, since the previous receice has disconnected the socket
                // * The return must be true, because the request have been enqueued before the transport seen the socket died
                // * The failure callback must have been called, so the received status must be InternalError

                Assert.IsTrue(callbackMutex.Wait(1000), @"The 2nd callback has not been received after 1 second");
                Assert.IsTrue(result, @"The first failed request should not see a false return");
                Assert.AreEqual(Status.InternalError, receivedStatus, @"The send operation should have detected that the socket is dead");

                // After a short delay, the transport should connect
                Assert.That(() => node.PoolSize, new DelayedConstraint(new EqualConstraint(1), 2000, 100), "After a while, the transport should manage to connect");

                expectedException = null;
                callbackMutex.Reset();
                result = node.TrySend(
                    new SetRequest
                {
                    RequestOpcode = Opcode.Set,
                    RequestId     = 1,
                    Expire        = TimeSpan.FromSeconds(1),
                    Key           = "Key".Select(c => (byte)c).ToArray(),
                    Message       = new byte[] { 0, 1, 2, 3, 4 },
                    CallBack      = s =>
                    {
                        receivedStatus = s;
                        callbackMutex.Set();
                    },
                }, 1000);

                // Expected result : everything should works fine now
                // * The return must be true, because the new transport should be available now
                // * No exception should have been raised
                // * The callback must have been called and with a NoError status

                Assert.IsTrue(result, @"The node has not been able to send a new request after a disconnection");
                Assert.IsTrue(callbackMutex.Wait(1000), @"The message has not been received after 1 second, case after reconnection");
                Assert.AreEqual(Status.NoError, receivedStatus, @"The response after a reconnection is still not NoError");
                Assert.IsNull(expectedException, "The request shouldn't have thrown an exception");
            }
        }
        public void ReceiveFailConsistency([Values(true, false)] bool failInBody)
        {
            using (var serverMock = new ServerMock())
            {
                var endpoint = serverMock.ListenEndPoint;
                serverMock.ResponseBody = new byte[24];
                if (failInBody)
                {
                    // the Opaque vs RequestId is check in the body receiving callback
                    // I put 2 different values
                    new MemcacheResponseHeader
                    {
                        Cas = 8,
                        DataType = 12,
                        ExtraLength = 0,
                        KeyLength = 0,
                        Opaque = 0,
                        Status = Status.NoError,
                        Opcode = Opcode.Set,
                        TotalBodyLength = 0,
                    }.ToData(serverMock.ResponseHeader);
                }
                else
                {
                    // the magic number is checked in the header receiving callback
                    // I corrupt it
                    new MemcacheResponseHeader
                    {
                        Cas = 8,
                        DataType = 12,
                        ExtraLength = 0,
                        KeyLength = 0,
                        Opaque = 1,
                        Status = Status.NoError,
                        Opcode = Opcode.Set,
                        TotalBodyLength = 0,
                    }.ToData(serverMock.ResponseHeader);
                    serverMock.ResponseHeader.CopyFrom(0, (uint)42);
                }

                var config = new MemcacheClientConfiguration
                {
                    PoolSize = 1,
                };

                var node = new Memcache.Node.MemcacheNode(endpoint, config);
                var errorMutex = new ManualResetEventSlim(false);
                var callbackMutex = new ManualResetEventSlim(false);

                Exception expectedException = null;
                node.TransportError += e =>
                    {
                        Interlocked.Exchange<Exception>(ref expectedException, e);
                        errorMutex.Set();
                    };
                int nodeAliveCount = 0;
                node.NodeAlive += t => ++nodeAliveCount;
                int nodeDeadCount = 0;
                node.NodeDead += t => ++nodeDeadCount;

                Status receivedStatus = Status.NoError;
                node.TrySend(
                    new SetRequest
                    {
                        RequestOpcode = Opcode.Set,
                        RequestId = 1,
                        Expire = TimeSpan.FromSeconds(1),
                        Key = "Key".Select(c => (byte)c).ToArray(),
                        Message = new byte[] { 0, 1, 2, 3, 4 },
                        CallBack = s =>
                        {
                            receivedStatus = s;
                            callbackMutex.Set();
                        },
                    }, 1000);
                // must wait before the next test because the TransportError event is fired after the callback call

                // Expected result :
                // * The callback must have been called before 1 sec
                // * The failure callback must have been called, so the received status must be InternalError
                // * An MemcacheException should have been raised by the receive due to the bad response
                // * The node should have exaclty one transport in its pool
                //      more mean that we added it twice after a failure, less means we didn't putted it back in the pool
                // * The node should not be seen has dead yet

                Assert.IsTrue(callbackMutex.Wait(1000), @"The 1st callback has not been received after 1 second");
                Assert.IsTrue(errorMutex.Wait(1000), @"The 1st error has not been received after 1 second");
                Assert.AreEqual(Status.InternalError, receivedStatus, @"A bad response has not sent an InternalError to the request callback");
                Assert.IsInstanceOf<Memcache.Exceptions.MemcacheException>(expectedException, @"A bad response has not triggered a transport error. Expected a MemcacheException.");
                Assert.AreEqual(0, nodeDeadCount, @"The node has been detected has dead before a new send has been made");
                // After a short delay, the transport should be back in the transport pool (node.PoolSize == 1)
                Assert.That(() => node.PoolSize, new DelayedConstraint(new EqualConstraint(1), 2000, 100), "After a while, the transport should be back in the pool");

                new MemcacheResponseHeader
                {
                    Cas = 8,
                    DataType = 12,
                    ExtraLength = 0,
                    KeyLength = 0,
                    // must be the same or it will crash : TODO add a test to ensure we detect this fail
                    Opaque = 1,
                    Status = Status.NoError,
                    Opcode = Opcode.Set,
                    TotalBodyLength = 0,
                }.ToData(serverMock.ResponseHeader);

                serverMock.ResponseBody = null;
                expectedException = null;
                callbackMutex.Reset();
                receivedStatus = Status.NoError;

                var result = node.TrySend(
                    new SetRequest
                    {
                        RequestOpcode = Opcode.Set,
                        RequestId = 1,
                        Expire = TimeSpan.FromSeconds(1),
                        Key = "Key".Select(c => (byte)c).ToArray(),
                        Message = new byte[] { 0, 1, 2, 3, 4 },
                        CallBack = s =>
                        {
                            receivedStatus = s;
                            callbackMutex.Set();
                        },
                    }, 1000);

                // Expected result :
                // * An SocketException should have been raised by the send, since the previous receice has disconnected the socket
                // * The return must be true, because the request have been enqueued before the transport seen the socket died
                // * The failure callback must have been called, so the received status must be InternalError

                Assert.IsTrue(callbackMutex.Wait(1000), @"The 2nd callback has not been received after 1 second");
                Assert.IsTrue(result, @"The first failed request should not see a false return");
                Assert.AreEqual(Status.InternalError, receivedStatus, @"The send operation should have detected that the socket is dead");

                // After a short delay, the transport should connect
                Assert.That(() => node.PoolSize, new DelayedConstraint(new EqualConstraint(1), 2000, 100), "After a while, the transport should manage to connect");

                expectedException = null;
                callbackMutex.Reset();
                result = node.TrySend(
                    new SetRequest
                    {
                        RequestOpcode = Opcode.Set,
                        RequestId = 1,
                        Expire = TimeSpan.FromSeconds(1),
                        Key = "Key".Select(c => (byte)c).ToArray(),
                        Message = new byte[] { 0, 1, 2, 3, 4 },
                        CallBack = s =>
                        {
                            receivedStatus = s;
                            callbackMutex.Set();
                        },
                    }, 1000);

                // Expected result : everything should works fine now
                // * The return must be true, because the new transport should be available now
                // * No exception should have been raised
                // * The callback must have been called and with a NoError status

                Assert.IsTrue(result, @"The node has not been able to send a new request after a disconnection");
                Assert.IsTrue(callbackMutex.Wait(1000), @"The message has not been received after 1 second, case after reconnection");
                Assert.AreEqual(Status.NoError, receivedStatus, @"The response after a reconnection is still not NoError");
                Assert.IsNull(expectedException, "The request shouldn't have thrown an exception");
            }
        }
Example #27
0
        public void MemcacheTransportDisposeTransportNotInPoolTest()
        {
            int    createdTransports  = 0;
            int    disposedTransports = 0;
            var    mutex1             = new ManualResetEventSlim(false);
            var    mutex2             = new ManualResetEventSlim(false);
            Status returnStatus       = Status.NoError;

            // Memcache client config
            var config = new MemcacheClientConfiguration
            {
                DeadTimeout = TimeSpan.FromSeconds(1),
                TransportConnectTimerPeriod = TimeSpan.FromMilliseconds(100),
                TransportFactory            = (_, __, ___, ____, _____, ______) =>
                                              new MemcacheTransportForTest(_, __, ___, ____, _____, ______, () => { createdTransports++; }, () => { disposedTransports++; mutex1.Set(); }),
                PoolSize = 1,
            };

            MemcacheClient memcacheClient;

            using (var serverMock = new ServerMock())
            {
                config.NodesEndPoints.Add(serverMock.ListenEndPoint);
                serverMock.ResponseBody = new byte[24];

                // Create Memcache client
                memcacheClient = new MemcacheClient(config);

                // Test the number of transports that have been created
                Assert.AreEqual(1, createdTransports);

                // Do a get to initialize the transport
                Assert.IsTrue(memcacheClient.Get("whatever", (Status s, byte[] o) => { returnStatus = s; mutex2.Set(); }));
                Assert.IsTrue(mutex2.Wait(1000), "Timeout on the get request");
                Assert.AreEqual(Status.InternalError, returnStatus);
                mutex2.Reset();
            }

            // Wait for the ServerMock to be fully disposed
            Thread.Sleep(100);

            // Attempt to send a request to take the transport out of the pool
            Assert.IsTrue(memcacheClient.Get("whatever", (Status s, byte[] o) => { returnStatus = s; mutex2.Set(); }));
            Assert.IsTrue(mutex2.Wait(1000), "Timeout on the get request");
            Assert.AreEqual(Status.InternalError, returnStatus);
            mutex2.Reset();

            // The initial transport should now be disposed, a new transport has been allocated and
            // is periodically trying to reconnect
            Assert.IsTrue(mutex1.Wait(1000), "Timeout on initial transport disposal");
            Assert.AreEqual(1, disposedTransports, "Expected the initial transport to be disposed");
            Assert.AreEqual(2, createdTransports, "Expected a new transport to be created to replace the disposed one");

            mutex1.Reset();

            // Dispose the client
            memcacheClient.Dispose();

            // Wait enough time for the reconnect timer to fire at least once
            Assert.IsTrue(mutex1.Wait(4000), "MemcacheTransport was not disposed before the timeout");

            // Check that all transports have been disposed
            Assert.AreEqual(2, disposedTransports);
            Assert.AreEqual(createdTransports, disposedTransports);
        }
        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 TransportDeadThenAliveTest()
        {
            IMemcacheNode theNode = null;
            FakeTransport transport = new FakeTransport();
            transport.Kill();

            // Memcache client config
            var config = new MemcacheClientConfiguration
            {
                DeadTimeout = TimeSpan.FromSeconds(1),
                TransportFactory = transport.Factory,
                NodeFactory = (e, c) =>  MemcacheClientConfiguration.DefaultNodeFactory(e, c),
                PoolSize = 1,
            };

            theNode = config.NodeFactory(null, config);
            Assert.IsFalse(theNode.IsDead, "The node should be alive before any failure");

            Assert.IsFalse(theNode.TrySend(null, 1), "The TrySend should fail with a broken transport");
            Assert.IsTrue(theNode.IsDead, "The node should be dead after the first send failed");

            transport.Resurect();
            Assert.IsFalse(theNode.IsDead, "The node should be alive after the transport resurected");
            Assert.IsTrue(theNode.TrySend(null, 1), "The TrySend should be able to send a request after the transport is up again");

            transport.Kill();
            Assert.IsFalse(theNode.TrySend(null, 1), "The TrySend should fail with a killed transport");
            Assert.IsTrue(theNode.IsDead, "The node should be dead after the a send failed");
        }
 public FakeTransport Factory(EndPoint endPoint,
     MemcacheClientConfiguration clientConfig,
     Action<IMemcacheTransport> registerEvents,
     Action<IMemcacheTransport> transportAvailable,
     bool autoConnect,
     Func<bool> nodeClosing)
 {
     registerEvents(this);
     _transportAvailable = transportAvailable;
     if (transportAvailable != null)
         transportAvailable(this);
     return this;
 }
        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();
            }
        }
Example #32
0
        public void UnsupportedSerializationThrows()
        {
            var config = new MemcacheClientConfiguration
            {
                ClusterFactory = c => _clusterMock,
            };
            var client = new MemcacheClient(config);

            // assert that both set and get throws NotSupportedException for an unknown type
            Assert.Throws(typeof(NotSupportedException), () => client.Set("Hello", new TestType(), TimeSpan.Zero));
            Assert.Throws(typeof(NotSupportedException), () => client.Get("Hello", (Status s, TestType v) => { }));
        }
Example #33
0
        public void MemcacheTransportDisposeTransportNotInPoolTest()
        {
            int createdTransports = 0;
            int disposedTransports = 0;
            var mutex1 = new ManualResetEventSlim(false);
            var mutex2 = new ManualResetEventSlim(false);
            Status returnStatus = Status.NoError;

            // Memcache client config
            var config = new MemcacheClientConfiguration
            {
                DeadTimeout = TimeSpan.FromSeconds(1),
                TransportConnectTimerPeriod = TimeSpan.FromMilliseconds(100),
                TransportFactory = (_, __, ___, ____, _____, ______) =>
                    new MemcacheTransportForTest(_, __, ___, ____, _____, ______, () => { createdTransports++; }, () => { disposedTransports++; mutex1.Set(); }),
                PoolSize = 1,
            };

            MemcacheClient memcacheClient;
            using (var serverMock = new ServerMock())
            {
                config.NodesEndPoints.Add(serverMock.ListenEndPoint);
                serverMock.ResponseBody = new byte[24];

                // Create Memcache client
                memcacheClient = new MemcacheClient(config);

                // Test the number of transports that have been created
                Assert.AreEqual(1, createdTransports);

                // Do a get to initialize the transport
                Assert.IsTrue(memcacheClient.Get("whatever", (Status s, byte[] o) => { returnStatus = s; mutex2.Set(); }));
                Assert.IsTrue(mutex2.Wait(1000), "Timeout on the get request");
                Assert.AreEqual(Status.InternalError, returnStatus);
                mutex2.Reset();
            }

            // Wait for the ServerMock to be fully disposed
            Thread.Sleep(100);

            // Attempt to send a request to take the transport out of the pool
            Assert.IsTrue(memcacheClient.Get("whatever", (Status s, byte[] o) => { returnStatus = s; mutex2.Set(); }));
            Assert.IsTrue(mutex2.Wait(1000), "Timeout on the get request");
            Assert.AreEqual(Status.InternalError, returnStatus);
            mutex2.Reset();

            // The initial transport should now be disposed, a new transport has been allocated and
            // is periodically trying to reconnect
            Assert.IsTrue(mutex1.Wait(1000), "Timeout on initial transport disposal");
            Assert.AreEqual(1, disposedTransports, "Expected the initial transport to be disposed");
            Assert.AreEqual(2, createdTransports, "Expected a new transport to be created to replace the disposed one");

            mutex1.Reset();

            // Dispose the client
            memcacheClient.Dispose();

            // Wait enough time for the reconnect timer to fire at least once
            Assert.IsTrue(mutex1.Wait(4000), "MemcacheTransport was not disposed before the timeout");

            // Check that all transports have been disposed
            Assert.AreEqual(2, disposedTransports);
            Assert.AreEqual(createdTransports, disposedTransports);
        }
Example #34
0
 public StaticCluster(MemcacheClientConfiguration configuration)
 {
     _configuration = configuration;
 }
Example #35
0
 public StaticCluster(MemcacheClientConfiguration configuration)
 {
     _configuration = configuration;
 }
Example #36
0
        public void Setup()
        {
            _configuration = new MemcacheClientConfiguration
            {
                QueueTimeout = 0,
                NodeFactory = (ipendpoint, config) => new NodeMock { EndPoint = ipendpoint, DefaultResponse = Status.NoError, },
            };

            _configuration.NodesEndPoints.Add(new IPEndPoint(new IPAddress(new byte[] { 192, 168, 18, 1 }), 11211));
            _configuration.NodesEndPoints.Add(new IPEndPoint(new IPAddress(new byte[] { 192, 168, 18, 2 }), 11211));
            _configuration.NodesEndPoints.Add(new IPEndPoint(new IPAddress(new byte[] { 192, 168, 18, 3 }), 11211));
            _configuration.NodesEndPoints.Add(new IPEndPoint(new IPAddress(new byte[] { 192, 168, 18, 4 }), 11211));
            _configuration.NodesEndPoints.Add(new IPEndPoint(new IPAddress(new byte[] { 192, 168, 18, 5 }), 11211));
            _configuration.NodesEndPoints.Add(new IPEndPoint(new IPAddress(new byte[] { 192, 168, 18, 6 }), 11211));
            _configuration.NodesEndPoints.Add(new IPEndPoint(new IPAddress(new byte[] { 192, 168, 18, 7 }), 11211));
            _configuration.NodesEndPoints.Add(new IPEndPoint(new IPAddress(new byte[] { 192, 168, 18, 8 }), 11211));
        }