1 // Licensed to the .NET Foundation under one or more agreements.
2 // The .NET Foundation licenses this file to you under the MIT license.
3 // See the LICENSE file in the project root for more information.
4 
5 using System.Collections.Generic;
6 using System.Linq;
7 using System.Runtime.InteropServices;
8 using System.Threading;
9 using System.Threading.Tasks;
10 using Xunit;
11 
12 namespace System.IO.Pipes.Tests
13 {
14     /// <summary>
15     /// The Simple NamedPipe tests cover potentially every-day scenarios that are shared
16     /// by all NamedPipes whether they be Server/Client or In/Out/Inout.
17     /// </summary>
18     public abstract class NamedPipeTest_Simple : NamedPipeTestBase
19     {
20         /// <summary>
21         /// Yields every combination of testing options for the OneWayReadWrites test
22         /// </summary>
23         /// <returns></returns>
OneWayReadWritesMemberData()24         public static IEnumerable<object[]> OneWayReadWritesMemberData()
25         {
26             var options = new[] { PipeOptions.None, PipeOptions.Asynchronous };
27             var bools = new[] { false, true };
28             foreach (PipeOptions serverOption in options)
29                 foreach (PipeOptions clientOption in options)
30                     foreach (bool asyncServerOps in bools)
31                         foreach (bool asyncClientOps in bools)
32                             yield return new object[] { serverOption, clientOption, asyncServerOps, asyncClientOps };
33         }
34 
35         [Theory]
36         [MemberData(nameof(OneWayReadWritesMemberData))]
OneWayReadWrites(PipeOptions serverOptions, PipeOptions clientOptions, bool asyncServerOps, bool asyncClientOps)37         public async Task OneWayReadWrites(PipeOptions serverOptions, PipeOptions clientOptions, bool asyncServerOps, bool asyncClientOps)
38         {
39             using (NamedPipePair pair = CreateNamedPipePair(serverOptions, clientOptions))
40             {
41                 NamedPipeClientStream client = pair.clientStream;
42                 NamedPipeServerStream server = pair.serverStream;
43                 byte[] received = new byte[] { 0 };
44                 Task clientTask = Task.Run(async () =>
45                 {
46                     if (asyncClientOps)
47                     {
48                         await client.ConnectAsync();
49                         if (pair.writeToServer)
50                         {
51                             received = await ReadBytesAsync(client, sendBytes.Length);
52                         }
53                         else
54                         {
55                             await WriteBytesAsync(client, sendBytes);
56                         }
57                     }
58                     else
59                     {
60                         client.Connect();
61                         if (pair.writeToServer)
62                         {
63                             received = ReadBytes(client, sendBytes.Length);
64                         }
65                         else
66                         {
67                             WriteBytes(client, sendBytes);
68                         }
69                     }
70                 });
71                 if (asyncServerOps)
72                 {
73                     await server.WaitForConnectionAsync();
74                     if (pair.writeToServer)
75                     {
76                         await WriteBytesAsync(server, sendBytes);
77                     }
78                     else
79                     {
80                         received = await ReadBytesAsync(server, sendBytes.Length);
81                     }
82                 }
83                 else
84                 {
85                     server.WaitForConnection();
86                     if (pair.writeToServer)
87                     {
88                         WriteBytes(server, sendBytes);
89                     }
90                     else
91                     {
92                         received = ReadBytes(server, sendBytes.Length);
93                     }
94                 }
95 
96                 await clientTask;
97                 Assert.Equal(sendBytes, received);
98 
99                 server.Disconnect();
100                 Assert.False(server.IsConnected);
101             }
102         }
103 
104         [Fact]
ClonedServer_ActsAsOriginalServer()105         public async Task ClonedServer_ActsAsOriginalServer()
106         {
107             byte[] msg1 = new byte[] { 5, 7, 9, 10 };
108             byte[] received1 = new byte[] { 0, 0, 0, 0 };
109 
110             using (NamedPipePair pair = CreateNamedPipePair())
111             {
112                 NamedPipeServerStream serverBase = pair.serverStream;
113                 NamedPipeClientStream client = pair.clientStream;
114                 pair.Connect();
115 
116                 if (pair.writeToServer)
117                 {
118                     Task<int> clientTask = client.ReadAsync(received1, 0, received1.Length);
119                     using (NamedPipeServerStream server = new NamedPipeServerStream(PipeDirection.Out, false, true, serverBase.SafePipeHandle))
120                     {
121                         if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
122                         {
123                             Assert.Equal(1, client.NumberOfServerInstances);
124                         }
125                         server.Write(msg1, 0, msg1.Length);
126                         int receivedLength = await clientTask;
127                         Assert.Equal(msg1.Length, receivedLength);
128                         Assert.Equal(msg1, received1);
129                     }
130                 }
131                 else
132                 {
133                     Task clientTask = client.WriteAsync(msg1, 0, msg1.Length);
134                     using (NamedPipeServerStream server = new NamedPipeServerStream(PipeDirection.In, false, true, serverBase.SafePipeHandle))
135                     {
136                         int receivedLength = server.Read(received1, 0, msg1.Length);
137                         Assert.Equal(msg1.Length, receivedLength);
138                         Assert.Equal(msg1, received1);
139                         await clientTask;
140                     }
141                 }
142             }
143         }
144 
145         [Fact]
ClonedClient_ActsAsOriginalClient()146         public async Task ClonedClient_ActsAsOriginalClient()
147         {
148             byte[] msg1 = new byte[] { 5, 7, 9, 10 };
149             byte[] received1 = new byte[] { 0, 0, 0, 0 };
150 
151             using (NamedPipePair pair = CreateNamedPipePair())
152             {
153                 pair.Connect();
154                 NamedPipeServerStream server = pair.serverStream;
155                 if (pair.writeToServer)
156                 {
157                     using (NamedPipeClientStream client = new NamedPipeClientStream(PipeDirection.In, false, true, pair.clientStream.SafePipeHandle))
158                     {
159                         if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
160                         {
161                             Assert.Equal(1, client.NumberOfServerInstances);
162                         }
163                         Task<int> clientTask = client.ReadAsync(received1, 0, received1.Length);
164                         server.Write(msg1, 0, msg1.Length);
165                         int receivedLength = await clientTask;
166                         Assert.Equal(msg1.Length, receivedLength);
167                         Assert.Equal(msg1, received1);
168                     }
169                 }
170                 else
171                 {
172                     using (NamedPipeClientStream client = new NamedPipeClientStream(PipeDirection.Out, false, true, pair.clientStream.SafePipeHandle))
173                     {
174                         Task clientTask = client.WriteAsync(msg1, 0, msg1.Length);
175                         int receivedLength = server.Read(received1, 0, msg1.Length);
176                         Assert.Equal(msg1.Length, receivedLength);
177                         Assert.Equal(msg1, received1);
178                         await clientTask;
179                     }
180                 }
181             }
182         }
183 
184         [Fact]
ConnectOnAlreadyConnectedClient_Throws_InvalidOperationException()185         public void ConnectOnAlreadyConnectedClient_Throws_InvalidOperationException()
186         {
187             using (NamedPipePair pair = CreateNamedPipePair())
188             {
189                 NamedPipeServerStream server = pair.serverStream;
190                 NamedPipeClientStream client = pair.clientStream;
191                 byte[] buffer = new byte[] { 0, 0, 0, 0 };
192 
193                 pair.Connect();
194 
195                 Assert.True(client.IsConnected);
196                 Assert.True(server.IsConnected);
197 
198                 Assert.Throws<InvalidOperationException>(() => client.Connect());
199             }
200         }
201 
202         [Fact]
WaitForConnectionOnAlreadyConnectedServer_Throws_InvalidOperationException()203         public void WaitForConnectionOnAlreadyConnectedServer_Throws_InvalidOperationException()
204         {
205             using (NamedPipePair pair = CreateNamedPipePair())
206             {
207                 NamedPipeServerStream server = pair.serverStream;
208                 NamedPipeClientStream client = pair.clientStream;
209                 byte[] buffer = new byte[] { 0, 0, 0, 0 };
210 
211                 pair.Connect();
212 
213                 Assert.True(client.IsConnected);
214                 Assert.True(server.IsConnected);
215 
216                 Assert.Throws<InvalidOperationException>(() => server.WaitForConnection());
217             }
218         }
219 
220         [Fact]
CancelTokenOn_ServerWaitForConnectionAsync_Throws_OperationCanceledException()221         public async Task CancelTokenOn_ServerWaitForConnectionAsync_Throws_OperationCanceledException()
222         {
223             using (NamedPipePair pair = CreateNamedPipePair())
224             {
225                 NamedPipeServerStream server = pair.serverStream;
226                 var ctx = new CancellationTokenSource();
227 
228                 if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) // cancellation token after the operation has been initiated
229                 {
230                     Task serverWaitTimeout = server.WaitForConnectionAsync(ctx.Token);
231                     ctx.Cancel();
232                     await Assert.ThrowsAnyAsync<OperationCanceledException>(() => serverWaitTimeout);
233                 }
234 
235                 ctx.Cancel();
236                 Assert.True(server.WaitForConnectionAsync(ctx.Token).IsCanceled);
237             }
238         }
239 
240         [Fact]
241         [PlatformSpecific(TestPlatforms.Windows)] // P/Invoking to Win32 functions
CancelTokenOff_ServerWaitForConnectionAsyncWithOuterCancellation_Throws_OperationCanceledException()242         public async Task CancelTokenOff_ServerWaitForConnectionAsyncWithOuterCancellation_Throws_OperationCanceledException()
243         {
244             using (NamedPipePair pair = CreateNamedPipePair())
245             {
246                 NamedPipeServerStream server = pair.serverStream;
247                 Task waitForConnectionTask = server.WaitForConnectionAsync(CancellationToken.None);
248 
249                 Assert.True(Interop.CancelIoEx(server.SafePipeHandle), "Outer cancellation failed");
250                 await Assert.ThrowsAnyAsync<OperationCanceledException>(() => waitForConnectionTask);
251                 Assert.True(waitForConnectionTask.IsCanceled);
252             }
253         }
254 
255         [Fact]
256         [PlatformSpecific(TestPlatforms.Windows)] // P/Invoking to Win32 functions
CancelTokenOn_ServerWaitForConnectionAsyncWithOuterCancellation_Throws_IOException()257         public async Task CancelTokenOn_ServerWaitForConnectionAsyncWithOuterCancellation_Throws_IOException()
258         {
259             using (NamedPipePair pair = CreateNamedPipePair())
260             {
261                 var cts = new CancellationTokenSource();
262                 NamedPipeServerStream server = pair.serverStream;
263                 Task waitForConnectionTask = server.WaitForConnectionAsync(cts.Token);
264 
265                 Assert.True(Interop.CancelIoEx(server.SafePipeHandle), "Outer cancellation failed");
266                 await Assert.ThrowsAsync<IOException>(() => waitForConnectionTask);
267             }
268         }
269 
270         [Fact]
OperationsOnDisconnectedServer()271         public async Task OperationsOnDisconnectedServer()
272         {
273             using (NamedPipePair pair = CreateNamedPipePair())
274             {
275                 NamedPipeServerStream server = pair.serverStream;
276                 pair.Connect();
277 
278                 Assert.Throws<InvalidOperationException>(() => server.IsMessageComplete);
279                 Assert.Throws<InvalidOperationException>(() => server.WaitForConnection());
280                 await Assert.ThrowsAsync<InvalidOperationException>(() => server.WaitForConnectionAsync()); // fails because allowed connections is set to 1
281 
282                 server.Disconnect();
283 
284                 Assert.Throws<InvalidOperationException>(() => server.Disconnect());    // double disconnect
285 
286                 byte[] buffer = new byte[] { 0, 0, 0, 0 };
287 
288                 if (pair.writeToServer)
289                 {
290                     Assert.Throws<InvalidOperationException>(() => server.Write(buffer, 0, buffer.Length));
291                     Assert.Throws<InvalidOperationException>(() => server.WriteByte(5));
292                     Assert.Throws<InvalidOperationException>(() => { server.WriteAsync(buffer, 0, buffer.Length); });
293                 }
294                 else
295                 {
296                     Assert.Throws<InvalidOperationException>(() => server.Read(buffer, 0, buffer.Length));
297                     Assert.Throws<InvalidOperationException>(() => server.ReadByte());
298                     Assert.Throws<InvalidOperationException>(() => { server.ReadAsync(buffer, 0, buffer.Length); });
299                 }
300 
301                 Assert.Throws<InvalidOperationException>(() => server.Flush());
302                 Assert.Throws<InvalidOperationException>(() => server.IsMessageComplete);
303                 Assert.Throws<InvalidOperationException>(() => server.GetImpersonationUserName());
304             }
305         }
306 
307         [Fact]
OperationsOnDisconnectedClient()308         public virtual async Task OperationsOnDisconnectedClient()
309         {
310             using (NamedPipePair pair = CreateNamedPipePair())
311             {
312                 NamedPipeServerStream server = pair.serverStream;
313                 NamedPipeClientStream client = pair.clientStream;
314                 pair.Connect();
315 
316                 Assert.Throws<InvalidOperationException>(() => client.IsMessageComplete);
317                 Assert.Throws<InvalidOperationException>(() => client.Connect());
318                 await Assert.ThrowsAsync<InvalidOperationException>(() => client.ConnectAsync());
319 
320                 server.Disconnect();
321 
322                 byte[] buffer = new byte[] { 0, 0, 0, 0 };
323 
324                 if (!pair.writeToServer)
325                 {
326                     if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) // writes on Unix may still succeed after other end disconnects, due to socket being used
327                     {
328                         // Pipe is broken
329                         Assert.Throws<IOException>(() => client.Write(buffer, 0, buffer.Length));
330                         Assert.Throws<IOException>(() => client.WriteByte(5));
331                         Assert.Throws<IOException>(() => { client.WriteAsync(buffer, 0, buffer.Length); });
332                         Assert.Throws<IOException>(() => client.Flush());
333                         Assert.Throws<IOException>(() => client.NumberOfServerInstances);
334                     }
335                 }
336                 else
337                 {
338                     // Nothing for the client to read, but no exception throwing
339                     Assert.Equal(0, client.Read(buffer, 0, buffer.Length));
340                     Assert.Equal(-1, client.ReadByte());
341 
342                     if (!RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) // NumberOfServerInstances not supported on Unix
343                     {
344                         Assert.Throws<PlatformNotSupportedException>(() => client.NumberOfServerInstances);
345                     }
346                 }
347 
348                 Assert.Throws<InvalidOperationException>(() => client.IsMessageComplete);
349             }
350         }
351 
352         [Fact]
353         [PlatformSpecific(TestPlatforms.Windows)] // Unix implemented on sockets, where disposal information doesn't propagate
Windows_OperationsOnNamedServerWithDisposedClient()354         public async Task Windows_OperationsOnNamedServerWithDisposedClient()
355         {
356             using (NamedPipePair pair = CreateNamedPipePair())
357             {
358                 NamedPipeServerStream server = pair.serverStream;
359                 pair.Connect();
360                 pair.clientStream.Dispose();
361 
362                 Assert.Throws<IOException>(() => server.WaitForConnection());
363                 await Assert.ThrowsAsync<IOException>(() => server.WaitForConnectionAsync());
364                 Assert.Throws<IOException>(() => server.GetImpersonationUserName());
365             }
366         }
367 
368         [Fact]
369         [PlatformSpecific(TestPlatforms.AnyUnix)] // Unix implemented on sockets, where disposal information doesn't propagate
Unix_OperationsOnNamedServerWithDisposedClient()370         public async Task Unix_OperationsOnNamedServerWithDisposedClient()
371         {
372             using (NamedPipePair pair = CreateNamedPipePair())
373             {
374                 NamedPipeServerStream server = pair.serverStream;
375                 pair.Connect();
376                 pair.clientStream.Dispose();
377 
378                 // On Unix, the server still thinks that it is connected after client Disposal.
379                 Assert.Throws<InvalidOperationException>(() => server.WaitForConnection());
380                 await Assert.ThrowsAsync<InvalidOperationException>(() => server.WaitForConnectionAsync());
381                 Assert.NotNull(server.GetImpersonationUserName());
382             }
383         }
384 
385         [Fact]
OperationsOnUnconnectedServer()386         public void OperationsOnUnconnectedServer()
387         {
388             using (NamedPipePair pair = CreateNamedPipePair())
389             {
390                 NamedPipeServerStream server = pair.serverStream;
391 
392                 // doesn't throw exceptions
393                 PipeTransmissionMode transmitMode = server.TransmissionMode;
394                 Assert.Throws<ArgumentOutOfRangeException>(() => server.ReadMode = (PipeTransmissionMode)999);
395 
396                 byte[] buffer = new byte[] { 0, 0, 0, 0 };
397 
398                 if (pair.writeToServer)
399                 {
400                     Assert.Equal(0, server.OutBufferSize);
401                     Assert.Throws<InvalidOperationException>(() => server.Write(buffer, 0, buffer.Length));
402                     Assert.Throws<InvalidOperationException>(() => server.WriteByte(5));
403                     Assert.Throws<InvalidOperationException>(() => { server.WriteAsync(buffer, 0, buffer.Length); });
404                 }
405                 else
406                 {
407                     Assert.Equal(0, server.InBufferSize);
408                     PipeTransmissionMode readMode = server.ReadMode;
409                     Assert.Throws<InvalidOperationException>(() => server.Read(buffer, 0, buffer.Length));
410                     Assert.Throws<InvalidOperationException>(() => server.ReadByte());
411                     Assert.Throws<InvalidOperationException>(() => { server.ReadAsync(buffer, 0, buffer.Length); });
412                 }
413 
414                 Assert.Throws<InvalidOperationException>(() => server.Disconnect());    // disconnect when not connected
415                 Assert.Throws<InvalidOperationException>(() => server.IsMessageComplete);
416             }
417         }
418 
419         [Fact]
OperationsOnUnconnectedClient()420         public void OperationsOnUnconnectedClient()
421         {
422             using (NamedPipePair pair = CreateNamedPipePair())
423             {
424                 NamedPipeClientStream client = pair.clientStream;
425                 byte[] buffer = new byte[] { 0, 0, 0, 0 };
426 
427                 if (client.CanRead)
428                 {
429                     Assert.Throws<InvalidOperationException>(() => client.Read(buffer, 0, buffer.Length));
430                     Assert.Throws<InvalidOperationException>(() => client.ReadByte());
431                     Assert.Throws<InvalidOperationException>(() => { client.ReadAsync(buffer, 0, buffer.Length); });
432                     Assert.Throws<InvalidOperationException>(() => client.ReadMode);
433                     Assert.Throws<InvalidOperationException>(() => client.ReadMode = PipeTransmissionMode.Byte);
434                 }
435                 if (client.CanWrite)
436                 {
437                     Assert.Throws<InvalidOperationException>(() => client.Write(buffer, 0, buffer.Length));
438                     Assert.Throws<InvalidOperationException>(() => client.WriteByte(5));
439                     Assert.Throws<InvalidOperationException>(() => { client.WriteAsync(buffer, 0, buffer.Length); });
440                 }
441 
442                 Assert.Throws<InvalidOperationException>(() => client.NumberOfServerInstances);
443                 Assert.Throws<InvalidOperationException>(() => client.TransmissionMode);
444                 Assert.Throws<InvalidOperationException>(() => client.InBufferSize);
445                 Assert.Throws<InvalidOperationException>(() => client.OutBufferSize);
446                 Assert.Throws<InvalidOperationException>(() => client.SafePipeHandle);
447             }
448         }
449 
450         [Fact]
DisposedServerPipe_Throws_ObjectDisposedException()451         public async Task DisposedServerPipe_Throws_ObjectDisposedException()
452         {
453             using (NamedPipePair pair = CreateNamedPipePair())
454             {
455                 NamedPipeServerStream pipe = pair.serverStream;
456                 pipe.Dispose();
457                 byte[] buffer = new byte[] { 0, 0, 0, 0 };
458 
459                 Assert.Throws<ObjectDisposedException>(() => pipe.Disconnect());
460                 Assert.Throws<ObjectDisposedException>(() => pipe.GetImpersonationUserName());
461                 Assert.Throws<ObjectDisposedException>(() => pipe.WaitForConnection());
462                 await Assert.ThrowsAsync<ObjectDisposedException>(() => pipe.WaitForConnectionAsync());
463             }
464         }
465 
466         [Fact]
DisposedClientPipe_Throws_ObjectDisposedException()467         public async Task DisposedClientPipe_Throws_ObjectDisposedException()
468         {
469             using (NamedPipePair pair = CreateNamedPipePair())
470             {
471                 pair.Connect();
472                 NamedPipeClientStream pipe = pair.clientStream;
473                 pipe.Dispose();
474                 byte[] buffer = new byte[] { 0, 0, 0, 0 };
475 
476                 Assert.Throws<ObjectDisposedException>(() => pipe.Connect());
477                 await Assert.ThrowsAsync<ObjectDisposedException>(() => pipe.ConnectAsync());
478                 Assert.Throws<ObjectDisposedException>(() => pipe.NumberOfServerInstances);
479             }
480         }
481 
482         [Fact]
ReadAsync_DisconnectDuringRead_Returns0()483         public async Task ReadAsync_DisconnectDuringRead_Returns0()
484         {
485             using (NamedPipePair pair = CreateNamedPipePair())
486             {
487                 pair.Connect();
488                 Task<int> readTask;
489                 if (pair.clientStream.CanRead)
490                 {
491                     readTask = pair.clientStream.ReadAsync(new byte[1], 0, 1);
492                     pair.serverStream.Dispose();
493                 }
494                 else
495                 {
496                     readTask = pair.serverStream.ReadAsync(new byte[1], 0, 1);
497                     pair.clientStream.Dispose();
498                 }
499                 Assert.Equal(0, await readTask);
500             }
501         }
502 
503         [PlatformSpecific(TestPlatforms.Windows)] // Unix named pipes are on sockets, where small writes with an empty buffer will succeed immediately
504         [Fact]
WriteAsync_DisconnectDuringWrite_Throws()505         public async Task WriteAsync_DisconnectDuringWrite_Throws()
506         {
507             using (NamedPipePair pair = CreateNamedPipePair())
508             {
509                 pair.Connect();
510                 Task writeTask;
511                 if (pair.clientStream.CanWrite)
512                 {
513                     writeTask = pair.clientStream.WriteAsync(new byte[1], 0, 1);
514                     pair.serverStream.Dispose();
515                 }
516                 else
517                 {
518                     writeTask = pair.serverStream.WriteAsync(new byte[1], 0, 1);
519                     pair.clientStream.Dispose();
520                 }
521                 await Assert.ThrowsAsync<IOException>(() => writeTask);
522             }
523         }
524 
525         [Fact]
526         [ActiveIssue("dotnet/corefx #16934", TargetFrameworkMonikers.NetFramework)] //Hangs forever in desktop as it doesn't have cancellation support
Server_ReadWriteCancelledToken_Throws_OperationCanceledException()527         public async Task Server_ReadWriteCancelledToken_Throws_OperationCanceledException()
528         {
529             using (NamedPipePair pair = CreateNamedPipePair())
530             {
531                 NamedPipeServerStream server = pair.serverStream;
532                 NamedPipeClientStream client = pair.clientStream;
533                 byte[] buffer = new byte[] { 0, 0, 0, 0 };
534 
535                 pair.Connect();
536 
537                 if (server.CanRead && client.CanWrite)
538                 {
539                     var ctx1 = new CancellationTokenSource();
540 
541                     Task<int> serverReadToken = server.ReadAsync(buffer, 0, buffer.Length, ctx1.Token);
542                     ctx1.Cancel();
543                     await Assert.ThrowsAnyAsync<OperationCanceledException>(() => serverReadToken);
544 
545                     ctx1.Cancel();
546                     Assert.True(server.ReadAsync(buffer, 0, buffer.Length, ctx1.Token).IsCanceled);
547                 }
548 
549                 if (server.CanWrite)
550                 {
551                     var ctx1 = new CancellationTokenSource();
552                     if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) // On Unix WriteAsync's aren't cancelable once initiated
553                     {
554                         Task serverWriteToken = server.WriteAsync(buffer, 0, buffer.Length, ctx1.Token);
555                         ctx1.Cancel();
556                         await Assert.ThrowsAnyAsync<OperationCanceledException>(() => serverWriteToken);
557                     }
558                     ctx1.Cancel();
559                     Assert.True(server.WriteAsync(buffer, 0, buffer.Length, ctx1.Token).IsCanceled);
560                 }
561             }
562         }
563 
564         [Fact]
565         [PlatformSpecific(TestPlatforms.Windows)] // P/Invoking to Win32 functions
CancelTokenOff_Server_ReadWriteCancelledToken_Throws_OperationCanceledException()566         public async Task CancelTokenOff_Server_ReadWriteCancelledToken_Throws_OperationCanceledException()
567         {
568             using (NamedPipePair pair = CreateNamedPipePair())
569             {
570                 NamedPipeServerStream server = pair.serverStream;
571                 byte[] buffer = new byte[] { 0, 0, 0, 0 };
572 
573                 pair.Connect();
574 
575                 if (server.CanRead)
576                 {
577                     Task serverReadToken = server.ReadAsync(buffer, 0, buffer.Length, CancellationToken.None);
578 
579                     Assert.True(Interop.CancelIoEx(server.SafePipeHandle), "Outer cancellation failed");
580                     await Assert.ThrowsAnyAsync<OperationCanceledException>(() => serverReadToken);
581                     Assert.True(serverReadToken.IsCanceled);
582                 }
583                 if (server.CanWrite)
584                 {
585                     Task serverWriteToken = server.WriteAsync(buffer, 0, buffer.Length, CancellationToken.None);
586 
587                     Assert.True(Interop.CancelIoEx(server.SafePipeHandle), "Outer cancellation failed");
588                     await Assert.ThrowsAnyAsync<OperationCanceledException>(() => serverWriteToken);
589                     Assert.True(serverWriteToken.IsCanceled);
590                 }
591             }
592         }
593 
594         [Fact]
595         [PlatformSpecific(TestPlatforms.Windows)] // P/Invoking to Win32 functions
CancelTokenOn_Server_ReadWriteCancelledToken_Throws_OperationCanceledException()596         public async Task CancelTokenOn_Server_ReadWriteCancelledToken_Throws_OperationCanceledException()
597         {
598             using (NamedPipePair pair = CreateNamedPipePair())
599             {
600                 NamedPipeServerStream server = pair.serverStream;
601                 byte[] buffer = new byte[] { 0, 0, 0, 0 };
602 
603                 pair.Connect();
604 
605                 if (server.CanRead)
606                 {
607                     var cts = new CancellationTokenSource();
608                     Task serverReadToken = server.ReadAsync(buffer, 0, buffer.Length, cts.Token);
609 
610                     Assert.True(Interop.CancelIoEx(server.SafePipeHandle), "Outer cancellation failed");
611                     await Assert.ThrowsAnyAsync<OperationCanceledException>(() => serverReadToken);
612                 }
613                 if (server.CanWrite)
614                 {
615                     var cts = new CancellationTokenSource();
616                     Task serverWriteToken = server.WriteAsync(buffer, 0, buffer.Length, cts.Token);
617 
618                     Assert.True(Interop.CancelIoEx(server.SafePipeHandle), "Outer cancellation failed");
619                     await Assert.ThrowsAnyAsync<OperationCanceledException>(() => serverWriteToken);
620                 }
621             }
622         }
623 
624         [Fact]
625         [ActiveIssue("dotnet/corefx #16934", TargetFrameworkMonikers.NetFramework)] //Hangs forever in desktop as it doesn't have cancellation support
Client_ReadWriteCancelledToken_Throws_OperationCanceledException()626         public async Task Client_ReadWriteCancelledToken_Throws_OperationCanceledException()
627         {
628             using (NamedPipePair pair = CreateNamedPipePair())
629             {
630                 NamedPipeClientStream client = pair.clientStream;
631                 byte[] buffer = new byte[] { 0, 0, 0, 0 };
632 
633                 pair.Connect();
634 
635                 if (client.CanRead)
636                 {
637                     var ctx1 = new CancellationTokenSource();
638 
639                     Task serverReadToken = client.ReadAsync(buffer, 0, buffer.Length, ctx1.Token);
640                     ctx1.Cancel();
641                     await Assert.ThrowsAnyAsync<OperationCanceledException>(() => serverReadToken);
642 
643                     Assert.True(client.ReadAsync(buffer, 0, buffer.Length, ctx1.Token).IsCanceled);
644                 }
645 
646                 if (client.CanWrite)
647                 {
648                     var ctx1 = new CancellationTokenSource();
649                     if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) // On Unix WriteAsync's aren't cancelable once initiated
650                     {
651                         Task serverWriteToken = client.WriteAsync(buffer, 0, buffer.Length, ctx1.Token);
652                         ctx1.Cancel();
653                         await Assert.ThrowsAnyAsync<OperationCanceledException>(() => serverWriteToken);
654                     }
655                     ctx1.Cancel();
656                     Assert.True(client.WriteAsync(buffer, 0, buffer.Length, ctx1.Token).IsCanceled);
657                 }
658             }
659         }
660 
661         [Fact]
662         [PlatformSpecific(TestPlatforms.Windows)] // P/Invoking to Win32 functions
CancelTokenOff_Client_ReadWriteCancelledToken_Throws_OperationCanceledException()663         public async Task CancelTokenOff_Client_ReadWriteCancelledToken_Throws_OperationCanceledException()
664         {
665             using (NamedPipePair pair = CreateNamedPipePair())
666             {
667                 NamedPipeClientStream client = pair.clientStream;
668                 byte[] buffer = new byte[] { 0, 0, 0, 0 };
669 
670                 pair.Connect();
671                 if (client.CanRead)
672                 {
673                     Task clientReadToken = client.ReadAsync(buffer, 0, buffer.Length, CancellationToken.None);
674 
675                     Assert.True(Interop.CancelIoEx(client.SafePipeHandle), "Outer cancellation failed");
676                     await Assert.ThrowsAnyAsync<OperationCanceledException>(() => clientReadToken);
677                     Assert.True(clientReadToken.IsCanceled);
678                 }
679                 if (client.CanWrite)
680                 {
681                     Task clientWriteToken = client.WriteAsync(buffer, 0, buffer.Length, CancellationToken.None);
682 
683                     Assert.True(Interop.CancelIoEx(client.SafePipeHandle), "Outer cancellation failed");
684                     await Assert.ThrowsAnyAsync<OperationCanceledException>(() => clientWriteToken);
685                     Assert.True(clientWriteToken.IsCanceled);
686                 }
687             }
688         }
689 
690         [Fact]
691         [PlatformSpecific(TestPlatforms.Windows)] // P/Invoking to Win32 functions
CancelTokenOn_Client_ReadWriteCancelledToken_Throws_OperationCanceledException()692         public async Task CancelTokenOn_Client_ReadWriteCancelledToken_Throws_OperationCanceledException()
693         {
694             using (NamedPipePair pair = CreateNamedPipePair())
695             {
696                 NamedPipeClientStream client = pair.clientStream;
697                 byte[] buffer = new byte[] { 0, 0, 0, 0 };
698 
699                 pair.Connect();
700                 if (client.CanRead)
701                 {
702                     var cts = new CancellationTokenSource();
703                     Task clientReadToken = client.ReadAsync(buffer, 0, buffer.Length, cts.Token);
704 
705                     Assert.True(Interop.CancelIoEx(client.SafePipeHandle), "Outer cancellation failed");
706                     await Assert.ThrowsAnyAsync<OperationCanceledException>(() => clientReadToken);
707                 }
708                 if (client.CanWrite)
709                 {
710                     var cts = new CancellationTokenSource();
711                     Task clientWriteToken = client.WriteAsync(buffer, 0, buffer.Length, cts.Token);
712 
713                     Assert.True(Interop.CancelIoEx(client.SafePipeHandle), "Outer cancellation failed");
714                     await Assert.ThrowsAnyAsync<OperationCanceledException>(() => clientWriteToken);
715                 }
716             }
717         }
718 
719         [Theory]
720         [InlineData(true)]
721         [InlineData(false)]
ManyConcurrentOperations(bool cancelable)722         public async Task ManyConcurrentOperations(bool cancelable)
723         {
724             using (NamedPipePair pair = CreateNamedPipePair(PipeOptions.Asynchronous, PipeOptions.Asynchronous))
725             {
726                 await Task.WhenAll(pair.serverStream.WaitForConnectionAsync(), pair.clientStream.ConnectAsync());
727 
728                 const int NumOps = 100;
729                 const int DataPerOp = 512;
730                 byte[] sendingData = new byte[NumOps * DataPerOp];
731                 byte[] readingData = new byte[sendingData.Length];
732                 new Random().NextBytes(sendingData);
733                 var cancellationToken = cancelable ? new CancellationTokenSource().Token : CancellationToken.None;
734 
735                 Stream reader = pair.writeToServer ? (Stream)pair.clientStream : pair.serverStream;
736                 Stream writer = pair.writeToServer ? (Stream)pair.serverStream : pair.clientStream;
737 
738                 var reads = new Task<int>[NumOps];
739                 var writes = new Task[NumOps];
740 
741                 for (int i = 0; i < reads.Length; i++)
742                     reads[i] = reader.ReadAsync(readingData, i * DataPerOp, DataPerOp, cancellationToken);
743                 for (int i = 0; i < reads.Length; i++)
744                     writes[i] = writer.WriteAsync(sendingData, i * DataPerOp, DataPerOp, cancellationToken);
745 
746                 const int WaitTimeout = 30000;
747                 Assert.True(Task.WaitAll(writes, WaitTimeout));
748                 Assert.True(Task.WaitAll(reads, WaitTimeout));
749 
750                 // The data of each write may not be written atomically, and as such some of the data may be
751                 // interleaved rather than entirely in the order written.
752                 Assert.Equal(sendingData.OrderBy(b => b), readingData.OrderBy(b => b));
753             }
754         }
755     }
756 
757     [ActiveIssue(22271, TargetFrameworkMonikers.UapNotUapAot)]
758     public class NamedPipeTest_Simple_ServerInOutRead_ClientInOutWrite : NamedPipeTest_Simple
759     {
CreateNamedPipePair(PipeOptions serverOptions, PipeOptions clientOptions)760         protected override NamedPipePair CreateNamedPipePair(PipeOptions serverOptions, PipeOptions clientOptions)
761         {
762             NamedPipePair ret = new NamedPipePair();
763             string pipeName = GetUniquePipeName();
764             ret.serverStream = new NamedPipeServerStream(pipeName, PipeDirection.InOut, 1, PipeTransmissionMode.Byte, serverOptions);
765             ret.clientStream = new NamedPipeClientStream(".", pipeName, PipeDirection.InOut, clientOptions);
766             ret.writeToServer = false;
767             return ret;
768         }
769     }
770 
771     [ActiveIssue(22271, TargetFrameworkMonikers.UapNotUapAot)]
772     public class NamedPipeTest_Simple_ServerInOutWrite_ClientInOutRead : NamedPipeTest_Simple
773     {
CreateNamedPipePair(PipeOptions serverOptions, PipeOptions clientOptions)774         protected override NamedPipePair CreateNamedPipePair(PipeOptions serverOptions, PipeOptions clientOptions)
775         {
776             NamedPipePair ret = new NamedPipePair();
777             string pipeName = GetUniquePipeName();
778             ret.serverStream = new NamedPipeServerStream(pipeName, PipeDirection.InOut, 1, PipeTransmissionMode.Byte, serverOptions);
779             ret.clientStream = new NamedPipeClientStream(".", pipeName, PipeDirection.InOut, clientOptions);
780             ret.writeToServer = true;
781             return ret;
782         }
783     }
784 
785     [ActiveIssue(22271, TargetFrameworkMonikers.UapNotUapAot)]
786     public class NamedPipeTest_Simple_ServerInOut_ClientIn : NamedPipeTest_Simple
787     {
CreateNamedPipePair(PipeOptions serverOptions, PipeOptions clientOptions)788         protected override NamedPipePair CreateNamedPipePair(PipeOptions serverOptions, PipeOptions clientOptions)
789         {
790             NamedPipePair ret = new NamedPipePair();
791             string pipeName = GetUniquePipeName();
792             ret.serverStream = new NamedPipeServerStream(pipeName, PipeDirection.InOut, 1, PipeTransmissionMode.Byte, serverOptions);
793             ret.clientStream = new NamedPipeClientStream(".", pipeName, PipeDirection.In, clientOptions);
794             ret.writeToServer = true;
795             return ret;
796         }
797     }
798 
799     [ActiveIssue(22271, TargetFrameworkMonikers.UapNotUapAot)]
800     public class NamedPipeTest_Simple_ServerInOut_ClientOut : NamedPipeTest_Simple
801     {
CreateNamedPipePair(PipeOptions serverOptions, PipeOptions clientOptions)802         protected override NamedPipePair CreateNamedPipePair(PipeOptions serverOptions, PipeOptions clientOptions)
803         {
804             NamedPipePair ret = new NamedPipePair();
805             string pipeName = GetUniquePipeName();
806             ret.serverStream = new NamedPipeServerStream(pipeName, PipeDirection.InOut, 1, PipeTransmissionMode.Byte, serverOptions);
807             ret.clientStream = new NamedPipeClientStream(".", pipeName, PipeDirection.Out, clientOptions);
808             ret.writeToServer = false;
809             return ret;
810         }
811     }
812 
813     [ActiveIssue(22271, TargetFrameworkMonikers.UapNotUapAot)]
814     public class NamedPipeTest_Simple_ServerOut_ClientIn : NamedPipeTest_Simple
815     {
CreateNamedPipePair(PipeOptions serverOptions, PipeOptions clientOptions)816         protected override NamedPipePair CreateNamedPipePair(PipeOptions serverOptions, PipeOptions clientOptions)
817         {
818             NamedPipePair ret = new NamedPipePair();
819             string pipeName = GetUniquePipeName();
820             ret.serverStream = new NamedPipeServerStream(pipeName, PipeDirection.Out, 1, PipeTransmissionMode.Byte, serverOptions);
821             ret.clientStream = new NamedPipeClientStream(".", pipeName, PipeDirection.In, clientOptions);
822             ret.writeToServer = true;
823             return ret;
824         }
825     }
826 
827     [ActiveIssue(22271, TargetFrameworkMonikers.UapNotUapAot)]
828     public class NamedPipeTest_Simple_ServerIn_ClientOut : NamedPipeTest_Simple
829     {
CreateNamedPipePair(PipeOptions serverOptions, PipeOptions clientOptions)830         protected override NamedPipePair CreateNamedPipePair(PipeOptions serverOptions, PipeOptions clientOptions)
831         {
832             NamedPipePair ret = new NamedPipePair();
833             string pipeName = GetUniquePipeName();
834             ret.serverStream = new NamedPipeServerStream(pipeName, PipeDirection.In, 1, PipeTransmissionMode.Byte, serverOptions);
835             ret.clientStream = new NamedPipeClientStream(".", pipeName, PipeDirection.Out, clientOptions);
836             ret.writeToServer = false;
837             return ret;
838         }
839     }
840 
841 }
842