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