-
Notifications
You must be signed in to change notification settings - Fork 1k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Added
PipeMessage
, IPipeException
and PipeException
with tests
- Loading branch information
1 parent
2b7539d
commit e3cdba5
Showing
10 changed files
with
563 additions
and
39 deletions.
There are no files selected for viewing
This file contains 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 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,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; } | ||
} | ||
} |
This file contains 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 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,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<ulong>(); | ||
if (magic != Magic) | ||
throw new InvalidDataException(); | ||
|
||
IsEmpty = stream.Read<bool>(); | ||
|
||
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); | ||
} | ||
} | ||
} | ||
} |
This file contains 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,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<TMessage> : 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<TMessage> 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<ulong>(); | ||
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(); | ||
} | ||
} | ||
} |
This file contains 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
99 changes: 99 additions & 0 deletions
99
tests/Neo.Hosting.App.Tests/NamedPipes/Protocol/TestPipeException.cs
This file contains 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,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); | ||
} | ||
} | ||
} |
Oops, something went wrong.