public void AuthenticationFailed() { var sentMutex = new ManualResetEventSlim(false); using (var serverStub = new ServerMock()) { IMemcacheRequest authenticationRequest = null; // a token that fails var authenticatorTokenFailing = new Moq.Mock<IAuthenticationToken>(); authenticatorTokenFailing .Setup(t => t.StepAuthenticate(Moq.It.IsAny<TimeSpan>(), out authenticationRequest)) .Returns(Status.TemporaryFailure); // a token that works var authenticatorTokenOk = new Moq.Mock<IAuthenticationToken>(); authenticatorTokenOk .Setup(t => t.StepAuthenticate(Moq.It.IsAny<TimeSpan>(), out authenticationRequest)) .Returns(Status.NoError); // an authenticator that returns one failing token followed by working tokens bool alreadyFailed = false; var authenticator = new Moq.Mock<IMemcacheAuthenticator>(); authenticator .Setup(auth => auth.CreateToken()) .Returns(() => { if (alreadyFailed) return authenticatorTokenOk.Object; alreadyFailed = true; return authenticatorTokenFailing.Object; }); // setup the request to send bool requestFailed = false; bool requestAchieved = false; var request = new Moq.Mock<IMemcacheRequest>(); request .Setup(r => r.Fail()) .Callback(() => { requestFailed = true; sentMutex.Set(); }); request .Setup(r => r.HandleResponse( Moq.It.Is<Headers.MemcacheResponseHeader>(h => h.Status == Status.NoError), Moq.It.IsAny<byte[]>(), Moq.It.IsAny<byte[]>(), Moq.It.IsAny<byte[]>())) .Callback(() => { requestAchieved = true; sentMutex.Set(); }); var queryBuffer = new byte[MemcacheRequestHeader.Size]; new MemcacheRequestHeader().ToData(queryBuffer); request .Setup(r => r.GetQueryBuffer()) .Returns(queryBuffer); IMemcacheTransport transportToWork = null; var transportToFail = new MemcacheTransport( serverStub.ListenEndPoint, new MemcacheClientConfiguration { SocketTimeout = TimeSpan.Zero, Authenticator = authenticator.Object, }, _ => { }, t => { Interlocked.Exchange(ref transportToWork, t); }, false, () => false); new MemcacheResponseHeader { Status = Status.NoError, Opcode = Opcode.Get, }.ToData(serverStub.ResponseHeader); Exception raised = null; transportToFail.TransportError += e => // when the transport fails collect the exception Interlocked.Exchange(ref raised, e); var sent = transportToFail.TrySend(request.Object); Assert.IsFalse(sent, "The request send should fail"); Assert.IsNotNull(raised, "The authentication should have failed"); // wait for reconnection to happen (should be done in a instant timer) Assert.That(ref transportToWork, (!Is.Null).After(1000, 10), "The working transport should have been set"); sent = transportToWork.TrySend(request.Object); Assert.IsTrue(sent, "The request should have been sent"); var received = sentMutex.Wait(TimeSpan.FromMinutes(5)); Assert.IsTrue(received, "The response should have been received"); Assert.IsFalse(requestFailed, "The request should not have failed"); Assert.IsTrue(requestAchieved, "The request should have achieved"); } }
public void MemcacheSocketTest([Values(0, 2, 10)]int maxByteSentByServer) { using (var serverMock = new ServerMock()) { var endPoint = serverMock.ListenEndPoint; serverMock.MaxSent = maxByteSentByServer; // random header var requestHeader = new MemcacheRequestHeader { Cas = 1, DataType = 2, ExtraLength = 5, KeyLength = 3, Opaque = 42, Opcode = Opcode.Increment, TotalBodyLength = 12, }; // body with the size defined in the header var requestBody = new byte[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12 }; // build the request buffer var requestBuffer = new byte[MemcacheRequestHeader.Size + requestHeader.TotalBodyLength]; requestHeader.ToData(requestBuffer); Array.Copy(requestBody, 0, requestBuffer, MemcacheRequestHeader.Size, requestHeader.TotalBodyLength); // build the response header var responseHeader = new MemcacheResponseHeader { Cas = 8, DataType = 12, ExtraLength = 3, KeyLength = 0, // must be the same or it will crash : TODO add a test to ensure we detect this fail Opaque = requestHeader.Opaque, Status = Status.UnknownCommand, Opcode = Opcode.Prepend, TotalBodyLength = 15, }; // body with the size defined in the header var responseExtra = new byte[] { 1, 2, 3 }; var responseMessage = new byte[] { 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 }; // build the request buffer var responseBody = new byte[responseHeader.TotalBodyLength]; Array.Copy(responseExtra, 0, responseBody, 0, responseHeader.ExtraLength); Array.Copy(responseMessage, 0, responseBody, responseHeader.ExtraLength, responseHeader.TotalBodyLength - responseHeader.ExtraLength); // set the things to answer to the server serverMock.ResponseBody = responseBody; responseHeader.ToData(serverMock.ResponseHeader); var request = new RequestMock { QueryBuffer = requestBuffer, RequestId = requestHeader.Opaque /*ResponseHeader = responseHeader, Message = responseMessage, Extra = responseExtra,*/ }; using (var transport = new MemcacheTransport(endPoint, new MemcacheClientConfiguration(), _ => { }, _ => { }, false, null)) { Assert.IsTrue(transport.TrySend(request)); Assert.IsTrue(request.Mutex.Wait(TimeSpan.FromSeconds(10)), "The request has not been completed on less than 10 sec"); // and now, assert that we sent what we had to send and we received what the server sent Assert.AreEqual(requestHeader, serverMock.LastReceivedHeader, "Sent header differ from header received by the server"); CollectionAssert.AreEqual(requestBody, serverMock.LastReceivedBody, "Sent body is different than received by the server"); Assert.AreEqual(responseHeader, request.ResponseHeader, "Received header differ from header sent by the server"); CollectionAssert.AreEqual(responseExtra, request.Extra, "Received extra is different than sent by the server"); CollectionAssert.AreEqual(responseMessage, request.Message, "Received message is different than sent by the server"); } } }
public void QueueFullTest() { var config = new Configuration.MemcacheClientConfiguration { QueueLength = 1, }; int transportAvailablized = 0; using (var serverMock = new ServerMock()) using (var transportToTest = new MemcacheTransport(serverMock.ListenEndPoint, config, t => { }, t => Interlocked.Increment(ref transportAvailablized), false, null)) { var requestHeader = new MemcacheResponseHeader { Cas = 1, DataType = 2, ExtraLength = 4, KeyLength = 0, Opaque = 42, Opcode = Opcode.Get, Status = Headers.Status.KeyNotFound, TotalBodyLength = 4, }; requestHeader.ToData(serverMock.ResponseHeader); serverMock.ResponseBody = new byte[4]; serverMock.ReceiveMutex = new ManualResetEventSlim(); var clientMutex = new ManualResetEventSlim(); var request1 = new GetRequest { RequestId = (uint)42, Key = "Hello, world".Select(c => (byte)c).ToArray(), RequestOpcode = Opcode.Get, CallBack = (r, v) => clientMutex.Set(), }; var request2 = new GetRequest { RequestId = (uint)42, Key = "Hello, world".Select(c => (byte)c).ToArray(), RequestOpcode = Opcode.Get, CallBack = (r, v) => { }, }; // we sent a first request and let the server wait before respond Assert.IsTrue(transportToTest.TrySend(request1), "The first request failed to be sent"); Assert.That(() => transportAvailablized, Is.EqualTo(2).After(1000, 50)); // we check that the queue is full, and the transport fail to send a new request Assert.IsFalse(transportToTest.TrySend(request2), "The second request should not have been sent"); // unblocks both server response and callback from client serverMock.ReceiveMutex.Set(); Assert.IsTrue(clientMutex.Wait(1000), "The response callback has not been triggered for the first request"); // make sure that we triggered the transport available after the queue is not full anymore Assert.That(() => transportAvailablized, Is.EqualTo(3).After(1000, 50)); // checks if we can send a new request since the queue is not full anymore Assert.IsTrue(transportToTest.TrySend(request2), "The third request failed to be sent"); Assert.That(() => transportAvailablized, Is.EqualTo(4).After(1000, 50)); } }
public void AuthenticationTest() { var config = new Configuration.MemcacheClientConfiguration { Authenticator = Configuration.MemcacheClientConfiguration.SaslPlainAuthenticatorFactory(string.Empty, "NoLogin", "NoPass"), }; using (var serverMock = new ServerMock()) using (var transport = new MemcacheTransport(serverMock.ListenEndPoint, config, t => { }, t => { }, false, null)) { var mutex = new ManualResetEventSlim(); new MemcacheResponseHeader { Opaque = 0, Opcode = Opcode.StartAuth, Status = Status.NoError, }.ToData(serverMock.ResponseHeader); Status responseStatus = Status.InternalError; Assert.IsTrue(transport.TrySend(new NoOpRequest { RequestId = 0, Callback = h => { mutex.Set(); responseStatus = h.Status; } }) , "Unable to send a request on authenticated transport"); Assert.IsTrue(mutex.Wait(1000), "No response retrived on authenticated transport"); Assert.AreEqual(Status.NoError, responseStatus, "The response returned on error"); } }