[SERVICES_WINETEST]: Import from Wine 1.5.19.
authorAmine Khaldi <amine.khaldi@reactos.org>
Sun, 9 Dec 2012 13:06:56 +0000 (13:06 +0000)
committerAmine Khaldi <amine.khaldi@reactos.org>
Sun, 9 Dec 2012 13:06:56 +0000 (13:06 +0000)
svn path=/trunk/; revision=57840

rostests/winetests/CMakeLists.txt
rostests/winetests/services/CMakeLists.txt [new file with mode: 0644]
rostests/winetests/services/service.c [new file with mode: 0644]
rostests/winetests/services/testlist.c [new file with mode: 0644]

index cae7c9c..0daeb5c 100644 (file)
@@ -71,6 +71,7 @@ add_subdirectory(rsaenh)
 add_subdirectory(schannel)
 add_subdirectory(secur32)
 add_subdirectory(serialui)
+add_subdirectory(services)
 add_subdirectory(setupapi)
 add_subdirectory(shdocvw)
 add_subdirectory(shell32)
diff --git a/rostests/winetests/services/CMakeLists.txt b/rostests/winetests/services/CMakeLists.txt
new file mode 100644 (file)
index 0000000..3cbd46b
--- /dev/null
@@ -0,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)
diff --git a/rostests/winetests/services/service.c b/rostests/winetests/services/service.c
new file mode 100644 (file)
index 0000000..99d28eb
--- /dev/null
@@ -0,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);
+}
diff --git a/rostests/winetests/services/testlist.c b/rostests/winetests/services/testlist.c
new file mode 100644 (file)
index 0000000..8c9c966
--- /dev/null
@@ -0,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 }
+};