From: Shane Caraveo Date: Mon, 15 Jan 2001 00:29:49 +0000 (+0000) Subject: Multithreaded stress test program for isapi module now supports phpt files X-Git-Tag: php-4.0.5RC1~577 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=dd01542bad127490ec4e0c7feedc810b2fc774b7;p=php Multithreaded stress test program for isapi module now supports phpt files still stuff to do before it's realy done, but does run the tests, just need to get it to compare results right now. --- diff --git a/sapi/isapi/stresstest/notes.txt b/sapi/isapi/stresstest/notes.txt index e6388a060f..e2ee5c2161 100644 --- a/sapi/isapi/stresstest/notes.txt +++ b/sapi/isapi/stresstest/notes.txt @@ -1,10 +1,12 @@ This stress test program is for debugging threading issues with the isapi module. -Create a file that contains a list of php script files, one per line. If you need to provide input, you can create an input file for each script file. File contents would look like: +2 ways to use it. + +1: test any php script file on multiple threads +2: run the php test scripts bundled with the source code -e:\inetpub\pages\index.php -e:\inetpub\pages\info.php -e:\inetpub\pages\posttest.php e:\inetpub\pages\postdata.txt + +GLOBAL SETTINGS If you need to set special environement variables, in addition to your regular environment, create a file that contains them, one setting per line: @@ -14,5 +16,34 @@ This can be used to simulate isapi environment variables if need be. By default, stress test uses 10 threads. To change this, change the define NUM_THREADS in stresstest.cpp. -This test program is a work in progress, no garauntees on it working right. +1: test any php script file on multiple threads + +Create a file that contains a list of php script files, one per line. If you need to provide input, place the GET data, or Query String, after the filename. File contents would look like: + +e:\inetpub\pages\index.php +e:\inetpub\pages\info.php +e:\inetpub\pages\test.php a=1&b=2 + +run: stresstest L files.txt + +2: run the php test scripts bundled with the source code + +supply the path to the parent of the "tests" directory +(expect a couple long pauses for a couple of the larger tests) + +run: stresstest T c:\php4-source + + + +TODO: + +Make an apropriate test of the output against the EXPECT data for the test files, right now it simply doesn't work since I'm burnt (tired that is). + +Make more options configurable: number of threads, itterations, etc. + +Improve stdout output to make it more usefull + +Log totals for each test. + +Implement support for SKIPIF diff --git a/sapi/isapi/stresstest/stresstest.cpp b/sapi/isapi/stresstest/stresstest.cpp index 975f8d784f..625a3f2817 100644 --- a/sapi/isapi/stresstest/stresstest.cpp +++ b/sapi/isapi/stresstest/stresstest.cpp @@ -29,11 +29,24 @@ // // The mandatory exports from the ISAPI DLL // +#define NUM_THREADS 10 +#define ITERATIONS 1 +HANDLE terminate[NUM_THREADS]; +HANDLE StartNow; +// quick and dirty environment +typedef CMapStringToString TEnvironment; +TEnvironment IsapiEnvironment; +CStringArray IsapiFileList; // list of filenames +CStringArray TestNames; // --TEST-- +CStringArray IsapiGetData; // --GET-- +CStringArray IsapiPostData; // --POST-- +CStringArray IsapiMatchData; // --EXPECT-- typedef struct _TIsapiContext { HANDLE in; HANDLE out; DWORD tid; + TEnvironment env; } TIsapiContext; // @@ -57,77 +70,52 @@ char * MakeDateStr(VOID); char * GetEnv(char *); -#define NUM_THREADS 10 -#define ITERATIONS 1 -HANDLE terminate[NUM_THREADS]; -HANDLE StartNow; -// quick and dirty environment -CMapStringToString IsapiEnvironment; -CStringArray IsapiFileList; -CStringArray IsapiArgList; DWORD CALLBACK IsapiThread(void *); -int stress_main(const char *filename, const char *arg); - - +int stress_main(const char *filename, + const char *arg, + const char *postfile, + const char *matchdata, + const char *testname); -int main(int argc, char* argv[]) { - LPVOID lpMsgBuf; - char *filelist, *environment; - - if (argc < 2) { - printf("Usage: stress filelist.txt env.txt\r\n"); - return 0; - } - filelist = argv[1]; - environment = argv[2]; - - hDll = LoadLibrary("php4isapi.dll"); // Load our DLL - if (!hDll) { - FormatMessage( - FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM, - NULL, - GetLastError(), - MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language - (LPTSTR) &lpMsgBuf, - 0, - NULL - ); - fprintf(stderr,"Error: Dll 'php4isapi.dll' not found -%d\n%s\n", GetLastError(),lpMsgBuf); - LocalFree( lpMsgBuf ); - return -1; - } - // - // Find the exported functions +BOOL test = FALSE; +char temppath[MAX_PATH]; - IsapiGetExtensionVersion = (VersionProc)GetProcAddress(hDll,"GetExtensionVersion"); - if (!IsapiGetExtensionVersion) { - fprintf(stderr,"Can't Get Extension Version %d\n",GetLastError()); - return -1; - } - IsapiHttpExtensionProc = (HttpExtProc)GetProcAddress(hDll,"HttpExtensionProc"); - if (!IsapiHttpExtensionProc) { - fprintf(stderr,"Can't Get Extension proc %d\n",GetLastError()); - return -1; - } +void stripcrlf(char *line) +{ + DWORD l = strlen(line)-1; + if (line[l]==10 || line[l]==13) line[l]=0; + l = strlen(line)-1; + if (line[l]==10 || line[l]==13) line[l]=0; +} - // This should really check if the version information matches what we - // expect. - // - __try { - if (!IsapiGetExtensionVersion(&version_info) ) { - fprintf(stderr,"Fatal: GetExtensionVersion failed\n"); - return -1; +BOOL ReadGlobalEnvironment(const char *environment) +{ + if (environment) { + FILE *fp = fopen(environment, "r"); + DWORD i=0; + if (fp) { + char line[2048]; + while (fgets(line,sizeof(line)-1,fp)) { + // file.php arg1 arg2 etc. + char *p = strchr(line, '='); + if (p) { + *p=0; + IsapiEnvironment[line]=p+1; + } } + fclose(fp); + return IsapiEnvironment.GetCount() > 0; } - __except(1) { - return -1; } + return FALSE; +} - // read config files +BOOL ReadFileList(const char *filelist) +{ FILE *fp = fopen(filelist, "r"); if (!fp) { printf("Unable to open %s\r\n", filelist); @@ -136,45 +124,45 @@ int main(int argc, char* argv[]) { int i=0; while (fgets(line,sizeof(line)-1,fp)) { // file.php arg1 arg2 etc. + stripcrlf(line); if (strlen(line)>3) { char *p = strchr(line, ' '); if (p) { *p = 0; // get file + IsapiFileList.Add(line); - IsapiArgList.Add(p+1); + IsapiGetData.Add(p+1); } else { // just a filename is all IsapiFileList.Add(line); - IsapiArgList.Add(""); + IsapiGetData.Add(""); } } + + // future use + IsapiPostData.Add(""); + IsapiMatchData.Add(""); + TestNames.Add(""); + i++; } fclose(fp); + return IsapiFileList.GetSize() > 0; +} - if (environment) { - fp = fopen(environment, "r"); - i=0; - if (fp) { - char line[2048]; - while (fgets(line,sizeof(line)-1,fp)) { - // file.php arg1 arg2 etc. - char *p = strchr(line, '='); - if (p) { - *p=0; - IsapiEnvironment[line]=p+1; - } - } - fclose(fp); - } +void DoThreads() { + + if (IsapiFileList.GetSize() == 0) { + printf("No Files to test\n"); + return; } printf("Starting Threads...\n"); // loop creating threads DWORD tid; HANDLE threads[NUM_THREADS]; - for (i=0; i< NUM_THREADS; i++) { + for (DWORD i=0; i< NUM_THREADS; i++) { terminate[i] = CreateEvent(NULL, FALSE, FALSE, NULL); if ((threads[i]=CreateThread(NULL, 0, IsapiThread, &terminate[i], CREATE_SUSPENDED, &tid))==NULL){ SetEvent(terminate[i]); @@ -185,9 +173,226 @@ int main(int argc, char* argv[]) { } // wait for threads to finish WaitForMultipleObjects(NUM_THREADS, terminate, TRUE, INFINITE); +} + +void DoFileList(const char *filelist, const char *environment) +{ + // read config files + + if (!ReadFileList(filelist)) { + printf("No Files to test!\r\n"); + return; + } + + ReadGlobalEnvironment(environment); + + DoThreads(); +} + + +/** + * ParseTestFile + * parse a single phpt file and add it to the arrays + */ +BOOL ParseTestFile(const char *path, const char *fn) +{ + // parse the test file + char filename[MAX_PATH]; + _snprintf(filename, sizeof(filename)-1, "%s\\%s", path, fn); + char line[1024]; + memset(line, 0, sizeof(line)); + CString cTest, cSkipIf, cPost, cGet, cFile, cExpect; + printf("Reading %s\r\n", filename); + + enum state {none, test, skipif, post, get, file, expect} parsestate = none; + + FILE *fp = fopen(filename, "r"); + if (fp) { + while (fgets(line,sizeof(line)-1,fp)) { + if (line[0]=='-') { + if (_strnicmp(line, "--TEST--", 8)==0) { + parsestate = test; + continue; + } else if (_strnicmp(line, "--SKIPIF--", 10)==0) { + parsestate = skipif; + continue; + } else if (_strnicmp(line, "--POST--", 8)==0) { + parsestate = post; + continue; + } else if (_strnicmp(line, "--GET--", 7)==0) { + parsestate = get; + continue; + } else if (_strnicmp(line, "--FILE--", 8)==0) { + parsestate = file; + continue; + } else if (_strnicmp(line, "--EXPECT--", 10)==0) { + parsestate = expect; + continue; + } + } + switch (parsestate) { + case test: + stripcrlf(line); + cTest = line; + break; + case skipif: + cSkipIf += line; + break; + case post: + cPost += line; + break; + case get: + cGet += line; + break; + case file: + cFile += line; + break; + case expect: + cExpect += line; + break; + } + } + + fclose(fp); + + if (!cTest.IsEmpty() && !cFile.IsEmpty() && !cExpect.IsEmpty()) { + BOOL created = FALSE; + char *fn = _tempnam(temppath,"pht."); + char *en = _tempnam(temppath,"exp."); + FILE *fp = fopen(fn, "w+"); + FILE *fe = fopen(en, "w+"); + if (fp && en) { + fwrite(cFile, cFile.GetLength(), 1, fp); + fwrite(cExpect, cExpect.GetLength(), 1, fe); + IsapiFileList.Add(fn); + TestNames.Add(cTest); + IsapiGetData.Add(cGet); + IsapiPostData.Add(cPost); + IsapiMatchData.Add(en); + created = TRUE; + } + if (fp) fclose(fp); + if (fe) fclose(fe); + + return created; + } + } + return FALSE; +} + + +/** + * GetTestFiles + * Recurse through the path and subdirectories, parse each phpt file + */ +BOOL GetTestFiles(const char *path) +{ + // find all files .phpt under testpath\tests + char FindPath[MAX_PATH]; + WIN32_FIND_DATA fd; + memset(&fd, 0, sizeof(WIN32_FIND_DATA)); + + _snprintf(FindPath, sizeof(FindPath)-1, "%s\\*.*",path); + HANDLE fh = FindFirstFile(FindPath, &fd); + if (fh != INVALID_HANDLE_VALUE) { + do { + if ((fd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) && + !strchr(fd.cFileName, '.')) { + // subdirectory, recurse into it + char NewFindPath[MAX_PATH]; + _snprintf(NewFindPath, sizeof(NewFindPath)-1, "%s\\%s",path, fd.cFileName); + GetTestFiles(NewFindPath); + } else if (strstr(fd.cFileName, ".phpt")) { + // got test file, parse it now + if (ParseTestFile(path, fd.cFileName)) { + printf("Test File Added: %s\\%s\r\n", path, fd.cFileName); + } + } + memset(&fd, 0, sizeof(WIN32_FIND_DATA)); + } while (FindNextFile(fh, &fd) != 0); + FindClose(fh); + } + return IsapiFileList.GetSize() > 0; +} + +void DoTestFiles(const char *filelist, const char *environment) +{ + if (!GetTestFiles(filelist)) { + printf("No Files to test!\r\n"); + return; + } + + ReadGlobalEnvironment(environment); + + DoThreads(); +} + +int main(int argc, char* argv[]) { + LPVOID lpMsgBuf; + char *filelist=NULL, *environment=NULL; + + if (argc < 3) { + // look for phpt files in tests + printf("USAGE: stresstest [L|T] filelist [environment]\r\n"); + return 0; + } else { + if (argv[1][0]=='T') test = TRUE; + if (argc > 1) filelist = argv[2]; + if (argc > 2) environment = argv[3]; + } + + GetTempPath(sizeof(temppath), temppath); + hDll = LoadLibrary("php4isapi.dll"); // Load our DLL + + if (!hDll) { + FormatMessage( + FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM, + NULL, + GetLastError(), + MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language + (LPTSTR) &lpMsgBuf, + 0, + NULL + ); + fprintf(stderr,"Error: Dll 'php4isapi.dll' not found -%d\n%s\n", GetLastError(),lpMsgBuf); + LocalFree( lpMsgBuf ); + return -1; + } + + // + // Find the exported functions + + IsapiGetExtensionVersion = (VersionProc)GetProcAddress(hDll,"GetExtensionVersion"); + if (!IsapiGetExtensionVersion) { + fprintf(stderr,"Can't Get Extension Version %d\n",GetLastError()); + return -1; + } + IsapiHttpExtensionProc = (HttpExtProc)GetProcAddress(hDll,"HttpExtensionProc"); + if (!IsapiHttpExtensionProc) { + fprintf(stderr,"Can't Get Extension proc %d\n",GetLastError()); + return -1; + } + + // This should really check if the version information matches what we + // expect. + // + if (!IsapiGetExtensionVersion(&version_info) ) { + fprintf(stderr,"Fatal: GetExtensionVersion failed\n"); + return -1; + } + + if (test) { + char TestPath[MAX_PATH]; + if (filelist != NULL) + _snprintf(TestPath, sizeof(TestPath)-1, "%s\\tests", filelist); + else strcpy(TestPath, "tests"); + DoTestFiles(TestPath, environment); + } else + DoFileList(filelist, environment); // cleanup + // We should really free memory (e.g., from GetEnv), but we'll be dead // soon enough @@ -204,8 +409,12 @@ DWORD CALLBACK IsapiThread(void *p) for (DWORD i=0; ienv.Lookup(lpszVariableName, value)) { + rc = value.GetLength(); + strncpy((char *)lpBuffer, value, *lpdwSize-1); } else rc = GetEnvironmentVariable(lpszVariableName,(char *)lpBuffer,*lpdwSize) ; @@ -305,7 +565,10 @@ BOOL WINAPI GetServerVariable(HCONN hConn, LPSTR lpszVariableName, BOOL WINAPI ReadClient(HCONN hConn, LPVOID lpBuffer, LPDWORD lpdwSize) { TIsapiContext *c = (TIsapiContext *)hConn; if (!c) return FALSE; - if (c->in) return ReadFile(c->in,lpBuffer,(*lpdwSize), lpdwSize,NULL); + + if (c->in != INVALID_HANDLE_VALUE) + return ReadFile(c->in,lpBuffer,(*lpdwSize), lpdwSize,NULL); + return FALSE; } // @@ -315,7 +578,10 @@ BOOL WINAPI WriteClient(HCONN hConn, LPVOID lpBuffer, LPDWORD lpdwSize, DWORD dwReserved) { TIsapiContext *c = (TIsapiContext *)hConn; if (!c) return FALSE; - if (c->out) return WriteFile(c->out,lpBuffer,*lpdwSize, lpdwSize,NULL); + + if (c->out != INVALID_HANDLE_VALUE) + return WriteFile(c->out,lpBuffer,*lpdwSize, lpdwSize,NULL); + return FALSE; } // diff --git a/sapi/isapi/stresstest/stresstest.dsp b/sapi/isapi/stresstest/stresstest.dsp index 847de279e5..bb2ce57a5e 100644 --- a/sapi/isapi/stresstest/stresstest.dsp +++ b/sapi/isapi/stresstest/stresstest.dsp @@ -61,8 +61,9 @@ LINK32=link.exe # PROP BASE Target_Dir "" # PROP Use_MFC 2 # PROP Use_Debug_Libraries 1 -# PROP Output_Dir "Debug" +# PROP Output_Dir "e:\php4test" # PROP Intermediate_Dir "Debug" +# PROP Ignore_Export_Lib 0 # PROP Target_Dir "" # ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /Yu"stdafx.h" /FD /GZ /c # ADD CPP /nologo /MDd /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /D "_AFXDLL" /FD /GZ /c