diff --git a/src/Neo.Hosting.App/Extensions/StreamExtensions.cs b/src/Neo.Hosting.App/Extensions/StreamExtensions.cs index 434902a6e5..aedc433ada 100644 --- a/src/Neo.Hosting.App/Extensions/StreamExtensions.cs +++ b/src/Neo.Hosting.App/Extensions/StreamExtensions.cs @@ -28,6 +28,14 @@ public static void Write(this Stream stream, T value) stream.Write(span); } + public static void Write(this Stream stream, ref T value) + where T : unmanaged + { + var tSpan = MemoryMarshal.CreateSpan(ref value, 1); + var span = MemoryMarshal.AsBytes(tSpan); + stream.Write(span); + } + public static void Write(this Stream stream, T[] values) where T : unmanaged { diff --git a/src/Neo.Hosting.App/NamedPipes/Protocol/IPipeException.cs b/src/Neo.Hosting.App/NamedPipes/Protocol/IPipeException.cs new file mode 100644 index 0000000000..e450e4b636 --- /dev/null +++ b/src/Neo.Hosting.App/NamedPipes/Protocol/IPipeException.cs @@ -0,0 +1,18 @@ +// Copyright (C) 2015-2024 The Neo Project. +// +// IPipeException.cs file belongs to the neo project and is free +// software distributed under the MIT software license, see the +// accompanying file LICENSE in the main directory of the +// repository or http://www.opensource.org/licenses/mit-license.php +// for more details. +// +// Redistribution and use in source and binary forms with or without +// modifications are permitted. + +namespace Neo.Hosting.App.NamedPipes.Protocol +{ + internal interface IPipeException + { + PipeException? Exception { get; } + } +} diff --git a/src/Neo.Hosting.App/NamedPipes/Protocol/IPipeMessage.cs b/src/Neo.Hosting.App/NamedPipes/Protocol/IPipeMessage.cs index 5afb0a115e..ff48311dc8 100644 --- a/src/Neo.Hosting.App/NamedPipes/Protocol/IPipeMessage.cs +++ b/src/Neo.Hosting.App/NamedPipes/Protocol/IPipeMessage.cs @@ -10,13 +10,14 @@ // modifications are permitted. using System.IO; +using System.Threading; using System.Threading.Tasks; namespace Neo.Hosting.App.NamedPipes.Protocol { internal interface IPipeMessage { - Task CopyToAsync(Stream stream); + Task CopyToAsync(Stream stream, CancellationToken cancellationToken = default); Task CopyFromAsync(Stream stream); byte[] ToArray(); } diff --git a/src/Neo.Hosting.App/NamedPipes/Protocol/PipeException.cs b/src/Neo.Hosting.App/NamedPipes/Protocol/PipeException.cs new file mode 100644 index 0000000000..c95d776c48 --- /dev/null +++ b/src/Neo.Hosting.App/NamedPipes/Protocol/PipeException.cs @@ -0,0 +1,80 @@ +// Copyright (C) 2015-2024 The Neo Project. +// +// PipeException.cs file belongs to the neo project and is free +// software distributed under the MIT software license, see the +// accompanying file LICENSE in the main directory of the +// repository or http://www.opensource.org/licenses/mit-license.php +// for more details. +// +// Redistribution and use in source and binary forms with or without +// modifications are permitted. + +using Neo.Hosting.App.Extensions; +using System.IO; +using System.Threading; +using System.Threading.Tasks; + +namespace Neo.Hosting.App.NamedPipes.Protocol +{ + internal sealed class PipeException : IPipeMessage + { + public const ulong Magic = 0x4552524f524d5347ul; // ERRORMSG + + public required bool IsEmpty { get; set; } + public string? Message { get; set; } + public string? StackTrace { get; set; } + + public Task CopyFromAsync(Stream stream) + { + if (stream.CanRead == false) + throw new IOException(); + + var magic = stream.Read(); + if (magic != Magic) + throw new InvalidDataException(); + + IsEmpty = stream.Read(); + + if (IsEmpty) + return Task.CompletedTask; + + Message = stream.ReadString(); + StackTrace = stream.ReadString(); + + if (string.IsNullOrEmpty(StackTrace)) + StackTrace = null; + + return Task.CompletedTask; + } + + public Task CopyToAsync(Stream stream, CancellationToken cancellationToken = default) + { + if (stream.CanWrite == false) + throw new IOException(); + + CopyToStream(stream); + return stream.FlushAsync(cancellationToken); + } + + public byte[] ToArray() + { + using var ms = new MemoryStream(); + CopyToStream(ms); + return ms.ToArray(); + } + + private void CopyToStream(Stream stream) + { + stream.Write(Magic); + + if (IsEmpty) + stream.Write(true); + else + { + stream.Write(false); + stream.Write(Message!); + stream.Write(StackTrace ?? string.Empty); + } + } + } +} diff --git a/src/Neo.Hosting.App/NamedPipes/Protocol/PipeMessage.cs b/src/Neo.Hosting.App/NamedPipes/Protocol/PipeMessage.cs new file mode 100644 index 0000000000..fbc7d97e92 --- /dev/null +++ b/src/Neo.Hosting.App/NamedPipes/Protocol/PipeMessage.cs @@ -0,0 +1,88 @@ +// Copyright (C) 2015-2024 The Neo Project. +// +// PipeMessage.cs file belongs to the neo project and is free +// software distributed under the MIT software license, see the +// accompanying file LICENSE in the main directory of the +// repository or http://www.opensource.org/licenses/mit-license.php +// for more details. +// +// Redistribution and use in source and binary forms with or without +// modifications are permitted. + +using Neo.Hosting.App.Extensions; +using System; +using System.IO; +using System.Threading; +using System.Threading.Tasks; + +namespace Neo.Hosting.App.NamedPipes.Protocol +{ + internal sealed class PipeMessage : IPipeMessage, IPipeException + where TMessage : class, IPipeMessage, new() + { + public const ulong Magic = 0x4d45535341474531ul; // MESSAGE1 + + public TMessage Payload { get; private set; } + + public PipeException Exception { get; private set; } + + public PipeMessage() + { + Payload = new TMessage(); + Exception = new() { IsEmpty = true }; + } + + public static PipeMessage Create(TMessage payload, Exception? exception = null) => + new() + { + Payload = payload, + Exception = new() + { + IsEmpty = exception is null, + Message = exception?.InnerException?.Message ?? exception?.Message, + StackTrace = exception?.InnerException?.StackTrace ?? exception?.StackTrace, + }, + }; + + public async Task CopyFromAsync(Stream stream) + { + if (stream.CanRead == false) + throw new IOException(); + + var magic = stream.Read(); + if (magic != Magic) + throw new InvalidDataException(); + + await Payload.CopyFromAsync(stream); + await Exception.CopyFromAsync(stream); + } + + public async Task CopyToAsync(Stream stream, CancellationToken cancellationToken = default) + { + if (stream.CanWrite == false) + throw new IOException(); + + stream.Write(Magic); + + await Payload.CopyToAsync(stream, cancellationToken); + await Exception.CopyToAsync(stream, cancellationToken); + } + + public byte[] ToArray() + { + using var ms = new MemoryStream(); + + ms.Write(Magic); + + var task = Payload.CopyToAsync(ms); + if (task.IsCompleted == false) + task.RunSynchronously(); + + task = Exception.CopyToAsync(ms); + if (task.IsCompleted == false) + task.RunSynchronously(); + + return ms.ToArray(); + } + } +} diff --git a/src/Neo.Hosting.App/NamedPipes/Protocol/PipeVersion.cs b/src/Neo.Hosting.App/NamedPipes/Protocol/PipeVersion.cs index d76076b39c..1f7418ea05 100644 --- a/src/Neo.Hosting.App/NamedPipes/Protocol/PipeVersion.cs +++ b/src/Neo.Hosting.App/NamedPipes/Protocol/PipeVersion.cs @@ -41,7 +41,7 @@ internal sealed class PipeVersion : IPipeMessage public PipeVersion() { VersionNumber = Program.ApplicationVersionNumber; - Plugins = Plugin.Plugins.ToDictionary(k => k.Name, v => v.Version, StringComparer.OrdinalIgnoreCase); + Plugins = Plugin.Plugins.ToDictionary(k => k.Name, v => v.Version, StringComparer.InvariantCultureIgnoreCase); Platform = Environment.OSVersion.Platform; TimeStamp = DateTime.UtcNow; MachineName = Environment.MachineName; @@ -65,7 +65,7 @@ public Task CopyFromAsync(Stream stream) VersionNumber = version; - var plugins = new Dictionary(StringComparer.OrdinalIgnoreCase); + var plugins = new Dictionary(StringComparer.InvariantCultureIgnoreCase); var count = stream.Read(); for (var i = 0; i < count; i++) @@ -85,14 +85,11 @@ public Task CopyFromAsync(Stream stream) return Task.CompletedTask; } - public Task CopyToAsync(Stream stream) - { - CopyToStream(stream); - return stream.FlushAsync(); - } - public Task CopyToAsync(Stream stream, CancellationToken cancellationToken = default) { + if (stream.CanWrite == false) + throw new IOException(); + CopyToStream(stream); return stream.FlushAsync(cancellationToken); } @@ -106,6 +103,9 @@ public byte[] ToArray() private void CopyToStream(Stream stream) { + if (stream.CanWrite == false) + throw new IOException(); + stream.Write(Magic); stream.Write(Program.ApplicationVersionNumber); diff --git a/tests/Neo.Hosting.App.Tests/NamedPipes/Protocol/TestPipeException.cs b/tests/Neo.Hosting.App.Tests/NamedPipes/Protocol/TestPipeException.cs new file mode 100644 index 0000000000..1f6d853539 --- /dev/null +++ b/tests/Neo.Hosting.App.Tests/NamedPipes/Protocol/TestPipeException.cs @@ -0,0 +1,99 @@ +// Copyright (C) 2015-2024 The Neo Project. +// +// TestPipeException.cs file belongs to the neo project and is free +// software distributed under the MIT software license, see the +// accompanying file LICENSE in the main directory of the +// repository or http://www.opensource.org/licenses/mit-license.php +// for more details. +// +// Redistribution and use in source and binary forms with or without +// modifications are permitted. + +using Akka.Util; +using Neo.Hosting.App.Extensions; +using Neo.Hosting.App.NamedPipes.Protocol; +using System.Diagnostics; +using Xunit.Abstractions; + +namespace Neo.Hosting.App.Tests.NamedPipes.Protocol +{ + public class TestPipeException + (ITestOutputHelper testOutputHelper) + { + private static readonly string s_exceptionMessage = "Test1"; + private static readonly string s_exceptionStackTrace = "Test2"; + + private readonly ITestOutputHelper _testOutputHelper = testOutputHelper; + + [Fact] + public async Task IPipeMessage_CopyFromAsync() + { + var exception1 = new PipeException() + { + IsEmpty = false, + Message = s_exceptionMessage, + StackTrace = s_exceptionStackTrace + }; + var expectedBytes = exception1.ToArray(); + var expectedHexString = Convert.ToHexString(expectedBytes); + + using var ms1 = new MemoryStream(); + await exception1.CopyToAsync(ms1).DefaultTimeout(); + + var exception2 = new PipeException() { IsEmpty = true }; + ms1.Position = 0; + await exception2.CopyFromAsync(ms1).DefaultTimeout(); + + var actualBytes = exception2.ToArray(); + var actualHexString = Convert.ToHexString(actualBytes); + + var className = nameof(PipeVersion); + var methodName = nameof(PipeVersion.CopyFromAsync); + _testOutputHelper.WriteLine(nameof(Debug).PadCenter(17, '-')); + _testOutputHelper.WriteLine($" Class: {className}"); + _testOutputHelper.WriteLine($" Method: {methodName}"); + + _testOutputHelper.WriteLine(nameof(Result).PadCenter(17, '-')); + _testOutputHelper.WriteLine($" Actual: {actualHexString}"); + _testOutputHelper.WriteLine($" Expected: {expectedHexString}"); + _testOutputHelper.WriteLine($"-----------------"); + + Assert.Equal(expectedBytes, actualBytes); + Assert.Equal(exception1.IsEmpty, exception2.IsEmpty); + Assert.Equal(exception1.Message, exception2.Message); + Assert.Equal(exception1.StackTrace, exception2.StackTrace); + } + + [Fact] + public async Task IPipeMessage_CopyToAsync() + { + var exception = new PipeException() + { + IsEmpty = false, + Message = s_exceptionMessage, + StackTrace = s_exceptionStackTrace + }; + var expectedBytes = exception.ToArray(); + var expectedHexString = Convert.ToHexString(expectedBytes); + + using var ms = new MemoryStream(); + await exception.CopyToAsync(ms).DefaultTimeout(); + + var actualBytes = ms.ToArray(); + var actualHexString = Convert.ToHexString(actualBytes); + + var className = nameof(PipeVersion); + var methodName = nameof(PipeVersion.CopyToAsync); + _testOutputHelper.WriteLine(nameof(Debug).PadCenter(17, '-')); + _testOutputHelper.WriteLine($" Class: {className}"); + _testOutputHelper.WriteLine($" Method: {methodName}"); + + _testOutputHelper.WriteLine(nameof(Result).PadCenter(17, '-')); + _testOutputHelper.WriteLine($" Actual: {actualHexString}"); + _testOutputHelper.WriteLine($" Expected: {expectedHexString}"); + _testOutputHelper.WriteLine($"-----------------"); + + Assert.Equal(expectedBytes, actualBytes); + } + } +} diff --git a/tests/Neo.Hosting.App.Tests/NamedPipes/Protocol/TestPipeMessage.cs b/tests/Neo.Hosting.App.Tests/NamedPipes/Protocol/TestPipeMessage.cs new file mode 100644 index 0000000000..7fc0704a78 --- /dev/null +++ b/tests/Neo.Hosting.App.Tests/NamedPipes/Protocol/TestPipeMessage.cs @@ -0,0 +1,169 @@ +// Copyright (C) 2015-2024 The Neo Project. +// +// TestPipeMessage.cs file belongs to the neo project and is free +// software distributed under the MIT software license, see the +// accompanying file LICENSE in the main directory of the +// repository or http://www.opensource.org/licenses/mit-license.php +// for more details. +// +// Redistribution and use in source and binary forms with or without +// modifications are permitted. + +using Akka.Util; +using Neo.Hosting.App.Extensions; +using Neo.Hosting.App.NamedPipes.Protocol; +using System.Diagnostics; +using Xunit.Abstractions; + +namespace Neo.Hosting.App.Tests.NamedPipes.Protocol +{ + public class TestPipeMessage + (ITestOutputHelper testOutputHelper) + { + private static readonly string s_exceptionMessage = "Test"; + private static readonly Exception s_testException = new(s_exceptionMessage); + + private readonly ITestOutputHelper _testOutputHelper = testOutputHelper; + + + [Fact] + public async Task IPipeMessage_CopyFromAsync_NoException() + { + var message1 = new PipeMessage(); + var expectedBytes = message1.ToArray(); + var expectedHexString = Convert.ToHexString(expectedBytes); + + using var ms1 = new MemoryStream(); + await message1.CopyToAsync(ms1).DefaultTimeout(); + + var message2 = new PipeMessage(); + ms1.Position = 0; + await message2.CopyFromAsync(ms1).DefaultTimeout(); + + var actualBytes = message2.ToArray(); + var actualHexString = Convert.ToHexString(actualBytes); + + var className = nameof(PipeMessage); + var methodName = nameof(PipeVersion.CopyFromAsync); + _testOutputHelper.WriteLine(nameof(Debug).PadCenter(17, '-')); + _testOutputHelper.WriteLine($" Class: {className}"); + _testOutputHelper.WriteLine($" Method: {methodName}"); + + _testOutputHelper.WriteLine(nameof(Result).PadCenter(17, '-')); + _testOutputHelper.WriteLine($" Actual: {actualHexString}"); + _testOutputHelper.WriteLine($" Expected: {expectedHexString}"); + _testOutputHelper.WriteLine($"-----------------"); + + Assert.Equal(expectedBytes, actualBytes); + Assert.Equal(message1.Payload.VersionNumber, message2.Payload.VersionNumber); + Assert.Equal(message1.Payload.Plugins, message2.Payload.Plugins); + Assert.Equal(message1.Payload.Platform, message2.Payload.Platform); + Assert.Equal(message1.Payload.TimeStamp, message2.Payload.TimeStamp); + Assert.Equal(message1.Payload.MachineName, message2.Payload.MachineName); + Assert.Equal(message1.Payload.UserName, message2.Payload.UserName); + Assert.Equal(message1.Payload.ProcessId, message2.Payload.ProcessId); + Assert.Equal(message1.Payload.ProcessPath, message2.Payload.ProcessPath); + Assert.True(message2.Exception.IsEmpty); + Assert.Null(message2.Exception.Message); + Assert.Null(message2.Exception.StackTrace); + } + + [Fact] + public async Task IPipeMessage_CopyFromAsync_WithException() + { + var version = new PipeVersion(); + var message1 = PipeMessage.Create(version, s_testException); + var expectedBytes = message1.ToArray(); + var expectedHexString = Convert.ToHexString(expectedBytes); + + using var ms1 = new MemoryStream(); + await message1.CopyToAsync(ms1).DefaultTimeout(); + + var message2 = new PipeMessage(); + ms1.Position = 0; + await message2.CopyFromAsync(ms1).DefaultTimeout(); + + var actualBytes = message2.ToArray(); + var actualHexString = Convert.ToHexString(actualBytes); + + var className = nameof(PipeMessage); + var methodName = nameof(PipeVersion.CopyFromAsync); + _testOutputHelper.WriteLine(nameof(Debug).PadCenter(17, '-')); + _testOutputHelper.WriteLine($" Class: {className}"); + _testOutputHelper.WriteLine($" Method: {methodName}"); + + _testOutputHelper.WriteLine(nameof(Result).PadCenter(17, '-')); + _testOutputHelper.WriteLine($" Actual: {actualHexString}"); + _testOutputHelper.WriteLine($" Expected: {expectedHexString}"); + _testOutputHelper.WriteLine($"-----------------"); + + Assert.Equal(expectedBytes, actualBytes); + Assert.Equal(message1.Payload.VersionNumber, message2.Payload.VersionNumber); + Assert.Equal(message1.Payload.Plugins, message2.Payload.Plugins); + Assert.Equal(message1.Payload.Platform, message2.Payload.Platform); + Assert.Equal(message1.Payload.TimeStamp, message2.Payload.TimeStamp); + Assert.Equal(message1.Payload.MachineName, message2.Payload.MachineName); + Assert.Equal(message1.Payload.UserName, message2.Payload.UserName); + Assert.Equal(message1.Payload.ProcessId, message2.Payload.ProcessId); + Assert.Equal(message1.Payload.ProcessPath, message2.Payload.ProcessPath); + Assert.False(message2.Exception.IsEmpty); + Assert.Equal(s_exceptionMessage, message2.Exception.Message); + Assert.Null(message2.Exception.StackTrace); + } + + [Fact] + public async Task IPipeMessage_CopyToAsync_WithException() + { + var version = new PipeVersion(); + var message1 = PipeMessage.Create(version, s_testException); + var expectedBytes = message1.ToArray(); + var expectedHexString = Convert.ToHexString(expectedBytes); + + using var ms = new MemoryStream(); + await message1.CopyToAsync(ms).DefaultTimeout(); + + var actualBytes = ms.ToArray(); + var actualHexString = Convert.ToHexString(actualBytes); + + var className = nameof(PipeVersion); + var methodName = nameof(PipeVersion.CopyToAsync); + _testOutputHelper.WriteLine(nameof(Debug).PadCenter(17, '-')); + _testOutputHelper.WriteLine($" Class: {className}"); + _testOutputHelper.WriteLine($" Method: {methodName}"); + + _testOutputHelper.WriteLine(nameof(Result).PadCenter(17, '-')); + _testOutputHelper.WriteLine($" Actual: {actualHexString}"); + _testOutputHelper.WriteLine($" Expected: {expectedHexString}"); + _testOutputHelper.WriteLine($"-----------------"); + + Assert.Equal(expectedBytes, actualBytes); + } + + [Fact] + public async Task IPipeMessage_CopyToAsync_NoException() + { + var message1 = new PipeMessage(); + var expectedBytes = message1.ToArray(); + var expectedHexString = Convert.ToHexString(expectedBytes); + + using var ms = new MemoryStream(); + await message1.CopyToAsync(ms).DefaultTimeout(); + + var actualBytes = ms.ToArray(); + var actualHexString = Convert.ToHexString(actualBytes); + + var className = nameof(PipeVersion); + var methodName = nameof(PipeVersion.CopyToAsync); + _testOutputHelper.WriteLine(nameof(Debug).PadCenter(17, '-')); + _testOutputHelper.WriteLine($" Class: {className}"); + _testOutputHelper.WriteLine($" Method: {methodName}"); + + _testOutputHelper.WriteLine(nameof(Result).PadCenter(17, '-')); + _testOutputHelper.WriteLine($" Actual: {actualHexString}"); + _testOutputHelper.WriteLine($" Expected: {expectedHexString}"); + _testOutputHelper.WriteLine($"-----------------"); + + Assert.Equal(expectedBytes, actualBytes); + } + } +} diff --git a/tests/Neo.Hosting.App.Tests/NamedPipes/Protocol/TestPipeVersion.cs b/tests/Neo.Hosting.App.Tests/NamedPipes/Protocol/TestPipeVersion.cs new file mode 100644 index 0000000000..5da6120418 --- /dev/null +++ b/tests/Neo.Hosting.App.Tests/NamedPipes/Protocol/TestPipeVersion.cs @@ -0,0 +1,91 @@ +// Copyright (C) 2015-2024 The Neo Project. +// +// TestPipeVersion.cs file belongs to the neo project and is free +// software distributed under the MIT software license, see the +// accompanying file LICENSE in the main directory of the +// repository or http://www.opensource.org/licenses/mit-license.php +// for more details. +// +// Redistribution and use in source and binary forms with or without +// modifications are permitted. + +using Akka.Util; +using Neo.Hosting.App.Extensions; +using Neo.Hosting.App.NamedPipes.Protocol; +using System.Diagnostics; +using Xunit.Abstractions; + +namespace Neo.Hosting.App.Tests.NamedPipes.Protocol +{ + public class TestPipeVersion + (ITestOutputHelper testOutputHelper) + { + private readonly ITestOutputHelper _testOutputHelper = testOutputHelper; + + [Fact] + public async Task IPipeMessage_CopyFromAsync() + { + var version1 = new PipeVersion(); + var expectedBytes = version1.ToArray(); + var expectedHexString = Convert.ToHexString(expectedBytes); + + using var ms1 = new MemoryStream(); + await version1.CopyToAsync(ms1).DefaultTimeout(); + + var version2 = new PipeVersion(); + ms1.Position = 0; + await version2.CopyFromAsync(ms1).DefaultTimeout(); + + var actualBytes = version2.ToArray(); + var actualHexString = Convert.ToHexString(actualBytes); + + var className = nameof(PipeVersion); + var methodName = nameof(PipeVersion.CopyFromAsync); + _testOutputHelper.WriteLine(nameof(Debug).PadCenter(17, '-')); + _testOutputHelper.WriteLine($" Class: {className}"); + _testOutputHelper.WriteLine($" Method: {methodName}"); + + _testOutputHelper.WriteLine(nameof(Result).PadCenter(17, '-')); + _testOutputHelper.WriteLine($" Actual: {actualHexString}"); + _testOutputHelper.WriteLine($" Expected: {expectedHexString}"); + _testOutputHelper.WriteLine($"-----------------"); + + Assert.Equal(expectedBytes, actualBytes); + Assert.Equal(version1.VersionNumber, version2.VersionNumber); + Assert.Equal(version1.Plugins, version2.Plugins); + Assert.Equal(version1.Platform, version2.Platform); + Assert.Equal(version1.TimeStamp, version2.TimeStamp); + Assert.Equal(version1.MachineName, version2.MachineName); + Assert.Equal(version1.UserName, version2.UserName); + Assert.Equal(version1.ProcessId, version2.ProcessId); + Assert.Equal(version1.ProcessPath, version2.ProcessPath); + } + + [Fact] + public async Task IPipeMessage_CopyToAsync() + { + var version = new PipeVersion(); + var expectedBytes = version.ToArray(); + var expectedHexString = Convert.ToHexString(expectedBytes); + + using var ms = new MemoryStream(); + await version.CopyToAsync(ms).DefaultTimeout(); + + var actualBytes = ms.ToArray(); + var actualHexString = Convert.ToHexString(actualBytes); + + var className = nameof(PipeVersion); + var methodName = nameof(PipeVersion.CopyToAsync); + _testOutputHelper.WriteLine(nameof(Debug).PadCenter(17, '-')); + _testOutputHelper.WriteLine($" Class: {className}"); + _testOutputHelper.WriteLine($" Method: {methodName}"); + + _testOutputHelper.WriteLine(nameof(Result).PadCenter(17, '-')); + _testOutputHelper.WriteLine($" Actual: {actualHexString}"); + _testOutputHelper.WriteLine($" Expected: {expectedHexString}"); + _testOutputHelper.WriteLine($"-----------------"); + + Assert.Equal(expectedBytes, actualBytes); + } + } +} diff --git a/tests/Neo.Hosting.App.Tests/NamedPipes/TestIPCProtocol.cs b/tests/Neo.Hosting.App.Tests/NamedPipes/TestIPCProtocol.cs index 824dbd443c..d3dfc01e8f 100644 --- a/tests/Neo.Hosting.App.Tests/NamedPipes/TestIPCProtocol.cs +++ b/tests/Neo.Hosting.App.Tests/NamedPipes/TestIPCProtocol.cs @@ -9,11 +9,8 @@ // Redistribution and use in source and binary forms with or without // modifications are permitted. -using Akka.Util; using Neo.Hosting.App.Extensions; using Neo.Hosting.App.Factories; -using Neo.Hosting.App.NamedPipes.Protocol; -using System.Diagnostics; using System.Text; using Xunit.Abstractions; @@ -26,33 +23,6 @@ public class TestIPCProtocol private readonly ITestOutputHelper _testOutputHelper = testOutputHelper; - [Fact] - public async Task PipeVersion_CopyToAsync() - { - var version = new PipeVersion(); - var expectedBytes = version.ToArray(); - var expectedHexString = Convert.ToHexString(expectedBytes); - - using var ms = new MemoryStream(); - await version.CopyToAsync(ms).DefaultTimeout(); - - var actualBytes = ms.ToArray(); - var actualHexString = Convert.ToHexString(actualBytes); - - var className = nameof(PipeVersion); - var methodName = nameof(PipeVersion.CopyToAsync); - _testOutputHelper.WriteLine(nameof(Debug).PadCenter(17, '-')); - _testOutputHelper.WriteLine($" Class: {className}"); - _testOutputHelper.WriteLine($" Method: {methodName}"); - - _testOutputHelper.WriteLine(nameof(Result).PadCenter(17, '-')); - _testOutputHelper.WriteLine($" Actual: {actualHexString}"); - _testOutputHelper.WriteLine($" Expected: {expectedHexString}"); - _testOutputHelper.WriteLine($"-----------------"); - - Assert.Equal(expectedBytes, actualBytes); - } - [Fact] public async Task BidirectionalStream_ServerReadsDataAndCompletes_GracefullyClosed() {