[KMTESTS]

- add simple loader application that can list/run tests from a driver via DeviceIoControl, and prints output to the console

svn path=/branches/GSoC_2011/KMTestSuite/; revision=52157
This commit is contained in:
Thomas Faber 2011-06-09 15:14:02 +00:00
parent 9e143d5955
commit 22216d2eb7
11 changed files with 442 additions and 3 deletions

View file

@ -3,6 +3,7 @@ add_subdirectory(apitests)
#add_subdirectory(dibtests)
add_subdirectory(drivers)
#add_subdirectory(dxtest)
add_subdirectory(kmtests)
#add_subdirectory(regtests)
add_subdirectory(rosautotest)
add_subdirectory(tests)

View file

@ -1,6 +1,9 @@
<?xml version="1.0"?>
<!DOCTYPE group SYSTEM "../../../tools/rbuild/project.dtd">
<group xmlns:xi="http://www.w3.org/2001/XInclude">
<directory name="apitests">
<xi:include href="apitests/directory.rbuild" />
</directory>
<directory name="drivers">
<xi:include href="drivers/directory.rbuild" />
</directory>
@ -10,6 +13,9 @@
<directory name="dxtest">
<xi:include href="dxtest/directory.rbuild" />
</directory>
<directory name="kmtests">
<xi:include href="kmtests/directory.rbuild" />
</directory>
<directory name="regtests">
<xi:include href="regtests/directory.rbuild" />
</directory>
@ -25,7 +31,4 @@
<directory name="winetests">
<xi:include href="winetests/directory.rbuild" />
</directory>
<directory name="apitests">
<xi:include href="apitests/directory.rbuild" />
</directory>
</group>

17
kmtests/CMakeLists.txt Normal file
View file

@ -0,0 +1,17 @@
include_directories(
include)
set_rc_compiler()
add_definitions(-D_DLL -D__USE_CRTIMP)
list(APPEND KMTEST_SOURCE
kmtest/kmtest.c
kmtest/service.c
kmtest/kmtest.rc)
add_executable(kmtest ${KMTEST_SOURCE})
set_module_type(kmtest win32cui)
add_importlibs(kmtest advapi32 msvcrt kernel32)
add_cd_file(TARGET kmtest DESTINATION reactos/bin FOR all)

8
kmtests/directory.rbuild Normal file
View file

@ -0,0 +1,8 @@
<?xml version="1.0"?>
<!DOCTYPE group SYSTEM "../../../tools/rbuild/project.dtd">
<group xmlns:xi="http://www.w3.org/2001/XInclude">
<!--<directory name="something">
<xi:include href="something/something_drv.rbuild" />
</directory>-->
<xi:include href="kmtest.rbuild" />
</group>

View file

@ -0,0 +1,20 @@
/*
* PROJECT: ReactOS kernel-mode tests
* LICENSE: GPLv2+ - See COPYING in the top level directory
* PURPOSE: Kernel-Mode Test Suite public declarations
* PROGRAMMER: Thomas Faber <thfabba@gmx.de>
*/
#ifndef _KMTEST_PUBLIC_H_
#define _KMTEST_PUBLIC_H_
#define IOCTL_KMTEST_GET_TESTS \
CTL_CODE(FILE_DEVICE_UNKNOWN, 0x800, METHOD_BUFFERED, FILE_READ_DATA)
#define IOCTL_KMTEST_RUN_TEST \
CTL_CODE(FILE_DEVICE_UNKNOWN, 0x801, METHOD_BUFFERED, FILE_READ_DATA | FILE_WRITE_DATA)
#define KMTEST_DEVICE_NAME L"Kmtest"
#define KMTEST_DEVICE_PATH (L"\\\\.\\Global\\GLOBALROOT\\Device\\" KMTEST_DEVICE_NAME)
#endif /* !defined _KMTEST_PUBLIC_H_ */

8
kmtests/kmtest.rbuild Normal file
View file

@ -0,0 +1,8 @@
<module name="kmtest" type="win32cui" installbase="system32" installname="kmtest.exe">
<include base="kmtest">include</include>
<library>advapi32</library>
<directory name="kmtest">
<file>kmtest.c</file>
<file>service.c</file>
</directory>
</module>

197
kmtests/kmtest/kmtest.c Normal file
View file

@ -0,0 +1,197 @@
/*
* PROJECT: ReactOS kernel-mode tests
* LICENSE: GPLv2+ - See COPYING in the top level directory
* PURPOSE: Kernel-Mode Test Suite Loader Application
* PROGRAMMER: Thomas Faber <thfabba@gmx.de>
*/
#define UNICODE
#include <windows.h>
#include <strsafe.h>
#include <assert.h>
#include <stdio.h>
#include <stdlib.h>
#include "kmtest.h"
#include <winioctl.h>
#include <kmt_public.h>
static void OutputError(FILE *fp, DWORD error);
static DWORD RunTest(char *testName);
static DWORD ListTests(PSTR *testList);
int __cdecl main(int argc, char **argv);
static void OutputError(FILE *fp, DWORD error)
{
char *message;
if (!FormatMessageA(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS | FORMAT_MESSAGE_ALLOCATE_BUFFER,
NULL, error, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPSTR)&message, 0, NULL))
{
fprintf(fp, "Could not retrieve error message (error 0x%08lx). Original error: 0x%08lx\n", GetLastError(), error);
}
fprintf(fp, "%s\n", message);
LocalFree(message);
}
static DWORD RunTest(char *testName)
{
DWORD error = ERROR_SUCCESS;
HANDLE hDevice = INVALID_HANDLE_VALUE;
DWORD bytesRead;
char buffer[1024];
BOOL ret;
hDevice = CreateFile(KMTEST_DEVICE_PATH, GENERIC_READ | GENERIC_WRITE, 0,
NULL, OPEN_EXISTING, 0, NULL);
if (hDevice == INVALID_HANDLE_VALUE)
{
error = GetLastError();
goto cleanup;
}
if (!DeviceIoControl(hDevice, IOCTL_KMTEST_RUN_TEST, testName, strlen(testName), NULL, 0, &bytesRead, NULL))
{
error = GetLastError();
goto cleanup;
}
while ((ret = ReadFile(hDevice, buffer, sizeof buffer - 1, &bytesRead, NULL)) != 0)
{
if (!bytesRead)
break;
assert(bytesRead < sizeof buffer);
buffer[bytesRead] = '\0';
fputs(buffer, stdout);
}
if (!ret)
{
error = GetLastError();
goto cleanup;
}
cleanup:
if (hDevice != INVALID_HANDLE_VALUE)
CloseHandle(hDevice);
return error;
}
static DWORD ListTests(PSTR *testList)
{
DWORD error = ERROR_SUCCESS;
HANDLE hDevice = INVALID_HANDLE_VALUE;
DWORD bytesRead;
PSTR buffer = NULL;
DWORD bufferSize;
if (!testList)
{
error = ERROR_INVALID_PARAMETER;
goto cleanup;
}
hDevice = CreateFile(KMTEST_DEVICE_PATH, GENERIC_READ | GENERIC_WRITE, 0,
NULL, OPEN_EXISTING, 0, NULL);
if (hDevice == INVALID_HANDLE_VALUE)
{
error = GetLastError();
goto cleanup;
}
bufferSize = 1024;
buffer = HeapAlloc(GetProcessHeap(), 0, bufferSize);
if (!buffer)
{
error = GetLastError();
goto cleanup;
}
if (!DeviceIoControl(hDevice, IOCTL_KMTEST_GET_TESTS, NULL, 0, buffer, bufferSize, &bytesRead, NULL))
{
error = GetLastError();
goto cleanup;
}
cleanup:
if (buffer && error)
{
HeapFree(GetProcessHeap(), 0, buffer);
buffer = NULL;
}
if (hDevice != INVALID_HANDLE_VALUE)
CloseHandle(hDevice);
if (testList)
*testList = buffer;
return error;
}
int __cdecl main(int argc, char **argv)
{
int status = EXIT_SUCCESS;
DWORD error;
if (argc <= 1)
{
/* no arguments: show usage and list tests */
char *programName = argc == 0 ? "kmtest" : argv[0];
char *testNames, *testName;
size_t len;
printf("Usage: %s test_name\n", programName);
puts("\nValid test names:");
puts(" Create");
puts(" Start");
puts(" Stop");
puts(" Delete");
error = ListTests(&testNames);
testName = testNames;
while ((len = strlen(testName)) != 0)
{
printf(" %s\n", testName);
testName += len + 1;
}
/* TODO: user-mode test parts */
if (error)
OutputError(stdout, error);
}
else
{
char *testName = argv[1];
if (argc > 2)
fputs("Excess arguments ignored\n", stderr);
if (!lstrcmpiA(testName, "create"))
error = Service_Control(Service_Create);
else if (!lstrcmpiA(testName, "delete"))
error = Service_Control(Service_Delete);
else if (!lstrcmpiA(testName, "start"))
error = Service_Control(Service_Start);
else if (!lstrcmpiA(testName, "stop"))
error = Service_Control(Service_Stop);
else
/* TODO: user-mode test parts */
error = RunTest(testName);
OutputError(stdout, error);
}
if (error)
status = EXIT_FAILURE;
return status;
}

View file

@ -0,0 +1,12 @@
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">
<assemblyIdentity version="1.0.0.0" processorArchitecture="x86" name="kmtest"/>
<description>ReactOS Kernel-Mode Test Suite Loader Application</description>
<trustInfo xmlns="urn:schemas-microsoft-com:asm.v3">
<security>
<requestedPrivileges>
<requestedExecutionLevel level="requireAdministrator" uiAccess="false"/>
</requestedPrivileges>
</security>
</trustInfo>
</assembly>

23
kmtests/kmtest/kmtest.h Normal file
View file

@ -0,0 +1,23 @@
/*
* PROJECT: ReactOS kernel-mode tests
* LICENSE: GPLv2+ - See COPYING in the top level directory
* PURPOSE: Kernel-Mode Test Suite Loader Application
* PROGRAMMER: Thomas Faber <thfabba@gmx.de>
*/
#ifndef _KMTESTS_H_
#define _KMTESTS_H_
#include <windows.h>
/* service control functions */
typedef DWORD SERVICE_FUNC(SC_HANDLE hManager);
SERVICE_FUNC Service_Create;
SERVICE_FUNC Service_Delete;
SERVICE_FUNC Service_Start;
SERVICE_FUNC Service_Stop;
DWORD Service_Control(SERVICE_FUNC *Service_Func);
#endif /* !defined _KMTESTS_H_ */

15
kmtests/kmtest/kmtest.rc Normal file
View file

@ -0,0 +1,15 @@
/*
* PROJECT: ReactOS kernel-mode tests
* LICENSE: GPLv2+ - See COPYING in the top level directory
* PURPOSE: Kernel-Mode Test Suite Loader Resource File
* PROGRAMMER: Thomas Faber <thfabba@gmx.de>
*/
#include <windows.h>
#define REACTOS_STR_FILE_DESCRIPTION "ReactOS Kernel-Mode Test Suite Loader Application\0"
#define REACTOS_STR_INTERNAL_NAME "kmtest.exe\0"
#define REACTOS_STR_ORIGINAL_FILENAME "kmtest.exe\0"
#include <reactos/version.rc>
CREATEPROCESS_MANIFEST_RESOURCE_ID RT_MANIFEST DISCARDABLE PURE "kmtest/kmtest.exe.manifest"

135
kmtests/kmtest/service.c Normal file
View file

@ -0,0 +1,135 @@
/*
* PROJECT: ReactOS kernel-mode tests
* LICENSE: GPLv2+ - See COPYING in the top level directory
* PURPOSE: Kernel-Mode Test Suite Loader service control functions
* PROGRAMMER: Thomas Faber <thfabba@gmx.de>
*/
#define UNICODE
#include <windows.h>
#include <strsafe.h>
#include "kmtest.h"
#define SERVICE_NAME L"Kmtest"
#define SERVICE_PATH L"\\kmtest_drv.sys"
DWORD Service_Create(SC_HANDLE hScm)
{
DWORD error = ERROR_SUCCESS;
SC_HANDLE hService = NULL;
wchar_t driverPath[MAX_PATH];
HRESULT result = S_OK;
if (!GetCurrentDirectory(sizeof driverPath / sizeof driverPath[0], driverPath)
|| FAILED(result = StringCbCat(driverPath, sizeof driverPath, SERVICE_PATH)))
{
if (FAILED(result))
error = result;
else
error = GetLastError();
goto cleanup;
}
hService = CreateService(hScm, SERVICE_NAME, L"ReactOS Kernel-Mode Test Suite Driver",
SERVICE_START, SERVICE_KERNEL_DRIVER, SERVICE_DEMAND_START,
SERVICE_ERROR_NORMAL, driverPath, NULL, NULL, NULL, NULL, NULL);
if (!hService)
error = GetLastError();
cleanup:
return error;
}
DWORD Service_Delete(SC_HANDLE hScm)
{
DWORD error = ERROR_SUCCESS;
SC_HANDLE hService = NULL;
hService = OpenService(hScm, SERVICE_NAME, DELETE);
if (!hService)
{
error = GetLastError();
goto cleanup;
}
if (!DeleteService(hService))
error = GetLastError();
cleanup:
if (hService)
CloseServiceHandle(hService);
return error;
}
DWORD Service_Start(SC_HANDLE hScm)
{
DWORD error = ERROR_SUCCESS;
SC_HANDLE hService = NULL;
hService = OpenService(hScm, SERVICE_NAME, SERVICE_START);
if (!hService)
{
error = GetLastError();
goto cleanup;
}
if (!StartService(hService, 0, NULL))
error = GetLastError();
cleanup:
if (hService)
CloseServiceHandle(hService);
return error;
}
DWORD Service_Stop(SC_HANDLE hScm)
{
DWORD error = ERROR_SUCCESS;
SC_HANDLE hService = NULL;
SERVICE_STATUS serviceStatus;
hService = OpenService(hScm, SERVICE_NAME, SERVICE_STOP);
if (!hService)
{
error = GetLastError();
goto cleanup;
}
if (!ControlService(hService, SERVICE_CONTROL_STOP, &serviceStatus))
error = GetLastError();
cleanup:
if (hService)
CloseServiceHandle(hService);
return error;
}
DWORD Service_Control(SERVICE_FUNC *Service_Func)
{
DWORD error = ERROR_SUCCESS;
SC_HANDLE hScm = NULL;
hScm = OpenSCManager(NULL, NULL, SC_MANAGER_CREATE_SERVICE);
if (!hScm)
{
error = GetLastError();
goto cleanup;
}
error = Service_Func(hScm);
cleanup:
if (hScm)
CloseServiceHandle(hScm);
return error;
}