2015-06-08 17:15:44 +00:00
/*
* PROJECT : ReactOS Local Spooler API Tests
2017-09-29 18:33:04 +00:00
* LICENSE : GPL - 2.0 + ( https : //spdx.org/licenses/GPL-2.0+)
2015-06-08 17:15:44 +00:00
* PURPOSE : Test list
2017-09-29 18:33:04 +00:00
* COPYRIGHT : Copyright 2015 - 2016 Colin Finck ( colin @ reactos . org )
2015-06-08 17:15:44 +00:00
*/
/*
* The original localspl . dll from Windows Server 2003 is not easily testable .
* It relies on a proper initialization inside spoolsv . exe , so we can ' t just load it in an API - Test as usual .
* See https : //www.reactos.org/pipermail/ros-dev/2015-June/017395.html for more information.
2021-09-13 01:33:14 +00:00
*
2015-06-08 17:15:44 +00:00
* To make testing possible anyway , this program basically does four things :
* - Injecting our testing code into spoolsv . exe .
* - Registering and running us as a service in the SYSTEM security context like spoolsv . exe , so that injection is possible at all .
* - Sending the test name and receiving the console output over named pipes .
* - Redirecting the received console output to stdout again , so it looks and feels like a standard API - Test .
*
* To simplify debugging of the injected code , it is entirely separated into a DLL file localspl_apitest . dll .
* What we actually inject is a LoadLibraryW call , so that the DLL is loaded gracefully without any hacks .
* Therefore , you can just attach your debugger to the spoolsv . exe process and set breakpoints on the localspl_apitest . dll code .
*/
# include <apitest.h>
# define WIN32_NO_STATUS
# include <stdio.h>
# include <stdlib.h>
# include <windef.h>
# include <winbase.h>
# include <wingdi.h>
# include <winreg.h>
# include <winsvc.h>
# include <winspool.h>
# include <winsplp.h>
# include "localspl_apitest.h"
static void
_RunRemoteTest ( const char * szTestName )
{
2015-06-09 13:22:25 +00:00
BOOL bSuccessful = FALSE ;
2015-06-08 17:15:44 +00:00
char szBuffer [ 1024 ] ;
DWORD cbRead ;
DWORD cbWritten ;
2015-06-09 13:22:25 +00:00
HANDLE hCommandPipe = INVALID_HANDLE_VALUE ;
2016-11-16 14:59:01 +00:00
HANDLE hFind = INVALID_HANDLE_VALUE ;
2015-06-09 13:22:25 +00:00
HANDLE hOutputPipe = INVALID_HANDLE_VALUE ;
2015-06-08 17:15:44 +00:00
PWSTR p ;
2015-06-09 13:22:25 +00:00
SC_HANDLE hSC = NULL ;
SC_HANDLE hService = NULL ;
SERVICE_STATUS ServiceStatus ;
2015-06-08 17:15:44 +00:00
WCHAR wszFilePath [ MAX_PATH + 20 ] ;
WIN32_FIND_DATAW fd ;
// Do a dummy EnumPrintersW call.
// This guarantees that the Spooler Service has actually loaded localspl.dll, which is a requirement for our injected DLL to work properly.
EnumPrintersW ( PRINTER_ENUM_LOCAL | PRINTER_ENUM_NAME , NULL , 1 , NULL , 0 , & cbRead , & cbWritten ) ;
// Get the full path to our EXE file.
if ( ! GetModuleFileNameW ( NULL , wszFilePath , MAX_PATH ) )
{
skip ( " GetModuleFileNameW failed with error %lu! \n " , GetLastError ( ) ) ;
2015-06-09 13:22:25 +00:00
goto Cleanup ;
2015-06-08 17:15:44 +00:00
}
// Replace the extension.
p = wcsrchr ( wszFilePath , L ' . ' ) ;
if ( ! p )
{
skip ( " File path has no file extension: %S \n " , wszFilePath ) ;
2015-06-09 13:22:25 +00:00
goto Cleanup ;
2015-06-08 17:15:44 +00:00
}
wcscpy ( p , L " .dll " ) ;
// Check if the corresponding DLL file exists.
2015-06-09 13:22:25 +00:00
hFind = FindFirstFileW ( wszFilePath , & fd ) ;
2016-11-16 14:59:01 +00:00
if ( hFind = = INVALID_HANDLE_VALUE )
2015-06-08 17:15:44 +00:00
{
skip ( " My DLL file \" %S \" does not exist! \n " , wszFilePath ) ;
2015-06-09 13:22:25 +00:00
goto Cleanup ;
2015-06-08 17:15:44 +00:00
}
// Change the extension back to .exe and add the parameters.
wcscpy ( p , L " .exe service dummy " ) ;
// Open a handle to the service manager.
hSC = OpenSCManagerW ( NULL , NULL , SC_MANAGER_ALL_ACCESS ) ;
if ( ! hSC )
{
skip ( " OpenSCManagerW failed with error %lu! \n " , GetLastError ( ) ) ;
2015-06-09 13:22:25 +00:00
goto Cleanup ;
2015-06-08 17:15:44 +00:00
}
2015-06-09 13:22:25 +00:00
// Ensure that the spooler service is running.
hService = OpenServiceW ( hSC , L " spooler " , SERVICE_QUERY_STATUS ) ;
if ( ! hService )
{
skip ( " OpenServiceW failed for the spooler service with error %lu! \n " , GetLastError ( ) ) ;
goto Cleanup ;
}
if ( ! QueryServiceStatus ( hService , & ServiceStatus ) )
{
skip ( " QueryServiceStatus failed for the spooler service with error %lu! \n " , GetLastError ( ) ) ;
goto Cleanup ;
}
if ( ServiceStatus . dwCurrentState ! = SERVICE_RUNNING )
{
skip ( " Spooler Service is not running! \n " ) ;
goto Cleanup ;
}
CloseServiceHandle ( hService ) ;
2015-06-08 17:15:44 +00:00
// Try to open the service if we've created it in a previous run.
hService = OpenServiceW ( hSC , SERVICE_NAME , SERVICE_ALL_ACCESS ) ;
if ( ! hService )
{
if ( GetLastError ( ) = = ERROR_SERVICE_DOES_NOT_EXIST )
{
// Create the service.
hService = CreateServiceW ( hSC , SERVICE_NAME , NULL , SERVICE_ALL_ACCESS , SERVICE_WIN32_OWN_PROCESS , SERVICE_DEMAND_START , SERVICE_ERROR_IGNORE , wszFilePath , NULL , NULL , NULL , NULL , NULL ) ;
if ( ! hService )
{
skip ( " CreateServiceW failed with error %lu! \n " , GetLastError ( ) ) ;
2015-06-09 13:22:25 +00:00
goto Cleanup ;
2015-06-08 17:15:44 +00:00
}
}
else
{
skip ( " OpenServiceW failed with error %lu! \n " , GetLastError ( ) ) ;
2015-06-09 13:22:25 +00:00
goto Cleanup ;
2015-06-08 17:15:44 +00:00
}
}
// Create pipes for the communication with the injected DLL.
hCommandPipe = CreateNamedPipeW ( COMMAND_PIPE_NAME , PIPE_ACCESS_OUTBOUND , PIPE_TYPE_MESSAGE | PIPE_READMODE_MESSAGE | PIPE_WAIT , 1 , 1024 , 1024 , 10000 , NULL ) ;
if ( hCommandPipe = = INVALID_HANDLE_VALUE )
{
skip ( " CreateNamedPipeW failed for the command pipe with error %lu! \n " , GetLastError ( ) ) ;
2015-06-09 13:22:25 +00:00
goto Cleanup ;
2015-06-08 17:15:44 +00:00
}
hOutputPipe = CreateNamedPipeW ( OUTPUT_PIPE_NAME , PIPE_ACCESS_INBOUND , PIPE_TYPE_BYTE | PIPE_READMODE_BYTE | PIPE_WAIT , 1 , 1024 , 1024 , 10000 , NULL ) ;
if ( hOutputPipe = = INVALID_HANDLE_VALUE )
{
skip ( " CreateNamedPipeW failed for the output pipe with error %lu! \n " , GetLastError ( ) ) ;
2015-06-09 13:22:25 +00:00
goto Cleanup ;
2015-06-08 17:15:44 +00:00
}
// Start the service with "service" and a dummy parameter (to distinguish it from a call by rosautotest to localspl_apitest:service)
if ( ! StartServiceW ( hService , 0 , NULL ) )
{
skip ( " StartServiceW failed with error %lu! \n " , GetLastError ( ) ) ;
2015-06-09 13:22:25 +00:00
goto Cleanup ;
2015-06-08 17:15:44 +00:00
}
// Wait till it has injected the DLL and the DLL expects its test name.
if ( ! ConnectNamedPipe ( hCommandPipe , NULL ) & & GetLastError ( ) ! = ERROR_PIPE_CONNECTED )
{
skip ( " ConnectNamedPipe failed for the command pipe with error %lu! \n " , GetLastError ( ) ) ;
2015-06-09 13:22:25 +00:00
goto Cleanup ;
2015-06-08 17:15:44 +00:00
}
// Send the test name.
2019-05-30 15:12:28 +00:00
if ( ! WriteFile ( hCommandPipe , szTestName , lstrlenA ( szTestName ) + sizeof ( char ) , & cbWritten , NULL ) )
2015-06-08 17:15:44 +00:00
{
skip ( " WriteFile failed with error %lu! \n " , GetLastError ( ) ) ;
2015-06-09 13:22:25 +00:00
goto Cleanup ;
2015-06-08 17:15:44 +00:00
}
// Now wait for the DLL to connect to the output pipe.
if ( ! ConnectNamedPipe ( hOutputPipe , NULL ) )
{
skip ( " ConnectNamedPipe failed for the output pipe with error %lu! \n " , GetLastError ( ) ) ;
2015-06-09 13:22:25 +00:00
goto Cleanup ;
2015-06-08 17:15:44 +00:00
}
// Get all testing messages from the pipe and output them on stdout.
while ( ReadFile ( hOutputPipe , szBuffer , sizeof ( szBuffer ) , & cbRead , NULL ) & & cbRead )
fwrite ( szBuffer , sizeof ( char ) , cbRead , stdout ) ;
2015-06-09 13:22:25 +00:00
bSuccessful = TRUE ;
Cleanup :
2016-11-16 14:59:01 +00:00
if ( hCommandPipe ! = INVALID_HANDLE_VALUE )
2015-06-09 13:22:25 +00:00
CloseHandle ( hCommandPipe ) ;
2016-11-16 14:59:01 +00:00
if ( hOutputPipe ! = INVALID_HANDLE_VALUE )
2015-06-09 13:22:25 +00:00
CloseHandle ( hOutputPipe ) ;
2016-11-16 14:59:01 +00:00
if ( hFind ! = INVALID_HANDLE_VALUE )
2015-06-09 13:22:25 +00:00
FindClose ( hFind ) ;
if ( hService )
CloseServiceHandle ( hService ) ;
if ( hSC )
CloseServiceHandle ( hSC ) ;
2015-06-08 17:15:44 +00:00
2015-06-09 13:22:25 +00:00
// If we successfully received test output through the named pipe, we have also output a summary line already.
// Prevent the testing framework from outputting another "0 tests executed" line in this case.
if ( bSuccessful )
ExitProcess ( 0 ) ;
2015-06-08 17:15:44 +00:00
}
START_TEST ( fpEnumPrinters )
{
2021-07-02 16:12:24 +00:00
# if defined(_M_AMD64)
if ( ! winetest_interactive )
{
skip ( " ROSTESTS-366: Skipping localspl_apitest:fpEnumPrinters because it hangs on Windows Server 2003 x64-Testbot. Set winetest_interactive to run it anyway. \n " ) ;
return ;
}
# endif
2015-06-08 17:15:44 +00:00
_RunRemoteTest ( " fpEnumPrinters " ) ;
}
2016-11-17 22:23:28 +00:00
START_TEST ( fpGetPrintProcessorDirectory )
{
2021-07-02 16:12:24 +00:00
# if defined(_M_AMD64)
if ( ! winetest_interactive )
{
skip ( " ROSTESTS-366: Skipping localspl_apitest:fpGetPrintProcessorDirectory because it hangs on Windows Server 2003 x64-Testbot. Set winetest_interactive to run it anyway. \n " ) ;
return ;
}
# endif
2016-11-17 22:23:28 +00:00
_RunRemoteTest ( " fpGetPrintProcessorDirectory " ) ;
}
2017-12-25 13:30:47 +00:00
START_TEST ( fpSetJob )
{
2021-07-02 16:12:24 +00:00
# if defined(_M_AMD64)
if ( ! winetest_interactive )
{
skip ( " ROSTESTS-366: Skipping localspl_apitest:fpSetJob because it hangs on Windows Server 2003 x64-Testbot. Set winetest_interactive to run it anyway. \n " ) ;
return ;
}
# endif
2017-12-25 13:30:47 +00:00
_RunRemoteTest ( " fpSetJob " ) ;
}