Catch hang-up regtests, added _DispatcherTimeout macros for tests to specify timeout...
[reactos.git] / reactos / regtests / shared / regtests.c
1 /*
2 * PROJECT: ReactOS kernel
3 * FILE: regtests/shared/regtests.c
4 * PURPOSE: Regression testing framework
5 * PROGRAMMER: Casper S. Hornstrup (chorns@users.sourceforge.net)
6 * UPDATE HISTORY:
7 * 06-07-2003 CSH Created
8 */
9 #include <ctype.h>
10 #include <stdlib.h>
11 #include <stdio.h>
12 #include <string.h>
13 #include <malloc.h>
14 #define NTOS_MODE_USER
15 #include <ntos.h>
16 #include <pseh.h>
17 #include "regtests.h"
18
19 #define NDEBUG
20 #include <debug.h>
21
22 typedef struct _PERFORM_TEST_ARGS
23 {
24 TestOutputRoutine OutputRoutine;
25 PROS_TEST Test;
26 LPSTR TestName;
27 } PERFORM_TEST_ARGS;
28
29 int _Result;
30 char *_Buffer;
31
32 static LIST_ENTRY AllTests;
33
34 VOID
35 InitializeTests()
36 {
37 InitializeListHead(&AllTests);
38 }
39
40 DWORD WINAPI
41 PerformTest(PVOID _arg)
42 {
43 PERFORM_TEST_ARGS *Args = (PERFORM_TEST_ARGS *)_arg;
44 TestOutputRoutine OutputRoutine = Args->OutputRoutine;
45 PROS_TEST Test = Args->Test;
46 LPSTR TestName = Args->TestName;
47 char OutputBuffer[5000];
48 char Buffer[5000];
49
50 memset(Buffer, 0, sizeof(Buffer));
51
52 _SEH_TRY {
53 _Result = TS_OK;
54 _Buffer = Buffer;
55 (Test->Routine)(TESTCMD_RUN);
56 } _SEH_HANDLE {
57 _Result = TS_FAILED;
58 sprintf(Buffer, "due to exception 0x%lx", _SEH_GetExceptionCode());
59 } _SEH_END;
60
61 if (_Result != TS_OK)
62 {
63 sprintf(OutputBuffer, "ROSREGTEST: |%s| Status: Failed (%s)\n", TestName, Buffer);
64 }
65 else
66 {
67 sprintf(OutputBuffer, "ROSREGTEST: |%s| Status: Success\n", TestName);
68 }
69 if (OutputRoutine != NULL)
70 {
71 (*OutputRoutine)(OutputBuffer);
72 }
73 else
74 {
75 DbgPrint(OutputBuffer);
76 }
77 return 1;
78 }
79
80 VOID
81 PerformTests(TestOutputRoutine OutputRoutine, LPSTR TestName)
82 {
83 PLIST_ENTRY CurrentEntry;
84 PLIST_ENTRY NextEntry;
85 PROS_TEST Current;
86 PERFORM_TEST_ARGS Args;
87 HANDLE hThread;
88 char OutputBuffer[1024];
89 char Name[200];
90 DWORD TimeOut;
91
92 Args.OutputRoutine = OutputRoutine;
93 Args.TestName = Name;
94
95 CurrentEntry = AllTests.Flink;
96 for (; CurrentEntry != &AllTests; CurrentEntry = NextEntry)
97 {
98 NextEntry = CurrentEntry->Flink;
99 Current = CONTAINING_RECORD(CurrentEntry, ROS_TEST, ListEntry);
100 Args.Test = Current;
101
102 /* Get name of test */
103 memset(Name, 0, sizeof(Name));
104
105 _Result = TS_OK;
106 _Buffer = Name;
107 (Current->Routine)(TESTCMD_TESTNAME);
108 if (_Result != TS_OK)
109 {
110 if (TestName != NULL)
111 {
112 continue;
113 }
114 strcpy(Name, "Unnamed");
115 }
116
117 if (TestName != NULL)
118 {
119 if (_stricmp(Name, TestName) != 0)
120 {
121 continue;
122 }
123 }
124
125 /* Get timeout for test */
126 TimeOut = 0;
127 _Result = TS_OK;
128 _Buffer = (char *)&TimeOut;
129 (Current->Routine)(TESTCMD_TIMEOUT);
130 if (_Result != TS_OK || TimeOut == INFINITE)
131 {
132 TimeOut = 5000;
133 }
134
135 /* Run test in thread */
136 hThread = _CreateThread(NULL, 0, PerformTest, (PVOID)&Args, 0, NULL);
137 if (hThread == NULL)
138 {
139 sprintf(OutputBuffer,
140 "ROSREGTEST: |%s| Status: Failed (CreateThread failed: 0x%x)\n",
141 Name, (unsigned int)GetLastError());
142 }
143 else if (_WaitForSingleObject(hThread, TimeOut) == WAIT_TIMEOUT)
144 {
145 if (!_TerminateThread(hThread, 0))
146 {
147 sprintf(OutputBuffer,
148 "ROSREGTEST: |%s| Status: Failed (Test timed out - %d ms, TerminateThread failed: 0x%x)\n",
149 Name, (int)TimeOut, (unsigned int)GetLastError());
150 }
151 else
152 {
153 sprintf(OutputBuffer, "ROSREGTEST: |%s| Status: Failed (Test timed out - %d ms)\n", Name, (int)TimeOut);
154 }
155 }
156 else
157 {
158 continue;
159 }
160
161 if (OutputRoutine != NULL)
162 {
163 (*OutputRoutine)(OutputBuffer);
164 }
165 else
166 {
167 DbgPrint(OutputBuffer);
168 }
169 }
170 }
171
172 VOID
173 AddTest(TestRoutine Routine)
174 {
175 PROS_TEST Test;
176
177 Test = (PROS_TEST) malloc(sizeof(ROS_TEST));
178 if (Test == NULL)
179 {
180 DbgPrint("Out of memory");
181 return;
182 }
183
184 Test->Routine = Routine;
185
186 InsertTailList(&AllTests, &Test->ListEntry);
187 }
188
189 PVOID STDCALL
190 FrameworkGetHook(ULONG index)
191 {
192 return FrameworkGetHookInternal(index);
193 }