[KMTESTS]
authorThomas Faber <thomas.faber@reactos.org>
Thu, 9 Jun 2011 15:14:02 +0000 (15:14 +0000)
committerThomas Faber <thomas.faber@reactos.org>
Thu, 9 Jun 2011 15:14:02 +0000 (15:14 +0000)
- 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

CMakeLists.txt
directory.rbuild
kmtests/CMakeLists.txt [new file with mode: 0644]
kmtests/directory.rbuild [new file with mode: 0644]
kmtests/include/kmt_public.h [new file with mode: 0644]
kmtests/kmtest.rbuild [new file with mode: 0644]
kmtests/kmtest/kmtest.c [new file with mode: 0644]
kmtests/kmtest/kmtest.exe.manifest [new file with mode: 0644]
kmtests/kmtest/kmtest.h [new file with mode: 0644]
kmtests/kmtest/kmtest.rc [new file with mode: 0644]
kmtests/kmtest/service.c [new file with mode: 0644]

index 9d890fa..9b85c32 100644 (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)
index 271e541..2aedf49 100644 (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>
diff --git a/kmtests/CMakeLists.txt b/kmtests/CMakeLists.txt
new file mode 100644 (file)
index 0000000..c80a939
--- /dev/null
@@ -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)
diff --git a/kmtests/directory.rbuild b/kmtests/directory.rbuild
new file mode 100644 (file)
index 0000000..2e65790
--- /dev/null
@@ -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>
diff --git a/kmtests/include/kmt_public.h b/kmtests/include/kmt_public.h
new file mode 100644 (file)
index 0000000..1c1b5dc
--- /dev/null
@@ -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_ */
diff --git a/kmtests/kmtest.rbuild b/kmtests/kmtest.rbuild
new file mode 100644 (file)
index 0000000..08c2ec9
--- /dev/null
@@ -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>
diff --git a/kmtests/kmtest/kmtest.c b/kmtests/kmtest/kmtest.c
new file mode 100644 (file)
index 0000000..a517822
--- /dev/null
@@ -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;
+}
diff --git a/kmtests/kmtest/kmtest.exe.manifest b/kmtests/kmtest/kmtest.exe.manifest
new file mode 100644 (file)
index 0000000..07b5944
--- /dev/null
@@ -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>
diff --git a/kmtests/kmtest/kmtest.h b/kmtests/kmtest/kmtest.h
new file mode 100644 (file)
index 0000000..d2c76a1
--- /dev/null
@@ -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_ */
diff --git a/kmtests/kmtest/kmtest.rc b/kmtests/kmtest/kmtest.rc
new file mode 100644 (file)
index 0000000..890e56e
--- /dev/null
@@ -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"
diff --git a/kmtests/kmtest/service.c b/kmtests/kmtest/service.c
new file mode 100644 (file)
index 0000000..83a6e7c
--- /dev/null
@@ -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;
+}