From 580b9aff88b28f391e6fb96f3ae604dd7855eb54 Mon Sep 17 00:00:00 2001 From: Gregorius Soedharmo Date: Fri, 10 Dec 2021 22:18:14 +0700 Subject: [PATCH] Add reproduction spec, not a bug, works as intended. (#5422) --- .../Serialization/CustomSerializerSpec.cs | 163 ++++++++++++++++++ 1 file changed, 163 insertions(+) diff --git a/src/core/Akka.Tests/Serialization/CustomSerializerSpec.cs b/src/core/Akka.Tests/Serialization/CustomSerializerSpec.cs index b9f4ff89e74..ffa2fa097cb 100644 --- a/src/core/Akka.Tests/Serialization/CustomSerializerSpec.cs +++ b/src/core/Akka.Tests/Serialization/CustomSerializerSpec.cs @@ -6,13 +6,18 @@ //----------------------------------------------------------------------- using System; +using System.Collections.Immutable; using System.Linq; +using System.Text; using Akka.Actor; +using Akka.Actor.Setup; using Akka.Configuration; using Akka.Serialization; +using Akka.TestKit; using Newtonsoft.Json; using Newtonsoft.Json.Converters; using Xunit; +using FluentAssertions; namespace Akka.Tests.Serialization { @@ -43,8 +48,166 @@ public void Custom_serializer_must_be_owner_of_its_serializerId() Assert.Equal(666, serializer.Identifier); } } + + [Fact] + public void Custom_SerializerWithStringManifest_should_work_with_base_class_binding() + { + var config = ConfigurationFactory.ParseString(@" + akka.actor { + serializers { + custom = ""Akka.Tests.Serialization.CustomManifestSerializer, Akka.Tests"" + } + serialization-bindings { + ""Akka.Tests.Serialization.MessageBase, Akka.Tests"" = custom + } + serialization-identifiers { + ""Akka.Tests.Serialization.CustomManifestSerializer, Akka.Tests"" = 101 + } + } + "); + + using (var system = ActorSystem.Create(nameof(CustomSerializerSpec), config)) + { + var firstMessage = new FirstMessage("First message"); + var serialization = system.Serialization; + var serializer = (CustomManifestSerializer)serialization.FindSerializerFor(firstMessage); + + var serialized = serializer.ToBinary(firstMessage); + var manifest = serializer.Manifest(firstMessage); + var deserializedFirstMessage = serializer.FromBinary(serialized, manifest); + manifest.Should().Be(FirstMessage.Manifest); + deserializedFirstMessage.Should().Be(firstMessage); + + var secondMessage = new SecondMessage("Second message"); + serialized = serializer.ToBinary(secondMessage); + manifest = serializer.Manifest(secondMessage); + var deserializedSecondMessage = serializer.FromBinary(serialized, manifest); + manifest.Should().Be(SecondMessage.Manifest); + deserializedSecondMessage.Should().Be(secondMessage); + } + } + + [Fact] + public void Custom_programmatic_SerializerWithStringManifest_should_work_with_base_class_binding() + { + var settings = SerializationSetup.Create(system => + ImmutableHashSet.Empty.Add( + new SerializerDetails( + alias: "custom", + serializer: new CustomManifestSerializer(system), + useFor: ImmutableHashSet.Empty.Add(typeof(MessageBase)))) + ); + + var setup = ActorSystemSetup.Create(settings); + + using (var system = ActorSystem.Create(nameof(CustomSerializerSpec), setup)) + { + var firstMessage = new FirstMessage("First message"); + var serialization = system.Serialization; + var serializer = (CustomManifestSerializer)serialization.FindSerializerFor(firstMessage); + + var serialized = serializer.ToBinary(firstMessage); + var manifest = serializer.Manifest(firstMessage); + var deserializedFirstMessage = serializer.FromBinary(serialized, manifest); + manifest.Should().Be(FirstMessage.Manifest); + deserializedFirstMessage.Should().Be(firstMessage); + + var secondMessage = new SecondMessage("Second message"); + serialized = serializer.ToBinary(secondMessage); + manifest = serializer.Manifest(secondMessage); + var deserializedSecondMessage = serializer.FromBinary(serialized, manifest); + manifest.Should().Be(SecondMessage.Manifest); + deserializedSecondMessage.Should().Be(secondMessage); + } + } + } + + internal abstract class MessageBase: IEquatable + { + public abstract string Message { get; } + + public bool Equals(MessageBase other) + { + if (ReferenceEquals(null, other)) return false; + if (ReferenceEquals(this, other)) return true; + return Message == other.Message; + } + + public override bool Equals(object obj) + { + if (ReferenceEquals(null, obj)) return false; + if (ReferenceEquals(this, obj)) return true; + return obj is MessageBase msg && Equals(msg); + } + + public override int GetHashCode() + { + return (Message != null ? Message.GetHashCode() : 0); + } + } + + internal class FirstMessage : MessageBase + { + public const string Manifest = "FM"; + + public FirstMessage(string message) + { + Message = message; + } + + public override string Message { get; } + } + + internal class SecondMessage : MessageBase + { + public const string Manifest = "SM"; + + public SecondMessage(string message) + { + Message = message; + } + + public override string Message { get; } } + + internal class CustomManifestSerializer : SerializerWithStringManifest + { + public CustomManifestSerializer(ExtendedActorSystem system) : base(system) + { + } + + public override int Identifier => 101; + + public override byte[] ToBinary(object obj) + => Encoding.UTF8.GetBytes(((MessageBase)obj).Message); + + public override object FromBinary(byte[] bytes, string manifest) + { + switch (manifest) + { + case FirstMessage.Manifest: + return new FirstMessage(Encoding.UTF8.GetString(bytes)); + case SecondMessage.Manifest: + return new SecondMessage(Encoding.UTF8.GetString(bytes)); + default: + throw new Exception($"Unknown manifest [{manifest}]"); + } + } + public override string Manifest(object o) + { + switch (o) + { + case FirstMessage _ : + return FirstMessage.Manifest; + case SecondMessage _ : + return SecondMessage.Manifest; + default: + throw new Exception($"Unknown object type {o.GetType()}"); + } + } + } + public class CustomSerializer : Serializer { public CustomSerializer(ExtendedActorSystem system) : base(system)