kernel32/tests: Added more named pipe tests.

Signed-off-by: Jacek Caban <jacek@codeweavers.com>
Signed-off-by: Alexandre Julliard <julliard@winehq.org>
This commit is contained in:
Jacek Caban 2017-03-23 15:42:47 +01:00 committed by Alexandre Julliard
parent b682e1c41d
commit a83b5cdb93
1 changed files with 413 additions and 0 deletions

View File

@ -36,6 +36,7 @@ static HANDLE alarm_event;
static BOOL (WINAPI *pDuplicateTokenEx)(HANDLE,DWORD,LPSECURITY_ATTRIBUTES,
SECURITY_IMPERSONATION_LEVEL,TOKEN_TYPE,PHANDLE);
static DWORD (WINAPI *pQueueUserAPC)(PAPCFUNC pfnAPC, HANDLE hThread, ULONG_PTR dwData);
static BOOL (WINAPI *pCancelIoEx)(HANDLE handle, LPOVERLAPPED lpOverlapped);
static BOOL user_apc_ran;
static void CALLBACK user_apc(ULONG_PTR param)
@ -110,6 +111,13 @@ static BOOL RpcReadFile(HANDLE hFile, LPVOID buffer, DWORD bytesToRead, LPDWORD
return (BOOL)rpcargs.returnValue;
}
#define test_not_signaled(h) _test_not_signaled(__LINE__,h)
static void _test_not_signaled(unsigned line, HANDLE handle)
{
DWORD res = WaitForSingleObject(handle, 0);
ok_(__FILE__,line)(res == WAIT_TIMEOUT, "WaitForSingleObject returned %u (%u)\n", res, GetLastError());
}
#define test_signaled(h) _test_signaled(__LINE__,h)
static void _test_signaled(unsigned line, HANDLE handle)
{
@ -2508,6 +2516,409 @@ todo_wine
CloseHandle(event);
}
#define test_peek_pipe(a,b,c) _test_peek_pipe(__LINE__,a,b,c)
static void _test_peek_pipe(unsigned line, HANDLE pipe, DWORD expected_read, DWORD expected_avail)
{
DWORD bytes_read = 0xdeadbeed, avail = 0xdeadbeef;
char buf[4000];
BOOL r;
r = PeekNamedPipe(pipe, buf, sizeof(buf), &bytes_read, &avail, NULL);
ok_(__FILE__,line)(r, "PeekNamedPipe failed: %u\n", GetLastError());
ok_(__FILE__,line)(bytes_read == expected_read, "bytes_read = %u, expected %u\n", bytes_read, expected_read);
ok_(__FILE__,line)(avail == expected_avail, "avail = %u, expected %u\n", avail, expected_avail);
}
#define overlapped_read_sync(a,b,c,d,e) _overlapped_read_sync(__LINE__,a,b,c,d,e)
static void _overlapped_read_sync(unsigned line, HANDLE reader, void *buf, DWORD buf_size, DWORD expected_result, BOOL partial_read)
{
DWORD read_bytes = 0xdeadbeef;
OVERLAPPED overlapped;
BOOL res;
memset(&overlapped, 0, sizeof(overlapped));
overlapped.hEvent = CreateEventW(NULL, TRUE, FALSE, NULL);
res = ReadFile(reader, buf, buf_size, &read_bytes, &overlapped);
if (partial_read)
ok_(__FILE__,line)(!res && GetLastError() == ERROR_MORE_DATA, "ReadFile returned: %x (%u)\n", res, GetLastError());
else
ok_(__FILE__,line)(res, "ReadFile failed: %u\n", GetLastError());
if(partial_read)
todo_wine ok_(__FILE__,line)(!read_bytes, "read_bytes %u expected 0\n", read_bytes);
else
ok_(__FILE__,line)(read_bytes == expected_result, "read_bytes %u expected %u\n", read_bytes, expected_result);
read_bytes = 0xdeadbeef;
res = GetOverlappedResult(reader, &overlapped, &read_bytes, FALSE);
if (partial_read)
ok_(__FILE__,line)(!res && GetLastError() == ERROR_MORE_DATA,
"GetOverlappedResult returned: %x (%u)\n", res, GetLastError());
else
ok_(__FILE__,line)(res, "GetOverlappedResult failed: %u\n", GetLastError());
ok_(__FILE__,line)(read_bytes == expected_result, "read_bytes %u expected %u\n", read_bytes, expected_result);
CloseHandle(overlapped.hEvent);
}
#define overlapped_read_async(a,b,c,d) _overlapped_read_async(__LINE__,a,b,c,d)
static void _overlapped_read_async(unsigned line, HANDLE reader, void *buf, DWORD buf_size, OVERLAPPED *overlapped)
{
DWORD read_bytes = 0xdeadbeef;
BOOL res;
memset(overlapped, 0, sizeof(*overlapped));
overlapped->hEvent = CreateEventW(NULL, TRUE, FALSE, NULL);
res = ReadFile(reader, buf, buf_size, &read_bytes, overlapped);
ok_(__FILE__,line)(!res && GetLastError() == ERROR_IO_PENDING, "ReadFile returned %x(%u)\n", res, GetLastError());
ok_(__FILE__,line)(!read_bytes, "read_bytes %u expected 0\n", read_bytes);
_test_not_signaled(line, overlapped->hEvent);
}
#define overlapped_write_sync(a,b,c) _overlapped_write_sync(__LINE__,a,b,c)
static void _overlapped_write_sync(unsigned line, HANDLE writer, void *buf, DWORD size)
{
DWORD written_bytes = 0xdeadbeef;
OVERLAPPED overlapped;
BOOL res;
memset(&overlapped, 0, sizeof(overlapped));
overlapped.hEvent = CreateEventW(NULL, TRUE, FALSE, NULL);
res = WriteFile(writer, buf, size, &written_bytes, &overlapped);
ok_(__FILE__,line)(res, "WriteFile returned %x(%u)\n", res, GetLastError());
ok_(__FILE__,line)(written_bytes == size, "WriteFile returned written_bytes = %u\n", written_bytes);
written_bytes = 0xdeadbeef;
res = GetOverlappedResult(writer, &overlapped, &written_bytes, FALSE);
ok_(__FILE__,line)(res, "GetOverlappedResult failed: %u\n", GetLastError());
ok_(__FILE__,line)(written_bytes == size, "GetOverlappedResult returned written_bytes %u expected %u\n", written_bytes, size);
CloseHandle(overlapped.hEvent);
}
#define overlapped_write_async(a,b,c,d) _overlapped_write_async(__LINE__,a,b,c,d)
static void _overlapped_write_async(unsigned line, HANDLE writer, void *buf, DWORD size, OVERLAPPED *overlapped)
{
DWORD written_bytes = 0xdeadbeef;
BOOL res;
memset(overlapped, 0, sizeof(*overlapped));
overlapped->hEvent = CreateEventW(NULL, TRUE, FALSE, NULL);
res = WriteFile(writer, buf, size, &written_bytes, overlapped);
ok_(__FILE__,line)(!res && GetLastError() == ERROR_IO_PENDING, "WriteFile returned %x(%u)\n", res, GetLastError());
todo_wine ok_(__FILE__,line)(!written_bytes, "written_bytes = %u\n", written_bytes);
_test_not_signaled(line, overlapped->hEvent);
}
#define test_flush_sync(a) _test_flush_sync(__LINE__,a)
static void _test_flush_sync(unsigned line, HANDLE pipe)
{
BOOL res;
res = FlushFileBuffers(pipe);
ok_(__FILE__,line)(res, "FlushFileBuffers failed: %u\n", GetLastError());
}
static DWORD expected_flush_error;
static DWORD CALLBACK flush_proc(HANDLE pipe)
{
BOOL res;
res = FlushFileBuffers(pipe);
if (expected_flush_error == ERROR_SUCCESS)
ok(res, "FlushFileBuffers failed: %u\n", GetLastError());
else
todo_wine ok(!res && GetLastError() == expected_flush_error, "FlushFileBuffers failed: %u\n", GetLastError());
return 0;
}
#define test_flush_async(a,b) _test_flush_async(__LINE__,a,b)
static HANDLE _test_flush_async(unsigned line, HANDLE pipe, DWORD error)
{
HANDLE thread;
DWORD tid;
expected_flush_error = error;
thread = CreateThread(NULL, 0, flush_proc, pipe, 0, &tid);
ok_(__FILE__,line)(thread != NULL, "CreateThread failed: %u\n", GetLastError());
Sleep(50);
_test_not_signaled(line, thread);
return thread;
}
#define test_flush_done(a) _test_flush_done(__LINE__,a)
static void _test_flush_done(unsigned line, HANDLE thread)
{
DWORD res = WaitForSingleObject(thread, 1000);
ok_(__FILE__,line)(res == WAIT_OBJECT_0, "WaitForSingleObject returned %u (%u)\n", res, GetLastError());
CloseHandle(thread);
}
#define test_overlapped_result(a,b,c,d) _test_overlapped_result(__LINE__,a,b,c,d)
static void _test_overlapped_result(unsigned line, HANDLE handle, OVERLAPPED *overlapped, DWORD expected_result, BOOL partial_read)
{
DWORD result = 0xdeadbeef;
BOOL res;
_test_signaled(line, overlapped->hEvent);
res = GetOverlappedResult(handle, overlapped, &result, FALSE);
if (partial_read)
ok_(__FILE__,line)(!res && GetLastError() == ERROR_MORE_DATA, "GetOverlappedResult returned: %x (%u)\n", res, GetLastError());
else
ok_(__FILE__,line)(res, "GetOverlappedResult failed: %u\n", GetLastError());
ok_(__FILE__,line)(result == expected_result, "read_bytes = %u, expected %u\n", result, expected_result);
CloseHandle(overlapped->hEvent);
}
#define test_overlapped_failure(a,b,c) _test_overlapped_failure(__LINE__,a,b,c)
static void _test_overlapped_failure(unsigned line, HANDLE handle, OVERLAPPED *overlapped, DWORD error)
{
DWORD result;
BOOL res;
_test_signaled(line, overlapped->hEvent);
res = GetOverlappedResult(handle, overlapped, &result, FALSE);
ok_(__FILE__,line)(!res && GetLastError() == error, "GetOverlappedResult returned: %x (%u), expected error %u\n",
res, GetLastError(), error);
ok_(__FILE__,line)(!result, "result = %u\n", result);
CloseHandle(overlapped->hEvent);
}
#define cancel_overlapped(a,b) _cancel_overlapped(__LINE__,a,b)
static void _cancel_overlapped(unsigned line, HANDLE handle, OVERLAPPED *overlapped)
{
BOOL res;
res = pCancelIoEx(handle, overlapped);
ok_(__FILE__,line)(res, "CancelIoEx failed: %u\n", GetLastError());
_test_overlapped_failure(line, handle, overlapped, ERROR_OPERATION_ABORTED);
}
static void test_blocking_rw(HANDLE writer, HANDLE reader, DWORD buf_size, BOOL msg_mode, BOOL msg_read)
{
OVERLAPPED read_overlapped, read_overlapped2, write_overlapped, write_overlapped2;
char buf[10000], read_buf[10000];
HANDLE flush_thread;
memset(buf, 0xaa, sizeof(buf));
/* test pending read with overlapped event */
overlapped_read_async(reader, read_buf, 1000, &read_overlapped);
test_flush_sync(writer);
test_peek_pipe(reader, 0, 0);
/* write more data than needed for read */
overlapped_write_sync(writer, buf, 4000);
test_overlapped_result(reader, &read_overlapped, 1000, msg_read);
/* test pending write with overlapped event */
overlapped_write_async(writer, buf, buf_size, &write_overlapped);
/* write one more byte */
overlapped_write_async(writer, buf, 1, &write_overlapped2);
flush_thread = test_flush_async(writer, ERROR_SUCCESS);
test_not_signaled(write_overlapped.hEvent);
/* empty write will not block */
overlapped_write_sync(writer, buf, 0);
test_not_signaled(write_overlapped.hEvent);
test_not_signaled(write_overlapped2.hEvent);
/* read remaining data from the first write */
overlapped_read_sync(reader, read_buf, 3000, 3000, FALSE);
test_overlapped_result(writer, &write_overlapped, buf_size, FALSE);
test_not_signaled(write_overlapped2.hEvent);
test_not_signaled(flush_thread);
/* read one byte so that the next write fits the buffer */
overlapped_read_sync(reader, read_buf, 1, 1, msg_read);
test_overlapped_result(writer, &write_overlapped2, 1, FALSE);
/* read the whole buffer */
overlapped_read_sync(reader, read_buf, buf_size, buf_size-msg_read, FALSE);
if(msg_read)
overlapped_read_sync(reader, read_buf, 1000, 1, FALSE);
if(msg_mode) {
/* we still have an empty message in queue */
overlapped_read_sync(reader, read_buf, 1000, 0, FALSE);
}
test_flush_done(flush_thread);
/* pipe is empty, the next read will block */
overlapped_read_async(reader, read_buf, 0, &read_overlapped);
overlapped_read_async(reader, read_buf, 1000, &read_overlapped2);
/* write one byte */
overlapped_write_sync(writer, buf, 1);
test_overlapped_result(reader, &read_overlapped, 0, msg_read);
test_overlapped_result(reader, &read_overlapped2, 1, FALSE);
/* write a message larger than buffer */
overlapped_write_async(writer, buf, buf_size+2000, &write_overlapped);
/* read so that pending write is still larger than the buffer */
overlapped_read_sync(reader, read_buf, 1999, 1999, msg_read);
test_not_signaled(write_overlapped.hEvent);
/* read one more byte */
overlapped_read_sync(reader, read_buf, 1, 1, msg_read);
test_overlapped_result(writer, &write_overlapped, buf_size+2000, FALSE);
/* read remaining data */
overlapped_read_sync(reader, read_buf, buf_size+1, buf_size, FALSE);
/* simple pass of empty message */
overlapped_write_sync(writer, buf, 0);
if(msg_mode)
overlapped_read_sync(reader, read_buf, 1, 0, FALSE);
/* pipe is empty, the next read will block */
test_flush_sync(writer);
overlapped_read_async(reader, read_buf, 0, &read_overlapped);
overlapped_read_async(reader, read_buf, 1, &read_overlapped2);
/* 0 length write wakes one read in msg mode */
overlapped_write_sync(writer, buf, 0);
if(msg_mode)
test_overlapped_result(reader, &read_overlapped, 0, FALSE);
else
test_not_signaled(read_overlapped.hEvent);
test_not_signaled(read_overlapped2.hEvent);
overlapped_write_sync(writer, buf, 1);
test_overlapped_result(reader, &read_overlapped2, 1, FALSE);
overlapped_write_sync(writer, buf, 20);
test_peek_pipe(reader, 20, 20);
overlapped_write_sync(writer, buf, 15);
test_peek_pipe(reader, msg_mode ? 20 : 35, 35);
overlapped_read_sync(reader, read_buf, 10, 10, msg_read);
test_peek_pipe(reader, msg_mode ? 10 : 25, 25);
overlapped_read_sync(reader, read_buf, 10, 10, FALSE);
test_peek_pipe(reader, 15, 15);
overlapped_read_sync(reader, read_buf, 15, 15, FALSE);
if(!pCancelIoEx) {
win_skip("CancelIoEx not available\n");
return;
}
/* add one more pending read, then cancel the first one */
overlapped_read_async(reader, read_buf, 1, &read_overlapped);
overlapped_read_async(reader, read_buf, 1, &read_overlapped2);
cancel_overlapped(reader, &read_overlapped2);
test_not_signaled(read_overlapped.hEvent);
overlapped_write_sync(writer, buf, 1);
test_overlapped_result(reader, &read_overlapped, 1, FALSE);
/* make two async writes, cancel the first one and make sure that we read from the second one */
overlapped_write_async(writer, buf, buf_size+2000, &write_overlapped);
overlapped_write_async(writer, buf, 1, &write_overlapped2);
cancel_overlapped(writer, &write_overlapped);
overlapped_read_sync(reader, read_buf, 1000, 1, FALSE);
test_overlapped_result(writer, &write_overlapped2, 1, FALSE);
/* same as above, but parially read written data before canceling */
overlapped_write_async(writer, buf, buf_size+2000, &write_overlapped);
overlapped_write_async(writer, buf, 1, &write_overlapped2);
overlapped_read_sync(reader, read_buf, 10, 10, msg_read);
test_not_signaled(write_overlapped.hEvent);
cancel_overlapped(writer, &write_overlapped);
overlapped_read_sync(reader, read_buf, 1000, 1, FALSE);
test_overlapped_result(writer, &write_overlapped2, 1, FALSE);
/* empty queue by canceling write and make sure that flush is signaled */
overlapped_write_async(writer, buf, buf_size+2000, &write_overlapped);
flush_thread = test_flush_async(writer, ERROR_SUCCESS);
test_not_signaled(flush_thread);
cancel_overlapped(writer, &write_overlapped);
test_flush_done(flush_thread);
}
static void create_overlapped_pipe(DWORD mode, HANDLE *client, HANDLE *server)
{
SECURITY_ATTRIBUTES sec_attr = { sizeof(sec_attr), NULL, TRUE };
DWORD read_mode = mode & (PIPE_READMODE_BYTE | PIPE_READMODE_MESSAGE);
OVERLAPPED overlapped;
BOOL res;
*server = CreateNamedPipeA(PIPENAME, FILE_FLAG_OVERLAPPED | PIPE_ACCESS_DUPLEX,
PIPE_WAIT | mode, 1, 5000, 6000, NMPWAIT_USE_DEFAULT_WAIT, NULL);
ok(&server != INVALID_HANDLE_VALUE, "CreateNamedPipe failed: %u\n", GetLastError());
test_signaled(*server);
memset(&overlapped, 0, sizeof(overlapped));
overlapped.hEvent = CreateEventW(NULL, TRUE, FALSE, NULL);
res = ConnectNamedPipe(*server, &overlapped);
ok(!res && GetLastError() == ERROR_IO_PENDING, "WriteFile returned %x(%u)\n", res, GetLastError());
test_not_signaled(*server);
test_not_signaled(overlapped.hEvent);
*client = CreateFileA(PIPENAME, GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, FILE_FLAG_OVERLAPPED, NULL);
ok(*server != INVALID_HANDLE_VALUE, "CreateFile failed: %u\n", GetLastError());
res = SetNamedPipeHandleState(*client, &read_mode, NULL, NULL);
ok(res, "SetNamedPipeHandleState failed: %u\n", GetLastError());
test_signaled(*client);
test_not_signaled(*server);
test_overlapped_result(*server, &overlapped, 0, FALSE);
}
static void test_overlapped_transport(BOOL msg_mode, BOOL msg_read_mode)
{
OVERLAPPED overlapped, overlapped2;
HANDLE server, client, flush;
char buf[60000];
BOOL res;
DWORD create_flags =
(msg_mode ? PIPE_TYPE_MESSAGE : PIPE_TYPE_BYTE) |
(msg_read_mode ? PIPE_READMODE_MESSAGE : PIPE_READMODE_BYTE);
create_overlapped_pipe(create_flags, &client, &server);
trace("testing %s, %s server->client writes...\n",
msg_mode ? "message mode" : "byte mode", msg_read_mode ? "message read" : "byte read");
test_blocking_rw(server, client, 5000, msg_mode, msg_read_mode);
CloseHandle(client);
CloseHandle(server);
/* close client with pending writes */
create_overlapped_pipe(create_flags, &client, &server);
overlapped_write_async(server, buf, 7000, &overlapped);
flush = test_flush_async(server, ERROR_BROKEN_PIPE);
CloseHandle(client);
test_overlapped_failure(server, &overlapped, ERROR_BROKEN_PIPE);
test_flush_done(flush);
CloseHandle(server);
/* close server with pending writes */
create_overlapped_pipe(create_flags, &client, &server);
overlapped_write_async(client, buf, 7000, &overlapped);
CloseHandle(server);
test_overlapped_failure(client, &overlapped, ERROR_BROKEN_PIPE);
CloseHandle(client);
/* disconnect with pending writes */
create_overlapped_pipe(create_flags, &client, &server);
overlapped_write_async(client, buf, 7000, &overlapped);
overlapped_write_async(server, buf, 7000, &overlapped2);
res = DisconnectNamedPipe(server);
ok(res, "DisconnectNamedPipe failed: %u\n", GetLastError());
test_overlapped_failure(client, &overlapped, ERROR_PIPE_NOT_CONNECTED);
test_overlapped_failure(client, &overlapped2, ERROR_PIPE_NOT_CONNECTED);
CloseHandle(server);
CloseHandle(client);
}
START_TEST(pipe)
{
HMODULE hmod;
@ -2516,6 +2927,7 @@ START_TEST(pipe)
pDuplicateTokenEx = (void *) GetProcAddress(hmod, "DuplicateTokenEx");
hmod = GetModuleHandleA("kernel32.dll");
pQueueUserAPC = (void *) GetProcAddress(hmod, "QueueUserAPC");
pCancelIoEx = (void *) GetProcAddress(hmod, "CancelIoEx");
if (test_DisconnectNamedPipe())
return;
@ -2531,4 +2943,5 @@ START_TEST(pipe)
test_NamedPipeHandleState();
test_GetNamedPipeInfo();
test_readfileex_pending();
test_overlapped_transport(TRUE, FALSE);
}