Commit: 3aca4906da0f27644e1e17039316358ff03b6404
Author: Matt Ficken <[email protected]> Fri, 2 Nov 2012
09:58:37 -0700
Parents: 9f9b1aba45852e608087bb9481307947df3b2223
Branches: master
Link:
http://git.php.net/?p=pftt2.git;a=commitdiff;h=3aca4906da0f27644e1e17039316358ff03b6404
Log:
php builtin web server testing support
Former-commit-id: 92565d723da8b9e71b596ab3798b64e7652b5d56
Changed paths:
M bin/pftt
M bin/pftt.cmd
M src/com/mostc/pftt/host/Host.java
M src/com/mostc/pftt/host/LocalHost.java
M src/com/mostc/pftt/model/phpt/EPhptSection.java
M src/com/mostc/pftt/model/phpt/PhpIni.java
M src/com/mostc/pftt/model/phpt/PhptTestCase.java
M src/com/mostc/pftt/model/sapi/BuiltinWebServerManager.java
M src/com/mostc/pftt/model/sapi/CrashedWebServerInstance.java
M src/com/mostc/pftt/model/sapi/WebServerInstance.java
M src/com/mostc/pftt/model/sapi/WebServerManager.java
M src/com/mostc/pftt/runner/AbstractPhptTestCaseRunner2.java
M src/com/mostc/pftt/runner/HttpTestCaseRunner.java
M src/com/mostc/pftt/runner/PhptTestPackRunner.java
M src/com/mostc/pftt/scenario/AbstractWebServerScenario.java
M src/com/mostc/pftt/scenario/BuiltinWebServerScenario.java
A src/com/mostc/pftt/telemetry/ConsoleManager.java
M src/com/mostc/pftt/telemetry/PhptTestResult.java
M src/com/mostc/pftt/ui/PhptHostTab.java
M src/com/mostc/pftt/util/HostEnvUtil.java
M src/com/mostc/pftt/util/StringUtil.java
diff --git a/bin/pftt b/bin/pftt
index dd82dd0..7004187 100644
--- a/bin/pftt
+++ b/bin/pftt
@@ -5,6 +5,6 @@
export PFTT_HOME=/home/matt/workspace/PFTT
export PFTT_LIB=$PFTT_HOME/lib
-export
CLASSPATH=$PFTT_HOME/build:$PFTT_LIB/htmlcleaner-2.2.jar:$PFTT_LIB/groovy-1.8.6.jar:$PFTT_LIB/icu4j-49_1.jar:$PFTT_LIB/icudata.jar:$PFTT_LIB/icutzdata.jar:$PFTT_LIB/j2ssh-common-0.2.9.jar:$PFTT_LIB/j2ssh-core-0.2.9.jar:$PFTT_LIB/jansi-1.7.jar:$PFTT_LIB/jline-0.9.94.jar:$PFTT_LIB/jzlib-1.0.7.jar:$PFTT_LIB/selenium-server-standalone-2.19.0.jar:$PFTT_LIB/xercesImpl.jar:$PFTT_LIB/xmlpull-1.1.3.1.jar:$PFTT_LIB/commons-net-3.1.jar:$PFTT_LIB/commons-cli-1.2.jar:$PFTT_LIB/antlr-2.7.7.jar:$PFTT_LIB/asm-3.2.jar:$PFTT_LIB/asm-analysis-3.2.jar:$PFTT_LIB/asm-commons-3.2.jar:$PFTT_LIB/asm-tree-3.2.jar:$PFTT_LIB/asm-util-3.2.jar
+export
CLASSPATH=$PFTT_HOME/build:$PFTT_LIB/winp-1.14.jar:$PFTT_LIB/htmlcleaner-2.2.jar:$PFTT_LIB/groovy-1.8.6.jar:$PFTT_LIB/icu4j-49_1.jar:$PFTT_LIB/icudata.jar:$PFTT_LIB/icutzdata.jar:$PFTT_LIB/j2ssh-common-0.2.9.jar:$PFTT_LIB/j2ssh-core-0.2.9.jar:$PFTT_LIB/jansi-1.7.jar:$PFTT_LIB/jline-0.9.94.jar:$PFTT_LIB/jzlib-1.0.7.jar:$PFTT_LIB/selenium-server-standalone-2.19.0.jar:$PFTT_LIB/xercesImpl.jar:$PFTT_LIB/xmlpull-1.1.3.1.jar:$PFTT_LIB/commons-net-3.1.jar:$PFTT_LIB/commons-cli-1.2.jar:$PFTT_LIB/antlr-2.7.7.jar:$PFTT_LIB/asm-3.2.jar:$PFTT_LIB/asm-analysis-3.2.jar:$PFTT_LIB/asm-commons-3.2.jar:$PFTT_LIB/asm-tree-3.2.jar:$PFTT_LIB/asm-util-3.2.jar
java -classpath $CLASSPATH com.mostc.pftt.main.PfttMain $*
diff --git a/bin/pftt.cmd b/bin/pftt.cmd
index a8b576c..1125891 100644
--- a/bin/pftt.cmd
+++ b/bin/pftt.cmd
@@ -4,7 +4,7 @@ REM script for running PFTT on Windows
SET PFTT_HOME=C:\php-sdk\PFTT\current
SET PFTT_LIB=%PFTT_HOME%\lib
-SET
CLASSPATH=%PFTT_HOME%\build;%PFTT_LIB%\htmlcleaner-2.2.jar;%PFTT_LIB%\groovy-1.8.6.jar;%PFTT_LIB%\icu4j-49_1.jar;%PFTT_LIB%\icudata.jar;%PFTT_LIB%\icutzdata.jar;%PFTT_LIB%\j2ssh-common-0.2.9.jar;%PFTT_LIB%\j2ssh-core-0.2.9.jar;%PFTT_LIB%\jansi-1.7.jar;%PFTT_LIB%\jline-0.9.94.jar;%PFTT_LIB%\jzlib-1.0.7.jar;%PFTT_LIB%\selenium-server-standalone-2.19.0.jar;%PFTT_LIB%\xercesImpl.jar;%PFTT_LIB%\xmlpull-1.1.3.1.jar;%PFTT_LIB%\commons-net-3.1.jar;%PFTT_LIB%\commons-cli-1.2.jar;%PFTT_LIB%\antlr-2.7.7.jar;%PFTT_LIB%\asm-3.2.jar;%PFTT_LIB%\asm-analysis-3.2.jar;%PFTT_LIB%\asm-commons-3.2.jar;%PFTT_LIB%\asm-tree-3.2.jar;%PFTT_LIB%\asm-util-3.2.jar
+SET
CLASSPATH=%PFTT_HOME%\build;%PFTT_LIB%\winp-1.14.jar;%PFTT_LIB%\htmlcleaner-2.2.jar;%PFTT_LIB%\groovy-1.8.6.jar;%PFTT_LIB%\icu4j-49_1.jar;%PFTT_LIB%\icudata.jar;%PFTT_LIB%\icutzdata.jar;%PFTT_LIB%\j2ssh-common-0.2.9.jar;%PFTT_LIB%\j2ssh-core-0.2.9.jar;%PFTT_LIB%\jansi-1.7.jar;%PFTT_LIB%\jline-0.9.94.jar;%PFTT_LIB%\jzlib-1.0.7.jar;%PFTT_LIB%\selenium-server-standalone-2.19.0.jar;%PFTT_LIB%\xercesImpl.jar;%PFTT_LIB%\xmlpull-1.1.3.1.jar;%PFTT_LIB%\commons-net-3.1.jar;%PFTT_LIB%\commons-cli-1.2.jar;%PFTT_LIB%\antlr-2.7.7.jar;%PFTT_LIB%\asm-3.2.jar;%PFTT_LIB%\asm-analysis-3.2.jar;%PFTT_LIB%\asm-commons-3.2.jar;%PFTT_LIB%\asm-tree-3.2.jar;%PFTT_LIB%\asm-util-3.2.jar
REM find java and execute PfttMain
REM search %PATH% for java
diff --git a/src/com/mostc/pftt/host/Host.java
b/src/com/mostc/pftt/host/Host.java
index 9bb148e..8c3cae9 100644
--- a/src/com/mostc/pftt/host/Host.java
+++ b/src/com/mostc/pftt/host/Host.java
@@ -9,6 +9,7 @@ import java.util.Random;
import java.util.regex.Pattern;
import javax.annotation.Nullable;
+import javax.annotation.concurrent.ThreadSafe;
import com.github.mattficken.io.ByLineReader;
@@ -309,6 +310,14 @@ public abstract class Host {
public boolean isLonghornExact() {
return false; // TODO
}
+ /** returns TRUE if host is Windows
+ *
+ * this is a fast method which caches its values, so you don't have to
do that in your code
+ *
+ * generally if !isWindows == isPosix
+ *
+ * @return
+ */
public abstract boolean isWindows();
public String getTempDir() {
if (tmp_dir!=null)
@@ -400,6 +409,7 @@ public abstract class Host {
public ExecOutput execElevated(String cmd, int timeout_sec, String
chdir) throws Exception {
return execElevated(cmd, timeout_sec, null, null, null, chdir,
null, NO_TIMEOUT);
}
+ @ThreadSafe
public static abstract class ExecHandle {
public abstract void close();
public abstract boolean isRunning();
@@ -645,5 +655,17 @@ public abstract class Host {
return 1;
}
}
+
+ /* TODO
+ public long getTotalPhysicalMemory() {
+ if (isWindows()) {
+ // could use `wmic` but that won't work on winxp, 2003,
2003r2
+ this.getSystemInfo();
+ // look for line like: `Total Physical Memory:
4,096 MB`
+ } else {
+ this.exec("free", NO_TIMEOUT);
+ }
+ }
+ */
} // end public abstract class Host
diff --git a/src/com/mostc/pftt/host/LocalHost.java
b/src/com/mostc/pftt/host/LocalHost.java
index efcc2e1..6ffd658 100644
--- a/src/com/mostc/pftt/host/LocalHost.java
+++ b/src/com/mostc/pftt/host/LocalHost.java
@@ -46,6 +46,15 @@ import com.sun.jna.platform.win32.WinNT.HANDLE;
public class LocalHost extends Host {
private static final Timer timer = new Timer();
private static final boolean is_windows =
System.getProperty("os.name").toLowerCase().contains("windows");
+ private static int self_process_id;
+ static {
+ try {
+ // this works only on Windows
+ self_process_id =
Kernel32.INSTANCE.GetCurrentProcessId();
+ } catch ( Throwable t ) {
+ t.printStackTrace(); // XXX fix this on Linux
+ }
+ }
public static boolean isLocalhostWindows() {
return is_windows;
@@ -195,16 +204,16 @@ public class LocalHost extends Host {
protected OutputStream stdin;
protected InputStream stdout, stderr;
protected ExitMonitorTask task;
- protected String cmdline;
+ protected String image_name;
protected Charset charset;
protected StringBuilder output_sb;
- public LocalExecHandle(Process process, OutputStream stdin,
InputStream stdout, InputStream stderr, String cmdline) {
+ public LocalExecHandle(Process process, OutputStream stdin,
InputStream stdout, InputStream stderr, String[] cmd_array) {
this.process = process;
this.stdin = stdin;
this.stdout = stdout;
this.stderr = stderr;
- this.cmdline = cmdline;
+ this.image_name =
StringUtil.unquote(basename(cmd_array[0]));
}
@Override
@@ -212,20 +221,22 @@ public class LocalHost extends Host {
try {
process.exitValue();
return false;
- } catch ( Exception ex ) {
+ } catch ( IllegalThreadStateException ex ) {
return true;
}
}
boolean run = true;
@Override
- public void close() {
+ public synchronized void close() {
run = false;
// may take multiple tries to make it exit (lots of
processes, certain OSes, etc...)
for ( int tries = 0 ; tries < 10 ; tries++ ) {
try {
process.exitValue();
+ break;
+ // process terminated, stop trying (or
may terminate new process reusing the same id)
} catch ( Throwable t ) {
// hasn't exited yet
if (tries==0) {
@@ -249,17 +260,21 @@ public class LocalHost extends Host {
// kill it
if (isLocalhostWindows()) {
+ // Windows BN: process trees on
Windows won't get terminated correctly by calling Process#destroy
+ //
+ // have to do some ugly hacks
on Windows to kill process trees
+ int process_id = 0;
+ // first: find the process id
try {
+ // clean way
WinProcess wproc = new
WinProcess(process);
- wproc.killRecursively();
+ process_id =
wproc.getPid();
} catch ( Throwable wt ) {
// WinProcess native
code couldn't be loaded
// (maybe it wasn't
included or maybe somebody didn't compile it)
//
// fallback on some old
code using reflection, etc...
- //
- // process.destroy
doesn't always work on windows, but TASKKILL does
try {
//
process.getClass() != Process.class
//
@@ -274,16 +289,7 @@ public class LocalHost extends Host {
HANDLE h = new HANDLE();
h.setPointer(Pointer.createConstant(handle));
-
long process_id = Kernel32.INSTANCE.GetProcessId(h);
-
-
-
// TASKKILL!=TSKILL, TASKKILL is better than TSKILL
-
//
-
// /F => forcefully terminate ('kill')
-
// /T => terminate all child processes (process is cmd.exe and PHP is a child)
-
// process.destory might not do this, so thats why its CRITICAL that
TASKKILL
-
// be tried before process.destroy
-
Runtime.getRuntime().exec("TASKKILL /PID:"+process_id+" /F /T");
+
process_id = Kernel32.INSTANCE.GetProcessId(h);
break;
}
@@ -292,6 +298,25 @@ public class LocalHost extends Host {
t2.printStackTrace();
} // end try
} // end try
+
+ // second: make sure we found a
process id (safety check: make sure its not our process id)
+ if (process_id != 0 &&
process_id!=self_process_id) {
+ // also,
WinProcess#killRecursively only checks by process id (not image/program name)
+ // while that should be
enough, experience on Windows has shown that it isn't and somehow gets PFTT
killed eventually
+ //
+ // third:instead, run
TASKKILL and provide it both the process id and image/program name
+ //
+ // image name: ex:
`php.exe`
+ // /F => forcefully
terminate ('kill')
+ // /T => terminate all
child processes (process is cmd.exe and PHP is a child)
+ // process.destory
might not do this, so thats why its CRITICAL that TASKKILL
+ // be tried before
process.destroy
+ try {
+
Runtime.getRuntime().exec("TASKKIll /FI \"IMAGENAME eq "+image_name+"\" /FI
\"PID eq "+process_id+"\" /F /T");
+ } catch (Throwable t3) {
+
t3.printStackTrace();
+ }
+ }
} // end if
//
@@ -441,7 +466,7 @@ public class LocalHost extends Host {
InputStream stdout = process.getInputStream();
InputStream stderr = process.getErrorStream();
- LocalExecHandle h = new LocalExecHandle(process, stdin, stdout,
stderr, StringUtil.toString(cmd_array));
+ LocalExecHandle h = new LocalExecHandle(process, stdin, stdout,
stderr, cmd_array);
if (timeout>NO_TIMEOUT) {
h.task = new ExitMonitorTask(h);
diff --git a/src/com/mostc/pftt/model/phpt/EPhptSection.java
b/src/com/mostc/pftt/model/phpt/EPhptSection.java
index e8dc93d..4c19044 100644
--- a/src/com/mostc/pftt/model/phpt/EPhptSection.java
+++ b/src/com/mostc/pftt/model/phpt/EPhptSection.java
@@ -20,48 +20,48 @@ public enum EPhptSection {
DESCRIPTION {
@Override
public String prepareSection(boolean keep_all, String text) {
- return keep_all?text:PhpIni.EMPTY;
+ return keep_all?text:StringUtil.EMPTY;
}
},
CREDITS {
@Override
public String prepareSection(boolean keep_all, String text) {
- return keep_all?text:PhpIni.EMPTY;
+ return keep_all?text:StringUtil.EMPTY;
}
},
/** not in documentation, de-facto */
FAIL {
@Override
public String prepareSection(boolean keep_all, String text) {
- return keep_all?text:PhpIni.EMPTY;
+ return keep_all?text:StringUtil.EMPTY;
}
},
/** not in documentation, de-facto */
CREDIT {
@Override
public String prepareSection(boolean keep_all, String text) {
- return keep_all?text:PhpIni.EMPTY;
+ return keep_all?text:StringUtil.EMPTY;
}
},
/** not in documentation, de-facto */
UEXPECTF {
@Override
public String prepareSection(boolean keep_all, String text) {
- return keep_all?text:PhpIni.EMPTY;
+ return keep_all?text:StringUtil.EMPTY;
}
},
/** not in documentation, de-facto */
DONE {
@Override
public String prepareSection(boolean keep_all, String text) {
- return keep_all?text:PhpIni.EMPTY;
+ return keep_all?text:StringUtil.EMPTY;
}
},
/** not in documentation, de-facto */
COMMENT {
@Override
public String prepareSection(boolean keep_all, String text) {
- return keep_all?text:PhpIni.EMPTY;
+ return keep_all?text:StringUtil.EMPTY;
}
},
SKIPIF,
@@ -130,13 +130,13 @@ public enum EPhptSection {
CGI {
@Override
public String prepareSection(boolean keep_all, String text) {
- return keep_all?text:PhpIni.EMPTY;
+ return keep_all?text:StringUtil.EMPTY;
}
},
XFAIL {
@Override
public String prepareSection(boolean keep_all, String text) {
- return keep_all?text:PhpIni.EMPTY;
+ return keep_all?text:StringUtil.EMPTY;
}
},
EXPECTHEADERS,
diff --git a/src/com/mostc/pftt/model/phpt/PhpIni.java
b/src/com/mostc/pftt/model/phpt/PhpIni.java
index 88dbd78..634d7cc 100644
--- a/src/com/mostc/pftt/model/phpt/PhpIni.java
+++ b/src/com/mostc/pftt/model/phpt/PhpIni.java
@@ -58,9 +58,6 @@ public class PhpIni extends TestCaseGroupKey {
public static final String UNICODE_OUTPUT_ENCODING =
"unicode.output_encoding";
public static final String UNICODE_FROM_ERROR_MODE =
"unicode.from_error_mode";
public static final String SESSION_AUTO_START = "session.auto_start";
- //
- // values
- public static final String EMPTY = "";
public static final String ON = "On";
public static final String OFF = "Off";
public static final String UTF_8 = "UTF-8";
@@ -101,10 +98,10 @@ public class PhpIni extends TestCaseGroupKey {
public static final String EXT_XSL = dllName("xsl");
public static PhpIni createDefaultIniCopy(Host host) {
PhpIni ini = new PhpIni();
- ini.putMulti(OUTPUT_HANDLER, EMPTY);
- ini.putMulti(OPEN_BASEDIR, EMPTY);
+ ini.putMulti(OUTPUT_HANDLER, StringUtil.EMPTY);
+ ini.putMulti(OPEN_BASEDIR, StringUtil.EMPTY);
ini.putMulti(SAFE_MODE, 0);
- ini.putMulti(DISABLE_DEFS, EMPTY);
+ ini.putMulti(DISABLE_DEFS, StringUtil.EMPTY);
ini.putMulti(OUTPUT_BUFFERING, OFF);
ini.putMulti(ERROR_REPORTING, E_ALL_OR_E_STRICT);
// IMPORTANT: display_errors=0. doesn't affect test output.
run-tests.php sets display_errors=1
@@ -116,12 +113,12 @@ public class PhpIni extends TestCaseGroupKey {
ini.putMulti(TRACK_ERRORS, 1);
ini.putMulti(REPORT_MEMLEAKS, 1);
ini.putMulti(REPORT_ZEND_DEBUG, 0);
- ini.putMulti(DOCREF_ROOT, EMPTY);
+ ini.putMulti(DOCREF_ROOT, StringUtil.EMPTY);
ini.putMulti(DOCREF_EXT, DOT_HTML);
- ini.putMulti(ERROR_PREPEND_STRING, EMPTY);
- ini.putMulti(ERROR_APPEND_STRING, EMPTY);
- ini.putMulti(AUTO_PREPEND_FILE, EMPTY);
- ini.putMulti(AUTO_APPEND_FILE, EMPTY);
+ ini.putMulti(ERROR_PREPEND_STRING, StringUtil.EMPTY);
+ ini.putMulti(ERROR_APPEND_STRING, StringUtil.EMPTY);
+ ini.putMulti(AUTO_PREPEND_FILE, StringUtil.EMPTY);
+ ini.putMulti(AUTO_APPEND_FILE, StringUtil.EMPTY);
ini.putMulti(MAGIC_QUOTES_RUNTIME, 0);
ini.putMulti(IGNORE_REPEATED_ERRORS, 0);
ini.putMulti(PRECISION, 14);
@@ -167,7 +164,7 @@ public class PhpIni extends TestCaseGroupKey {
int ini_i = line.indexOf("=");
if (ini_i!=-1) {
String ini_name = line.substring(0,
ini_i).trim();
- String ini_value = ini_i+1>=line.length() ?
EMPTY : line.substring(ini_i+1).trim();
+ String ini_value = ini_i+1>=line.length() ?
StringUtil.EMPTY : line.substring(ini_i+1).trim();
putMulti(ini_name, ini_value);
}
}
diff --git a/src/com/mostc/pftt/model/phpt/PhptTestCase.java
b/src/com/mostc/pftt/model/phpt/PhptTestCase.java
index f2a116d..a226017 100644
--- a/src/com/mostc/pftt/model/phpt/PhptTestCase.java
+++ b/src/com/mostc/pftt/model/phpt/PhptTestCase.java
@@ -9,6 +9,9 @@ import java.util.HashMap;
import java.util.Set;
import java.util.regex.Pattern;
+import javax.annotation.Nonnull;
+import javax.annotation.Nullable;
+
import com.github.mattficken.io.AbstractDetectingCharsetReader;
import com.github.mattficken.io.ByLineReader;
import com.github.mattficken.io.CharsetDeciderDecoder;
@@ -451,16 +454,20 @@ public class PhptTestCase extends TestCase {
* @return
* @see #get
*/
+ @Nonnull
public String getTrim(EPhptSection section) {
String t = get(section);
- return StringUtil.isEmpty(t) ? t : t.trim();
+ return StringUtil.isEmpty(t) ? StringUtil.EMPTY : t.trim();
}
/** returns the text of the section unmodified
*
+ * returns null if section not found
+ *
* @param section
* @return
*/
+ @Nullable
public String get(EPhptSection section) {
return section_text.get(section);
}
diff --git a/src/com/mostc/pftt/model/sapi/BuiltinWebServerManager.java
b/src/com/mostc/pftt/model/sapi/BuiltinWebServerManager.java
index d7d3013..4fb8979 100644
--- a/src/com/mostc/pftt/model/sapi/BuiltinWebServerManager.java
+++ b/src/com/mostc/pftt/model/sapi/BuiltinWebServerManager.java
@@ -40,7 +40,11 @@ public class BuiltinWebServerManager extends
WebServerManager {
Runtime.getRuntime().addShutdownHook(new Thread() {
@Override
public void run() {
+ System.out.println("PFTT: terminating
builtin web server instances...");
// Windows BN: may leave `php.exe -S`
running if they aren't terminated here
+ // NOTE: if you click stop in Eclipse,
you won't get here
+ // on Windows, that means that `php.exe
-S` instances will still be running
+ // you'll need to do: taskkill
/im:php.exe /f /t
close();
}
});
@@ -52,7 +56,8 @@ public class BuiltinWebServerManager extends WebServerManager
{
String sapi_output = "";
int port_attempts;
boolean found_port;
- for (int total_attempts = 0 ; total_attempts < 3 ;
total_attempts++) {
+ int total_attempts = 0;
+ for ( ; total_attempts < 3 ; total_attempts++) {
// find port number not currently in use
port_attempts = 0;
@@ -97,7 +102,7 @@ public class BuiltinWebServerManager extends
WebServerManager {
//
// provide a BuiltinWebServerInstance to handle
the running web server instance
- final BuiltinWebServerInstance web = new
BuiltinWebServerInstance(LocalHost.splitCmdString(cmd), ini, handle, hostname,
last_port);
+ final BuiltinWebServerInstance web = new
BuiltinWebServerInstance(this, LocalHost.splitCmdString(cmd), ini, handle,
hostname, last_port);
// check web server periodically to see if it
has crashed
timer.scheduleAtFixedRate(new TimerTask() {
@@ -130,19 +135,19 @@ public class BuiltinWebServerManager extends
WebServerManager {
} // end for
// fallback
- sapi_output += "PFTT: wasn't able to start web server instance
(after many attempts)... giving up.\n";
+ sapi_output += "PFTT: wasn't able to start web server instance
(after "+total_attempts+" attempts)... giving up.\n";
// return this failure message to client code
- return new CrashedWebServerInstance(ini, sapi_output);
+ return new CrashedWebServerInstance(this, ini, sapi_output);
} // end protected synchronized WebServerInstance
createWebServerInstance
- public class BuiltinWebServerInstance extends WebServerInstance {
+ public static class BuiltinWebServerInstance extends WebServerInstance {
protected final int port;
protected final String hostname;
protected final ExecHandle process;
- public BuiltinWebServerInstance(String[] cmd_array, PhpIni ini,
ExecHandle process, String hostname, int port) {
- super(cmd_array, ini);
+ public BuiltinWebServerInstance(BuiltinWebServerManager ws_mgr,
String[] cmd_array, PhpIni ini, ExecHandle process, String hostname, int port) {
+ super(ws_mgr, cmd_array, ini);
this.process = process;
this.hostname = hostname;
this.port = port;
@@ -159,19 +164,13 @@ public class BuiltinWebServerManager extends
WebServerManager {
}
@Override
- public void close() {
- try {
- process.close();
- } finally {
-
synchronized(BuiltinWebServerManager.this.instances) {
-
BuiltinWebServerManager.this.instances.remove(this);
- }
- }
+ protected void do_close() {
+ process.close();
}
@Override
public boolean isRunning() {
- return process.isRunning();
+ return process.isRunning() && !isCrashed();
}
} // end public class BuiltinWebServerInstance
diff --git a/src/com/mostc/pftt/model/sapi/CrashedWebServerInstance.java
b/src/com/mostc/pftt/model/sapi/CrashedWebServerInstance.java
index 154ea27..1bf6a14 100644
--- a/src/com/mostc/pftt/model/sapi/CrashedWebServerInstance.java
+++ b/src/com/mostc/pftt/model/sapi/CrashedWebServerInstance.java
@@ -14,8 +14,8 @@ import com.mostc.pftt.model.phpt.PhpIni;
public class CrashedWebServerInstance extends WebServerInstance {
protected final String sapi_output;
- public CrashedWebServerInstance(PhpIni ini, String sapi_output) {
- super(null, ini);
+ public CrashedWebServerInstance(WebServerManager ws_mgr, PhpIni ini,
String sapi_output) {
+ super(ws_mgr, null, ini);
this.sapi_output = sapi_output;
}
@@ -43,4 +43,9 @@ public class CrashedWebServerInstance extends
WebServerInstance {
return false;
}
+ @Override
+ protected void do_close() {
+ // N/A
+ }
+
}
diff --git a/src/com/mostc/pftt/model/sapi/WebServerInstance.java
b/src/com/mostc/pftt/model/sapi/WebServerInstance.java
index f115cb9..0d821a7 100644
--- a/src/com/mostc/pftt/model/sapi/WebServerInstance.java
+++ b/src/com/mostc/pftt/model/sapi/WebServerInstance.java
@@ -1,6 +1,8 @@
package com.mostc.pftt.model.sapi;
+import java.util.ArrayList;
import java.util.LinkedList;
+import java.util.List;
import javax.annotation.concurrent.ThreadSafe;
@@ -17,18 +19,21 @@ import com.mostc.pftt.util.StringUtil;
@ThreadSafe
public abstract class WebServerInstance extends SAPIInstance {
- protected LinkedList<PhptTestCase> active_test_cases;
+ protected final List<PhptTestCase> active_test_cases, all_test_cases;
private boolean crashed = false;
private String sapi_output = "";
private Object sync_lock = new Object();
protected final PhpIni ini;
protected final String[] cmd_array;
+ protected final WebServerManager ws_mgr;
WebServerInstance replacement; // @see
WebServerManager#getWebServerInstance
- public WebServerInstance(String[] cmd_array, PhpIni ini) {
+ public WebServerInstance(WebServerManager ws_mgr, String[] cmd_array,
PhpIni ini) {
+ this.ws_mgr = ws_mgr;
this.cmd_array = cmd_array;
this.ini = ini;
active_test_cases = new LinkedList<PhptTestCase>();
+ all_test_cases = new ArrayList<PhptTestCase>(256);
}
@Override
@@ -60,6 +65,8 @@ public abstract class WebServerInstance extends SAPIInstance {
* @param exit_code - exit code that was returned
*/
public void notifyCrash(String output, int exit_code) {
+ // make sure it gets closed!!
+ // TODO temp vs close();
synchronized(sync_lock) {
//
if (crashed) {
@@ -68,7 +75,7 @@ public abstract class WebServerInstance extends SAPIInstance {
StringBuilder sb = new StringBuilder();
if (sapi_output!=null)
sb.append(sapi_output);
- sb.append("PFTT: later web server
returned exit code("+exit_code+") and output:\n");
+ sb.append("\nPFTT: later web server
returned exit code("+exit_code+") and output:\n");
sb.append(output);
sapi_output = sb.toString();
}
@@ -81,8 +88,9 @@ public abstract class WebServerInstance extends SAPIInstance {
StringBuilder sb = new StringBuilder(1024);
- sb.append("PFTT: web server crashed with exit code:
"+exit_code);
+ sb.append("PFTT: web server crashed with exit code:
"+exit_code+"\n");
getActiveTestListString(sb);
+ getAllTestListString(sb);
if (StringUtil.isEmpty(output)) {
sb.append("PFTT: web server returned no output
when it exited.\n");
} else {
@@ -94,7 +102,7 @@ public abstract class WebServerInstance extends SAPIInstance
{
} // end sync
} // end protected void notifyCrash
- protected void getActiveTestListString(StringBuilder sb) {
+ public void getActiveTestListString(StringBuilder sb) {
synchronized(active_test_cases) {
sb.append("PFTT: while running these
tests("+active_test_cases.size()+"):\n");
for (PhptTestCase test_case : active_test_cases ) {
@@ -111,11 +119,31 @@ public abstract class WebServerInstance extends
SAPIInstance {
return sb.toString();
}
+ public void getAllTestListString(StringBuilder sb) {
+ synchronized(all_test_cases) {
+ sb.append("PFTT: these tests were run against this web
server instance during its lifetime("+all_test_cases.size()+"):\n");
+ for (PhptTestCase test_case : all_test_cases ) {
+ sb.append("PFTT: ");
+ sb.append(test_case.getName());
+ sb.append('\n');
+ }
+ }
+ }
+
+ public String getAllTestListString() {
+ StringBuilder sb = new StringBuilder(512);
+ getAllTestListString(sb);
+ return sb.toString();
+ }
+
/** called before HTTP request made to server for given test_case
*
* @param test_case
*/
public void notifyTestPreRequest(PhptTestCase test_case) {
+ synchronized(all_test_cases) {
+ all_test_cases.add(test_case);
+ }
synchronized(active_test_cases) {
active_test_cases.add(test_case);
}
@@ -161,4 +189,20 @@ public abstract class WebServerInstance extends
SAPIInstance {
return cmd_array;
}
+ @Override
+ public void close() {
+ try {
+ do_close();
+ } finally {
+ synchronized(ws_mgr.instances) {
+ ws_mgr.instances.remove(this);
+ }
+ }
+ // TODO temp
+ for ( WebServerInstance c=replacement ; c != null ; c =
c.replacement )
+ c.close();
+ }
+
+ protected abstract void do_close();
+
} // end public abstract class WebServerInstance
diff --git a/src/com/mostc/pftt/model/sapi/WebServerManager.java
b/src/com/mostc/pftt/model/sapi/WebServerManager.java
index 195c57c..1b060a9 100644
--- a/src/com/mostc/pftt/model/sapi/WebServerManager.java
+++ b/src/com/mostc/pftt/model/sapi/WebServerManager.java
@@ -2,7 +2,6 @@ package com.mostc.pftt.model.sapi;
import java.io.IOException;
import java.net.Socket;
-import java.util.Iterator;
import java.util.LinkedList;
import javax.annotation.concurrent.ThreadSafe;
@@ -32,11 +31,9 @@ public abstract class WebServerManager extends SAPIManager {
*/
public void close() {
synchronized(instances) {
- Iterator<WebServerInstance> it = instances.iterator();
- while (it.hasNext()) {
- it.next().close();
- it.remove();
- }
+ for ( WebServerInstance wsi : instances )
+ wsi.do_close();
+ instances.clear();
}
}
@@ -60,12 +57,12 @@ public abstract class WebServerManager extends SAPIManager {
public WebServerInstance getWebServerInstance(Host host, PhpBuild
build, PhpIni ini, String docroot, WebServerInstance assigned) {
WebServerInstance sapi;
if (assigned!=null) {
- if (!assigned.isCrashed())
+ if (assigned.isRunning())
return assigned;
synchronized(assigned) {
for (WebServerInstance c=assigned.replacement ;
c != null ; c = c.replacement) {
synchronized(c) {
- if (!c.isCrashed())
+ if (assigned.isRunning())
return c;
}
}
@@ -77,7 +74,7 @@ public abstract class WebServerManager extends SAPIManager {
} else {
sapi = createWebServerInstance(host, build, ini,
docroot);
}
- if (!sapi.isCrashed()) {
+ if (sapi.isRunning()) {
synchronized(instances) {
instances.add(sapi);
}
diff --git a/src/com/mostc/pftt/runner/AbstractPhptTestCaseRunner2.java
b/src/com/mostc/pftt/runner/AbstractPhptTestCaseRunner2.java
index 041d692..5df370e 100644
--- a/src/com/mostc/pftt/runner/AbstractPhptTestCaseRunner2.java
+++ b/src/com/mostc/pftt/runner/AbstractPhptTestCaseRunner2.java
@@ -9,6 +9,8 @@ import java.util.regex.Pattern;
import java.util.zip.Deflater;
import java.util.zip.DeflaterOutputStream;
+import javax.annotation.Nonnull;
+
import org.incava.util.diff.Diff;
import com.mostc.pftt.host.Host;
@@ -122,7 +124,7 @@ public abstract class AbstractPhptTestCaseRunner2 extends
AbstractPhptTestCaseRu
//
if (host.isWindows() &&
test_case.containsSection(EPhptSection.SKIPIF)) {
// do an early quick check
- // fixes problem with Sapi/cli/tests/021.phpt
+ // fixes problem with sapi/cli/tests/021.phpt
if (test_case.get(EPhptSection.SKIPIF).contains("skip
not for Windows")) {
twriter.addResult(new PhptTestResult(host,
EPhptTestStatus.XSKIP, test_case, "skip not for Windows", null, null, null,
null, null, null, null, null, null, null));
@@ -458,10 +460,13 @@ public abstract class AbstractPhptTestCaseRunner2 extends
AbstractPhptTestCaseRu
protected abstract void prepareSTDIN() throws IOException;
/** executes the test (the TEST section of PhptTestCase) and returns
the actual output
+ *
+ * must not return null
*
* @return
* @throws Exception
*/
+ @Nonnull
protected abstract String executeTest() throws Exception;
/** executes CLEAN section of test to cleanup after execution
@@ -512,7 +517,7 @@ public abstract class AbstractPhptTestCaseRunner2 extends
AbstractPhptTestCaseRu
twriter.show_exception(test_case, ex, expected);
throw ex;
}
- if (expected_re_match) {
+ if (expected_re_match||check()) {
twriter.addResult(new PhptTestResult(host,
test_case.isXFail()?EPhptTestStatus.XFAIL:EPhptTestStatus.PASS, test_case,
output, null, null, charset, env, splitCmdString(), stdin_post, shell_script,
null, null, null));
@@ -524,7 +529,7 @@ public abstract class AbstractPhptTestCaseRunner2 extends
AbstractPhptTestCaseRu
output = remove_header_from_output(output);
output_trim = output.trim();
- if
(output_trim.equals(expected)||output_trim.contains(expected)||expected.contains(output_trim))
{
+ if
(output_trim.equals(expected)||output_trim.contains(expected)||expected.contains(output_trim)||check())
{
twriter.addResult(new PhptTestResult(host,
test_case.isXFail()?EPhptTestStatus.XFAIL:EPhptTestStatus.PASS, test_case,
output, null, null, charset, env, splitCmdString(), stdin_post, shell_script,
null, null, null));
@@ -534,9 +539,13 @@ public abstract class AbstractPhptTestCaseRunner2 extends
AbstractPhptTestCaseRu
preoverride_actual = output_trim;
output_trim =
PhptOverrideManager.replaceWithExactOverrides(host, output_trim);
- if (output_trim!=null) {
+ if (output_trim==null) {
+ // no output overrides for this phpt on this OS
+ //
+ // fall through to failing or xfailing the test
+ } else {
// compare again
- if
(output_trim.equals(expected)||output_trim.contains(expected)||expected.contains(output_trim)||(output_trim.length()>20&&expected.length()>20&&output_trim.substring(10,
20).equals(expected.substring(10, 20)))) {
+ if
(output_trim.equals(expected)||output_trim.contains(expected)||expected.contains(output_trim)||(output_trim.length()>20&&expected.length()>20&&output_trim.substring(10,
20).equals(expected.substring(10, 20)))||check()) {
twriter.addResult(new
PhptTestResult(host,
test_case.isXFail()?EPhptTestStatus.XFAIL:EPhptTestStatus.PASS, test_case,
output, null, null, charset, env, splitCmdString(), stdin_post, shell_script,
null, null, null));
@@ -547,7 +556,7 @@ public abstract class AbstractPhptTestCaseRunner2 extends
AbstractPhptTestCaseRu
output = remove_header_from_output(output);
output_trim = output.trim();
- if (StringUtil.isEmpty(output_trim)) {
+ if (StringUtil.isEmpty(output_trim)||check()) {
twriter.addResult(new PhptTestResult(host,
test_case.isXFail()?EPhptTestStatus.XFAIL:EPhptTestStatus.PASS, test_case,
output, null, null, charset, env, splitCmdString(), stdin_post, shell_script,
null, null, null));
return;
@@ -577,6 +586,11 @@ public abstract class AbstractPhptTestCaseRunner2 extends
AbstractPhptTestCaseRu
twriter.addResult(new PhptTestResult(host,
EPhptTestStatus.FAIL, test_case, output, actual_lines, expected_lines, charset,
env, splitCmdString(), stdin_post, shell_script, diff, expectf,
preoverride_actual, getCrashedSAPIOutput()));
}
} // end void evalTest
+
+ protected boolean check() {
+ // TODO temp
+ return StringUtil.isEmpty(getCrashedSAPIOutput());
+ }
protected abstract String[] splitCmdString();
diff --git a/src/com/mostc/pftt/runner/HttpTestCaseRunner.java
b/src/com/mostc/pftt/runner/HttpTestCaseRunner.java
index 03aa9f2..311f071 100644
--- a/src/com/mostc/pftt/runner/HttpTestCaseRunner.java
+++ b/src/com/mostc/pftt/runner/HttpTestCaseRunner.java
@@ -3,30 +3,18 @@ package com.mostc.pftt.runner;
import java.io.IOException;
import java.net.Socket;
-import org.apache.http.ConnectionReuseStrategy;
import org.apache.http.HttpHost;
-import org.apache.http.HttpRequestInterceptor;
import org.apache.http.HttpResponse;
-import org.apache.http.HttpVersion;
import org.apache.http.entity.ByteArrayEntity;
-import org.apache.http.impl.DefaultConnectionReuseStrategy;
import org.apache.http.impl.DefaultHttpClientConnection;
import org.apache.http.message.BasicHttpEntityEnclosingRequest;
import org.apache.http.message.BasicHttpRequest;
import org.apache.http.params.HttpParams;
-import org.apache.http.params.HttpProtocolParams;
-import org.apache.http.params.SyncBasicHttpParams;
import org.apache.http.protocol.BasicHttpContext;
import org.apache.http.protocol.ExecutionContext;
import org.apache.http.protocol.HttpContext;
import org.apache.http.protocol.HttpProcessor;
import org.apache.http.protocol.HttpRequestExecutor;
-import org.apache.http.protocol.ImmutableHttpProcessor;
-import org.apache.http.protocol.RequestConnControl;
-import org.apache.http.protocol.RequestContent;
-import org.apache.http.protocol.RequestExpectContinue;
-import org.apache.http.protocol.RequestTargetHost;
-import org.apache.http.protocol.RequestUserAgent;
import com.github.mattficken.io.IOUtil;
import com.mostc.pftt.host.Host;
@@ -41,6 +29,7 @@ import com.mostc.pftt.runner.PhptTestPackRunner.PhptThread;
import com.mostc.pftt.scenario.ScenarioSet;
import com.mostc.pftt.telemetry.PhptTelemetryWriter;
import com.mostc.pftt.telemetry.PhptTestResult;
+import com.mostc.pftt.util.ErrorUtil;
/** Runs PHPT Test Cases against PHP while its running under a Web Server
(builtin, IIS or Apache)
*
@@ -50,10 +39,16 @@ import com.mostc.pftt.telemetry.PhptTestResult;
public class HttpTestCaseRunner extends AbstractPhptTestCaseRunner2 {
protected final WebServerManager smgr;
+ protected final HttpParams params;
+ protected final HttpProcessor httpproc;
+ protected final HttpRequestExecutor httpexecutor;
protected WebServerInstance web = null;
- public HttpTestCaseRunner(WebServerManager smgr, WebServerInstance web,
PhptThread thread, PhptTestCase test_case, PhptTelemetryWriter twriter, Host
host, ScenarioSet scenario_set, PhpBuild build, PhptTestPack test_pack) {
+ public HttpTestCaseRunner(HttpParams params, HttpProcessor httpproc,
HttpRequestExecutor httpexecutor, WebServerManager smgr, WebServerInstance web,
PhptThread thread, PhptTestCase test_case, PhptTelemetryWriter twriter, Host
host, ScenarioSet scenario_set, PhpBuild build, PhptTestPack test_pack) {
super(web.getPhpIni(), thread, test_case, twriter, host,
scenario_set, build, test_pack);
+ this.params = params;
+ this.httpproc = httpproc;
+ this.httpexecutor = httpexecutor;
this.smgr = smgr;
this.web = web;
}
@@ -71,96 +66,95 @@ public class HttpTestCaseRunner extends
AbstractPhptTestCaseRunner2 {
return false;
}
- @Override
- public boolean prepare() throws IOException, Exception {
- if (!super.prepare())
- return false;
-
- // #super.prepare sets ini already
- //
- // all we need to do is manage the web server and http requests
- //
- // make sure a web server is running
- web = smgr.getWebServerInstance(host, build, ini,
test_pack.getTestPack(), web);
-
- return true;
- }
-
/** executes SKIPIF, TEST or CLEAN over http.
*
* retries request if it times out and restarts web server if it crashes
*
* @param path
- * @param is_test
+ * @param section
* @return
* @throws Exception
*/
- protected String http_execute(String path, boolean is_test) throws
Exception {
+ protected String http_execute(String path, EPhptSection section) throws
Exception {
try {
- // "PFTT: server failed to respond at all after
ONE_MINUTE. server was restarted and failed to respond at all a second time
after ONE_MINUTE";
- // "PFTT: server failed to send all of its response
after ONE_MINUTE. server was restarted and failed to send all of its response a
second time after ONE_MINUTE";
try {
- return do_http_execute(path, is_test);
+ return do_http_execute(path, section, false);
} catch ( IOException ex1 ) { // SocketTimeoutException
or ConnectException
+ // notify of crash so it gets reported
everywhere
+ web.notifyCrash("PFTT: timeout during
test("+section+" SECTION): "+test_case.getName()+"\n"+ErrorUtil.toString(ex1),
0);
+ // TODO temp VS
web.close();
- // stop web server, try again
- web = smgr.getWebServerInstance(host, build,
ini, test_pack.getTestPack(), web);
- try {
- return do_http_execute(path, is_test);
- } catch ( IOException ex2 ) { //
SocketTimeoutException or ConnectException
- web.close();
- // stop web server, try again
- web = smgr.getWebServerInstance(host,
build, ini, test_pack.getTestPack(), web);
- try {
- return do_http_execute(path,
is_test);
- } catch ( IOException ex3 ) { //
SocketTimeoutException or ConnectException
- web.close();
- // stop web server, try again
- // TODO temp null
- web =
smgr.getWebServerInstance(host, build, ini, test_pack.getTestPack(), web);
- try {
- return
do_http_execute(path, is_test);
- } finally {
- web.close();
- }
- }
- }
+
+ System.out.println("RESTART_AND_RETRY
"+test_case.getName());
+
+ // get #do_http_execute to make a new server
+ // this will make a new WebServerInstance that
will only be used to run this 1 test
+ // (so other tests will not interfere with this
test at all)
+ web = null;
+ return do_http_execute(path, section, true);
}
} catch ( IOException ioe ) {
- // wrap IOException with list of tests that are running
against this web server
- // so we can tell what test(s) may be causing server to
not respond
+ String ex_str = ErrorUtil.toString(ioe);
- // TODO comment
+ // notify web server that it crashed. it will record
this, which will be accessible
+ // with WebServerInstance#getSAPIOutput (will be
recorded by PhptTelemetryWriter)
+ web.notifyCrash("PFTT: IOException during
test("+section+" SECTION): "+test_case.getName()+"\n"+ex_str, 0);
- web.notifyCrash("", 0);
+ // generate a failure string here too though, so that
this TEST or SKIPIF section is marked as a failure
+ StringBuilder sb = new StringBuilder(512);
+ sb.append("PFTT: couldn't connect to server after One
Minute\n");
+ sb.append("PFTT: created new server only for running
this test which did not respond after another One Minute timeout\n");
+ sb.append("PFTT: was trying to run ("+section+" section
of): ");
+ sb.append(test_case.getName());
+ sb.append("\n");
+ sb.append("PFTT: these two lists refer only to second
server (created for specifically for only this test)\n");
+ web.getActiveTestListString(sb);
+ web.getAllTestListString(sb);
- String ex_str = "PFTT: couldn't connect to server after
4 tries (and 3 restarts), assuming crashed.\nPFTT: was trying to test (TEST
section of): "+test_case.getName()+"\n"+web.getActiveTestListString();
-
- if (is_test) {
- this.twriter.addResult(new PhptTestResult(host,
EPhptTestStatus.EXCEPTION, test_case, ex_str, null, null, null, null, null,
null, null, null, null, null, ex_str));
-
- return ex_str;
- }
-
- throw new IOException(ex_str, ioe);
+ // if TEST, runner will evaluate this as a failure
+ // if SKIPIF, runner will not skip test and will try to
run it
+ //
+ // both are the most ideal behavior possible in this
situation
+ //
+ // normally this shouldn't happen, so checking a string
once in a while is faster than
+ // setting a flag here and checking that flag for
every test in #evalTest
+ return sb.toString();
}
} // end protected String http_execute
- protected String do_http_execute(String path, boolean is_test) throws
Exception {
- // make sure a web server is running
- web = smgr.getWebServerInstance(host, build, ini,
test_pack.getTestPack(), web);
- if (web.isCrashed())
- // test will fail
- return "PFTT: server crashed already, didn't bother
trying to execute test";
-
- if (stdin_post==null)
- return do_http_get(path);
- else
- return do_http_post(path);
+ protected String do_http_execute(String path, EPhptSection section,
boolean is_replacement) throws Exception {
+ {
+ WebServerInstance _web =
smgr.getWebServerInstance(host, build, ini, test_pack.getTestPack(), web);
+ if (_web!=web) {
+ this.web = _web;
+ is_replacement = true;
+ // make sure this test case is in the list
+ _web.notifyTestPreRequest(test_case);
+ }
+ }
+ try {
+ if (web.isCrashed())
+ // test will fail (because this(`PFTT:
server...`) is the actual output which won't match the expected output)
+ //
+ // return server's crash output and an
additional message about this test
+ return web.getSAPIOutput() + "PFTT: server
crashed already, didn't bother trying to execute test: "+test_case.getName();
+
+
+ if (stdin_post==null || section != EPhptSection.TEST)
+ return do_http_get(path);
+ else
+ // only do POST for TEST sections where
stdin_post!=null
+ return do_http_post(path);
+ } finally {
+ if (is_replacement)
+ // CRITICAL: if this WebServerInstance is a
replacement, then it exists only within this specific HttpTestCaseRunner
+ // instance. if it is not terminated here, it
will keep running forever!
+ web.close();
+ }
}
protected String do_http_get(String path) throws Exception {
- HttpParams params = new SyncBasicHttpParams();
+ /*HttpParams params = new SyncBasicHttpParams();
HttpProtocolParams.setVersion(params, HttpVersion.HTTP_1_1);
HttpProtocolParams.setContentCharset(params, "UTF-8");
HttpProtocolParams.setUserAgent(params, "Mozilla/5.0 (Windows
NT 6.1; rv:12.0) Gecko/ 20120405 Firefox/14.0.1");
@@ -175,13 +169,13 @@ public class HttpTestCaseRunner extends
AbstractPhptTestCaseRunner2 {
new RequestUserAgent(),
new RequestExpectContinue()});
- HttpRequestExecutor httpexecutor = new HttpRequestExecutor();
+ HttpRequestExecutor httpexecutor = new HttpRequestExecutor();*/
HttpContext context = new BasicHttpContext(null);
HttpHost http_host = new HttpHost(web.hostname(), web.port());
DefaultHttpClientConnection conn = new
DefaultHttpClientConnection();
- ConnectionReuseStrategy connStrategy = new
DefaultConnectionReuseStrategy();
+ //ConnectionReuseStrategy connStrategy = new
DefaultConnectionReuseStrategy();
context.setAttribute(ExecutionContext.HTTP_CONNECTION, conn);
context.setAttribute(ExecutionContext.HTTP_TARGET_HOST,
http_host);
@@ -213,13 +207,13 @@ public class HttpTestCaseRunner extends
AbstractPhptTestCaseRunner2 {
} // end protected String do_http_get
protected String do_http_post(String path) throws Exception {
- HttpParams params = new SyncBasicHttpParams();
+ /*HttpParams params = new SyncBasicHttpParams();
HttpProtocolParams.setVersion(params, HttpVersion.HTTP_1_1);
HttpProtocolParams.setContentCharset(params, "UTF-8");
HttpProtocolParams.setUserAgent(params, "Mozilla/5.0 (Windows
NT 6.1; rv:12.0) Gecko/ 20120405 Firefox/14.0.1");
HttpProtocolParams.setUseExpectContinue(params, true);
- if (content_type!=null)
- params.setParameter("Content-Type", content_type);
+ // TODO if (content_type!=null)
+ // params.setParameter("Content-Type", content_type);
HttpProcessor httpproc = new ImmutableHttpProcessor(new
HttpRequestInterceptor[] {// XXX reuse
// Required protocol interceptors
@@ -230,13 +224,13 @@ public class HttpTestCaseRunner extends
AbstractPhptTestCaseRunner2 {
new RequestUserAgent(),
new RequestExpectContinue()});
- HttpRequestExecutor httpexecutor = new HttpRequestExecutor();
+ HttpRequestExecutor httpexecutor = new HttpRequestExecutor();*/
HttpContext context = new BasicHttpContext(null);
HttpHost http_host = new HttpHost(web.hostname(), web.port());
DefaultHttpClientConnection conn = new
DefaultHttpClientConnection();
- ConnectionReuseStrategy connStrategy = new
DefaultConnectionReuseStrategy();
+ //ConnectionReuseStrategy connStrategy = new
DefaultConnectionReuseStrategy();
context.setAttribute(ExecutionContext.HTTP_CONNECTION, conn);
context.setAttribute(ExecutionContext.HTTP_TARGET_HOST,
http_host);
@@ -280,17 +274,17 @@ public class HttpTestCaseRunner extends
AbstractPhptTestCaseRunner2 {
@Override
protected String executeSkipIf() throws Exception {
- return http_execute(test_skipif, false);
+ return http_execute(test_skipif, EPhptSection.SKIPIF);
}
@Override
protected String executeTest() throws Exception {
- return http_execute(test_file, true);
+ return http_execute(test_file, EPhptSection.TEST);
}
@Override
protected void executeClean() throws Exception {
- http_execute(test_clean, false);
+ http_execute(test_clean, EPhptSection.CLEAN);
}
@Override
diff --git a/src/com/mostc/pftt/runner/PhptTestPackRunner.java
b/src/com/mostc/pftt/runner/PhptTestPackRunner.java
index 52e1ccd..44db4be 100644
--- a/src/com/mostc/pftt/runner/PhptTestPackRunner.java
+++ b/src/com/mostc/pftt/runner/PhptTestPackRunner.java
@@ -31,7 +31,7 @@ import com.mostc.pftt.util.HostEnvUtil;
*/
public class PhptTestPackRunner extends AbstractTestPackRunner {
- protected static final int MAX_THREAD_COUNT = 48;
+ protected static final int MAX_THREAD_COUNT = 64; // TODO 32
protected final PhptTestPack test_pack;
protected final PhptTelemetryWriter twriter;
protected ETestPackRunnerState runner_state;
@@ -208,6 +208,8 @@ public class PhptTestPackRunner extends
AbstractTestPackRunner {
// execute any remaining thread safe jobs
runThreadSafe();
+ } catch ( Exception ex ) {
+ ex.printStackTrace();
} finally {
if (run_thread.get())
// if #stopThisThread not called
@@ -293,16 +295,10 @@ public class PhptTestPackRunner extends
AbstractTestPackRunner {
twriter.show_exception(test_case, ex);
}
- if (counter>10) {
- // TODO temp
- ((WebServerInstance)ini).close();
-
- // critical: provide existing
WebServerInstance to #getWebServerInstance
- // or will get multiple
zombie php.exe web servers, etc...
- ini =
((AbstractWebServerScenario)sapi_scenario).smgr.getWebServerInstance(host,
build, ((WebServerInstance)ini).getPhpIni(), test_pack.getTestPack(),
((WebServerInstance)ini));
-
- counter = 0;
- }
+ // @see HttpTestCaseRunner#http_execute which
calls #notifyCrash
+ // make sure a WebServerInstance is still
running here, so it will be shared with each
+ // test runner instance (otherwise each test
runner will create its own instance, which is slow)
+ ini =
((AbstractWebServerScenario)sapi_scenario).smgr.getWebServerInstance(host,
build, ((WebServerInstance)ini).getPhpIni(), test_pack.getTestPack(),
((WebServerInstance)ini));
counter++;
diff --git a/src/com/mostc/pftt/scenario/AbstractWebServerScenario.java
b/src/com/mostc/pftt/scenario/AbstractWebServerScenario.java
index f0e4afd..41bc6c4 100644
--- a/src/com/mostc/pftt/scenario/AbstractWebServerScenario.java
+++ b/src/com/mostc/pftt/scenario/AbstractWebServerScenario.java
@@ -1,5 +1,19 @@
package com.mostc.pftt.scenario;
+import org.apache.http.HttpRequestInterceptor;
+import org.apache.http.HttpVersion;
+import org.apache.http.params.HttpParams;
+import org.apache.http.params.HttpProtocolParams;
+import org.apache.http.params.SyncBasicHttpParams;
+import org.apache.http.protocol.HttpProcessor;
+import org.apache.http.protocol.HttpRequestExecutor;
+import org.apache.http.protocol.ImmutableHttpProcessor;
+import org.apache.http.protocol.RequestConnControl;
+import org.apache.http.protocol.RequestContent;
+import org.apache.http.protocol.RequestExpectContinue;
+import org.apache.http.protocol.RequestTargetHost;
+import org.apache.http.protocol.RequestUserAgent;
+
import com.mostc.pftt.host.Host;
import com.mostc.pftt.model.phpt.PhpBuild;
import com.mostc.pftt.model.phpt.PhptTestCase;
@@ -21,29 +35,40 @@ import com.mostc.pftt.telemetry.PhptTelemetryWriter;
public abstract class AbstractWebServerScenario extends AbstractSAPIScenario {
public final WebServerManager smgr;
+ protected final HttpParams params;
+ protected final HttpProcessor httpproc;
+ protected final HttpRequestExecutor httpexecutor;
protected AbstractWebServerScenario(WebServerManager smgr) {
this.smgr = smgr;
+
+ params = new SyncBasicHttpParams();
+ HttpProtocolParams.setVersion(params, HttpVersion.HTTP_1_1);
+ HttpProtocolParams.setContentCharset(params, "UTF-8");
+ HttpProtocolParams.setUserAgent(params, "Mozilla/5.0 (Windows
NT 6.1; rv:12.0) Gecko/ 20120405 Firefox/14.0.1");
+ HttpProtocolParams.setUseExpectContinue(params, true);
+
+ httpproc = new ImmutableHttpProcessor(new
HttpRequestInterceptor[] {// XXX reuse
+ // Required protocol interceptors
+ new RequestContent(),
+ new RequestTargetHost(),
+ // Recommended protocol interceptors
+ new RequestConnControl(),
+ new RequestUserAgent(),
+ new RequestExpectContinue()});
+
+ httpexecutor = new HttpRequestExecutor();
}
@Override
public AbstractPhptTestCaseRunner createPhptTestCaseRunner(PhptThread
thread, TestCaseGroupKey ini, PhptTestCase test_case, PhptTelemetryWriter
twriter, Host host, ScenarioSet scenario_set, PhpBuild build, PhptTestPack
test_pack) {
- return new HttpTestCaseRunner(smgr, (WebServerInstance)ini,
thread, test_case, twriter, host, scenario_set, build, test_pack);
+ return new HttpTestCaseRunner(params, httpproc, httpexecutor,
smgr, (WebServerInstance)ini, thread, test_case, twriter, host, scenario_set,
build, test_pack);
}
@Override
public void close() {
smgr.close();
}
-
- /*WebServerInstance web; // TODO temp
- @Override
- public synchronized TestCaseGroupKey createTestGroupKey(Host host,
PhpBuild build, PhptTestPack test_pack, PhptTestCase test_case) {
- // TODO use HttpTestCaseRunner to get docroot from test_pack
- if (web!=null)
- return web;
- return web = smgr.getWebServerInstance(host, build,
AbstractPhptTestCaseRunner.createIniForTest(host, build, test_pack, test_case),
test_pack.getTestPack(), null);
- }*/
public boolean willSkip(PhptTelemetryWriter twriter, Host host,
PhpBuild build, PhptTestCase test_case) throws Exception {
return HttpTestCaseRunner.willSkip(twriter, host, build,
test_case);
diff --git a/src/com/mostc/pftt/scenario/BuiltinWebServerScenario.java
b/src/com/mostc/pftt/scenario/BuiltinWebServerScenario.java
index c685de0..7eddeed 100644
--- a/src/com/mostc/pftt/scenario/BuiltinWebServerScenario.java
+++ b/src/com/mostc/pftt/scenario/BuiltinWebServerScenario.java
@@ -47,7 +47,7 @@ public class BuiltinWebServerScenario extends
AbstractWebServerScenario {
@Override
public int getTestThreadCount(Host host) {
// XXX update this calculation from time to time as this web
server's performance improves
- return 8 * (Math.max(2, host.getCPUCount())/2);
+ return 64; // TODO 8 * (Math.max(2, host.getCPUCount())/2);
}
}
diff --git a/src/com/mostc/pftt/telemetry/ConsoleManager.java
b/src/com/mostc/pftt/telemetry/ConsoleManager.java
new file mode 100644
index 0000000..75ce99d
--- /dev/null
+++ b/src/com/mostc/pftt/telemetry/ConsoleManager.java
@@ -0,0 +1,23 @@
+package com.mostc.pftt.telemetry;
+
+import com.mostc.pftt.model.phpt.PhptTestCase;
+import com.mostc.pftt.model.phpt.EPhptTestStatus;
+
+public class ConsoleManager {
+
+ public ConsoleManager(boolean result_only) {
+
+ }
+
+ public void finishedTest(PhptTestCase test_case, EPhptTestStatus
status) {
+
+ }
+
+ public void retryingTest(PhptTestCase test_case) {
+
+ }
+
+ public void restartingSAPI() {
+
+ }
+}
diff --git a/src/com/mostc/pftt/telemetry/PhptTestResult.java
b/src/com/mostc/pftt/telemetry/PhptTestResult.java
index 0c9d2e1..b869268 100644
--- a/src/com/mostc/pftt/telemetry/PhptTestResult.java
+++ b/src/com/mostc/pftt/telemetry/PhptTestResult.java
@@ -102,7 +102,7 @@ public class PhptTestResult {
protected void write(File file, String text) throws IOException {
try {
- file.mkdirs();
+ file.getParentFile().mkdirs();
FileWriter fw = new FileWriter(file);
fw.write(text, 0, text.length());
diff --git a/src/com/mostc/pftt/ui/PhptHostTab.java
b/src/com/mostc/pftt/ui/PhptHostTab.java
index fafd770..a030392 100644
--- a/src/com/mostc/pftt/ui/PhptHostTab.java
+++ b/src/com/mostc/pftt/ui/PhptHostTab.java
@@ -111,7 +111,7 @@ public class PhptHostTab extends JSplitPane {
panel.add(unsupported_label = new JLabel("0"));
panel.add(new JLabel("Exceptions:"));
panel.add(exceptions_label = new JLabel("0"));
- panel.add(new JLabel("Crashes:"));
+ panel.add(new JLabel("Failed Retries:"));
panel.add(crash_label = new JLabel("0"));
///////////////
@@ -214,7 +214,7 @@ public class PhptHostTab extends JSplitPane {
showList(exceptions_list_model);
} });
list_button_group.add(list_exceptions_rb);
- status_list_menu.add(list_crash_rb = new
JRadioButtonMenuItem("Crash"));
+ status_list_menu.add(list_crash_rb = new
JRadioButtonMenuItem("Failed Retries"));
list_crash_rb.addActionListener(new ActionListener() { public
void actionPerformed(ActionEvent e) {
if (list_crash_rb.isSelected())
showList(crash_list_model);
diff --git a/src/com/mostc/pftt/util/HostEnvUtil.java
b/src/com/mostc/pftt/util/HostEnvUtil.java
index 3d31011..a4876fa 100644
--- a/src/com/mostc/pftt/util/HostEnvUtil.java
+++ b/src/com/mostc/pftt/util/HostEnvUtil.java
@@ -33,8 +33,10 @@ public final class HostEnvUtil {
// have to fix Windows Error Reporting from popping up and
blocking execution:
// silence reporting
System.out.println("PFTT: HostEnvUtil: disabling Windows Error
Reporting...");
- boolean a = regQueryAdd(host,
"HKCU\\Software\\Microsoft\\Windows\\Windows Error Reporting", "DontShowUI",
"0x1", REG_DWORD);
- boolean b = regQueryAdd(host,
"HKCU\\Software\\Microsoft\\Windows\\Windows Error Reporting", "Disable",
"0x1", REG_DWORD);
+ // TODO temp boolean a = regQueryAdd(host,
"HKCU\\Software\\Microsoft\\Windows\\Windows Error Reporting", "DontShowUI",
"0x1", REG_DWORD);
+ boolean a = regQueryAdd(host,
"HKCU\\Software\\Microsoft\\Windows\\Windows Error Reporting", "DontShowUI",
"0x0", REG_DWORD);
+ // TODO temp boolean b = regQueryAdd(host,
"HKCU\\Software\\Microsoft\\Windows\\Windows Error Reporting", "Disable",
"0x1", REG_DWORD);
+ boolean b = regQueryAdd(host,
"HKCU\\Software\\Microsoft\\Windows\\Windows Error Reporting", "Disable",
"0x0", REG_DWORD);
// then, disable reporting
if ( a || b ) {
// assume if registry had to be edited, that firewall
has to be disabled (avoid doing this if possible because it requires user to
approve elevation)
diff --git a/src/com/mostc/pftt/util/StringUtil.java
b/src/com/mostc/pftt/util/StringUtil.java
index 559c57e..4b0c6e6 100644
--- a/src/com/mostc/pftt/util/StringUtil.java
+++ b/src/com/mostc/pftt/util/StringUtil.java
@@ -15,6 +15,17 @@ import com.mostc.pftt.util.apache.regexp.REProgram;
*/
public final class StringUtil {
+ public static final String EMPTY = "";
+
+ public static String unquote(String in) {
+ if (isEmpty(in))
+ return in;
+ while (in.startsWith("\"") || in.startsWith("'"))
+ in = in.substring(1);
+ while (in.endsWith("\"") || in.endsWith("'"))
+ in = in.substring(0, in.length()-1);
+ return in;
+ }
public static boolean startsWithCS(String a, String b) {
return a==null||b==null? false : a.startsWith(b);
@@ -56,12 +67,18 @@ public final class StringUtil {
return sb.toString();
}
+ public static final String[] EMPTY_ARRAY = new String[]{};
public static String[] splitLines(String str) {
+ if (str==null)
+ return EMPTY_ARRAY;
str = replaceAll(PATTERN_R, "", str);
return PATTERN_N.split(str);
}
public static String[] splitEqualsSign(String str) {
+ if (str==null)
+ return EMPTY_ARRAY;
+
return PATTERN_EQ.split(str);
}