Skip to content

Commit

Permalink
Added tests for Handshake, Sender, and Receiver
Browse files Browse the repository at this point in the history
  • Loading branch information
statianzo committed Mar 12, 2011
1 parent 7282510 commit 38b7773
Show file tree
Hide file tree
Showing 7 changed files with 374 additions and 66 deletions.
3 changes: 3 additions & 0 deletions src/Fleck.Tests/Fleck.Tests.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,10 @@
<Reference Include="System.Xml" />
</ItemGroup>
<ItemGroup>
<Compile Include="HandshakeHandlerTests.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="ReceiverTests.cs" />
<Compile Include="SenderTests.cs" />
<Compile Include="WebSocketServerTests.cs" />
</ItemGroup>
<ItemGroup>
Expand Down
174 changes: 174 additions & 0 deletions src/Fleck.Tests/HandshakeHandlerTests.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,174 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Net.Sockets;
using System.Text;
using Moq;
using NUnit.Framework;

namespace Fleck.Tests
{
[TestFixture]
public class HandshakeHandlerTests
{
private HandshakeHandler _handler;

private const string ExampleRequest =
@"GET /demo HTTP/1.1
Host: example.com
Connection: Upgrade
Sec-WebSocket-Key2: 12998 5 Y3 1 .P00
Sec-WebSocket-Protocol: sample
Upgrade: WebSocket
Sec-WebSocket-Key1: 4 @1 46546xW%0l 1 5
Origin: http://example.com
^n:ds[4U";

private const string ExampleResponse =
@"HTTP/1.1 101 WebSocket Protocol Handshake
Upgrade: WebSocket
Connection: Upgrade
Sec-WebSocket-Origin: http://example.com
Sec-WebSocket-Location: ws://example.com/demo
Sec-WebSocket-Protocol: sample
8jKS'y:G*Co,Wxa-";
//From http://www.whatwg.org/specs/web-socket-protocol/ Page 4
const string Key1 = "4 @1 46546xW%0l 1 5";
const string Key2 = "12998 5 Y3 1 .P00";
const string Challenge = "^n:ds[4U";
const string ExpectedAnswer = "8jKS'y:G*Co,Wxa-";

[SetUp]
public void Setup()
{
_handler = new HandshakeHandler(null, "ws://fleck-test.com");
}

[Test]
public void ShouldShake()
{
var fakeSocket = new FakeSocket(ExampleRequest);
_handler.Shake(fakeSocket);
}


[Test]
public void ShouldParseClientHandshake()
{
var requestBytes = Encoding.UTF8.GetBytes(ExampleRequest);
var requestSegment = new ArraySegment<byte>(requestBytes);
var client = HandshakeHandler.ParseClientHandshake(requestSegment);

Assert.AreEqual(Key1, client.Key1);
Assert.AreEqual(Key2, client.Key2);
Assert.AreEqual("http://example.com", client.Origin);
Assert.AreEqual("example.com", client.Host);
var clientChallenge = client.ChallengeBytes.Array.Skip(client.ChallengeBytes.Offset).Take(client.ChallengeBytes.Count).ToArray();
var clientChallengeString = Encoding.UTF8.GetString(clientChallenge);
Assert.AreEqual(Challenge, clientChallengeString);
}

[Test]
public void ShouldGenerateServerHandshake()
{
var requestBytes = Encoding.UTF8.GetBytes(ExampleRequest);
var requestSegment = new ArraySegment<byte>(requestBytes);
var client = HandshakeHandler.ParseClientHandshake(requestSegment);
_handler.ClientHandshake = client;
var server = _handler.GenerateResponseHandshake();

Assert.IsTrue(server.Location.Contains(client.Host));
var answer = Encoding.UTF8.GetString(server.AnswerBytes);
Assert.AreEqual(ExpectedAnswer,answer);

Assert.AreEqual(ExampleResponse,server.ToResponseString() + answer);

}

[Test]
public void ShouldCalculateAnswerBytes()
{
var challengeBytes = Encoding.UTF8.GetBytes(Challenge);
var challengeSegment = new ArraySegment<byte>(challengeBytes);
var answerBytes = HandshakeHandler.CalculateAnswerBytes(Key1, Key2, challengeSegment);

Assert.AreEqual(16, answerBytes.Length);

var answer = Encoding.UTF8.GetString(answerBytes);

Assert.AreEqual(ExpectedAnswer, answer);
}
}

public class FakeSocket : ISocket
{
private readonly string _request;

public FakeSocket(string request)
{
_request = request;
}

public bool Connected
{
get { throw new NotImplementedException(); }
}

public IAsyncResult BeginReceive(IList<ArraySegment<byte>> buffers, SocketFlags socketFlags, AsyncCallback callback, object state)
{
Encoding.UTF8.GetBytes(_request).CopyTo(buffers[0].Array, 0);
var result = new Mock<IAsyncResult>();
result.Setup(r => r.AsyncState).Returns(state);
callback(result.Object);
return result.Object;
}

public int EndReceive(IAsyncResult asyncResult)
{
return Encoding.UTF8.GetBytes(_request).Length;
}

public IAsyncResult BeginAccept(AsyncCallback callback, object state)
{
throw new NotImplementedException();
}

public ISocket EndAccept(IAsyncResult asyncResult)
{
throw new NotImplementedException();
}

public void Dispose()
{
throw new NotImplementedException();
}

public void Close()
{
throw new NotImplementedException();
}

public IAsyncResult BeginSend(IList<ArraySegment<byte>> buffers, SocketFlags socketFlags, AsyncCallback callback, object state)
{
throw new NotImplementedException();
}

public int EndSend(IAsyncResult asyncResult)
{
throw new NotImplementedException();
}

public void Bind(EndPoint ipLocal)
{
throw new NotImplementedException();
}

public void Listen(int backlog)
{
throw new NotImplementedException();
}
}
}
63 changes: 63 additions & 0 deletions src/Fleck.Tests/ReceiverTests.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
using System;
using System.Collections.Generic;
using System.Net.Sockets;
using System.Threading;
using Moq;
using NUnit.Framework;

namespace Fleck.Tests
{
[TestFixture]
public class ReceiverTests
{
private bool _wasClosed;
private Mock<ISocket> _mockSocket;
private Receiver _receiver;
private string _message;

[SetUp]
public void Setup()
{
_message = null;
_wasClosed = false;
_mockSocket = new Mock<ISocket>();
_receiver = new Receiver(_mockSocket.Object,s => _message = s, () => _wasClosed = true);
}

[Test]
public void ShouldNotReceiveWhenNotConnected()
{
_mockSocket.Setup(s => s.Connected).Returns(false);
_receiver.Receive();
_mockSocket.Verify(s => s.BeginReceive(It.IsAny<IList<ArraySegment<byte>>>(),It.IsAny<SocketFlags>(),It.IsAny<AsyncCallback>(),It.IsAny<object>()),Times.Never());
Assert.IsTrue(_wasClosed);
}

[Test]
public void ShouldCloseOnException()
{
_mockSocket.Setup(s => s.Connected).Returns(true);
_receiver.Receive();
_mockSocket.Setup(s => s.BeginReceive(It.IsAny<IList<ArraySegment<byte>>>(),It.IsAny<SocketFlags>(),It.IsAny<AsyncCallback>(),It.IsAny<object>()))
.Returns<IList<ArraySegment<byte>>, SocketFlags, AsyncCallback, object>((seg, flag, call, obj) =>
{
var result = new Mock<IAsyncResult>();
result.Setup(r => r.AsyncState).Returns(obj);
result.Setup(r => r.IsCompleted).Returns(true);
call(result.Object);
return result.Object;
});
_mockSocket
.Setup(s => s.EndReceive(It.IsAny<IAsyncResult>()))
.Throws<Exception>()
.Verifiable();
_receiver.Receive();
Thread.Sleep(100);
_mockSocket.Verify();
Assert.IsTrue(_wasClosed);
}



}
}
68 changes: 68 additions & 0 deletions src/Fleck.Tests/SenderTests.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
using System;
using System.Collections.Generic;
using System.Net.Sockets;
using System.Threading;
using Moq;
using NUnit.Framework;

namespace Fleck.Tests
{
[TestFixture]
public class SenderTests
{
private bool _wasHit;
private Mock<ISocket> _mockSocket;
private Sender _sender;

[SetUp]
public void Setup()
{
_wasHit = false;
_mockSocket = new Mock<ISocket>();
_sender = new Sender(_mockSocket.Object, () => _wasHit = true);
}

[Test]
public void DoesNotSendWhenSocketNotConnected()
{
_mockSocket.Setup(s => s.Connected).Returns(false);
_sender.Send("Data!");
_mockSocket.Verify(s => s.BeginSend(It.IsAny<IList<ArraySegment<byte>>>(),It.IsAny<SocketFlags>(),It.IsAny<AsyncCallback>(),It.IsAny<object>()),Times.Never());
Assert.IsFalse(_wasHit);
}

[Test]
public void SendsWhenSocketConnected()
{
_mockSocket.Setup(s => s.Connected).Returns(true);
_sender.Send("Data!");
_mockSocket.Verify(s => s.BeginSend(It.IsAny<IList<ArraySegment<byte>>>(),It.IsAny<SocketFlags>(),It.IsAny<AsyncCallback>(),It.IsAny<object>()),Times.Once());
Assert.IsFalse(_wasHit);
}

[Test]
public void CallsCloseActionOnException()
{
_mockSocket.Setup(
s =>
s.BeginSend(It.IsAny<IList<ArraySegment<byte>>>(), It.IsAny<SocketFlags>(), It.IsAny<AsyncCallback>(),
It.IsAny<object>()))
.Returns<IList<ArraySegment<byte>>, SocketFlags, AsyncCallback, object>((seg, flag, call, obj) =>
{
var result = new Mock<IAsyncResult>();
result.Setup(r => r.AsyncState).Returns(obj);
call(result.Object);
return result.Object;
});
_mockSocket.Setup(s => s.Connected).Returns(true);
_mockSocket
.Setup(s => s.EndSend(It.IsAny<IAsyncResult>()))
.Throws<Exception>()
.Verifiable();
_sender.Send("Data!");
Thread.Sleep(100);
_mockSocket.Verify();
Assert.IsTrue(_wasHit);
}
}
}
14 changes: 7 additions & 7 deletions src/Fleck/HandshakeHandler.cs
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ public void Shake(ISocket socket)
TaskContinuationOptions.OnlyOnFaulted);
}

private void DoShake(HandShakeState state, int receivedByteCount)
public void DoShake(HandShakeState state, int receivedByteCount)
{
ClientHandshake = ParseClientHandshake(new ArraySegment<byte>(state.Buffer, 0, receivedByteCount));

Expand All @@ -52,7 +52,7 @@ private void DoShake(HandShakeState state, int receivedByteCount)
}
}

private static ClientHandshake ParseClientHandshake(ArraySegment<byte> byteShake)
public static ClientHandshake ParseClientHandshake(ArraySegment<byte> byteShake)
{
const string pattern = @"^(?<connect>[^\s]+)\s(?<path>[^\s]+)\sHTTP\/1\.1\r\n" + // request line
@"((?<field_name>[^:\r\n]+):\s(?<field_value>[^\r\n]+)\r\n)+";
Expand Down Expand Up @@ -104,7 +104,7 @@ private static ClientHandshake ParseClientHandshake(ArraySegment<byte> byteShake
return handshake;
}

private ServerHandshake GenerateResponseHandshake()
public ServerHandshake GenerateResponseHandshake()
{
var responseHandshake = new ServerHandshake
{
Expand All @@ -122,7 +122,7 @@ private ServerHandshake GenerateResponseHandshake()
return responseHandshake;
}

private void BeginSendServerHandshake(ServerHandshake handshake, ISocket socket)
public void BeginSendServerHandshake(ServerHandshake handshake, ISocket socket)
{
string stringShake = handshake.ToResponseString();

Expand All @@ -144,7 +144,7 @@ private void EndSendServerHandshake()
OnSuccess(ClientHandshake);
}

private static byte[] CalculateAnswerBytes(string key1, string key2, ArraySegment<byte> challenge)
public static byte[] CalculateAnswerBytes(string key1, string key2, ArraySegment<byte> challenge)
{
byte[] result1Bytes = ParseKey(key1);
byte[] result2Bytes = ParseKey(key2);
Expand All @@ -158,7 +158,7 @@ private static byte[] CalculateAnswerBytes(string key1, string key2, ArraySegmen
return md5.ComputeHash(rawAnswer);
}

private static byte[] ParseKey(string key)
public static byte[] ParseKey(string key)
{
int spaces = key.Count(x => x == ' ');
var digits = new String(key.Where(Char.IsDigit).ToArray());
Expand All @@ -171,7 +171,7 @@ private static byte[] ParseKey(string key)
return result;
}

private class HandShakeState
public class HandShakeState
{
private const int BufferSize = 1024;
public readonly byte[] Buffer = new byte[BufferSize];
Expand Down

0 comments on commit 38b7773

Please sign in to comment.