Skip to content

Commit

Permalink
Support message retransmission in CoapClient
Browse files Browse the repository at this point in the history
  • Loading branch information
NZSmartie committed Aug 21, 2017
1 parent 1bd0cb4 commit f568528
Show file tree
Hide file tree
Showing 8 changed files with 359 additions and 53 deletions.
109 changes: 98 additions & 11 deletions CoAPNet.Tests/CoapClientTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ public void TestClientRequest()
{
client.SendAsync(new CoapMessage
{
Type = CoapMessageType.Confirmable,
Type = CoapMessageType.NonConfirmable,
Code = CoapMessageCode.None
}).Wait();
}
Expand All @@ -54,6 +54,7 @@ public void TestClientResponse()

var expected = new CoapMessage
{
Id = 0x1234,
Type = CoapMessageType.Acknowledgement,
Code = CoapMessageCode.Content,
Options = new System.Collections.Generic.List<CoapOption>
Expand All @@ -63,22 +64,18 @@ public void TestClientResponse()
Payload = System.Text.Encoding.UTF8.GetBytes("</.well-known/core>")
};

mockPayload
.Setup(p => p.Payload)
.Returns(() => expected.Serialise());
mockClientEndpoint
.Setup(c => c.SendAsync(It.IsAny<CoapPacket>(), It.IsAny<CancellationToken>()))
// Copy the ID from the message sent out, to the message for the client to receive
.Callback<CoapPacket, CancellationToken>((p, ct) => expected.Id = p.MessageId)
.Returns(Task.CompletedTask);
mockClientEndpoint
.SetupSequence(c => c.ReceiveAsync(It.IsAny<CancellationToken>()))
.Returns(Task.FromResult(mockPayload.Object))
.Returns(Task.FromResult(new CoapPacket{Payload = expected.Serialise()}))
.Throws(new CoapEndpointException("Endpoint closed"));

// Ack
using (var client = new CoapClient(mockClientEndpoint.Object))
{
client.SetNetMessageId(0x1234);
// Sned message
var sendTask = client.GetAsync("coap://example.com/.well-known/core");
sendTask.Wait(MaxTaskTimeout);
Expand All @@ -89,7 +86,7 @@ public void TestClientResponse()
try
{
while (true)
client.ReceiveAsync(CancellationToken.None).Wait();
client.ReceiveAsync(CancellationToken.None).Wait(MaxTaskTimeout);
}catch(AggregateException ex) when(ex.InnerException.GetType() == typeof(CoapEndpointException)) { }

// Receive msssage
Expand Down Expand Up @@ -231,12 +228,102 @@ public void TestRequestWithSeperateResponse()
Times.Exactly(1));
}

// TODO: Test Retransmit Delays
[Test]
[Category("[RFC7252] Section 4.2")]
public void TestRetransmitDelays()
public void TestRetransmissionAttempts()
{
Assert.Inconclusive("Not Implemented");
// Arrange
var requestMessage = new CoapMessage
{
Id = 0x1234,
Type = CoapMessageType.Confirmable,
Code = CoapMessageCode.Get,
Options = new System.Collections.Generic.List<CoapOption>
{
new Options.UriPath("test")
}
};

var mockClientEndpoint = new Mock<ICoapEndpoint>();
mockClientEndpoint
.SetupSequence(c => c.ReceiveAsync(It.IsAny<CancellationToken>()))
.Returns(Task.Delay(500).ContinueWith(delayTask => new CoapPacket
{
Payload = new CoapMessage
{
Id = 0x1234,
Type = CoapMessageType.Acknowledgement
}.Serialise()
}))
.Throws(new CoapEndpointException("Endpoint closed"));

// Act
using (var mockClient = new CoapClient(mockClientEndpoint.Object))
{
mockClient.RetransmitTimeout = TimeSpan.FromMilliseconds(200);
mockClient.MaxRetransmitAttempts = 3;

mockClient.SendAsync(requestMessage).GetAwaiter().GetResult();

try
{
while (true)
{
mockClient.ReceiveAsync(CancellationToken.None).GetAwaiter().GetResult();
}
}
catch (CoapEndpointException) { }
}

// Assert
mockClientEndpoint.Verify(
cep => cep.SendAsync(It.Is<CoapPacket>(p => p.Payload.SequenceEqual(requestMessage.Serialise())), It.IsAny<CancellationToken>()),
Times.Exactly(2));
}

[Test]
[Category("[RFC7252] Section 4.2")]
public void TestRetransmissionMaxAttempts()
{
// Arrange
var requestMessage = new CoapMessage
{
Id = 0x1234,
Type = CoapMessageType.Confirmable,
Code = CoapMessageCode.Get,
Options = new System.Collections.Generic.List<CoapOption>
{
new Options.UriPath("test")
}
};

var mockClientEndpoint = new Mock<ICoapEndpoint>();
mockClientEndpoint
.SetupSequence(c => c.ReceiveAsync(It.IsAny<CancellationToken>()))
.Returns(Task.Delay(2000).ContinueWith<CoapPacket>(delayTask => throw new CoapEndpointException("Endpoint closed")));

// Act
using (var mockClient = new CoapClient(mockClientEndpoint.Object))
{
mockClient.RetransmitTimeout = TimeSpan.FromMilliseconds(200);
mockClient.MaxRetransmitAttempts = 3;

Assert.ThrowsAsync<CoapClientException>(async () => await mockClient.SendAsync(requestMessage));

try
{
while (true)
{
mockClient.ReceiveAsync(CancellationToken.None).GetAwaiter().GetResult();
}
}
catch (CoapEndpointException) { }
}

// Assert
mockClientEndpoint.Verify(
cep => cep.SendAsync(It.Is<CoapPacket>(p => p.Payload.SequenceEqual(requestMessage.Serialise())), It.IsAny<CancellationToken>()),
Times.Exactly(3));
}

// TODO: Test Ignore Repeated Messages
Expand Down
4 changes: 4 additions & 0 deletions CoAPNet/AssemblyInfo.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
using System.Runtime.CompilerServices;

// Allow CoAPNet.Tests to access internal members for testing purposes
[assembly: InternalsVisibleTo("CoAPNet.Tests")]
6 changes: 4 additions & 2 deletions CoAPNet/CoAPNet.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
<TargetFrameworks Condition="'$(LibraryFrameworks)'!=''">$(LibraryFrameworks)</TargetFrameworks>
<GeneratePackageOnBuild>True</GeneratePackageOnBuild>
<PackageId>NZSmartie.CoAPNet</PackageId>
<Version>0.2.0</Version>
<Version>0.2.1</Version>
<Authors>Roman Vaughan</Authors>
<Company>NZSmartie</Company>
<Product>CoAPNet</Product>
Expand All @@ -15,7 +15,9 @@
<PackageTags>CoAP IoT sensors devices hardware network protocol</PackageTags>
<IncludeSource>True</IncludeSource>
<IncludeSymbols>True</IncludeSymbols>
<PackageReleaseNotes>v0.2.0
<PackageReleaseNotes>v0.2.1
- Support message retransmission in CoapClient
v0.2.0
- Added (still Work in Progress) CoapHandler and CoapService with tests for handling incomming requests.
v0.1.1
- Improve concurrency in CoapClient
Expand Down
Loading

0 comments on commit f568528

Please sign in to comment.