Skip to content
Open
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -157,3 +157,7 @@ $RECYCLE.BIN/
packages/
.vs/config/applicationhost.config
.vs/

# VS Code
.vscode
*.code-workspace
157 changes: 157 additions & 0 deletions Obvs.Tests/GZippedMessageSerializationTest.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,157 @@
using System;
using System.Text;
using System.IO;

using Moq;

using Obvs.Types;
using Obvs.Serialization;

using Xunit;

namespace Obvs.Tests {

/// <summary>
/// Test Gzipped message serialization
/// </summary>
public class GZippedMessageSerializationTest {

public class TestMessage: IMessage {
public string Content {get; set;} = null;

public override bool Equals(object obj)
{
//
// See the full list of guidelines at
// http://go.microsoft.com/fwlink/?LinkID=85237
// and also the guidance for operator== at
// http://go.microsoft.com/fwlink/?LinkId=85238
//

if (obj == null || GetType() != obj.GetType())
{
return false;
}

return this.Content.Equals(((TestMessage) obj).Content);
}

// override object.GetHashCode
public override int GetHashCode()
{
return Content.GetHashCode();
}

}

#region "Serialization tests"
[Fact]
public void Test_GZippedMessageSerializerNullActionConstruction_Fails() {
Assert.Throws(typeof(ArgumentNullException),
() => new GZippedMessageSerializer(null as Action<Stream, object>));
}

[Fact]
public void Test_GZippedMessageSerializerNullGzippedSerializerConstruction_Fails() {
Assert.Throws(typeof(ArgumentNullException),
() => new GZippedMessageSerializer(null as GZippedMessageSerializer));
}

[Fact]
public void Test_GZippedMessageSerializerGzippedSerializerConstruction_Fails() {
Assert.Throws(typeof(ArgumentException),
() => new GZippedMessageSerializer(new GZippedMessageSerializer( (Stream stream, object obj) => {})));
}

#endregion

#region "Deserialization tests"

[Fact]
public void Test_GZippedMessageDeserializerNullActionConstruction_Fails() {
Assert.Throws(
typeof(ArgumentNullException),
() => new GZippedMessageDeserializer<TestMessage>(null as Func<System.IO.Stream, TestMessage>));
}


[Fact]
public void Test_GZippedMessageDeserializerNullGzippedSerializerConstruction_Fails() {
Assert.Throws(typeof(ArgumentNullException),
() => new GZippedMessageDeserializer<Obvs.Types.IMessage>(null as GZippedMessageDeserializer<TestMessage>));
}
#endregion

[Fact]
public void Test_GZippedMessageDeserializerGzippedSerializerConstruction_Fails() {
Assert.Throws(typeof(ArgumentException),
() => new GZippedMessageDeserializer<TestMessage>(new GZippedMessageDeserializer<TestMessage>( (Stream stream) => new TestMessage{})));
}

[Fact]
public void Test_GzippedMessageFullSerialization_Succeeds() {
var content = "test";
var wasSerializeActionCalled = false;
Action<Stream, object> serializeAction = (stream, obj) => {
wasSerializeActionCalled = true;
var message = obj as TestMessage;
var contentBytes = Encoding.UTF8.GetBytes(message.Content);
stream.Write(contentBytes, 0, contentBytes.Length);
};
var messageSerializer = new GZippedMessageSerializer(serializeAction);

var wasDeserializeFuncCalled = false;
Func<Stream, TestMessage> deserializeFunction = stream => {
wasDeserializeFuncCalled = true;
var buffer = new byte[Encoding.UTF8.GetByteCount(content)];
var numBytesRead = stream.Read(buffer, 0, buffer.Length);
var deserializedMessage = new TestMessage {
Content = Encoding.UTF8.GetString(buffer)
};
return deserializedMessage;
};
var messageDeserializer = new GZippedMessageDeserializer<TestMessage>(deserializeFunction);

var testMessage = new TestMessage {
Content = content
};
var messageStream = new MemoryStream();
messageSerializer.Serialize(messageStream, testMessage);
Assert.True(wasSerializeActionCalled);
messageStream.Position = 0;
var deserializedTestMessage = messageDeserializer.Deserialize(messageStream);
Assert.True(wasDeserializeFuncCalled);

Assert.Equal(testMessage, deserializedTestMessage);
}

#region "IMessage serializer extensions"
[Fact]
public void Test_SerializeGZipped_Fails() {
var messageSerializer = new GZippedMessageSerializer((stream, obj) => {});
Assert.Throws(typeof(ArgumentException), () => messageSerializer.SerializeGZipped());
}

[Fact]
public void Test_DeserializeGZipped_Fails() {
var messageDeserializer = new GZippedMessageDeserializer<TestMessage>((stream) => new TestMessage{});
Assert.Throws(typeof(ArgumentException), () => messageDeserializer.DeserializeGZipped());
}

[Fact]
public void Test_SerializeGZipped_Success() {
var messageSerializerMock = new Mock<IMessageSerializer>();
var gzippedMessageSerializer = messageSerializerMock.Object.SerializeGZipped();
Assert.NotNull(gzippedMessageSerializer);
}

[Fact]
public void Test_DeserializeGZipped_Success() {
var messageDeserializerMock = new Mock<IMessageDeserializer<TestMessage>>();
var gzippedMessageDeserializer = messageDeserializerMock.Object.DeserializeGZipped<TestMessage>();
Assert.NotNull(gzippedMessageDeserializer);
}
#endregion

}
}
20 changes: 11 additions & 9 deletions Obvs.Tests/Obvs.Tests.csproj
Original file line number Diff line number Diff line change
@@ -1,19 +1,21 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFrameworks>netcoreapp2.0</TargetFrameworks>
<Company>Christopher Read</Company>
<Copyright>Copyright © Christopher Read 2014</Copyright>
<Authors />
<Authors/>
<IsPackable>false</IsPackable>
<GenerateFullPaths>true</GenerateFullPaths>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="FakeItEasy" Version="4.1.1" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="15.3.0" />
<PackageReference Include="Microsoft.Reactive.Testing" Version="3.1.1" />
<PackageReference Include="xunit" Version="2.3.1" />
<PackageReference Include="xunit.runner.visualstudio" Version="2.3.1" />
<PackageReference Include="FakeItEasy" Version="4.9.2"/>
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="15.9.0"/>
<PackageReference Include="Microsoft.Reactive.Testing" Version="3.1.1"/>
<PackageReference Include="xunit" Version="2.4.1"/>
<PackageReference Include="xunit.runner.visualstudio" Version="2.4.1"/>
<PackageReference Include="Moq" Version="4.10.1"/>
Comment thread
fernando-almeida marked this conversation as resolved.
Outdated
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\Obvs\Obvs.csproj" />
<ProjectReference Include="..\Obvs\Obvs.csproj"/>
</ItemGroup>
</Project>
3 changes: 2 additions & 1 deletion Obvs/Obvs.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -10,13 +10,14 @@
<PackageTags>obvs messaging microservice bus messagebus rx reactive servicebus</PackageTags>
<PackageReleaseNotes>New csproj format</PackageReleaseNotes>
<Description>An observable microservice bus .NET library, based on Reactive Extensions. Search 'Obvs' for other transport, serialization, and logging extensions.</Description>
<GenerateFullPaths>true</GenerateFullPaths>
</PropertyGroup>
<ItemGroup Condition=" '$(TargetFramework)' == 'net45' ">
<Reference Include="System" />
<Reference Include="Microsoft.CSharp" />
</ItemGroup>
<ItemGroup Condition=" '$(TargetFramework)' != 'net45' ">
<PackageReference Include="Microsoft.Extensions.DependencyModel" Version="2.0.3" />
<PackageReference Include="Microsoft.Extensions.DependencyModel" Version="2.1.0" />
<PackageReference Include="System.Diagnostics.Process" Version="4.3.0" />
<PackageReference Include="System.Net.NameResolution" Version="4.3.0" />
<PackageReference Include="System.Reflection.Emit.Lightweight" Version="4.3.0" />
Expand Down
73 changes: 73 additions & 0 deletions Obvs/Serialization/GZippedMessageDeserializer.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
using System;
using System.IO;
using System.IO.Compression;

namespace Obvs.Serialization
{

/// <summary>
/// Gzipped message deserializer
/// </summary>
/// <typeparam name="TMessage">Type of message</typeparam>
public class GZippedMessageDeserializer<TMessage> : MessageDeserializerBase<TMessage>
where TMessage : class
{
/// <summary>
/// Message from stream deserializer functor
/// </summary>
private readonly Func<Stream, TMessage> _messageStreamDeserializerFn;

/// <summary>
/// Constructor
/// </summary>
/// <param name="messageStreamDeserializerFn">Message deserializer fn</param>
public GZippedMessageDeserializer(Func<Stream, TMessage> messageStreamDeserializerFn)
{
if (messageStreamDeserializerFn == null) {
throw new ArgumentNullException(nameof(messageStreamDeserializerFn));
}
_messageStreamDeserializerFn = messageStreamDeserializerFn;
}

/// <summary>
/// Constructor
/// </summary>
/// <param name="messageDeserializer">Message deserializer implementation<</param>
public GZippedMessageDeserializer(IMessageDeserializer<TMessage> messageDeserializer) {
if (messageDeserializer == null) {
throw new ArgumentNullException(nameof(messageDeserializer));
}
var gzippedMessageDeserializer = messageDeserializer as GZippedMessageDeserializer<TMessage>;
if (gzippedMessageDeserializer != null) {
throw new ArgumentException("Invalid message deserializer GZippedMessageDeserializer");
}
_messageStreamDeserializerFn = messageDeserializer.Deserialize;
}

/// <inheritdoc />
public override TMessage Deserialize(Stream stream)
{
using (var gzipStream = new GZipStream(stream, CompressionMode.Decompress, true))
{
return _messageStreamDeserializerFn(gzipStream);
}
}
}

public static class GZippedMessageDeserializerExtensions {

/// <summary>
/// Apply GZip decompression to an existing message serializer
/// </summary>
/// <typeparam name="TMessage">Type of message</typeparam>
public static GZippedMessageDeserializer<TMessage> DeserializeGZipped<TMessage>(
this IMessageDeserializer<TMessage> messageDeserializer
) where TMessage : class {
var gzippedMessageSerializer = messageDeserializer as GZippedMessageDeserializer<TMessage>;
if (gzippedMessageSerializer != null) {

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

if (messageDeserializer is GZippedMessageDeserializer<TMessage>) {

throw new ArgumentException("Message serializer implementation cannot be GzippedMessageSerializer");
}
return new GZippedMessageDeserializer<TMessage>(messageDeserializer.Deserialize);
}
}
}
79 changes: 79 additions & 0 deletions Obvs/Serialization/GZippedMessageSerializer.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
using System;
using System.IO;
using System.IO.Compression;

namespace Obvs.Serialization
{
/// <summary>
/// Gzipped message serializer
/// </summary>
public class GZippedMessageSerializer : IMessageSerializer
{

/// <summary>
/// Message to strem serializer functor
/// </summary>
private readonly Action<Stream, object> _messageStreamSerializerFn;

/// <summary>
/// Compression level
/// </summary>
private readonly CompressionLevel _compressionLevel;

/// <summary>
/// Constructor
/// </summary>
/// <param name="messageStreamSerializerFn">Message stream serializer</param>
/// <param name="compressionLevel">Compression level</param>
public GZippedMessageSerializer(Action<Stream, object> messageStreamSerializerFn, CompressionLevel compressionLevel = CompressionLevel.Optimal)
{
if (messageStreamSerializerFn == null) {
throw new ArgumentNullException(nameof(messageStreamSerializerFn));
}
_messageStreamSerializerFn = messageStreamSerializerFn;
_compressionLevel = compressionLevel;
}

/// <summary>
/// Constructor
/// </summary>
/// <param name="messageSerializer">Message stream serializer</param>
/// <param name="compressionLevel">Compression level</param>
public GZippedMessageSerializer(IMessageSerializer messageSerializer, CompressionLevel compressionLevel = CompressionLevel.Optimal)
{
if (messageSerializer == null) {
throw new ArgumentNullException(nameof(messageSerializer));
}
var gzippedMessageSerializer = messageSerializer as GZippedMessageSerializer;
if (gzippedMessageSerializer != null) {
throw new ArgumentException("Invalid message deserializer GZippedMessageSerializer");
}
_messageStreamSerializerFn = messageSerializer.Serialize;
_compressionLevel = compressionLevel;
}

/// <inheritdoc />
public void Serialize(Stream stream, object message)
{
using (var gzipStream = new GZipStream(stream, CompressionLevel.Fastest, true))
Comment thread
fernando-almeida marked this conversation as resolved.
Outdated
{
_messageStreamSerializerFn(gzipStream, message);
}
}
}

public static class GZippedMessageSerializerExtensions {

/// <summary>
/// Apply GZip compression to an existing message serializer
/// </summary>
/// <typeparam name="TMessage">Type of message</typeparam>
public static GZippedMessageSerializer SerializeGZipped(this IMessageSerializer messageSerializer) {
var gzippedMessageSerializer = messageSerializer as GZippedMessageSerializer;
if (gzippedMessageSerializer != null) {
Comment thread
fernando-almeida marked this conversation as resolved.
Outdated
throw new ArgumentException("Message serializer implementation cannot be GzippedMessageSerializer");
}
return new GZippedMessageSerializer(messageSerializer.Serialize);
}
}
}
2 changes: 1 addition & 1 deletion Obvs/Serialization/IMessageSerializer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

namespace Obvs.Serialization
{
public static class MessageSerializerExtentions
public static class MessageSerializerExtensions
{
public static byte[] Serialize(this IMessageSerializer serializer, object obj)
{
Expand Down