Commit: 5a47517085698cd53e7b7a3c67a9a172803345ba Author: Matt Ficken <v-maf...@microsoft.com> Mon, 12 Nov 2012 15:42:31 -0800 Parents: d784ea41a3e0a0dad768054bf90ed81de5b92d5e Branches: master
Link: http://git.php.net/?p=pftt2.git;a=commitdiff;h=5a47517085698cd53e7b7a3c67a9a172803345ba Log: Multi-Scenario configuration, permutation and testing support Former-commit-id: 76c03a4888ac9e3218af681afafc5adea82078dc Changed paths: M README.mdown A conf/all_databases.groovy A conf/all_smb.groovy A conf/other_network_services.groovy M doc/index.html M src/com/mostc/pftt/host/Host.java M src/com/mostc/pftt/host/LocalHost.java M src/com/mostc/pftt/host/SSHHost.java A src/com/mostc/pftt/main/Config.java D src/com/mostc/pftt/main/ConfigUtil.java M src/com/mostc/pftt/main/PfttMain.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/PhptSourceTestPack.java M src/com/mostc/pftt/model/phpt/PhptTestCase.java M src/com/mostc/pftt/report/AbstractReportGen.groovy 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/runner/PhptTestPackRunner.java M src/com/mostc/pftt/scenario/AbstractCodeCacheScenario.java M src/com/mostc/pftt/scenario/AbstractFileSystemScenario.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/AbstractSerialScenario.java M src/com/mostc/pftt/scenario/AbstractSocketScenario.java M src/com/mostc/pftt/scenario/CLIScenario.java M src/com/mostc/pftt/scenario/LocalFileSystemScenario.java M src/com/mostc/pftt/scenario/SMBCSCOptionScenario.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/telemetry/ConsoleManager.java M src/com/mostc/pftt/telemetry/PhptTestResult.java M src/com/mostc/pftt/ui/ExpectedActualDiffPHPTDisplay.java M src/com/mostc/pftt/ui/PhptDebuggerFrame.java M src/com/mostc/pftt/util/HostEnvUtil.java
diff --git a/README.mdown b/README.mdown index b4ed406..43734eb 100644 --- a/README.mdown +++ b/README.mdown @@ -144,11 +144,11 @@ PFTT will automatically generate an FBC report and display it using system defau ## Adding Scenarios -To add any test [Scenario](doc/apidoc/com/mostc/pftt/scenario/Scenario.html), implement [Scenario](doc/apidoc/com/mostc/pftt/scenario/Scenario.html) and instantiate it in Scenario#getAllScenarios. +To add any test [Scenario](doc/apidoc/com/mostc/pftt/scenario/Scenario.html), implement [Scenario](doc/apidoc/com/mostc/pftt/scenario/Scenario.html) and instantiate it in Scenario#getAllDefaultScenarios or a config file if it needs special configuration (like connecting to a remote host, database, etc... that the user would have to setup). ### Database Scenario -More specifically, to add a database scenario (MySQL, Firebird, etc...) implement [AbstractDatabaseScenario](doc/apidoc/com/mostc/pftt/scenario/AbstractDatabaseScenario.html) and add it to Scenario#getAllScenarios. +More specifically, to add a database scenario (MySQL, Firebird, etc...) implement [AbstractDatabaseScenario](doc/apidoc/com/mostc/pftt/scenario/AbstractDatabaseScenario.html) and add it to Scenario#getAllDefaultScenarios or a config file if it needs special configuration (like connecting to a remote host, database, etc... that the user would have to setup). ### SAPI Scenario diff --git a/conf/all_databases.groovy b/conf/all_databases.groovy new file mode 100644 index 0000000..f8c1ccc --- /dev/null +++ b/conf/all_databases.groovy @@ -0,0 +1,11 @@ + +def scenarios() { +[ + new MSAccessScenario(), + new MSSQLODBCScenario(), + new MSSQLScenario(), + new MySQLScenario(), + new PostgresSQLScenario(), + new SQLite3Scenario() +] +} diff --git a/conf/all_smb.groovy b/conf/all_smb.groovy new file mode 100644 index 0000000..cf6f3e4 --- /dev/null +++ b/conf/all_smb.groovy @@ -0,0 +1,12 @@ + +def scenarios() { + SSHHost win8_server = new SSHHost("192.168.1.1", "administrator", "password01!"); +[ + new SMBBasicScenario(win8_server), + new SMBDeduplicationScenario(win8_server, "E:"), + /* XXX new SMBDFSScenario(), + new SMBCAScenario(),*/ + // probably don't need to test branch cache, but including it for completeness + //new SMBBranchCacheScenario() +] +} diff --git a/conf/other_network_services.groovy b/conf/other_network_services.groovy new file mode 100644 index 0000000..ea8d1f5 --- /dev/null +++ b/conf/other_network_services.groovy @@ -0,0 +1,11 @@ + +def scenarios() { +[ + // streams + new FTPScenario(), + new HTTPScenario(), + // web services + new SOAPScenario(), + new XMLRPCScenario() +] +} diff --git a/doc/index.html b/doc/index.html index 949fbfc..f704f21 100644 --- a/doc/index.html +++ b/doc/index.html @@ -180,11 +180,11 @@ That should be it (PFTT comes with eclipse .project and .classpath files which a <h2>Adding Scenarios</h2> -<p>To add any test Scenario, implement <a href="apidoc/com/mostc/pftt/scenario/Scenario.html">Scenario</a> and instantiate it in Scenario#getAllScenarios.</p> +<p>To add any test Scenario, implement <a href="apidoc/com/mostc/pftt/scenario/Scenario.html">Scenario</a> and instantiate it in Scenario#getAllDefaultScenarios or a config file if it needs special configuration (like connecting to a remote host, database, etc... that the user would have to setup).</p> <h3>Database Scenario</h3> -<p>More specifically, to add a database scenario (MySQL, Firebird, etc...) implement <a href="apidoc/com/mostc/pftt/scenario/AbstractDatabaseScenario.html">AbstractDatabaseScenario</a> and add it to Scenario#getAllScenarios.</p> +<p>More specifically, to add a database scenario (MySQL, Firebird, etc...) implement <a href="apidoc/com/mostc/pftt/scenario/AbstractDatabaseScenario.html">AbstractDatabaseScenario</a> and add it to Scenario#getAllDefaultScenarios or a config file if it needs special configuration (like connecting to a remote host, database, etc... that the user would have to setup).</p> <h3>SAPI Scenario</h3> diff --git a/src/com/mostc/pftt/host/Host.java b/src/com/mostc/pftt/host/Host.java index d5c0790..3860be8 100644 --- a/src/com/mostc/pftt/host/Host.java +++ b/src/com/mostc/pftt/host/Host.java @@ -19,7 +19,7 @@ import com.mostc.pftt.util.StringUtil; /** Abstracts host management so client code doesn't need to care if host is local or remote(ssh). * * @see #exec - * @see #cmd + * @see #test_cmd * @see Host#DEV * @see #isRemote * @see #readFile @@ -87,7 +87,7 @@ public abstract class Host { if (path.length() >= 2) { if (path.charAt(1)==':') { if (Character.isLetter(path.charAt(0))) - return path.substring(0, 1); + return path.substring(0, 1).toUpperCase(); } } return null; @@ -170,8 +170,8 @@ public abstract class Host { * @throws IllegalStateException * @throws IOException */ - public abstract void saveFile(String filename, String text) throws IllegalStateException, IOException; - public abstract void saveFile(String filename, String text, Charset charset) throws IllegalStateException, IOException; + public abstract void saveTextFile(String filename, String text) throws IllegalStateException, IOException; + public abstract void saveTextFile(String filename, String text, Charset charset) throws IllegalStateException, IOException; public abstract void delete(String path) throws IllegalStateException, IOException; public void deleteIfExists(String path) { try { @@ -752,5 +752,26 @@ public abstract class Host { } return 0L; } // end public long getTotalPhysicalMemoryK + + /** on Windows, returns the directory where windows is stored, typically C:\Windows. + * + * on other OSes, it returns / + * + * @return + */ + public String getSystemRoot() { + if (!isWindows()) + return "/"; + String sr = getEnvValue("SYSTEMROOT"); + if (StringUtil.isNotEmpty(sr)) + return sr; + else + // fallback + return getSystemDrive()+"\\Windows"; + } + + public abstract boolean dirContainsExact(String path, String name); + public abstract boolean dirContainsFragment(String path, String name_fragment); + public abstract String[] list(String path); } // end public abstract class Host diff --git a/src/com/mostc/pftt/host/LocalHost.java b/src/com/mostc/pftt/host/LocalHost.java index 029ce73..8b87fba 100644 --- a/src/com/mostc/pftt/host/LocalHost.java +++ b/src/com/mostc/pftt/host/LocalHost.java @@ -126,12 +126,12 @@ public class LocalHost extends Host { } @Override - public void saveFile(String filename, String text) throws IOException { - saveFile(filename, text, null); + public void saveTextFile(String filename, String text) throws IOException { + saveTextFile(filename, text, null); } @Override - public void saveFile(String filename, String text, Charset charset) throws IOException { + public void saveTextFile(String filename, String text, Charset charset) throws IOException { if (text==null) text = ""; FileOutputStream fos = new FileOutputStream(filename); @@ -602,5 +602,37 @@ public class LocalHost extends Host { protected String getOSNameOnWindows() { return getOSNameLong(); } + + @Override + public boolean dirContainsExact(String path, String name) { + for ( File file : new File(path).listFiles() ) { + if (file.getName().equalsIgnoreCase(name)) + return true; + } + return false; + } + + @Override + public boolean dirContainsFragment(String path, String name_fragment) { + name_fragment = name_fragment.toLowerCase(); + for ( File file : new File(path).listFiles() ) { + if (file.getName().toLowerCase().contains(name_fragment)) + return true; + } + return false; + } + + @Override + public String[] list(String path) { + return new File(path).list(); + } + + public static String getLocalPfttDir() { + if (DEV > 0) { + return isLocalhostWindows() ? "C:\\php-sdk\\PFTT\\Dev-"+DEV+"\\" : System.getenv("HOME")+"/php-sdk/PFTT/dev-"+DEV+"/"; + } else { + return isLocalhostWindows() ? "C:\\php-sdk\\PFTT\\Current\\" : System.getenv("HOME")+"/php-sdk/PFTT/current/"; + } + } } // end public class Host diff --git a/src/com/mostc/pftt/host/SSHHost.java b/src/com/mostc/pftt/host/SSHHost.java index 14bd262..949ee31 100644 --- a/src/com/mostc/pftt/host/SSHHost.java +++ b/src/com/mostc/pftt/host/SSHHost.java @@ -14,6 +14,7 @@ import java.net.InetAddress; import java.net.UnknownHostException; import java.nio.charset.Charset; import java.util.LinkedList; +import java.util.List; import java.util.Map; import java.util.Timer; import java.util.TimerTask; @@ -240,7 +241,7 @@ public class SSHHost extends RemoteHost { } @Override - public void saveFile(String filename, String text, Charset charset) throws IOException { + public void saveTextFile(String filename, String text, Charset charset) throws IOException { if (text==null) text = ""; ensureScpOpen(); @@ -249,8 +250,8 @@ public class SSHHost extends RemoteHost { } @Override - public void saveFile(String filename, String text) throws IOException { - saveFile(filename, text, null); + public void saveTextFile(String filename, String text) throws IOException { + saveTextFile(filename, text, null); } protected SessionChannelClient do_exec(String cmd, Map<String, String> env, String chdir, byte[] stdin_post, OutputStream out) throws IOException, IllegalStateException { @@ -531,4 +532,35 @@ public class SSHHost extends RemoteHost { return false; } + @Override + public boolean dirContainsExact(String path, String name) { + for ( String a : list(path) ) { + if (a.equalsIgnoreCase(name)) + return true; + } + return false; + } + + @Override + public boolean dirContainsFragment(String path, String name_fragment) { + for ( String a : list(path) ) { + if (a.contains(name_fragment)) + return true; + } + return false; + } + + @SuppressWarnings({ "rawtypes", "unchecked" }) + @Override + public String[] list(String path) { + try { + ensureSftpOpen(); + List list = sftp.ls(path); + return (String[]) list.toArray(new String[list.size()]); + } catch ( Exception ex ) { + ex.printStackTrace(); + } + return StringUtil.EMPTY_ARRAY; + } + } // end public class SSHHost diff --git a/src/com/mostc/pftt/main/Config.java b/src/com/mostc/pftt/main/Config.java new file mode 100644 index 0000000..ed752fa --- /dev/null +++ b/src/com/mostc/pftt/main/Config.java @@ -0,0 +1,272 @@ +package com.mostc.pftt.main; + +import java.io.File; +import java.io.FileInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.util.Arrays; +import java.util.LinkedList; +import java.util.List; + +import org.apache.commons.net.ftp.FTPClient; +import org.codehaus.groovy.control.CompilationFailedException; +import org.columba.ristretto.smtp.SMTPProtocol; + +import com.github.mattficken.io.IOUtil; +import com.mostc.pftt.host.Host; +import com.mostc.pftt.scenario.Scenario; +import com.mostc.pftt.scenario.ScenarioSet; +import com.mostc.pftt.telemetry.ConsoleManager; + +import groovy.lang.GroovyClassLoader; +import groovy.lang.GroovyObject; + +/** Handles loading a configuration (hosts, scenarios, credentials, etc...) from a groovy script. + * + * This allows for loading scenarios and hosts without creating a special configuration format, its just executable code. + * + * @see Config#getHosts + * @see Config#loadConfigFromFile + * + * An example configuration file: + * def hosts() { + * [ + * // connect to a host using ssh + * // + * // can test multiple operating systems, one host for each OS (so multiple hosts) + * new SSHHost("192.168.1.1", "administrator", "password01!") + * ] + * } + * def scenario_sets() { + * [ + * // provide address of a MySQL server + * new MySQLScenario() + * ] + * } + * def configure_smtp(def smtp_client) { + * // specify smtp server and credentials + * } + * def configure_ftp_client(def ftp_client) { + * // specify ftp server and credentials + * } + * + * @author Matt Ficken + * + */ + +public final class Config { + public static final String HOSTS_METHOD = "hosts"; + public static final String SCENARIO_SETS_METHOD = "scenario_sets"; + public static final String SCENARIOS_METHOD = "scenarios"; + public static final String CONFIGURE_SMTP_METHOD = "configure_smtp"; + public static final String CONFIGURE_FTP_CLIENT_METHOD = "configure_ftp_client"; + // + protected final LinkedList<Host> hosts; + protected final LinkedList<ScenarioSet> scenario_sets; + protected GroovyObject configure_smtp_method, configure_ftp_client_method; + + protected Config() { + hosts = new LinkedList<Host>(); + scenario_sets = new LinkedList<ScenarioSet>(); + } + + public List<Host> getHosts() { + return hosts; + } + + public List<ScenarioSet> getScenarioSets() { + return scenario_sets; + } + + public boolean configureSMTP(SMTPProtocol smtp) { + return configureSMTP(null, smtp); + } + + public boolean configureSMTP(ConsoleManager cm, SMTPProtocol smtp) { + if (configure_smtp_method==null) + return false; + try { + configure_smtp_method.invokeMethod(CONFIGURE_SMTP_METHOD, smtp); + + return true; + } catch ( Exception ex ) { + if (cm==null) + ex.printStackTrace(); + else + cm.printStackTrace(ex); + } + return false; + } + + public boolean configureFTPClient(FTPClient ftp) { + return configureFTPClient(null, ftp); + } + + public boolean configureFTPClient(ConsoleManager cm, FTPClient ftp) { + if (configure_ftp_client_method==null) + return false; + try { + configure_ftp_client_method.invokeMethod(CONFIGURE_FTP_CLIENT_METHOD, ftp); + + return true; + } catch ( Exception ex ) { + if (cm==null) + ex.printStackTrace(); + else + cm.printStackTrace(ex); + } + return false; + } + + public static Config loadConfigFromStreams(ConsoleManager cm, InputStream... ins) throws CompilationFailedException, InstantiationException, IllegalAccessException, IOException { + GroovyClassLoader loader = new GroovyClassLoader(Config.class.getClassLoader()); + + Config config = new Config(); + + LinkedList<Scenario> scenarios = new LinkedList<Scenario>(); + scenarios.addAll(Arrays.asList(Scenario.getAllDefaultScenarios())); + + // load each configuration streams + GroovyObject go; + Class<?> clazz; + int i=1; + for (InputStream in : ins) { + clazz = loader.parseClass(importString(IOUtil.toString(in))); + + go = (GroovyObject) clazz.newInstance(); + + // call methods in file to get configuration (hosts, etc...) + loadObjectToConfig(cm, config, go, scenarios, "InputStream #"+(i++)+" ("+in+")"); + } + + return loadConfigCommon(cm, scenarios, config); + } // end public static Config loadConfigFromStreams + + public static Config loadConfigFromFiles(ConsoleManager cm, File... files) throws CompilationFailedException, InstantiationException, IllegalAccessException, IOException { + GroovyClassLoader loader = new GroovyClassLoader(Config.class.getClassLoader()); + + Config config = new Config(); + + LinkedList<Scenario> scenarios = new LinkedList<Scenario>(); + scenarios.addAll(Arrays.asList(Scenario.getAllDefaultScenarios())); + + // load each configuration file + GroovyObject go; + Class<?> clazz; + for (File file : files) { + clazz = loader.parseClass(importString(IOUtil.toString(new FileInputStream(file)))); + + go = (GroovyObject) clazz.newInstance(); + + // call methods in file to get configuration (hosts, etc...) + loadObjectToConfig(cm, config, go, scenarios, file.getAbsolutePath()); + } + + return loadConfigCommon(cm, scenarios, config); + } // end public static Config loadConfigFromFiles + + protected static String importString(String code) { + // a hack to import common classes for configuration files (XXX do this a better way) + StringBuilder sb = new StringBuilder(128+code.length()); + // import all standard Scenarios and Host types + sb.append("import ");sb.append(Scenario.class.getPackage().getName());sb.append(".*;\n"); + sb.append("import ");sb.append(Host.class.getPackage().getName());sb.append(".*;\n"); + sb.append("import ");sb.append(SMTPProtocol.class.getName());sb.append(";\n"); + sb.append("import ");sb.append(FTPClient.class.getName());sb.append(";\n"); + sb.append(code); + return sb.toString(); + } + + protected static Config loadConfigCommon(ConsoleManager cm, LinkedList<Scenario> scenarios, Config config) { + // configs may specify individual scenarios, in addition or in place of whole sets + // + // permute the given individual scenarios and add them to the list of scenario sets + for (ScenarioSet scenario_set : ScenarioSet.permuteScenarioSets(scenarios) ) { + if (!config.scenario_sets.contains(scenario_set)) + config.scenario_sets.add(scenario_set); + } + // + + if (cm!=null) { + // report progress + if (config.hosts.size()>0) { + cm.println("Config", "Loaded "+config.hosts.size()+" hosts"); + } + if (config.scenario_sets.size()>0) { + cm.println("Config", "Loaded "+config.scenario_sets.size()+" Scenario-Sets"); + } + } + + + return config; + } // end protected static Config loadConfigCommon + + protected static void loadObjectToConfig(ConsoleManager cm, Config config, GroovyObject go, List<Scenario> scenarios, String file_name) { + Object ret; + try { + ret = go.invokeMethod(HOSTS_METHOD, null); + if (ret instanceof List) { + for (Object o : (List<?>)ret) { + if (o instanceof Host) { + if (!config.hosts.contains(o)) + config.hosts.add((Host)o); + } else { + cm.println("Config", "List returned by hosts() must only contain Host objects, not: "+o.getClass()+" see: "+file_name); + } + } + } else { + cm.println("Config", "hosts() must return List of Hosts, not: "+(ret==null?"null":ret.getClass())+" see: "+file_name); + } + } catch ( Exception ex ) { + } + try { + ret = go.invokeMethod(SCENARIO_SETS_METHOD, null); + if (ret instanceof List) { + for (Object o : (List<?>)ret) { + if (o instanceof ScenarioSet) { + if (!config.scenario_sets.contains(o)) + config.scenario_sets.add((ScenarioSet)o); + } else { + cm.println("Config", "List returned by scenario_sets() must only contain ScenarioSet objects, not: "+o.getClass()+" see: "+file_name); + } + } + } else { + cm.println("Config", "scenario_sets() must return List of ScenarioSets, not: "+(ret==null?"null":ret.getClass())+" see: "+file_name); + } + } catch ( Exception ex ) { + } + try { + ret = go.invokeMethod(SCENARIOS_METHOD, null); + if (ret instanceof List) { + for (Object o : (List<?>)ret) { + if (o instanceof Scenario) { + if (!scenarios.contains(o)) + scenarios.add((Scenario)o); + } else { + cm.println("Config", "List returned by scenarios() must only contain Scenario objects, not: "+o.getClass()+" see: "+file_name); + } + } + } else { + cm.println("Config", "scenarios() must return List of Scenarios, not: "+(ret==null?"null":ret.getClass())+" see: "+file_name); + } + } catch ( Exception ex ) { + } + try { + if (go.getProperty(CONFIGURE_SMTP_METHOD)!=null) { + if (config.configure_smtp_method!=null) + cm.println("Config", CONFIGURE_SMTP_METHOD+"() overriden by : "+file_name); + config.configure_smtp_method = go; + } + } catch ( Exception ex ) { + } + try { + if (go.getProperty(CONFIGURE_FTP_CLIENT_METHOD)!=null) { + if (config.configure_ftp_client_method!=null) + cm.println("Config", CONFIGURE_FTP_CLIENT_METHOD+"() overriden by : "+file_name); + config.configure_ftp_client_method = go; + } + } catch ( Exception ex ) { + } + } // end protected static void loadObjectToConfig + +} // end public final class ConfigUtil diff --git a/src/com/mostc/pftt/main/ConfigUtil.java b/src/com/mostc/pftt/main/ConfigUtil.java deleted file mode 100644 index 4d4eece..0000000 --- a/src/com/mostc/pftt/main/ConfigUtil.java +++ /dev/null @@ -1,88 +0,0 @@ -package com.mostc.pftt.main; - -import java.io.File; -import java.io.IOException; -import java.io.InputStream; -import java.util.List; - -import org.apache.commons.net.ftp.FTPClient; -import org.codehaus.groovy.control.CompilationFailedException; -import org.columba.ristretto.smtp.SMTPProtocol; - -import com.mostc.pftt.host.Host; -import com.mostc.pftt.scenario.ScenarioSet; - -import groovy.lang.GroovyClassLoader; -import groovy.lang.GroovyObject; - -/** Handles loading a configuration (hosts, scenarios, credentials, etc...) from a groovy script. - * - * This allows for loading scenarios and hosts without creating a special configuration format, its just executable code. - * - * @see ConfigUtil#getHosts - * @see ConfigUtil#loadConfigFromFile - * - * An example configuration file: - * hosts() { - * [ - * // connect to a host using ssh - * // - * // can test multiple operating systems, one host for each OS (so multiple hosts) - * new SSHHost("192.168.1.1", "administrator", "password01!") - * ] - * } - * scenario_sets() { - * [ - * // provide address of a MySQL server - * new MySQLScenario() - * ] - * } - * configure_smtp(def smtp_client) { - * // specify smtp server and credentials - * } - * configure_ftp_client(def ftp_client) { - * // specify ftp server and credentials - * } - * - * @author Matt Ficken - * - */ - -public final class ConfigUtil { - public static final String HOSTS_METHOD = "hosts"; - public static final String SCENARIO_SETS_METHOD = "scenario_sets"; - public static final String CONFIGURE_SMTP_METHOD = "configure_smtp"; - public static final String CONFIGURE_FTP_CLIENT_METHOD = "configure_ftp_client"; - - @SuppressWarnings("unchecked") - public static List<Host> getHosts(GroovyObject gobj) { - return (List<Host>) gobj.invokeMethod(HOSTS_METHOD, null); - } - - @SuppressWarnings("unchecked") - public static List<ScenarioSet> getScenarioSets(GroovyObject gobj) { - return (List<ScenarioSet>) gobj.invokeMethod(SCENARIO_SETS_METHOD, null); - } - - public static void configureSMTPProtocol(GroovyObject gobj, SMTPProtocol smtp) { - gobj.invokeMethod(CONFIGURE_SMTP_METHOD, smtp); - } - - public static void configureFTPClient(GroovyObject gobj, FTPClient ftp) { - gobj.invokeMethod(CONFIGURE_FTP_CLIENT_METHOD, ftp); - } - - @SuppressWarnings("deprecation") - public static GroovyObject loadConfigFromStream(InputStream in) throws CompilationFailedException, InstantiationException, IllegalAccessException { - GroovyClassLoader gcl = new GroovyClassLoader(ConfigUtil.class.getClassLoader()); - return (GroovyObject) gcl.parseClass(in).newInstance(); - } - - public static GroovyObject loadConfigFromFile(File file) throws CompilationFailedException, InstantiationException, IllegalAccessException, IOException { - GroovyClassLoader gcl = new GroovyClassLoader(ConfigUtil.class.getClassLoader()); - return (GroovyObject) gcl.parseClass(file).newInstance(); - } - - private ConfigUtil() {} - -} // end public final class ConfigUtil diff --git a/src/com/mostc/pftt/main/PfttMain.java b/src/com/mostc/pftt/main/PfttMain.java index 94965ae..c708bf9 100644 --- a/src/com/mostc/pftt/main/PfttMain.java +++ b/src/com/mostc/pftt/main/PfttMain.java @@ -1,7 +1,6 @@ package com.mostc.pftt.main; import groovy.lang.Binding; -import groovy.lang.GroovyObject; import groovy.ui.Console; import java.awt.Desktop; @@ -113,26 +112,28 @@ public class PfttMain { return last_file == null ? null : PhptTelemetryReader.open(host, last_file); } - public void run_all(ConsoleManager cm, PhpBuild build, PhptSourceTestPack test_pack, ScenarioSet scenario_set) throws Exception { - LinkedList<PhptTestCase> test_cases = new LinkedList<PhptTestCase>(); - - PhptTelemetryWriter tmgr = new PhptTelemetryWriter(host, cm, telem_dir(), build, test_pack, scenario_set); - test_pack.cleanup(); - cm.println("PhptTestPack", "enumerating test cases from test-pack..."); - test_pack.add_test_files(test_cases, tmgr, build); - cm.println("PhptTestPack", "enumerated test cases."); - - PhptTestPackRunner test_pack_runner = new PhptTestPackRunner(tmgr, test_pack, scenario_set, build, host); - cm.showGUI(test_pack_runner); - - test_pack_runner.runTestList(test_cases); - - tmgr.close(); - - new PhptTestCountsMatchSmokeTest(); - - phpt_report(tmgr); - } + public void run_all(ConsoleManager cm, PhpBuild build, PhptSourceTestPack test_pack, List<ScenarioSet> scenario_sets) throws Exception { + for ( ScenarioSet scenario_set : scenario_sets ) { + ArrayList<PhptTestCase> test_cases = new ArrayList<PhptTestCase>(12600); + + PhptTelemetryWriter tmgr = new PhptTelemetryWriter(host, cm, telem_dir(), build, test_pack, scenario_set); + test_pack.cleanup(); + cm.println("PhptTestPack", "enumerating test cases from test-pack..."); + test_pack.read(test_cases, tmgr, build); + cm.println("PhptTestPack", "enumerated test cases."); + + PhptTestPackRunner test_pack_runner = new PhptTestPackRunner(tmgr, test_pack, scenario_set, build, host); + cm.showGUI(test_pack_runner); + + test_pack_runner.runTestList(test_cases); + + tmgr.close(); + + new PhptTestCountsMatchSmokeTest(); + + phpt_report(tmgr); + } + } // end public void run_all protected void phpt_report(PhptTelemetryWriter test_telem) throws FileNotFoundException { PhptTelemetryReader base_telem = last_telem(test_telem); @@ -157,25 +158,27 @@ public class PfttMain { } } - public void run_named_tests(ConsoleManager cm, PhpBuild build, PhptSourceTestPack test_pack, ScenarioSet scenario_set, List<String> names) throws Exception { - LinkedList<PhptTestCase> test_cases = new LinkedList<PhptTestCase>(); - - PhptTelemetryWriter tmgr = new PhptTelemetryWriter(host, cm, telem_dir(), build, test_pack, scenario_set); - test_pack.cleanup(); - cm.println("PhptTestPack", "enumerating test cases from test-pack..."); - test_pack.add_named_tests(test_cases, names, tmgr, build); - cm.println("PhptTestPack", "enumerated test cases."); - - PhptTestPackRunner test_pack_runner = new PhptTestPackRunner(tmgr, test_pack, scenario_set, build, host); - cm.showGUI(test_pack_runner); - - test_pack_runner.runTestList(test_cases); - - tmgr.close(); - - new PhptTestCountsMatchSmokeTest(); - - phpt_report(tmgr); + public void run_named_tests(ConsoleManager cm, PhpBuild build, PhptSourceTestPack test_pack, List<ScenarioSet> scenario_sets, List<String> names) throws Exception { + for ( ScenarioSet scenario_set : scenario_sets ) { + LinkedList<PhptTestCase> test_cases = new LinkedList<PhptTestCase>(); + + PhptTelemetryWriter tmgr = new PhptTelemetryWriter(host, cm, telem_dir(), build, test_pack, scenario_set); + test_pack.cleanup(); + cm.println("PhptTestPack", "enumerating test cases from test-pack..."); + test_pack.read(test_cases, names, tmgr, build); + cm.println("PhptTestPack", "enumerated test cases."); + + PhptTestPackRunner test_pack_runner = new PhptTestPackRunner(tmgr, test_pack, scenario_set, build, host); + cm.showGUI(test_pack_runner); + + test_pack_runner.runTestList(test_cases); + + tmgr.close(); + + new PhptTestCountsMatchSmokeTest(); + + phpt_report(tmgr); + } // end for } /* -------------------------------------------------- */ @@ -205,12 +208,15 @@ public class PfttMain { System.out.println(); System.out.println("Options:"); System.out.println("-gui - show gui for certain commands"); - System.out.println("-config <file> - configuration file"); + System.out.println("-config <file1,file2> - load 1+ configuration file(s)"); System.out.println("-force - disables confirmation dialogs and forces proceeding anyway"); System.out.println("-stress_each <0+> - runs each test-case N times consecutively"); System.out.println("-stress_all <0+> - runs all tests N times in loop"); System.out.println("-results_only - displays only test results and no other information (for automation)."); System.out.println("-disable_debug_prompt - disables asking you if you want to debug PHP crashes (for automation. default=enabled)"); + System.out.println("-phpt-not-in-place - copies PHPTs to a temporary dir and runs PHPTs from there (default=disabled, test in-place)"); + System.out.println("-dont-cleanup-test-pack - doesn't delete temp dir created by -phpt-not-in-place or SMB scenario (default=delete)"); + System.out.println("-auto - changes default options for automated testing"); System.out.println("(note: stress options not useful against CLI without code caching)"); System.out.println(); } // end protected static void cmd_help @@ -263,11 +269,11 @@ public class PfttMain { console.run(); } - protected static void cmd_phpt_all(PfttMain rt, ConsoleManager cm, GroovyObject config_obj, PhpBuild build, PhptSourceTestPack test_pack) throws Exception { - rt.run_all(cm, build, test_pack, ScenarioSet.getScenarioSets().iterator().next()); + protected static void cmd_phpt_all(PfttMain rt, ConsoleManager cm, Config config, PhpBuild build, PhptSourceTestPack test_pack) throws Exception { + rt.run_all(cm, build, test_pack, config==null?ScenarioSet.getDefaultScenarioSets():config.getScenarioSets()); } - protected static void cmd_phpt_list(PfttMain rt, ConsoleManager cm, GroovyObject config_obj, PhpBuild build, PhptSourceTestPack test_pack, File list_file) throws Exception { + protected static void cmd_phpt_list(PfttMain rt, ConsoleManager cm, Config config, PhpBuild build, PhptSourceTestPack test_pack, File list_file) throws Exception { BufferedReader fr = new BufferedReader(new FileReader(list_file)); LinkedList<String> tests = new LinkedList<String>(); String line; @@ -279,11 +285,11 @@ public class PfttMain { tests.add(line); } - rt.run_named_tests(cm, build, test_pack, ScenarioSet.getScenarioSets().iterator().next(), tests); + rt.run_named_tests(cm, build, test_pack, config==null?ScenarioSet.getDefaultScenarioSets():config.getScenarioSets(), tests); } - protected static void cmd_phpt_named(PfttMain rt, ConsoleManager cm, GroovyObject config_obj, PhpBuild build, PhptSourceTestPack test_pack, List<String> names) throws Exception { - rt.run_named_tests(cm, build, test_pack, ScenarioSet.getScenarioSets().iterator().next(), names); + protected static void cmd_phpt_named(PfttMain rt, ConsoleManager cm, Config config, PhpBuild build, PhptSourceTestPack test_pack, List<String> names) throws Exception { + rt.run_named_tests(cm, build, test_pack, config==null?ScenarioSet.getDefaultScenarioSets():config.getScenarioSets(), names); } protected static void cmd_ui() { @@ -375,7 +381,7 @@ public class PfttMain { HttpProtocolParams.setUserAgent(params, "Mozilla/5.0 (Windows NT 6.1; rv:12.0) Gecko/ 20120405 Firefox/14.0.1"); HttpProtocolParams.setUseExpectContinue(params, true); - HttpProcessor httpproc = new ImmutableHttpProcessor(new HttpRequestInterceptor[] {// XXX reuse + HttpProcessor httpproc = new ImmutableHttpProcessor(new HttpRequestInterceptor[] { // Required protocol interceptors new RequestContent(), new RequestTargetHost(), @@ -568,8 +574,9 @@ public class PfttMain { // int args_i = 0; - GroovyObject config_obj = null; - boolean show_gui = false, force = false, disable_debug_prompt = false, results_only = false; + Config config = null; + boolean show_gui = false, force = false, disable_debug_prompt = false, results_only = false, dont_cleanup_test_pack = false, phpt_not_in_place = false; + LinkedList<File> config_files = new LinkedList<File>(); int stress_all = 0, stress_each = 0; // @@ -579,15 +586,46 @@ public class PfttMain { } else if (args[args_i].equals("-force")) { force = true; } else if (args[args_i].equals("-config")) { - File config_file = new File(args[args_i++]); - if (!config_file.isFile()) { - System.err.println("User Error: config file not found: "+config_file); - System.exit(-255); - return; - } - - // load configuration - config_obj = ConfigUtil.loadConfigFromFile(config_file); + args_i++; + for ( String part : args[args_i].split("[;|:|,]") ) { + File config_file = new File(part); + if (config_file.exists()) { + if (!config_files.contains(config_file)) + config_files.add(config_file); + } else { + config_file = new File(part+".groovy"); + if (config_file.exists()) { + if (!config_files.contains(config_file)) + config_files.add(config_file); + } else { + config_file = new File(LocalHost.getLocalPfttDir()+"/conf/"+part); + if (config_file.exists()) { + if (!config_files.contains(config_file)) + config_files.add(config_file); + } else { + config_file = new File(LocalHost.getLocalPfttDir()+"/conf/"+part+".groovy"); + if (config_file.exists()) { + if (!config_files.contains(config_file)) + config_files.add(config_file); + } else { + System.err.println("User Error: config file not found: "+config_file); + System.exit(-255); + break; + } + } + } + } + } // end for + } else if (args[args_i].equals("-phpt-not-in-place")) { + phpt_not_in_place = false; + } else if (args[args_i].equals("-dont-cleanup-test-pack")) { + dont_cleanup_test_pack = true; + } else if (args[args_i].equals("-auto")) { + // change these defaults for automated testing + disable_debug_prompt = true; + results_only = false; + dont_cleanup_test_pack = false; + phpt_not_in_place = true; } else if (args[args_i].equals("-stress_each")) { stress_each = Integer.parseInt(args[args_i++]); } else if (args[args_i].equals("-stress_all")) { @@ -619,7 +657,9 @@ public class PfttMain { System.err.println("PFTT: not implemented: stress_each="+stress_each+" stress_all="+stress_all+" ignored"); } - ConsoleManager cm = new ConsoleManager(results_only, show_gui, disable_debug_prompt); + ConsoleManager cm = new ConsoleManager(results_only, show_gui, disable_debug_prompt, dont_cleanup_test_pack, phpt_not_in_place); + + config = Config.loadConfigFromFiles(cm, (File[])config_files.toArray(new File[config_files.size()])); if (command!=null) { if (command.equals("phpt_named")||command.equals("phptnamed")||command.equals("phptn")||command.equals("pn")) { @@ -653,8 +693,8 @@ public class PfttMain { cm.println("Build", build.toString()); cm.println("Test-Pack", test_pack.toString()); - HostEnvUtil.prepareHostEnv(rt.host, cm, !disable_debug_prompt); - cmd_phpt_named(rt, cm, config_obj, build, test_pack, names); + HostEnvUtil.prepareHostEnv(rt.host, cm, !cm.isDisableDebugPrompt()); + cmd_phpt_named(rt, cm, config, build, test_pack, names); System.out.println("PFTT: finished"); } else if (command.equals("phpt_list")||command.equals("phptlist")||command.equals("phptl")||command.equals("pl")) { @@ -691,7 +731,7 @@ public class PfttMain { cm.println("Test-Pack", test_pack.toString()); HostEnvUtil.prepareHostEnv(rt.host, cm, !disable_debug_prompt); - cmd_phpt_list(rt, cm, config_obj, build, test_pack, list_file); + cmd_phpt_list(rt, cm, config, build, test_pack, list_file); System.out.println("PFTT: finished"); } else if (command.equals("phpt_all")||command.equals("phptall")||command.equals("phpta")||command.equals("pa")) { @@ -722,7 +762,7 @@ public class PfttMain { // run all tests HostEnvUtil.prepareHostEnv(rt.host, cm, !disable_debug_prompt); - cmd_phpt_all(rt, cm, config_obj, build, test_pack); + cmd_phpt_all(rt, cm, config, build, test_pack); System.out.println("PFTT: finished"); } else if (command.equals("aut")) { @@ -735,7 +775,7 @@ public class PfttMain { } no_show_gui(show_gui, command); - cmd_aut(cm, rt, rt.host, build, ScenarioSet.getScenarioSets()); + cmd_aut(cm, rt, rt.host, build, config==null?ScenarioSet.getDefaultScenarioSets():config.getScenarioSets()); } else if (command.equals("shell_ui")||(show_gui && command.equals("shell"))) { cmd_shell_ui(); } else if (command.equals("shell")) { diff --git a/src/com/mostc/pftt/model/phpt/PhpBuild.java b/src/com/mostc/pftt/model/phpt/PhpBuild.java index b972d79..7bd1b3f 100644 --- a/src/com/mostc/pftt/model/phpt/PhpBuild.java +++ b/src/com/mostc/pftt/model/phpt/PhpBuild.java @@ -261,11 +261,11 @@ public class PhpBuild extends Build { public void setDefaultPhpIni(Host host, PhpIni ini) throws IOException { this.php_ini = new WeakReference<PhpIni>(ini); - host.saveFile(getDefaultPhpIniPath(host), ini.toString()); + host.saveTextFile(getDefaultPhpIniPath(host), ini.toString()); if (!host.isWindows()) { - host.saveFile("/etc/php/cli/php.ini", ini.toString()); - host.saveFile("/etc/php/cgi/php.ini", ini.toString()); + host.saveTextFile("/etc/php/cli/php.ini", ini.toString()); + host.saveTextFile("/etc/php/cgi/php.ini", ini.toString()); } } @@ -298,7 +298,7 @@ public class PhpBuild extends Build { String php_filename = host.mktempname("Build", ".php"); - host.saveFile(php_filename, code); + host.saveTextFile(php_filename, code); PHPOutput output = new PHPOutput(php_filename, host.exec(php_exe+" "+php_filename, timeout_seconds, new HashMap<String,String>(), null, Host.dirname(php_filename))); if (auto_cleanup && !output.hasFatalError()) diff --git a/src/com/mostc/pftt/model/phpt/PhpIni.java b/src/com/mostc/pftt/model/phpt/PhpIni.java index 634d7cc..44f042f 100644 --- a/src/com/mostc/pftt/model/phpt/PhpIni.java +++ b/src/com/mostc/pftt/model/phpt/PhpIni.java @@ -104,9 +104,7 @@ public class PhpIni extends TestCaseGroupKey { ini.putMulti(DISABLE_DEFS, StringUtil.EMPTY); ini.putMulti(OUTPUT_BUFFERING, OFF); ini.putMulti(ERROR_REPORTING, E_ALL_OR_E_STRICT); - // IMPORTANT: display_errors=0. doesn't affect test output. run-tests.php sets display_errors=1 - // but on Windows, that will cause a blocking Winpopup message (bad) - ini.putMulti(DISPLAY_ERRORS, 0); + ini.putMulti(DISPLAY_ERRORS, 1); ini.putMulti(DISPLAY_STARTUP_ERRORS, 0); ini.putMulti(LOG_ERRORS, 0); ini.putMulti(HTML_ERRORS, 0); diff --git a/src/com/mostc/pftt/model/phpt/PhptSourceTestPack.java b/src/com/mostc/pftt/model/phpt/PhptSourceTestPack.java index 93a32e0..c47aee8 100644 --- a/src/com/mostc/pftt/model/phpt/PhptSourceTestPack.java +++ b/src/com/mostc/pftt/model/phpt/PhptSourceTestPack.java @@ -53,18 +53,17 @@ public class PhptSourceTestPack extends SourceTestPack { // these are symlinks(junctions) which may cause an infinite loop // // normally, they are deleted, but if certain tests were interrupted, they may still be there - host.deleteIfExists("ext/standard/tests/file/windows_links/mklink_junction"); - host.deleteIfExists("ext/standard/tests/file/windows_links/directory"); - host.deleteIfExists("ext/standard/tests/file/windows_links/mounted_volume"); - host.deleteIfExists("ext/standard/tests/file/windows_links/mnt"); + host.deleteIfExists(test_pack+"/ext/standard/tests/file/windows_links/mklink_junction"); + host.deleteIfExists(test_pack+"/ext/standard/tests/file/windows_links/directory"); + host.deleteIfExists(test_pack+"/ext/standard/tests/file/windows_links/mounted_volume"); + host.deleteIfExists(test_pack+"/ext/standard/tests/file/windows_links/mnt"); } - public void add_named_tests(List<PhptTestCase> test_files, List<String> names, PhptTelemetryWriter twriter, PhpBuild build) throws FileNotFoundException, IOException, Exception { - add_named_tests(test_files, names, twriter, build, false); + public void read(List<PhptTestCase> test_files, List<String> names, PhptTelemetryWriter twriter, PhpBuild build) throws FileNotFoundException, IOException, Exception { + read(test_files, names, twriter, build, false); } - // TODO rename this - always call before (only once) before using PhptTestPack - public void add_named_tests(List<PhptTestCase> test_files, List<String> names, PhptTelemetryWriter twriter, PhpBuild build, boolean ignore_missing) throws FileNotFoundException, IOException, Exception { + public void read(List<PhptTestCase> test_files, List<String> names, PhptTelemetryWriter twriter, PhpBuild build, boolean ignore_missing) throws FileNotFoundException, IOException, Exception { test_pack_file = new File(test_pack); test_pack = test_pack_file.getAbsolutePath(); // normalize path @@ -114,7 +113,7 @@ public class PhptSourceTestPack extends SourceTestPack { twriter.setTotalCount(test_files.size()); } - public void add_test_files(List<PhptTestCase> test_files, PhptTelemetryWriter twriter, PhpBuild build) throws FileNotFoundException, IOException, Exception { + public void read(List<PhptTestCase> test_files, PhptTelemetryWriter twriter, PhpBuild build) throws FileNotFoundException, IOException, Exception { test_pack_file = new File(test_pack); test_pack = test_pack_file.getAbsolutePath(); // normalize path add_test_files(test_pack_file.listFiles(), test_files, null, twriter, build, null, new LinkedList<PhptTestCase>()); @@ -140,9 +139,6 @@ public class PhptSourceTestPack extends SourceTestPack { if (test_name.startsWith("/") || test_name.startsWith("\\")) test_name = test_name.substring(1); -// if (test_name.contains("a_dir")) -// continue; // TODO - PhptTestCase test_case = PhptTestCase.load(host, this, false, test_name, twriter, redirect_parent); add_test_case(test_case, test_files, names, twriter, build, redirect_parent, redirect_targets); @@ -166,12 +162,8 @@ public class PhptSourceTestPack extends SourceTestPack { add_test_files(dir.listFiles(), test_files, names, twriter, build, redirect_parent, redirect_targets); } else { - // test refers to a specific test, try to load it - //try { - test_case = PhptTestCase.load(host, this, false, target_test_name, twriter, redirect_parent); - /*} catch ( Exception ex ) { - ex.printStackTrace(); // TODO temp - }*/ + // test refers to a specific test, load it + test_case = PhptTestCase.load(host, this, false, target_test_name, twriter, redirect_parent); if (redirect_targets.contains(test_case)) // can only have 1 level of redirection @@ -197,6 +189,10 @@ public class PhptSourceTestPack extends SourceTestPack { public String getContents(Host host, String name) throws IOException { return host.getContentsDetectCharset(new File(test_pack_file, name).getAbsolutePath(), PhptTestCase.newCharsetDeciderDecoder()); } + + public PhptActiveTestPack installInPlace() { + return new PhptActiveTestPack(this.getSourceDirectory()); + } public PhptActiveTestPack install(Host host, String test_pack_dir) throws IllegalStateException, IOException, Exception { if (!this.host.isRemote() || this.host.equals(host)) { diff --git a/src/com/mostc/pftt/model/phpt/PhptTestCase.java b/src/com/mostc/pftt/model/phpt/PhptTestCase.java index d50ac6f..c26d93c 100644 --- a/src/com/mostc/pftt/model/phpt/PhptTestCase.java +++ b/src/com/mostc/pftt/model/phpt/PhptTestCase.java @@ -537,6 +537,15 @@ public class PhptTestCase extends TestCase { return name.equals(o); } + public boolean isNamed(String...names) { + // XXX someday, do a Trie structure here to speed up checking + for (String name:names) { + if (this.name.equals(name)) + return true; + } + return false; + } + /** returns the name of this test. * * for standardization/normalization, all backslashes(\) in test names are converted to unix/forwardslashes(/) @@ -786,64 +795,60 @@ public class PhptTestCase extends TestCase { * @return */ public boolean isSlowTest() { - // TODO start the slow tests first, so that all tests finish faster - return isSlowTest(getName()); - } - public static boolean isSlowTest(String test_name) { - // TODO - return false; + return isNamed( + "ext/date/tests/date_diff.phpt", + "ext/oci8/tests/bug42496_1.phpt", + "ext/oci8/tests/bug42496_2.phpt", + "ext/oci8/tests/bug43497.phpt", + "ext/oci8/tests/bug43497_92.phpt", + "ext/oci8/tests/bug44113.phpt", + "ext/oci8/tests/conn_attr_4.phpt", + "ext/oci8/tests/error2.phpt", + "ext/oci8/tests/extauth_01.phpt", + "ext/oci8/tests/extauth_02.phpt", + "ext/oci8/tests/extauth_03.phpt", + "ext/oci8/tests/lob_043.phpt", + "ext/oci8/tests/pecl_bug10194.phpt", + "ext/oci8/tests/pecl_bug10194_blob.phpt", + "ext/oci8/tests/pecl_bug10194_blob_64.phpt", + "ext/phar/tests/bug13727.phpt", + "ext/phar/tests/bug45218_SLOWTEST.phpt", + "ext/phar/tests/bug45218_SLOWTESTU.phpt", + "ext/phar/tests/bug46032.phpt", + "ext/phar/tests/bug46060.phpt", + "ext/standard/tests/file/001.phpt", + "ext/standard/tests/file/005_variation.phpt", + "ext/standard/tests/file/file_get_contents_error001.phpt", + "ext/standard/tests/file/lstat_stat_basic.phpt", + "ext/standard/tests/file/lstat_stat_variation10.phpt", + "ext/standard/tests/file/lstat_stat_variation11.phpt", + "ext/standard/tests/file/lstat_stat_variation12.phpt", + "ext/standard/tests/file/lstat_stat_variation13.phpt", + "ext/standard/tests/file/lstat_stat_variation15.phpt", + "ext/standard/tests/file/lstat_stat_variation16.phpt", + "ext/standard/tests/file/lstat_stat_variation17.phpt", + "ext/standard/tests/file/lstat_stat_variation21.phpt", + "ext/standard/tests/file/lstat_stat_variation4.phpt", + "ext/standard/tests/file/lstat_stat_variation5.phpt", + "ext/standard/tests/file/lstat_stat_variation6.phpt", + "ext/standard/tests/file/lstat_stat_variation8.phpt", + "ext/standard/tests/file/touch_basic.phpt", + "ext/standard/tests/general_functions/bug39322.phpt", + "ext/standard/tests/general_functions/proc_open02.phpt", + "ext/standard/tests/general_functions/sleep_basic.phpt", + "ext/standard/tests/general_functions/usleep_basic.phpt", + "ext/standard/tests/misc/time_nanosleep_basic.phpt", + "ext/standard/tests/misc/time_sleep_until_basic.phpt", + "ext/standard/tests/network/gethostbyname_basic001.phpt", + "ext/standard/tests/network/gethostbyname_error004.phpt", + "ext/standard/tests/network/getmxrr.phpt", + "ext/standard/tests/network/http-stream.phpt", + "tests/func/005a.phpt", + "tests/func/010.phpt", + "tests/lang/045.phpt", + "Zend/tests/bug55509.phpt" + ); } - /* ext/date/tests/date_diff.phpt -ext/oci8/tests/bug42496_1.phpt -ext/oci8/tests/bug42496_2.phpt -ext/oci8/tests/bug43497.phpt -ext/oci8/tests/bug43497_92.phpt -ext/oci8/tests/bug44113.phpt -ext/oci8/tests/conn_attr_4.phpt -ext/oci8/tests/error2.phpt -ext/oci8/tests/extauth_01.phpt -ext/oci8/tests/extauth_02.phpt -ext/oci8/tests/extauth_03.phpt -ext/oci8/tests/lob_043.phpt -ext/oci8/tests/pecl_bug10194.phpt -ext/oci8/tests/pecl_bug10194_blob.phpt -ext/oci8/tests/pecl_bug10194_blob_64.phpt -ext/phar/tests/bug13727.phpt -ext/phar/tests/bug45218_SLOWTEST.phpt -ext/phar/tests/bug45218_SLOWTESTU.phpt -ext/phar/tests/bug46032.phpt -ext/phar/tests/bug46060.phpt -ext/standard/tests/file/001.phpt -ext/standard/tests/file/005_variation.phpt -ext/standard/tests/file/file_get_contents_error001.phpt -ext/standard/tests/file/lstat_stat_basic.phpt -ext/standard/tests/file/lstat_stat_variation10.phpt -ext/standard/tests/file/lstat_stat_variation11.phpt -ext/standard/tests/file/lstat_stat_variation12.phpt -ext/standard/tests/file/lstat_stat_variation13.phpt -ext/standard/tests/file/lstat_stat_variation15.phpt -ext/standard/tests/file/lstat_stat_variation16.phpt -ext/standard/tests/file/lstat_stat_variation17.phpt -ext/standard/tests/file/lstat_stat_variation21.phpt -ext/standard/tests/file/lstat_stat_variation4.phpt -ext/standard/tests/file/lstat_stat_variation5.phpt -ext/standard/tests/file/lstat_stat_variation6.phpt -ext/standard/tests/file/lstat_stat_variation8.phpt -ext/standard/tests/file/touch_basic.phpt -ext/standard/tests/general_functions/bug39322.phpt -ext/standard/tests/general_functions/proc_open02.phpt -ext/standard/tests/general_functions/sleep_basic.phpt -ext/standard/tests/general_functions/usleep_basic.phpt -ext/standard/tests/misc/time_nanosleep_basic.phpt -ext/standard/tests/misc/time_sleep_until_basic.phpt -ext/standard/tests/network/gethostbyname_basic001.phpt -ext/standard/tests/network/gethostbyname_error004.phpt -ext/standard/tests/network/getmxrr.phpt -ext/standard/tests/network/http-stream.phpt -tests/func/005a.phpt -tests/func/010.phpt -tests/lang/045.phpt -Zend/tests/bug55509.phpt */ public static DefaultCharsetDeciderDecoder newCharsetDeciderDecoder() { return new DefaultCharsetDeciderDecoder(CharsetDeciderDecoder.EXPRESS_RECOGNIZERS); diff --git a/src/com/mostc/pftt/report/AbstractReportGen.groovy b/src/com/mostc/pftt/report/AbstractReportGen.groovy index be0f565..64549a5 100644 --- a/src/com/mostc/pftt/report/AbstractReportGen.groovy +++ b/src/com/mostc/pftt/report/AbstractReportGen.groovy @@ -13,7 +13,7 @@ abstract class AbstractReportGen implements Runnable { System.out.println(html_file); System.out.println(html_str); - host.saveFile(html_file, html_str); + host.saveTextFile(html_file, html_str); return html_file; } diff --git a/src/com/mostc/pftt/runner/AbstractPhptTestCaseRunner.java b/src/com/mostc/pftt/runner/AbstractPhptTestCaseRunner.java index 3e806c5..1359a64 100644 --- a/src/com/mostc/pftt/runner/AbstractPhptTestCaseRunner.java +++ b/src/com/mostc/pftt/runner/AbstractPhptTestCaseRunner.java @@ -55,7 +55,7 @@ public abstract class AbstractPhptTestCaseRunner { return true; // TODO openbasedir - } else if (test_case.isNamed("tests/security/open_basedir_is_file.phpt")||test_case.isNamed("ext/standard/tests/php_ini_loaded_file.phpt")||test_case.isNamed("tests/run-test/test010.phpt")||test_case.isNamed("ext/standard/tests/misc/time_sleep_until_basic.phpt") || test_case.getName().contains("session") || test_case.isNamed("ext/standard/tests/misc/time_nanosleep_basic.phpt")) { + } else if (test_case.isNamed("tests/security/open_basedir_is_file.phpt", "ext/standard/tests/php_ini_loaded_file.phpt", "tests/run-test/test010.phpt", "ext/standard/tests/misc/time_sleep_until_basic.phpt", "ext/standard/tests/misc/time_nanosleep_basic.phpt")) { twriter.addResult(new PhptTestResult(host, EPhptTestStatus.XSKIP, test_case, "test sometimes randomly fails, ignore it", 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 a4a7b09..f9cfb7d 100644 --- a/src/com/mostc/pftt/runner/AbstractPhptTestCaseRunner2.java +++ b/src/com/mostc/pftt/runner/AbstractPhptTestCaseRunner2.java @@ -1,7 +1,6 @@ package com.mostc.pftt.runner; import java.io.ByteArrayOutputStream; -import java.io.File; import java.io.IOException; import java.nio.charset.Charset; import java.util.Map; @@ -39,20 +38,14 @@ public abstract class AbstractPhptTestCaseRunner2 extends AbstractPhptTestCaseRu protected final PhptThread thread; protected final PhptActiveTestPack active_test_pack; protected byte[] stdin_post; - // TODO cleanup field names protected String skipif_file; - protected String cmd; - protected String shell_script; - protected String ini_settings; - protected String shell_file, selected_php_exe; - protected String temp_target; - protected String temp_source; protected String test_dir; protected String base_file_name; protected String test_file; protected String test_clean; - protected String tmp_post, content_type; - protected final PhpIni ini; + protected String content_type; + protected PhpIni ini; + protected String tmp_post; // TODO move this to telemetry manager /** runs the test case and reports the results to the PhptTelemetryManager * @@ -61,13 +54,10 @@ public abstract class AbstractPhptTestCaseRunner2 extends AbstractPhptTestCaseRu */ @Override public void runTest() throws IOException, Exception, Throwable { - // Default ini settings -// ini = PhpIni.createDefaultIniCopy(host); if (!prepare()) + // test is SKIP BORK EXCEPTION etc... return; - // XXX check if prepare() has borked the test -> don't bother running SKIPIF leads to test_skipif=null -> exception - notifyStart(); try { @@ -120,19 +110,14 @@ public abstract class AbstractPhptTestCaseRunner2 extends AbstractPhptTestCaseRu } test_dir = active_test_pack.getDirectory()+host.dirSeparator()+Host.dirname(test_case.getName()); - - /*if (temp_source!=null && temp_target!=null) { - // XXX needed?? - test_dir = StringUtil.replaceAll(Pattern.compile(temp_source), temp_target, test_dir); - }*/ - base_file_name = Host.basename(test_case.getName()).replaceAll(".phpt", ""); // TODO clean this up + base_file_name = Host.basename(Host.removeFileExt(test_case.getName())); // if (test_case.containsSection(EPhptSection.SKIPIF)) { skipif_file = test_dir + host.dirSeparator() + base_file_name + ".skip.php"; - host.saveFile(skipif_file, test_case.get(EPhptSection.SKIPIF)); + host.saveTextFile(skipif_file, test_case.get(EPhptSection.SKIPIF)); } else { // clearly flag that skipif isn't to be executed skipif_file = null; @@ -144,18 +129,13 @@ public abstract class AbstractPhptTestCaseRunner2 extends AbstractPhptTestCaseRu test_clean = test_dir + host.dirSeparator() + base_file_name + ".clean.php"; tmp_post = test_dir + host.dirSeparator() + base_file_name + ".post.php"; - /*if (temp_source!=null && temp_target!=null) { - // TODO temp - String copy_file = test_dir + host.dirSeparator() + Host.basename(test_case.getName()) + ".phps"; - - if (!new File(Host.dirname(copy_file)).isDirectory()) { - new File(Host.dirname(copy_file)).mkdirs(); - } - }*/ - - // - ini_settings = ini.toCliArgString(host); + if (test_case.containsSection(EPhptSection.INI)) { + PhpIni ini = test_case.getINI(active_test_pack, host); + ini.appendAll(this.ini); + this.ini = ini; + } + // return true; } // end boolean prepare @@ -215,13 +195,9 @@ public abstract class AbstractPhptTestCaseRunner2 extends AbstractPhptTestCaseRu // open external file and copy to test_file (binary, no char conversion - which could break it - often this is a PHAR file - which will be broken if charset coversion is done) host.copy(src_test_pack.getSourceDirectory()+host.dirSeparator()+Host.dirname(test_case.getName()) + "/" + test_case.get(EPhptSection.FILE_EXTERNAL), test_file); } else { - host.saveFile(test_file, test_case.get(EPhptSection.FILE), test_case.getCommonCharset()); + host.saveTextFile(test_file, test_case.get(EPhptSection.FILE), test_case.getCommonCharset()); } - - // copy CLI args to pass - String args = test_case.containsSection(EPhptSection.ARGS) ? " -- " + test_case.get(EPhptSection.ARGS) : ""; - - + // copy STDIN to pass (POST, POST_RAW, STDIN, etc...) if (test_case.containsSection(EPhptSection.POST_RAW)) { String post = test_case.getTrim(EPhptSection.POST_RAW); @@ -251,10 +227,10 @@ public abstract class AbstractPhptTestCaseRunner2 extends AbstractPhptTestCaseRu request_sb.append(line); request_sb.append('\n'); } - } else { + } // TODO else { request_sb.append(line); request_sb.append('\n'); - } + //} } String request = request_sb.toString(); @@ -271,12 +247,10 @@ public abstract class AbstractPhptTestCaseRunner2 extends AbstractPhptTestCaseRu return; } - host.saveFile(tmp_post, request); + host.saveTextFile(tmp_post, request); stdin_post = request.getBytes(); - cmd = selected_php_exe+" "+ini_settings+" -f \""+test_file+"\""; - } else if (test_case.containsSection(EPhptSection.PUT)) { String post = test_case.getTrim(EPhptSection.PUT); String[] raw_lines = StringUtil.splitLines(post); @@ -311,7 +285,6 @@ public abstract class AbstractPhptTestCaseRunner2 extends AbstractPhptTestCaseRu } stdin_post = request.getBytes(); - cmd = selected_php_exe+" "+ini_settings+" -f \""+test_file+"\""; } else if (test_case.containsSection(EPhptSection.POST)) { @@ -319,7 +292,7 @@ public abstract class AbstractPhptTestCaseRunner2 extends AbstractPhptTestCaseRu if (test_case.containsSection(EPhptSection.GZIP_POST)) { // php's gzencode() => gzip compression => java's GZIPOutputStream - //post = gzencode(post, 9, FORCE_GZIP); + // post = gzencode(post, 9, FORCE_GZIP); ByteArrayOutputStream baos = new ByteArrayOutputStream(); GZIPOutputStreamLevel d = new GZIPOutputStreamLevel(baos, 9); d.write(post.getBytes()); @@ -328,7 +301,7 @@ public abstract class AbstractPhptTestCaseRunner2 extends AbstractPhptTestCaseRu setContentEncoding("gzip"); } else if (test_case.containsSection(EPhptSection.DEFLATE_POST)) { // php's gzcompress() => zlib compression => java's DeflaterOutputStream - //post = gzcompress(post, 9); + // post = gzcompress(post, 9); ByteArrayOutputStream baos = new ByteArrayOutputStream(); DeflaterOutputStream d = new DeflaterOutputStream(baos, new Deflater(9)); d.write(post.getBytes()); @@ -346,19 +319,13 @@ public abstract class AbstractPhptTestCaseRunner2 extends AbstractPhptTestCaseRu setContentType("application/x-www-form-urlencoded"); // critical: php-cgi won"t read more bytes than this (thus some input can go missing) setContentLength(content_length); - - cmd = selected_php_exe+" "+ini_settings+" -f \""+test_file+"\""; - - } else { + } else { setRequestMethod("GET"); if (!hasContentType()) setContentType(StringUtil.EMPTY); setContentLength(0); - - cmd = selected_php_exe+" "+ini_settings+" -f \""+test_file+"\" "+args; } - } // end void prepareTest protected void setContentEncoding(String encoding) { @@ -434,9 +401,9 @@ public abstract class AbstractPhptTestCaseRunner2 extends AbstractPhptTestCaseRu twriter.show_exception(test_case, ex, expected); throw ex; } - if (expected_re_match||check()) { + if (expected_re_match) { - twriter.addResult(new PhptTestResult(host, test_case.isXFail()?EPhptTestStatus.XFAIL:EPhptTestStatus.PASS, test_case, output, null, null, charset, getEnv(), splitCmdString(), stdin_post, shell_script, null, null, null)); + twriter.addResult(new PhptTestResult(host, test_case.isXFail()?EPhptTestStatus.XFAIL:EPhptTestStatus.PASS, test_case, output, null, null, charset, getEnv(), splitCmdString(), stdin_post, getShellScript(), null, null, null)); return; } @@ -446,9 +413,9 @@ public abstract class AbstractPhptTestCaseRunner2 extends AbstractPhptTestCaseRu output = remove_header_from_output(output); output_trim = output.trim(); - if (output_trim.equals(expected)||output_trim.contains(expected)||expected.contains(output_trim)||check()) { + if (output_trim.equals(expected)||output_trim.contains(expected)||expected.contains(output_trim)) { - twriter.addResult(new PhptTestResult(host, test_case.isXFail()?EPhptTestStatus.XFAIL:EPhptTestStatus.PASS, test_case, output, null, null, charset, getEnv(), splitCmdString(), stdin_post, shell_script, null, null, null)); + twriter.addResult(new PhptTestResult(host, test_case.isXFail()?EPhptTestStatus.XFAIL:EPhptTestStatus.PASS, test_case, output, null, null, charset, getEnv(), splitCmdString(), stdin_post, getShellScript(), null, null, null)); return; } @@ -462,9 +429,9 @@ public abstract class AbstractPhptTestCaseRunner2 extends AbstractPhptTestCaseRu // fall through to failing or xfailing the test } else { // compare again - if (output_trim.equals(expected)||output_trim.contains(expected)||expected.contains(output_trim)||(output_trim.length()>20&&expected.length()>20&&output_trim.substring(10, 20).equals(expected.substring(10, 20)))||check()) { + if (output_trim.equals(expected)||output_trim.contains(expected)||expected.contains(output_trim)||(output_trim.length()>20&&expected.length()>20&&output_trim.substring(10, 20).equals(expected.substring(10, 20)))) { - twriter.addResult(new PhptTestResult(host, test_case.isXFail()?EPhptTestStatus.XFAIL:EPhptTestStatus.PASS, test_case, output, null, null, charset, getEnv(), splitCmdString(), stdin_post, shell_script, null, null, null)); + twriter.addResult(new PhptTestResult(host, test_case.isXFail()?EPhptTestStatus.XFAIL:EPhptTestStatus.PASS, test_case, output, null, null, charset, getEnv(), splitCmdString(), stdin_post, getShellScript(), null, null, null)); return; } // end if @@ -473,8 +440,8 @@ public abstract class AbstractPhptTestCaseRunner2 extends AbstractPhptTestCaseRu output = remove_header_from_output(output); output_trim = output.trim(); - if (StringUtil.isEmpty(output_trim)||check()) { - twriter.addResult(new PhptTestResult(host, test_case.isXFail()?EPhptTestStatus.XFAIL:EPhptTestStatus.PASS, test_case, output, null, null, charset, getEnv(), splitCmdString(), stdin_post, shell_script, null, null, null)); + if (StringUtil.isEmpty(output_trim)) { + twriter.addResult(new PhptTestResult(host, test_case.isXFail()?EPhptTestStatus.XFAIL:EPhptTestStatus.PASS, test_case, output, null, null, charset, getEnv(), splitCmdString(), stdin_post, getShellScript(), null, null, null)); return; } @@ -483,7 +450,7 @@ public abstract class AbstractPhptTestCaseRunner2 extends AbstractPhptTestCaseRu // if here, test failed! if (test_case.isXFail()) { - twriter.addResult(new PhptTestResult(host, EPhptTestStatus.XFAIL, test_case, output, null, null, charset, getEnv(), splitCmdString(), stdin_post, shell_script, null, null, preoverride_actual)); + twriter.addResult(new PhptTestResult(host, EPhptTestStatus.XFAIL, test_case, output, null, null, charset, getEnv(), splitCmdString(), stdin_post, getShellScript(), null, null, preoverride_actual)); } else { // test is FAIL @@ -500,18 +467,18 @@ public abstract class AbstractPhptTestCaseRunner2 extends AbstractPhptTestCaseRu expectf = null; } - twriter.addResult(new PhptTestResult(host, EPhptTestStatus.FAIL, test_case, output, actual_lines, expected_lines, charset, getEnv(), splitCmdString(), stdin_post, shell_script, diff, expectf, preoverride_actual, getCrashedSAPIOutput())); + twriter.addResult(new PhptTestResult(host, EPhptTestStatus.FAIL, test_case, output, actual_lines, expected_lines, charset, getEnv(), splitCmdString(), stdin_post, getShellScript(), diff, expectf, preoverride_actual, getCrashedSAPIOutput())); } } // end void evalTest protected Map<String, String> getEnv() { return null; } - protected boolean check() { - // TODO temp - return StringUtil.isEmpty(getCrashedSAPIOutput()); + + protected String getShellScript() { + return null; } - + protected abstract String[] splitCmdString(); protected static String remove_header_from_output(String output) { diff --git a/src/com/mostc/pftt/runner/CliPhptTestCaseRunner.java b/src/com/mostc/pftt/runner/CliPhptTestCaseRunner.java index 9b8991b..241652e 100644 --- a/src/com/mostc/pftt/runner/CliPhptTestCaseRunner.java +++ b/src/com/mostc/pftt/runner/CliPhptTestCaseRunner.java @@ -37,7 +37,7 @@ import com.mostc.pftt.util.StringUtil; public class CliPhptTestCaseRunner extends AbstractPhptTestCaseRunner2 { protected ExecOutput output; protected HashMap<String,String> env; - protected String skip_cmd; + protected String selected_php_exe, shell_script, test_cmd, skip_cmd, ini_settings, shell_file; public CliPhptTestCaseRunner(PhpIni ini, PhptThread thread, PhptTestCase test_case, PhptTelemetryWriter twriter, Host host, ScenarioSet scenario_set, PhpBuild build, PhptSourceTestPack src_test_pack, PhptActiveTestPack active_test_pack) { super(ini, thread, test_case, twriter, host, scenario_set, build, src_test_pack, active_test_pack); @@ -48,6 +48,8 @@ public class CliPhptTestCaseRunner extends AbstractPhptTestCaseRunner2 { @Override protected boolean prepare() throws IOException, Exception { if (super.prepare()) { + ini_settings = ini.toCliArgString(host); + // read ENV vars from test, from its parent (if a test redirected to this test), and merge from scenario env = test_case.getENV(env, twriter.getConsoleManager(), host, build); @@ -77,6 +79,12 @@ public class CliPhptTestCaseRunner extends AbstractPhptTestCaseRunner2 { protected void prepareTest() throws Exception { super.prepareTest(); + // copy CLI args to pass + String args = test_case.containsSection(EPhptSection.ARGS) ? " -- " + test_case.get(EPhptSection.ARGS) : ""; + + // generate cmd string to run test_file with php.exe + test_cmd = selected_php_exe+" "+ini_settings+" -f \""+test_file+"\""+(args==null?"":" "+args); + if (test_case.containsSection(EPhptSection.STDIN)) { if (host.isWindows()) { // @see Zend/tests/multibyte* @@ -145,11 +153,6 @@ public class CliPhptTestCaseRunner extends AbstractPhptTestCaseRunner2 { } @Override - protected Map<String, String> getEnv() { - return this.env; - } - - @Override protected String executeSkipIf() throws Exception { // Check if test should be skipped. if (skipif_file != null) { @@ -182,7 +185,7 @@ public class CliPhptTestCaseRunner extends AbstractPhptTestCaseRunner2 { @Override protected void executeClean() throws Exception { if (test_case.containsSection(EPhptSection.CLEAN)) { - host.saveFile(test_clean, test_case.getTrim(EPhptSection.CLEAN), null); + host.saveTextFile(test_clean, test_case.getTrim(EPhptSection.CLEAN), null); env.remove(ENV_REQUEST_METHOD); env.remove(ENV_QUERY_STRING); @@ -245,7 +248,7 @@ public class CliPhptTestCaseRunner extends AbstractPhptTestCaseRunner2 { } else fw.println("export "+name+"=\""+value+"\""); } - fw.println(cmd); + fw.println(test_cmd); fw.close(); shell_script = sw.toString(); FileWriter w = new FileWriter(shell_file); @@ -279,7 +282,17 @@ public class CliPhptTestCaseRunner extends AbstractPhptTestCaseRunner2 { @Override protected String[] splitCmdString() { - return LocalHost.splitCmdString(cmd); + return LocalHost.splitCmdString(test_cmd); + } + + @Override + protected Map<String, String> getEnv() { + return env; + } + + @Override + protected String getShellScript() { + return shell_script; } } // end public class CliTestCaseRunner diff --git a/src/com/mostc/pftt/runner/HttpTestCaseRunner.java b/src/com/mostc/pftt/runner/HttpTestCaseRunner.java index 7d6aa3e..2d08c9d 100644 --- a/src/com/mostc/pftt/runner/HttpTestCaseRunner.java +++ b/src/com/mostc/pftt/runner/HttpTestCaseRunner.java @@ -72,6 +72,8 @@ public class HttpTestCaseRunner extends AbstractPhptTestCaseRunner2 { twriter.addResult(new PhptTestResult(host, EPhptTestStatus.XSKIP, test_case, "ENV section not supported for testing against web servers", null, null, null, null, null, null, null, null, null, null)); else if (test_case.containsSection(EPhptSection.STDIN)) twriter.addResult(new PhptTestResult(host, EPhptTestStatus.XSKIP, test_case, "STDIN section not supported for testing against web servers", null, null, null, null, null, null, null, null, null, null)); + else if (test_case.containsSection(EPhptSection.ARGS)) + twriter.addResult(new PhptTestResult(host, EPhptTestStatus.XSKIP, test_case, "ARGS section not supported for testing against web servers", null, null, null, null, null, null, null, null, null, null)); return false; } diff --git a/src/com/mostc/pftt/runner/PhptTestPackRunner.java b/src/com/mostc/pftt/runner/PhptTestPackRunner.java index f8aea39..8d73ace 100644 --- a/src/com/mostc/pftt/runner/PhptTestPackRunner.java +++ b/src/com/mostc/pftt/runner/PhptTestPackRunner.java @@ -6,6 +6,7 @@ import java.util.List; import java.util.concurrent.LinkedBlockingQueue; import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.atomic.AtomicInteger; +import java.util.concurrent.atomic.AtomicReference; import com.mostc.pftt.host.Host; import com.mostc.pftt.model.phpt.PhpBuild; @@ -34,24 +35,32 @@ public class PhptTestPackRunner extends AbstractTestPackRunner { protected final PhptSourceTestPack src_test_pack; protected final PhptTelemetryWriter twriter; protected PhptActiveTestPack active_test_pack; - protected ETestPackRunnerState runner_state; + protected AtomicReference<ETestPackRunnerState> runner_state; protected AtomicInteger test_count, active_thread_count; protected HashMap<TestCaseGroupKey,LinkedBlockingQueue<PhptTestCase>> thread_safe_tests; protected HashMap<String,HashMap<TestCaseGroupKey,LinkedBlockingQueue<PhptTestCase>>> non_thread_safe_tests; protected AbstractSAPIScenario sapi_scenario; + protected AbstractFileSystemScenario file_scenario; protected LinkedBlockingQueue<TestCaseGroupKey> group_keys; public PhptTestPackRunner(PhptTelemetryWriter twriter, PhptSourceTestPack test_pack, ScenarioSet scenario_set, PhpBuild build, Host host) { super(scenario_set, build, host); this.twriter = twriter; this.src_test_pack = test_pack; + + runner_state = new AtomicReference<ETestPackRunnerState>(); } public void runTestList(List<PhptTestCase> test_cases) throws Exception { - // XXX if already running, wait - runner_state = ETestPackRunnerState.RUNNING; + // if already running, wait + while (runner_state.get()==ETestPackRunnerState.RUNNING) { + Thread.sleep(100); + } + // + + runner_state.set(ETestPackRunnerState.RUNNING); sapi_scenario = ScenarioSet.getSAPIScenario(scenario_set); - AbstractFileSystemScenario file_scenario = ScenarioSet.getFileSystemScenario(scenario_set); + file_scenario = ScenarioSet.getFileSystemScenario(scenario_set); ////////////////// install test-pack onto the storage it will be run from // for local file system, this is just a file copy. for other scenarios, its more complicated (let the filesystem scenario deal with it) @@ -89,10 +98,10 @@ public class PhptTestPackRunner extends AbstractTestPackRunner { active_test_pack = null; try { // TODO console option (local filesystem scenario only) to use PhptSourceTestPack as PhptActiveTestPack - // -phpt-in-place - // if not -auto and local file system, do in-place by default - // if -auto, don't do in-place - active_test_pack = src_test_pack.install(host, test_pack_dir); + if (twriter.getConsoleManager().isPhptNotInPlace() || !file_scenario.allowPhptInPlace()) + active_test_pack = src_test_pack.install(host, test_pack_dir); + else + active_test_pack = src_test_pack.installInPlace(); } catch (Exception ex ) { twriter.getConsoleManager().printStackTrace(ex); } @@ -121,20 +130,23 @@ public class PhptTestPackRunner extends AbstractTestPackRunner { // TODO serialSAPIInstance_executeTestCases(); parallelSAPIInstance_executeTestCases(); - // delete if successful (otherwise leave it behind for user to analyze the internal exception(s)) - // TODO console option to not cleanup - twriter.getConsoleManager().println("PhptTestPackRunner", "deleting up active test-pack: "+active_test_pack); - host.delete(active_test_pack.getDirectory()); + // TODO delete if successful (otherwise leave it behind for user to analyze the internal exception(s)) + if (!twriter.getConsoleManager().isDontCleanupTestPack() && !active_test_pack.getDirectory().equals(src_test_pack.getSourceDirectory())) { + twriter.getConsoleManager().println("PhptTestPackRunner", "deleting/cleaning-up active test-pack: "+active_test_pack); + host.delete(active_test_pack.getDirectory()); + + // cleanup, disconnect storage, etc... + file_scenario.notifyFinishedTestPack(twriter.getConsoleManager(), host); + } + // } finally { // be sure all running WebServerInstances, or other SAPIInstances are - // closed by end of testing (otherwise php.exe -S will keep on running) + // closed by end of testing (otherwise `php.exe -S` will keep on running) close(); } } // end public void runTestList public void close() { - if (sapi_scenario instanceof AbstractWebServerScenario) // TODO temp - ((AbstractWebServerScenario)sapi_scenario).smgr.close(); sapi_scenario.close(); } @@ -360,7 +372,7 @@ public class PhptTestPackRunner extends AbstractTestPackRunner { test_case = jobs.poll() ) != null && run_thread.get() && - runner_state==ETestPackRunnerState.RUNNING + runner_state.get()==ETestPackRunnerState.RUNNING ) { // CRITICAL: catch exception so thread will always end normally try { @@ -378,8 +390,6 @@ public class PhptTestPackRunner extends AbstractTestPackRunner { counter++; test_count.incrementAndGet(); - - //Thread.yield() } } // end protected void exec_jobs @@ -405,12 +415,12 @@ public class PhptTestPackRunner extends AbstractTestPackRunner { @Override public void setState(ETestPackRunnerState state) throws IllegalStateException { - this.runner_state = state; + this.runner_state.set(state); } @Override public ETestPackRunnerState getState() { - return runner_state; + return runner_state.get(); } } // end public class PhptTestPackRunner diff --git a/src/com/mostc/pftt/scenario/AbstractCodeCacheScenario.java b/src/com/mostc/pftt/scenario/AbstractCodeCacheScenario.java index 69aaef9..3dd3782 100644 --- a/src/com/mostc/pftt/scenario/AbstractCodeCacheScenario.java +++ b/src/com/mostc/pftt/scenario/AbstractCodeCacheScenario.java @@ -1,5 +1,8 @@ package com.mostc.pftt.scenario; public abstract class AbstractCodeCacheScenario extends AbstractSerialScenario { - + @Override + public Class<?> getSerialKey() { + return AbstractCodeCacheScenario.class; + } } diff --git a/src/com/mostc/pftt/scenario/AbstractFileSystemScenario.java b/src/com/mostc/pftt/scenario/AbstractFileSystemScenario.java index 58bf174..ae9bf92 100644 --- a/src/com/mostc/pftt/scenario/AbstractFileSystemScenario.java +++ b/src/com/mostc/pftt/scenario/AbstractFileSystemScenario.java @@ -4,11 +4,23 @@ import com.mostc.pftt.host.Host; import com.mostc.pftt.telemetry.ConsoleManager; public abstract class AbstractFileSystemScenario extends AbstractSerialScenario { - + @Override + public Class<?> getSerialKey() { + return AbstractFileSystemScenario.class; + } public abstract boolean notifyPrepareStorageDir(ConsoleManager cm, Host host); public abstract String getTestPackStorageDir(Host host); public boolean notifyTestPackInstalled(ConsoleManager cm, Host host) { return true; // proceed with using test-pack } + /** checks if -phpt-in-place console option can be ignored or not + * + * @return FALSE - ignore -phpt-in-place, TRUE to follow it (if present) + */ + public abstract boolean allowPhptInPlace(); + public void notifyFinishedTestPack(ConsoleManager consoleManager, Host host) { + + } + } diff --git a/src/com/mostc/pftt/scenario/AbstractParallelScenario.java b/src/com/mostc/pftt/scenario/AbstractParallelScenario.java index eefa4ab..7e72338 100644 --- a/src/com/mostc/pftt/scenario/AbstractParallelScenario.java +++ b/src/com/mostc/pftt/scenario/AbstractParallelScenario.java @@ -7,8 +7,5 @@ package com.mostc.pftt.scenario; */ public abstract class AbstractParallelScenario extends Scenario { - @Override - public boolean rejectOther(Scenario o) { - return o instanceof AbstractParallelScenario && !o.getClass().isInstance(this); - } + } diff --git a/src/com/mostc/pftt/scenario/AbstractSAPIScenario.java b/src/com/mostc/pftt/scenario/AbstractSAPIScenario.java index 5d257f6..c8dc38d 100644 --- a/src/com/mostc/pftt/scenario/AbstractSAPIScenario.java +++ b/src/com/mostc/pftt/scenario/AbstractSAPIScenario.java @@ -24,6 +24,11 @@ import com.mostc.pftt.telemetry.PhptTelemetryWriter; public abstract class AbstractSAPIScenario extends AbstractSerialScenario { + @Override + public Class<?> getSerialKey() { + return AbstractSAPIScenario.class; + } + /** creates a runner to run a single PhptTestCase under this SAPI scenario * * @param thread diff --git a/src/com/mostc/pftt/scenario/AbstractSMBScenario.java b/src/com/mostc/pftt/scenario/AbstractSMBScenario.java index 1936eea..898fd6e 100644 --- a/src/com/mostc/pftt/scenario/AbstractSMBScenario.java +++ b/src/com/mostc/pftt/scenario/AbstractSMBScenario.java @@ -39,6 +39,13 @@ public abstract class AbstractSMBScenario extends AbstractFileSystemScenario { this.base_share_name = base_share_name; } + @Override + public boolean allowPhptInPlace() { + // always make sure test-pack is installed onto SMB Share + // otherwise, there wouldn't be a point in testing on SMB + return false; + } + /** creates a File Share and connects to it. * * a test-pack can then be installed on that File Share. @@ -101,7 +108,7 @@ public abstract class AbstractSMBScenario extends AbstractFileSystemScenario { return false; } } else { - // XXX + // host is local, try using a local drive, normal file system operations, not SMB, etc... local_drive = file_path; return true; @@ -133,4 +140,34 @@ public abstract class AbstractSMBScenario extends AbstractFileSystemScenario { return local_drive; // H: I: J: ... Y: } + public boolean deleteShare(ConsoleManager cm, Host host) { + try { + if (host.execElevated("NET SHARE "+file_path+" /DELETE", Host.ONE_MINUTE).isSuccess()) { + host.delete(file_path); + + return true; + } + } catch ( Exception ex ) { + cm.printStackTrace(ex); + } + return false; + } + + public boolean disconnect(ConsoleManager cm, Host host) { + try { + return host.exec("NET USE "+local_drive+" /DELETE", Host.ONE_MINUTE).isSuccess(); + } catch ( Exception ex ) { + cm.printStackTrace(ex); + } + return false; + } + + @Override + 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; + } + } + } // end public abstract class AbstractSMBScenario diff --git a/src/com/mostc/pftt/scenario/AbstractSerialScenario.java b/src/com/mostc/pftt/scenario/AbstractSerialScenario.java index 68b73b3..da8358a 100644 --- a/src/com/mostc/pftt/scenario/AbstractSerialScenario.java +++ b/src/com/mostc/pftt/scenario/AbstractSerialScenario.java @@ -9,8 +9,7 @@ package com.mostc.pftt.scenario; */ public abstract class AbstractSerialScenario extends Scenario { + @Override - public boolean rejectOther(Scenario o) { - return false; - } + public abstract Class<?> getSerialKey(); } diff --git a/src/com/mostc/pftt/scenario/AbstractSocketScenario.java b/src/com/mostc/pftt/scenario/AbstractSocketScenario.java index 4c0cdc0..5def2a0 100644 --- a/src/com/mostc/pftt/scenario/AbstractSocketScenario.java +++ b/src/com/mostc/pftt/scenario/AbstractSocketScenario.java @@ -1,5 +1,8 @@ package com.mostc.pftt.scenario; public abstract class AbstractSocketScenario extends AbstractOptionScenario { - + @Override + public Class<?> getSerialKey() { + return AbstractSocketScenario.class; + } } diff --git a/src/com/mostc/pftt/scenario/CLIScenario.java b/src/com/mostc/pftt/scenario/CLIScenario.java index ce2b5db..63fa894 100644 --- a/src/com/mostc/pftt/scenario/CLIScenario.java +++ b/src/com/mostc/pftt/scenario/CLIScenario.java @@ -40,8 +40,7 @@ public class CliScenario extends AbstractSAPIScenario { @Override public int getTestThreadCount(Host host) { - // 4 => 395 - return 2 * host.getCPUCount(); + return 4 * host.getCPUCount(); } } // end public class CliScenario diff --git a/src/com/mostc/pftt/scenario/LocalFileSystemScenario.java b/src/com/mostc/pftt/scenario/LocalFileSystemScenario.java index a555970..06c1c69 100644 --- a/src/com/mostc/pftt/scenario/LocalFileSystemScenario.java +++ b/src/com/mostc/pftt/scenario/LocalFileSystemScenario.java @@ -20,6 +20,11 @@ public class LocalFileSystemScenario extends AbstractFileSystemScenario { public boolean isImplemented() { return true; } + + @Override + public boolean allowPhptInPlace() { + return false; + } @Override public boolean notifyPrepareStorageDir(ConsoleManager cm, Host host) { diff --git a/src/com/mostc/pftt/scenario/SMBCSCOptionScenario.java b/src/com/mostc/pftt/scenario/SMBCSCOptionScenario.java index 969c1dd..887289d 100644 --- a/src/com/mostc/pftt/scenario/SMBCSCOptionScenario.java +++ b/src/com/mostc/pftt/scenario/SMBCSCOptionScenario.java @@ -5,6 +5,11 @@ import com.mostc.pftt.telemetry.ConsoleManager; public abstract class SMBCSCOptionScenario extends AbstractOptionScenario { + @Override + public Class<?> getSerialKey() { + return SMBCSCOptionScenario.class; + } + public abstract boolean isEnable(); @Override @@ -17,7 +22,7 @@ public abstract class SMBCSCOptionScenario extends AbstractOptionScenario { String ps_file = host.mktempname(getName(), "ps1"); try { - host.saveFile(ps_file, ps_sb.toString()); + host.saveTextFile(ps_file, ps_sb.toString()); if (host.exec("powershell -File "+ps_file, Host.ONE_MINUTE).isSuccess()) { host.delete(ps_file); diff --git a/src/com/mostc/pftt/scenario/SMBDFSRScenario.java b/src/com/mostc/pftt/scenario/SMBDFSRScenario.java index 737571e..24e6f46 100644 --- a/src/com/mostc/pftt/scenario/SMBDFSRScenario.java +++ b/src/com/mostc/pftt/scenario/SMBDFSRScenario.java @@ -38,7 +38,7 @@ public class SMBDFSRScenario extends AbstractSMBScenario { ps_sb.append("Add-WindowsFeature -name FS-DFS-Replication\n"); String tmp_file = host.mktempname(getName(), "ps1"); - host.saveFile(tmp_file, ps_sb.toString()); + host.saveTextFile(tmp_file, ps_sb.toString()); if (host.exec("Powershell -File "+tmp_file, Host.NO_TIMEOUT).isSuccess()) { host.delete(tmp_file); diff --git a/src/com/mostc/pftt/scenario/SMBDeduplicationScenario.java b/src/com/mostc/pftt/scenario/SMBDeduplicationScenario.java index 1d57030..8346af2 100644 --- a/src/com/mostc/pftt/scenario/SMBDeduplicationScenario.java +++ b/src/com/mostc/pftt/scenario/SMBDeduplicationScenario.java @@ -56,7 +56,7 @@ public class SMBDeduplicationScenario extends AbstractSMBScenario { if (!remote_host.isWin8OrLater()) { cm.println(getName(), "Scenario can only be run against a Windows 8/2012+ host"); return false; - } else if (remote_host.getSystemDrive().equalsIgnoreCase(volume)) { + } else if (volume.equals("C:")||remote_host.getSystemDrive().equalsIgnoreCase(volume)) { cm.println(getName(), "Can not use Deduplication on a Windows System Drive (ex: C:\\)"); return false; } @@ -76,10 +76,10 @@ public class SMBDeduplicationScenario extends AbstractSMBScenario { // create PowerShell script to install and enable deduplication try { - remote_host.saveFile(tmp_file, ps_sb.toString()); + remote_host.saveTextFile(tmp_file, ps_sb.toString()); // - if (remote_host.exec("powershell -File "+tmp_file, Host.ONE_MINUTE * 10).isSuccess()) { + if (remote_host.execElevated("powershell -File "+tmp_file, Host.ONE_MINUTE * 10).isSuccess()) { // don't delete tmp_file if it failed to help user see why remote_host.delete(tmp_file); } @@ -102,12 +102,15 @@ public class SMBDeduplicationScenario extends AbstractSMBScenario { public boolean notifyTestPackInstalled(ConsoleManager cm, Host host) { try { // run deduplication job (on test-pack) -wait for completion - remote_host.exec("powershell -Command {Start-Dedupjob -Volume "+volume+" -Type Optimization -Wait}", Host.NO_TIMEOUT); - - return true; + cm.println(getName(), "Running deduplication job..."); + if (remote_host.exec("powershell -Command {Start-Dedupjob -Volume "+volume+" -Type Optimization -Wait}", Host.NO_TIMEOUT).isSuccess()) { + cm.println(getName(), "Deduplication completed successfully."); + return true; + } } catch ( Exception ex ) { cm.printStackTrace(ex); } + cm.println(getName(), "Deduplication failed"); return false; } diff --git a/src/com/mostc/pftt/scenario/Scenario.java b/src/com/mostc/pftt/scenario/Scenario.java index 92c610e..47e30de 100644 --- a/src/com/mostc/pftt/scenario/Scenario.java +++ b/src/com/mostc/pftt/scenario/Scenario.java @@ -19,7 +19,10 @@ import com.mostc.pftt.telemetry.ConsoleManager; public abstract class Scenario { - public abstract boolean rejectOther(Scenario o); + public Class<?> getSerialKey() { + return getClass(); + } + public abstract String getName(); public abstract boolean isImplemented(); @@ -38,59 +41,29 @@ public abstract class Scenario { public static final AbstractFileSystemScenario DEFAULT_FILESYSTEM_SCENARIO = LOCALFILESYSTEM_SCENARIO; // 90 ScenarioSets => (APC, WinCache, No) * (CLI, Buitlin-WWW, Apache, IIS-Standard, IIS-Express) * ( local filesystem, the 5 types of SMB ) - public static Scenario[][] getAllScenarios() { - return new Scenario[][] { + public static Scenario[] getAllDefaultScenarios() { + return new Scenario[]{ // sockets - new Scenario[] { new PlainSocketScenario(), - new SSLSocketScenario() - }, + new SSLSocketScenario(), // code caches - new Scenario[] { new NoCodeCacheScenario(), new APCScenario(), - new WinCacheScenario() - }, + new WinCacheScenario(), // SAPIs - new Scenario[]{ - new CliScenario(), - // TODO new BuiltinWebServerScenario(), - /* TODO new ApacheModPHPScenario(), + CLI_SCENARIO, + new BuiltinWebServerScenario(), + // if Apache or IIS not installed, will skip these scenarios + new ApacheModPHPScenario(), new IISExpressFastCGIScenario(), - new IISStandardFastCGIScenario() */ - }, + new IISStandardFastCGIScenario(), // filesystems - new Scenario[] { LOCALFILESYSTEM_SCENARIO, -// new SMBBasicScenario(), -// new SMBDeduplicationScenario(), - /* XXX new SMBDFSScenario(), - new SMBCAScenario(), - // probably don't need to test branch cache, but including it for completeness - new SMBBranchCacheScenario()*/ - }, // options for smb - can be applied to any type of smb - new Scenario[] { - // default is CSC enabled - new CSCEnableScenario(), - new CSCDisableScenario(), - }, - // databases - new Scenario[]{ - new MSAccessScenario(), - new MSSQLODBCScenario(), - new MSSQLScenario(), - new MySQLScenario(), - new PostgresSQLScenario(), - new SQLite3Scenario(), - // streams - new FTPScenario(), - new HTTPScenario(), - // web services - new SOAPScenario(), - new XMLRPCScenario() - } + // default is CSC enabled + new CSCEnableScenario(), + new CSCDisableScenario(), }; - } + } // end public static Scenario[] getAllDefaultScenarios } // end public abstract class Scenario diff --git a/src/com/mostc/pftt/scenario/ScenarioSet.java b/src/com/mostc/pftt/scenario/ScenarioSet.java index 15e229d..0b5aa6c 100644 --- a/src/com/mostc/pftt/scenario/ScenarioSet.java +++ b/src/com/mostc/pftt/scenario/ScenarioSet.java @@ -2,6 +2,9 @@ package com.mostc.pftt.scenario; import java.util.ArrayList; import java.util.Arrays; +import java.util.Collections; +import java.util.Comparator; +import java.util.HashMap; import java.util.List; import com.mostc.pftt.host.Host; @@ -34,7 +37,7 @@ import com.mostc.pftt.telemetry.ConsoleManager; * Even so, being able to have fast test runs is critical. PHP builds couldn't be tested across all that otherwise. * * @see #isSupported - * @see ScenarioSet#getScenarioSets() + * @see ScenarioSet#getDefaultScenarioSets() * @author Matt Ficken * */ @@ -42,6 +45,59 @@ import com.mostc.pftt.telemetry.ConsoleManager; @SuppressWarnings("serial") public class ScenarioSet extends ArrayList<Scenario> { + private boolean sorted = false, sorting = false; + private static Comparator<Scenario> COMPARATOR = new Comparator<Scenario>() { + @Override + public int compare(Scenario a, Scenario b) { + return a.getSerialKey().getName().compareTo(b.getSerialKey().getName()); + } + }; + private synchronized void sort() { + if (sorting) + return; + sorting = true; + Collections.sort(this, COMPARATOR); + sorting = false; + sorted = true; + } + + protected void forceSort() { + if (sorting) + return; + sort(); + } + + protected void ensureSorted() { + if (sorted) + return; + sort(); + } + + @Override + public String toString() { + ensureSorted(); + return super.toString(); + } + + @Override + public boolean add(Scenario s) { + super.add(s); + forceSort(); + return true; + } + + @Override + public boolean equals(Object o) { + ensureSorted(); + return super.equals(o); + } + + @Override + public int hashCode() { + ensureSorted(); + return super.hashCode(); + } + /** finds the SAPI Scenario in the ScenarioSet or returns the default SAPI scenario (CLI) in case the ScenarioSet doesn't specify one. * * @see AbstractSAPIScenario @@ -86,59 +142,69 @@ public class ScenarioSet extends ArrayList<Scenario> { return (ScenarioSet) super.clone(); } - /** returns all possible valid ScenarioSets for all Scenarios + + /** calculates all permutations/combinations of given Scenarios and returns them as ScenarioSets * + * @param scenarios * @return */ - public static List<ScenarioSet> getScenarioSets() { - return getScenarioSets(Scenario.getAllScenarios()); - } - - public static List<ScenarioSet> getScenarioSets(Scenario[][] scenarios) { - ArrayList<Scenario[]> s = new ArrayList<Scenario[]>(3); - s.add(scenarios[0]); - s.add(scenarios[1]); - s.add(scenarios[2]); - List<Scenario> b = Arrays.asList(scenarios[3]); - ArrayList<ScenarioSet> sets = permute(s); - for (ScenarioSet set:sets) { - for (Scenario c: b) { - if (c.isImplemented()) - set.add(c); + public static List<ScenarioSet> permuteScenarioSets(List<Scenario> scenarios) { + HashMap<Class<?>,List<Scenario>> map = new HashMap<Class<?>,List<Scenario>>(); + for ( Scenario scenario : scenarios ) { + Class<?> clazz = scenario.getSerialKey(); + // + List<Scenario> list = map.get(clazz); + if (list==null) { + list = new ArrayList<Scenario>(2); + map.put(clazz, list); } + list.add(scenario); } - return sets.subList(0, 1);// TODO 2); // XXX + List<List<Scenario>> remap = new ArrayList<List<Scenario>>(); + for ( List<Scenario> list : map.values() ) + remap.add(list); + return permute(remap); } - protected static ArrayList<ScenarioSet> permute(List<Scenario[]> input) { + protected static ArrayList<ScenarioSet> permute(List<List<Scenario>> input) { ArrayList<ScenarioSet> output = new ArrayList<ScenarioSet>(); - if (input.isEmpty()) { - output.add(new ScenarioSet()); - return output; - } - List<Scenario[]> list = new ArrayList<Scenario[]>(input); - Scenario[] head = list.get(0); - List<Scenario[]> rest = list.subList(1, list.size()); - for (List<Scenario> permutations : permute(rest)) { - List<ScenarioSet> subLists = new ArrayList<ScenarioSet>(); - for (int i = 0; i <= permutations.size(); i++) { - for (int j=0 ; j < head.length; j++) { - if (!head[j].isImplemented()) - continue; // skip it - ScenarioSet subList = new ScenarioSet(); - subList.addAll(permutations); - subList.add(i, head[j]); - subLists.add(subList); - } - } - output.addAll(subLists); - } - return output; - } + if (input.isEmpty()) { + output.add(new ScenarioSet()); + return output; + } + List<List<Scenario>> list = new ArrayList<List<Scenario>>(input); + List<Scenario> head = list.get(0); + List<List<Scenario>> rest = list.subList(1, list.size()); + for (List<Scenario> permutations : permute(rest)) { + List<ScenarioSet> subLists = new ArrayList<ScenarioSet>(); + for (int i = 0; i <= permutations.size(); i++) { + for (int j=0 ; j < head.size(); j++) { + if (!head.get(j).isImplemented()) + continue; // skip it + ScenarioSet subList = new ScenarioSet(); + subList.addAll(permutations); + subList.add(i, head.get(j)); + if (!subList.contains(subList)) + subLists.add(subList); + } + } + for ( ScenarioSet a : subLists ) { + if (!output.contains(a)) + output.add(a); + } + } + return output; + } // end protected static ArrayList<ScenarioSet> permute - public static List<ScenarioSet> toList(ScenarioSet set) { - ArrayList<ScenarioSet> list = new ArrayList<ScenarioSet>(1); - list.add(set); - return list; + private static List<ScenarioSet> scenario_sets; + /** returns all builtin ScenarioSets (ScenarioSets that don't require special configuration (ex: SMB scenarios require a remote SMB host)) + * + * @return + */ + public static List<ScenarioSet> getDefaultScenarioSets() { + return scenario_sets; + } + static { + scenario_sets = permuteScenarioSets(Arrays.asList(Scenario.getAllDefaultScenarios())); } } // end public class ScenarioSet diff --git a/src/com/mostc/pftt/telemetry/ConsoleManager.java b/src/com/mostc/pftt/telemetry/ConsoleManager.java index 56d736c..facd7c7 100644 --- a/src/com/mostc/pftt/telemetry/ConsoleManager.java +++ b/src/com/mostc/pftt/telemetry/ConsoleManager.java @@ -12,14 +12,15 @@ import com.mostc.pftt.ui.PhptDebuggerFrame; import com.mostc.pftt.util.ErrorUtil; public class ConsoleManager { - protected final boolean results_only, show_gui, disable_debug_prompt; + protected final boolean results_only, show_gui, disable_debug_prompt, dont_cleanup_test_pack, phpt_not_in_place; protected PhptDebuggerFrame gui; - public ConsoleManager(boolean results_only, boolean show_gui, boolean disable_debug_prompt) { + public ConsoleManager(boolean results_only, boolean show_gui, boolean disable_debug_prompt, boolean dont_cleanup_test_pack, boolean phpt_not_in_place) { this.results_only = results_only; this.show_gui = show_gui; this.disable_debug_prompt = disable_debug_prompt; - + this.dont_cleanup_test_pack = dont_cleanup_test_pack; + this.phpt_not_in_place = phpt_not_in_place; } public void showGUI(PhptTestPackRunner test_pack_runner) { @@ -76,5 +77,13 @@ public class ConsoleManager { public boolean isResultsOnly() { return results_only; } + + public boolean isDontCleanupTestPack() { + return dont_cleanup_test_pack; + } + + public boolean isPhptNotInPlace() { + return phpt_not_in_place; + } } // end public class ConsoleManager diff --git a/src/com/mostc/pftt/telemetry/PhptTestResult.java b/src/com/mostc/pftt/telemetry/PhptTestResult.java index b869268..44613ab 100644 --- a/src/com/mostc/pftt/telemetry/PhptTestResult.java +++ b/src/com/mostc/pftt/telemetry/PhptTestResult.java @@ -63,8 +63,6 @@ public class PhptTestResult { } public PhptTestResult(Host host, EPhptTestStatus status, PhptTestCase test_case, String actual, String[] actual_lines, String[] expected_lines, Charset actual_cs, Map<String,String> env, String[] cmd_array, byte[] stdin_data, String shell_script, Diff<String> diff, String expectf_output, String preoverride_actual, String sapi_output) { - actual = (""+actual_cs)+"\n"+actual; // TODO - this.sapi_output = sapi_output; this.host = host; diff --git a/src/com/mostc/pftt/ui/ExpectedActualDiffPHPTDisplay.java b/src/com/mostc/pftt/ui/ExpectedActualDiffPHPTDisplay.java index 438016d..9727337 100644 --- a/src/com/mostc/pftt/ui/ExpectedActualDiffPHPTDisplay.java +++ b/src/com/mostc/pftt/ui/ExpectedActualDiffPHPTDisplay.java @@ -11,11 +11,9 @@ import java.io.FileNotFoundException; import java.io.IOException; import java.io.InputStream; -import javax.swing.DefaultListModel; import javax.swing.JButton; import javax.swing.JFrame; import javax.swing.JLabel; -import javax.swing.JList; import javax.swing.JOptionPane; import javax.swing.JPanel; import javax.swing.JScrollPane; @@ -43,8 +41,6 @@ public class ExpectedActualDiffPHPTDisplay extends JScrollPane { protected TextDisplayPanel expected_display, diff_display, actual_display, test_display; protected DefaultTableModel env_table_model; protected JTable env_table; - protected DefaultListModel cmd_array_list_model; - protected JList cmd_array_list; protected JTextArea stdin_data_textarea, shell_script_textarea, expectf_textarea, pre_override_textarea, sapi_output_textarea; protected PhptTestResult test; @@ -102,9 +98,6 @@ public class ExpectedActualDiffPHPTDisplay extends JScrollPane { prepared_panel.add(new JScrollPane(env_table = new JTable(env_table_model = new DefaultTableModel()))); env_table_model.addColumn("Name"); env_table_model.addColumn("Value"); - prepared_panel.add(new JScrollPane(cmd_array_list = new JList(cmd_array_list_model = new DefaultListModel()))); - vertical_panel.add(prepared_panel); - vertical_panel.add(test_display.text_area); } @@ -124,12 +117,6 @@ public class ExpectedActualDiffPHPTDisplay extends JScrollPane { env_table_model.addRow(new Object[]{name, test.env.get(name)}); } } - cmd_array_list_model.clear(); - if (test.cmd_array!=null) { - for (String cmd : test.cmd_array ) { - cmd_array_list_model.addElement(cmd); - } - } if (test.stdin_data!=null) stdin_data_textarea.setText(new String(test.stdin_data)); else diff --git a/src/com/mostc/pftt/ui/PhptDebuggerFrame.java b/src/com/mostc/pftt/ui/PhptDebuggerFrame.java index a1d7e9b..b753d29 100644 --- a/src/com/mostc/pftt/ui/PhptDebuggerFrame.java +++ b/src/com/mostc/pftt/ui/PhptDebuggerFrame.java @@ -60,7 +60,7 @@ public class PhptDebuggerFrame extends JPanel { jmb.add(new JMenu("Test:")); jmb.add(scenario_menu = new JMenu("Scenarios")); ButtonGroup scenario_bg = new ButtonGroup(); - for ( ScenarioSet set : ScenarioSet.getScenarioSets() ) { + for ( ScenarioSet set : ScenarioSet.getDefaultScenarioSets() ) { // TODO JRadioButtonMenuItem rb = new JRadioButtonMenuItem(set.toString()); scenario_bg.add(rb); scenario_menu.add(rb); diff --git a/src/com/mostc/pftt/util/HostEnvUtil.java b/src/com/mostc/pftt/util/HostEnvUtil.java index 3350657..8fc695c 100644 --- a/src/com/mostc/pftt/util/HostEnvUtil.java +++ b/src/com/mostc/pftt/util/HostEnvUtil.java @@ -2,6 +2,7 @@ package com.mostc.pftt.util; import com.mostc.pftt.host.ExecOutput; import com.mostc.pftt.host.Host; +import com.mostc.pftt.host.LocalHost; import com.mostc.pftt.telemetry.ConsoleManager; /** Utilities for setting up the test environment and convenience settings on Hosts @@ -54,20 +55,34 @@ public final class HostEnvUtil { cm.println("HostEnvUtil", "disabling Windows Firewall..."); // LATER edit firewall rules instead (what if on public network, ex: Azure) - host.execElevated("netsh firewall set opmode disable", Host.ONE_MINUTE); - - - cm.println("HostEnvUtil", "creating File Share for "+host.getPhpSdkDir()+"..."); - // share PHP-SDK over network. this also will share C$, G$, etc... - host.execElevated("NET SHARE PHP_SDK="+host.getPhpSdkDir()+" /Grant:"+host.getUsername()+",Full", Host.ONE_MINUTE); + host.execElevated("netsh firewall set opmode disable", Host.ONE_MINUTE); + + + cm.println("HostEnvUtil", "creating File Share for "+host.getPhpSdkDir()+"..."); + // share PHP-SDK over network. this also will share C$, G$, etc... + host.execElevated("NET SHARE PHP_SDK="+host.getPhpSdkDir()+" /Grant:"+host.getUsername()+",Full", Host.ONE_MINUTE); } - - - if (host.isVistaOrBefore()) { + + if (host.isVistaOrBefore()) { // install VC9 runtime (win7+ don't need this) - // TODO - } - cm.println("HostEnvUtil", "Windows host prepared to run PHP."); + if (host.dirContainsFragment(host.getSystemRoot()+"\\WinSxS", "vc9")) { + cm.println("HostEnvUtil", "VC9 Runtime alread installed"); + } else { + String local_file = LocalHost.getLocalPfttDir()+"/bin/vc9_vcredist_x86.exe"; + String remote_file = null; + if (host.isRemote()) { + remote_file = host.mktempname("HostEnvUtil", ".exe"); + + cm.println("HostEnvUtil", "Uploading VC9 Runtime"); + host.upload(local_file, remote_file); + } + cm.println("HostEnvUtil", "Installing VC9 Runtime"); + host.execElevated(remote_file+" /Q", Host.NO_TIMEOUT); + if (remote_file!=null) + host.delete(remote_file); + } + } + cm.println("HostEnvUtil", "Windows host prepared to run PHP."); } // end public static void prepareWindows public static final String REG_DWORD = "REG_DWORD";