Skip to content

Commit 9041fa7

Browse files
author
Erik
committed
refactored to enable testing
1 parent aa73938 commit 9041fa7

16 files changed

Lines changed: 425 additions & 30 deletions

EventSource4Net.Test/EventSource4Net.Test.csproj

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,9 @@
5252
<ItemGroup>
5353
<Compile Include="Properties\AssemblyInfo.cs" />
5454
<Compile Include="StringSplitterTest.cs" />
55+
<Compile Include="TestableEventSource.cs" />
56+
<Compile Include="EventSourceTest.cs" />
57+
<Compile Include="WebRequesterFactoryTest.cs" />
5558
</ItemGroup>
5659
<ItemGroup>
5760
<ProjectReference Include="..\EventSource4Net\EventSource4Net.csproj">
Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,85 @@
1+
using System;
2+
using Microsoft.VisualStudio.TestTools.UnitTesting;
3+
using System.Collections.Generic;
4+
using System.Threading;
5+
6+
namespace EventSource4Net.Test
7+
{
8+
[TestClass]
9+
public class EventSourceTest
10+
{
11+
[TestMethod]
12+
public void TestFailedConnection()
13+
{
14+
// setup
15+
Uri url = new Uri("http://test.com");
16+
CancellationTokenSource cts = new CancellationTokenSource();
17+
List<EventSourceState> states = new List<EventSourceState>();
18+
ServiceResponseMock response = new ServiceResponseMock(url, System.Net.HttpStatusCode.NotFound);
19+
WebRequesterFactoryMock factory = new WebRequesterFactoryMock(response);
20+
ManualResetEvent stateIsClosed = new ManualResetEvent(false);
21+
22+
TestableEventSource es = new TestableEventSource(url, factory);
23+
es.StateChanged += (o, e) =>
24+
{
25+
states.Add(e.State);
26+
if (e.State == EventSourceState.CLOSED)
27+
{
28+
stateIsClosed.Set();
29+
cts.Cancel();
30+
}
31+
};
32+
33+
34+
// act
35+
stateIsClosed.Reset();
36+
37+
es.Start(cts.Token);
38+
39+
stateIsClosed.WaitOne();
40+
41+
// assert
42+
Assert.IsTrue(states.Count == 2);
43+
Assert.AreEqual(states[0], EventSourceState.CONNECTING);
44+
Assert.AreEqual(states[1], EventSourceState.CLOSED);
45+
}
46+
47+
[TestMethod]
48+
public void TestSuccesfulConnection()
49+
{
50+
// setup
51+
Uri url = new Uri("http://test.com");
52+
CancellationTokenSource cts = new CancellationTokenSource();
53+
List<EventSourceState> states = new List<EventSourceState>();
54+
ServiceResponseMock response = new ServiceResponseMock(url, System.Net.HttpStatusCode.OK);
55+
WebRequesterFactoryMock factory = new WebRequesterFactoryMock(response);
56+
ManualResetEvent stateIsOpen = new ManualResetEvent(false);
57+
58+
TestableEventSource es = new TestableEventSource(url, factory);
59+
es.StateChanged += (o, e) =>
60+
{
61+
states.Add(e.State);
62+
if (e.State == EventSourceState.OPEN)
63+
{
64+
stateIsOpen.Set();
65+
cts.Cancel();
66+
}
67+
};
68+
69+
70+
// act
71+
stateIsOpen.Reset();
72+
73+
es.Start(cts.Token);
74+
75+
stateIsOpen.WaitOne();
76+
77+
// assert
78+
Assert.IsTrue(states.Count == 2);
79+
Assert.AreEqual(states[0], EventSourceState.CONNECTING);
80+
Assert.AreEqual(states[1], EventSourceState.OPEN);
81+
}
82+
83+
84+
}
85+
}

EventSource4Net.Test/StringSplitterTest.cs

Lines changed: 49 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,64 @@
11
using System;
22
using Microsoft.VisualStudio.TestTools.UnitTesting;
3+
using System.Threading;
4+
using System.Collections.Generic;
35

46
namespace EventSource4Net.Test
57
{
68
[TestClass]
79
public class StringSplitterTest
810
{
11+
Uri url = new Uri("http://test.com");
12+
CancellationTokenSource cts;
13+
List<EventSourceState> states;
14+
ServiceResponseMock response;
15+
WebRequesterFactoryMock factory;
16+
ManualResetEvent stateIsOpen;
17+
18+
19+
private TestableEventSource SetupAndConnect()
20+
{
21+
// setup
22+
cts = new CancellationTokenSource();
23+
states = new List<EventSourceState>();
24+
response = new ServiceResponseMock(url, System.Net.HttpStatusCode.OK);
25+
factory = new WebRequesterFactoryMock(response);
26+
stateIsOpen = new ManualResetEvent(false);
27+
28+
TestableEventSource es = new TestableEventSource(url, factory);
29+
es.StateChanged += (o, e) =>
30+
{
31+
states.Add(e.State);
32+
if (e.State == EventSourceState.OPEN)
33+
stateIsOpen.Set();
34+
};
35+
36+
return es;
37+
}
38+
939
[TestMethod]
1040
public void TestDoubleLineFeed()
1141
{
12-
string remainingText = string.Empty;
13-
string[] lines =
14-
StringSplitter.SplitIntoLines("test\n\n", out remainingText);
42+
// setup
43+
TestableEventSource es = SetupAndConnect();
1544

16-
Assert.AreEqual(lines.Length, 2);
17-
Assert.AreEqual(lines[0], "test");
18-
Assert.AreEqual(lines[1], string.Empty);
45+
List<string> receivedMessages = new List<string>();
46+
ManualResetEvent eventReceived = new ManualResetEvent(false);
47+
es.EventReceived += (o, e) =>
48+
{
49+
receivedMessages.Add(e.Message.Data);
50+
eventReceived.Set();
51+
};
52+
53+
// act
54+
es.Start(cts.Token);
55+
stateIsOpen.WaitOne();
56+
response.WriteTestTextToStream("test\n\n");
57+
eventReceived.WaitOne();
58+
59+
// assert
60+
Assert.AreEqual(receivedMessages.Count, 1);
61+
Assert.AreEqual(receivedMessages[0], "test");
1962
}
2063
[TestMethod]
2164
public void TestDoubleCarriageReturn()
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
using System;
2+
using System.Collections.Generic;
3+
using System.Linq;
4+
using System.Text;
5+
using System.Threading.Tasks;
6+
7+
namespace EventSource4Net.Test
8+
{
9+
class TestableEventSource : EventSource
10+
{
11+
public TestableEventSource(Uri url,IWebRequesterFactory factory) : base(url,factory)
12+
{
13+
14+
}
15+
}
16+
}
Lines changed: 98 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,98 @@
1+
using System;
2+
using System.Collections.Generic;
3+
using System.IO;
4+
using System.Linq;
5+
using System.Net;
6+
using System.Text;
7+
using System.Threading;
8+
using System.Threading.Tasks;
9+
10+
namespace EventSource4Net.Test
11+
{
12+
class WebRequesterFactoryMock : IWebRequesterFactory
13+
{
14+
public WebRequesterMock WebRequesterMock
15+
{
16+
get;
17+
private set;
18+
}
19+
public WebRequesterFactoryMock(ServiceResponseMock response)
20+
{
21+
this.WebRequesterMock = new WebRequesterMock(response);
22+
}
23+
public IWebRequester Create()
24+
{
25+
return WebRequesterMock;
26+
}
27+
}
28+
29+
class WebRequesterMock : IWebRequester
30+
{
31+
public ManualResetEvent GetCalled = new ManualResetEvent(false);
32+
public ServiceResponseMock Response { get; private set; }
33+
34+
public WebRequesterMock(ServiceResponseMock response)
35+
{
36+
this.Response = response;
37+
}
38+
39+
public System.Threading.Tasks.Task<IServerResponse> Get(Uri url)
40+
{
41+
return Task.Factory.StartNew<IServerResponse>(() =>
42+
{
43+
GetCalled.Set();
44+
return Response;
45+
});
46+
}
47+
}
48+
49+
class ServiceResponseMock : IServerResponse
50+
{
51+
private MemoryStream mStream = new MemoryStream();
52+
private StreamWriter mStreamWriter;
53+
private Uri mUrl;
54+
private HttpStatusCode mStatusCode;
55+
56+
public ManualResetEvent StatusCodeCalled = new ManualResetEvent(false);
57+
58+
public ServiceResponseMock(Uri url, HttpStatusCode statusCode)
59+
{
60+
mUrl = url;
61+
mStatusCode = statusCode;
62+
mStreamWriter = new StreamWriter(mStream);
63+
}
64+
65+
public System.Net.HttpStatusCode StatusCode
66+
{
67+
get
68+
{
69+
StatusCodeCalled.Set();
70+
return mStatusCode;
71+
}
72+
}
73+
74+
public System.IO.Stream GetResponseStream()
75+
{
76+
return mStream;
77+
}
78+
79+
public Uri ResponseUri
80+
{
81+
get { return mUrl; }
82+
}
83+
84+
public void WriteTestTextToStream(string text)
85+
{
86+
mStreamWriter.Write(text);
87+
}
88+
}
89+
90+
class GetIsCalledEventArgs : EventArgs
91+
{
92+
public ServiceResponseMock ServerResponse { get; private set; }
93+
public GetIsCalledEventArgs(ServiceResponseMock response)
94+
{
95+
ServerResponse = response;
96+
}
97+
}
98+
}

EventSource4Net/ConnectedState.cs

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -13,14 +13,16 @@ class ConnectedState : IConnectionState
1313
{
1414
private static readonly slf4net.ILogger _logger = slf4net.LoggerFactory.GetLogger(typeof(ConnectedState));
1515

16+
private IWebRequesterFactory mWebRequesterFactory;
1617
private ServerSentEvent mSse = null;
1718
private string mRemainingText = string.Empty; // the text that is not ended with a lineending char is saved for next call.
18-
private HttpWebResponse mResponse;
19+
private IServerResponse mResponse;
1920
public EventSourceState State { get { return EventSourceState.OPEN; } }
2021

21-
public ConnectedState(HttpWebResponse resp)
22+
public ConnectedState(IServerResponse response, IWebRequesterFactory webRequesterFactory)
2223
{
23-
mResponse = resp;
24+
mResponse = response;
25+
mWebRequesterFactory = webRequesterFactory;
2426
}
2527

2628
public Task<IConnectionState> Run(Action<ServerSentEvent> msgReceived, CancellationToken cancelToken)
@@ -128,7 +130,7 @@ public Task<IConnectionState> Run(Action<ServerSentEvent> msgReceived, Cancellat
128130
//stream.Close();
129131
//mResponse.Close();
130132
//mResponse.Dispose();
131-
return new DisconnectedState(mResponse.ResponseUri);
133+
return new DisconnectedState(mResponse.ResponseUri, mWebRequesterFactory);
132134
}
133135
}
134136
});

EventSource4Net/ConnectingState.cs

Lines changed: 12 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -14,40 +14,38 @@ class ConnectingState : IConnectionState
1414
private static readonly slf4net.ILogger _logger = slf4net.LoggerFactory.GetLogger(typeof(ConnectingState));
1515

1616
private Uri mUrl;
17+
private IWebRequesterFactory mWebRequesterFactory;
1718
public EventSourceState State { get { return EventSourceState.CONNECTING; } }
1819

19-
public ConnectingState(Uri url)
20+
public ConnectingState(Uri url, IWebRequesterFactory webRequesterFactory)
2021
{
21-
if(url==null) throw new ArgumentNullException("Url cant be null");
22+
if (url == null) throw new ArgumentNullException("Url cant be null");
23+
if (webRequesterFactory == null) throw new ArgumentNullException("Factory cant be null");
2224
mUrl = url;
25+
mWebRequesterFactory = webRequesterFactory;
2326
}
2427

2528
public Task<IConnectionState> Run(Action<ServerSentEvent> donothing, CancellationToken cancelToken)
2629
{
27-
var wreq = (HttpWebRequest)WebRequest.Create(mUrl);
28-
wreq.Method = "GET";
29-
wreq.Proxy = null;
30-
31-
var taskResp = Task.Factory.FromAsync<WebResponse>(wreq.BeginGetResponse,
32-
wreq.EndGetResponse,
33-
null);
30+
IWebRequester requester = mWebRequesterFactory.Create();
31+
var taskResp = requester.Get(mUrl);
3432

3533
return taskResp.ContinueWith<IConnectionState>(tsk =>
3634
{
3735
if (tsk.Status == TaskStatus.RanToCompletion && !cancelToken.IsCancellationRequested)
3836
{
39-
HttpWebResponse resp = tsk.Result as HttpWebResponse;
40-
if (resp != null && resp.StatusCode == HttpStatusCode.OK)
37+
IServerResponse response = tsk.Result;
38+
if (response.StatusCode == HttpStatusCode.OK)
4139
{
42-
return new ConnectedState(resp);
40+
return new ConnectedState(response, mWebRequesterFactory);
4341
}
4442
else
4543
{
46-
_logger.Info("Failed to connect to: " + mUrl.ToString() + resp ?? (" Http statuscode: " + resp.StatusCode));
44+
_logger.Info("Failed to connect to: " + mUrl.ToString() + response ?? (" Http statuscode: " + response.StatusCode));
4745
}
4846
}
4947

50-
return new DisconnectedState(mUrl);
48+
return new DisconnectedState(mUrl, mWebRequesterFactory);
5149
});
5250
}
5351
}

EventSource4Net/DisconnectedState.cs

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,23 +10,25 @@ namespace EventSource4Net
1010
class DisconnectedState : IConnectionState
1111
{
1212
private Uri mUrl;
13+
private IWebRequesterFactory mWebRequesterFactory;
1314
public EventSourceState State
1415
{
1516
get { return EventSourceState.CLOSED; }
1617
}
1718

18-
public DisconnectedState(Uri url)
19+
public DisconnectedState(Uri url, IWebRequesterFactory webRequesterFactory)
1920
{
2021
if (url == null) throw new ArgumentNullException("Url cant be null");
2122
mUrl = url;
23+
mWebRequesterFactory = webRequesterFactory;
2224
}
2325

2426
public Task<IConnectionState> Run(Action<ServerSentEvent> donothing, CancellationToken cancelToken)
2527
{
2628
if(cancelToken.IsCancellationRequested)
27-
return Task.Factory.StartNew<IConnectionState>(() => { return new DisconnectedState(mUrl); });
29+
return Task.Factory.StartNew<IConnectionState>(() => { return new DisconnectedState(mUrl, mWebRequesterFactory); });
2830
else
29-
return Task.Factory.StartNew<IConnectionState>(() => { return new ConnectingState(mUrl); });
31+
return Task.Factory.StartNew<IConnectionState>(() => { return new ConnectingState(mUrl, mWebRequesterFactory); });
3032
}
3133
}
3234
}

0 commit comments

Comments
 (0)