From: Sebastian Lackner Subject: [2/5] wininet/tests: Add tests for asynchronous InternetReadFileEx. (v3) Message-Id: <7655dd36-c339-4b20-ed8e-dc14345cb214@fds-team.de> Date: Tue, 26 Apr 2016 23:37:54 +0200 Signed-off-by: Sebastian Lackner --- Changes in v3: * Use timeout of 0 to avoid blocking * Change todo_wine_if as suggested, to ensure it doesn't hide Wine test failures dlls/wininet/tests/http.c | 117 +++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 116 insertions(+), 1 deletion(-) diff --git a/dlls/wininet/tests/http.c b/dlls/wininet/tests/http.c index 82fd10b..fcaba10 100644 --- a/dlls/wininet/tests/http.c +++ b/dlls/wininet/tests/http.c @@ -109,7 +109,7 @@ static int expect[MAX_INTERNET_STATUS], optional[MAX_INTERNET_STATUS], wine_allow[MAX_INTERNET_STATUS], notified[MAX_INTERNET_STATUS]; static const char *status_string[MAX_INTERNET_STATUS]; -static HANDLE hCompleteEvent, conn_close_event; +static HANDLE hCompleteEvent, conn_close_event, conn_wait_event; static DWORD req_error; #define TESTF_REDIRECT 0x01 @@ -2358,6 +2358,15 @@ static DWORD CALLBACK server_thread(LPVOID param) else send(c, notokmsg, sizeof notokmsg-1, 0); } + if (strstr(buffer, "/async_read")) + { + const char *page1_mid = page1 + (sizeof page1 - 1)/2; + const char *page1_end = page1 + sizeof page1 - 1; + send(c, okmsg, sizeof okmsg-1, 0); + send(c, page1, page1_mid - page1, 0); + WaitForSingleObject(conn_wait_event, INFINITE); + send(c, page1_mid, page1_end - page1_mid, 0); + } shutdown(c, 2); closesocket(c); c = -1; @@ -4420,6 +4429,111 @@ static void test_basic_auth_credentials_reuse(int port) InternetCloseHandle( ses ); } +static void test_async_read(int port) +{ + HINTERNET ses, con, req; + INTERNET_BUFFERSA ib; + char buffer[0x100]; + DWORD pending_reads; + DWORD res, count; + BOOL ret; + + hCompleteEvent = CreateEventW(NULL, FALSE, FALSE, NULL); + conn_wait_event = CreateEventW(NULL, FALSE, FALSE, NULL); + + /* test asynchronous InternetReadFileEx */ + ses = InternetOpenA( "winetest", INTERNET_OPEN_TYPE_DIRECT, NULL, NULL, INTERNET_FLAG_ASYNC ); + ok( ses != NULL, "InternetOpenA failed\n" ); + pInternetSetStatusCallbackA( ses, &callback ); + + SET_EXPECT( INTERNET_STATUS_HANDLE_CREATED ); + con = InternetConnectA( ses, "localhost", port, NULL, NULL, INTERNET_SERVICE_HTTP, 0, 0xdeadbeef ); + ok( con != NULL, "InternetConnectA failed %u\n", GetLastError() ); + CHECK_NOTIFIED( INTERNET_STATUS_HANDLE_CREATED ); + + SET_EXPECT( INTERNET_STATUS_HANDLE_CREATED ); + req = HttpOpenRequestA( con, "GET", "/async_read", NULL, NULL, NULL, INTERNET_FLAG_RELOAD, 0xdeadbeef ); + ok( req != NULL, "HttpOpenRequestA failed %u\n", GetLastError() ); + CHECK_NOTIFIED( INTERNET_STATUS_HANDLE_CREATED ); + + SET_OPTIONAL( INTERNET_STATUS_COOKIE_SENT ); + SET_OPTIONAL( INTERNET_STATUS_DETECTING_PROXY ); + SET_EXPECT( INTERNET_STATUS_CONNECTING_TO_SERVER ); + SET_EXPECT( INTERNET_STATUS_CONNECTED_TO_SERVER ); + SET_EXPECT( INTERNET_STATUS_SENDING_REQUEST ); + SET_EXPECT( INTERNET_STATUS_REQUEST_SENT ); + SET_EXPECT( INTERNET_STATUS_RECEIVING_RESPONSE ); + SET_EXPECT( INTERNET_STATUS_RESPONSE_RECEIVED ); + SET_OPTIONAL( INTERNET_STATUS_CLOSING_CONNECTION ); + SET_OPTIONAL( INTERNET_STATUS_CONNECTION_CLOSED ); + SET_EXPECT( INTERNET_STATUS_REQUEST_COMPLETE ); + + SetLastError( 0xdeadbeef ); + ret = HttpSendRequestA( req, NULL, 0, NULL, 0 ); + ok( !ret, "HttpSendRequestA unexpectedly succeeded\n" ); + ok( GetLastError() == ERROR_IO_PENDING, "expected ERROR_IO_PENDING, got %u\n", GetLastError() ); + WaitForSingleObject( hCompleteEvent, INFINITE ); + ok( req_error == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %u\n", req_error ); + + CLEAR_NOTIFIED( INTERNET_STATUS_COOKIE_SENT ); + CLEAR_NOTIFIED( INTERNET_STATUS_DETECTING_PROXY ); + CHECK_NOTIFIED( INTERNET_STATUS_CONNECTING_TO_SERVER ); + CHECK_NOTIFIED( INTERNET_STATUS_CONNECTED_TO_SERVER ); + CHECK_NOTIFIED( INTERNET_STATUS_SENDING_REQUEST ); + CHECK_NOTIFIED( INTERNET_STATUS_REQUEST_SENT ); + CHECK_NOTIFIED( INTERNET_STATUS_RECEIVING_RESPONSE ); + CHECK_NOTIFIED( INTERNET_STATUS_RESPONSE_RECEIVED ); + CLEAR_NOTIFIED( INTERNET_STATUS_CLOSING_CONNECTION ); + CLEAR_NOTIFIED( INTERNET_STATUS_CONNECTION_CLOSED ); + CHECK_NOTIFIED( INTERNET_STATUS_REQUEST_COMPLETE ); + + pending_reads = 0; + memset( &ib, 0, sizeof(ib) ); + memset( buffer, 0, sizeof(buffer) ); + ib.dwStructSize = sizeof(ib); + for (count = 0; count < sizeof(buffer); count += ib.dwBufferLength) + { + ib.lpvBuffer = buffer + count; + ib.dwBufferLength = min(16, sizeof(buffer) - count); + + SET_OPTIONAL( INTERNET_STATUS_RECEIVING_RESPONSE ); + SET_OPTIONAL( INTERNET_STATUS_RESPONSE_RECEIVED ); + + ret = InternetReadFileExA( req, &ib, 0, 0xdeadbeef ); + if (!count) /* the first part should arrive immediately */ + ok( ret, "InternetReadFileExA failed %u\n", GetLastError() ); + if (!ret) + { + ok( GetLastError() == ERROR_IO_PENDING, "expected ERROR_IO_PENDING, got %u\n", GetLastError() ); + SET_EXPECT( INTERNET_STATUS_REQUEST_COMPLETE ); + if (!pending_reads++) + { + res = WaitForSingleObject( hCompleteEvent, 0 ); + ok( res == WAIT_TIMEOUT, "expected WAIT_TIMEOUT, got %u\n", res ); + SetEvent( conn_wait_event ); + } + res = WaitForSingleObject( hCompleteEvent, INFINITE ); + ok( res == WAIT_OBJECT_0, "expected WAIT_OBJECT_0, got %u\n", res ); + ok( req_error == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %u\n", req_error ); + todo_wine_if( pending_reads > 1 ) + ok( ib.dwBufferLength != 0, "expected ib.dwBufferLength != 0\n" ); + CHECK_NOTIFIED( INTERNET_STATUS_REQUEST_COMPLETE ); + } + + CLEAR_NOTIFIED( INTERNET_STATUS_RECEIVING_RESPONSE ); + CLEAR_NOTIFIED( INTERNET_STATUS_RESPONSE_RECEIVED ); + if (!ib.dwBufferLength) break; + } + + todo_wine + ok( pending_reads == 1, "expected 1 pending read, got %u\n", pending_reads ); + ok( !strcmp(buffer, page1), "unexpected buffer content\n" ); + close_async_handle( ses, hCompleteEvent, 2 ); + + CloseHandle( hCompleteEvent ); + CloseHandle( conn_wait_event ); +} + static void test_http_connection(void) { struct server_info si; @@ -4469,6 +4583,7 @@ static void test_http_connection(void) test_request_content_length(si.port); test_accept_encoding(si.port); test_basic_auth_credentials_reuse(si.port); + test_async_read(si.port); /* send the basic request again to shutdown the server thread */ test_basic_request(si.port, "GET", "/quit"); -- 2.8.0