mirror of
https://github.com/reactos/reactos.git
synced 2025-05-23 02:56:09 +00:00
[ADVAPI32_APITEST]: Add a small helper lib 'svchlp' for common routines for test-services embedded in api tests. Taken & heavily adapted from Jacek Caban's services_service test and Thomas Faber's ServiceArgs.c (the latter will be able to use 'svchlp' when it'll be ready).
CORE-12414 svn path=/trunk/; revision=73430
This commit is contained in:
parent
ab777da1ae
commit
8e18f1fbd9
3 changed files with 392 additions and 0 deletions
|
@ -14,6 +14,7 @@ list(APPEND SOURCE
|
||||||
RtlEncryptMemory.c
|
RtlEncryptMemory.c
|
||||||
SaferIdentifyLevel.c
|
SaferIdentifyLevel.c
|
||||||
ServiceArgs.c
|
ServiceArgs.c
|
||||||
|
svchlp.c
|
||||||
testlist.c)
|
testlist.c)
|
||||||
|
|
||||||
add_executable(advapi32_apitest ${SOURCE})
|
add_executable(advapi32_apitest ${SOURCE})
|
||||||
|
|
318
rostests/apitests/advapi32/svchlp.c
Normal file
318
rostests/apitests/advapi32/svchlp.c
Normal file
|
@ -0,0 +1,318 @@
|
||||||
|
/*
|
||||||
|
* PROJECT: ReactOS api tests
|
||||||
|
* LICENSE: LGPLv2.1+ - See COPYING.LIB in the top level directory
|
||||||
|
* PURPOSE: Support helpers for embedded services inside api tests.
|
||||||
|
* PROGRAMMERS: Jacek Caban for CodeWeavers
|
||||||
|
* Thomas Faber <thomas.faber@reactos.org>
|
||||||
|
* Hermes Belusca-Maito
|
||||||
|
*
|
||||||
|
* NOTE: Room for improvements:
|
||||||
|
* - One test_runner managing 1 pipe for 1 service process that is shared
|
||||||
|
* by multiple services of type SERVICE_WIN32_SHARE_PROCESS.
|
||||||
|
* - Find a way to elegantly determine the registered service name inside
|
||||||
|
* the service process, without really passing it
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <apitest.h>
|
||||||
|
#include <winnls.h>
|
||||||
|
#include <winsvc.h>
|
||||||
|
#include <strsafe.h>
|
||||||
|
|
||||||
|
static HANDLE hClientPipe = INVALID_HANDLE_VALUE;
|
||||||
|
static WCHAR named_pipe_name[100]; // Shared: FIXME!
|
||||||
|
|
||||||
|
static CHAR service_nameA[100];
|
||||||
|
static WCHAR service_nameW[100];
|
||||||
|
|
||||||
|
|
||||||
|
/********** S E R V I C E ( C L I E N T ) M O D U L E S I D E *********/
|
||||||
|
|
||||||
|
void send_msg(const char *type, const char *msg)
|
||||||
|
{
|
||||||
|
DWORD written = 0;
|
||||||
|
char buf[512];
|
||||||
|
|
||||||
|
StringCbPrintfA(buf, sizeof(buf), "%s:%s", type, msg);
|
||||||
|
WriteFile(hClientPipe, buf, strlen(buf)+1, &written, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
void service_trace(const char *msg, ...)
|
||||||
|
{
|
||||||
|
va_list valist;
|
||||||
|
char buf[512];
|
||||||
|
|
||||||
|
va_start(valist, msg);
|
||||||
|
StringCbVPrintfA(buf, sizeof(buf), msg, valist);
|
||||||
|
va_end(valist);
|
||||||
|
|
||||||
|
send_msg("TRACE", buf);
|
||||||
|
}
|
||||||
|
|
||||||
|
void service_ok(int cnd, const char *msg, ...)
|
||||||
|
{
|
||||||
|
va_list valist;
|
||||||
|
char buf[512];
|
||||||
|
|
||||||
|
va_start(valist, msg);
|
||||||
|
StringCbVPrintfA(buf, sizeof(buf), msg, valist);
|
||||||
|
va_end(valist);
|
||||||
|
|
||||||
|
send_msg(cnd ? "OK" : "FAIL", buf);
|
||||||
|
}
|
||||||
|
|
||||||
|
void service_process(BOOL (*start_service)(PCSTR, PCWSTR), int argc, char** argv)
|
||||||
|
{
|
||||||
|
BOOL res;
|
||||||
|
|
||||||
|
StringCbCopyA(service_nameA, sizeof(service_nameA), argv[2]);
|
||||||
|
MultiByteToWideChar(CP_ACP, 0, service_nameA, -1, service_nameW, _countof(service_nameW));
|
||||||
|
StringCbPrintfW(named_pipe_name, sizeof(named_pipe_name), L"\\\\.\\pipe\\%ls_pipe", service_nameW);
|
||||||
|
|
||||||
|
res = WaitNamedPipeW(named_pipe_name, NMPWAIT_USE_DEFAULT_WAIT);
|
||||||
|
if (!res)
|
||||||
|
return;
|
||||||
|
|
||||||
|
hClientPipe = CreateFileW(named_pipe_name, GENERIC_WRITE, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
|
||||||
|
if (hClientPipe == INVALID_HANDLE_VALUE)
|
||||||
|
return;
|
||||||
|
|
||||||
|
service_trace("Service process starting...\n");
|
||||||
|
res = start_service(service_nameA, service_nameW);
|
||||||
|
service_trace("Service process stopped.\n");
|
||||||
|
|
||||||
|
CloseHandle(hClientPipe);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*********** T E S T E R ( S E R V E R ) M O D U L E S I D E **********/
|
||||||
|
|
||||||
|
SC_HANDLE register_service_exA(
|
||||||
|
SC_HANDLE scm_handle,
|
||||||
|
PCSTR test_name,
|
||||||
|
PCSTR service_name, // LPCSTR lpServiceName,
|
||||||
|
PCSTR extra_args OPTIONAL,
|
||||||
|
DWORD dwDesiredAccess,
|
||||||
|
DWORD dwServiceType,
|
||||||
|
DWORD dwStartType,
|
||||||
|
DWORD dwErrorControl,
|
||||||
|
LPCSTR lpLoadOrderGroup OPTIONAL,
|
||||||
|
LPDWORD lpdwTagId OPTIONAL,
|
||||||
|
LPCSTR lpDependencies OPTIONAL,
|
||||||
|
LPCSTR lpServiceStartName OPTIONAL,
|
||||||
|
LPCSTR lpPassword OPTIONAL)
|
||||||
|
{
|
||||||
|
SC_HANDLE service;
|
||||||
|
CHAR service_cmd[MAX_PATH+150];
|
||||||
|
|
||||||
|
/* Retrieve our full path */
|
||||||
|
if (!GetModuleFileNameA(NULL, service_cmd, MAX_PATH))
|
||||||
|
{
|
||||||
|
skip("GetModuleFileNameW failed with error %lu!\n", GetLastError());
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Build up our custom command line. The first parameter is the test name,
|
||||||
|
* the second parameter is the flag used to decide whether we should start
|
||||||
|
* as a service.
|
||||||
|
*/
|
||||||
|
StringCbCatA(service_cmd, sizeof(service_cmd), " ");
|
||||||
|
StringCbCatA(service_cmd, sizeof(service_cmd), test_name);
|
||||||
|
StringCbCatA(service_cmd, sizeof(service_cmd), " ");
|
||||||
|
StringCbCatA(service_cmd, sizeof(service_cmd), service_name);
|
||||||
|
if (extra_args)
|
||||||
|
{
|
||||||
|
StringCbCatA(service_cmd, sizeof(service_cmd), " ");
|
||||||
|
StringCbCatA(service_cmd, sizeof(service_cmd), extra_args);
|
||||||
|
}
|
||||||
|
|
||||||
|
trace("service_cmd \"%s\"\n", service_cmd);
|
||||||
|
|
||||||
|
service = CreateServiceA(scm_handle, service_name, service_name,
|
||||||
|
dwDesiredAccess, dwServiceType, dwStartType, dwErrorControl,
|
||||||
|
service_cmd, lpLoadOrderGroup, lpdwTagId, lpDependencies,
|
||||||
|
lpServiceStartName, lpPassword);
|
||||||
|
if (!service && GetLastError() == ERROR_ACCESS_DENIED)
|
||||||
|
{
|
||||||
|
skip("Not enough access right to create service.\n");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
ok(service != NULL, "CreateService failed: %lu\n", GetLastError());
|
||||||
|
return service;
|
||||||
|
}
|
||||||
|
|
||||||
|
SC_HANDLE register_service_exW(
|
||||||
|
SC_HANDLE scm_handle,
|
||||||
|
PCWSTR test_name,
|
||||||
|
PCWSTR service_name, // LPCWSTR lpServiceName,
|
||||||
|
PCWSTR extra_args OPTIONAL,
|
||||||
|
DWORD dwDesiredAccess,
|
||||||
|
DWORD dwServiceType,
|
||||||
|
DWORD dwStartType,
|
||||||
|
DWORD dwErrorControl,
|
||||||
|
LPCWSTR lpLoadOrderGroup OPTIONAL,
|
||||||
|
LPDWORD lpdwTagId OPTIONAL,
|
||||||
|
LPCWSTR lpDependencies OPTIONAL,
|
||||||
|
LPCWSTR lpServiceStartName OPTIONAL,
|
||||||
|
LPCWSTR lpPassword OPTIONAL)
|
||||||
|
{
|
||||||
|
SC_HANDLE service;
|
||||||
|
WCHAR service_cmd[MAX_PATH+150];
|
||||||
|
|
||||||
|
/* Retrieve our full path */
|
||||||
|
if (!GetModuleFileNameW(NULL, service_cmd, MAX_PATH))
|
||||||
|
{
|
||||||
|
skip("GetModuleFileNameW failed with error %lu!\n", GetLastError());
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Build up our custom command line. The first parameter is the test name,
|
||||||
|
* the second parameter is the flag used to decide whether we should start
|
||||||
|
* as a service.
|
||||||
|
*/
|
||||||
|
StringCbCatW(service_cmd, sizeof(service_cmd), L" ");
|
||||||
|
StringCbCatW(service_cmd, sizeof(service_cmd), test_name);
|
||||||
|
StringCbCatW(service_cmd, sizeof(service_cmd), L" ");
|
||||||
|
StringCbCatW(service_cmd, sizeof(service_cmd), service_name);
|
||||||
|
if (extra_args)
|
||||||
|
{
|
||||||
|
StringCbCatW(service_cmd, sizeof(service_cmd), L" ");
|
||||||
|
StringCbCatW(service_cmd, sizeof(service_cmd), extra_args);
|
||||||
|
}
|
||||||
|
|
||||||
|
trace("service_cmd \"%ls\"\n", service_cmd);
|
||||||
|
|
||||||
|
service = CreateServiceW(scm_handle, service_name, service_name,
|
||||||
|
dwDesiredAccess, dwServiceType, dwStartType, dwErrorControl,
|
||||||
|
service_cmd, lpLoadOrderGroup, lpdwTagId, lpDependencies,
|
||||||
|
lpServiceStartName, lpPassword);
|
||||||
|
if (!service && GetLastError() == ERROR_ACCESS_DENIED)
|
||||||
|
{
|
||||||
|
skip("Not enough access right to create service.\n");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
ok(service != NULL, "CreateService failed: %lu\n", GetLastError());
|
||||||
|
return service;
|
||||||
|
}
|
||||||
|
|
||||||
|
SC_HANDLE register_serviceA(
|
||||||
|
SC_HANDLE scm_handle,
|
||||||
|
PCSTR test_name,
|
||||||
|
PCSTR service_name,
|
||||||
|
PCSTR extra_args OPTIONAL)
|
||||||
|
{
|
||||||
|
return register_service_exA(scm_handle, test_name, service_name, extra_args,
|
||||||
|
SERVICE_ALL_ACCESS,
|
||||||
|
SERVICE_WIN32_OWN_PROCESS,
|
||||||
|
SERVICE_DEMAND_START,
|
||||||
|
SERVICE_ERROR_IGNORE,
|
||||||
|
NULL, NULL, NULL, NULL, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
SC_HANDLE register_serviceW(
|
||||||
|
SC_HANDLE scm_handle,
|
||||||
|
PCWSTR test_name,
|
||||||
|
PCWSTR service_name,
|
||||||
|
PCWSTR extra_args OPTIONAL)
|
||||||
|
{
|
||||||
|
return register_service_exW(scm_handle, test_name, service_name, extra_args,
|
||||||
|
SERVICE_ALL_ACCESS,
|
||||||
|
SERVICE_WIN32_OWN_PROCESS,
|
||||||
|
SERVICE_DEMAND_START,
|
||||||
|
SERVICE_ERROR_IGNORE,
|
||||||
|
NULL, NULL, NULL, NULL, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
static DWORD WINAPI pipe_thread(void *param)
|
||||||
|
{
|
||||||
|
HANDLE hServerPipe = (HANDLE)param;
|
||||||
|
DWORD read;
|
||||||
|
BOOL res;
|
||||||
|
char buf[512];
|
||||||
|
|
||||||
|
// printf("pipe_thread -- ConnectNamedPipe...\n");
|
||||||
|
res = ConnectNamedPipe(hServerPipe, NULL);
|
||||||
|
ok(res || GetLastError() == ERROR_PIPE_CONNECTED, "ConnectNamedPipe failed: %lu\n", GetLastError());
|
||||||
|
// printf("pipe_thread -- ConnectNamedPipe ok\n");
|
||||||
|
|
||||||
|
while (1)
|
||||||
|
{
|
||||||
|
res = ReadFile(hServerPipe, buf, sizeof(buf), &read, NULL);
|
||||||
|
if (!res)
|
||||||
|
{
|
||||||
|
ok(GetLastError() == ERROR_BROKEN_PIPE || GetLastError() == ERROR_INVALID_HANDLE,
|
||||||
|
"ReadFile failed: %lu\n", GetLastError());
|
||||||
|
// printf("pipe_thread -- break loop\n");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!strncmp(buf, "TRACE:", 6))
|
||||||
|
{
|
||||||
|
trace("service trace: %s", buf+6);
|
||||||
|
}
|
||||||
|
else if (!strncmp(buf, "OK:", 3))
|
||||||
|
{
|
||||||
|
ok(1, "service: %s", buf+3);
|
||||||
|
}
|
||||||
|
else if (!strncmp(buf, "FAIL:", 5))
|
||||||
|
{
|
||||||
|
ok(0, "service: %s", buf+5);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
ok(0, "malformed service message: %s\n", buf);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// printf("pipe_thread -- DisconnectNamedPipe\n");
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Flush the pipe to allow the client to read
|
||||||
|
* the pipe's contents before disconnecting.
|
||||||
|
*/
|
||||||
|
FlushFileBuffers(hServerPipe);
|
||||||
|
|
||||||
|
DisconnectNamedPipe(hServerPipe);
|
||||||
|
trace("pipe disconnected\n");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void test_runner(void (*run_test)(PCSTR, PCWSTR, void*), void *param)
|
||||||
|
{
|
||||||
|
HANDLE hServerPipe = INVALID_HANDLE_VALUE;
|
||||||
|
HANDLE hThread;
|
||||||
|
|
||||||
|
StringCbPrintfW(service_nameW, sizeof(service_nameW), L"WineTestService%lu", GetTickCount());
|
||||||
|
WideCharToMultiByte(CP_ACP, 0, service_nameW, -1, service_nameA, _countof(service_nameA), NULL, NULL);
|
||||||
|
//trace("service_name: %ls\n", service_nameW);
|
||||||
|
StringCbPrintfW(named_pipe_name, sizeof(named_pipe_name), L"\\\\.\\pipe\\%ls_pipe", service_nameW);
|
||||||
|
|
||||||
|
hServerPipe = CreateNamedPipeW(named_pipe_name, PIPE_ACCESS_INBOUND,
|
||||||
|
PIPE_TYPE_MESSAGE|PIPE_READMODE_MESSAGE|PIPE_WAIT, 10, 2048, 2048, 10000, NULL);
|
||||||
|
ok(hServerPipe != INVALID_HANDLE_VALUE, "CreateNamedPipe failed: %lu\n", GetLastError());
|
||||||
|
if (hServerPipe == INVALID_HANDLE_VALUE)
|
||||||
|
return;
|
||||||
|
|
||||||
|
hThread = CreateThread(NULL, 0, pipe_thread, (LPVOID)hServerPipe, 0, NULL);
|
||||||
|
ok(hThread != NULL, "CreateThread failed: %lu\n", GetLastError());
|
||||||
|
if (!hThread)
|
||||||
|
goto Quit;
|
||||||
|
|
||||||
|
run_test(service_nameA, service_nameW, param);
|
||||||
|
|
||||||
|
ok(WaitForSingleObject(hThread, 10000) == WAIT_OBJECT_0, "Timeout waiting for thread\n");
|
||||||
|
|
||||||
|
Quit:
|
||||||
|
if (hThread)
|
||||||
|
{
|
||||||
|
/* Be sure to kill the thread if it did not already terminate */
|
||||||
|
TerminateThread(hThread, 0);
|
||||||
|
CloseHandle(hThread);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (hServerPipe != INVALID_HANDLE_VALUE)
|
||||||
|
CloseHandle(hServerPipe);
|
||||||
|
}
|
73
rostests/apitests/advapi32/svchlp.h
Normal file
73
rostests/apitests/advapi32/svchlp.h
Normal file
|
@ -0,0 +1,73 @@
|
||||||
|
/*
|
||||||
|
* PROJECT: ReactOS api tests
|
||||||
|
* LICENSE: LGPLv2.1+ - See COPYING.LIB in the top level directory
|
||||||
|
* PURPOSE: Support helpers for embedded services inside api tests.
|
||||||
|
* PROGRAMMERS: Jacek Caban for CodeWeavers
|
||||||
|
* Thomas Faber <thomas.faber@reactos.org>
|
||||||
|
* Hermes Belusca-Maito
|
||||||
|
*/
|
||||||
|
|
||||||
|
// #include <apitest.h>
|
||||||
|
|
||||||
|
|
||||||
|
/********** S E R V I C E ( C L I E N T ) M O D U L E S I D E *********/
|
||||||
|
|
||||||
|
void send_msg(const char *type, const char *msg);
|
||||||
|
void service_trace(const char *msg, ...);
|
||||||
|
void service_ok(int cnd, const char *msg, ...);
|
||||||
|
void service_process(BOOL (*start_service)(PCSTR, PCWSTR), int argc, char** argv);
|
||||||
|
|
||||||
|
|
||||||
|
/*********** T E S T E R ( S E R V E R ) M O D U L E S I D E **********/
|
||||||
|
|
||||||
|
SC_HANDLE register_service_exA(
|
||||||
|
SC_HANDLE scm_handle,
|
||||||
|
PCSTR test_name,
|
||||||
|
PCSTR service_name, // LPCSTR lpServiceName,
|
||||||
|
PCSTR extra_args OPTIONAL,
|
||||||
|
DWORD dwDesiredAccess,
|
||||||
|
DWORD dwServiceType,
|
||||||
|
DWORD dwStartType,
|
||||||
|
DWORD dwErrorControl,
|
||||||
|
LPCSTR lpLoadOrderGroup OPTIONAL,
|
||||||
|
LPDWORD lpdwTagId OPTIONAL,
|
||||||
|
LPCSTR lpDependencies OPTIONAL,
|
||||||
|
LPCSTR lpServiceStartName OPTIONAL,
|
||||||
|
LPCSTR lpPassword OPTIONAL);
|
||||||
|
|
||||||
|
SC_HANDLE register_service_exW(
|
||||||
|
SC_HANDLE scm_handle,
|
||||||
|
PCWSTR test_name,
|
||||||
|
PCWSTR service_name, // LPCWSTR lpServiceName,
|
||||||
|
PCWSTR extra_args OPTIONAL,
|
||||||
|
DWORD dwDesiredAccess,
|
||||||
|
DWORD dwServiceType,
|
||||||
|
DWORD dwStartType,
|
||||||
|
DWORD dwErrorControl,
|
||||||
|
LPCWSTR lpLoadOrderGroup OPTIONAL,
|
||||||
|
LPDWORD lpdwTagId OPTIONAL,
|
||||||
|
LPCWSTR lpDependencies OPTIONAL,
|
||||||
|
LPCWSTR lpServiceStartName OPTIONAL,
|
||||||
|
LPCWSTR lpPassword OPTIONAL);
|
||||||
|
|
||||||
|
SC_HANDLE register_serviceA(
|
||||||
|
SC_HANDLE scm_handle,
|
||||||
|
PCSTR test_name,
|
||||||
|
PCSTR service_name,
|
||||||
|
PCSTR extra_args OPTIONAL);
|
||||||
|
|
||||||
|
SC_HANDLE register_serviceW(
|
||||||
|
SC_HANDLE scm_handle,
|
||||||
|
PCWSTR test_name,
|
||||||
|
PCWSTR service_name,
|
||||||
|
PCWSTR extra_args OPTIONAL);
|
||||||
|
|
||||||
|
#ifdef UNICODE
|
||||||
|
#define register_service_ex register_service_exW
|
||||||
|
#define register_service register_serviceW
|
||||||
|
#else
|
||||||
|
#define register_service_ex register_service_exA
|
||||||
|
#define register_service register_serviceA
|
||||||
|
#endif
|
||||||
|
|
||||||
|
void test_runner(void (*run_test)(PCSTR, PCWSTR, void*), void *param);
|
Loading…
Reference in a new issue