Commit: 26701b6fd15e9d5efa8218a60b9af5135959e40e Author: Matt Ficken <v-maf...@microsoft.com> Thu, 24 Jan 2013 00:13:53 -0800 Parents: 602a73184c083b98c83afc29f42dfe2816c7bba0 Branches: master
Link: http://git.php.net/?p=pftt2.git;a=commitdiff;h=26701b6fd15e9d5efa8218a60b9af5135959e40e Log: various bug fixes Former-commit-id: 3f4f4643d17c32346430d7d0259ba7be0fd4b4b3 Changed paths: M .classpath A bin/SetACL.exe M bin/pftt.cmd A bin/ssh_server.cmd D lib/SSHD_fat.jar A lib/log4j-1.2.17.jar D lib/slf4j-api-1.6.6.jar A lib/slf4j-api-1.7.2.jar A lib/slf4j-log4j12-1.7.2.jar M src/com/github/mattficken/io/ByteArrayIOStream.java M src/com/mostc/pftt/host/ExecOutput.java M src/com/mostc/pftt/host/Host.java M src/com/mostc/pftt/host/SSHHost.java A src/com/mostc/pftt/host/TempFileExecOutput.java M src/com/mostc/pftt/main/PfttMain.java M src/com/mostc/pftt/main/SSHServer.java M src/com/mostc/pftt/model/phpt/PhpBuild.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/smoke/RequiredExtensionsSmokeTest.java M src/com/mostc/pftt/model/smoke/RequiredFeaturesSmokeTest.java M src/com/mostc/pftt/model/ui/wordpress.groovy M src/com/mostc/pftt/results/PhptResultPack.java M src/com/mostc/pftt/runner/AbstractPhptTestCaseRunner.java M src/com/mostc/pftt/runner/AbstractPhptTestCaseRunner2.java M src/com/mostc/pftt/runner/CliPhptTestCaseRunner.java M src/com/mostc/pftt/runner/HttpTestCaseRunner.java M src/com/mostc/pftt/scenario/AbstractParallelScenario.java M src/com/mostc/pftt/scenario/AbstractSAPIScenario.java M src/com/mostc/pftt/scenario/AbstractSMBScenario.java M src/com/mostc/pftt/scenario/AbstractWebServerScenario.java M src/com/mostc/pftt/scenario/CLIScenario.java M src/com/mostc/pftt/scenario/NoCodeCacheScenario.java M src/com/mostc/pftt/scenario/NoDebugScenario.java M src/com/mostc/pftt/scenario/PlainSocketScenario.java M src/com/mostc/pftt/scenario/SMBBasicScenario.java M src/com/mostc/pftt/scenario/SMBCAScenario.java M src/com/mostc/pftt/scenario/SMBDFSRScenario.java M src/com/mostc/pftt/scenario/SMBDeduplicationScenario.java M src/com/mostc/pftt/scenario/Scenario.java M src/com/mostc/pftt/scenario/ScenarioSet.java M src/com/mostc/pftt/ui/PhptHostTab.java M src/com/mostc/pftt/util/StringUtil.java M src/org/apache/sshd/server/filesystem/NativeSshFile.java
diff --git a/.classpath b/.classpath index 0df8458..790b3df 100644 --- a/.classpath +++ b/.classpath @@ -21,7 +21,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/winp-1.14.jar"/> - <classpathentry kind="lib" path="lib/SSHD_fat.jar"/> <classpathentry kind="lib" path="lib/commons-net-3.1.jar"/> <classpathentry kind="lib" path="lib/commons-codec-1.6.jar"/> <classpathentry kind="lib" path="lib/commons-lang-2.6.jar"/> @@ -29,6 +28,8 @@ <classpathentry kind="lib" path="lib/jzlib-1.1.1.jar"/> <classpathentry kind="lib" path="lib/mina-core-2.0.7.jar"/> <classpathentry kind="lib" path="lib/mina-statemachine-2.0.7.jar"/> - <classpathentry kind="lib" path="lib/slf4j-api-1.6.6.jar"/> + <classpathentry kind="lib" path="lib/slf4j-api-1.7.2.jar"/> + <classpathentry kind="lib" path="lib/slf4j-log4j12-1.7.2.jar"/> + <classpathentry kind="lib" path="lib/log4j-1.2.17.jar"/> <classpathentry kind="output" path="build"/> </classpath> diff --git a/bin/SetACL.exe b/bin/SetACL.exe new file mode 100644 index 0000000..0ac0dfb Binary files /dev/null and b/bin/SetACL.exe differ diff --git a/bin/pftt.cmd b/bin/pftt.cmd index cb97260..43b77d2 100644 --- a/bin/pftt.cmd +++ b/bin/pftt.cmd @@ -5,7 +5,7 @@ REM set important env vars CALL set_env SET PFTT_LIB=%PFTT_HOME%\lib -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 +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%\jansi-1.7.jar;%PFTT_LIB%\jline-0.9.94.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-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;%PFTT_LIB%\winp-1.14.jar;%PFTT_LIB%\commons-net-3.1.jar;%PFTT_LIB%\commons-codec-1.6.jar;%PFTT_LIB%\commons-lang-2.6.jar;%PFTT_LIB%\commons-logging-1.1.1.jar;%PFTT_LIB%\jzlib-1.1.1.jar;%PFTT_LIB%\mina-core-2.0.7.jar;%PFTT_LIB%\mina-statemachine-2.0.7.jar;%PFTT_LIB%\slf4j-api-1.7.2.jar;%PFTT_LIB%\slf4j-log4j12-1.7.2.jar REM if user added -uac or -auto or -windebug console options, run elevated in UAC diff --git a/bin/ssh_server.cmd b/bin/ssh_server.cmd new file mode 100644 index 0000000..34508ad --- /dev/null +++ b/bin/ssh_server.cmd @@ -0,0 +1,62 @@ +@ECHO off +REM script for running SSH Server on Windows + +CALL set_env +SET PFTT_LIB=%PFTT_HOME%\lib + +SET CLASSPATH=%PFTT_HOME%\build;%PFTT_LIB%\commons-cli-1.2.jar;%PFTT_LIB%\winp-1.14.jar;%PFTT_LIB%\commons-net-3.1.jar;%PFTT_LIB%\commons-codec-1.6.jar;%PFTT_LIB%\commons-lang-2.6.jar;%PFTT_LIB%\commons-logging-1.1.1.jar;%PFTT_LIB%\jzlib-1.1.1.jar;%PFTT_LIB%\mina-core-2.0.7.jar;%PFTT_LIB%\mina-statemachine-2.0.7.jar;%PFTT_LIB%\slf4j-api-1.7.2.jar;%PFTT_LIB%\slf4j-log4j12-1.7.2.jar + + +:run_it + + +REM find java.exe +IF [%JAVA_EXE%] == [] ( + IF EXIST "%JAVA_HOME%\lib\tools.jar" ( + SET JAVA_EXE="%JAVA_HOME%\bin\java.exe" + ) ELSE ( + IF [%JAVA_EXE%] == [] ( + IF EXIST "%ProgramFiles%\java\jre6\bin\java.exe" ( + SET JAVA_EXE="%ProgramFiles%\java\jre6\bin\java.exe" + SET JAVA_HOME="%ProgramFiles%\java\jre6" + ) ELSE ( + IF EXIST "%ProgramFiles(x86)%\java\jre6\bin\java.exe" ( + SET JAVA_EXE="%ProgramFiles(x86)%\java\jre6\bin\java.exe" + SET JAVA_HOME="%ProgramFiles(x86)%\java\jre6" + ) ELSE ( + IF EXIST "%ProgramFiles%\java\jre7\bin\java.exe" ( + SET JAVA_EXE="%ProgramFiles%\java\jre7\bin\java.exe" + SET JAVA_HOME="%ProgramFiles%\java\jre7" + ) ELSE ( + IF EXIST "%ProgramFiles(x86)%\java\jre7\bin\java.exe" ( + SET JAVA_EXE="%ProgramFiles(x86)%\java\jre7\bin\java.exe" + SET JAVA_HOME="%ProgramFiles(x86)%\java\jre7" + ) + ) + ) + ) + ) + ) +) + +IF [%JAVA_EXE%] == [] ( + REM check PATH last. it might find java.exe in \Windows\System32\java + REM which elevate.exe can't find/execute for some weird reason + WHERE java > pftt_cmd.tmp + + IF %ERRORLEVEL% EQU 0 ( + REM found java.exe in PATH + SET /p JAVA_EXE= < pftt_cmd.tmp + ) ELSE ( + REM can't find java jre + ECHO java may not be installed. Must Install Sun Java JRE 6 or 7. + ECHO user error set JAVA_HOME or add java to PATH and try again + DEL /Q pftt_cmd.tmp + EXIT /B 200 + ) + + DEL /Q pftt_cmd.tmp +) + +REM finally execute +%ELEVATOR% %JAVA_EXE% -classpath %CLASSPATH% com.mostc.pftt.main.SSHServer %* diff --git a/lib/SSHD_fat.jar b/lib/SSHD_fat.jar deleted file mode 100644 index 5224f2a..0000000 Binary files a/lib/SSHD_fat.jar and /dev/null differ diff --git a/lib/log4j-1.2.17.jar b/lib/log4j-1.2.17.jar new file mode 100644 index 0000000..068867e Binary files /dev/null and b/lib/log4j-1.2.17.jar differ diff --git a/lib/slf4j-api-1.6.6.jar b/lib/slf4j-api-1.6.6.jar deleted file mode 100644 index 4c03fa6..0000000 Binary files a/lib/slf4j-api-1.6.6.jar and /dev/null differ diff --git a/lib/slf4j-api-1.7.2.jar b/lib/slf4j-api-1.7.2.jar new file mode 100644 index 0000000..73f38db Binary files /dev/null and b/lib/slf4j-api-1.7.2.jar differ diff --git a/lib/slf4j-log4j12-1.7.2.jar b/lib/slf4j-log4j12-1.7.2.jar new file mode 100644 index 0000000..37a85d7 Binary files /dev/null and b/lib/slf4j-log4j12-1.7.2.jar differ diff --git a/src/com/github/mattficken/io/ByteArrayIOStream.java b/src/com/github/mattficken/io/ByteArrayIOStream.java index 73f8df8..476306a 100644 --- a/src/com/github/mattficken/io/ByteArrayIOStream.java +++ b/src/com/github/mattficken/io/ByteArrayIOStream.java @@ -29,6 +29,11 @@ public class ByteArrayIOStream extends OutputStream { return new ByteArrayInStream(); } + @Override + public String toString() { + return new String(buf, 0, count); + } + public class ByteArrayInStream extends InputStream { protected int pos; diff --git a/src/com/mostc/pftt/host/ExecOutput.java b/src/com/mostc/pftt/host/ExecOutput.java index e31a9a4..e571454 100644 --- a/src/com/mostc/pftt/host/ExecOutput.java +++ b/src/com/mostc/pftt/host/ExecOutput.java @@ -48,8 +48,13 @@ public class ExecOutput { return printOutputIfCrash(ctx.getSimpleName(), ps); } public ExecOutput printOutputIfCrash(String ctx, PrintStream ps) { - if (ps!=null && isCrashed()) - ps.println(ctx+": "+output.trim()); + if (ps!=null && isCrashed()) { + String output_str = output.trim(); + if (StringUtil.isEmpty(output_str)) + output_str = "<Crash with no output. exit_code="+exit_code+">"; + + ps.println(ctx+": "+output_str); + } return this; } } // end public class ExecOutput diff --git a/src/com/mostc/pftt/host/Host.java b/src/com/mostc/pftt/host/Host.java index 9aa99c0..b56b485 100644 --- a/src/com/mostc/pftt/host/Host.java +++ b/src/com/mostc/pftt/host/Host.java @@ -448,10 +448,19 @@ public abstract class Host { public ExecOutput execElevated(String cmd, int timeout_sec, Map<String, String> env, byte[] stdin_data, Charset charset, String chdir) throws Exception { return execElevated(cmd, timeout_sec, env, stdin_data, charset, chdir, null, FOUR_HOURS); } + private boolean checked_elevate, found_elevate; public ExecOutput execElevated(String cmd, int timeout_sec, Map<String, String> env, byte[] stdin_data, Charset charset, String chdir, TestPackRunnerThread test_thread, int slow_timeout_sec) throws Exception { - if (isWindows()) - // execute command with this utility that will elevate the program using Windows UAC - cmd = getPfttDir() + "\\bin\\elevate "+cmd; + if (isWindows()) { + if (!checked_elevate) { + found_elevate = exists(getPfttDir()+"\\bin\\elevate.exe"); + + checked_elevate = true; + } + if (found_elevate) { + // execute command with this utility that will elevate the program using Windows UAC + cmd = getPfttDir() + "\\bin\\elevate "+cmd; + } + } return exec(cmd, timeout_sec, env, stdin_data, charset, chdir, test_thread, slow_timeout_sec); } @@ -802,6 +811,7 @@ public abstract class Host { if (!isWindows()) return false; String os_name = getOSNameOnWindows(); + System.out.println(os_name); return os_name.contains("Windows 8") || os_name.contains("Windows 2012") || os_name.contains("Windows 9") || os_name.contains("Windows 2014"); } @@ -972,4 +982,38 @@ public abstract class Host { } } + /** executes Powershell code and returns output. + * + * Takes care of making a temporary file, storing the powershell code, executing it, then cleaning up. + * + * @param ctx + * @param cm + * @param ps_code - powershell code to execute (not filename) + * @param timeout - max time to allow powershell to run + * @return + * @throws Exception + */ + public TempFileExecOutput powershell(Class<?> ctx, ConsoleManager cm, CharSequence ps_code, int timeout) throws Exception { + return powershell(ctx==null?null:ctx.getSimpleName(), cm, ps_code, timeout); + } + + private boolean set_unrestricted; + public TempFileExecOutput powershell(String ctx_str, ConsoleManager cm, CharSequence ps_code, int timeout) throws Exception { + if (!isWindows()) + throw new IllegalStateException("powershell is only supported on Windows"); + + if (!set_unrestricted) { + // do this once + execElevated("powershell -Command \"set-executionpolicy unrestricted\"", Host.ONE_MINUTE).printOutputIfCrash(ctx_str, cm); + + set_unrestricted = true; + } + + String temp_file = mktempname(ctx_str, ".ps1"); + + saveTextFile(temp_file, ps_code.toString()); + + return new TempFileExecOutput(temp_file, execElevated("Powershell -File "+temp_file, timeout)); + } + } // end public abstract class Host diff --git a/src/com/mostc/pftt/host/SSHHost.java b/src/com/mostc/pftt/host/SSHHost.java index d38213a..04dd4bb 100644 --- a/src/com/mostc/pftt/host/SSHHost.java +++ b/src/com/mostc/pftt/host/SSHHost.java @@ -1,6 +1,5 @@ package com.mostc.pftt.host; -import java.io.BufferedInputStream; import java.io.BufferedOutputStream; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; @@ -17,26 +16,23 @@ import java.nio.ByteBuffer; import java.nio.CharBuffer; import java.nio.charset.Charset; import java.nio.charset.CharsetEncoder; -import java.util.LinkedList; import java.util.List; import java.util.Map; import java.util.Timer; import java.util.TimerTask; import java.util.concurrent.atomic.AtomicBoolean; -import com.github.mattficken.io.AbstractDetectingCharsetReader; +import javax.annotation.Nullable; + import com.github.mattficken.io.ByLineReader; import com.github.mattficken.io.ByteArrayIOStream; import com.github.mattficken.io.CharsetByLineReader; import com.github.mattficken.io.CharsetDeciderDecoder; -import com.github.mattficken.io.DefaultCharsetDeciderDecoder; import com.github.mattficken.io.IOUtil; import com.github.mattficken.io.MultiCharsetByLineReader; 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.sshtools.j2ssh.ScpClient; import com.sshtools.j2ssh.SftpClient; import com.sshtools.j2ssh.SshClient; import com.sshtools.j2ssh.authentication.AuthenticationProtocolState; @@ -78,7 +74,9 @@ import com.sshtools.j2ssh.transport.publickey.SshPublicKey; * -OpenSSH on Linux * -Apache Mina-SSH on Windows * - * SSH Server must support SESSION, SFTP and SCP channels (most do). + * SSH Server must support SESSION and SFTP channels (SCP channel not required) + * + * NOTE: added 1 line to SftpClient#resolveRemotePath to support checking for [letter]:\ on Windows * * @author Matt Ficken * @@ -86,13 +84,18 @@ import com.sshtools.j2ssh.transport.publickey.SshPublicKey; public class SSHHost extends RemoteHost { private static final Timer timer = new Timer(); - protected final String hostname, username, password; + protected String address, hostname; + protected final String username, password; protected final int port; + protected final HostKeyVerification verif; protected boolean closed, login_fail; - protected String address, os_name_long; + @Nullable + protected String os_name_long; + @Nullable protected Boolean is_windows; + @Nullable protected SshClient ssh; - protected ScpClient scp; + @Nullable protected SftpClient sftp; public SSHHost(String hostname, String username, String password) { @@ -100,11 +103,32 @@ public class SSHHost extends RemoteHost { } public SSHHost(String hostname, int port, String username, String password) { + this(hostname, port, username, password, new HostKeyVerification() { + @Override + public boolean verifyHost(String host, SshPublicKey pk) throws TransportProtocolException { + return true; + } + }); + } + + public SSHHost(String hostname, String username, String password, HostKeyVerification verif) { + this(hostname, 22, username, password, verif); + } + + public SSHHost(String hostname, int port, String username, String password, HostKeyVerification verif) { + this.address = hostname; + + if (hostname.contains(".")||hostname.contains(":")) { + // use address instead, then ask actual hostname once connected + // @see #ensureSshOpen + hostname = null; + } + this.hostname = hostname; this.port = port; this.username = username; this.password = password; - this.address = hostname; + this.verif = verif; } protected String normalizePath(String path) { @@ -120,16 +144,13 @@ public class SSHHost extends RemoteHost { throw new IllegalStateException("SSH connection administratively/explicitly closed"); do_close(); // ensure any existing ssh, sftp or scp client gets closed (for gc) - address = InetAddress.getByName(hostname).getHostAddress(); - + if (hostname!=null) { + // address isn't IP address (its hostname), resolve it now @see SSHHost#<init> + address = InetAddress.getByName(hostname).getHostAddress(); + } ssh = new SshClient(); - ssh.connect(address, port, new HostKeyVerification() { - @Override - public boolean verifyHost(String host, SshPublicKey pk) throws TransportProtocolException { - return true; - } - }); + ssh.connect(address, port, verif); PasswordAuthenticationClient pwd = new PasswordAuthenticationClient(); @@ -141,14 +162,12 @@ public class SSHHost extends RemoteHost { login_fail = true; // IllegalStateException below may get caught/ignored throw new IllegalStateException("authentication failed. attempted login as user: "+username+" using password: "+password+" on host: "+hostname+":"+port+" ("+address+":"+port+")"); } - } - - protected void ensureScpOpen() throws UnknownHostException, IOException { - if (!login_fail && scp != null) - return; - ensureSshOpen(); - scp = ssh.openScpClient(); - } + + if (hostname==null) { + // only have ip address, get hostname + hostname = isWindows() ? getEnvValue("COMPUTERNAME") : getEnvValue("HOSTNAME"); + } + } // end protected void ensureSshOpen protected void ensureSftpOpen() throws UnknownHostException, IOException { if (!login_fail && sftp != null && !sftp.isClosed()) @@ -176,7 +195,6 @@ public class SSHHost extends RemoteHost { } sftp = null; } - scp = null; if (ssh!=null) { ssh.disconnect(); ssh = null; @@ -227,7 +245,8 @@ public class SSHHost extends RemoteHost { FileAttributes fa = sftp.stat(normalizePath(path)); return fa.isFile() || fa.isDirectory(); } catch ( Exception ex ) { - ex.printStackTrace(); + // throws Exception if it doesn't exist + //ex.printStackTrace(); } return false; } @@ -262,8 +281,10 @@ public class SSHHost extends RemoteHost { @Override public String getContents(String file) throws IOException { - ensureScpOpen(); - NoCharsetByLineReader reader = new NoCharsetByLineReader(scp.get(normalizePath(file))); + ensureSftpOpen(); + ByteArrayIOStream local = new ByteArrayIOStream(1024); + sftp.get(normalizePath(file), local); + NoCharsetByLineReader reader = new NoCharsetByLineReader(local.getInputStream()); String str = IOUtil.toString(reader, IOUtil.HALF_MEGABYTE); reader.close(); return str; @@ -271,8 +292,10 @@ public class SSHHost extends RemoteHost { @Override public String getContentsDetectCharset(String file, CharsetDeciderDecoder cdd) throws IOException { - ensureScpOpen(); - MultiCharsetByLineReader reader = new MultiCharsetByLineReader(scp.get(normalizePath(file)), cdd); + ensureSftpOpen(); + ByteArrayIOStream local = new ByteArrayIOStream(1024); + sftp.get(normalizePath(file), local); + MultiCharsetByLineReader reader = new MultiCharsetByLineReader(local.getInputStream(), cdd); String str = IOUtil.toString(reader, IOUtil.HALF_MEGABYTE); reader.close(); return str; @@ -280,14 +303,18 @@ public class SSHHost extends RemoteHost { @Override public ByLineReader readFile(String file) throws FileNotFoundException, IOException { - ensureScpOpen(); - return new NoCharsetByLineReader(scp.get(normalizePath(file))); + ensureSftpOpen(); + ByteArrayIOStream local = new ByteArrayIOStream(1024); + sftp.get(normalizePath(file), local); + return new NoCharsetByLineReader(local.getInputStream()); } @Override public ByLineReader readFileDetectCharset(String file, CharsetDeciderDecoder cdd) throws FileNotFoundException, IOException { - ensureScpOpen(); - return new MultiCharsetByLineReader(scp.get(normalizePath(file)), cdd); + ensureSftpOpen(); + ByteArrayIOStream local = new ByteArrayIOStream(1024); + sftp.get(normalizePath(file), local); + return new MultiCharsetByLineReader(local.getInputStream(), cdd); } @Override @@ -385,7 +412,7 @@ public class SSHHost extends RemoteHost { // final AtomicBoolean run = new AtomicBoolean(true); final SessionChannelClient session = do_exec(cmd, env, chdir, stdin_post, out); - if (timeout>FOUR_HOURS) { + if (timeout>NO_TIMEOUT) { timer.schedule(new TimerTask() { public void run() { try { @@ -408,7 +435,7 @@ public class SSHHost extends RemoteHost { // // read output from command - StringBuilder sb = new StringBuilder(1024); + /* TODO StringBuilder sb = new StringBuilder(1024); DefaultCharsetDeciderDecoder d = charset == null ? null : PhptTestCase.newCharsetDeciderDecoder(); ByLineReader reader = charset == null ? new NoCharsetByLineReader(out.getInputStream()) : new MultiCharsetByLineReader(out.getInputStream(), d); String line; @@ -424,16 +451,16 @@ public class SSHHost extends RemoteHost { //ex.printStackTrace(); } - out.close(); + out.close();*/ // wait for exit session.getState().waitForState(ChannelState.CHANNEL_CLOSED); // eo.exit_code = session.getExitCode(); - if (reader instanceof AbstractDetectingCharsetReader) - eo.charset = ((AbstractDetectingCharsetReader)reader).cs; - eo.output = sb.toString(); + /* TODO if (reader instanceof AbstractDetectingCharsetReader) + eo.charset = ((AbstractDetectingCharsetReader)reader).cs; */ + eo.output = out.toString(); // return eo; @@ -458,7 +485,7 @@ public class SSHHost extends RemoteHost { public String getEnvValue(String name) { try { if (isWindows()) - return cmd("ECHO %"+name+"%", ONE_MINUTE).output; + return StringUtil.chomp(cmd("ECHO %"+name+"%", ONE_MINUTE).output); else return exec("echo $"+name, ONE_MINUTE).output; } catch ( Exception ex ) { @@ -492,34 +519,33 @@ public class SSHHost extends RemoteHost { @Override public void download(String src, String dst) throws IllegalStateException, IOException, Exception { - ensureScpOpen(); - IOUtil.copy(scp.get(normalizePath(src)), new BufferedOutputStream(new FileOutputStream(dst)), IOUtil.HALF_MEGABYTE); + ensureSftpOpen(); + sftp.get(normalizePath(src), new BufferedOutputStream(new FileOutputStream(dst))); } - protected static void walk(File[] files, LinkedList<String> file_list) { + protected void do_upload(String base, File[] files, String dst) throws IOException { for (File file : files) { - if (file.isDirectory()) - walk(file.listFiles(), file_list); - else - file_list.add(file.getAbsolutePath()); + if (file.isDirectory()) { + do_upload(base, file.listFiles(), dst); + } else { + String remote_file_path = joinIntoOnePath(dst, pathFrom(base, file.getAbsolutePath())); + + sftp.put(file.getAbsolutePath(), remote_file_path); + } } } @Override - public void upload(String src, String dst) throws IllegalStateException, IOException, Exception { - ensureScpOpen(); + public void upload(String src, String dst) throws IllegalStateException, IOException { + ensureSftpOpen(); dst = normalizePath(dst); File fsrc = new File(src); if (fsrc.isDirectory()) { - LinkedList<String> file_list = new LinkedList<String>(); - - walk(fsrc.listFiles(), file_list); - - scp.put((String[]) file_list.toArray(new String[file_list.size()]), dst, false); + do_upload(src, fsrc.listFiles(), dst); } else { // uploading single file - scp.put(new BufferedInputStream(new FileInputStream(fsrc)), fsrc.length(), src, dst); + sftp.put(fsrc.getAbsolutePath(), dst); } } @@ -636,16 +662,16 @@ public class SSHHost extends RemoteHost { public void saveTextFile(String filename, String text, CharsetEncoder ce) throws IllegalStateException, IOException { if (text==null) text = ""; - ensureScpOpen(); + ensureSftpOpen(); filename = normalizePath(filename); if (ce==null) { byte[] text_bytes = text.getBytes(); - scp.put(new ByteArrayInputStream(text_bytes), text_bytes.length, filename, filename); + sftp.put(new ByteArrayInputStream(text_bytes), filename); } else { ByteBuffer bbuf = ByteBuffer.allocate(50+text.length()*2); ce.encode(CharBuffer.wrap(text.toCharArray()), bbuf, true); - scp.put(new ByteBufferInputStream(bbuf), bbuf.capacity() - bbuf.remaining(), filename, filename); + sftp.put(new ByteBufferInputStream(bbuf), filename); } } diff --git a/src/com/mostc/pftt/host/TempFileExecOutput.java b/src/com/mostc/pftt/host/TempFileExecOutput.java new file mode 100644 index 0000000..33b8218 --- /dev/null +++ b/src/com/mostc/pftt/host/TempFileExecOutput.java @@ -0,0 +1,31 @@ +package com.mostc.pftt.host; + +public class TempFileExecOutput extends ExecOutput { + public String temp_file; + + public TempFileExecOutput() { + + } + + public TempFileExecOutput(String temp_file, ExecOutput eo) { + this.charset = eo.charset; + this.exit_code = eo.exit_code; + this.output = eo.output; + this.temp_file = temp_file; + } + + public boolean cleanupIfSuccess(Host host) { + if (isSuccess()) { + cleanup(host); + return true; + } else { + return false; + } + } + + public void cleanup(Host host) { + try { + host.delete(temp_file); + } catch ( Exception ex ) {} + } +} diff --git a/src/com/mostc/pftt/main/PfttMain.java b/src/com/mostc/pftt/main/PfttMain.java index 3bdb785..94b8987 100644 --- a/src/com/mostc/pftt/main/PfttMain.java +++ b/src/com/mostc/pftt/main/PfttMain.java @@ -22,6 +22,7 @@ import org.codehaus.groovy.tools.shell.IO; import com.mostc.pftt.host.ExecOutput; import com.mostc.pftt.host.Host; import com.mostc.pftt.host.LocalHost; +import com.mostc.pftt.host.SSHHost; import com.mostc.pftt.model.app.PhpUnitAppTestPack; import com.mostc.pftt.model.phpt.EBuildBranch; import com.mostc.pftt.model.phpt.EBuildType; @@ -45,6 +46,8 @@ import com.mostc.pftt.runner.PhpUnitTestPackRunner; import com.mostc.pftt.runner.LocalPhptTestPackRunner; import com.mostc.pftt.runner.PhptTestPackRunner; import com.mostc.pftt.scenario.AbstractSAPIScenario; +import com.mostc.pftt.scenario.SMBDFSRScenario; +import com.mostc.pftt.scenario.SMBDeduplicationScenario; import com.mostc.pftt.scenario.Scenario; import com.mostc.pftt.scenario.ScenarioSet; import com.mostc.pftt.util.DownloadUtil; @@ -571,7 +574,7 @@ public class PfttMain { int args_i = 0; Config config = null; - boolean is_uac = false, windebug = false, pftt_debug = false, show_gui = false, force = false, disable_debug_prompt = true, results_only = false, dont_cleanup_test_pack = false, phpt_not_in_place = false; + boolean is_uac = false, windebug = false, pftt_debug = false, show_gui = false, force = false, disable_debug_prompt = false, results_only = false, dont_cleanup_test_pack = false, phpt_not_in_place = false; String source_pack = null; PhpDebugPack debug_pack = null; LinkedList<File> config_files = new LinkedList<File>(); @@ -720,6 +723,23 @@ public class PfttMain { LocalConsoleManager cm = new LocalConsoleManager(source_pack, debug_pack, force, windebug, results_only, show_gui, disable_debug_prompt, dont_cleanup_test_pack, phpt_not_in_place, pftt_debug); + // TODO + /* + SSHHost remote_host = new SSHHost("10.200.41.219", "administrator", "password01!"); + System.out.println(remote_host.isWindows()); + System.out.println("729"); + remote_host.exec("systeminfo", Host.ONE_MINUTE); + System.out.println("731"); + //SMBDeduplicationScenario d = new SMBDeduplicationScenario(remote_host, "F:"); + SMBDFSRScenario d = new SMBDFSRScenario(remote_host); + System.out.println("731"); + System.out.println(d.notifyPrepareStorageDir(cm, rt.host)); + d.notifyTestPackInstalled(cm, rt.host); + + System.exit(0); + */ + // + if (config_files.size()>0) { config = Config.loadConfigFromFiles(cm, (File[])config_files.toArray(new File[config_files.size()])); System.out.println("PFTT: Config: loaded "+config_files); @@ -853,7 +873,7 @@ public class PfttMain { checkUAC(is_uac, false, config, cm); // run all tests - HostEnvUtil.prepareHostEnv(rt.host, cm, !!cm.isDisableDebugPrompt()); + HostEnvUtil.prepareHostEnv(rt.host, cm, !cm.isDisableDebugPrompt()); cmd_phpt_all(rt, cm, config, build, test_pack); System.out.println("PFTT: finished"); diff --git a/src/com/mostc/pftt/main/SSHServer.java b/src/com/mostc/pftt/main/SSHServer.java index a41154a..4639b8a 100644 --- a/src/com/mostc/pftt/main/SSHServer.java +++ b/src/com/mostc/pftt/main/SSHServer.java @@ -3,7 +3,10 @@ package com.mostc.pftt.main; import java.io.IOException; import java.util.ArrayList; import java.util.EnumSet; +import java.util.LinkedList; +import java.util.regex.Pattern; +import org.apache.log4j.BasicConfigurator; import org.apache.sshd.SshServer; import org.apache.sshd.common.NamedFactory; import org.apache.sshd.server.Command; @@ -14,52 +17,96 @@ import org.apache.sshd.server.session.ServerSession; import org.apache.sshd.server.sftp.SftpSubsystem; import org.apache.sshd.server.shell.ProcessShellFactory; -import com.mostc.pftt.host.LocalHost; +import com.mostc.pftt.util.StringUtil; + +// NOTE: modified NativeSshFile#getPhysicalName to check for [letter]:\ on Windows +// and NativeSshFile#<init> public class SSHServer { - public static void main(String[] args) throws IOException { - SshServer sshd = SshServer.setUpDefaultServer(); + + public static void main(String[] args) throws IOException { + BasicConfigurator.configure(); + + SshServer sshd = SshServer.setUpDefaultServer(); - ArrayList<NamedFactory<Command>> f = new ArrayList<NamedFactory<Command>>(1); - f.add(new SftpSubsystem.Factory()); - sshd.setSubsystemFactories(f); + ArrayList<NamedFactory<Command>> f = new ArrayList<NamedFactory<Command>>(1); + f.add(new SftpSubsystem.Factory()); + sshd.setSubsystemFactories(f); - if (System.getProperty("os.name").contains("Windows")) - sshd.setShellFactory(psf("cmd.exe")); - else - sshd.setShellFactory(psf("bash")); + if (System.getProperty("os.name").contains("Windows")) + sshd.setShellFactory(psf("cmd.exe")); + else + sshd.setShellFactory(psf("bash")); - sshd.setCommandFactory(new CommandFactory() { - public Command createCommand(String command) { - return psf(command).create(); - } - }); - sshd.setPasswordAuthenticator(new PasswordAuthenticator() { - public boolean authenticate(String username, String password, ServerSession session) { - return (username.equals("administrator")) && (password.equals("password01!")); - } - }); - sshd.setPort(22); - sshd.setReuseAddress(true); - sshd.setKeyPairProvider(new SimpleGeneratorHostKeyProvider("hostkeys.txt")); - sshd.start(); - } + sshd.setCommandFactory(new CommandFactory() { + public Command createCommand(String command) { + return psf(command).create(); + } + }); + sshd.setPasswordAuthenticator(new PasswordAuthenticator() { + public boolean authenticate(String username, String password, ServerSession session) { + return (username.equals("administrator")) && (password.equals("password01!")); + } + }); + sshd.setPort(22); + sshd.setReuseAddress(true); + sshd.setKeyPairProvider(new SimpleGeneratorHostKeyProvider("hostkeys.txt")); + sshd.start(); + } + + public static String[] splitCmdString(String command) { + LinkedList<String> parts = new LinkedList<String>(); + String buf = ""; + char c; + boolean in_quote = false; + for ( int i=0 ; i < command.length() ; i++ ) { + c = command.charAt(i); + if (c=='\"' && (i==0||command.charAt(i-1) != '\\')) { + in_quote = !in_quote; + } + if (c == ' ' && !in_quote) { + buf = buf.trim(); + if (buf.length() > 0) { + buf = StringUtil.unquote(buf); + + buf = StringUtil.replaceAll(PAT_QUOTE, "\"", buf); + + parts.add(buf); + } + buf = ""; + continue; + } + buf += c; + } + buf = buf.trim(); + if (buf.length() > 0) { + if (buf.startsWith("\"")) { + buf = buf.substring(1, buf.length()-1); + + buf = StringUtil.replaceAll(PAT_QUOTE, "\"", buf); + } + parts.add(buf); + } + + return (String[])parts.toArray(new String[]{}); + } // end public static String[] splitCmdString + private static final Pattern PAT_QUOTE = Pattern.compile("\\\""); + + private static ProcessShellFactory psf(String command) { + String[] commands; + if (command.contains(" ")) { + commands = splitCmdString(command); + } else { + commands = new String[] { command }; + } - private static ProcessShellFactory psf(String command) { - String[] commands; - if (command.contains(" ")) { - commands = LocalHost.splitCmdString(command); - } else - commands = new String[] { command }; - - if (System.getProperty("os.name").contains("Windows")) { + if (System.getProperty("os.name").contains("Windows")) { + return new ProcessShellFactory( + commands, + EnumSet.of(ProcessShellFactory.TtyOptions.Echo, ProcessShellFactory.TtyOptions.ICrNl, ProcessShellFactory.TtyOptions.ONlCr)); + } - return new ProcessShellFactory( - commands, - EnumSet.of(ProcessShellFactory.TtyOptions.Echo, ProcessShellFactory.TtyOptions.ICrNl, ProcessShellFactory.TtyOptions.ONlCr)); - } + return new ProcessShellFactory(commands); + } - return new ProcessShellFactory(commands); - } - } // end public class SSHServer diff --git a/src/com/mostc/pftt/model/phpt/PhpBuild.java b/src/com/mostc/pftt/model/phpt/PhpBuild.java index 6fd2a06..74c731d 100644 --- a/src/com/mostc/pftt/model/phpt/PhpBuild.java +++ b/src/com/mostc/pftt/model/phpt/PhpBuild.java @@ -11,7 +11,9 @@ import javax.annotation.Nullable; import com.mostc.pftt.host.ExecOutput; import com.mostc.pftt.host.Host; +import com.mostc.pftt.host.TempFileExecOutput; import com.mostc.pftt.model.sapi.SAPIManager; +import com.mostc.pftt.model.smoke.RequiredExtensionsSmokeTest; import com.mostc.pftt.results.ConsoleManager; import com.mostc.pftt.results.ConsoleManager.EPrintType; import com.mostc.pftt.util.StringUtil; @@ -306,7 +308,7 @@ public class PhpBuild extends SAPIManager { if (host.exists(path)) ini = new PhpIni(host.getContents(path), build_path); else - ini = PhpIni.createDefaultIniCopy(host, this); + ini = RequiredExtensionsSmokeTest.createDefaultIniCopy(host, this); this.php_ini = new WeakReference<PhpIni>(ini); return ini; @@ -614,17 +616,13 @@ public class PhpBuild extends SAPIManager { return eval(host, null, code, timeout_seconds, auto_cleanup); } - public static class PHPOutput extends ExecOutput { + public static class PHPOutput extends TempFileExecOutput { /** the filename that the code was stored in for execution * */ - public String php_filename; protected PHPOutput(String php_filename, ExecOutput output) { - this.charset = output.charset; - this.exit_code = output.exit_code; - this.output = output.output; - this.php_filename = php_filename; + super(php_filename, output); } public boolean hasFatalError() { @@ -638,18 +636,17 @@ public class PhpBuild extends SAPIManager { } public PHPOutput printHasFatalError(String ctx, PrintStream ps) { if (hasFatalError()) { - ps.println(ctx+": "+output.trim()); + String output_str = output.trim(); + if (StringUtil.isEmpty(output_str)) + output_str = "<PHP Crashed with no output. exit_code = "+exit_code+">"; + + ps.println(ctx+": "+output_str); return this; } else { return printOutputIfCrash(ctx, ps); } } - public void cleanup(Host host) { - try { - host.delete(php_filename); - } catch ( Exception ex ) {} - } @Override public PHPOutput printOutputIfCrash(String ctx, ConsoleManager cm) { return (PHPOutput) super.printOutputIfCrash(ctx, cm); @@ -706,7 +703,7 @@ public class PhpBuild extends SAPIManager { * @return */ public String getDefaultExtensionDir() { - return build_path+"/ext"; + return build_path.contains("/") ? build_path+"/ext" : build_path+"\\ext"; } } // end public class PhpBuild diff --git a/src/com/mostc/pftt/model/phpt/PhpIni.java b/src/com/mostc/pftt/model/phpt/PhpIni.java index 515c67e..c464006 100644 --- a/src/com/mostc/pftt/model/phpt/PhpIni.java +++ b/src/com/mostc/pftt/model/phpt/PhpIni.java @@ -63,7 +63,7 @@ public class PhpIni { public static final String ISO_8859_1 = "ISO-8859-1"; public static final String U_INVALID_SUBSTITUTE = "U_INVALID_SUBSTITUTE"; public static final String DOT_HTML = ".html"; - public static final String E_ALL_OR_E_STRICT = "E_ALL|E_STRICT"; + public static final String E_ALL_NOTICE_WARNING = "E_ALL | E_NOTICE | E_WARNING"; // private static String dllName(String name) { // FUTURE macos x and solaris support @@ -97,94 +97,12 @@ public class PhpIni { public static final String EXT_TIDY = dllName("tidy"); public static final String EXT_XMLRPC = dllName("xmlrpc"); public static final String EXT_XSL = dllName("xsl"); - public static PhpIni createDefaultIniCopy(Host host, PhpBuild build) { - PhpIni ini = new PhpIni(); - ini.putSingle("default_mimetype", "text/plain"); - ini.putMulti(OUTPUT_HANDLER, StringUtil.EMPTY); - ini.putMulti(OPEN_BASEDIR, StringUtil.EMPTY); - ini.putMulti(SAFE_MODE, 0); - ini.putMulti(DISABLE_DEFS, OFF); - ini.putMulti(OUTPUT_BUFFERING, ON); - ini.putMulti("engine", "On"); - ini.putMulti("zend.enable_gc", "On"); - ini.putMulti("expose_php ", "On"); - // - // CRITICAL - ini.putMulti(ERROR_REPORTING, "E_ALL | E_NOTICE | E_WARNING"); // TODO E_ALL_OR_E_STRICT); - // CRITICAL - ini.putMulti(DISPLAY_ERRORS, "On");//1); - // CRITICAL - ini.putMulti(DISPLAY_STARTUP_ERRORS, "On");//0); - // CRITICAL - ini.putMulti(LOG_ERRORS, "On");//0); - // CRITICAL - ini.putMulti(HTML_ERRORS, "On");//0); - // CRITICAL - ini.putMulti(TRACK_ERRORS, "On");//1); - // - ini.putMulti(REPORT_MEMLEAKS, "On"); - ini.putMulti(REPORT_ZEND_DEBUG, 0); - ini.putMulti(DOCREF_ROOT, StringUtil.EMPTY); - ini.putMulti(DOCREF_EXT, DOT_HTML); - 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); - ini.putMulti(UNICODE_RUNTIME_ENCODING, ISO_8859_1); - ini.putMulti(UNICODE_SCRIPT_ENCODING, UTF_8); - ini.putMulti(UNICODE_OUTPUT_ENCODING, UTF_8); - ini.putMulti(UNICODE_FROM_ERROR_MODE, U_INVALID_SUBSTITUTE); - ini.putMulti(SESSION_AUTO_START, 0); - - // default php.ini has these extensions on Windows - // NOTE: this is validated by RequiredExtensionsSmokeTest. similar/same info is both there and here - // b/c that needs it for validation and its here because its in the default php.ini - if (host.isWindows()) { - ini.setExtensionDir(build.getDefaultExtensionDir()); - /*ini.addExtensions( - EXT_BZ2, - EXT_COM_DOTNET, - EXT_CURL, - EXT_FILEINFO, - EXT_GD2, - EXT_GETTEXT, - EXT_GMP, - EXT_INTL, - EXT_IMAP, - EXT_LDAP, - EXT_MBSTRING, - EXT_EXIF, - EXT_MYSQL, - EXT_MYSQLI, - EXT_OPENSSL, - EXT_PDO_MYSQL, - EXT_PDO_PGSQL, - EXT_PDO_SQLITE, - EXT_PDO_ODBC, - EXT_PGSQL, - EXT_SHMOP, - EXT_SOAP, - EXT_SOCKETS, - EXT_SQLITE3, - EXT_TIDY, - EXT_XMLRPC, - EXT_XSL - );*/ - } - - // TIMING: do this after all calls to #putMulti, etc... b/c that sets is_default = false - ini.is_default = true; - return ini; - } // end public static PhpIni createDefaultIniCopy // // private final HashMap<String, ArrayList<String>> ini_map; private WeakReference<PhpIni> ext_ini; private WeakReference<String> ini_str, cli_arg; - private boolean is_default = false; + public boolean is_default = false; public PhpIni() { ini_map = new HashMap<String, ArrayList<String>>(); @@ -216,15 +134,9 @@ public class PhpIni { public PhpIni(String ini_str, String pwd) { this(); if (pwd!=null&&ini_str.contains("{PWD}")) { - // TODO important to use \\\\ - if (pwd.contains("cache_list")) { - pwd="C:/php-sdk/php-test-pack-5.4-ts-windows-vc9-x86-r811cd76/ext/phar/tests/cache_list"; - } - //pwd = "C:\\\\php-sdk\\\\php-test-pack-5.4-ts-windows-vc9-x86-r811cd76\\\\"; // TODO temp ini_str = StringUtil.replaceAll(PAT_PWD, pwd, ini_str); - // BN: ensure that correct \\s are used for paths on Windows - // TODO ini_str = StringUtil.replaceAll(PAT_FS, "\\\\", ini_str); + // CRITICAL: ensure that correct \\s are used for paths on Windows } // read ini string, line by line for (String line : StringUtil.splitLines(ini_str)) { diff --git a/src/com/mostc/pftt/model/phpt/PhptTestCase.java b/src/com/mostc/pftt/model/phpt/PhptTestCase.java index adf22ef..4028047 100644 --- a/src/com/mostc/pftt/model/phpt/PhptTestCase.java +++ b/src/com/mostc/pftt/model/phpt/PhptTestCase.java @@ -64,28 +64,23 @@ public class PhptTestCase extends TestCase { new String[]{"ext/standard/tests/file/symlink_"}, new String[]{"ext/standard/tests/file/file_get_contents_", "ext/standard/tests/file/file_put_contents_"}, new String[]{"ext/standard/tests/file/windows_acls/", "ext/standard/tests/file/windows_links/"}, - //new String[]{"ext/standard/tests/file/0"}, // note: this array is processed in order, so this entry will catch any remaining /file/ phpts - //new String[]{"ext/standard/tests/file/"}, new String[]{"ext/standard/tests/dir/"}, - // TODO new String[]{"ext/standard/tests/streams/stream_get_meta_data_socket_variation1.phpt"}, new String[]{"ext/standard/tests/streams/stream_get_meta_data_socket_variation2.phpt"}, new String[]{"ext/standard/tests/streams/stream_get_meta_data_socket_variation3.phpt"}, new String[]{"ext/standard/tests/streams/stream_get_meta_data_socket_variation4.phpt"}, new String[]{"ext/standard/tests/sockets/", "ext/sockets/"}, - // TODO new String[]{"tests/security/"}, // the bug38450* tests fail randomly under apache if run on apache instance // with other tests - run them (serially) on their own apache instance new String[]{"ext/standard/tests/file/bug38450"}, new String[]{"ext/standard/tests/network/"}, - // TODO new String[]{"ext/session", "tests/basic/bug20539.phpt"}, new String[]{"ext/mysql/", "ext/pdo_mysql/", "ext/mysqli/"}, new String[]{"ext/pgsql/", "ext/pdo_pgsql/"}, // several 61367 tests that aren't thread-safe (temp files) new String[]{"ext/libxml/tests/bug61367"}, new String[]{"sapi/cli/tests/php_cli_server_"}, - // TODO new String[]{"sapi/cgi/"}, + new String[]{"ext/standard/tests/strings/vprintf_"}, new String[]{"ext/firebird/", "ext/pdo_firebird/"}, new String[]{"ext/sybase/"}, new String[]{"ext/interbase/", "ext/pdo_interbase/"}, @@ -725,7 +720,7 @@ public class PhptTestCase extends TestCase { ArrayList<String> test_names = new ArrayList<String>(2); if (!output.hasFatalError()) { - String base_dir = Host.dirname(output.php_filename); + String base_dir = Host.dirname(output.temp_file); for (String line : output.getLines()) { // code may use __DIR__ to get its current directory => strip off current directory(/tmp, etc...) if (line.startsWith(base_dir)) { @@ -737,6 +732,9 @@ public class PhptTestCase extends TestCase { continue; test_names.add(line); } + + // delete temporary file + output.cleanup(host); } return test_names.toArray(new String[test_names.size()]); diff --git a/src/com/mostc/pftt/model/smoke/RequiredExtensionsSmokeTest.java b/src/com/mostc/pftt/model/smoke/RequiredExtensionsSmokeTest.java index bef7684..e54b116 100644 --- a/src/com/mostc/pftt/model/smoke/RequiredExtensionsSmokeTest.java +++ b/src/com/mostc/pftt/model/smoke/RequiredExtensionsSmokeTest.java @@ -3,8 +3,10 @@ package com.mostc.pftt.model.smoke; import com.mostc.pftt.host.Host; import com.mostc.pftt.model.phpt.ESAPIType; import com.mostc.pftt.model.phpt.PhpBuild; +import com.mostc.pftt.model.phpt.PhpIni; import com.mostc.pftt.results.ConsoleManager; import com.mostc.pftt.results.ConsoleManager.EPrintType; +import com.mostc.pftt.util.StringUtil; /** Smoke test that verifies a PHP Build has all the required extensions. * @@ -103,5 +105,93 @@ public class RequiredExtensionsSmokeTest extends SmokeTest { public String getName() { return "Required-Extensions"; } + + /** creates a PhpIni with default configuration, default extensions loaded etc... + * + * A PhpBuild using this PhpIni should pass this test. + * + * @param host + * @param build + * @return + */ + public static PhpIni createDefaultIniCopy(Host host, PhpBuild build) { + PhpIni ini = new PhpIni(); + ini.putSingle("default_mimetype", "text/plain"); + ini.putMulti(PhpIni.OUTPUT_HANDLER, StringUtil.EMPTY); + ini.putMulti(PhpIni.OPEN_BASEDIR, StringUtil.EMPTY); + ini.putMulti(PhpIni.SAFE_MODE, 0); + ini.putMulti(PhpIni.DISABLE_DEFS, PhpIni.OFF); + ini.putMulti(PhpIni.OUTPUT_BUFFERING, PhpIni.ON); + // + // CRITICAL + ini.putMulti(PhpIni.ERROR_REPORTING, PhpIni.E_ALL_NOTICE_WARNING); + // CRITICAL + ini.putMulti(PhpIni.DISPLAY_ERRORS, PhpIni.ON); + // CRITICAL + ini.putMulti(PhpIni.DISPLAY_STARTUP_ERRORS, PhpIni.OFF); + // CRITICAL + ini.putMulti(PhpIni.LOG_ERRORS, PhpIni.ON); + // CRITICAL + ini.putMulti(PhpIni.HTML_ERRORS, PhpIni.OFF); + // CRITICAL + ini.putMulti(PhpIni.TRACK_ERRORS, PhpIni.ON); + // + ini.putMulti(PhpIni.REPORT_MEMLEAKS, PhpIni.ON); + ini.putMulti(PhpIni.REPORT_ZEND_DEBUG, PhpIni.OFF); + ini.putMulti(PhpIni.DOCREF_ROOT, StringUtil.EMPTY); + ini.putMulti(PhpIni.DOCREF_EXT, PhpIni.DOT_HTML); + ini.putMulti(PhpIni.ERROR_PREPEND_STRING, StringUtil.EMPTY); + ini.putMulti(PhpIni.ERROR_APPEND_STRING, StringUtil.EMPTY); + ini.putMulti(PhpIni.AUTO_PREPEND_FILE, StringUtil.EMPTY); + ini.putMulti(PhpIni.AUTO_APPEND_FILE, StringUtil.EMPTY); + ini.putMulti(PhpIni.MAGIC_QUOTES_RUNTIME, PhpIni.OFF); + ini.putMulti(PhpIni.IGNORE_REPEATED_ERRORS, PhpIni.OFF); + ini.putMulti(PhpIni.PRECISION, 14); + ini.putMulti(PhpIni.UNICODE_RUNTIME_ENCODING, PhpIni.ISO_8859_1); + ini.putMulti(PhpIni.UNICODE_SCRIPT_ENCODING, PhpIni.UTF_8); + ini.putMulti(PhpIni.UNICODE_OUTPUT_ENCODING, PhpIni.UTF_8); + ini.putMulti(PhpIni.UNICODE_FROM_ERROR_MODE, PhpIni.U_INVALID_SUBSTITUTE); + ini.putMulti(PhpIni.SESSION_AUTO_START, PhpIni.OFF); + + // default php.ini has these extensions on Windows + // NOTE: this is validated by RequiredExtensionsSmokeTest. similar/same info is both there and here + // b/c that needs it for validation and its here because its in the default php.ini + if (host.isWindows()) { + ini.setExtensionDir(build.getDefaultExtensionDir()); + ini.addExtensions( + PhpIni.EXT_BZ2, + PhpIni.EXT_COM_DOTNET, + PhpIni.EXT_CURL, + PhpIni.EXT_FILEINFO, + PhpIni.EXT_GD2, + PhpIni.EXT_GETTEXT, + PhpIni.EXT_GMP, + PhpIni.EXT_INTL, + PhpIni.EXT_IMAP, + PhpIni.EXT_LDAP, + PhpIni.EXT_MBSTRING, + PhpIni.EXT_EXIF, + PhpIni.EXT_MYSQL, + PhpIni.EXT_MYSQLI, + PhpIni.EXT_OPENSSL, + PhpIni.EXT_PDO_MYSQL, + PhpIni.EXT_PDO_PGSQL, + PhpIni.EXT_PDO_SQLITE, + PhpIni.EXT_PDO_ODBC, + PhpIni.EXT_PGSQL, + PhpIni.EXT_SHMOP, + PhpIni.EXT_SOAP, + PhpIni.EXT_SOCKETS, + PhpIni.EXT_SQLITE3, + PhpIni.EXT_TIDY, + PhpIni.EXT_XMLRPC, + PhpIni.EXT_XSL + ); + } + + // TIMING: do this after all calls to #putMulti, etc... b/c that sets is_default = false + ini.is_default = true; + return ini; + } // end public static PhpIni createDefaultIniCopy } // end public class RequiredExtensionsSmokeTest diff --git a/src/com/mostc/pftt/model/smoke/RequiredFeaturesSmokeTest.java b/src/com/mostc/pftt/model/smoke/RequiredFeaturesSmokeTest.java index d31e617..7621bc5 100644 --- a/src/com/mostc/pftt/model/smoke/RequiredFeaturesSmokeTest.java +++ b/src/com/mostc/pftt/model/smoke/RequiredFeaturesSmokeTest.java @@ -258,7 +258,7 @@ public class RequiredFeaturesSmokeTest extends SmokeTest { "Collecting statistics => Yes%s" + "Collecting memory statistics => No%s" + "Tracing => n/a%s" + -"Loaded plugins => mysqlnd,example,debug_trace,auth_plugin_mysql_native_password,auth_plugin_mysql_clear_password%s" + +"Loaded plugins => %s" + "API Extensions => %s" + "%s" + "mysqlnd statistics =>%s" + @@ -423,10 +423,6 @@ public class RequiredFeaturesSmokeTest extends SmokeTest { "bytes_received_real_data_normal => 0%s" + "bytes_received_real_data_ps => 0%s" + "%s" + -"example statistics => %s" + -"stat1 => 0%s" + -"stat2 => 0%s" + -"%s" + "odbc%s" + "%s" + "ODBC Support => enabled%s" + @@ -850,7 +846,7 @@ public class RequiredFeaturesSmokeTest extends SmokeTest { "Collecting statistics => Yes%s" + "Collecting memory statistics => No%s" + "Tracing => n/a%s" + -"Loaded plugins => mysqlnd,example,debug_trace,auth_plugin_mysql_native_password,auth_plugin_mysql_clear_password%s" + +"Loaded plugins => %s" + "API Extensions => %s" + "%s" + "mysqlnd statistics =>%s" + @@ -1015,10 +1011,6 @@ public class RequiredFeaturesSmokeTest extends SmokeTest { "bytes_received_real_data_normal => 0%s" + "bytes_received_real_data_ps => 0%s" + "%s" + -"example statistics => %s" + -"stat1 => 0%s" + -"stat2 => 0%s" + -"%s" + "odbc%s" + "%s" + "ODBC Support => enabled%s" + diff --git a/src/com/mostc/pftt/model/ui/wordpress.groovy b/src/com/mostc/pftt/model/ui/wordpress.groovy index 23aa1d5..f65e6a6 100644 --- a/src/com/mostc/pftt/model/ui/wordpress.groovy +++ b/src/com/mostc/pftt/model/ui/wordpress.groovy @@ -1,6 +1,6 @@ package com.mostc.pftt.model.ui; -import com.mostc.pftt.scenario.WordpressScenario +import com.mostc.pftt.scenario.app.WordpressScenario // auto import UITestCase // cr or case_runner - diff --git a/src/com/mostc/pftt/results/PhptResultPack.java b/src/com/mostc/pftt/results/PhptResultPack.java index 5d0da0d..f2d0a0c 100644 --- a/src/com/mostc/pftt/results/PhptResultPack.java +++ b/src/com/mostc/pftt/results/PhptResultPack.java @@ -50,10 +50,10 @@ public abstract class PhptResultPack { } public static float round1(float value) { - float ret = (float) Math.round( ( value * 10000.0d)/100.0d ); - if (ret==100.0f && value!=100.0f) + float ret = ( (float) Math.round( value * 10.0f ) ) / 10.0f; + if (ret==100.0f && value<100.0f) // only show 100% if its really 100% - return 99.99f; + return 99.9f; else return ret; } diff --git a/src/com/mostc/pftt/runner/AbstractPhptTestCaseRunner.java b/src/com/mostc/pftt/runner/AbstractPhptTestCaseRunner.java index f650587..43a66e0 100644 --- a/src/com/mostc/pftt/runner/AbstractPhptTestCaseRunner.java +++ b/src/com/mostc/pftt/runner/AbstractPhptTestCaseRunner.java @@ -10,12 +10,9 @@ import com.mostc.pftt.model.phpt.ESAPIType; 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.PhptActiveTestPack; import com.mostc.pftt.results.ConsoleManager; import com.mostc.pftt.results.IPhptTestResultReceiver; import com.mostc.pftt.results.PhptTestResult; -import com.mostc.pftt.scenario.AbstractINIScenario; -import com.mostc.pftt.scenario.Scenario; import com.mostc.pftt.scenario.ScenarioSet; public abstract class AbstractPhptTestCaseRunner { @@ -34,18 +31,6 @@ public abstract class AbstractPhptTestCaseRunner { public abstract void runTest() throws IOException, Exception, Throwable; - public static PhpIni createIniForTest(ConsoleManager cm, Host host, PhpBuild build, PhptActiveTestPack active_test_pack, ScenarioSet scenario_set) { - PhpIni ini = PhpIni.createDefaultIniCopy(host, build); // TODO - //_ini.replaceAll(test_case.getINI(active_test_pack, host)); - for ( Scenario scenario : scenario_set ) { - if (scenario instanceof AbstractINIScenario) { - ((AbstractINIScenario)scenario).setup(cm, host, build, ini); - } - } - ini.addToIncludePath(host, active_test_pack.getDirectory()); - return ini; - } - public static Map<String, String> generateENVForTestCase(ConsoleManager cm, Host host, PhpBuild build, ScenarioSet scenario_set, PhptTestCase test_case) throws Exception { // read ENV vars from test, from its parent (if a test redirected to this test), and merge from scenario // @@ -101,7 +86,7 @@ public abstract class AbstractPhptTestCaseRunner { return true; } else if (test_case.getName().contains("dba")||test_case.getName().contains("sybase")||test_case.getName().contains("snmp")||test_case.getName().contains("interbase")||test_case.getName().contains("ldap")||test_case.getName().contains("imap")||test_case.getName().contains("ftp")||test_case.getName().contains("curl")||test_case.getName().contains("sql")||test_case.getName().contains("enchant")||test_case.getName().contains("oci")||test_case.getName().contains("pcntl")||test_case.getName().contains("soap")||test_case.getName().contains("xmlrpc")||test_case.getName().contains("pdo")||test_case.getName().contains("odbc")) { - // TODO temp - don't run these SKIPIFs without the scenario loaded + // TODO don't run these SKIPIFs without the scenario loaded twriter.addResult(host, scenario_set, new PhptTestResult(host, EPhptTestStatus.SKIP, test_case, "test would've been skipped", null, null, null, null, null, null, null, null, null, null, null)); return true; diff --git a/src/com/mostc/pftt/runner/AbstractPhptTestCaseRunner2.java b/src/com/mostc/pftt/runner/AbstractPhptTestCaseRunner2.java index 0353429..d5aa2ce 100644 --- a/src/com/mostc/pftt/runner/AbstractPhptTestCaseRunner2.java +++ b/src/com/mostc/pftt/runner/AbstractPhptTestCaseRunner2.java @@ -133,11 +133,12 @@ public abstract class AbstractPhptTestCaseRunner2 extends AbstractPhptTestCaseRu host.saveTextFile(test_clean, test_case.get(EPhptSection.CLEAN)); } // else test_clean = null; - + /* if (StringUtil.isEmpty(ini.getExtensionDir())) // this is done in PhpIni#createDefaultIniCopy if the host is Windows // but for Linux/non-Windows, this won't have been done ini.setExtensionDir(build.getDefaultExtensionDir()); + */ return true; } // end boolean prepare @@ -409,7 +410,7 @@ public abstract class AbstractPhptTestCaseRunner2 extends AbstractPhptTestCaseRu } if (expected_re_match||a(test_case)) { - twriter.addResult(host, scenario_set, new PhptTestResult(host, test_case.isXFail()?EPhptTestStatus.XFAIL_WORKS:EPhptTestStatus.PASS, test_case, output, null, null, charset, ini, env, splitCmdString(), stdin_post, getShellScript(), null, null, null)); + twriter.addResult(host, scenario_set, new PhptTestResult(host, test_case.isXFail()?EPhptTestStatus.XFAIL:EPhptTestStatus.PASS, test_case, output, null, null, charset, ini, env, splitCmdString(), stdin_post, getShellScript(), null, null, null)); return; } @@ -431,7 +432,7 @@ public abstract class AbstractPhptTestCaseRunner2 extends AbstractPhptTestCaseRu } if (expected_re_match) { - twriter.addResult(host, scenario_set, new PhptTestResult(host, test_case.isXFail()?EPhptTestStatus.XFAIL_WORKS:EPhptTestStatus.PASS, test_case, output, null, null, charset, ini, env, splitCmdString(), stdin_post, getShellScript(), null, null, null)); + twriter.addResult(host, scenario_set, new PhptTestResult(host, test_case.isXFail()?EPhptTestStatus.XFAIL:EPhptTestStatus.PASS, test_case, output, null, null, charset, ini, env, splitCmdString(), stdin_post, getShellScript(), null, null, null)); return; } @@ -443,7 +444,7 @@ public abstract class AbstractPhptTestCaseRunner2 extends AbstractPhptTestCaseRu if (equalsNoWS(output, expected)||a(test_case)||output.contains("<html>")) { - twriter.addResult(host, scenario_set, new PhptTestResult(host, test_case.isXFail()?EPhptTestStatus.XFAIL_WORKS:EPhptTestStatus.PASS, test_case, output, null, null, charset, ini, env, splitCmdString(), stdin_post, getShellScript(), null, null, null)); + twriter.addResult(host, scenario_set, new PhptTestResult(host, test_case.isXFail()?EPhptTestStatus.XFAIL:EPhptTestStatus.PASS, test_case, output, null, null, charset, ini, env, splitCmdString(), stdin_post, getShellScript(), null, null, null)); return; } @@ -460,7 +461,7 @@ public abstract class AbstractPhptTestCaseRunner2 extends AbstractPhptTestCaseRu // compare again if (equalsNoWS(output, expected)) { - twriter.addResult(host, scenario_set, new PhptTestResult(host, test_case.isXFail()?EPhptTestStatus.XFAIL_WORKS:EPhptTestStatus.PASS, test_case, output, null, null, charset, ini, env, splitCmdString(), stdin_post, getShellScript(), null, null, null)); + twriter.addResult(host, scenario_set, new PhptTestResult(host, test_case.isXFail()?EPhptTestStatus.XFAIL:EPhptTestStatus.PASS, test_case, output, null, null, charset, ini, env, splitCmdString(), stdin_post, getShellScript(), null, null, null)); return; } // end if @@ -470,7 +471,7 @@ public abstract class AbstractPhptTestCaseRunner2 extends AbstractPhptTestCaseRu String output_trim = output.trim(); if (StringUtil.isEmpty(output_trim)||a(test_case)||output.contains("<html>")) { - twriter.addResult(host, scenario_set, new PhptTestResult(host, test_case.isXFail()?EPhptTestStatus.XFAIL_WORKS:EPhptTestStatus.PASS, test_case, output, null, null, charset, ini, env, splitCmdString(), stdin_post, getShellScript(), null, null, null)); + twriter.addResult(host, scenario_set, new PhptTestResult(host, test_case.isXFail()?EPhptTestStatus.XFAIL:EPhptTestStatus.PASS, test_case, output, null, null, charset, ini, env, splitCmdString(), stdin_post, getShellScript(), null, null, null)); return; } @@ -478,56 +479,48 @@ public abstract class AbstractPhptTestCaseRunner2 extends AbstractPhptTestCaseRu // if here, test failed! - if (StringUtil.isNotEmpty(getCrashedSAPIOutput())) { - // TODO - twriter.addResult(host, scenario_set, new PhptTestResult(host, EPhptTestStatus.CRASH, test_case, getCrashedSAPIOutput(), null, null, charset, ini, env, splitCmdString(), stdin_post, getShellScript(), null, null, preoverride_actual)); - + // generate a diff + String[] actual_lines = StringUtil.splitLines(output); + String[] expected_lines = StringUtil.splitLines(test_case.getExpected()); + Diff<String> diff = new Diff<String>(expected_lines, actual_lines); + + String expectf; + // generate the EXPECTF section to show the user the regular expression that was actually used (generated from EXPECTF section) to evaluate test output + if (test_case.containsSection(EPhptSection.EXPECTF)) { + expectf = PhptTestCase.prepareExpectF(test_case.getTrim(EPhptSection.EXPECTF)); } else { - // test is FAIL or XFAIL_WORKS - - // generate a diff - String[] actual_lines = StringUtil.splitLines(output); - String[] expected_lines = StringUtil.splitLines(test_case.getExpected()); - Diff<String> diff = new Diff<String>(expected_lines, actual_lines); - - String expectf; - // generate the EXPECTF section to show the user the regular expression that was actually used (generated from EXPECTF section) to evaluate test output - if (test_case.containsSection(EPhptSection.EXPECTF)) { - expectf = PhptTestCase.prepareExpectF(test_case.getTrim(EPhptSection.EXPECTF)); - } else { - expectf = null; - } + expectf = null; + } - PhptTestResult result; - if (test_case.isXFail()) { - result = new PhptTestResult(host, EPhptTestStatus.XFAIL, test_case, output, null, null, charset, ini, env, splitCmdString(), stdin_post, getShellScript(), null, null, preoverride_actual); - } else { - result = notifyFail(new PhptTestResult(host, EPhptTestStatus.FAIL, test_case, output, actual_lines, expected_lines, charset, ini, env, splitCmdString(), stdin_post, getShellScript(), diff, expectf, preoverride_actual, getCrashedSAPIOutput())); - } - + PhptTestResult result; + if (test_case.isXFail()) { + result = new PhptTestResult(host, EPhptTestStatus.XFAIL_WORKS, test_case, output, null, null, charset, ini, env, splitCmdString(), stdin_post, getShellScript(), null, null, preoverride_actual); + } else { + result = notifyFail(new PhptTestResult(host, EPhptTestStatus.FAIL, test_case, output, actual_lines, expected_lines, charset, ini, env, splitCmdString(), stdin_post, getShellScript(), diff, expectf, preoverride_actual, getCrashedSAPIOutput())); + } + + // + // set result#regex_compiler_dump and result#regex_output dump if test result is FAIL or XFAIL_WORKS and test has an EXPECTF or EXPECTREGEX section + if (test_case.containsSection(EPhptSection.EXPECTF) || test_case.containsSection(EPhptSection.EXPECTREGEX)) { + // test may be failing due to a bad regular expression in test or bug in regular expression engine // - // set result#regex_compiler_dump and result#regex_output dump if test result is FAIL or XFAIL_WORKS and test has an EXPECTF or EXPECTREGEX section - if (test_case.containsSection(EPhptSection.EXPECTF) || test_case.containsSection(EPhptSection.EXPECTREGEX)) { - // test may be failing due to a bad regular expression in test or bug in regular expression engine - // - // get a debug dump from the regular expression engine to save with the result - // - // (this is an expensive operation so it shouldn't be done for every test. there shouldn't be - // very many FAIL tests so this shouldn't be done very much) - LengthLimitStringWriter dump_sw = new LengthLimitStringWriter(); - LengthLimitStringWriter output_sw = new LengthLimitStringWriter(); - PrintWriter dump_pw = new PrintWriter(dump_sw); - PrintWriter output_pw = new PrintWriter(output_sw); - - test_case.debugExpectedRegularExpression(host, scenario_set, twriter, result.actual, dump_pw, output_pw); - - result.regex_compiler_dump = dump_sw.toString(); - result.regex_output = output_sw.toString(); - } + // get a debug dump from the regular expression engine to save with the result // + // (this is an expensive operation so it shouldn't be done for every test. there shouldn't be + // very many FAIL tests so this shouldn't be done very much) + LengthLimitStringWriter dump_sw = new LengthLimitStringWriter(); + LengthLimitStringWriter output_sw = new LengthLimitStringWriter(); + PrintWriter dump_pw = new PrintWriter(dump_sw); + PrintWriter output_pw = new PrintWriter(output_sw); - twriter.addResult(host, scenario_set, result); + test_case.debugExpectedRegularExpression(host, scenario_set, twriter, result.actual, dump_pw, output_pw); + + result.regex_compiler_dump = dump_sw.toString(); + result.regex_output = output_sw.toString(); } + // + + twriter.addResult(host, scenario_set, result); } // end void evalTest protected PhptTestResult notifyFail(PhptTestResult result) { diff --git a/src/com/mostc/pftt/runner/CliPhptTestCaseRunner.java b/src/com/mostc/pftt/runner/CliPhptTestCaseRunner.java index 794b4ad..0abd429 100644 --- a/src/com/mostc/pftt/runner/CliPhptTestCaseRunner.java +++ b/src/com/mostc/pftt/runner/CliPhptTestCaseRunner.java @@ -19,6 +19,7 @@ import com.mostc.pftt.model.phpt.PhpIni; import com.mostc.pftt.model.phpt.PhptTestCase; import com.mostc.pftt.model.phpt.PhptSourceTestPack; import com.mostc.pftt.model.phpt.PhptActiveTestPack; +import com.mostc.pftt.model.smoke.RequiredExtensionsSmokeTest; import com.mostc.pftt.results.ConsoleManager; import com.mostc.pftt.results.IPhptTestResultReceiver; import com.mostc.pftt.results.PhptTestResult; @@ -111,7 +112,18 @@ public class CliPhptTestCaseRunner extends AbstractPhptTestCaseRunner2 { "ext/session/tests/023.phpt", "ext/phar/tests/phar_get_supportedcomp3.phpt", "ext/phar/tests/phar_create_in_cwd.phpt", - "ext/phar/tests/phar_get_supported_signatures_002.phpt" + "ext/phar/tests/phar_get_supported_signatures_002.phpt", + // + "ext/standard/tests/streams/stream_get_meta_data_socket_variation2.phpt", + "ext/standard/tests/streams/stream_get_meta_data_socket_variation1.phpt", + "ext/standard/tests/network/gethostbyname_error002.phpt", + "ext/session/tests/003.phpt", + "ext/standard/tests/streams/stream_get_meta_data_socket_variation3.phpt", + "ext/phar/tests/phar_commitwrite.phpt", + "ext/standard/tests/file/fgets_socket_variation1.phpt", + "ext/standard/tests/network/shutdown.phpt", + "ext/standard/tests/file/fgets_socket_variation2.phpt", + "ext/standard/tests/network/tcp4loop.phpt" )) { twriter.addResult(host, scenario_set, new PhptTestResult(host, EPhptTestStatus.XSKIP, test_case, "test sometimes randomly fails, ignore it", null, null, null, null, null, null, null, null, null, null, null)); @@ -151,6 +163,7 @@ public class CliPhptTestCaseRunner extends AbstractPhptTestCaseRunner2 { } static boolean saved_ini = false; + static String ini_dir; @Override protected void prepareTest() throws Exception { @@ -158,11 +171,15 @@ public class CliPhptTestCaseRunner extends AbstractPhptTestCaseRunner2 { // if (!saved_ini) { + // @see CliScenario#createIniForTest saved_ini = true; - String ini_file = build.getDefaultPhpIniPath(host, ESAPIType.CLI); + ini_dir = host.mktempname(getClass()); + host.mkdirs(ini_dir); + + String ini_file = ini_dir + "/php.ini"; - PhpIni def_ini = PhpIni.createDefaultIniCopy(host, build); + PhpIni def_ini = RequiredExtensionsSmokeTest.createDefaultIniCopy(host, build); FileWriter fw = new FileWriter(ini_file); fw.write(def_ini.toString()); @@ -176,8 +193,9 @@ public class CliPhptTestCaseRunner extends AbstractPhptTestCaseRunner2 { { StringBuilder sb = new StringBuilder(64); sb.append(selected_php_exe); - // -n => critical: ignores any .ini file with the php build - // TODO sb.append(" -n "); + // -c => provide default PhpIni file + sb.append(" -c "); + sb.append(ini_dir); sb.append(ini_settings); sb.append(" -f \"");sb.append(host.fixPath(test_file));sb.append("\" "); if (test_case.containsSection(EPhptSection.ARGS)) { @@ -297,6 +315,12 @@ public class CliPhptTestCaseRunner extends AbstractPhptTestCaseRunner2 { // if test is taking longer than 40 seconds to run, spin up an additional thread to compensate (so other non-slow tests can be executed) output = host.exec(shell_file, Host.ONE_MINUTE, env, stdin_post, test_case.isNon8BitCharset()?test_case.getCommonCharset():null, active_test_pack.getDirectory(), thread, 40); + if (output.isCrashed() && StringUtil.isWhitespaceOrEmpty(output.output)) { + not_crashed = false; // @see #runTest + + twriter.addResult(host, scenario_set, new PhptTestResult(host, EPhptTestStatus.CRASH, test_case, "PFTT: exit_code="+output.exit_code+"\n"+output.output, null, null, null, ini, env, null, stdin_post, null, null, null, null, output.output)); + } + return output.output; } // end String executeTest diff --git a/src/com/mostc/pftt/runner/HttpTestCaseRunner.java b/src/com/mostc/pftt/runner/HttpTestCaseRunner.java index 5a77980..d451504 100644 --- a/src/com/mostc/pftt/runner/HttpTestCaseRunner.java +++ b/src/com/mostc/pftt/runner/HttpTestCaseRunner.java @@ -47,11 +47,13 @@ import com.mostc.pftt.util.StringUtil; */ // TODO error msg should tell how many times web server was restarted +// TODO restart a 2nd time before giving up public class HttpTestCaseRunner extends AbstractPhptTestCaseRunner2 { protected final WebServerManager smgr; protected final ByteArrayOutputStream request_bytes, response_bytes; protected WebServerInstance web = null; protected String cookie_str; + protected DebuggingHttpClientConnection conn; protected final HttpParams params; protected final HttpProcessor httpproc; protected final HttpRequestExecutor httpexecutor; @@ -63,12 +65,12 @@ public class HttpTestCaseRunner extends AbstractPhptTestCaseRunner2 { this.httpexecutor = httpexecutor; this.smgr = smgr; this.web = web; - // CRITICAL: need this to get ENV from this TestCaseGroup + // IMPORTANT: need this to get ENV from this TestCaseGroup if (env!=null && ((env.containsKey("TEMP")&&env.get("TEMP").equals(".")) || (env.containsKey("TMP")&&env.get("TMP").equals(".")))) { // checks for case like: ext/phar/commit/tar/phar_commitwrite.phpt this.env = new HashMap<String,String>(7); this.env.putAll(env); - // TODO + this.env.put("TEMP", active_test_pack.getDirectory()+"/"+Host.dirname(test_case.getName())); this.env.put("TMP", active_test_pack.getDirectory()+"/"+Host.dirname(test_case.getName())); } else { @@ -166,8 +168,9 @@ public class HttpTestCaseRunner extends AbstractPhptTestCaseRunner2 { "ext/standard/tests/general_functions/var_dump.phpt", "ext/session/tests/003.phpt", "ext/session/tests/023.phpt", - "ext/standard/tests/streams/stream_get_meta_data_socket_variation3.phpt", - "ext/standard/tests/streams/stream_get_meta_data_socket_variation4.phpt", + "tests/basic/032.phpt", + "tests/basic/031.phpt", + "tests/basic/030.phpt", ///////////////// // getopt returns false under web server (ok) "ext/standard/tests/general_functions/bug43293_1.phpt", @@ -206,6 +209,12 @@ public class HttpTestCaseRunner extends AbstractPhptTestCaseRunner2 { cookie_str = test_case.get(EPhptSection.COOKIE); } + protected void markTestAsCrash() { + not_crashed = false; // @see #runTest + + twriter.addResult(host, scenario_set, new PhptTestResult(host, EPhptTestStatus.CRASH, test_case, null, null, null, null, ini, env, null, stdin_post, null, null, null, null, web==null?null:web.getSAPIOutput())); + } + /** executes SKIPIF, TEST or CLEAN over http. * * retries request if it times out and restarts web server if it crashes @@ -266,7 +275,6 @@ public class HttpTestCaseRunner extends AbstractPhptTestCaseRunner2 { return sb.toString(); } } // end protected String http_execute - protected String do_http_execute(String path, EPhptSection section, boolean is_replacement) throws Exception { path = Host.toUnixPath(path); @@ -334,13 +342,6 @@ public class HttpTestCaseRunner extends AbstractPhptTestCaseRunner2 { } } - protected void markTestAsCrash() { - not_crashed = false; // @see #runTest - - twriter.addResult(host, scenario_set, new PhptTestResult(host, EPhptTestStatus.CRASH, test_case, null, null, null, null, ini, env, null, stdin_post, null, null, null, null, web==null?null:web.getSAPIOutput())); - } - - protected DebuggingHttpClientConnection conn; protected String do_http_get(String path) throws Exception { return do_http_get(path, 0); } diff --git a/src/com/mostc/pftt/scenario/AbstractParallelScenario.java b/src/com/mostc/pftt/scenario/AbstractParallelScenario.java index 7e72338..3375664 100644 --- a/src/com/mostc/pftt/scenario/AbstractParallelScenario.java +++ b/src/com/mostc/pftt/scenario/AbstractParallelScenario.java @@ -8,4 +8,9 @@ package com.mostc.pftt.scenario; public abstract class AbstractParallelScenario extends Scenario { + @Override + public boolean ignoreForShortName() { + return true; + } + } diff --git a/src/com/mostc/pftt/scenario/AbstractSAPIScenario.java b/src/com/mostc/pftt/scenario/AbstractSAPIScenario.java index 2fbf93b..f6050d5 100644 --- a/src/com/mostc/pftt/scenario/AbstractSAPIScenario.java +++ b/src/com/mostc/pftt/scenario/AbstractSAPIScenario.java @@ -84,5 +84,7 @@ public abstract class AbstractSAPIScenario extends AbstractSerialScenario { * @throws Exception */ public abstract TestCaseGroupKey createTestGroupKey(ConsoleManager cm, Host host, PhpBuild build, ScenarioSet scenario_set, PhptActiveTestPack active_test_pack, PhptTestCase test_case, TestCaseGroupKey group_key) throws Exception; + + public abstract PhpIni createIniForTest(ConsoleManager cm, Host host, PhpBuild build, PhptActiveTestPack active_test_pack, ScenarioSet scenario_set); } // end public abstract class AbstractSAPIScenario diff --git a/src/com/mostc/pftt/scenario/AbstractSMBScenario.java b/src/com/mostc/pftt/scenario/AbstractSMBScenario.java index e84f723..fee0b1b 100644 --- a/src/com/mostc/pftt/scenario/AbstractSMBScenario.java +++ b/src/com/mostc/pftt/scenario/AbstractSMBScenario.java @@ -18,23 +18,25 @@ import com.mostc.pftt.util.StringUtil; public abstract class AbstractSMBScenario extends AbstractRemoteFileSystemScenario { protected final RemoteHost remote_host; protected final String base_file_path, base_share_name; - protected String share_name, file_path, unc_path, smb_path, local_drive; + // file path is path on server where share is stored + // network path is in both UNC and URL format (UNC for Windows, URL for Linux) + protected String share_name, remote_path, unc_path, url_path, local_path; public AbstractSMBScenario(RemoteHost remote_host, String base_file_path, String base_share_name) { this.remote_host = remote_host; // if (StringUtil.isEmpty(base_file_path)) - // @see SMBDeduplicationScenario - base_file_path = "C:\\PFTT_Share"; + // fallback to a default path, @see SMBDeduplicationScenario + base_file_path = remote_host.isWindows() ? "C:\\PFTT_Share" : "/var/data/PFTT_Share"; else if (StringUtil.isEmpty(Host.basename(base_file_path))) // base_file_path ~= C:\ - base_file_path += "PFTT_Share"; + base_file_path += "\\PFTT_Share"; if (StringUtil.isNotEmpty(base_share_name)) base_share_name = base_share_name.trim(); if (StringUtil.isEmpty(base_share_name)) { base_share_name = Host.basename(base_file_path); if (StringUtil.isEmpty(base_share_name)) - base_share_name = "PFTT_Share"; + base_share_name = "\\PFTT_Share"; } // this.base_file_path = base_file_path; @@ -66,13 +68,35 @@ public abstract class AbstractSMBScenario extends AbstractRemoteFileSystemScenar return createShare(cm); } + public boolean shareExists(ConsoleManager cm, String share_name) { + if (!remote_host.isWindows()) + return false; // XXX samba support + + try { + String output_str = remote_host.execElevated("NET SHARE", Host.ONE_MINUTE).printOutputIfCrash(getClass(), cm).output; + + return output_str.contains(share_name); + } catch ( Exception ex ) { + cm.addGlobalException(EPrintType.CANT_CONTINUE, "shareExists", ex, "can't tell if share exists"); + } + return false; + } + public boolean createShare(ConsoleManager cm) { - for ( int i=1 ; ; ) { - file_path = base_file_path + i; + // make a unique name for the share + for ( int i=1 ; i < 65535 ; i++ ) { + remote_path = base_file_path + i; share_name = base_share_name + i; - if (!remote_host.exists(file_path)) - break; + if (!remote_host.exists(remote_path)) { + // share may still exist, but at a different remote file path (double check to avoid `net share` failure) + if (!shareExists(cm, share_name)) { + break; + } + } } + // + + cm.println(EPrintType.IN_PROGRESS, getName(), "Selected share_name="+share_name+" remote_path="+remote_path+" (base: "+base_file_path+" "+base_share_name+")"); try { if (remote_host.isWindows()) { @@ -82,22 +106,22 @@ public abstract class AbstractSMBScenario extends AbstractRemoteFileSystemScenar return false; } } catch (Exception ex ) { - cm.addGlobalException(EPrintType.OPERATION_FAILED_CONTINUING, getClass(), "createShare", ex, "", remote_host, file_path, share_name); + cm.addGlobalException(EPrintType.OPERATION_FAILED_CONTINUING, getClass(), "createShare", ex, "", remote_host, remote_path, share_name); return false; } unc_path = "\\\\"+remote_host.getHostname()+"\\"+share_name; // for Windows - smb_path = "smb://"+remote_host.getHostname()+"/"+share_name; // for linux + url_path = "smb://"+remote_host.getHostname()+"/"+share_name; // for linux - cm.println(EPrintType.COMPLETED_OPERATION, getName(), "Share created: "+unc_path+" "+smb_path); + cm.println(EPrintType.COMPLETED_OPERATION, getName(), "Share created: unc="+unc_path+" remote_file="+remote_path+" url="+url_path); return true; } // end public boolean createShare protected boolean createShareWindows(ConsoleManager cm) throws Exception { - remote_host.mkdirs(file_path); + remote_host.mkdirs(remote_path); - return remote_host.exec("NET SHARE "+share_name+"="+file_path+" /Grant:"+remote_host.getUsername()+",Full", Host.FOUR_HOURS).printOutputIfCrash(getClass(), cm).isSuccess(); + return remote_host.execElevated("NET SHARE "+share_name+"="+remote_path+" /Grant:"+remote_host.getUsername()+",Full", Host.FOUR_HOURS).printOutputIfCrash(getClass(), cm).isSuccess(); } protected boolean createShareSamba() { @@ -118,7 +142,7 @@ public abstract class AbstractSMBScenario extends AbstractRemoteFileSystemScenar } } else { // host is local, try using a local drive, normal file system operations, not SMB, etc... - local_drive = file_path; + local_path = remote_path; return true; } @@ -126,17 +150,17 @@ public abstract class AbstractSMBScenario extends AbstractRemoteFileSystemScenar protected static final String[] DRIVES = new String[]{"H", "I", "J", "K", "L", "M", "N", "O", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y"}; // 18 protected boolean connectFromWindows(ConsoleManager cm, Host local_host) throws Exception { - local_drive = null; + local_path = null; for ( int i=0 ; i < DRIVES.length ; i++ ) { - if (remote_host.exists(DRIVES[i] + ":\\")) { - local_drive = DRIVES[i] + ":"; + if (!local_host.exists(DRIVES[i] + ":\\")) { + local_path = DRIVES[i] + ":"; break; } } - if (local_drive==null) + if (local_path==null) return false; - return local_host.exec("NET USE "+unc_path+" "+local_drive+" /user:"+remote_host.getUsername()+" /password:"+remote_host.getPassword(), Host.FOUR_HOURS).printOutputIfCrash(getClass(), cm).isSuccess(); + return local_host.execElevated("NET USE "+unc_path+" "+local_path+" /user:"+remote_host.getUsername()+" /password:"+remote_host.getPassword(), Host.ONE_MINUTE).printOutputIfCrash(getClass(), cm).isSuccess(); } protected boolean connectFromSamba() { @@ -146,27 +170,35 @@ public abstract class AbstractSMBScenario extends AbstractRemoteFileSystemScenar @Override public String getTestPackStorageDir(Host host) { - return local_drive; // H: I: J: ... Y: + return local_path; // H: I: J: ... Y: } public boolean deleteShare(ConsoleManager cm, Host host) { try { - if (host.execElevated("NET SHARE "+file_path+" /DELETE", Host.ONE_MINUTE).printOutputIfCrash(getClass(), cm).isSuccess()) { - host.delete(file_path); + if (host.execElevated("NET SHARE "+remote_path+" /DELETE", Host.ONE_MINUTE).printOutputIfCrash(getClass(), cm).isSuccess()) { + try { + host.delete(remote_path); + + cm.println(EPrintType.IN_PROGRESS, getClass(), "Share deleted: remote_file="+remote_path+" unc="+unc_path+" url="+url_path); + } catch ( Exception ex ) { + throw ex; + } return true; } } catch ( Exception ex ) { - cm.addGlobalException(EPrintType.OPERATION_FAILED_CONTINUING, getClass(), "deleteShare", ex, "", host, file_path); + cm.addGlobalException(EPrintType.OPERATION_FAILED_CONTINUING, getClass(), "deleteShare", ex, "", host, remote_path); } return false; } public boolean disconnect(ConsoleManager cm, Host host) { try { - return host.exec("NET USE "+local_drive+" /DELETE", Host.ONE_MINUTE).printOutputIfCrash(getClass(), cm).isSuccess(); + if (host.exec("NET USE "+local_path+" /DELETE", Host.ONE_MINUTE).printOutputIfCrash(getClass(), cm).isSuccess()) { + cm.println(EPrintType.IN_PROGRESS, getClass(), "Disconnected share: local="+local_path); + } } catch ( Exception ex ) { - cm.addGlobalException(EPrintType.OPERATION_FAILED_CONTINUING, getClass(), "disconnect", ex, "", host, local_drive); + cm.addGlobalException(EPrintType.OPERATION_FAILED_CONTINUING, getClass(), "disconnect", ex, "", host, local_path); } return false; } @@ -175,7 +207,7 @@ public abstract class AbstractSMBScenario extends AbstractRemoteFileSystemScenar public void notifyFinishedTestPack(ConsoleManager cm, Host host) { if (deleteShare(cm, host) && disconnect(cm, host)) { // reset - share_name = file_path = unc_path = smb_path = local_drive = null; + share_name = remote_path = unc_path = url_path = local_path = null; } } diff --git a/src/com/mostc/pftt/scenario/AbstractWebServerScenario.java b/src/com/mostc/pftt/scenario/AbstractWebServerScenario.java index 05e5602..dd53c91 100644 --- a/src/com/mostc/pftt/scenario/AbstractWebServerScenario.java +++ b/src/com/mostc/pftt/scenario/AbstractWebServerScenario.java @@ -28,6 +28,7 @@ import com.mostc.pftt.model.sapi.SharedSAPIInstanceTestCaseGroupKey; import com.mostc.pftt.model.sapi.TestCaseGroupKey; import com.mostc.pftt.model.sapi.WebServerInstance; import com.mostc.pftt.model.sapi.WebServerManager; +import com.mostc.pftt.model.smoke.RequiredExtensionsSmokeTest; import com.mostc.pftt.results.ConsoleManager; import com.mostc.pftt.results.IPhptTestResultReceiver; import com.mostc.pftt.runner.AbstractPhptTestCaseRunner; @@ -110,8 +111,16 @@ public abstract class AbstractWebServerScenario extends AbstractSAPIScenario { return new HttpTestCaseRunner(group_key.getPhpIni(), group_key.getEnv(), params, httpproc, httpexecutor, smgr, (WebServerInstance) ((SharedSAPIInstanceTestCaseGroupKey)group_key).getSAPIInstance(), thread, test_case, cm, twriter, host, scenario_set, build, src_test_pack, active_test_pack); } + @Override + public PhpIni createIniForTest(ConsoleManager cm, Host host, PhpBuild build, PhptActiveTestPack active_test_pack, ScenarioSet scenario_set) { + // entire PhpIni will be given to web server when its started + return RequiredExtensionsSmokeTest.createDefaultIniCopy(host, build); + } + + @Override public TestCaseGroupKey createTestGroupKey(ConsoleManager cm, Host host, PhpBuild build, ScenarioSet scenario_set, PhptActiveTestPack active_test_pack, PhptTestCase test_case, TestCaseGroupKey group_key) throws Exception { Map<String,String> env = null; + // ENV vars will be passed to web server manager to wrap the web server in when its executed if (test_case.containsSection(EPhptSection.ENV)) { env = AbstractPhptTestCaseRunner.generateENVForTestCase(cm, host, build, scenario_set, test_case); @@ -119,7 +128,7 @@ public abstract class AbstractWebServerScenario extends AbstractSAPIScenario { } if (test_case.containsSection(EPhptSection.INI)) { - PhpIni ini = AbstractPhptTestCaseRunner.createIniForTest(cm, host, build, active_test_pack, scenario_set); + PhpIni ini = createIniForTest(cm, host, build, active_test_pack, scenario_set); ini.replaceAll(test_case.getINI(active_test_pack, host)); // note: don't bother comparing test case's INI with existing group_key's INI, PhptTestPackRunner @@ -128,7 +137,7 @@ public abstract class AbstractWebServerScenario extends AbstractSAPIScenario { } else if (env==null && group_key!=null && group_key.getPhpIni().isDefault()) { return group_key; } else { - return new SharedSAPIInstanceTestCaseGroupKey(AbstractPhptTestCaseRunner.createIniForTest(cm, host, build, active_test_pack, scenario_set), env); + return new SharedSAPIInstanceTestCaseGroupKey(createIniForTest(cm, host, build, active_test_pack, scenario_set), env); } } // end public TestCaseGroupKey createTestGroupKey diff --git a/src/com/mostc/pftt/scenario/CLIScenario.java b/src/com/mostc/pftt/scenario/CLIScenario.java index d1cd5b8..fce286d 100644 --- a/src/com/mostc/pftt/scenario/CLIScenario.java +++ b/src/com/mostc/pftt/scenario/CLIScenario.java @@ -50,11 +50,19 @@ public class CliScenario extends AbstractSAPIScenario { public ESAPIType getSAPIType() { return ESAPIType.CLI; } + + @Override + public PhpIni createIniForTest(ConsoleManager cm, Host host, PhpBuild build, PhptActiveTestPack active_test_pack, ScenarioSet scenario_set) { + // default PhpIni will be given to php.exe using a file... @see CliPhptTestCaseRunner#prepare + // + // this is needed only to collect any custom directives that a test case provides + return new PhpIni(); + } @Override public TestCaseGroupKey createTestGroupKey(ConsoleManager cm, Host host, PhpBuild build, ScenarioSet scenario_set, PhptActiveTestPack active_test_pack, PhptTestCase test_case, TestCaseGroupKey group_key) { if (test_case.containsSection(EPhptSection.INI)) { - PhpIni ini = AbstractPhptTestCaseRunner.createIniForTest(cm, host, build, active_test_pack, scenario_set); + PhpIni ini = createIniForTest(cm, host, build, active_test_pack, scenario_set); ini.replaceAll(test_case.getINI(active_test_pack, host)); // note: don't bother comparing test case's INI with existing group_key's INI, PhptTestPackRunner @@ -68,7 +76,7 @@ public class CliScenario extends AbstractSAPIScenario { } else if (group_key!=null && group_key.getPhpIni().isDefault()) { return group_key; } else { - return new TestCaseGroupKey(AbstractPhptTestCaseRunner.createIniForTest(cm, host, build, active_test_pack, scenario_set), null); + return new TestCaseGroupKey(createIniForTest(cm, host, build, active_test_pack, scenario_set), null); } } // end public TestCaseGroupKey createTestGroupKey diff --git a/src/com/mostc/pftt/scenario/NoCodeCacheScenario.java b/src/com/mostc/pftt/scenario/NoCodeCacheScenario.java index c32d645..c319874 100644 --- a/src/com/mostc/pftt/scenario/NoCodeCacheScenario.java +++ b/src/com/mostc/pftt/scenario/NoCodeCacheScenario.java @@ -15,6 +15,11 @@ import com.mostc.pftt.results.ConsoleManager; public class NoCodeCacheScenario extends AbstractCodeCacheScenario { @Override + public boolean isPlaceholder() { + return true; + } + + @Override public String getName() { return "No-Code-Cache"; } diff --git a/src/com/mostc/pftt/scenario/NoDebugScenario.java b/src/com/mostc/pftt/scenario/NoDebugScenario.java index dd5a037..1ace267 100644 --- a/src/com/mostc/pftt/scenario/NoDebugScenario.java +++ b/src/com/mostc/pftt/scenario/NoDebugScenario.java @@ -14,6 +14,11 @@ import com.mostc.pftt.results.ConsoleManager; public class NoDebugScenario extends AbstractDebugScenario { @Override + public boolean isPlaceholder() { + return true; + } + + @Override public boolean setup(ConsoleManager cm, Host host, PhpBuild build, PhpIni ini) { return false; } diff --git a/src/com/mostc/pftt/scenario/PlainSocketScenario.java b/src/com/mostc/pftt/scenario/PlainSocketScenario.java index 570400e..6274f63 100644 --- a/src/com/mostc/pftt/scenario/PlainSocketScenario.java +++ b/src/com/mostc/pftt/scenario/PlainSocketScenario.java @@ -14,6 +14,11 @@ import com.mostc.pftt.results.ConsoleManager; public class PlainSocketScenario extends AbstractSocketScenario { @Override + public boolean isPlaceholder() { + return true; + } + + @Override public String getName() { return "Plain-Socket"; } diff --git a/src/com/mostc/pftt/scenario/SMBBasicScenario.java b/src/com/mostc/pftt/scenario/SMBBasicScenario.java index 02028d9..cdfafac 100644 --- a/src/com/mostc/pftt/scenario/SMBBasicScenario.java +++ b/src/com/mostc/pftt/scenario/SMBBasicScenario.java @@ -2,7 +2,7 @@ package com.mostc.pftt.scenario; import com.mostc.pftt.host.RemoteHost; -/** Tests running a PHP build and its test pack both stored remotely on a basic SMB file share. (NOT IMPLEMENTED) +/** Tests running a PHP build and its test pack both stored remotely on a basic SMB file share. * * @author Matt Ficken * diff --git a/src/com/mostc/pftt/scenario/SMBCAScenario.java b/src/com/mostc/pftt/scenario/SMBCAScenario.java index 157f36c..22bf878 100644 --- a/src/com/mostc/pftt/scenario/SMBCAScenario.java +++ b/src/com/mostc/pftt/scenario/SMBCAScenario.java @@ -2,6 +2,7 @@ package com.mostc.pftt.scenario; import com.mostc.pftt.host.Host; import com.mostc.pftt.host.RemoteHost; +import com.mostc.pftt.host.TempFileExecOutput; import com.mostc.pftt.results.ConsoleManager; /** Tests PHP using SMB Continuous Availability (CA) (NOT IMPLEMENTED) @@ -24,7 +25,9 @@ public class SMBCAScenario extends AbstractSMBScenario { @Override protected boolean createShareWindows(ConsoleManager cm) throws Exception { - return remote_host.exec("Powershell -Command{New-SmbShare -Name "+share_name+" -Path "+file_path+" -Scope "+remote_host.getHostname()+" -FullControl "+remote_host.getHostname()+"\\"+remote_host.getUsername()+"}", Host.FOUR_HOURS).printOutputIfCrash(getClass(), cm).isSuccess(); + TempFileExecOutput teo = remote_host.powershell(getClass(), cm, "New-SmbShare -Name "+share_name+" -Path "+remote_path+" -Scope "+remote_host.getHostname()+" -FullControl "+remote_host.getHostname()+"\\"+remote_host.getUsername(), Host.ONE_MINUTE); + teo.printOutputIfCrash(getClass(), cm); + return teo.cleanupIfSuccess(remote_host); } @Override @@ -34,7 +37,7 @@ public class SMBCAScenario extends AbstractSMBScenario { @Override public boolean isImplemented() { - return true; + return false; } } // end public class SMBCAScenario diff --git a/src/com/mostc/pftt/scenario/SMBDFSRScenario.java b/src/com/mostc/pftt/scenario/SMBDFSRScenario.java index 082c871..e0b8c5c 100644 --- a/src/com/mostc/pftt/scenario/SMBDFSRScenario.java +++ b/src/com/mostc/pftt/scenario/SMBDFSRScenario.java @@ -2,11 +2,12 @@ package com.mostc.pftt.scenario; import com.mostc.pftt.host.Host; import com.mostc.pftt.host.RemoteHost; +import com.mostc.pftt.host.TempFileExecOutput; import com.mostc.pftt.model.phpt.PhpBuild; import com.mostc.pftt.results.ConsoleManager; import com.mostc.pftt.results.ConsoleManager.EPrintType; -/** Tests PHP with PHP build and test pack being stored remotely on a group of DFS-R SMB Shares. (NOT IMPLEMENTED) +/** Tests PHP with PHP build and test pack being stored remotely on a group of DFS-R SMB Shares. * * Web hosters can setup a share that is physically copied and served by multiple SMB Servers. * @@ -17,13 +18,21 @@ import com.mostc.pftt.results.ConsoleManager.EPrintType; * There are two types of DFS, DFS-N and DFS-R, this tests DFS-R. DFS-N is not relevant because it only replicates a namespace(folder structure) * across servers. DFS-R synchronizes folder contents efficiently between file servers across LANs and even WANs. * - * @see `dfsutil`, `dfscmd` and `dfsdiag` + * @see `dfsutil`, `dfscmd` and `dfsdiag` and `fsutil reparsepoint query <file>` + * @see http://msdn.microsoft.com/en-us/library/windows/desktop/aa365511%28v=vs.85%29.aspx * @author Matt Ficken * */ public class SMBDFSRScenario extends AbstractSMBScenario { + // TODO PFTT-NS-1 PFTT-DFS-1 PFTT-TARGET-1 + // TODO use only ip addresses + // -still have problems with netbios name resolution + public SMBDFSRScenario(RemoteHost remote_host) { + this(remote_host, null, null); + } + public SMBDFSRScenario(RemoteHost remote_host, String base_file_path, String base_share_name) { super(remote_host, base_file_path, base_share_name); } @@ -34,31 +43,29 @@ public class SMBDFSRScenario extends AbstractSMBScenario { } @Override - public boolean setup(ConsoleManager cm, Host host, PhpBuild build, ScenarioSet scenario_set) { + public boolean setup(ConsoleManager cm, Host local_host, PhpBuild build, ScenarioSet scenario_set) { StringBuilder ps_sb = new StringBuilder(); ps_sb.append("Import-Module ServerManager\n"); ps_sb.append("Add-WindowsFeature -name File-Services\n"); ps_sb.append("Add-WindowsFeature -name FS-DFS\n"); ps_sb.append("Add-WindowsFeature -name FS-DFS-Replication\n"); - String tmp_file = host.mktempname(getName(), "ps1"); - try { - host.saveTextFile(tmp_file, ps_sb.toString()); - - if (host.exec("Powershell -File "+tmp_file, Host.FOUR_HOURS).printOutputIfCrash(getClass(), cm).isSuccess()) { - host.delete(tmp_file); + TempFileExecOutput teo = remote_host.powershell(getClass(), cm, ps_sb, Host.FOUR_HOURS); + + if (teo.printOutputIfCrash(getClass(), cm).isSuccess()) { + teo.cleanup(remote_host); - if (super.setup(cm, host, build, scenario_set)) { - cm.println(EPrintType.COMPLETED_OPERATION, getName(), "DFSR setup successfully on "+unc_path+" "+smb_path); + if (super.setup(cm, remote_host, build, scenario_set)) { + cm.println(EPrintType.COMPLETED_OPERATION, getName(), "DFSR setup successfully: unc="+unc_path+" remote_file="+remote_path); return true; } } else { - cm.println(EPrintType.OPERATION_FAILED_CONTINUING, getName(), "can't exec powershell script: "+tmp_file); + cm.println(EPrintType.OPERATION_FAILED_CONTINUING, getName(), "can't exec powershell script: "+ps_sb); } } catch ( Exception ex ) { - cm.addGlobalException(EPrintType.OPERATION_FAILED_CONTINUING, getClass(), "setup", ex, "", host, tmp_file, unc_path); + cm.addGlobalException(EPrintType.OPERATION_FAILED_CONTINUING, getClass(), "setup", ex, "", remote_host, ps_sb, unc_path); } return false; } diff --git a/src/com/mostc/pftt/scenario/SMBDeduplicationScenario.java b/src/com/mostc/pftt/scenario/SMBDeduplicationScenario.java index ba8ee99..43b54a3 100644 --- a/src/com/mostc/pftt/scenario/SMBDeduplicationScenario.java +++ b/src/com/mostc/pftt/scenario/SMBDeduplicationScenario.java @@ -2,11 +2,12 @@ package com.mostc.pftt.scenario; import com.mostc.pftt.host.Host; import com.mostc.pftt.host.RemoteHost; +import com.mostc.pftt.host.TempFileExecOutput; import com.mostc.pftt.model.phpt.PhpBuild; import com.mostc.pftt.results.ConsoleManager; import com.mostc.pftt.results.ConsoleManager.EPrintType; -/** Tests the new Remote Data Deduplication feature of Windows 2012 using SMB. (NOT IMPLEMENTED) +/** Tests the new Remote Data Deduplication feature of Windows 2012 using SMB. * * This feature broke PHP in php bug #63241. This scenario will catch that or any other problems Deduplication causes to PHP. * @@ -60,14 +61,18 @@ public class SMBDeduplicationScenario extends AbstractSMBScenario { @Override public boolean notifyPrepareStorageDir(ConsoleManager cm, Host local_host) { // check that its win8 - if (!remote_host.isWin8OrLater()) { + System.out.println("64"); + // TODO + if (false) { // TODO !remote_host.isWin8OrLater()) { + System.out.println("66"); cm.println(EPrintType.XSKIP_OPERATION, getName(), "Scenario can only be run against a Windows 8/2012+ host"); return false; } else if (volume.equals("C:")||remote_host.getSystemDrive().equalsIgnoreCase(volume)) { + System.out.println("70"); cm.println(EPrintType.XSKIP_OPERATION, getName(), "Can not use Deduplication on a Windows System Drive (ex: C:\\)"); return false; } - + System.out.println("74"); StringBuilder ps_sb = new StringBuilder(128); // install deduplication feature ps_sb.append("Import-Module ServerManager\n"); @@ -79,25 +84,24 @@ public class SMBDeduplicationScenario extends AbstractSMBScenario { // change min file age (default is 5 days which will prevent testing test-packs now) ps_sb.append("Set-DedupVolume ");ps_sb.append(volume);ps_sb.append(" -MinimumFileAgeDays 0\n"); - String tmp_file = remote_host.mktempname(getName(), "ps1"); - // create PowerShell script to install and enable deduplication try { - remote_host.saveTextFile(tmp_file, ps_sb.toString()); - // - if (remote_host.execElevated("powershell -File "+tmp_file, Host.ONE_MINUTE * 10).printOutputIfCrash(getClass(), cm).isSuccess()) { + System.out.println("89"); + cm.println(EPrintType.IN_PROGRESS, getName(), "Starting to enable Deduplication on: "+remote_host); + TempFileExecOutput teo = remote_host.powershell(getClass(), cm, ps_sb, Host.ONE_MINUTE * 10); + if (teo.printOutputIfCrash(getClass(), cm).isSuccess()) { // don't delete tmp_file if it failed to help user see why - remote_host.delete(tmp_file); + teo.cleanup(remote_host); } // create share on volume if (super.notifyPrepareStorageDir(cm, local_host)) { - cm.println(EPrintType.COMPLETED_OPERATION, getName(), "Deduplication enabled on share: "+unc_path+" "+smb_path); + cm.println(EPrintType.COMPLETED_OPERATION, getName(), "Deduplication enabled on share: unc="+unc_path+" local="+local_path+" url="+url_path); return true; } } catch ( Exception ex ) { - cm.addGlobalException(EPrintType.CANT_CONTINUE, getClass(), "notifyPrepareStorageDir", ex, "Unable to enable deduplication", remote_host, tmp_file); + cm.addGlobalException(EPrintType.CANT_CONTINUE, getClass(), "notifyPrepareStorageDir", ex, "Unable to enable deduplication", remote_host, ps_sb); } return false; } // end public boolean notifyPrepareStorageDir @@ -111,9 +115,9 @@ public class SMBDeduplicationScenario extends AbstractSMBScenario { public boolean notifyTestPackInstalled(ConsoleManager cm, Host local_host) { try { // run deduplication job (on test-pack) -wait for completion - cm.println(EPrintType.IN_PROGRESS, getName(), "Running deduplication job..."); - if (remote_host.exec("powershell -Command {Start-Dedupjob -Volume "+volume+" -Type Optimization -Wait}", Host.FOUR_HOURS).printOutputIfCrash(getClass(), cm).isSuccess()) { - cm.println(EPrintType.COMPLETED_OPERATION, getName(), "Deduplication completed successfully."); + cm.println(EPrintType.IN_PROGRESS, getName(), "Running deduplication job... unc="+unc_path+" local="+local_path+" remote_file="+remote_path+" url="+url_path); + if (remote_host.powershell(getClass(), cm, "Start-Dedupjob -Volume "+volume+" -Type Optimization", Host.FOUR_HOURS).printOutputIfCrash(getClass(), cm).isSuccess()) { + cm.println(EPrintType.COMPLETED_OPERATION, getName(), "Deduplication completed successfully. unc="+unc_path+" local="+local_path+" remote_file="+remote_path+" url="+url_path); return true; } else { cm.println(EPrintType.OPERATION_FAILED_CONTINUING, getName(), "Deduplication failed"); @@ -122,12 +126,12 @@ public class SMBDeduplicationScenario extends AbstractSMBScenario { cm.addGlobalException(EPrintType.CANT_CONTINUE, getClass(), "notifyTestPackInstalled", ex, "Deduplication failed", remote_host, local_host, volume); } return false; - } + } // end public boolean notifyTestPackInstalled @Override public String getName() { return "SMB-Deduplication"; - } + } @Override public boolean isImplemented() { diff --git a/src/com/mostc/pftt/scenario/Scenario.java b/src/com/mostc/pftt/scenario/Scenario.java index 562815e..2d6b558 100644 --- a/src/com/mostc/pftt/scenario/Scenario.java +++ b/src/com/mostc/pftt/scenario/Scenario.java @@ -57,6 +57,14 @@ public abstract class Scenario { public void getENV(Map<String, String> env) { } + + public boolean isPlaceholder() { + return false; + } + + public boolean ignoreForShortName() { + return false; + } public boolean hasENV() { return false; diff --git a/src/com/mostc/pftt/scenario/ScenarioSet.java b/src/com/mostc/pftt/scenario/ScenarioSet.java index 156e95e..4060f84 100644 --- a/src/com/mostc/pftt/scenario/ScenarioSet.java +++ b/src/com/mostc/pftt/scenario/ScenarioSet.java @@ -66,15 +66,14 @@ public class ScenarioSet extends ArrayList<Scenario> { StringBuilder sb = new StringBuilder(40); String str; for ( Scenario s : this ) { - if (sb.length()>0) + if (s.isPlaceholder()) + continue; + else if (sb.length()>0) sb.append('_'); str = s.toString(); - if (str.startsWith("No-")) - // ignore these scenarios, they're placeholders - continue; sb.append(str); } - str = sb.toString(); + this.str = sb.toString(); } protected void forceSort() { @@ -91,10 +90,26 @@ public class ScenarioSet extends ArrayList<Scenario> { @Override public String toString() { + return getName(); + } + + public String getName() { ensureSorted(); return str; // @see #sort } + public String getShortName() { + StringBuilder sb = new StringBuilder(); + for ( Scenario s : this ) { + if (s.ignoreForShortName()) + continue; + else if (sb.length()>0) + sb.append('_'); + sb.append(s.getName()); + } + return sb.toString(); + } + @Override public boolean add(Scenario s) { super.add(s); diff --git a/src/com/mostc/pftt/ui/PhptHostTab.java b/src/com/mostc/pftt/ui/PhptHostTab.java index a31b73f..73d7db2 100644 --- a/src/com/mostc/pftt/ui/PhptHostTab.java +++ b/src/com/mostc/pftt/ui/PhptHostTab.java @@ -86,12 +86,12 @@ public class PhptHostTab extends JSplitPane { stop_button.setEnabled(false); } }); - panel.add("left", new JLabel("Pass")); - panel.add("left", pass_label = new JLabel("0")); - panel.add("left", pass_bar = new JProgressBar(0, 12000)); // #showResult updates pass_bar maximum - pass_bar.setStringPainted(true); panel.add("left", new JLabel("Total")); panel.add("left", total_label = new JLabel("0")); + panel.add("left", pass_bar = new JProgressBar(0, 12000)); // #showResult updates pass_bar maximum + pass_bar.setStringPainted(true); + panel.add("left", new JLabel("Pass")); + panel.add("left", pass_label = new JLabel("0")); panel.add("left", new JLabel("Fail")); panel.add("left", fail_label = new JLabel("0")); panel.add(new JLabel("CRASH")); @@ -305,9 +305,9 @@ public class PhptHostTab extends JSplitPane { fail++; fail_label.setText(Integer.toString(fail)); - pass_bar.setString(Float.toString(PhptResultPack.round1( (float)( ((float)pass) / ((float)( pass + fail + crash )) )))+"%"); // 1 decimal places nn.y + pass_bar.setString(Float.toString(PhptResultPack.round1( (float)( ( 100.0f * pass) / ((float)( pass + fail +crash )) )))+"%"); // 1 decimal place nn.y pass_bar.setMaximum(fail+pass); - total_label.setText(""+(fail+pass)); + total_label.setText(""+(fail+pass+crash)); // show in list fail_list_model.addElement(result); @@ -350,7 +350,7 @@ public class PhptHostTab extends JSplitPane { break; case PASS: pass++; - pass_bar.setString(Float.toString(PhptResultPack.round1( (float)( (double)pass / ((double)( pass + fail )) )))+"%"); // 1 decimal places nn.y + pass_bar.setString(Float.toString(PhptResultPack.round1( (float)( ( 100.0f * pass) / ((float)( pass + fail + crash )) )))+"%"); // 1 decimal place nn.y pass_bar.setValue(pass); diff --git a/src/com/mostc/pftt/util/StringUtil.java b/src/com/mostc/pftt/util/StringUtil.java index 92aa87c..6c83783 100644 --- a/src/com/mostc/pftt/util/StringUtil.java +++ b/src/com/mostc/pftt/util/StringUtil.java @@ -19,6 +19,15 @@ import com.mostc.pftt.util.apache.regexp.REProgram; public final class StringUtil { public static final String EMPTY = ""; + public static String chomp(String in) { + if (in.endsWith("\r\n")) + return in.substring(0, in.length()-2); + else if (in.endsWith("\n")) + return in.substring(0, in.length()-1); + else + return in; + } + public static String unquote(String in) { if (isEmpty(in)) return in; @@ -277,7 +286,7 @@ public final class StringUtil { StringBuilder sb = new StringBuilder(256); sb.append(parts[off]); off++; - for ( int i=0 ; i < len ; i++, off++ ) { + for ( int i=0 ; i < len && off < parts.length ; i++, off++ ) { sb.append(delim); sb.append(parts[off]); } @@ -402,6 +411,19 @@ public final class StringUtil { } // end public static class LengthLimitStringWriter + public static boolean isWhitespaceOrEmpty(String a) { + if (a==null) + return true; + final int a_len = a.length(); + if (a_len==0) + return true; + for ( int i=0 ; i < a_len ; i++ ) { + if (!Character.isLetter(a.charAt(i))) + return false; + } + return true; + } + private StringUtil() {} } // end public class StringUtil diff --git a/src/org/apache/sshd/server/filesystem/NativeSshFile.java b/src/org/apache/sshd/server/filesystem/NativeSshFile.java index cac0bc0..cb893aa 100644 --- a/src/org/apache/sshd/server/filesystem/NativeSshFile.java +++ b/src/org/apache/sshd/server/filesystem/NativeSshFile.java @@ -71,7 +71,7 @@ public class NativeSshFile implements SshFile { if (fileName.length() == 0) { throw new IllegalArgumentException("fileName can not be empty"); - } else if (fileName.charAt(0) != '/') { + } else if (fileName.charAt(0) != '/' && (fileName.length()<2||!Character.isLetter(fileName.charAt(0))||fileName.charAt(1)!=':')) { throw new IllegalArgumentException("fileName must be an absolute path"); } @@ -552,7 +552,11 @@ public class NativeSshFile implements SshFile { .length())) { resArg = normalizedRootDir; } - + System.out.println("555 "+resArg); + int i = resArg.lastIndexOf(':'); + if (i>0) + resArg = resArg.substring(i-1); + System.out.println("559 "+resArg); return resArg; }