|
4 | 4 | using System.Text;
|
5 | 5 | using Microsoft.AspNetCore.Connections;
|
6 | 6 | using Microsoft.AspNetCore.Internal;
|
| 7 | +using Microsoft.AspNetCore.Server.Kestrel.Transport.NamedPipes.Internal; |
7 | 8 | using Microsoft.AspNetCore.Testing;
|
8 | 9 |
|
9 | 10 | namespace Microsoft.AspNetCore.Server.Kestrel.Transport.NamedPipes.Tests;
|
@@ -39,7 +40,7 @@ public async Task InputReadAsync_ServerAborted_ThrowError()
|
39 | 40 | var clientStream = NamedPipeTestHelpers.CreateClientStream(connectionListener.EndPoint);
|
40 | 41 | await clientStream.ConnectAsync().DefaultTimeout();
|
41 | 42 | await clientStream.WriteAsync(TestData).DefaultTimeout();
|
42 |
| - |
| 43 | + |
43 | 44 | var serverConnection = await connectionListener.AcceptAsync().DefaultTimeout();
|
44 | 45 | var readResult = await serverConnection.Transport.Input.ReadAtLeastAsync(TestData.Length).DefaultTimeout();
|
45 | 46 | serverConnection.Transport.Input.AdvanceTo(readResult.Buffer.End);
|
@@ -103,4 +104,70 @@ public async Task OutputWriteAsync_ServerAborted_ThrowError()
|
103 | 104 | // Complete writing.
|
104 | 105 | await serverConnection.Transport.Output.CompleteAsync();
|
105 | 106 | }
|
| 107 | + |
| 108 | + [ConditionalFact] |
| 109 | + [OSSkipCondition(OperatingSystems.Linux | OperatingSystems.MacOSX, SkipReason = "Non-OS implementations use UDS with different transport behavior.")] |
| 110 | + public async Task CompleteTransport_BeforeClientHasReadLastBytes_DontLoseData() |
| 111 | + { |
| 112 | + var options = new NamedPipeTransportOptions(); |
| 113 | + await using var connectionListener = await NamedPipeTestHelpers.CreateConnectionListenerFactory(LoggerFactory, options: options); |
| 114 | + |
| 115 | + var clientStream = NamedPipeTestHelpers.CreateClientStream(connectionListener.EndPoint); |
| 116 | + var connectTask = clientStream.ConnectAsync(); |
| 117 | + |
| 118 | + var connection = (NamedPipeConnection)await connectionListener.AcceptAsync(); |
| 119 | + await connection.Transport.Output.WriteAsync(new byte[] { 41 }); |
| 120 | + byte[] readBuffer = new byte[1]; |
| 121 | + var readAmount = await clientStream.ReadAsync(readBuffer); |
| 122 | + Assert.Equal(1, readAmount); |
| 123 | + Assert.Equal(41, readBuffer[0]); |
| 124 | + await connection.Transport.Output.WriteAsync(new byte[] { 42 }); |
| 125 | + |
| 126 | + connection.Transport.Output.Complete(); |
| 127 | + |
| 128 | + // Wait for a short amount of time after completing transport before asserting the server is waiting for the client to finish reading. |
| 129 | + // Actual stream disconnection should happen after the last client read happens. |
| 130 | + await Task.Delay(100); |
| 131 | + Assert.False(connection._sendingTask.IsCompleted, "Sending isn't complete until the client reads data."); |
| 132 | + |
| 133 | + readAmount = await clientStream.ReadAsync(readBuffer); |
| 134 | + Assert.Equal(1, readAmount); |
| 135 | + Assert.Equal(42, readBuffer[0]); |
| 136 | + |
| 137 | + await connection._sendingTask.DefaultTimeout(); |
| 138 | + } |
| 139 | + |
| 140 | + [ConditionalFact] |
| 141 | + [OSSkipCondition(OperatingSystems.Linux | OperatingSystems.MacOSX, SkipReason = "Non-OS implementations use UDS with different transport behavior.")] |
| 142 | + public async Task DisposeAsync_BeforeClientHasReadLastBytes_DontLoseData() |
| 143 | + { |
| 144 | + var options = new NamedPipeTransportOptions(); |
| 145 | + await using var connectionListener = await NamedPipeTestHelpers.CreateConnectionListenerFactory(LoggerFactory, options: options); |
| 146 | + |
| 147 | + var clientStream = NamedPipeTestHelpers.CreateClientStream(connectionListener.EndPoint); |
| 148 | + var connectTask = clientStream.ConnectAsync(); |
| 149 | + |
| 150 | + var connection = (NamedPipeConnection)await connectionListener.AcceptAsync(); |
| 151 | + await connection.Transport.Output.WriteAsync(new byte[] { 41 }); |
| 152 | + byte[] readBuffer = new byte[1]; |
| 153 | + var readAmount = await clientStream.ReadAsync(readBuffer); |
| 154 | + Assert.Equal(1, readAmount); |
| 155 | + Assert.Equal(41, readBuffer[0]); |
| 156 | + await connection.Transport.Output.WriteAsync(new byte[] { 42 }); |
| 157 | + |
| 158 | + var disposeTask = connection.DisposeAsync(); |
| 159 | + |
| 160 | + // Wait for a short amount of time after completing transport before asserting the server is waiting for the client to finish reading. |
| 161 | + // Actual stream disconnection should happen after the last client read happens. |
| 162 | + await Task.Delay(100); |
| 163 | + Assert.False(connection._sendingTask.IsCompleted, "Sending isn't complete until the client reads data."); |
| 164 | + Assert.False(disposeTask.IsCompleted, "Sending isn't complete until the client reads data."); |
| 165 | + |
| 166 | + readAmount = await clientStream.ReadAsync(readBuffer); |
| 167 | + Assert.Equal(1, readAmount); |
| 168 | + Assert.Equal(42, readBuffer[0]); |
| 169 | + |
| 170 | + await connection._sendingTask.DefaultTimeout(); |
| 171 | + await disposeTask.DefaultTimeout(); |
| 172 | + } |
106 | 173 | }
|
0 commit comments