diff --git a/.gitignore b/.gitignore index 12d027be13..67f7451e58 100644 --- a/.gitignore +++ b/.gitignore @@ -2,4 +2,5 @@ node_modules/ .BUILD_COMPLETED lerna-debug.log .DS_Store -.idea \ No newline at end of file +.idea +dist \ No newline at end of file diff --git a/packages/jsii-dotnet-runtime-test/test/Amazon.JSII.Runtime.IntegrationTests/ComplianceTests.cs b/packages/jsii-dotnet-runtime-test/test/Amazon.JSII.Runtime.IntegrationTests/ComplianceTests.cs index 203f98160a..a464ae836e 100644 --- a/packages/jsii-dotnet-runtime-test/test/Amazon.JSII.Runtime.IntegrationTests/ComplianceTests.cs +++ b/packages/jsii-dotnet-runtime-test/test/Amazon.JSII.Runtime.IntegrationTests/ComplianceTests.cs @@ -861,7 +861,7 @@ public void NullShouldBeTreatedAsUndefined() obj.ChangeMeToUndefined = null; obj.VerifyPropertyIsUndefined(); } - + [Fact(DisplayName = Prefix + nameof(JsiiAgent))] public void JsiiAgent() { diff --git a/packages/jsii-dotnet-runtime/.gitignore b/packages/jsii-dotnet-runtime/.gitignore index 720c810bbb..4ea90d1e30 100644 --- a/packages/jsii-dotnet-runtime/.gitignore +++ b/packages/jsii-dotnet-runtime/.gitignore @@ -23,3 +23,4 @@ coverage/ bin/ cli/ obj/ +*.DotSettings.user diff --git a/packages/jsii-dotnet-runtime/src/Amazon.JSII.Runtime.UnitTests/Amazon.JSII.Runtime.UnitTests.csproj b/packages/jsii-dotnet-runtime/src/Amazon.JSII.Runtime.UnitTests/Amazon.JSII.Runtime.UnitTests.csproj index 314f5e1055..f910b9187a 100644 --- a/packages/jsii-dotnet-runtime/src/Amazon.JSII.Runtime.UnitTests/Amazon.JSII.Runtime.UnitTests.csproj +++ b/packages/jsii-dotnet-runtime/src/Amazon.JSII.Runtime.UnitTests/Amazon.JSII.Runtime.UnitTests.csproj @@ -1,4 +1,4 @@ - + netcoreapp2.0 diff --git a/packages/jsii-dotnet-runtime/src/Amazon.JSII.Runtime.UnitTests/Client/RuntimeTests.cs b/packages/jsii-dotnet-runtime/src/Amazon.JSII.Runtime.UnitTests/Client/RuntimeTests.cs new file mode 100644 index 0000000000..30382ec3ea --- /dev/null +++ b/packages/jsii-dotnet-runtime/src/Amazon.JSII.Runtime.UnitTests/Client/RuntimeTests.cs @@ -0,0 +1,41 @@ +using System.IO; +using Amazon.JSII.Runtime.Services; +using NSubstitute; +using NSubstitute.ReturnsExtensions; +using Xunit; + +namespace Amazon.JSII.Runtime.UnitTests.Client +{ + public class RuntimeTests + { + private const string Prefix = "Runtime."; + + private INodeProcess _nodeProcessMock; + private TextReader _standardOutputMock; + private TextReader _standardErrorMock; + + private IRuntime _sut; + + public RuntimeTests() + { + _nodeProcessMock = Substitute.For(); + _standardOutputMock = Substitute.For(); + _standardErrorMock = Substitute.For(); + + _nodeProcessMock.StandardOutput.Returns(_standardOutputMock); + _nodeProcessMock.StandardError.Returns(_standardErrorMock); + + _sut = new Services.Runtime(_nodeProcessMock); + } + + [Fact(DisplayName = Prefix + nameof(ThrowsJsiiExceptionWhenResponseNotReceived))] + public void ThrowsJsiiExceptionWhenResponseNotReceived() + { + _nodeProcessMock.StandardOutput.ReadLine().ReturnsNull(); + _nodeProcessMock.StandardError.ReadToEnd().Returns("This is a test."); + + var ex = Assert.Throws(() => _sut.ReadResponse()); + Assert.Equal("Child process exited unexpectedly: This is a test.", ex.Message); + } + } +} \ No newline at end of file diff --git a/packages/jsii-dotnet-runtime/src/Amazon.JSII.Runtime/JsiiException.cs b/packages/jsii-dotnet-runtime/src/Amazon.JSII.Runtime/JsiiException.cs index 996770b66d..d7390dbd3a 100644 --- a/packages/jsii-dotnet-runtime/src/Amazon.JSII.Runtime/JsiiException.cs +++ b/packages/jsii-dotnet-runtime/src/Amazon.JSII.Runtime/JsiiException.cs @@ -1,5 +1,5 @@ -using Amazon.JSII.JsonModel.Api.Response; -using System; +using System; +using Amazon.JSII.JsonModel.Api.Response; namespace Amazon.JSII.Runtime { @@ -7,6 +7,10 @@ public class JsiiException : Exception { public ErrorResponse ErrorResponse { get; } + public JsiiException(string message) : base(message) + { + } + public JsiiException(string message, Exception innerException) : base(message, innerException) { diff --git a/packages/jsii-dotnet-runtime/src/Amazon.JSII.Runtime/Services/INodeProcess.cs b/packages/jsii-dotnet-runtime/src/Amazon.JSII.Runtime/Services/INodeProcess.cs index 635837dc5a..7da3671bdc 100644 --- a/packages/jsii-dotnet-runtime/src/Amazon.JSII.Runtime/Services/INodeProcess.cs +++ b/packages/jsii-dotnet-runtime/src/Amazon.JSII.Runtime/Services/INodeProcess.cs @@ -5,8 +5,10 @@ namespace Amazon.JSII.Runtime.Services { public interface INodeProcess : IDisposable { - StreamWriter StandardInput { get; } + TextWriter StandardInput { get; } - StreamReader StandardOutput { get; } + TextReader StandardOutput { get; } + + TextReader StandardError { get; } } -} +} \ No newline at end of file diff --git a/packages/jsii-dotnet-runtime/src/Amazon.JSII.Runtime/Services/NodeProcess.cs b/packages/jsii-dotnet-runtime/src/Amazon.JSII.Runtime/Services/NodeProcess.cs index d3f0cd22f3..3d715a0f82 100644 --- a/packages/jsii-dotnet-runtime/src/Amazon.JSII.Runtime/Services/NodeProcess.cs +++ b/packages/jsii-dotnet-runtime/src/Amazon.JSII.Runtime/Services/NodeProcess.cs @@ -1,7 +1,7 @@ -using Microsoft.Extensions.Logging; -using System; +using System; using System.Diagnostics; using System.IO; +using Microsoft.Extensions.Logging; namespace Amazon.JSII.Runtime.Services { @@ -23,10 +23,11 @@ public NodeProcess(IJsiiRuntimeProvider jsiiRuntimeProvider, ILoggerFactory logg Arguments = "--max-old-space-size=4096 " + jsiiRuntimeProvider.JsiiRuntimePath, RedirectStandardInput = true, RedirectStandardOutput = true, + RedirectStandardError = true } }; - _process.StartInfo.EnvironmentVariables.Add("JSII_AGENT", "DotNet/" + Environment.Version.ToString()); + _process.StartInfo.EnvironmentVariables.Add("JSII_AGENT", "DotNet/" + Environment.Version); _logger.LogDebug("Starting jsii runtime..."); _logger.LogDebug($"{_process.StartInfo.FileName} {_process.StartInfo.Arguments}"); @@ -34,13 +35,18 @@ public NodeProcess(IJsiiRuntimeProvider jsiiRuntimeProvider, ILoggerFactory logg _process.Start(); } - public StreamWriter StandardInput => _process.StandardInput; + public TextWriter StandardInput => _process.StandardInput; - public StreamReader StandardOutput => _process.StandardOutput; + public TextReader StandardOutput => _process.StandardOutput; + + public TextReader StandardError => _process.StandardError; void IDisposable.Dispose() { + StandardInput.Dispose(); + StandardOutput.Dispose(); + StandardError.Dispose(); _process.Dispose(); } } -} +} \ No newline at end of file diff --git a/packages/jsii-dotnet-runtime/src/Amazon.JSII.Runtime/Services/Runtime.cs b/packages/jsii-dotnet-runtime/src/Amazon.JSII.Runtime/Services/Runtime.cs index 5f1cc7ceac..bbb4550df6 100644 --- a/packages/jsii-dotnet-runtime/src/Amazon.JSII.Runtime/Services/Runtime.cs +++ b/packages/jsii-dotnet-runtime/src/Amazon.JSII.Runtime/Services/Runtime.cs @@ -1,4 +1,5 @@ using System; +using System.Threading.Tasks; namespace Amazon.JSII.Runtime.Services { @@ -9,11 +10,22 @@ public class Runtime : IRuntime public Runtime(INodeProcess nodeProcess) { _nodeProcess = nodeProcess ?? throw new ArgumentNullException(nameof(nodeProcess)); + if (Environment.GetEnvironmentVariable("JSII_DEBUG") != null) + { + Task.Run(() => RedirectStandardError()); + } } public string ReadResponse() { - return _nodeProcess.StandardOutput.ReadLine(); + var response = _nodeProcess.StandardOutput.ReadLine(); + if (string.IsNullOrEmpty(response)) + { + var errorMessage = _nodeProcess.StandardError.ReadToEnd(); + throw new JsiiException("Child process exited unexpectedly: " + errorMessage); + } + + return response; } public void WriteRequest(string request) @@ -31,5 +43,13 @@ public void WriteRequest(string request) _nodeProcess.StandardInput.WriteLine(request); _nodeProcess.StandardInput.Flush(); } + + private void RedirectStandardError() + { + while (true) + { + Console.WriteLine(_nodeProcess.StandardError.ReadLine()); + } + } } -} +} \ No newline at end of file