Skip to content
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

Fix Akka.Remote serialization exception bubbling and messages #5072

Merged
merged 10 commits into from Jun 9, 2021
88 changes: 88 additions & 0 deletions src/core/Akka.Remote.Tests/Serialization/BugFix5062Spec.cs
@@ -0,0 +1,88 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Runtime.Serialization;
using System.Text;
using System.Threading.Tasks;
using Akka.Actor;
using Akka.Configuration;
using Akka.Remote.Configuration;
using Akka.Serialization;
using Akka.TestKit;
using FluentAssertions;
using Google.Protobuf;
using Xunit;
using Xunit.Abstractions;

namespace Akka.Remote.Tests.Serialization
{
public class BugFix5062Spec: AkkaSpec
{
private static Config DDataConfig => ConfigurationFactory.ParseString($@"
akka.actor {{
serializers {{
dummyWithManifest = ""{typeof(DummySerializerWithStringManifest).AssemblyQualifiedName}""
}}
serialization-bindings {{
""{typeof(SomeMessage).AssemblyQualifiedName}"" = dummyWithManifest
}}
serialization-identifiers {{
""{typeof(DummySerializerWithStringManifest).AssemblyQualifiedName}"" = 13
}}
}}")
.WithFallback(RemoteConfigFactory.Default());

public BugFix5062Spec(ITestOutputHelper output) : base(output, DDataConfig)
{ }

[Fact]
public void Failed_serialization_should_give_proper_exception_message()
{
var childName = "dummy";
var message = new ActorSelectionMessage(
new SomeMessage(),
new SelectionPathElement[] { new SelectChildName(childName) },
true);

var node1 = new Address("akka.tcp", "Sys", "localhost", 2551);
var serialized = MessageSerializer.Serialize((ExtendedActorSystem)Sys, node1, message);

var o = new object();
o.Invoking(s => MessageSerializer.Deserialize((ExtendedActorSystem)Sys, serialized)).Should()
.Throw<SerializationException>()
.WithMessage($"Failed to deserialize payload object when deserializing {nameof(ActorSelectionMessage)} addressed to [{childName}]")
.WithInnerExceptionExactly<NotImplementedException>();
}

public class SomeMessage
{
}

public class DummySerializerWithStringManifest : SerializerWithStringManifest
{
public DummySerializerWithStringManifest(ExtendedActorSystem system) : base(system)
{
}

public override byte[] ToBinary(object obj)
{
return Array.Empty<byte>();
}

public override object FromBinary(byte[] bytes, string manifest)
{
throw new NotImplementedException();
}

public override string Manifest(object o)
{
if (o is SomeMessage)
return "SM";
throw new Exception("Unknown object type");
}
}


}
}
14 changes: 13 additions & 1 deletion src/core/Akka.Remote/Serialization/MessageContainerSerializer.cs
Expand Up @@ -7,7 +7,9 @@

using System;
using System.Linq;
using System.Runtime.Serialization;
using Akka.Actor;
using Akka.Remote.Serialization.Proto.Msg;
using Akka.Serialization;
using Akka.Util;
using Google.Protobuf;
Expand Down Expand Up @@ -71,7 +73,6 @@ public override byte[] ToBinary(object obj)
public override object FromBinary(byte[] bytes, Type type)
{
var selectionEnvelope = Proto.Msg.SelectionEnvelope.Parser.ParseFrom(bytes);
var message = _payloadSupport.PayloadFrom(selectionEnvelope.Payload);

var elements = new SelectionPathElement[selectionEnvelope.Pattern.Count];
for (var i = 0; i < selectionEnvelope.Pattern.Count; i++)
Expand All @@ -85,6 +86,17 @@ public override object FromBinary(byte[] bytes, Type type)
elements[i] = new SelectParent();
}

object message;
try
{
message = _payloadSupport.PayloadFrom(selectionEnvelope.Payload);
}
catch (Exception ex)
{
throw new SerializationException(
$"Failed to deserialize payload object when deserializing {nameof(ActorSelectionMessage)} addressed to [{string.Join(",", elements.Select(e => e.ToString()))}]", ex);
}

return new ActorSelectionMessage(message, elements);
}

Expand Down