- Add support for recovering from crashed tests
- Add check to prevent us from running the test every boot
- Delete some useless code
- Record test result information in the registry
- Under the Kmtest\Parameters key, you will find CurrentStage which is the stage that testing is on (almost always 8 if it boots). You will also find <Test Name>SuccessCount which is the number of successful tests, <Test Name>FailureCount which is the number of failed tests, <Test Name>TotalCount which is the total number of tests, and <Test Name>SkippedCount which is the number of tests that have been skipped
- Enjoy your reg testing! :)

svn path=/trunk/; revision=47309
This commit is contained in:
Cameron Gutman 2010-05-22 18:34:01 +00:00
parent d7bbeaed19
commit afcd401a32
10 changed files with 330 additions and 676 deletions

View file

@ -25,8 +25,12 @@
#include <ddk/ntddk.h>
#include "kmtest.h"
#define NDEBUG
#include <debug.h>
LONG successes;
LONG failures;
LONG skipped;
tls_data glob_data;
/* PRIVATE FUNCTIONS ***********************************************************/
@ -35,12 +39,61 @@ StartTest()
{
successes = 0;
failures = 0;
skipped = 0;
}
VOID
FinishTest(LPSTR TestName)
FinishTest(HANDLE KeyHandle, LPWSTR TestName)
{
DbgPrint("%s: %d test executed (0 marked as todo, %d failures), 0 skipped.\n", TestName, successes + failures, failures);
WCHAR KeyName[100];
LONG total = successes + failures;
UNICODE_STRING KeyNameU;
wcscpy(KeyName, TestName);
wcscat(KeyName, L"SuccessCount");
RtlInitUnicodeString(&KeyNameU, KeyName);
ZwSetValueKey(KeyHandle,
&KeyNameU,
0,
REG_DWORD,
&successes,
sizeof(ULONG));
wcscpy(KeyName, TestName);
wcscat(KeyName, L"FailureCount");
RtlInitUnicodeString(&KeyNameU, KeyName);
ZwSetValueKey(KeyHandle,
&KeyNameU,
0,
REG_DWORD,
&failures,
sizeof(ULONG));
wcscpy(KeyName, TestName);
wcscat(KeyName, L"TotalCount");
RtlInitUnicodeString(&KeyNameU, KeyName);
ZwSetValueKey(KeyHandle,
&KeyNameU,
0,
REG_DWORD,
&total,
sizeof(ULONG));
wcscpy(KeyName, TestName);
wcscat(KeyName, L"SkipCount");
RtlInitUnicodeString(&KeyNameU, KeyName);
ZwSetValueKey(KeyHandle,
&KeyNameU,
0,
REG_DWORD,
&skipped,
sizeof(ULONG));
DbgPrint("%S: %d test executed (0 marked as todo, %d failures), %d skipped.\n", TestName, total, failures, skipped);
}
void kmtest_set_location(const char* file, int line)
@ -105,11 +158,14 @@ PWCHAR CreateLowerDeviceRegistryKey(PUNICODE_STRING RegistryPath, PWCHAR NewDriv
/*
* Test Declarations
*/
VOID NtoskrnlIoTests();
VOID NtoskrnlKeTests();
VOID NtoskrnlObTest();
VOID NtoskrnlExecutiveTests();
VOID NtoskrnlPoolsTest();
VOID RegisterDI_Test(HANDLE KeyHandle);
VOID NtoskrnlIoMdlTest(HANDLE KeyHandle);
VOID NtoskrnlIoIrpTest(HANDLE KeyHandle);
VOID NtoskrnlObTest(HANDLE KeyHandle);
VOID ExTimerTest(HANDLE KeyHandle);
VOID PoolsTest(HANDLE KeyHandle);
VOID PoolsCorruption(HANDLE KeyHandle);
VOID KeStallTest(HANDLE KeyHandle);
VOID DriverObjectTest(PDRIVER_OBJECT, int);
VOID DeviceCreateDeleteTest(PDRIVER_OBJECT);
VOID DeviceObjectTest(PDEVICE_OBJECT);
@ -119,6 +175,19 @@ BOOLEAN DetachDeviceTest(PDEVICE_OBJECT);
BOOLEAN AttachDeviceTest(PDEVICE_OBJECT, PWCHAR);
VOID LowerDeviceKernelAPITest(PDEVICE_OBJECT, BOOLEAN);
typedef enum {
TestStageExTimer = 0,
TestStageIoMdl,
TestStageIoDi,
TestStageIoIrp,
TestStageMmPoolTest,
TestStageMmPoolCorruption,
TestStageOb,
TestStageKeStall,
TestStageDrv,
TestStageMax
} TEST_STAGE;
/*
* KmtestDispatch
*/
@ -192,7 +261,148 @@ KmtestUnload(IN PDRIVER_OBJECT DriverObject)
IoDeleteDevice(MainDeviceObject);
}
FinishTest("Driver Tests");
}
static
PKEY_VALUE_PARTIAL_INFORMATION
NTAPI
ReadRegistryValue(HANDLE KeyHandle, PWCHAR ValueName)
{
NTSTATUS Status;
PKEY_VALUE_PARTIAL_INFORMATION InformationBuffer = NULL;
ULONG AllocatedLength = 0, RequiredLength = 0;
UNICODE_STRING ValueNameU;
RtlInitUnicodeString(&ValueNameU, ValueName);
Status = ZwQueryValueKey(KeyHandle,
&ValueNameU,
KeyValuePartialInformation,
NULL,
0,
&RequiredLength);
if (Status == STATUS_BUFFER_TOO_SMALL || Status == STATUS_BUFFER_OVERFLOW)
{
InformationBuffer = ExAllocatePool(PagedPool, RequiredLength);
AllocatedLength = RequiredLength;
if (!InformationBuffer) return NULL;
Status = ZwQueryValueKey(KeyHandle,
&ValueNameU,
KeyValuePartialInformation,
InformationBuffer,
AllocatedLength,
&RequiredLength);
}
if (!NT_SUCCESS(Status))
{
DPRINT1("Failed to read %S (0x%x)\n", ValueName, Status);
if (InformationBuffer != NULL)
ExFreePool(InformationBuffer);
return NULL;
}
return InformationBuffer;
}
static
VOID
RunKernelModeTest(PDRIVER_OBJECT DriverObject,
PUNICODE_STRING RegistryPath,
HANDLE KeyHandle,
TEST_STAGE Stage)
{
UNICODE_STRING KeyName = RTL_CONSTANT_STRING(L"CurrentStage");
PWCHAR LowerDriverRegPath;
DPRINT1("Running stage %d test...\n", Stage);
ZwSetValueKey(KeyHandle,
&KeyName,
0,
REG_DWORD,
&Stage,
sizeof(ULONG));
switch (Stage)
{
case TestStageExTimer:
ExTimerTest(KeyHandle);
break;
case TestStageIoMdl:
NtoskrnlIoMdlTest(KeyHandle);
break;
case TestStageIoDi:
RegisterDI_Test(KeyHandle);
break;
case TestStageIoIrp:
NtoskrnlIoIrpTest(KeyHandle);
break;
case TestStageMmPoolTest:
PoolsTest(KeyHandle);
break;
case TestStageMmPoolCorruption:
PoolsCorruption(KeyHandle);
break;
case TestStageOb:
NtoskrnlObTest(KeyHandle);
break;
case TestStageKeStall:
KeStallTest(KeyHandle);
break;
case TestStageDrv:
/* Start the tests for the driver routines */
StartTest();
/* Do DriverObject Test for Driver Entry */
DriverObjectTest(DriverObject, 0);
/* Create and delete device, on return MainDeviceObject has been created */
DeviceCreateDeleteTest(DriverObject);
/* Make sure a device object was created */
if (MainDeviceObject)
{
LowerDriverRegPath = CreateLowerDeviceRegistryKey(RegistryPath, L"kmtestassist");
if (LowerDriverRegPath)
{
/* Load driver test and load the lower driver */
if (ZwLoadTest(DriverObject, RegistryPath, LowerDriverRegPath))
{
AttachDeviceTest(MainDeviceObject, L"kmtestassists");
if (AttachDeviceObject)
{
LowerDeviceKernelAPITest(MainDeviceObject, FALSE);
}
/* Unload lower driver without detaching from its device */
ZwUnloadTest(DriverObject, RegistryPath, LowerDriverRegPath);
LowerDeviceKernelAPITest(MainDeviceObject, TRUE);
}
else
{
DbgPrint("Failed to load kmtestassist driver\n");
}
}
}
FinishTest(KeyHandle, L"DriverTest");
break;
default:
ASSERT(FALSE);
break;
}
}
/*
@ -204,61 +414,98 @@ DriverEntry(PDRIVER_OBJECT DriverObject,
PUNICODE_STRING RegistryPath)
{
int i;
PWCHAR LowerDriverRegPath;
NTSTATUS Status;
OBJECT_ATTRIBUTES ObjectAttributes;
UNICODE_STRING ParameterKeyName = RTL_CONSTANT_STRING(L"Parameters");
PKEY_VALUE_PARTIAL_INFORMATION KeyInfo;
PULONG KeyValue;
TEST_STAGE CurrentStage;
HANDLE DriverKeyHandle, ParameterKeyHandle;
DbgPrint("\n===============================================\n");
DbgPrint("Kernel Mode Regression Driver Test starting...\n");
DbgPrint("===============================================\n");
MainDeviceObject = NULL;
AttachDeviceObject = NULL;
ThisDriverObject = DriverObject;
InitializeObjectAttributes(&ObjectAttributes,
RegistryPath,
OBJ_CASE_INSENSITIVE,
0,
NULL);
NtoskrnlExecutiveTests();
NtoskrnlKeTests();
NtoskrnlIoTests();
NtoskrnlObTest();
NtoskrnlPoolsTest();
/* Start the tests for the driver routines */
StartTest();
/* Do DriverObject Test for Driver Entry */
DriverObjectTest(DriverObject, 0);
/* Create and delete device, on return MainDeviceObject has been created */
DeviceCreateDeleteTest(DriverObject);
/* Make sure a device object was created */
if (MainDeviceObject)
Status = ZwOpenKey(&DriverKeyHandle,
KEY_CREATE_SUB_KEY | KEY_ENUMERATE_SUB_KEYS,
&ObjectAttributes);
if (!NT_SUCCESS(Status))
{
LowerDriverRegPath = CreateLowerDeviceRegistryKey(RegistryPath, L"kmtestassist");
DPRINT1("Failed to open %wZ\n", RegistryPath);
return Status;
}
if (LowerDriverRegPath)
InitializeObjectAttributes(&ObjectAttributes,
&ParameterKeyName,
OBJ_OPENIF | OBJ_CASE_INSENSITIVE,
DriverKeyHandle,
NULL);
Status = ZwCreateKey(&ParameterKeyHandle,
KEY_SET_VALUE | KEY_QUERY_VALUE,
&ObjectAttributes,
0,
NULL,
REG_OPTION_NON_VOLATILE,
NULL);
ZwClose(DriverKeyHandle);
if (!NT_SUCCESS(Status))
{
DPRINT1("Failed to create %wZ\\%wZ\n", RegistryPath, &ParameterKeyName);
return Status;
}
KeyInfo = ReadRegistryValue(ParameterKeyHandle, L"CurrentStage");
if (KeyInfo)
{
if (KeyInfo->DataLength != sizeof(ULONG))
{
/* Load driver test and load the lower driver */
if (ZwLoadTest(DriverObject, RegistryPath, LowerDriverRegPath))
{
AttachDeviceTest(MainDeviceObject, L"kmtestassists");
if (AttachDeviceObject)
{
LowerDeviceKernelAPITest(MainDeviceObject, FALSE);
}
/* Unload lower driver without detaching from its device */
ZwUnloadTest(DriverObject, RegistryPath, LowerDriverRegPath);
LowerDeviceKernelAPITest(MainDeviceObject, TRUE);
}
else
{
DbgPrint("Failed to load kmtestassist driver\n");
}
DPRINT1("Invalid data length for CurrentStage: %d\n", KeyInfo->DataLength);
ExFreePool(KeyInfo);
return STATUS_UNSUCCESSFUL;
}
KeyValue = (PULONG)KeyInfo->Data;
if ((*KeyValue) + 1 < TestStageMax)
{
DPRINT1("Resuming testing after a crash at stage %d\n", (*KeyValue));
CurrentStage = (TEST_STAGE)((*KeyValue) + 1);
}
else
{
DPRINT1("Testing was completed on a previous boot\n");
ExFreePool(KeyInfo);
return STATUS_UNSUCCESSFUL;
}
ExFreePool(KeyInfo);
}
else
{
return STATUS_UNSUCCESSFUL;
DPRINT1("Starting a fresh test\n");
CurrentStage = (TEST_STAGE)0;
}
/* Run the tests */
while (CurrentStage < TestStageMax)
{
RunKernelModeTest(DriverObject,
RegistryPath,
ParameterKeyHandle,
CurrentStage);
CurrentStage++;
}
DPRINT1("Testing is complete!\n");
ZwClose(ParameterKeyHandle);
/* Set all MajorFunctions to NULL to verify that kernel fixes them */
for (i = 1; i <= IRP_MJ_MAXIMUM_FUNCTION; i++)
DriverObject->MajorFunction[i] = NULL;