Update named pipe test

Mike McCormack mike at codeweavers.com
Thu May 15 00:44:39 CDT 2003


Hi All,

This adds Dan's latest pipe test to the CVS, now that most tests pass.
The test's coverage is great!

Thanks Dan!

Mike


ChangeLog:
* add Dan Kegel's latest named pipe test
-------------- next part --------------
Index: dlls/kernel/tests/pipe.c
===================================================================
RCS file: /home/wine/wine/dlls/kernel/tests/pipe.c,v
retrieving revision 1.4
diff -u -u -r1.4 pipe.c
--- dlls/kernel/tests/pipe.c	15 May 2003 04:22:45 -0000	1.4
+++ dlls/kernel/tests/pipe.c	15 May 2003 05:38:39 -0000
@@ -23,13 +23,22 @@
 #include <stdlib.h>
 #include <stdio.h>
 #include <time.h>
+#include <assert.h>
 
 #ifndef STANDALONE
 #include "wine/test.h"
 #else
 #include <assert.h>
 #define START_TEST(name) main(int argc, char **argv)
-#define ok(condition, msg) assert(condition)
+#define ok(condition, msg) \
+	do { \
+		if(!(condition)) \
+		{ \
+			fprintf(stderr,"failed at %d\n",__LINE__); \
+			exit(0); \
+		} \
+	} while(0)
+
 #define todo_wine
 #endif
 
@@ -40,18 +49,24 @@
 
 #define PIPENAME "\\\\.\\PiPe\\tests_" __FILE__
 
-void test_CreateNamedPipeA(void)
+static void msg(const char *s)
+{
+    DWORD cbWritten;
+    WriteFile(GetStdHandle(STD_OUTPUT_HANDLE), s, strlen(s), &cbWritten, NULL);
+}
+
+void test_CreateNamedPipe(void)
 {
     HANDLE hnp;
     HANDLE hFile;
     const char obuf[] = "Bit Bucket";
     char ibuf[32];
     DWORD written;
-    DWORD gelesen;
+    DWORD readden;
 
+    msg("test_CreateNamedPipe starting\n");
     /* Bad parameter checks */
-    hnp = CreateNamedPipeA("not a named pipe", 
-        PIPE_ACCESS_DUPLEX, PIPE_TYPE_BYTE|PIPE_WAIT, 
+    hnp = CreateNamedPipe("not a named pipe", PIPE_ACCESS_DUPLEX, PIPE_TYPE_BYTE | PIPE_WAIT,
         /* nMaxInstances */ 1,
         /* nOutBufSize */ 1024,
         /* nInBufSize */ 1024,
@@ -60,27 +75,27 @@
 
     if (hnp == INVALID_HANDLE_VALUE && GetLastError() == ERROR_CALL_NOT_IMPLEMENTED) {
         /* Is this the right way to notify user of skipped tests? */
-        ok(hnp == INVALID_HANDLE_VALUE && GetLastError() == ERROR_CALL_NOT_IMPLEMENTED, 
-	    "CreateNamedPipe not supported on this platform, skipping tests.");
+        ok(hnp == INVALID_HANDLE_VALUE && GetLastError() == ERROR_CALL_NOT_IMPLEMENTED,
+            "CreateNamedPipe not supported on this platform, skipping tests.");
         return;
     }
     ok(hnp == INVALID_HANDLE_VALUE && GetLastError() == ERROR_INVALID_NAME,
         "CreateNamedPipe should fail if name doesn't start with \\\\.\\pipe");
 
-    hnp = CreateNamedPipeA(NULL, 
-        PIPE_ACCESS_DUPLEX, PIPE_TYPE_BYTE|PIPE_WAIT, 
+    hnp = CreateNamedPipe(NULL,
+        PIPE_ACCESS_DUPLEX, PIPE_TYPE_BYTE | PIPE_WAIT,
         1, 1024, 1024, NMPWAIT_USE_DEFAULT_WAIT, NULL);
     ok(hnp == INVALID_HANDLE_VALUE && GetLastError() == ERROR_PATH_NOT_FOUND,
         "CreateNamedPipe should fail if name is NULL");
 
-    hFile = CreateFileA(PIPENAME, GENERIC_READ|GENERIC_WRITE, 0, 
-	NULL, OPEN_EXISTING, 0, 0);
-    ok(hFile == INVALID_HANDLE_VALUE && GetLastError() == ERROR_FILE_NOT_FOUND, "connecting to nonexistent named pipe should fail with ERROR_FILE_NOT_FOUND");
+    hFile = CreateFileA(PIPENAME, GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, 0);
+    ok(hFile == INVALID_HANDLE_VALUE
+        && GetLastError() == ERROR_FILE_NOT_FOUND,
+        "connecting to nonexistent named pipe should fail with ERROR_FILE_NOT_FOUND");
 
     /* Functional checks */
 
-    hnp = CreateNamedPipeA(PIPENAME,
-        PIPE_ACCESS_DUPLEX, PIPE_TYPE_BYTE|PIPE_WAIT, 
+    hnp = CreateNamedPipe(PIPENAME, PIPE_ACCESS_DUPLEX, PIPE_TYPE_BYTE | PIPE_WAIT,
         /* nMaxInstances */ 1,
         /* nOutBufSize */ 1024,
         /* nInBufSize */ 1024,
@@ -88,68 +103,504 @@
         /* lpSecurityAttrib */ NULL);
     ok(hnp != INVALID_HANDLE_VALUE, "CreateNamedPipe failed");
 
-    hFile = CreateFileA(PIPENAME, GENERIC_READ|GENERIC_WRITE, 0, 
-            NULL, OPEN_EXISTING, 0, 0);
+    hFile = CreateFileA(PIPENAME, GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, 0);
     ok(hFile != INVALID_HANDLE_VALUE, "CreateFile failed");
 
     /* don't try to do i/o if one side couldn't be opened, as it hangs */
     if (hFile != INVALID_HANDLE_VALUE) {
-	HANDLE hFile2;
+        HANDLE hFile2;
 
-	/* Make sure we can read and write a few bytes in both directions*/
-	memset(ibuf, 0, sizeof(ibuf));
-	ok(WriteFile(hnp, obuf, sizeof(obuf), &written, NULL), "WriteFile");
-	ok(written == sizeof(obuf), "write file len");
-	ok(ReadFile(hFile, ibuf, sizeof(obuf), &gelesen, NULL), "ReadFile");
-	ok(gelesen == sizeof(obuf), "read file len");
-	ok(memcmp(obuf, ibuf, written) == 0, "content check");
-
-	memset(ibuf, 0, sizeof(ibuf));
-	ok(WriteFile(hFile, obuf, sizeof(obuf), &written, NULL), "WriteFile");
-	ok(written == sizeof(obuf), "write file len");
-	ok(ReadFile(hnp, ibuf, sizeof(obuf), &gelesen, NULL), "ReadFile");
-	ok(gelesen == sizeof(obuf), "read file len");
-	ok(memcmp(obuf, ibuf, written) == 0, "content check");
-
-	/* Picky conformance tests */
-
-	/* Verify that you can't connect to pipe again
-	 * until server calls DisconnectNamedPipe+ConnectNamedPipe
-	 * or creates a new pipe
-	 * case 1: other client not yet closed
-	 */
-	hFile2 = CreateFileA(PIPENAME, GENERIC_READ|GENERIC_WRITE, 0, 
-	    NULL, OPEN_EXISTING, 0, 0);
-	ok(hFile2 == INVALID_HANDLE_VALUE, "connecting to named pipe after other client closes but before DisconnectNamedPipe should fail");
-	ok(GetLastError() == ERROR_PIPE_BUSY, "connecting to named pipe before other client closes should fail with ERROR_PIPE_BUSY");
-
-	ok(CloseHandle(hFile), "CloseHandle");
-
-	/* case 2: other client already closed */
-	hFile = CreateFileA(PIPENAME, GENERIC_READ|GENERIC_WRITE, 0, 
-	    NULL, OPEN_EXISTING, 0, 0);
-	ok(hFile == INVALID_HANDLE_VALUE, "connecting to named pipe after other client closes but before DisconnectNamedPipe should fail");
-	ok(GetLastError() == ERROR_PIPE_BUSY, "connecting to named pipe after other client closes but before DisconnectNamedPipe should fail with ERROR_PIPE_BUSY");
-
-	ok(DisconnectNamedPipe(hnp), "DisconnectNamedPipe");
-
-	/* case 3: server has called DisconnectNamedPipe but not ConnectNamed Pipe */
-	hFile = CreateFileA(PIPENAME, GENERIC_READ|GENERIC_WRITE, 0, 
-	    NULL, OPEN_EXISTING, 0, 0);
-	ok(hFile == INVALID_HANDLE_VALUE, "connecting to named pipe after other client closes but before DisconnectNamedPipe should fail");
-	ok(GetLastError() == ERROR_PIPE_BUSY, "connecting to named pipe after other client closes but before ConnectNamedPipe should fail with ERROR_PIPE_BUSY");
-
-	/* to be complete, we'd call ConnectNamedPipe here and loop,
-	 * but by default that's blocking, so we'd either have
-	 * to turn on the uncommon nonblocking mode, or
-	 * use another thread.
-	 */
+        /* Make sure we can read and write a few bytes in both directions */
+        memset(ibuf, 0, sizeof(ibuf));
+        ok(WriteFile(hnp, obuf, sizeof(obuf), &written, NULL), "WriteFile");
+        ok(written == sizeof(obuf), "write file len");
+        ok(ReadFile(hFile, ibuf, sizeof(obuf), &readden, NULL), "ReadFile");
+        ok(readden == sizeof(obuf), "read file len");
+        ok(memcmp(obuf, ibuf, written) == 0, "content check");
+
+        memset(ibuf, 0, sizeof(ibuf));
+        ok(WriteFile(hFile, obuf, sizeof(obuf), &written, NULL), "WriteFile");
+        ok(written == sizeof(obuf), "write file len");
+        ok(ReadFile(hnp, ibuf, sizeof(obuf), &readden, NULL), "ReadFile");
+        ok(readden == sizeof(obuf), "read file len");
+        ok(memcmp(obuf, ibuf, written) == 0, "content check");
+
+        /* Picky conformance tests */
+
+        /* Verify that you can't connect to pipe again
+         * until server calls DisconnectNamedPipe+ConnectNamedPipe
+         * or creates a new pipe
+         * case 1: other client not yet closed
+         */
+        hFile2 = CreateFileA(PIPENAME, GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, 0);
+        ok(hFile2 == INVALID_HANDLE_VALUE,
+            "connecting to named pipe after other client closes but before DisconnectNamedPipe should fail");
+        ok(GetLastError() == ERROR_PIPE_BUSY,
+            "connecting to named pipe before other client closes should fail with ERROR_PIPE_BUSY");
+
+        ok(CloseHandle(hFile), "CloseHandle");
+
+        /* case 2: other client already closed */
+        hFile = CreateFileA(PIPENAME, GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, 0);
+        ok(hFile == INVALID_HANDLE_VALUE,
+            "connecting to named pipe after other client closes but before DisconnectNamedPipe should fail");
+        ok(GetLastError() == ERROR_PIPE_BUSY,
+            "connecting to named pipe after other client closes but before DisconnectNamedPipe should fail with ERROR_PIPE_BUSY");
+
+        ok(DisconnectNamedPipe(hnp), "DisconnectNamedPipe");
+
+        /* case 3: server has called DisconnectNamedPipe but not ConnectNamed Pipe */
+        hFile = CreateFileA(PIPENAME, GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, 0);
+        ok(hFile == INVALID_HANDLE_VALUE,
+            "connecting to named pipe after other client closes but before DisconnectNamedPipe should fail");
+        ok(GetLastError() == ERROR_PIPE_BUSY,
+            "connecting to named pipe after other client closes but before ConnectNamedPipe should fail with ERROR_PIPE_BUSY");
+
+        /* to be complete, we'd call ConnectNamedPipe here and loop,
+         * but by default that's blocking, so we'd either have
+         * to turn on the uncommon nonblocking mode, or
+         * use another thread.
+         */
     }
 
     ok(CloseHandle(hnp), "CloseHandle");
+
+    msg("test_CreateNamedPipe returning\n");
+}
+
+void test_CreateNamedPipe_instances_must_match(void)
+{
+    HANDLE hnp, hnp2;
+
+    /* Check no mismatch */
+    hnp = CreateNamedPipe(PIPENAME, PIPE_ACCESS_DUPLEX, PIPE_TYPE_BYTE | PIPE_WAIT,
+        /* nMaxInstances */ 2,
+        /* nOutBufSize */ 1024,
+        /* nInBufSize */ 1024,
+        /* nDefaultWait */ NMPWAIT_USE_DEFAULT_WAIT,
+        /* lpSecurityAttrib */ NULL);
+    ok(hnp != INVALID_HANDLE_VALUE, "CreateNamedPipe failed");
+
+    hnp2 = CreateNamedPipe(PIPENAME, PIPE_ACCESS_DUPLEX, PIPE_TYPE_BYTE | PIPE_WAIT,
+        /* nMaxInstances */ 2,
+        /* nOutBufSize */ 1024,
+        /* nInBufSize */ 1024,
+        /* nDefaultWait */ NMPWAIT_USE_DEFAULT_WAIT,
+        /* lpSecurityAttrib */ NULL);
+    ok(hnp2 != INVALID_HANDLE_VALUE, "CreateNamedPipe failed");
+
+    ok(CloseHandle(hnp), "CloseHandle");
+    ok(CloseHandle(hnp2), "CloseHandle");
+
+    /* Check nMaxInstances */
+    hnp = CreateNamedPipe(PIPENAME, PIPE_ACCESS_DUPLEX, PIPE_TYPE_BYTE | PIPE_WAIT,
+        /* nMaxInstances */ 1,
+        /* nOutBufSize */ 1024,
+        /* nInBufSize */ 1024,
+        /* nDefaultWait */ NMPWAIT_USE_DEFAULT_WAIT,
+        /* lpSecurityAttrib */ NULL);
+    ok(hnp != INVALID_HANDLE_VALUE, "CreateNamedPipe failed");
+
+    hnp2 = CreateNamedPipe(PIPENAME, PIPE_ACCESS_DUPLEX, PIPE_TYPE_BYTE | PIPE_WAIT,
+        /* nMaxInstances */ 1,
+        /* nOutBufSize */ 1024,
+        /* nInBufSize */ 1024,
+        /* nDefaultWait */ NMPWAIT_USE_DEFAULT_WAIT,
+        /* lpSecurityAttrib */ NULL);
+    ok(hnp2 == INVALID_HANDLE_VALUE
+        && GetLastError() == ERROR_PIPE_BUSY, "nMaxInstances not obeyed");
+
+    ok(CloseHandle(hnp), "CloseHandle");
+
+    /* Check PIPE_ACCESS_* */
+    hnp = CreateNamedPipe(PIPENAME, PIPE_ACCESS_DUPLEX, PIPE_TYPE_BYTE | PIPE_WAIT,
+        /* nMaxInstances */ 2,
+        /* nOutBufSize */ 1024,
+        /* nInBufSize */ 1024,
+        /* nDefaultWait */ NMPWAIT_USE_DEFAULT_WAIT,
+        /* lpSecurityAttrib */ NULL);
+    ok(hnp != INVALID_HANDLE_VALUE, "CreateNamedPipe failed");
+
+    hnp2 = CreateNamedPipe(PIPENAME, PIPE_ACCESS_INBOUND, PIPE_TYPE_BYTE | PIPE_WAIT,
+        /* nMaxInstances */ 1,
+        /* nOutBufSize */ 1024,
+        /* nInBufSize */ 1024,
+        /* nDefaultWait */ NMPWAIT_USE_DEFAULT_WAIT,
+        /* lpSecurityAttrib */ NULL);
+    ok(hnp2 == INVALID_HANDLE_VALUE
+        && GetLastError() == ERROR_ACCESS_DENIED, "PIPE_ACCESS_* mismatch allowed");
+
+    ok(CloseHandle(hnp), "CloseHandle");
+
+    /* etc, etc */
+}
+
+/** implementation of alarm() */
+static DWORD CALLBACK alarmThreadMain(LPVOID arg)
+{
+    DWORD timeout = (DWORD) arg;
+    msg("alarmThreadMain\n");
+    Sleep(timeout);
+    ok(FALSE, "alarm");
+    ExitProcess(1);
+    return 1;
+}
+
+HANDLE hnp = INVALID_HANDLE_VALUE;
+
+/** Trivial byte echo server - disconnects after each session */
+static DWORD CALLBACK serverThreadMain1(LPVOID arg)
+{
+    int i;
+
+    msg("serverThreadMain1 start\n");
+    /* Set up a simple echo server */
+    hnp = CreateNamedPipe(PIPENAME "serverThreadMain1", PIPE_ACCESS_DUPLEX,
+        PIPE_TYPE_BYTE | PIPE_WAIT,
+        /* nMaxInstances */ 1,
+        /* nOutBufSize */ 1024,
+        /* nInBufSize */ 1024,
+        /* nDefaultWait */ NMPWAIT_USE_DEFAULT_WAIT,
+        /* lpSecurityAttrib */ NULL);
+
+    ok(hnp != INVALID_HANDLE_VALUE, "CreateNamedPipe failed");
+    for (i = 0; ; i++) {
+        char buf[512];
+        DWORD written;
+        DWORD readden;
+        DWORD success;
+
+        /* Wait for client to connect */
+        msg("Server calling ConnectNamedPipe...\n");
+        ok(ConnectNamedPipe(hnp, NULL)
+            || GetLastError() == ERROR_PIPE_CONNECTED, "ConnectNamedPipe");
+        msg("ConnectNamedPipe returned.\n");
+
+        /* Echo bytes once */
+        memset(buf, 0, sizeof(buf));
+
+        msg("Server reading...\n");
+        success = ReadFile(hnp, buf, sizeof(buf), &readden, NULL);
+        msg("Server done reading.\n");
+        ok(success, "ReadFile");
+		ok(readden, "short read");
+
+        msg("Server writing...\n");
+        ok(WriteFile(hnp, buf, readden, &written, NULL), "WriteFile");
+        msg("Server done writing.\n");
+        ok(written == readden, "write file len");
+
+        /* finish this connection, wait for next one */
+        ok(FlushFileBuffers(hnp), "FlushFileBuffers");
+        msg("Server done flushing.\n");
+        ok(DisconnectNamedPipe(hnp), "DisconnectNamedPipe");
+        msg("Server done disconnecting.\n");
+    }
+}
+
+/** Trivial byte echo server - closes after each connection */
+static DWORD CALLBACK serverThreadMain2(LPVOID arg)
+{
+    int i;
+    HANDLE hnpNext = 0;
+
+    msg("serverThreadMain2\n");
+    /* Set up a simple echo server */
+    hnp = CreateNamedPipe(PIPENAME "serverThreadMain2", PIPE_ACCESS_DUPLEX,
+        PIPE_TYPE_BYTE | PIPE_WAIT,
+        /* nMaxInstances */ 2,
+        /* nOutBufSize */ 1024,
+        /* nInBufSize */ 1024,
+        /* nDefaultWait */ NMPWAIT_USE_DEFAULT_WAIT,
+        /* lpSecurityAttrib */ NULL);
+    ok(hnp != INVALID_HANDLE_VALUE, "CreateNamedPipe failed");
+
+    for (i = 0; ; i++) {
+        char buf[512];
+        DWORD written;
+        DWORD readden;
+        DWORD success;
+
+        /* Wait for client to connect */
+        msg("Server calling ConnectNamedPipe...\n");
+        ok(ConnectNamedPipe(hnp, NULL)
+            || GetLastError() == ERROR_PIPE_CONNECTED, "ConnectNamedPipe");
+        msg("ConnectNamedPipe returned.\n");
+
+        /* Echo bytes once */
+        memset(buf, 0, sizeof(buf));
+
+        msg("Server reading...\n");
+        success = ReadFile(hnp, buf, sizeof(buf), &readden, NULL);
+        msg("Server done reading.\n");
+        ok(success, "ReadFile");
+
+        msg("Server writing...\n");
+        ok(WriteFile(hnp, buf, readden, &written, NULL), "WriteFile");
+        msg("Server done writing.\n");
+        ok(written == readden, "write file len");
+
+        /* finish this connection, wait for next one */
+        ok(FlushFileBuffers(hnp), "FlushFileBuffers");
+        ok(DisconnectNamedPipe(hnp), "DisconnectNamedPipe");
+
+        /* Set up next echo server */
+        hnpNext =
+            CreateNamedPipe(PIPENAME "serverThreadMain2", PIPE_ACCESS_DUPLEX,
+            PIPE_TYPE_BYTE | PIPE_WAIT,
+            /* nMaxInstances */ 2,
+            /* nOutBufSize */ 1024,
+            /* nInBufSize */ 1024,
+            /* nDefaultWait */ NMPWAIT_USE_DEFAULT_WAIT,
+            /* lpSecurityAttrib */ NULL);
+
+        ok(hnpNext != INVALID_HANDLE_VALUE, "CreateNamedPipe failed");
+
+        ok(CloseHandle(hnp), "CloseHandle");
+        hnp = hnpNext;
+    }
+}
+
+/** Trivial byte echo server - uses overlapped named pipe calls */
+static DWORD CALLBACK serverThreadMain3(LPVOID arg)
+{
+    int i;
+    HANDLE hEvent;
+
+    msg("serverThreadMain3\n");
+    /* Set up a simple echo server */
+    hnp = CreateNamedPipe(PIPENAME "serverThreadMain3", PIPE_ACCESS_DUPLEX | FILE_FLAG_OVERLAPPED,
+        PIPE_TYPE_BYTE | PIPE_WAIT,
+        /* nMaxInstances */ 1,
+        /* nOutBufSize */ 1024,
+        /* nInBufSize */ 1024,
+        /* nDefaultWait */ NMPWAIT_USE_DEFAULT_WAIT,
+        /* lpSecurityAttrib */ NULL);
+    ok(hnp != INVALID_HANDLE_VALUE, "CreateNamedPipe failed");
+
+    hEvent = CreateEvent(NULL,  // security attribute
+        TRUE,                   // manual reset event 
+        FALSE,                  // initial state 
+        NULL);                  // name
+    ok(hEvent != NULL, "CreateEvent");
+
+    for (i = 0; ; i++) {
+        char buf[512];
+        DWORD written;
+        DWORD readden;
+        DWORD dummy;
+        DWORD success;
+        OVERLAPPED oOverlap;
+        int letWFSOEwait = (i & 2);
+        int letGORwait = (i & 1);
+	DWORD err;
+
+        memset(&oOverlap, 0, sizeof(oOverlap));
+        oOverlap.hEvent = hEvent;
+
+        /* Wait for client to connect */
+        msg("Server calling overlapped ConnectNamedPipe...\n");
+        success = ConnectNamedPipe(hnp, &oOverlap);
+        err = GetLastError();
+        ok(success || err == ERROR_IO_PENDING
+            || err == ERROR_PIPE_CONNECTED, "overlapped ConnectNamedPipe");
+        msg("overlapped ConnectNamedPipe returned.\n");
+        if (!success && (err == ERROR_IO_PENDING) && letWFSOEwait)
+            ok(WaitForSingleObjectEx(hEvent, INFINITE, TRUE) == 0, "wait ConnectNamedPipe");
+        success = GetOverlappedResult(hnp, &oOverlap, &dummy, letGORwait);
+	if (!letGORwait && !letWFSOEwait && !success) {
+	    ok(GetLastError() == ERROR_IO_INCOMPLETE, "GetOverlappedResult");
+	    success = GetOverlappedResult(hnp, &oOverlap, &dummy, TRUE);
+	}
+	ok(success, "GetOverlappedResult ConnectNamedPipe");
+        msg("overlapped ConnectNamedPipe operation complete.\n");
+
+        /* Echo bytes once */
+        memset(buf, 0, sizeof(buf));
+
+        msg("Server reading...\n");
+        success = ReadFile(hnp, buf, sizeof(buf), NULL, &oOverlap);
+        msg("Server ReadFile returned...\n");
+        err = GetLastError();
+        ok(success || err == ERROR_IO_PENDING, "overlapped ReadFile");
+        msg("overlapped ReadFile returned.\n");
+        if (!success && (err == ERROR_IO_PENDING) && letWFSOEwait)
+            ok(WaitForSingleObjectEx(hEvent, INFINITE, TRUE) == 0, "wait ReadFile");
+        success = GetOverlappedResult(hnp, &oOverlap, &readden, letGORwait);
+	if (!letGORwait && !letWFSOEwait && !success) {
+	    ok(GetLastError() == ERROR_IO_INCOMPLETE, "GetOverlappedResult");
+	    success = GetOverlappedResult(hnp, &oOverlap, &readden, TRUE);
+	}
+        msg("Server done reading.\n");
+        ok(success, "overlapped ReadFile");
+
+        msg("Server writing...\n");
+        success = WriteFile(hnp, buf, readden, NULL, &oOverlap);
+        msg("Server WriteFile returned...\n");
+        err = GetLastError();
+        ok(success || err == ERROR_IO_PENDING, "overlapped WriteFile");
+        msg("overlapped WriteFile returned.\n");
+        if (!success && (err == ERROR_IO_PENDING) && letWFSOEwait)
+            ok(WaitForSingleObjectEx(hEvent, INFINITE, TRUE) == 0, "wait WriteFile");
+        success = GetOverlappedResult(hnp, &oOverlap, &written, letGORwait);
+	if (!letGORwait && !letWFSOEwait && !success) {
+	    ok(GetLastError() == ERROR_IO_INCOMPLETE, "GetOverlappedResult");
+	    success = GetOverlappedResult(hnp, &oOverlap, &written, TRUE);
+	}
+        msg("Server done writing.\n");
+        ok(success, "overlapped WriteFile");
+        ok(written == readden, "write file len");
+
+        /* finish this connection, wait for next one */
+        ok(FlushFileBuffers(hnp), "FlushFileBuffers");
+        ok(DisconnectNamedPipe(hnp), "DisconnectNamedPipe");
+    }
+}
+
+static void exercizeServer(const char *pipename, HANDLE serverThread)
+{
+    int i;
+
+    msg("exercizeServer starting\n");
+    for (i = 0; i < 8; i++) {
+        HANDLE hFile;
+        const char obuf[] = "Bit Bucket";
+        char ibuf[32];
+        DWORD written;
+        DWORD readden;
+        int loop;
+
+        for (loop = 0; loop < 3; loop++) {
+	    DWORD err;
+            msg("Client connecting...\n");
+            /* Connect to the server */
+            hFile = CreateFileA(pipename, GENERIC_READ | GENERIC_WRITE, 0,
+                NULL, OPEN_EXISTING, 0, 0);
+            if (hFile != INVALID_HANDLE_VALUE)
+                break;
+	    err = GetLastError();
+	    if (loop == 0)
+	        ok(err == ERROR_PIPE_BUSY || err == ERROR_FILE_NOT_FOUND, "connecting to pipe");
+	    else
+	        ok(err == ERROR_PIPE_BUSY, "connecting to pipe");
+            msg("connect failed, retrying\n");
+            Sleep(200);
+        }
+        ok(hFile != INVALID_HANDLE_VALUE, "client opening named pipe");
+
+        /* Make sure it can echo */
+        memset(ibuf, 0, sizeof(ibuf));
+        msg("Client writing...\n");
+        ok(WriteFile(hFile, obuf, sizeof(obuf), &written, NULL), "WriteFile to client end of pipe");
+        ok(written == sizeof(obuf), "write file len");
+        msg("Client reading...\n");
+        ok(ReadFile(hFile, ibuf, sizeof(obuf), &readden, NULL), "ReadFile from client end of pipe");
+        ok(readden == sizeof(obuf), "read file len");
+        ok(memcmp(obuf, ibuf, written) == 0, "content check");
+
+        msg("Client closing...\n");
+        ok(CloseHandle(hFile), "CloseHandle");
+    }
+
+    ok(TerminateThread(serverThread, 0), "TerminateThread");
+    CloseHandle(hnp);
+    msg("exercizeServer returning\n");
+}
+
+void test_NamedPipe_2(void)
+{
+    HANDLE serverThread;
+    DWORD serverThreadId;
+    HANDLE alarmThread;
+    DWORD alarmThreadId;
+
+    msg("test_NamedPipe_2 starting\n");
+    /* Set up a ten second timeout */
+    alarmThread = CreateThread(NULL, 0, alarmThreadMain, (void *) 10000, 0, &alarmThreadId);
+
+    /* The servers we're about to exercize do try to clean up carefully,
+     * but to reduce the change of a test failure due to a pipe handle
+     * leak in the test code, we'll use a different pipe name for each server.
+     */
+
+    /* Try server #1 */
+    serverThread = CreateThread(NULL, 0, serverThreadMain1, 0, 0, &serverThreadId);
+    ok(serverThread != INVALID_HANDLE_VALUE, "CreateThread");
+    exercizeServer(PIPENAME "serverThreadMain1", serverThread);
+
+    /* Try server #2 */
+    serverThread = CreateThread(NULL, 0, serverThreadMain2, 0, 0, &serverThreadId);
+    ok(serverThread != INVALID_HANDLE_VALUE, "CreateThread");
+    exercizeServer(PIPENAME "serverThreadMain2", serverThread);
+
+    if( 0 ) /* overlapped pipe server doesn't work yet - it randomly fails */
+    {
+    /* Try server #3 */
+    serverThread = CreateThread(NULL, 0, serverThreadMain3, 0, 0, &serverThreadId);
+    ok(serverThread != INVALID_HANDLE_VALUE, "CreateThread");
+    exercizeServer(PIPENAME "serverThreadMain3", serverThread);
+    }
+
+    ok(TerminateThread(alarmThread, 0), "TerminateThread");
+    msg("test_NamedPipe_2 returning\n");
+}
+
+void test_DisconnectNamedPipe(void)
+{
+    HANDLE hnp;
+    HANDLE hFile;
+    const char obuf[] = "Bit Bucket";
+    char ibuf[32];
+    DWORD written;
+    DWORD readden;
+
+    hnp = CreateNamedPipe(PIPENAME, PIPE_ACCESS_DUPLEX, PIPE_TYPE_BYTE | PIPE_WAIT,
+        /* nMaxInstances */ 1,
+        /* nOutBufSize */ 1024,
+        /* nInBufSize */ 1024,
+        /* nDefaultWait */ NMPWAIT_USE_DEFAULT_WAIT,
+        /* lpSecurityAttrib */ NULL);
+    ok(hnp != INVALID_HANDLE_VALUE, "CreateNamedPipe failed");
+
+    ok(WriteFile(hnp, obuf, sizeof(obuf), &written, NULL) == 0
+        && GetLastError() == ERROR_PIPE_LISTENING, "WriteFile to not-yet-connected pipe");
+    ok(ReadFile(hnp, ibuf, sizeof(ibuf), &readden, NULL) == 0
+        && GetLastError() == ERROR_PIPE_LISTENING, "ReadFile from not-yet-connected pipe");
+
+    hFile = CreateFileA(PIPENAME, GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, 0);
+    ok(hFile != INVALID_HANDLE_VALUE, "CreateFile failed");
+
+    /* don't try to do i/o if one side couldn't be opened, as it hangs */
+    if (hFile != INVALID_HANDLE_VALUE) {
+
+        /* see what happens if server calls DisconnectNamedPipe
+         * when there are bytes in the pipe
+         */
+
+        ok(WriteFile(hFile, obuf, sizeof(obuf), &written, NULL), "WriteFile");
+        ok(written == sizeof(obuf), "write file len");
+        ok(DisconnectNamedPipe(hnp), "DisconnectNamedPipe while messages waiting");
+        ok(WriteFile(hFile, obuf, sizeof(obuf), &written, NULL) == 0
+            && GetLastError() == ERROR_PIPE_NOT_CONNECTED, "WriteFile to disconnected pipe");
+        ok(ReadFile(hnp, ibuf, sizeof(ibuf), &readden, NULL) == 0
+            && GetLastError() == ERROR_PIPE_NOT_CONNECTED,
+            "ReadFile from disconnected pipe with bytes waiting");
+        ok(CloseHandle(hFile), "CloseHandle");
+    }
+
+    ok(CloseHandle(hnp), "CloseHandle");
+
 }
 
 START_TEST(pipe)
 {
-    test_CreateNamedPipeA();
+    msg("test 1 of 4:\n");
+    test_DisconnectNamedPipe();
+    msg("test 2 of 4:\n");
+    test_CreateNamedPipe_instances_must_match();
+    msg("test 3 of 4:\n");
+    test_NamedPipe_2();
+    msg("test 4 of 4:\n");
+    test_CreateNamedPipe();
+    msg("all tests done\n");
 }


More information about the wine-patches mailing list