shane           Sun Jan 14 16:29:49 2001 EDT

  Modified files:              
    /php4/sapi/isapi/stresstest notes.txt stresstest.cpp stresstest.dsp 
  Log:
  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.
  
  
  
Index: php4/sapi/isapi/stresstest/notes.txt
diff -u php4/sapi/isapi/stresstest/notes.txt:1.1 
php4/sapi/isapi/stresstest/notes.txt:1.2
--- php4/sapi/isapi/stresstest/notes.txt:1.1    Sun Jan  7 16:10:06 2001
+++ php4/sapi/isapi/stresstest/notes.txt        Sun Jan 14 16:29:49 2001
@@ -1,11 +1,13 @@
 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.
 
-e:\inetpub\pages\index.php
-e:\inetpub\pages\info.php
-e:\inetpub\pages\posttest.php e:\inetpub\pages\postdata.txt
+1: test any php script file on multiple threads
+2: run the php test scripts bundled with the source code
+
 
+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:
 
 MY_ENV_VAR=XXXXXXXX
@@ -13,6 +15,35 @@
 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.
+
+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.
 
-This test program is a work in progress, no garauntees on it working right.
+Implement support for SKIPIF
 
Index: php4/sapi/isapi/stresstest/stresstest.cpp
diff -u php4/sapi/isapi/stresstest/stresstest.cpp:1.3 
php4/sapi/isapi/stresstest/stresstest.cpp:1.4
--- php4/sapi/isapi/stresstest/stresstest.cpp:1.3       Sun Jan  7 17:14:49 2001
+++ php4/sapi/isapi/stresstest/stresstest.cpp   Sun Jan 14 16:29:49 2001
@@ -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 * 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 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 @@
        }
        // 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 @@
                for (DWORD i=0; i<filecount; i++) {
                        // execute each file
                        printf("Thread %d File %s\n", GetCurrentThreadId(), 
IsapiFileList.GetAt(i));
-                       stress_main(IsapiFileList.GetAt(i), IsapiArgList.GetAt(i));
-                       //Sleep(10);
+                       stress_main(IsapiFileList.GetAt(i), 
+                                               IsapiGetData.GetAt(i), 
+                                               IsapiPostData.GetAt(i),
+                                               IsapiMatchData.GetAt(i),
+                                               TestNames.GetAt(i));
+                       Sleep(10);
                }
        }
        SetEvent(*terminate);
@@ -221,7 +430,12 @@
  * the DLL to load. There is no recompilation required.                    *
  * ======================================================================= *
 */
-int stress_main(const char *filename, const char *arg) {
+int stress_main(const char *filename, 
+                               const char *arg, 
+                               const char *postdata,
+                               const char *matchdata,
+                               const char *testname) 
+{
 
        EXTENSION_CONTROL_BLOCK ECB;
        DWORD rc;
@@ -231,13 +445,16 @@
        context.tid = GetCurrentThreadId();
        CString fname;
        fname.Format("%08X.out", context.tid);
+
        context.out = CreateFile(fname, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, 0, 
NULL);
        if (context.out==INVALID_HANDLE_VALUE) {
                printf("failed to open output file %s\n", fname);
                return 0;
        }
-       if (arg) context.in  = CreateFile(arg, GENERIC_READ, 0, NULL, OPEN_EXISTING, 
0, NULL);
-       else context.in = INVALID_HANDLE_VALUE;
+
+       // not using post files
+       context.in = INVALID_HANDLE_VALUE;
+
        //
        // Fill the ECB with the necessary information
        //
@@ -250,16 +467,54 @@
        // first arg = filename
        // this is added for testing php from command line
 
+       context.env.RemoveAll();
+       context.env["PATH_TRANSLATED"]= filename;
+       context.env["SCRIPT_MAP"]= filename;
+       context.env["CONTENT_TYPE"]= "";
+       context.env["CONTENT_LENGTH"]= "";
+       context.env["QUERY_STRING"]= arg;
+       context.env["METHOD"]="GET";
+
+       char buf[MAX_PATH];
+       if (postdata && *postdata !=0) {
+               ECB.cbAvailable = strlen(postdata);
+               ECB.cbTotalBytes = ECB.cbAvailable;
+               ECB.lpbData = (unsigned char *)postdata;
+               context.env["METHOD"]="POST";
+
+               _snprintf(buf, sizeof(buf)-1, "%d", ECB.cbTotalBytes);
+               context.env["CONTENT_LENGTH"]=buf;
+
+               context.env["CONTENT_TYPE"]="application/x-www-form-urlencoded";
+       }
     ECB.lpszPathTranslated = strdup(filename);
+       ECB.lpszQueryString = strdup(arg);
 
        // Call the DLL
        //
        rc = IsapiHttpExtensionProc(&ECB);
+
+       free(ECB.lpszPathTranslated);
+       free(ECB.lpszQueryString);
+
 
-       free (ECB.lpszPathTranslated);
+       // compare the output with the EXPECT section
+       if (matchdata && *matchdata != 0) {
+               // wimpy I know, but I'm tired and lazy now
+               HANDLE md = CreateFile(matchdata, GENERIC_READ, FILE_SHARE_READ, NULL, 
+OPEN_EXISTING, 0, NULL);
+               if (md) {
+                       DWORD osz = 0, msz = 0;
+                       GetFileSize(md, &msz);
+                       GetFileSize(context.out, &osz);
+                       if (osz == msz && osz != 0) {
+                               printf("%s OK\r\n", testname);
+                       } else {
+                               printf("%s FAILED\r\n", testname);
+                       }
+               }
+       }
 
        if (context.out) CloseHandle(context.out);
-       if (context.in) CloseHandle(context.in);
 
        //if (rc == HSE_STATUS_PENDING) // We will exit in ServerSupportFunction
        //      Sleep(INFINITE);
@@ -276,10 +531,15 @@
 
        DWORD rc;
        CString value;
+       TIsapiContext *c = (TIsapiContext *)hConn;
+       if (!c) return FALSE;
 
        if (IsapiEnvironment.Lookup(lpszVariableName, value)) {
                rc = value.GetLength();
                strncpy((char *)lpBuffer, value, *lpdwSize-1);
+       } else if (c->env.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 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 @@
                        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;
 }
 //
Index: php4/sapi/isapi/stresstest/stresstest.dsp
diff -u php4/sapi/isapi/stresstest/stresstest.dsp:1.1 
php4/sapi/isapi/stresstest/stresstest.dsp:1.2
--- php4/sapi/isapi/stresstest/stresstest.dsp:1.1       Sun Jan  7 15:52:18 2001
+++ php4/sapi/isapi/stresstest/stresstest.dsp   Sun Jan 14 16:29:49 2001
@@ -61,8 +61,9 @@
 # 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

-- 
PHP CVS Mailing List (http://www.php.net/)
To unsubscribe, e-mail: [EMAIL PROTECTED]
For additional commands, e-mail: [EMAIL PROTECTED]
To contact the list administrators, e-mail: [EMAIL PROTECTED]

Reply via email to