Commit: 2e15bedb15bc91931ef84e20f4d57e0aee361ee8
Author: Matt Ficken <v-maf...@microsoft.com> Tue, 30 Oct 2012
11:12:04 -0700
Parents: 23688d20d56c5fe07d2693970fc955038fc1c260
Branches: master
Link:
http://git.php.net/?p=pftt2.git;a=commitdiff;h=2e15bedb15bc91931ef84e20f4d57e0aee361ee8
Log:
interim partially working http testing support
Changed paths:
M .classpath
A lib/winp-1.14.jar
A lib/winp.x64.dll
M src/com/mostc/pftt/host/Host.java
M src/com/mostc/pftt/host/LocalHost.java
M src/com/mostc/pftt/model/phpt/EPhptTestStatus.java
D src/com/mostc/pftt/model/sapi/BuiltinWebServerInstance.java
M src/com/mostc/pftt/model/sapi/BuiltinWebServerManager.java
M src/com/mostc/pftt/model/sapi/WebServerInstance.java
M src/com/mostc/pftt/runner/AbstractPhptTestCaseRunner.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/AbstractSAPIScenario.java
M src/com/mostc/pftt/scenario/AbstractWebServerScenario.java
M src/com/mostc/pftt/scenario/BuiltinWebServerScenario.java
M src/com/mostc/pftt/scenario/CLIScenario.java
M src/com/mostc/pftt/telemetry/PhptTelemetryReader.java
M src/com/mostc/pftt/telemetry/PhptTelemetryWriter.java
M src/com/mostc/pftt/telemetry/PhptTestResult.java
M src/com/mostc/pftt/ui/ExpectedActualDiffPHPTDisplay.java
M src/com/mostc/pftt/ui/PhptHostTab.java
diff --git a/.classpath b/.classpath
index 4bf0572..02cf268 100644
--- a/.classpath
+++ b/.classpath
@@ -24,5 +24,6 @@
<classpathentry kind="lib" path="lib/asm-tree-3.2.jar"/>
<classpathentry kind="lib" path="lib/asm-util-3.2.jar"/>
<classpathentry kind="lib" path="lib/j2ssh-core-0.2.9.jar"/>
+ <classpathentry kind="lib" path="lib/winp-1.14.jar"/>
<classpathentry kind="output" path="build"/>
</classpath>
diff --git a/lib/winp-1.14.jar b/lib/winp-1.14.jar
new file mode 100644
index 0000000..240382c
Binary files /dev/null and b/lib/winp-1.14.jar differ
diff --git a/lib/winp.x64.dll b/lib/winp.x64.dll
new file mode 100644
index 0000000..f28aa19
Binary files /dev/null and b/lib/winp.x64.dll differ
diff --git a/src/com/mostc/pftt/host/Host.java
b/src/com/mostc/pftt/host/Host.java
index 443bb71..9bb148e 100644
--- a/src/com/mostc/pftt/host/Host.java
+++ b/src/com/mostc/pftt/host/Host.java
@@ -615,5 +615,35 @@ public abstract class Host {
public String getLocalhostServableAddress() {
return isWindows() ? getAddress() : "127.0.0.1";
}
+
+ /** returns number of CPUs on this host
+ *
+ * if exception, returns 1, always returns at least 1
+ *
+ * @return
+ */
+ public int getCPUCount() {
+ try {
+ if (isWindows())
+ return
Integer.parseInt(getEnvValue("NUMBER_OF_PROCESSORS"));
+
+ int proc = 0;
+ ByLineReader r = readFile("/proc/cpuinfo");
+ String line;
+ while (r.hasMoreLines()) {
+ line = r.readLine();
+ if (line==null)
+ break;
+
+ if (line.startsWith("processor"))
+ proc++;
+ }
+ return Math.max(1, proc);
+ } catch ( Exception ex ) {
+ ex.printStackTrace();
+
+ return 1;
+ }
+ }
} // end public abstract class Host
diff --git a/src/com/mostc/pftt/host/LocalHost.java
b/src/com/mostc/pftt/host/LocalHost.java
index 1b8f94b..efcc2e1 100644
--- a/src/com/mostc/pftt/host/LocalHost.java
+++ b/src/com/mostc/pftt/host/LocalHost.java
@@ -20,6 +20,8 @@ import java.util.Timer;
import java.util.TimerTask;
import java.util.regex.Pattern;
+import org.jvnet.winp.WinProcess;
+
import com.github.mattficken.io.AbstractDetectingCharsetReader;
import com.github.mattficken.io.ByLineReader;
import com.github.mattficken.io.CharsetDeciderDecoder;
@@ -30,6 +32,9 @@ import com.github.mattficken.io.NoCharsetByLineReader;
import com.mostc.pftt.model.phpt.PhptTestCase;
import com.mostc.pftt.runner.AbstractTestPackRunner.TestPackRunnerThread;
import com.mostc.pftt.util.StringUtil;
+import com.sun.jna.Pointer;
+import com.sun.jna.platform.win32.Kernel32;
+import com.sun.jna.platform.win32.WinNT.HANDLE;
/** Represents the local Host that the program is currently running on.
*
@@ -194,12 +199,11 @@ public class LocalHost extends Host {
protected Charset charset;
protected StringBuilder output_sb;
- public LocalExecHandle(Process process, OutputStream stdin,
InputStream stdout, InputStream stderr, ExitMonitorTask task, String cmdline) {
+ public LocalExecHandle(Process process, OutputStream stdin,
InputStream stdout, InputStream stderr, String cmdline) {
this.process = process;
this.stdin = stdin;
this.stdout = stdout;
this.stderr = stderr;
- this.task = task;
this.cmdline = cmdline;
}
@@ -213,16 +217,97 @@ public class LocalHost extends Host {
}
}
+ boolean run = true;
@Override
public void close() {
- for ( int i=0 ; i < 10 ; i++ ) {
+ 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.destroy();
- } catch ( Throwable ex ) {
- ex.printStackTrace();
- }
- }
- }
+ process.exitValue();
+ } catch ( Throwable t ) {
+ // hasn't exited yet
+ if (tries==0) {
+ // try closing streams to
encourage it to exit
+ try {
+ stdin.close();
+ } catch ( Throwable t2 ) {
+ t2.printStackTrace();
+ }
+ try {
+ stdout.close();
+ } catch ( Throwable t2 ) {
+ t2.printStackTrace();
+ }
+ try {
+ stderr.close();
+ } catch ( Throwable t2 ) {
+ t2.printStackTrace();
+ }
+ }
+
+ // kill it
+ if (isLocalhostWindows()) {
+
+ try {
+ WinProcess wproc = new
WinProcess(process);
+ wproc.killRecursively();
+ } 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
+ //
+ // kind of a
hack to get the process id:
+ // look
through hidden fields to find a field like java.lang.ProcessImpl#handle (long)
+ for
(java.lang.reflect.Field f : process.getClass().getDeclaredFields() ) {
+ if
(f.getType()==long.class) { // ProcessImpl#handle
+
// this is a private field. without this, #getLong will throw an
IllegalAccessException
+
f.setAccessible(true);
+
+
long handle = f.getLong(process);
+
+
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");
+
+
break;
+ }
+ } // end for
+ } catch ( Throwable t2
) {
+
t2.printStackTrace();
+ } // end try
+ } // end try
+ } // end if
+ //
+
+
+ // terminate through java Process API
+ // this is works on Linux and is a
fallback on Windows
+ try {
+ process.destroy();
+ } catch ( Throwable t2 ) {
+ t2.printStackTrace();
+ }
+ //
+
+ } // end try
+ } // end for
+ } // end public void close
protected void run(Charset charset) throws IOException,
InterruptedException {
output_sb = new StringBuilder(1024);
@@ -247,7 +332,7 @@ public class LocalHost extends Host {
ByLineReader reader = charset == null ? new
NoCharsetByLineReader(in) : new MultiCharsetByLineReader(in, d);
String line;
try {
- while (reader.hasMoreLines()) {
+ while (reader.hasMoreLines()&&run) {
line = reader.readLine();
if (line==null)
break;
@@ -356,95 +441,27 @@ public class LocalHost extends Host {
InputStream stdout = process.getInputStream();
InputStream stderr = process.getErrorStream();
- ExitMonitorTask task = null;
+ LocalExecHandle h = new LocalExecHandle(process, stdin, stdout,
stderr, StringUtil.toString(cmd_array));
+
if (timeout>NO_TIMEOUT) {
- task = new ExitMonitorTask(process,stdin, stdout, stderr);
- timer.schedule(task, 5*1000);
+ h.task = new ExitMonitorTask(h);
+ timer.schedule(h.task, 5*1000);
}
- return new LocalExecHandle(process, stdin, stdout, stderr, task,
StringUtil.toString(cmd_array));
+ return h;
} // end protected static LocalExecHandle exec_impl
protected static class ExitMonitorTask extends TimerTask {
- protected Process process;
- protected OutputStream stdin;
- protected InputStream stdout, stderr;
+ protected final LocalExecHandle h;
- protected ExitMonitorTask(Process process, OutputStream stdin,
InputStream stdout, InputStream stderr) {
- this.process = process;
- this.stdin = stdin;
- this.stdout = stdout;
- this.stderr = stderr;
+ protected ExitMonitorTask(LocalExecHandle h) {
+ this.h = h;
}
@Override
public void run() {
- // may take multiple tries to make it exit (lots of
processes, certain OSes, etc...)
- for ( int tries = 0 ; tries < 10 ; tries++ ) {
- try {
- process.exitValue();
- } catch ( Throwable t ) {
- // hasn't exited yet
- if (tries==0) {
- // try closing streams to
encourage it to exit
- try {
- stdin.close();
- } catch ( Throwable t2 ) {
- t2.printStackTrace();
- }
- try {
- stdout.close();
- } catch ( Throwable t2 ) {
- t2.printStackTrace();
- }
- try {
- stderr.close();
- } catch ( Throwable t2 ) {
- t2.printStackTrace();
- }
- }
-
- // kill it
- if (isLocalhostWindows()) {
- // process.destory doesn't
always work on windows, but TASKKILL does
- try {
- // process.getClass()
!= Process.class
- //
- // kind of a hack to
get the process id:
- // look through
hidden fields to find a field like java.lang.ProcessImpl#handle (long)
- for
(java.lang.reflect.Field f : process.getClass().getDeclaredFields() ) {
- if
(f.getType()==long.class) {
- // this
is a private field. without this, #getLong will throw an IllegalAccessException
-
f.setAccessible(true);
-
- long
process_id = f.getLong(process);
-
- //
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");
-
- break;
- }
- }
- } catch ( Throwable t2 ) {
- t2.printStackTrace();
- }
- }
- try {
- process.destroy();
- } catch ( Throwable t2 ) {
- t2.printStackTrace();
- }
-
-
-
- } // end try
- }
- } // end public void run
+ h.close();
+ }
} // end protected static class ExitMonitorTask
diff --git a/src/com/mostc/pftt/model/phpt/EPhptTestStatus.java
b/src/com/mostc/pftt/model/phpt/EPhptTestStatus.java
index e90514c..6ca1afd 100644
--- a/src/com/mostc/pftt/model/phpt/EPhptTestStatus.java
+++ b/src/com/mostc/pftt/model/phpt/EPhptTestStatus.java
@@ -18,5 +18,5 @@ public enum EPhptTestStatus {
/** test is malformed */
BORK,
/** an internal PFTT error */
- INTERNAL_EXCEPTION
+ EXCEPTION
}
diff --git a/src/com/mostc/pftt/model/sapi/BuiltinWebServerInstance.java
b/src/com/mostc/pftt/model/sapi/BuiltinWebServerInstance.java
deleted file mode 100644
index c447057..0000000
--- a/src/com/mostc/pftt/model/sapi/BuiltinWebServerInstance.java
+++ /dev/null
@@ -1,46 +0,0 @@
-package com.mostc.pftt.model.sapi;
-
-import com.mostc.pftt.host.Host.ExecHandle;
-import com.mostc.pftt.model.phpt.PhpIni;
-
-/** running instance of PHP's builtin web server.
- *
- * m
- *
- * @author Matt Ficken
- *
- */
-
-public 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);
- this.process = process;
- this.hostname = hostname;
- this.port = port;
- }
-
- @Override
- public String hostname() {
- return hostname;
- }
-
- @Override
- public int port() {
- return port;
- }
-
- @Override
- public void close() {
- process.close();
- }
-
- @Override
- public boolean isRunning() {
- return process.isRunning();
- }
-
-} // end public class BuiltinWebServerInstance
diff --git a/src/com/mostc/pftt/model/sapi/BuiltinWebServerManager.java
b/src/com/mostc/pftt/model/sapi/BuiltinWebServerManager.java
index e8b88a2..d7d3013 100644
--- a/src/com/mostc/pftt/model/sapi/BuiltinWebServerManager.java
+++ b/src/com/mostc/pftt/model/sapi/BuiltinWebServerManager.java
@@ -9,6 +9,7 @@ import javax.annotation.concurrent.ThreadSafe;
import com.mostc.pftt.host.Host;
import com.mostc.pftt.host.LocalHost;
+import com.mostc.pftt.host.Host.ExecHandle;
import com.mostc.pftt.model.phpt.PhpBuild;
import com.mostc.pftt.model.phpt.PhpIni;
import com.mostc.pftt.util.ErrorUtil;
@@ -34,6 +35,16 @@ public class BuiltinWebServerManager extends
WebServerManager {
public BuiltinWebServerManager() {
timer = new Timer();
+
+ if (LocalHost.isLocalhostWindows()) {
+ Runtime.getRuntime().addShutdownHook(new Thread() {
+ @Override
+ public void run() {
+ // Windows BN: may leave `php.exe -S`
running if they aren't terminated here
+ close();
+ }
+ });
+ }
}
@Override
@@ -76,8 +87,7 @@ public class BuiltinWebServerManager extends WebServerManager
{
handle = host.execThread(cmd, docroot);
final Host.ExecHandle handlef = handle;
- new Exception().printStackTrace(); // TODO temp
-
+
// ensure server can be connected to
Socket sock = new Socket(hostname, last_port);
if (!sock.isConnected())
@@ -125,7 +135,47 @@ public class BuiltinWebServerManager extends
WebServerManager {
// return this failure message to client code
return new CrashedWebServerInstance(ini, sapi_output);
} // end protected synchronized WebServerInstance
createWebServerInstance
+
+ public 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);
+ this.process = process;
+ this.hostname = hostname;
+ this.port = port;
+ }
+
+ @Override
+ public String hostname() {
+ return hostname;
+ }
+
+ @Override
+ public int port() {
+ return port;
+ }
+ @Override
+ public void close() {
+ try {
+ process.close();
+ } finally {
+
synchronized(BuiltinWebServerManager.this.instances) {
+
BuiltinWebServerManager.this.instances.remove(this);
+ }
+ }
+ }
+
+ @Override
+ public boolean isRunning() {
+ return process.isRunning();
+ }
+
+ } // end public class BuiltinWebServerInstance
+
@Override
public boolean allowConcurrentWebServerSAPIInstances() {
return true;
diff --git a/src/com/mostc/pftt/model/sapi/WebServerInstance.java
b/src/com/mostc/pftt/model/sapi/WebServerInstance.java
index d1ee66f..f115cb9 100644
--- a/src/com/mostc/pftt/model/sapi/WebServerInstance.java
+++ b/src/com/mostc/pftt/model/sapi/WebServerInstance.java
@@ -82,14 +82,7 @@ public abstract class WebServerInstance extends SAPIInstance
{
StringBuilder sb = new StringBuilder(1024);
sb.append("PFTT: web server crashed with exit code:
"+exit_code);
- synchronized(active_test_cases) {
- sb.append("PFTT: while running these
tests("+active_test_cases.size()+"):\n");
- for (PhptTestCase test_case : active_test_cases
) {
- sb.append("PFTT: ");
- sb.append(test_case.getName());
- sb.append('\n');
- }
- }
+ getActiveTestListString(sb);
if (StringUtil.isEmpty(output)) {
sb.append("PFTT: web server returned no output
when it exited.\n");
} else {
@@ -101,6 +94,23 @@ public abstract class WebServerInstance extends
SAPIInstance {
} // end sync
} // end protected void notifyCrash
+ protected 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 ) {
+ sb.append("PFTT: ");
+ sb.append(test_case.getName());
+ sb.append('\n');
+ }
+ }
+ }
+
+ public String getActiveTestListString() {
+ StringBuilder sb = new StringBuilder(512);
+ getActiveTestListString(sb);
+ return sb.toString();
+ }
+
/** called before HTTP request made to server for given test_case
*
* @param test_case
diff --git a/src/com/mostc/pftt/runner/AbstractPhptTestCaseRunner.java
b/src/com/mostc/pftt/runner/AbstractPhptTestCaseRunner.java
index cd55764..019b4fc 100644
--- a/src/com/mostc/pftt/runner/AbstractPhptTestCaseRunner.java
+++ b/src/com/mostc/pftt/runner/AbstractPhptTestCaseRunner.java
@@ -27,11 +27,14 @@ public abstract class AbstractPhptTestCaseRunner {
public abstract void runTest() throws IOException, Exception, Throwable;
+ static PhpIni _ini;
public static PhpIni createIniForTest(Host host, PhpBuild build,
PhptTestPack test_pack, PhptTestCase test_case) {
- PhpIni ini = PhpIni.createDefaultIniCopy(host);
- ini.replaceAll(test_case.getINI(test_pack, host));
- ini.addToIncludePath(host, test_pack.getTestPack());
- return ini;
+ if (_ini!=null)
+ return _ini; // TODO
+ _ini = PhpIni.createDefaultIniCopy(host);
+ _ini.replaceAll(test_case.getINI(test_pack, host));
+ _ini.addToIncludePath(host, test_pack.getTestPack());
+ return _ini;
}
/** TODO
diff --git a/src/com/mostc/pftt/runner/AbstractPhptTestCaseRunner2.java
b/src/com/mostc/pftt/runner/AbstractPhptTestCaseRunner2.java
index df4e987..041d692 100644
--- a/src/com/mostc/pftt/runner/AbstractPhptTestCaseRunner2.java
+++ b/src/com/mostc/pftt/runner/AbstractPhptTestCaseRunner2.java
@@ -118,6 +118,18 @@ public abstract class AbstractPhptTestCaseRunner2 extends
AbstractPhptTestCaseRu
return false;
}
+
+ //
+ if (host.isWindows() &&
test_case.containsSection(EPhptSection.SKIPIF)) {
+ // do an early quick check
+ // 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));
+
+ return false;
+ }
+ }
+ //
selected_php_exe = build.getPhpExe();
@@ -469,10 +481,6 @@ public abstract class AbstractPhptTestCaseRunner2 extends
AbstractPhptTestCaseRu
*/
protected abstract String getCrashedSAPIOutput();
- private boolean check() {
- return
!test_case.isNamed("ext/phar/tests/tar/phar_setsignaturealgo2.phpt");
- }
-
/** evaluates the output of the executed test and reports the result
*
* @param output
@@ -504,7 +512,7 @@ public abstract class AbstractPhptTestCaseRunner2 extends
AbstractPhptTestCaseRu
twriter.show_exception(test_case, ex, expected);
throw ex;
}
- if (expected_re_match||check()) {
+ if (expected_re_match) {
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));
@@ -516,7 +524,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)||check())
{
+ if
(output_trim.equals(expected)||output_trim.contains(expected)||expected.contains(output_trim))
{
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));
diff --git a/src/com/mostc/pftt/runner/HttpTestCaseRunner.java
b/src/com/mostc/pftt/runner/HttpTestCaseRunner.java
index 8f4d47c..03aa9f2 100644
--- a/src/com/mostc/pftt/runner/HttpTestCaseRunner.java
+++ b/src/com/mostc/pftt/runner/HttpTestCaseRunner.java
@@ -96,31 +96,55 @@ public class HttpTestCaseRunner extends
AbstractPhptTestCaseRunner2 {
* @throws Exception
*/
protected String http_execute(String path, boolean is_test) throws
Exception {
- // "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);
- } catch ( IOException ex1 ) { // SocketTimeoutException or
ConnectException
- web.close();
- // stop web server, try again
- web = smgr.getWebServerInstance(host, build, ini,
test_pack.getTestPack(), web);
+ // "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);
- } catch ( IOException ex2 ) { // SocketTimeoutException
or ConnectException
+ } catch ( IOException ex1 ) { // 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
+ } catch ( IOException ex2 ) { //
SocketTimeoutException or ConnectException
web.close();
// stop web server, try again
web = smgr.getWebServerInstance(host,
build, ini, test_pack.getTestPack(), web);
- return do_http_execute(path, is_test);
+ 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();
+ }
+ }
}
}
+ } 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
+
+ // TODO comment
+
+ web.notifyCrash("", 0);
+
+ 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);
}
- }
+ } // end protected String http_execute
protected String do_http_execute(String path, boolean is_test) throws
Exception {
// make sure a web server is running
@@ -165,8 +189,7 @@ public class HttpTestCaseRunner extends
AbstractPhptTestCaseRunner2 {
Socket socket = new Socket(http_host.getHostName(),
http_host.getPort());
//socket.setSoTimeout(6*1000);
conn.bind(socket, params);
- conn.setSocketTimeout(2*1000);
- // TODO support POST for some tests that do that
+ conn.setSocketTimeout(60*1000);
//
path = Host.toUnixPath(path);
@@ -221,7 +244,7 @@ public class HttpTestCaseRunner extends
AbstractPhptTestCaseRunner2 {
Socket socket = new Socket(http_host.getHostName(),
http_host.getPort());
//socket.setSoTimeout(6*1000);
conn.bind(socket, params);
- conn.setSocketTimeout(2*1000);
+ conn.setSocketTimeout(60*1000);
//
path = Host.toUnixPath(path);
diff --git a/src/com/mostc/pftt/runner/PhptTestPackRunner.java
b/src/com/mostc/pftt/runner/PhptTestPackRunner.java
index a0cdb61..52e1ccd 100644
--- a/src/com/mostc/pftt/runner/PhptTestPackRunner.java
+++ b/src/com/mostc/pftt/runner/PhptTestPackRunner.java
@@ -9,11 +9,14 @@ import java.util.concurrent.atomic.AtomicInteger;
import com.mostc.pftt.host.Host;
import com.mostc.pftt.model.phpt.PhpBuild;
+import com.mostc.pftt.model.phpt.PhpIni;
import com.mostc.pftt.model.phpt.PhptTestCase;
import com.mostc.pftt.model.phpt.PhptTestPack;
import com.mostc.pftt.model.sapi.SAPIInstance;
import com.mostc.pftt.model.sapi.TestCaseGroupKey;
+import com.mostc.pftt.model.sapi.WebServerInstance;
import com.mostc.pftt.scenario.AbstractSAPIScenario;
+import com.mostc.pftt.scenario.AbstractWebServerScenario;
import com.mostc.pftt.scenario.ScenarioSet;
import com.mostc.pftt.telemetry.PhptTelemetryWriter;
import com.mostc.pftt.util.HostEnvUtil;
@@ -28,8 +31,7 @@ import com.mostc.pftt.util.HostEnvUtil;
*/
public class PhptTestPackRunner extends AbstractTestPackRunner {
- protected static final int INIT_THREAD_COUNT = 8; // TODO 16;
- protected static final int MAX_THREAD_COUNT = 32;
+ protected static final int MAX_THREAD_COUNT = 48;
protected final PhptTestPack test_pack;
protected final PhptTelemetryWriter twriter;
protected ETestPackRunnerState runner_state;
@@ -67,10 +69,8 @@ public class PhptTestPackRunner extends
AbstractTestPackRunner {
}
public void close() {
- for ( TestCaseGroupKey group_key : group_keys ) {
- if (group_key instanceof SAPIInstance)
- ((SAPIInstance)group_key).close();
- }
+ ((AbstractWebServerScenario)sapi_scenario).smgr.close();
+ sapi_scenario.close();
}
protected void groupTestCases(List<PhptTestCase> test_cases) throws
InterruptedException {
@@ -137,17 +137,22 @@ public class PhptTestPackRunner extends
AbstractTestPackRunner {
} // end protected void groupTestCases
protected void parallelSAPIInstance_executeTestCases() throws
InterruptedException {
- int thread_count = INIT_THREAD_COUNT;
+ int thread_count = Math.min(MAX_THREAD_COUNT,
sapi_scenario.getTestThreadCount(host));
test_count = new AtomicInteger(0);
active_thread_count = new AtomicInteger(thread_count);
- thread_count = INIT_THREAD_COUNT;
+ long start_time = System.currentTimeMillis();
+
for ( int i=0 ; i < thread_count ; i++ ) {
start_thread();
}
// wait until done
int c ; while ( ( c = active_thread_count.get() ) > 0 ) {
Thread.sleep(c>3?1000:50); }
+
+ long run_time = Math.abs(System.currentTimeMillis() -
start_time);
+
+ System.out.println((run_time/1000)+" seconds");
} // end protected void parallelSAPIInstance_executeTestCases
/*protected void serialSAPIInstance_executeTestCases() throws
InterruptedException {
@@ -225,8 +230,15 @@ public class PhptTestPackRunner extends
AbstractTestPackRunner {
if (jobs.isEmpty())
group_it.remove();
}
- if (group_key!=null)
+ if (group_key!=null && !jobs.isEmpty()) {
+ // TODO temp
+ group_key =
((AbstractWebServerScenario)sapi_scenario).smgr.getWebServerInstance(host,
build, (PhpIni)group_key, test_pack.getTestPack(), null);
+
exec_jobs(group_key, jobs, test_count);
+
+ // TODO temp
+ ((WebServerInstance)group_key).close();
+ }
}
} // end protected void runThreadSafe
@@ -267,6 +279,7 @@ public class PhptTestPackRunner extends
AbstractTestPackRunner {
protected void exec_jobs(TestCaseGroupKey ini,
LinkedBlockingQueue<PhptTestCase> jobs, AtomicInteger test_count) {
PhptTestCase test_case;
+ int counter = 0;
while ( (
test_case = jobs.poll()
) != null &&
@@ -280,6 +293,19 @@ 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;
+ }
+
+ counter++;
+
test_count.incrementAndGet();
//Thread.yield()
@@ -316,4 +342,4 @@ public class PhptTestPackRunner extends
AbstractTestPackRunner {
return runner_state;
}
-} // end class TestPackRunner
+} // end public class PhptTestPackRunner
diff --git a/src/com/mostc/pftt/scenario/AbstractSAPIScenario.java
b/src/com/mostc/pftt/scenario/AbstractSAPIScenario.java
index 8475fcc..ccb1cb4 100644
--- a/src/com/mostc/pftt/scenario/AbstractSAPIScenario.java
+++ b/src/com/mostc/pftt/scenario/AbstractSAPIScenario.java
@@ -38,10 +38,20 @@ public abstract class AbstractSAPIScenario extends
AbstractSerialScenario {
// TODO rename ini
public abstract AbstractPhptTestCaseRunner
createPhptTestCaseRunner(PhptThread thread, TestCaseGroupKey ini, PhptTestCase
test_case, PhptTelemetryWriter twriter, Host host, ScenarioSet scenario_set,
PhpBuild build, PhptTestPack test_pack);
- public abstract TestCaseGroupKey createTestGroupKey(Host host, PhpBuild
build, PhptTestPack test_pack, PhptTestCase test_case);
-
public boolean willSkip(PhptTelemetryWriter twriter, Host host,
PhpBuild build, PhptTestCase test_case) throws Exception {
return AbstractPhptTestCaseRunner.willSkip(twriter, host,
build, test_case);
}
+
+ public TestCaseGroupKey createTestGroupKey(Host host, PhpBuild build,
PhptTestPack test_pack, PhptTestCase test_case) {
+ return AbstractPhptTestCaseRunner.createIniForTest(host, build,
test_pack, test_case);
+ }
+
+ public void close() {
+
+ }
+
+ public int getTestThreadCount(Host host) {
+ return 8;
+ }
}
diff --git a/src/com/mostc/pftt/scenario/AbstractWebServerScenario.java
b/src/com/mostc/pftt/scenario/AbstractWebServerScenario.java
index 4f3fa99..f0e4afd 100644
--- a/src/com/mostc/pftt/scenario/AbstractWebServerScenario.java
+++ b/src/com/mostc/pftt/scenario/AbstractWebServerScenario.java
@@ -20,7 +20,7 @@ import com.mostc.pftt.telemetry.PhptTelemetryWriter;
*/
public abstract class AbstractWebServerScenario extends AbstractSAPIScenario {
- protected final WebServerManager smgr;
+ public final WebServerManager smgr;
protected AbstractWebServerScenario(WebServerManager smgr) {
this.smgr = smgr;
@@ -31,14 +31,19 @@ public abstract class AbstractWebServerScenario extends
AbstractSAPIScenario {
return new HttpTestCaseRunner(smgr, (WebServerInstance)ini,
thread, test_case, twriter, host, scenario_set, build, test_pack);
}
- WebServerInstance web; // TODO temp
+ @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 55b9466..c685de0 100644
--- a/src/com/mostc/pftt/scenario/BuiltinWebServerScenario.java
+++ b/src/com/mostc/pftt/scenario/BuiltinWebServerScenario.java
@@ -43,5 +43,11 @@ public class BuiltinWebServerScenario extends
AbstractWebServerScenario {
public boolean isImplemented() {
return true;
}
+
+ @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);
+ }
}
diff --git a/src/com/mostc/pftt/scenario/CLIScenario.java
b/src/com/mostc/pftt/scenario/CLIScenario.java
index 7844719..d709b42 100644
--- a/src/com/mostc/pftt/scenario/CLIScenario.java
+++ b/src/com/mostc/pftt/scenario/CLIScenario.java
@@ -37,9 +37,6 @@ public class CLIScenario extends AbstractSAPIScenario {
return new CliPhptTestCaseRunner((PhpIni)ini, thread,
test_case, twriter, host, scenario_set, build, test_pack);
}
- @Override
- public TestCaseGroupKey createTestGroupKey(Host host, PhpBuild build,
PhptTestPack test_pack, PhptTestCase test_case) {
- return AbstractPhptTestCaseRunner.createIniForTest(host, build,
test_pack, test_case);
- }
+
}
diff --git a/src/com/mostc/pftt/telemetry/PhptTelemetryReader.java
b/src/com/mostc/pftt/telemetry/PhptTelemetryReader.java
index b044a15..71e8e1e 100644
--- a/src/com/mostc/pftt/telemetry/PhptTelemetryReader.java
+++ b/src/com/mostc/pftt/telemetry/PhptTelemetryReader.java
@@ -98,7 +98,7 @@ public class PhptTelemetryReader extends PhptTelemetry {
return tally.unsupported;
case BORK:
return tally.bork;
- case INTERNAL_EXCEPTION:
+ case EXCEPTION:
return tally.exception;
}
return 0;
diff --git a/src/com/mostc/pftt/telemetry/PhptTelemetryWriter.java
b/src/com/mostc/pftt/telemetry/PhptTelemetryWriter.java
index 1eeb2c0..517fb5a 100644
--- a/src/com/mostc/pftt/telemetry/PhptTelemetryWriter.java
+++ b/src/com/mostc/pftt/telemetry/PhptTelemetryWriter.java
@@ -93,7 +93,7 @@ public class PhptTelemetryWriter extends PhptTelemetry {
tally.xfail_works =
counts.get(EPhptTestStatus.XFAIL_WORKS).get();
tally.unsupported =
counts.get(EPhptTestStatus.UNSUPPORTED).get();
tally.bork = counts.get(EPhptTestStatus.BORK).get();
- tally.exception =
counts.get(EPhptTestStatus.INTERNAL_EXCEPTION).get();
+ tally.exception =
counts.get(EPhptTestStatus.EXCEPTION).get();
FileWriter fw = new FileWriter(new File(telem_dir,
"tally.xml"));
PhptTallyFile.write(tally, fw);
fw.close();
@@ -160,7 +160,7 @@ public class PhptTelemetryWriter extends PhptTelemetry {
String ex_str = ErrorUtil.toString(ex);
// count exceptions as a result (the worst kind of failure, a
pftt failure)
- addResult(new PhptTestResult(host,
EPhptTestStatus.INTERNAL_EXCEPTION, test_case, ex_str, null, null, null, null,
null, null, null, null, null, null));
+ addResult(new PhptTestResult(host, EPhptTestStatus.EXCEPTION,
test_case, ex_str, null, null, null, null, null, null, null, null, null, null));
// TODO show count of exceptions in gui
}
int completed = 0; // XXX
diff --git a/src/com/mostc/pftt/telemetry/PhptTestResult.java
b/src/com/mostc/pftt/telemetry/PhptTestResult.java
index edfcee0..0c9d2e1 100644
--- a/src/com/mostc/pftt/telemetry/PhptTestResult.java
+++ b/src/com/mostc/pftt/telemetry/PhptTestResult.java
@@ -101,9 +101,15 @@ public class PhptTestResult {
}
protected void write(File file, String text) throws IOException {
- FileWriter fw = new FileWriter(file);
- fw.write(text, 0, text.length());
- fw.close();
+ try {
+ file.mkdirs();
+
+ FileWriter fw = new FileWriter(file);
+ fw.write(text, 0, text.length());
+ fw.close();
+ } catch ( Exception ex ) {
+ ex.printStackTrace();
+ }
}
protected void writeDiffFile(File telem_dir) throws IOException {
diff --git a/src/com/mostc/pftt/ui/ExpectedActualDiffPHPTDisplay.java
b/src/com/mostc/pftt/ui/ExpectedActualDiffPHPTDisplay.java
index abe3f7f..438016d 100644
--- a/src/com/mostc/pftt/ui/ExpectedActualDiffPHPTDisplay.java
+++ b/src/com/mostc/pftt/ui/ExpectedActualDiffPHPTDisplay.java
@@ -53,8 +53,8 @@ public class ExpectedActualDiffPHPTDisplay extends
JScrollPane {
horizontal_panel = new JPanel(new BorderLayout());
horizontal_jsp.getViewport().setView(horizontal_panel);
- horizontal_button_panel = new JPanel(new GridLayout(1, 5, 2,
2));
- vertical_panel = new JPanel(new GridLayout(1, 5, 2, 2));
+ horizontal_button_panel = new JPanel(new GridLayout(1, 7, 2,
2));
+ vertical_panel = new JPanel(new GridLayout(1, 7, 2, 2));
horizontal_panel.add(vertical_jsp = new
JScrollPane(vertical_panel), BorderLayout.CENTER);
vertical_jsp = this;
@@ -94,7 +94,7 @@ public class ExpectedActualDiffPHPTDisplay extends
JScrollPane {
JPanel prepared_panel = new JPanel(new GridLayout(5, 1, 2, 2));
- vertical_panel.add(new JScrollPane(sapi_output_textarea));
+ prepared_panel.add(new JScrollPane(sapi_output_textarea));
prepared_panel.add(new JScrollPane(stdin_data_textarea = new
JTextArea()));
stdin_data_textarea.setLineWrap(true);
prepared_panel.add(new JScrollPane(shell_script_textarea = new
JTextArea()));
@@ -125,8 +125,10 @@ public class ExpectedActualDiffPHPTDisplay extends
JScrollPane {
}
}
cmd_array_list_model.clear();
- for (String cmd : test.cmd_array ) {
- cmd_array_list_model.addElement(cmd);
+ if (test.cmd_array!=null) {
+ for (String cmd : test.cmd_array ) {
+ cmd_array_list_model.addElement(cmd);
+ }
}
if (test.stdin_data!=null)
stdin_data_textarea.setText(new
String(test.stdin_data));
diff --git a/src/com/mostc/pftt/ui/PhptHostTab.java
b/src/com/mostc/pftt/ui/PhptHostTab.java
index e112b70..fafd770 100644
--- a/src/com/mostc/pftt/ui/PhptHostTab.java
+++ b/src/com/mostc/pftt/ui/PhptHostTab.java
@@ -298,6 +298,7 @@ public class PhptHostTab extends JSplitPane {
progress_bar.setMaximum(total);
//
+ // count crashes - crash != test status
though (crashed test will be counted as fail, pass, xfail, etc...)
if
(StringUtil.isNotEmpty(result.getSAPIOutput())) {
crash++;
crash_label.setText(Integer.toString(crash));
@@ -347,6 +348,12 @@ public class PhptHostTab extends JSplitPane {
bork_list_model.addElement(result);
break;
+ case EXCEPTION:
+ exceptions++;
+
exceptions_label.setText(Integer.toString(exceptions));
+
+
exceptions_list_model.addElement(result);
+ break;
case PASS:
pass++;
pass_bar.setString(Float.toString(PhptTelemetry.round1( (float)( (double)pass /
((double)( pass + fail )) )))+"%"); // 1 decimal places nn.y
--
PHP Quality Assurance Mailing List <http://www.php.net/>
To unsubscribe, visit: http://www.php.net/unsub.php