-
Notifications
You must be signed in to change notification settings - Fork 45
Added support for a meta gzipped message serialization #36
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Open
fernando-almeida
wants to merge
3
commits into
christopherread:master
Choose a base branch
from
fernando-almeida:feature/meta_gzipped_serialization
base: master
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Open
Changes from 1 commit
Commits
Show all changes
3 commits
Select commit
Hold shift + click to select a range
9849222
Added support for a meta gzipped message serializer to allow the comp…
fernando-almeida 627b6af
Removed Moq dependency from Obvs.Tests to continue to favor FakeItEasy.
fernando-almeida c027096
Merge branch 'master' into feature/meta_gzipped_serialization
megakid File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -157,3 +157,7 @@ $RECYCLE.BIN/ | |
| packages/ | ||
| .vs/config/applicationhost.config | ||
| .vs/ | ||
|
|
||
| # VS Code | ||
| .vscode | ||
| *.code-workspace | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| 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 | ||
|
|
||
| } | ||
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| 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"/> | ||
| </ItemGroup> | ||
| <ItemGroup> | ||
| <ProjectReference Include="..\Obvs\Obvs.csproj" /> | ||
| <ProjectReference Include="..\Obvs\Obvs.csproj"/> | ||
| </ItemGroup> | ||
| </Project> | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| 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) { | ||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
|
||
| throw new ArgumentException("Message serializer implementation cannot be GzippedMessageSerializer"); | ||
| } | ||
| return new GZippedMessageDeserializer<TMessage>(messageDeserializer.Deserialize); | ||
| } | ||
| } | ||
| } | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| 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)) | ||
|
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) { | ||
|
fernando-almeida marked this conversation as resolved.
Outdated
|
||
| throw new ArgumentException("Message serializer implementation cannot be GzippedMessageSerializer"); | ||
| } | ||
| return new GZippedMessageSerializer(messageSerializer.Serialize); | ||
| } | ||
| } | ||
| } | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.