[KMTESTS]
authorThomas Faber <thomas.faber@reactos.org>
Thu, 14 Jun 2012 18:43:32 +0000 (18:43 +0000)
committerThomas Faber <thomas.faber@reactos.org>
Thu, 14 Jun 2012 18:43:32 +0000 (18:43 +0000)
- Add minimal ExCallback and PsNotify tests
See issue #7120 for more details.

svn path=/trunk/; revision=56734

rostests/kmtests/CMakeLists.txt
rostests/kmtests/kmtest_drv/testlist.c
rostests/kmtests/ntos_ex/ExCallback.c [new file with mode: 0644]
rostests/kmtests/ntos_ps/PsNotify.c [new file with mode: 0644]

index d8c63a2..d4b366f 100644 (file)
@@ -24,6 +24,7 @@ list(APPEND KMTEST_DRV_SOURCE
 
     example/Example.c
     example/KernelType.c
+    ntos_ex/ExCallback.c
     ntos_ex/ExDoubleList.c
     ntos_ex/ExFastMutex.c
     ntos_ex/ExHardError.c
@@ -50,6 +51,7 @@ list(APPEND KMTEST_DRV_SOURCE
     ntos_ob/ObReference.c
     ntos_ob/ObType.c
     ntos_ob/ObTypes.c
+    ntos_ps/PsNotify.c
     ${COMMON_SOURCE}
 
     kmtest_drv/kmtest_drv.rc)
index d633c39..4170778 100644 (file)
@@ -8,6 +8,7 @@
 #include <kmt_test.h>
 
 KMT_TESTFUNC Test_Example;
+KMT_TESTFUNC Test_ExCallback;
 KMT_TESTFUNC Test_ExDoubleList;
 KMT_TESTFUNC Test_ExFastMutex;
 KMT_TESTFUNC Test_ExHardError;
@@ -37,6 +38,7 @@ KMT_TESTFUNC Test_ObType;
 KMT_TESTFUNC Test_ObTypeClean;
 KMT_TESTFUNC Test_ObTypeNoClean;
 KMT_TESTFUNC Test_ObTypes;
+KMT_TESTFUNC Test_PsNotify;
 KMT_TESTFUNC Test_RtlAvlTree;
 KMT_TESTFUNC Test_RtlException;
 KMT_TESTFUNC Test_RtlMemory;
@@ -44,6 +46,7 @@ KMT_TESTFUNC Test_RtlSplayTree;
 
 const KMT_TEST TestList[] =
 {
+    { "ExCallback",                         Test_ExCallback },
     { "ExDoubleList",                       Test_ExDoubleList },
     { "ExFastMutex",                        Test_ExFastMutex },
     { "ExHardError",                        Test_ExHardError },
@@ -74,6 +77,7 @@ const KMT_TEST TestList[] =
     { "-ObTypeClean",                       Test_ObTypeClean },
     { "-ObTypeNoClean",                     Test_ObTypeNoClean },
     { "ObTypes",                            Test_ObTypes },
+    { "PsNotify",                           Test_PsNotify },
     { "RtlAvlTreeKM",                       Test_RtlAvlTree },
     { "RtlExceptionKM",                     Test_RtlException },
     { "RtlMemoryKM",                        Test_RtlMemory },
diff --git a/rostests/kmtests/ntos_ex/ExCallback.c b/rostests/kmtests/ntos_ex/ExCallback.c
new file mode 100644 (file)
index 0000000..631b753
--- /dev/null
@@ -0,0 +1,153 @@
+/*
+ * PROJECT:         ReactOS kernel-mode tests
+ * LICENSE:         GPLv2+ - See COPYING in the top level directory
+ * PURPOSE:         Kernel-Mode Test Suite Executive Callback test
+ * PROGRAMMER:      Thomas Faber <thfabba@gmx.de>
+ */
+
+#include <kmt_test.h>
+
+static
+PEX_CALLBACK_ROUTINE_BLOCK
+(NTAPI
+*ExAllocateCallBack)(
+    IN PEX_CALLBACK_FUNCTION Function,
+    IN PVOID Context
+)
+//= (PVOID)0x809af1f4 // 2003 sp1 x86
+//= (PVOID)0x80a7f04a // 2003 sp1 x86 checked
+;
+
+static
+VOID
+(NTAPI
+*ExFreeCallBack)(
+    IN PEX_CALLBACK_ROUTINE_BLOCK CallbackBlock
+)
+//= (PVOID)0x80918bb5 // 2003 sp1 x86
+//= (PVOID)0x80a355f0 // 2003 sp1 x86 checked
+;
+
+static INT CallbackArgument1;
+static INT CallbackArgument2;
+
+static
+NTSTATUS
+NTAPI
+ExCallbackFunction(
+    IN PVOID CallbackContext,
+    IN PVOID Argument1 OPTIONAL,
+    IN PVOID Argument2 OPTIONAL)
+{
+    ok(0, "Callback function unexpectedly called\n");
+    return STATUS_SUCCESS;
+}
+
+static
+VOID
+TestPrivateFunctions(VOID)
+{
+    UNICODE_STRING ExAllocateCallBackName = RTL_CONSTANT_STRING(L"ExAllocateCallBack");
+    UNICODE_STRING ExFreeCallBackName = RTL_CONSTANT_STRING(L"ExFreeCallBack");
+    PEX_CALLBACK_ROUTINE_BLOCK CallbackBlock;
+    INT CallbackContext;
+
+    if (!ExAllocateCallBack)
+        ExAllocateCallBack = MmGetSystemRoutineAddress(&ExAllocateCallBackName);
+    if (!ExFreeCallBack)
+        ExFreeCallBack = MmGetSystemRoutineAddress(&ExFreeCallBackName);
+
+    if (skip(ExAllocateCallBack && ExFreeCallBack,
+             "ExAllocateCallBack and/or ExFreeCallBack unavailable\n"))
+        return;
+
+    CallbackBlock = ExAllocateCallBack(ExCallbackFunction, &CallbackContext);
+    ok(CallbackBlock != NULL, "CallbackBlock = NULL\n");
+
+    if (skip(CallbackBlock != NULL, "Allocating callback failed\n"))
+        return;
+
+    ok_eq_pointer(CallbackBlock->Function, ExCallbackFunction);
+    ok_eq_pointer(CallbackBlock->Context, &CallbackContext);
+    ok_eq_hex(KmtGetPoolTag(CallbackBlock), 'brbC');
+
+    ExFreeCallBack(CallbackBlock);
+}
+
+static
+VOID
+NTAPI
+CallbackFunction(
+    IN PVOID CallbackContext,
+    IN PVOID Argument1,
+    IN PVOID Argument2)
+{
+    INT *InvocationCount = CallbackContext;
+
+    ok_irql(PASSIVE_LEVEL);
+
+    (*InvocationCount)++;
+    ok_eq_pointer(Argument1, &CallbackArgument1);
+    ok_eq_pointer(Argument2, &CallbackArgument2);
+}
+
+START_TEST(ExCallback)
+{
+    NTSTATUS Status;
+    PCALLBACK_OBJECT CallbackObject;
+    OBJECT_ATTRIBUTES ObjectAttributes;
+    UNICODE_STRING CallbackName = RTL_CONSTANT_STRING(L"\\Callback\\KmtestExCallbackTestCallback");
+    PVOID CallbackRegistration;
+    INT InvocationCount = 0;
+
+    TestPrivateFunctions();
+
+    /* TODO: Parameter tests */
+    /* TODO: Test the three predefined callbacks */
+    /* TODO: Test opening an existing callback */
+    /* TODO: Test AllowMultipleCallbacks */
+    /* TODO: Test calling multiple callbacks */
+    /* TODO: Test registering the same function twice */
+    /* TODO: Test callback object fields */
+    /* TODO: Test callback registration fields */
+    InitializeObjectAttributes(&ObjectAttributes,
+                               &CallbackName,
+                               OBJ_CASE_INSENSITIVE,
+                               NULL,
+                               NULL);
+
+    CallbackObject = KmtInvalidPointer;
+    Status = ExCreateCallback(&CallbackObject,
+                              &ObjectAttributes,
+                              TRUE,
+                              TRUE);
+    ok_eq_hex(Status, STATUS_SUCCESS);
+    ok(CallbackObject != NULL && CallbackObject != KmtInvalidPointer,
+        "CallbackObject = %p", CallbackObject);
+
+    if (skip(NT_SUCCESS(Status), "Creating callback failed\n"))
+        return;
+
+    CallbackRegistration = ExRegisterCallback(CallbackObject,
+                                              CallbackFunction,
+                                              &InvocationCount);
+    ok(CallbackRegistration != NULL, "CallbackRegistration = NULL\n");
+
+    if (!skip(CallbackRegistration != NULL, "Registering callback failed\n"))
+    {
+        ok_eq_hex(KmtGetPoolTag(CallbackRegistration), 'eRBC');
+        ok_eq_int(InvocationCount, 0);
+        ExNotifyCallback(CallbackObject,
+                         &CallbackArgument1,
+                         &CallbackArgument2);
+        ok_eq_int(InvocationCount, 1);
+        ExNotifyCallback(CallbackObject,
+                         &CallbackArgument1,
+                         &CallbackArgument2);
+        ok_eq_int(InvocationCount, 2);
+
+        ExUnregisterCallback(CallbackRegistration);
+    }
+
+    ObDereferenceObject(CallbackObject);
+}
diff --git a/rostests/kmtests/ntos_ps/PsNotify.c b/rostests/kmtests/ntos_ps/PsNotify.c
new file mode 100644 (file)
index 0000000..7062d12
--- /dev/null
@@ -0,0 +1,177 @@
+/*
+ * PROJECT:         ReactOS kernel-mode tests
+ * LICENSE:         GPLv2+ - See COPYING in the top level directory
+ * PURPOSE:         Kernel-Mode Test Suite Process Notification Routines test
+ * PROGRAMMER:      Thomas Faber <thfabba@gmx.de>
+ */
+
+#include <kmt_test.h>
+
+//#define NDEBUG
+#include <debug.h>
+
+static
+VOID
+NTAPI
+CreateProcessNotifyRoutine(
+    IN HANDLE ParentId,
+    IN HANDLE ProcessId,
+    IN BOOLEAN Create)
+{
+    ok_irql(PASSIVE_LEVEL);
+    if (!Create)
+        ok_eq_pointer(ProcessId, PsGetCurrentProcessId());
+    else
+        ok(ProcessId != PsGetCurrentProcessId(),
+           "ProcessId %p equals current\n", ProcessId);
+    DPRINT("%s(%p, %p, %d)\n", __FUNCTION__, ParentId, ProcessId, Create);
+}
+
+static
+VOID
+TestCreateProcessNotify(VOID)
+{
+    NTSTATUS Status;
+
+    Status = PsSetCreateProcessNotifyRoutine(NULL, TRUE);
+    ok_eq_hex(Status, STATUS_PROCEDURE_NOT_FOUND);
+
+    Status = PsSetCreateProcessNotifyRoutine(NULL, FALSE);
+    ok_eq_hex(Status, STATUS_SUCCESS);
+
+    Status = PsSetCreateProcessNotifyRoutine(NULL, TRUE);
+    ok_eq_hex(Status, STATUS_SUCCESS);
+
+    Status = PsSetCreateProcessNotifyRoutine(NULL, TRUE);
+    ok_eq_hex(Status, STATUS_PROCEDURE_NOT_FOUND);
+
+    Status = PsSetCreateProcessNotifyRoutine(CreateProcessNotifyRoutine, TRUE);
+    ok_eq_hex(Status, STATUS_PROCEDURE_NOT_FOUND);
+
+    Status = PsSetCreateProcessNotifyRoutine(CreateProcessNotifyRoutine, FALSE);
+    ok_eq_hex(Status, STATUS_SUCCESS);
+
+    /* TODO: test whether the callback is notified on process creation */
+
+    Status = PsSetCreateProcessNotifyRoutine(CreateProcessNotifyRoutine, TRUE);
+    ok_eq_hex(Status, STATUS_SUCCESS);
+
+    Status = PsSetCreateProcessNotifyRoutine(CreateProcessNotifyRoutine, TRUE);
+    ok_eq_hex(Status, STATUS_PROCEDURE_NOT_FOUND);
+
+    /* TODO: register the same routine twice */
+    /* TODO: register more than the maximum number of notifications */
+}
+
+static
+VOID
+NTAPI
+CreateThreadNotifyRoutine(
+    IN HANDLE ProcessId,
+    IN HANDLE ThreadId,
+    IN BOOLEAN Create)
+{
+    ok_irql(PASSIVE_LEVEL);
+    if (!Create)
+    {
+        ok_eq_pointer(ProcessId, PsGetCurrentProcessId());
+        ok_eq_pointer(ThreadId, PsGetCurrentThreadId());
+    }
+    else
+    {
+        ok(ThreadId != PsGetCurrentThreadId(),
+           "ThreadId %p equals current\n", ThreadId);
+    }
+    DPRINT("%s(%p, %p, %d)\n", __FUNCTION__, ProcessId, ThreadId, Create);
+}
+
+static
+VOID
+TestCreateThreadNotify(VOID)
+{
+    NTSTATUS Status;
+
+    Status = PsRemoveCreateThreadNotifyRoutine(NULL);
+    ok_eq_hex(Status, STATUS_PROCEDURE_NOT_FOUND);
+
+    Status = PsSetCreateThreadNotifyRoutine(NULL);
+    ok_eq_hex(Status, STATUS_SUCCESS);
+
+    Status = PsRemoveCreateThreadNotifyRoutine(NULL);
+    ok_eq_hex(Status, STATUS_SUCCESS);
+
+    Status = PsRemoveCreateThreadNotifyRoutine(NULL);
+    ok_eq_hex(Status, STATUS_PROCEDURE_NOT_FOUND);
+
+    Status = PsRemoveCreateThreadNotifyRoutine(CreateThreadNotifyRoutine);
+    ok_eq_hex(Status, STATUS_PROCEDURE_NOT_FOUND);
+
+    Status = PsSetCreateThreadNotifyRoutine(CreateThreadNotifyRoutine);
+    ok_eq_hex(Status, STATUS_SUCCESS);
+
+    /* TODO: test whether the callback is notified on thread creation */
+
+    Status = PsRemoveCreateThreadNotifyRoutine(CreateThreadNotifyRoutine);
+    ok_eq_hex(Status, STATUS_SUCCESS);
+
+    Status = PsRemoveCreateThreadNotifyRoutine(CreateThreadNotifyRoutine);
+    ok_eq_hex(Status, STATUS_PROCEDURE_NOT_FOUND);
+
+    /* TODO: register the same routine twice */
+    /* TODO: register more than the maximum number of notifications */
+}
+
+static
+VOID
+NTAPI
+LoadImageNotifyRoutine(
+    IN PUNICODE_STRING FullImageName OPTIONAL,
+    IN HANDLE ProcessId,
+    IN PIMAGE_INFO ImageInfo)
+{
+    ok_irql(PASSIVE_LEVEL);
+    DPRINT("%s('%wZ', %p, %p)\n", __FUNCTION__, FullImageName, ProcessId, ImageInfo);
+}
+
+static
+VOID
+TestLoadImageNotify(VOID)
+{
+    NTSTATUS Status;
+
+    Status = PsRemoveLoadImageNotifyRoutine(NULL);
+    ok_eq_hex(Status, STATUS_PROCEDURE_NOT_FOUND);
+
+    Status = PsSetLoadImageNotifyRoutine(NULL);
+    ok_eq_hex(Status, STATUS_SUCCESS);
+
+    Status = PsRemoveLoadImageNotifyRoutine(NULL);
+    ok_eq_hex(Status, STATUS_SUCCESS);
+
+    Status = PsRemoveLoadImageNotifyRoutine(NULL);
+    ok_eq_hex(Status, STATUS_PROCEDURE_NOT_FOUND);
+
+    Status = PsRemoveLoadImageNotifyRoutine(LoadImageNotifyRoutine);
+    ok_eq_hex(Status, STATUS_PROCEDURE_NOT_FOUND);
+
+    Status = PsSetLoadImageNotifyRoutine(LoadImageNotifyRoutine);
+    ok_eq_hex(Status, STATUS_SUCCESS);
+
+    /* TODO: test whether the callback is notified on image load */
+
+    Status = PsRemoveLoadImageNotifyRoutine(LoadImageNotifyRoutine);
+    ok_eq_hex(Status, STATUS_SUCCESS);
+
+    Status = PsRemoveLoadImageNotifyRoutine(LoadImageNotifyRoutine);
+    ok_eq_hex(Status, STATUS_PROCEDURE_NOT_FOUND);
+
+    /* TODO: register the same routine twice */
+    /* TODO: register more than the maximum number of notifications */
+}
+
+START_TEST(PsNotify)
+{
+    TestCreateProcessNotify();
+    TestCreateThreadNotify();
+    TestLoadImageNotify();
+}