Author: akhaldi Date: Sun Dec 9 13:06:56 2012 New Revision: 57840
URL: http://svn.reactos.org/svn/reactos?rev=57840&view=rev Log: [SERVICES_WINETEST]: Import from Wine 1.5.19.
Added: trunk/rostests/winetests/services/ trunk/rostests/winetests/services/CMakeLists.txt (with props) trunk/rostests/winetests/services/service.c (with props) trunk/rostests/winetests/services/testlist.c (with props) Modified: trunk/rostests/winetests/CMakeLists.txt
Modified: trunk/rostests/winetests/CMakeLists.txt URL: http://svn.reactos.org/svn/reactos/trunk/rostests/winetests/CMakeLists.txt?r... ============================================================================== --- trunk/rostests/winetests/CMakeLists.txt [iso-8859-1] (original) +++ trunk/rostests/winetests/CMakeLists.txt [iso-8859-1] Sun Dec 9 13:06:56 2012 @@ -71,6 +71,7 @@ add_subdirectory(schannel) add_subdirectory(secur32) add_subdirectory(serialui) +add_subdirectory(services) add_subdirectory(setupapi) add_subdirectory(shdocvw) add_subdirectory(shell32)
Added: trunk/rostests/winetests/services/CMakeLists.txt URL: http://svn.reactos.org/svn/reactos/trunk/rostests/winetests/services/CMakeLi... ============================================================================== --- trunk/rostests/winetests/services/CMakeLists.txt (added) +++ trunk/rostests/winetests/services/CMakeLists.txt [iso-8859-1] Sun Dec 9 13:06:56 2012 @@ -1,0 +1,7 @@ + +add_definitions(-D__ROS_LONG64__) +add_executable(services_winetest service.c testlist.c) +target_link_libraries(services_winetest wine) +set_module_type(services_winetest win32cui) +add_importlibs(services_winetest advapi32 msvcrt kernel32 ntdll) +add_cd_file(TARGET services_winetest DESTINATION reactos/bin FOR all)
Propchange: trunk/rostests/winetests/services/CMakeLists.txt ------------------------------------------------------------------------------ svn:eol-style = native
Added: trunk/rostests/winetests/services/service.c URL: http://svn.reactos.org/svn/reactos/trunk/rostests/winetests/services/service... ============================================================================== --- trunk/rostests/winetests/services/service.c (added) +++ trunk/rostests/winetests/services/service.c [iso-8859-1] Sun Dec 9 13:06:56 2012 @@ -1,0 +1,490 @@ +/* + * Copyright 2012 Jacek Caban for CodeWeavers + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#include <windows.h> +#include <stdio.h> + +#include "wine/test.h" + +static SERVICE_STATUS_HANDLE (WINAPI *pRegisterServiceCtrlHandlerExA)(LPCSTR,LPHANDLER_FUNCTION_EX,LPVOID); + +static HANDLE pipe_handle = INVALID_HANDLE_VALUE; +static char service_name[100], named_pipe_name[100]; +static SERVICE_STATUS_HANDLE service_handle; + +/* Service process global variables */ +static HANDLE service_stop_event; + +static void send_msg(const char *type, const char *msg) +{ + DWORD written = 0; + char buf[512]; + + sprintf(buf, "%s:%s", type, msg); + WriteFile(pipe_handle, buf, strlen(buf)+1, &written, NULL); +} + +static inline void service_trace(const char *msg) +{ + send_msg("TRACE", msg); +} + +static inline void service_event(const char *event) +{ + send_msg("EVENT", event); +} + +static void service_ok(int cnd, const char *msg, ...) +{ + va_list valist; + char buf[512]; + + va_start(valist, msg); + vsprintf(buf, msg, valist); + va_end(valist); + + send_msg(cnd ? "OK" : "FAIL", buf); +} + +static DWORD WINAPI service_handler(DWORD ctrl, DWORD event_type, void *event_data, void *context) +{ + SERVICE_STATUS status; + + status.dwServiceType = SERVICE_WIN32; + status.dwControlsAccepted = SERVICE_ACCEPT_STOP; + status.dwWin32ExitCode = 0; + status.dwServiceSpecificExitCode = 0; + status.dwCheckPoint = 0; + status.dwWaitHint = 0; + + switch(ctrl) + { + case SERVICE_CONTROL_STOP: + case SERVICE_CONTROL_SHUTDOWN: + service_event("STOP"); + status.dwCurrentState = SERVICE_STOP_PENDING; + status.dwControlsAccepted = 0; + SetServiceStatus(service_handle, &status); + SetEvent(service_stop_event); + return NO_ERROR; + default: + status.dwCurrentState = SERVICE_RUNNING; + SetServiceStatus( service_handle, &status ); + return NO_ERROR; + } +} + +static void WINAPI service_main(DWORD argc, char **argv) +{ + SERVICE_STATUS status; + BOOL res; + + service_ok(argc == 1, "argc = %d", argc); + if(argc) + service_ok(!strcmp(argv[0], service_name), "argv[0] = %s, expected %s", argv[0], service_name); + + service_handle = pRegisterServiceCtrlHandlerExA(service_name, service_handler, NULL); + service_ok(service_handle != NULL, "RegisterServiceCtrlHandlerEx failed: %u\n", GetLastError()); + if(!service_handle) + return; + + status.dwServiceType = SERVICE_WIN32; + status.dwCurrentState = SERVICE_RUNNING; + status.dwControlsAccepted = SERVICE_ACCEPT_STOP | SERVICE_ACCEPT_SHUTDOWN; + status.dwWin32ExitCode = 0; + status.dwServiceSpecificExitCode = 0; + status.dwCheckPoint = 0; + status.dwWaitHint = 10000; + res = SetServiceStatus(service_handle, &status); + service_ok(res, "SetServiceStatus(SERVICE_RUNNING) failed: %u", GetLastError()); + + service_event("RUNNING"); + + WaitForSingleObject(service_stop_event, INFINITE); + + status.dwCurrentState = SERVICE_STOPPED; + status.dwControlsAccepted = 0; + res = SetServiceStatus(service_handle, &status); + service_ok(res, "SetServiceStatus(SERVICE_STOPPED) failed: %u", GetLastError()); +} + +static void service_process(void (WINAPI *p_service_main)(DWORD, char **)) +{ + BOOL res; + + SERVICE_TABLE_ENTRYA servtbl[] = { + {service_name, p_service_main}, + {NULL, NULL} + }; + + res = WaitNamedPipeA(named_pipe_name, NMPWAIT_USE_DEFAULT_WAIT); + if(!res) + return; + + pipe_handle = CreateFileA(named_pipe_name, GENERIC_WRITE, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); + if(pipe_handle == INVALID_HANDLE_VALUE) + return; + + service_trace("Starting..."); + + service_stop_event = CreateEventA(NULL, TRUE, FALSE, NULL); + service_ok(service_stop_event != NULL, "Could not create event: %u\n", GetLastError()); + if(!service_stop_event) + return; + + res = StartServiceCtrlDispatcherA(servtbl); + service_ok(res, "StartServiceCtrlDispatcher failed: %u\n", GetLastError()); + + /* Let service thread terminate */ + Sleep(50); + + CloseHandle(service_stop_event); + CloseHandle(pipe_handle); +} + +static DWORD WINAPI no_stop_handler(DWORD ctrl, DWORD event_type, void *event_data, void *context) +{ + SERVICE_STATUS status; + + status.dwServiceType = SERVICE_WIN32; + status.dwControlsAccepted = SERVICE_ACCEPT_STOP; + status.dwWin32ExitCode = 0; + status.dwServiceSpecificExitCode = 0; + status.dwCheckPoint = 0; + status.dwWaitHint = 0; + + switch(ctrl) + { + case SERVICE_CONTROL_STOP: + case SERVICE_CONTROL_SHUTDOWN: + service_event("STOP"); + status.dwCurrentState = SERVICE_STOPPED; + status.dwControlsAccepted = 0; + SetServiceStatus(service_handle, &status); + SetEvent(service_stop_event); + return NO_ERROR; + default: + status.dwCurrentState = SERVICE_RUNNING; + SetServiceStatus( service_handle, &status ); + return NO_ERROR; + } +} + +static void WINAPI no_stop_main(DWORD argc, char **argv) +{ + SERVICE_STATUS status; + BOOL res; + + service_ok(argc == 1, "argc = %d", argc); + if(argc) + service_ok(!strcmp(argv[0], service_name), "argv[0] = %s, expected %s", argv[0], service_name); + + service_handle = pRegisterServiceCtrlHandlerExA(service_name, no_stop_handler, NULL); + service_ok(service_handle != NULL, "RegisterServiceCtrlHandlerEx failed: %u\n", GetLastError()); + if(!service_handle) + return; + + status.dwServiceType = SERVICE_WIN32; + status.dwCurrentState = SERVICE_RUNNING; + status.dwControlsAccepted = SERVICE_ACCEPT_STOP | SERVICE_ACCEPT_SHUTDOWN; + status.dwWin32ExitCode = 0; + status.dwServiceSpecificExitCode = 0; + status.dwCheckPoint = 0; + status.dwWaitHint = 10000; + res = SetServiceStatus(service_handle, &status); + service_ok(res, "SetServiceStatus(SERVICE_RUNNING) failed: %u", GetLastError()); + + service_event("RUNNING"); +} + +/* Test process global variables */ +static SC_HANDLE scm_handle; + +static char current_event[32]; +static HANDLE event_handle = INVALID_HANDLE_VALUE; +static CRITICAL_SECTION event_cs; + +static SC_HANDLE register_service(const char *test_name) +{ + char service_cmd[MAX_PATH+150], *ptr; + SC_HANDLE service; + + ptr = service_cmd + GetModuleFileNameA(NULL, service_cmd, MAX_PATH); + + /* If the file doesn't exist, assume we're using built-in exe and append .so to the path */ + if(GetFileAttributesA(service_cmd) == INVALID_FILE_ATTRIBUTES) { + strcpy(ptr, ".so"); + ptr += 3; + } + + strcpy(ptr, " service "); + ptr += strlen(ptr); + sprintf(ptr, "%s ", test_name); + ptr += strlen(ptr); + strcpy(ptr, service_name); + + trace("service_cmd "%s"\n", service_cmd); + + service = CreateServiceA(scm_handle, service_name, service_name, GENERIC_ALL, + SERVICE_WIN32_OWN_PROCESS, SERVICE_DEMAND_START, SERVICE_ERROR_IGNORE, + service_cmd, NULL, NULL, NULL, NULL, NULL); + if(!service && GetLastError() == ERROR_ACCESS_DENIED) { + skip("Not enough access right to create service\n"); + return NULL; + } + + ok(service != NULL, "CreateService failed: %u\n", GetLastError()); + return service; +} + +static void expect_event(const char *event_name) +{ + char evt[32]; + DWORD res; + + trace("waiting for %s\n", event_name); + + res = WaitForSingleObject(event_handle, 30000); + ok(res == WAIT_OBJECT_0, "WaitForSingleObject failed: %u\n", res); + if(res != WAIT_OBJECT_0) + return; + + EnterCriticalSection(&event_cs); + strcpy(evt, current_event); + *current_event = 0; + LeaveCriticalSection(&event_cs); + + ok(!strcmp(evt, event_name), "Unexpected event: %s, expected %s\n", evt, event_name); +} + +static DWORD WINAPI pipe_thread(void *arg) +{ + char buf[257], *ptr; + DWORD read; + BOOL res; + + res = ConnectNamedPipe(pipe_handle, NULL); + ok(res || GetLastError() == ERROR_PIPE_CONNECTED, "ConnectNamedPipe failed: %u\n", GetLastError()); + + while(1) { + res = ReadFile(pipe_handle, buf, sizeof(buf), &read, NULL); + if(!res) { + ok(GetLastError() == ERROR_BROKEN_PIPE || GetLastError() == ERROR_INVALID_HANDLE, + "ReadFile failed: %u\n", GetLastError()); + break; + } + + for(ptr = buf; ptr < buf+read; ptr += strlen(ptr)+1) { + if(!strncmp(ptr, "TRACE:", 6)) { + trace("service trace: %s\n", ptr+6); + }else if(!strncmp(ptr, "OK:", 3)) { + ok(1, "service: %s\n", ptr+3); + }else if(!strncmp(ptr, "FAIL:", 5)) { + ok(0, "service: %s\n", ptr+5); + }else if(!strncmp(ptr, "EVENT:", 6)) { + trace("service event: %s\n", ptr+6); + EnterCriticalSection(&event_cs); + ok(!current_event[0], "event %s still queued\n", current_event); + strcpy(current_event, ptr+6); + LeaveCriticalSection(&event_cs); + SetEvent(event_handle); + }else { + ok(0, "malformed service message: %s\n", ptr); + } + } + } + + DisconnectNamedPipe(pipe_handle); + trace("pipe disconnected\n"); + return 0; +} + +static void test_service(void) +{ + SC_HANDLE service_handle = register_service("simple_service"); + SERVICE_STATUS status; + BOOL res; + + if(!service_handle) + return; + + trace("starting...\n"); + res = StartServiceA(service_handle, 0, NULL); + ok(res, "StartService failed: %u\n", GetLastError()); + if(!res) { + DeleteService(service_handle); + return; + } + expect_event("RUNNING"); + + res = QueryServiceStatus(service_handle, &status); + ok(res, "QueryServiceStatus failed: %d\n", GetLastError()); + todo_wine ok(status.dwServiceType == SERVICE_WIN32_OWN_PROCESS, "status.dwServiceType = %x\n", status.dwServiceType); + ok(status.dwCurrentState == SERVICE_RUNNING, "status.dwCurrentState = %x\n", status.dwCurrentState); + ok(status.dwControlsAccepted == (SERVICE_ACCEPT_STOP | SERVICE_ACCEPT_SHUTDOWN), + "status.dwControlsAccepted = %x\n", status.dwControlsAccepted); + ok(status.dwWin32ExitCode == 0, "status.dwExitCode = %d\n", status.dwWin32ExitCode); + ok(status.dwServiceSpecificExitCode == 0, "status.dwServiceSpecificExitCode = %d\n", + status.dwServiceSpecificExitCode); + ok(status.dwCheckPoint == 0, "status.dwCheckPoint = %d\n", status.dwCheckPoint); + todo_wine ok(status.dwWaitHint == 0, "status.dwWaitHint = %d\n", status.dwWaitHint); + + res = ControlService(service_handle, SERVICE_CONTROL_STOP, &status); + ok(res, "ControlService failed: %u\n", GetLastError()); + expect_event("STOP"); + + res = DeleteService(service_handle); + ok(res, "DeleteService failed: %u\n", GetLastError()); + + CloseServiceHandle(service_handle); +} + +static inline void test_no_stop(void) +{ + SC_HANDLE service_handle = register_service("no_stop"); + SERVICE_STATUS status; + BOOL res; + + if(!service_handle) + return; + + trace("starting...\n"); + res = StartServiceA(service_handle, 0, NULL); + ok(res, "StartService failed: %u\n", GetLastError()); + if(!res) { + DeleteService(service_handle); + return; + } + expect_event("RUNNING"); + + /* Let service thread terminate */ + Sleep(1000); + + res = QueryServiceStatus(service_handle, &status); + ok(res, "QueryServiceStatus failed: %d\n", GetLastError()); + todo_wine ok(status.dwServiceType == SERVICE_WIN32_OWN_PROCESS, "status.dwServiceType = %x\n", status.dwServiceType); + ok(status.dwCurrentState == SERVICE_RUNNING, "status.dwCurrentState = %x\n", status.dwCurrentState); + ok(status.dwControlsAccepted == (SERVICE_ACCEPT_STOP | SERVICE_ACCEPT_SHUTDOWN), + "status.dwControlsAccepted = %x\n", status.dwControlsAccepted); + ok(status.dwWin32ExitCode == 0, "status.dwExitCode = %d\n", status.dwWin32ExitCode); + ok(status.dwServiceSpecificExitCode == 0, "status.dwServiceSpecificExitCode = %d\n", + status.dwServiceSpecificExitCode); + ok(status.dwCheckPoint == 0, "status.dwCheckPoint = %d\n", status.dwCheckPoint); + todo_wine ok(status.dwWaitHint == 0, "status.dwWaitHint = %d\n", status.dwWaitHint); + + res = ControlService(service_handle, SERVICE_CONTROL_STOP, &status); + ok(res, "ControlService failed: %u\n", GetLastError()); + expect_event("STOP"); + + res = QueryServiceStatus(service_handle, &status); + ok(res, "QueryServiceStatus failed: %d\n", GetLastError()); + todo_wine ok(status.dwServiceType == SERVICE_WIN32_OWN_PROCESS, "status.dwServiceType = %x\n", status.dwServiceType); + ok(status.dwCurrentState==SERVICE_STOPPED || status.dwCurrentState==SERVICE_STOP_PENDING, + "status.dwCurrentState = %x\n", status.dwCurrentState); + ok(status.dwControlsAccepted == 0, "status.dwControlsAccepted = %x\n", status.dwControlsAccepted); + ok(status.dwWin32ExitCode == 0, "status.dwExitCode = %d\n", status.dwWin32ExitCode); + ok(status.dwServiceSpecificExitCode == 0, "status.dwServiceSpecificExitCode = %d\n", + status.dwServiceSpecificExitCode); + ok(status.dwCheckPoint == 0, "status.dwCheckPoint = %d\n", status.dwCheckPoint); + ok(status.dwWaitHint == 0, "status.dwWaitHint = %d\n", status.dwWaitHint); + + res = DeleteService(service_handle); + ok(res, "DeleteService failed: %u\n", GetLastError()); + + res = QueryServiceStatus(service_handle, &status); + ok(res, "QueryServiceStatus failed: %d\n", GetLastError()); + todo_wine ok(status.dwServiceType == SERVICE_WIN32_OWN_PROCESS, "status.dwServiceType = %x\n", status.dwServiceType); + ok(status.dwCurrentState==SERVICE_STOPPED || status.dwCurrentState==SERVICE_STOP_PENDING, + "status.dwCurrentState = %x\n", status.dwCurrentState); + ok(status.dwControlsAccepted == 0, "status.dwControlsAccepted = %x\n", status.dwControlsAccepted); + ok(status.dwWin32ExitCode == 0, "status.dwExitCode = %d\n", status.dwWin32ExitCode); + ok(status.dwServiceSpecificExitCode == 0, "status.dwServiceSpecificExitCode = %d\n", + status.dwServiceSpecificExitCode); + ok(status.dwCheckPoint == 0, "status.dwCheckPoint = %d\n", status.dwCheckPoint); + ok(status.dwWaitHint == 0, "status.dwWaitHint = %d\n", status.dwWaitHint); + + CloseServiceHandle(service_handle); + + res = QueryServiceStatus(service_handle, &status); + ok(!res, "QueryServiceStatus should have failed\n"); + ok(GetLastError() == ERROR_INVALID_HANDLE, "GetLastError = %d\n", GetLastError()); +} + +static void test_runner(void (*p_run_test)(void)) +{ + HANDLE thread; + + sprintf(service_name, "WineTestService%d", GetTickCount()); + trace("service_name: %s\n", service_name); + sprintf(named_pipe_name, "\\.\pipe\%s_pipe", service_name); + + pipe_handle = CreateNamedPipeA(named_pipe_name, PIPE_ACCESS_INBOUND, + PIPE_TYPE_BYTE|PIPE_READMODE_BYTE|PIPE_WAIT, 10, 2048, 2048, 10000, NULL); + ok(pipe_handle != INVALID_HANDLE_VALUE, "CreateNamedPipe failed: %u\n", GetLastError()); + if(pipe_handle == INVALID_HANDLE_VALUE) + return; + + InitializeCriticalSection(&event_cs); + event_handle = CreateEventA(NULL, FALSE, FALSE, NULL); + ok(event_handle != INVALID_HANDLE_VALUE, "CreateEvent failed: %u\n", GetLastError()); + if(event_handle == INVALID_HANDLE_VALUE) + return; + + thread = CreateThread(NULL, 0, pipe_thread, NULL, 0, NULL); + ok(thread != NULL, "CreateThread failed: %u\n", GetLastError()); + if(!thread) + return; + + p_run_test(); + + WaitForSingleObject(thread, INFINITE); + CloseHandle(event_handle); + CloseHandle(pipe_handle); +} + +START_TEST(service) +{ + char **argv; + int argc; + + pRegisterServiceCtrlHandlerExA = (void*)GetProcAddress(GetModuleHandleA("advapi32.dll"), "RegisterServiceCtrlHandlerExA"); + if(!pRegisterServiceCtrlHandlerExA) { + win_skip("RegisterServiceCtrlHandlerExA not available, skipping tests\n"); + return; + } + + argc = winetest_get_mainargs(&argv); + + scm_handle = OpenSCManagerA(NULL, NULL, GENERIC_ALL); + ok(scm_handle != NULL, "OpenSCManager failed: %u\n", GetLastError()); + + if(argc < 3) { + test_runner(test_service); + test_runner(test_no_stop); + }else { + strcpy(service_name, argv[3]); + sprintf(named_pipe_name, "\\.\pipe\%s_pipe", service_name); + + if(!strcmp(argv[2], "simple_service")) + service_process(service_main); + else if(!strcmp(argv[2], "no_stop")) + service_process(no_stop_main); + } + + CloseServiceHandle(scm_handle); +}
Propchange: trunk/rostests/winetests/services/service.c ------------------------------------------------------------------------------ svn:eol-style = native
Added: trunk/rostests/winetests/services/testlist.c URL: http://svn.reactos.org/svn/reactos/trunk/rostests/winetests/services/testlis... ============================================================================== --- trunk/rostests/winetests/services/testlist.c (added) +++ trunk/rostests/winetests/services/testlist.c [iso-8859-1] Sun Dec 9 13:06:56 2012 @@ -1,0 +1,15 @@ +/* Automatically generated file; DO NOT EDIT!! */ + +#define WIN32_LEAN_AND_MEAN +#include <windows.h> + +#define STANDALONE +#include "wine/test.h" + +extern void func_service(void); + +const struct test winetest_testlist[] = +{ + { "service", func_service }, + { 0, 0 } +};
Propchange: trunk/rostests/winetests/services/testlist.c ------------------------------------------------------------------------------ svn:eol-style = native