com pftt2: @dataProvider and @depends support for phpunit: conf/app/drupal.groovy conf/app/joomla.groovy conf/app/mediawiki.groovy
conf/app/phpbb3.groovy conf/app/phpmyadmin.groovy conf/app/sema ntic_mediawiki.groovy conf/app/wordpress.groovy conf/ symfony.groovy
conf/task/test_pack3.groovy src/com/ mostc/pftt/host/AbstractRemoteTestPackRunner.java src/com/m ostc/pftt/host/CommonCommandManager.java
src/com/mostc/pftt /host/LocalHost.java src/com/mostc

From: Date: Tue, 30 Jul 2013 21:57:19 +0000
Subject: com pftt2: @dataProvider and @depends support for phpunit: conf/app/drupal.groovy conf/app/joomla.groovy conf/app/mediawiki.groovy
conf/app/phpbb3.groovy conf/app/phpmyadmin.groovy conf/app/sema ntic_mediawiki.groovy conf/app/wordpress.groovy conf/ symfony.groovy
conf/task/test_pack3.groovy src/com/ mostc/pftt/host/AbstractRemoteTestPackRunner.java src/com/m ostc/pftt/host/CommonCommandManager.java
src/com/mostc/pftt /host/LocalHost.java src/com/mostc
Groups: php.qa 
Request: Send a blank email to php-qa+get-68369@lists.php.net to get a copy of this message
Commit: eda35d3902c6264f82e1c7ae94e1544e09043637 Author: Matt Ficken <v-mafick@microsoft.com> Tue, 30 Jul 2013 14:57:19 -0700 Parents: 6c576a7ca8983d969ef1caf1de61011549a70638 Branches: master Link: http://git.php.net/?p=pftt2.git;a=commitdiff;h=eda35d3902c6264f82e1c7ae94e1544e09043637 Log: @dataProvider and @depends support for phpunit Former-commit-id: 51143a2b59a519be36d3c514ee24f95731a4ace8 Changed paths: M conf/app/drupal.groovy M conf/app/joomla..groovy M conf/app/mediawiki.groovy M conf/app/phpbb3.groovy M conf/app/phpmyadmin.groovy M conf/app/semantic_mediawiki.groovy M conf/app/wordpress.groovy M conf/symfony.groovy A conf/task/test_pack3.groovy M src/com/mostc/pftt/host/AbstractRemoteTestPackRunner.java M src/com/mostc/pftt/host/CommonCommandManager.java M src/com/mostc/pftt/host/LocalHost.java M src/com/mostc/pftt/host/PSCAgentServer.java M src/com/mostc/pftt/main/PfttMain.java M src/com/mostc/pftt/model/SourceTestPack.java M src/com/mostc/pftt/model/app/DatabasePhpUnitSourceTestPack.java A src/com/mostc/pftt/model/app/OptionalDatabasePhpUnitSourceTestPack.java M src/com/mostc/pftt/model/app/PhpUnitSourceTestPack.java M src/com/mostc/pftt/model/app/PhpUnitTemplate.groovy M src/com/mostc/pftt/model/app/PhpUnitTestCase.java A src/com/mostc/pftt/model/app/RequiredDatabasePhpUnitSourceTestPack.java M src/com/mostc/pftt/model/core/PhpParser.java M src/com/mostc/pftt/model/core/PhptSourceTestPack.java M src/com/mostc/pftt/model/sapi/ApacheManager.java M src/com/mostc/pftt/model/sapi/BuiltinWebServerManager.java M src/com/mostc/pftt/model/sapi/IISManager.java M src/com/mostc/pftt/model/sapi/WebServerManager.java M src/com/mostc/pftt/results/PhpResultPackReader.java M src/com/mostc/pftt/results/PhptResultReader.java M src/com/mostc/pftt/runner/AbstractPhpUnitTestCaseRunner.java M src/com/mostc/pftt/runner/AbstractPhptTestCaseRunner2.java M src/com/mostc/pftt/runner/CliPhptTestCaseRunner.java M src/com/mostc/pftt/runner/HttpPhptTestCaseRunner.java M src/com/mostc/pftt/runner/LocalPhpUnitTestPackRunner.java M src/com/mostc/pftt/runner/LocalPhptTestPackRunner.java M src/com/mostc/pftt/scenario/ApacheScenario.java M src/com/mostc/pftt/scenario/BuiltinWebServerScenario.java M src/com/mostc/pftt/scenario/CLIScenario.java M src/com/mostc/pftt/scenario/EnchantScenario.java M src/com/mostc/pftt/scenario/IISScenario.java M src/com/mostc/pftt/scenario/RemoteFileSystemScenario.java M src/com/mostc/pftt/scenario/SAPIScenario.java M src/com/mostc/pftt/scenario/Scenario.java M src/com/mostc/pftt/scenario/UserCacheScenario.java M src/com/mostc/pftt/scenario/WebServerScenario.java M src/com/mostc/pftt/util/ValgrindMemoryCheckManager.java

diff --git a/conf/app/drupal.groovy b/conf/app/drupal.groovy index be0fc27..92368d6 100644 --- a/conf/app/drupal.groovy +++ b/conf/app/drupal.groovy @@ -11,7 +11,7 @@ def scenarios() { /** see drupal.patch.txt for patch to drupal required to make this work * */ -class DrupalPhpUnitTestPack extends PhpUnitSourceTestPack { +class DrupalPhpUnitTestPack extends RequiredDatabasePhpUnitSourceTestPack { @Override public String getNameAndVersionString() { diff --git a/conf/app/joomla.groovy b/conf/app/joomla.groovy index f1d382c..55fe851 100644 --- a/conf/app/joomla.groovy +++ b/conf/app/joomla.groovy @@ -18,7 +18,7 @@ def getUITestPack() { * */ -class JoomlaPlatformPhpUnitTestPack extends PhpUnitSourceTestPack { +class JoomlaPlatformPhpUnitTestPack extends OptionalDatabasePhpUnitSourceTestPack { @Override public String getNameAndVersionString() { @@ -55,6 +55,7 @@ require_once '$root/tests/suites/unit/joomla/application/stubs/JApplicationWebIn @Override public String[][] getNonThreadSafeTestFileNames() { return [ + ["joomla/archive/"], ["joomla/filesystem/"], ["joomla/language/"], ["joomla/cache/"], diff --git a/conf/app/mediawiki.groovy b/conf/app/mediawiki.groovy index 9873512..1c61845 100644 --- a/conf/app/mediawiki.groovy +++ b/conf/app/mediawiki.groovy @@ -8,7 +8,7 @@ def scenarios() { } // MediaWiki PhpUnit Code Coverage: https://integration.wikimedia.org/cover/mediawiki-core/master/php/ -class MediaWikiPhpUnitTestPack extends DatabasePhpUnitSourceTestPack { +class MediaWikiPhpUnitTestPack extends RequiredDatabasePhpUnitSourceTestPack { @Override public String getNameAndVersionString() { diff --git a/conf/app/phpbb3.groovy b/conf/app/phpbb3.groovy index 6c582cb..949f557 100644 --- a/conf/app/phpbb3.groovy +++ b/conf/app/phpbb3.groovy @@ -14,7 +14,7 @@ def describe() { "Load PhpBB3 application" } -class PhpBB3PhpUnitTestPack extends PhpUnitSourceTestPack { +class PhpBB3PhpUnitTestPack extends RequiredDatabasePhpUnitSourceTestPack { @Override public String getNameAndVersionString() { diff --git a/conf/app/phpmyadmin.groovy b/conf/app/phpmyadmin.groovy index de45c6f..2750e61 100644 --- a/conf/app/phpmyadmin.groovy +++ b/conf/app/phpmyadmin.groovy @@ -7,7 +7,7 @@ def describe() { "Load PhpMyAdmin application" } -class PhpMyAdminPhpUnitTestPack extends PhpUnitSourceTestPack { +class PhpMyAdminPhpUnitTestPack extends RequiredDatabasePhpUnitSourceTestPack { @Override public String getNameAndVersionString() { diff --git a/conf/app/semantic_mediawiki.groovy b/conf/app/semantic_mediawiki.groovy index 413b3e2..277f838 100644 --- a/conf/app/semantic_mediawiki.groovy +++ b/conf/app/semantic_mediawiki.groovy @@ -11,7 +11,7 @@ def getUITestPack() { return null; // TODO } -class SemanticMediaWikiPhpUnitTestPack extends DatabasePhpUnitSourceTestPack { +class SemanticMediaWikiPhpUnitTestPack extends RequiredDatabasePhpUnitSourceTestPack { @Override public String getNameAndVersionString() { diff --git a/conf/app/wordpress.groovy b/conf/app/wordpress.groovy index 7fda3b9..6b0f969 100644 --- a/conf/app/wordpress.groovy +++ b/conf/app/wordpress.groovy @@ -15,7 +15,7 @@ def getUITestPack() { /** see wordpress-tests.patch.txt for patch to wordpress-tests required to make this work * */ -class WordpressPhpUnitTestPack extends DatabasePhpUnitSourceTestPack { +class WordpressPhpUnitTestPack extends RequiredDatabasePhpUnitSourceTestPack { @Override public String getNameAndVersionString() { diff --git a/conf/symfony.groovy b/conf/symfony.groovy index 5320694..fb80097 100644 --- a/conf/symfony.groovy +++ b/conf/symfony.groovy @@ -12,7 +12,7 @@ def describe() { */ // use symfony-standard instead of just symfony // seems that composer.json from symfony-standard installs a bunch of extra modules that composer.json from symfony does not -class SymfonyPhpUnitTestPack extends PhpUnitSourceTestPack { +class SymfonyPhpUnitTestPack extends OptionalDatabasePhpUnitSourceTestPack { @Override public String getNameAndVersionString() { @@ -41,6 +41,8 @@ class SymfonyPhpUnitTestPack extends PhpUnitSourceTestPack { protected boolean openAfterInstall(ConsoleManager cm, AHost host) throws Exception { // 1. do initial install (if not done already) if (!host.exists(getRoot()+"/vendor")) { + // TODO modified require_once __DIR__ in C:\php-sdk\PFTT\current\cache\working\symfony-standard\vendor\symfony\symfony\vendor\symfony\symfony\autoload.php.dist + // -fixes ~100 (or less) TEST_EXCEPTIONs if (host.isWindows()) { // composer needs git host.exec(host.getPfttDir()+"\\cache\\dep\\git.exe /VERYSILENT /SP-", AHost.ONE_MINUTE*4) diff --git a/conf/task/test_pack3.groovy b/conf/task/test_pack3.groovy new file mode 100644 index 0000000..13442de --- /dev/null +++ b/conf/task/test_pack3.groovy @@ -0,0 +1,9 @@ + +def describe() { + "run test-pack 3 times" +} + +def processConsoleOptions(List options) { + options.add("-run_test_pack") + options.add("3") +} diff --git a/src/com/mostc/pftt/host/AbstractRemoteTestPackRunner.java b/src/com/mostc/pftt/host/AbstractRemoteTestPackRunner.java index dccb44a..395ed97 100644 --- a/src/com/mostc/pftt/host/AbstractRemoteTestPackRunner.java +++ b/src/com/mostc/pftt/host/AbstractRemoteTestPackRunner.java @@ -163,7 +163,7 @@ public abstract class AbstractRemoteTestPackRunner<A extends ActiveTestPack, S e @Override public void runTestList(S test_pack, List<T> test_cases) throws Exception { - A active_test_pack = test_pack.installNamed(this.storage_host, remote_host.getPhpSdkDir()+"/Remote", test_cases); + A active_test_pack = test_pack.installNamed(null, this.storage_host, remote_host.getPhpSdkDir()+"/Remote", test_cases); commonRunStart(); sendTestPack(active_test_pack); diff --git a/src/com/mostc/pftt/host/CommonCommandManager.java b/src/com/mostc/pftt/host/CommonCommandManager.java index d94c475..1c191b8 100644 --- a/src/com/mostc/pftt/host/CommonCommandManager.java +++ b/src/com/mostc/pftt/host/CommonCommandManager.java @@ -5,11 +5,11 @@ import java.util.concurrent.TimeUnit; import java.util.concurrent.locks.ReentrantLock; public class CommonCommandManager { - protected SoftReference<String[]> wer_fault_query; - protected final ReentrantLock wer_fault_query_lock, win_close_all_handles_lock, win_kill_process_lock; + protected SoftReference<String[]> process_table_query; + protected final ReentrantLock process_table_query_lock, win_close_all_handles_lock, win_kill_process_lock; public CommonCommandManager() { - wer_fault_query_lock = new ReentrantLock(); + process_table_query_lock = new ReentrantLock(); win_close_all_handles_lock = new ReentrantLock(); win_kill_process_lock = new ReentrantLock(); } @@ -95,27 +95,19 @@ public class CommonCommandManager { } } - /** finds and kills any WERFault.exe processes (WER popup message) created for given process. - * - * this method will only launch one WMIC query process at a time per Localhost instance. this added complexity (complexity - * entirely handled internally by this method) is needed to avoid a WMIC process-storm if this method is called many times (30+) - * in quick succession. - * - * @param host - * @param process_id - */ - public boolean ensureWERFaultIsNotRunning(AHost host, int process_id) { + + protected String[] getWindowsProcessTable(AHost host) { // lock if no other thread is waiting - final boolean no_other_thread_is_waiting = wer_fault_query_lock.tryLock(); + final boolean no_other_thread_is_waiting = process_table_query_lock.tryLock(); if (!no_other_thread_is_waiting) // wait and lock until other thread is done - wer_fault_query_lock.lock(); + process_table_query_lock.lock(); String[] lines = null; - if (wer_fault_query!=null) - lines = wer_fault_query.get(); + if (process_table_query!=null) + lines = process_table_query.get(); if (lines==null||no_other_thread_is_waiting) { // only query again if: @@ -129,9 +121,24 @@ public class CommonCommandManager { } catch ( Exception ex ) { } - wer_fault_query = new SoftReference<String[]>(lines); + process_table_query = new SoftReference<String[]>(lines); } - wer_fault_query_lock.unlock(); + process_table_query_lock.unlock(); + + return lines; + } + + /** finds and kills any WERFault.exe processes (WER popup message) created for given process. + * + * this method will only launch one WMIC query process at a time per Localhost instance. this added complexity (complexity + * entirely handled internally by this method) is needed to avoid a WMIC process-storm if this method is called many times (30+) + * in quick succession. + * + * @param host + * @param process_id + */ + public boolean ensureWERFaultIsNotRunning(AHost host, int process_id) { + String[] lines = getWindowsProcessTable(host); if (lines==null) return false; // just in case @@ -154,6 +161,34 @@ public class CommonCommandManager { return false; } + public boolean ensureWinDebugIsNotRunning(LocalHost host, int pid) { + // look for `windbg [other args] -p <process id> [other args]` + String[] lines = getWindowsProcessTable(host); + + if (lines==null) + return false; // just in case + + String prev_line = ""; + for ( String line : lines ) { + line = line.toLowerCase(); + // @see WinDebugManager for command line args + if (line.contains("windbg.exe") && line.contains("-p "+pid)) { + + // get PID of windbg process to kill + int blocking_process_id = Integer.parseInt(prev_line.trim()); + + // kill it + winKillProcess(host, "windbg.exe", blocking_process_id); + + // now target process (pid) should be able to terminate + // (should terminate immediately after windbg killed actually) + return true; + } + prev_line = line; + } + return false; + } + public boolean move(AHost host, String src, String dst, boolean elevated) throws Exception { if (!host.isSafePath(dst)) return false; @@ -162,9 +197,9 @@ public class CommonCommandManager { dst = AHost.toWindowsPath(dst); if (elevated) - host.cmdElevated("move \""+src+"\" \""+dst+"\"", AHost.NO_TIMEOUT); + host.cmdElevated("move /Y \""+src+"\" \""+dst+"\"", AHost.NO_TIMEOUT); else - host.cmd("move \""+src+"\" \""+dst+"\"", AHost.NO_TIMEOUT); + host.cmd("move /Y \""+src+"\" \""+dst+"\"", AHost.NO_TIMEOUT); } else { src = AHost.toUnixPath(src); dst = AHost.toUnixPath(dst); diff --git a/src/com/mostc/pftt/host/LocalHost.java b/src/com/mostc/pftt/host/LocalHost.java index 8fe756b..2ce8ad8 100644 --- a/src/com/mostc/pftt/host/LocalHost.java +++ b/src/com/mostc/pftt/host/LocalHost.java @@ -40,6 +40,7 @@ import com.github.mattficken.io.IOUtil; import com.github.mattficken.io.MultiCharsetByLineReader; import com.github.mattficken.io.NoCharsetByLineReader; import com.github.mattficken.io.StringUtil; +import com.mostc.pftt.main.PfttMain; import com.mostc.pftt.model.core.PhptTestCase; import com.mostc.pftt.results.ConsoleManager; import com.mostc.pftt.results.EPrintType; @@ -413,6 +414,14 @@ public class LocalHost extends AHost { // WER just killed, try again wprocess.kill(); } + // can kill off windebug if running under PUTS (windebug shouldn't be running at all, sometimes does) + if (!PfttMain.is_puts && ccm.ensureWinDebugIsNotRunning(LocalHost.this, pid)) { + // process should terminate on its own, so don't call #kill here + // (it may kill a different process that has been allocated the same PID) + // + // instead, wait for loop to reach #winKillProcess because that'll check by image name and PID + // to ensure process is terminated + } } } if (force&&tries==1||tries>3) { @@ -868,7 +877,9 @@ public class LocalHost extends AHost { } } // end try } - + if (process==null) + return new LocalExecHandle(process, null, null, null, null); + OutputStream stdin = process.getOutputStream(); if (stdin_data!=null && stdin_data.length>0) { diff --git a/src/com/mostc/pftt/host/PSCAgentServer.java b/src/com/mostc/pftt/host/PSCAgentServer.java index 5c1e4c6..4e39122 100644 --- a/src/com/mostc/pftt/host/PSCAgentServer.java +++ b/src/com/mostc/pftt/host/PSCAgentServer.java @@ -22,6 +22,7 @@ import com.mostc.pftt.model.core.EPhptTestStatus; import com.mostc.pftt.model.core.PhpBuild; import com.mostc.pftt.model.core.PhpDebugPack; import com.mostc.pftt.model.core.PhptActiveTestPack; +import com.mostc.pftt.model.core.PhptSourceTestPack; import com.mostc.pftt.model.core.PhptTestCase; import com.mostc.pftt.model.ui.UITestPack; import com.mostc.pftt.results.ConsoleManager; @@ -179,7 +180,7 @@ public abstract class PSCAgentServer implements ConsoleManager, ITestResultRecei } @Override - public void notifyStart(AHost this_host, ScenarioSetSetup this_scenario_set, PhptTestCase test_case) { + public void notifyStart(AHost this_host, ScenarioSetSetup this_scenario_set, PhptSourceTestPack src_test_pack, PhptTestCase test_case) { // TODO Auto-generated method stub } @@ -194,7 +195,7 @@ public abstract class PSCAgentServer implements ConsoleManager, ITestResultRecei } @Override - public void addResult(AHost this_host, ScenarioSetSetup this_scenario_set, PhptTestResult result) { + public void addResult(AHost this_host, ScenarioSetSetup this_scenario_set, PhptSourceTestPack src_test_pack, PhptTestResult result) { try { sendResult(result); } catch ( Exception ex ) { @@ -232,11 +233,6 @@ public abstract class PSCAgentServer implements ConsoleManager, ITestResultRecei } // end protected void sendResult @Override - public void setTotalCount(int size) { - sendMessage("<totalCount>"+size+"</totalCount>"); - } - - @Override public void restartingAndRetryingTest(TestCase test_case) { restartingAndRetryingTest(test_case.getName()); } @@ -512,15 +508,15 @@ public abstract class PSCAgentServer implements ConsoleManager, ITestResultRecei this.serial.setOutput(this.serial_out, "utf-8"); System.setOut(ps); - addResult(host, scenario_set, new PhptTestResult(host, EPhptTestStatus.PASS, null, "", null, null, null, null, null, null, null, null, null, null, null)); - addResult(host, scenario_set, new PhptTestResult(host, EPhptTestStatus.PASS, null, "", null, null, null, null, null, null, null, null, null, null, null)); + addResult(host, scenario_set, null, new PhptTestResult(host, EPhptTestStatus.PASS, null, "", null, null, null, null, null, null, null, null, null, null, null)); + addResult(host, scenario_set, null, new PhptTestResult(host, EPhptTestStatus.PASS, null, "", null, null, null, null, null, null, null, null, null, null, null)); restartingAndRetryingTest("ext/standard/strings/strpos.phpt"); - addResult(host, scenario_set, new PhptTestResult(host, EPhptTestStatus.PASS, null, "", null, null, null, null, null, null, null, null, null, null, null)); - addResult(host, scenario_set, new PhptTestResult(host, EPhptTestStatus.SKIP, null, "", null, null, null, null, null, null, null, null, null, null, null)); - addResult(host, scenario_set, new PhptTestResult(host, EPhptTestStatus.PASS, null, "", null, null, null, null, null, null, null, null, null, null, null)); + addResult(host, scenario_set, null, new PhptTestResult(host, EPhptTestStatus.PASS, null, "", null, null, null, null, null, null, null, null, null, null, null)); + addResult(host, scenario_set, null, new PhptTestResult(host, EPhptTestStatus.SKIP, null, "", null, null, null, null, null, null, null, null, null, null, null)); + addResult(host, scenario_set, null, new PhptTestResult(host, EPhptTestStatus.PASS, null, "", null, null, null, null, null, null, null, null, null, null, null)); println(EPrintType.CLUE, "setup", "setup finished"); - addResult(host, scenario_set, new PhptTestResult(host, EPhptTestStatus.PASS, null, "", null, null, null, null, null, null, null, null, null, null, null)); - addResult(host, scenario_set, new PhptTestResult(host, EPhptTestStatus.PASS, null, "", null, null, null, null, null, null, null, null, null, null, null)); + addResult(host, scenario_set, null, new PhptTestResult(host, EPhptTestStatus.PASS, null, "", null, null, null, null, null, null, null, null, null, null, null)); + addResult(host, scenario_set, null, new PhptTestResult(host, EPhptTestStatus.PASS, null, "", null, null, null, null, null, null, null, null, null, null, null)); // flush(); diff --git a/src/com/mostc/pftt/main/PfttMain.java b/src/com/mostc/pftt/main/PfttMain.java index 1059694..820168f 100644 --- a/src/com/mostc/pftt/main/PfttMain.java +++ b/src/com/mostc/pftt/main/PfttMain.java @@ -26,6 +26,7 @@ import com.mostc.pftt.host.ExecOutput; import com.mostc.pftt.host.Host; import com.mostc.pftt.host.LocalHost; import com.mostc.pftt.model.app.PhpUnitSourceTestPack; +import com.mostc.pftt.model.app.PhpUnitTestCase; import com.mostc.pftt.model.core.EBuildBranch; import com.mostc.pftt.model.core.EBuildType; import com.mostc.pftt.model.core.ECPUArch; @@ -296,6 +297,7 @@ import com.mostc.pftt.util.WindowsSnapshotDownloadUtil.FindBuildTestPackPair; // (after ported to windows) drizzle weakref fpdf gnupg xdebug? suhosin?? public class PfttMain { + public static boolean is_puts = false; // TODO protected final LocalHost host; protected LocalConsoleManager cm; protected final HashMap<PhpBuild,PhpResultPackWriter> writer_map; @@ -539,11 +541,21 @@ public class PfttMain { cm.println(EPrintType.TIP, PfttMain.class, "Add test-pack configuration file to -c console option. For example `aa -c symfony`"); return; } + for ( int i=0 ; i < cm.getRunTestPack() ; i++ ) { for ( PhpUnitSourceTestPack test_pack : test_packs ) { cm.println(EPrintType.CLUE, PfttMain.class, "Test-Pack: "+test_pack); cm.println(EPrintType.CLUE, PfttMain.class, "Writing Result-Pack: "+tmgr.getResultPackPath()); + LinkedList<PhpUnitTestCase> test_cases = new LinkedList<PhpUnitTestCase>(); + + test_pack.cleanup(cm); + cm.println(EPrintType.IN_PROGRESS, "PhpUnitSourceTestPack", "enumerating test cases from test-pack..."); + test_pack.installNamed(cm, host, "", test_cases); + test_pack.read(config, test_cases, test_names, tmgr.getConsoleManager(), tmgr, build, true); + cm.println(EPrintType.IN_PROGRESS, "PhpUnitSourceTestPack", "enumerated test cases."); + + for ( ScenarioSet scenario_set : getScenarioSets(config, EScenarioSetPermutationLayer.WEB_APPLICATION)) { List<AHost> hosts = config.getHosts(); @@ -551,9 +563,7 @@ public class PfttMain { LocalPhpUnitTestPackRunner r = new LocalPhpUnitTestPackRunner(cm, tmgr, scenario_set, build, host, host); cm.showGUI(r, test_pack); - // TODO implement app_list - //test_pack.read(test_cases, cm, tmgr, build); - //r.runTestList(test_pack, test_cases); + r.runTestList(test_pack, test_cases); tmgr.notifyPhpUnitFinished(host, r.getScenarioSetSetup(), test_pack); @@ -635,7 +645,7 @@ public class PfttMain { test_pack_runner.runAllTests(config, test_pack); - tmgr.notifyPhptFinished(host, test_pack_runner.getScenarioSetSetup()); + tmgr.notifyPhptFinished(host, test_pack_runner.getScenarioSetSetup(), test_pack); } // @@ -700,7 +710,7 @@ public class PfttMain { test_pack_runner.runTestList(test_pack, test_cases); - tmgr.notifyPhptFinished(host, test_pack_runner.getScenarioSetSetup()); + tmgr.notifyPhptFinished(host, test_pack_runner.getScenarioSetSetup(), test_pack); } // diff --git a/src/com/mostc/pftt/model/SourceTestPack.java b/src/com/mostc/pftt/model/SourceTestPack.java index a8221c4..6c94f80 100644 --- a/src/com/mostc/pftt/model/SourceTestPack.java +++ b/src/com/mostc/pftt/model/SourceTestPack.java @@ -8,12 +8,15 @@ import com.mostc.pftt.host.AHost; import com.mostc.pftt.main.Config; import com.mostc.pftt.model.core.EBuildBranch; import com.mostc.pftt.model.core.PhpBuild; +import com.mostc.pftt.model.core.PhptTestCase; import com.mostc.pftt.results.ConsoleManager; import com.mostc.pftt.results.ITestResultReceiver; +import com.mostc.pftt.results.PhpResultPackWriter; public interface SourceTestPack<A extends ActiveTestPack, T extends TestCase> { void cleanup(ConsoleManager cm); String getSourceDirectory(); + String getNameAndVersionString(); /** may be called more than once. if tests have been added to test-pack * since last read should add only those new tests, otherwise subsequent reads should be ignored * @@ -28,8 +31,23 @@ public interface SourceTestPack<A extends ActiveTestPack, T extends TestCase> { * @throws Exception */ void read(Config config, List<T> test_cases, ConsoleManager cm, ITestResultReceiver twriter, PhpBuild build) throws FileNotFoundException, IOException, Exception; + /** only reads tests with names matching the given name fragments + * + * @param config + * @param test_cases + * @param names - fragments of names to read + * @param cm + * @param twriter + * @param build + * @param ignore_missing + * @throws FileNotFoundException + * @throws IOException + * @throws Exception + */ + void read(Config config, List<T> test_cases, List<String> names, ConsoleManager cm, PhpResultPackWriter twriter, PhpBuild build, boolean ignore_missing) throws FileNotFoundException, IOException, Exception; + void read(Config config, List<T> test_cases, List<String> names, ConsoleManager cm, PhpResultPackWriter twriter, PhpBuild build) throws FileNotFoundException, IOException, Exception; A installInPlace(ConsoleManager cm, AHost host) throws IOException, Exception; - A installNamed(AHost host, String string, List<T> test_cases) throws IllegalStateException, IOException, Exception; + A installNamed(ConsoleManager cm, AHost host, String string, List<T> test_cases) throws IllegalStateException, IOException, Exception; A install(ConsoleManager cm, AHost host, String local_test_pack_dir, String remote_test_pack_dir) throws IllegalStateException, IOException, Exception; EBuildBranch getTestPackBranch(); String getTestPackVersionRevision(); diff --git a/src/com/mostc/pftt/model/app/DatabasePhpUnitSourceTestPack.java b/src/com/mostc/pftt/model/app/DatabasePhpUnitSourceTestPack.java index d92e125..7ed84df 100644 --- a/src/com/mostc/pftt/model/app/DatabasePhpUnitSourceTestPack.java +++ b/src/com/mostc/pftt/model/app/DatabasePhpUnitSourceTestPack.java @@ -12,23 +12,28 @@ import com.mostc.pftt.scenario.ScenarioSet; public abstract class DatabasePhpUnitSourceTestPack extends PhpUnitSourceTestPack { protected DatabaseScenarioSetup database; + DatabasePhpUnitSourceTestPack() { + // make sure this can only be subclassed within this package + } + @Overridable protected DatabaseScenario getDatabaseScenario(AHost runner_host, ScenarioSet scenario_set, PhpBuild build) { return scenario_set.getScenario(DatabaseScenario.class); } + protected abstract boolean handleNoDatabaseScenario(ConsoleManager cm); + @Override public boolean startRun(ConsoleManager cm, AHost runner_host, ScenarioSet scenario_set, PhpBuild build) { DatabaseScenario ds = getDatabaseScenario(runner_host, scenario_set, build); if (ds==null) { - cm.println(EPrintType.CANT_CONTINUE, getClass(), "No database scenario found. Try adding `local_mysql` or other scenario to your -config."); - return false; + return handleNoDatabaseScenario(cm); } database = ds.setup(cm, runner_host, build, scenario_set); if (database==null) { cm.println(EPrintType.CANT_CONTINUE, getClass(), "Could not setup database scenario"); - return false; + return handleNoDatabaseScenario(cm); } configureDatabaseServer(); return true; diff --git a/src/com/mostc/pftt/model/app/OptionalDatabasePhpUnitSourceTestPack.java b/src/com/mostc/pftt/model/app/OptionalDatabasePhpUnitSourceTestPack.java new file mode 100644 index 0000000..d8c2a76 --- /dev/null +++ b/src/com/mostc/pftt/model/app/OptionalDatabasePhpUnitSourceTestPack.java @@ -0,0 +1,13 @@ +package com.mostc.pftt.model.app; + +import com.mostc.pftt.results.ConsoleManager; +import com.mostc.pftt.results.EPrintType; + +public abstract class OptionalDatabasePhpUnitSourceTestPack extends DatabasePhpUnitSourceTestPack { + + protected boolean handleNoDatabaseScenario(ConsoleManager cm) { + cm.println(EPrintType.TIP, getClass(), "Try adding `local_mysql` or other scenario to your -config to run database tests."); + return true; // false will stop the test run + } + +} diff --git a/src/com/mostc/pftt/model/app/PhpUnitSourceTestPack.java b/src/com/mostc/pftt/model/app/PhpUnitSourceTestPack.java index 87c9d0b..b9930cc 100644 --- a/src/com/mostc/pftt/model/app/PhpUnitSourceTestPack.java +++ b/src/com/mostc/pftt/model/app/PhpUnitSourceTestPack.java @@ -13,6 +13,7 @@ import java.util.Map; import javax.annotation.Nullable; import com.github.mattficken.Overridable; +import com.github.mattficken.io.StringUtil; import com.mostc.pftt.host.AHost; import com.mostc.pftt.host.Host; import com.mostc.pftt.host.LocalHost; @@ -27,6 +28,7 @@ import com.mostc.pftt.model.core.PhpParser.FunctionDefinition; import com.mostc.pftt.model.core.PhpParser.PhpScript; import com.mostc.pftt.results.ConsoleManager; import com.mostc.pftt.results.ITestResultReceiver; +import com.mostc.pftt.results.PhpResultPackWriter; import com.mostc.pftt.scenario.ScenarioSet; /** Represents a pack of PhpUnitTestCases and the configuration information needed to run them. @@ -50,6 +52,9 @@ import com.mostc.pftt.scenario.ScenarioSet; * NOTE: what `phpunit` calls 'preamble' code, is post-bootstrap in PFTT. * 8. optionally, add globals to #prepareGlobals. optionally, add INI directives to #prepareINI * + * If your test-pack MUST be run with a database scenario (ex: mysql), you should extend RequiredDatabasePhpUnitSourceTestPack instead (it'll take care of making sure a database scenario is included in the configuration). + * If your test-pack has some database tests that can be run, you should extend OptionalDatabasePhpUnitSourceTestPack. + * * While your test-pack is in development, you should override #isDevelopment and have it return true. You'll get more stack traces and other * information to help during the develop-test cycle you'll be in developing your test-pack. * @@ -187,6 +192,16 @@ public abstract class PhpUnitSourceTestPack implements SourceTestPack<PhpUnitAct return this; } + @Override + public void read(Config config, List<PhpUnitTestCase> test_cases, List<String> names, ConsoleManager cm, PhpResultPackWriter twriter, PhpBuild build) throws FileNotFoundException, IOException, Exception { + read(config, test_cases, names, cm, twriter, build, false); + } + + @Override + public void read(Config config, List<PhpUnitTestCase> test_cases, List<String> names, ConsoleManager cm, PhpResultPackWriter twriter, PhpBuild build, boolean ignore_missing) throws FileNotFoundException, IOException, Exception { + doRead(config, cm, test_cases, names); + } + /** reads all the PhpUnitTestCases from this test-pack * * @param config @@ -209,9 +224,19 @@ public abstract class PhpUnitSourceTestPack implements SourceTestPack<PhpUnitAct } // + doRead(config, cm, test_cases, null); + + // cache for future use + _test_cases = new ArrayList<PhpUnitTestCase>(test_cases.size()); + _test_cases.addAll(test_cases); + _ref_test_cases = new SoftReference<ArrayList<PhpUnitTestCase>>(_test_cases); + // + } + + protected void doRead(Config config, ConsoleManager cm, List<PhpUnitTestCase> test_cases, List<String> test_names) throws IOException { final int max_read_count = cm.getMaxTestReadCount(); for (PhpUnitDist php_unit_dist : php_unit_dists) { - readDir(config, max_read_count, test_cases, php_unit_dist, php_unit_dist.path); + readDir(config, max_read_count, test_cases, php_unit_dist, php_unit_dist.path, test_names); } // alphabetize @@ -221,13 +246,7 @@ public abstract class PhpUnitSourceTestPack implements SourceTestPack<PhpUnitAct return a.getName().compareTo(b.getName()); } }); - - // cache for future use - _test_cases = new ArrayList<PhpUnitTestCase>(test_cases.size()); - _test_cases.addAll(test_cases); - _ref_test_cases = new SoftReference<ArrayList<PhpUnitTestCase>>(_test_cases); - // - } // end public void read + } /** Many test-packs store their phpunit tests only in files that end with `Test.php`, * but some don't. @@ -263,7 +282,7 @@ public abstract class PhpUnitSourceTestPack implements SourceTestPack<PhpUnitAct * @param dir * @throws IOException */ - protected void readDir(Config config, final int max_read_count, List<PhpUnitTestCase> test_cases, PhpUnitDist php_unit_dist, File dir) throws IOException { + protected void readDir(Config config, final int max_read_count, List<PhpUnitTestCase> test_cases, PhpUnitDist php_unit_dist, File dir, List<String> test_names) throws IOException { if (max_read_count > 0 && test_cases.size() >= max_read_count) return; @@ -275,7 +294,7 @@ public abstract class PhpUnitSourceTestPack implements SourceTestPack<PhpUnitAct if (file.isDirectory()) { if (max_read_count > 0 && test_cases.size() >= max_read_count) return; - readDir(config, max_read_count, test_cases, php_unit_dist, file); + readDir(config, max_read_count, test_cases, php_unit_dist, file, test_names); if (max_read_count > 0 && test_cases.size() >= max_read_count) return; } else if (isFileNameATest(file.getName())) { @@ -284,6 +303,17 @@ public abstract class PhpUnitSourceTestPack implements SourceTestPack<PhpUnitAct String abs_file_name = PhpUnitTestCase.normalizeFileName(file.getAbsolutePath()); String lc_test_file_name = rel_file_name.toLowerCase(); + if (test_names!=null) { + boolean skip = true; + for ( String test_name : test_names ) { + if (lc_test_file_name.contains(test_name)) { + skip = false; + break; + } + } + if (skip) + continue; + } if (blacklist_test_names.contains(lc_test_file_name)) continue; else if (!whitelist_test_names.isEmpty() && !whitelist_test_names.contains(lc_test_file_name)) @@ -310,6 +340,7 @@ public abstract class PhpUnitSourceTestPack implements SourceTestPack<PhpUnitAct */ protected void readTestFile(Config config, final int max_read_count, String rel_test_file_name, String abs_test_file_name, PhpUnitDist php_unit_dist, List<PhpUnitTestCase> test_cases, File file) { PhpScript script = PhpParser.parseScript(file); + String dataProviderMethodName, dependsMethodName; for ( ClassDefinition clazz : script.getClasses() ) { if (clazz.isAbstract()||clazz.isInterface()) @@ -319,6 +350,16 @@ public abstract class PhpUnitSourceTestPack implements SourceTestPack<PhpUnitAct // search class for functions that start with 'test' if (isFunctionATest(func.getName())) { // this is a test case + // + // + // some tests use these annotations to provide the name of a function (in same class) + // to call to get the arguments for this test case method + // + // @see http://phpunit.de/manual/3.7/en/appendixes.annotations.html#appendixes.annotations.dataProvider + dataProviderMethodName = cleanFunctionName(func.getAnnotationValue("dataProvider")); + // @see http://phpunit.de/manual/3.7/en/appendixes.annotations.html#appendixes.annotations.depends + dependsMethodName = cleanFunctionName(func.getAnnotationValue("depends")); + PhpUnitTestCase test_case = new PhpUnitTestCase( php_unit_dist, abs_test_file_name, @@ -329,7 +370,9 @@ public abstract class PhpUnitSourceTestPack implements SourceTestPack<PhpUnitAct clazz.getName(), // name of method within the class func.getName(), - func.getArgumentCount() + func.getArgumentCount(), + dataProviderMethodName, + dependsMethodName ); config.processPhpUnit(test_case); test_cases.add(test_case); @@ -340,6 +383,19 @@ public abstract class PhpUnitSourceTestPack implements SourceTestPack<PhpUnitAct } } } // end protected void readTestFile + + protected static String cleanFunctionName(String name) { + if (StringUtil.isEmpty(name)) + return null; + name = name.trim(); + int i = name.indexOf("::"); + if (i!=-1) + name = name.substring(i+"::".length()); + i = name.indexOf('('); + if (i!=-1) + name = name.substring(0, i); + return StringUtil.isEmpty(name) ? null : name; + } @Override public void cleanup(ConsoleManager cm) { @@ -375,11 +431,17 @@ public abstract class PhpUnitSourceTestPack implements SourceTestPack<PhpUnitAct } @Override - public PhpUnitActiveTestPack installNamed(AHost host, String string, - List<PhpUnitTestCase> test_cases) throws IllegalStateException, - IOException, Exception { - // TODO Auto-generated method stub - return null; + public PhpUnitActiveTestPack installNamed(ConsoleManager cm, AHost host, String string, List<PhpUnitTestCase> test_cases) throws IllegalStateException, IOException, Exception { + final String src_root = getSourceRoot(new LocalHost()); + addIncludeDirectory(src_root); + if (!new File(src_root).isDirectory()) { + throw new IOException("source-test-pack not found: "+src_root); + } + setRoot(src_root); + + openAfterInstall(cm, host); + + return new PhpUnitActiveTestPack(src_root, src_root); } @Override diff --git a/src/com/mostc/pftt/model/app/PhpUnitTemplate.groovy b/src/com/mostc/pftt/model/app/PhpUnitTemplate.groovy index 89b7f62..7cc4233 100644 --- a/src/com/mostc/pftt/model/app/PhpUnitTemplate.groovy +++ b/src/com/mostc/pftt/model/app/PhpUnitTemplate.groovy @@ -38,14 +38,6 @@ public class PhpUnitTemplate { } public static String renderTemplate(AHost host, ScenarioSet scenario_set, PhpUnitTestCase test_case, String prebootstrap_code, String bootstrap_file, String postbootstrap_code, String cwd, String include_path, String[] included_files, Map<String, String> globals, Map<String, String> constants, HashMap<String, String> env, String my_temp_dir, boolean reflection_only, boolean strict) { - // XXX will need to get these values from PHP code - // data source: PhpUnit_Framework_TestCase constructor (default value) - String data = "a:0:{}"; - // data source: PhpUnit_Framework_TestCase constructor (default value) - String dataName = ""; - // default value - String dependencyInput = "a:0:{}"; - StringWriter sw = new StringWriter(16384); PrintWriter pw = new PrintWriter(sw); @@ -176,14 +168,36 @@ function __phpunit_run_isolated_test() if (!class_exists('$test_case.className')) { require_once '$test_case.abs_filename'; } - - \$test = new $test_case.className('$test_case.methodName', unserialize('$data'), '$dataName'); - \$test->setDependencyInput(unserialize('$dependencyInput')); - \$test->setInIsolation(TRUE); ob_end_clean(); ob_start(); +"""); + if (test_case.dataProviderMethodName!=null) { + pw.print(""" + \$test = new $test_case.className('$test_case.dataProviderMethodName', array(), ''); + \$test->setInIsolation(TRUE); + \$test->pftt_step1(); + \$data = \$test->$test_case.dataProviderMethodName(); + \$data = array_shift(\$data); +""") + } else if (test_case.dependsMethodName!=null) { + pw.print(""" + \$test = new $test_case.className('$test_case.dependsMethodName', array(), ''); + \$test->setInIsolation(TRUE); + \$test->pftt_step1(); + + \$data = \$test->$test_case.dependsMethodName(); +""") + } else { + pw.print(""" + \$data = array(); +""") + } + pw.print(""" + \$test = new $test_case.className('$test_case.methodName', \$data, ''); + \$test->setInIsolation(TRUE); + """); // if (reflection_only) { @@ -223,7 +237,32 @@ pw.println(""" pw.println("""clearstatcache(); \$test->pftt_step1(); \$start_time = microtime(TRUE); - \$test->$test_case.methodName(); +""") + + // + // if had to call depends or dataProvider method, need to pass the arguments to the test + // method + if (test_case.dependsMethodName!=null||test_case.dataProviderMethodName!=null) { + // could use this PHP Code: + // call_user_func_array(\$test->test_case.methodName, \$data); + // + // but that uses reflection... we know the number of arguments (since we parsed this PHP file already) + // so generate the PHP code to read from each index of the $data array (and to call the test method) + pw.println("\$test->$test_case.methodName(") + for ( int i=0 ; i < test_case.getArgCount() ; i++ ) { + if (i>0) + pw.print(", ") + pw.print("\$data[$i]") + } + pw.println(");"); + // + } else { + // don't have to pass arguments, just call the method + pw.println("\$test->$test_case.methodName();") + } + // + + pw.println(""" \$run_time = microtime(TRUE) - \$start_time; \$test->pftt_step2(); try { diff --git a/src/com/mostc/pftt/model/app/PhpUnitTestCase.java b/src/com/mostc/pftt/model/app/PhpUnitTestCase.java index fccf1b4..e1a6f0a 100644 --- a/src/com/mostc/pftt/model/app/PhpUnitTestCase.java +++ b/src/com/mostc/pftt/model/app/PhpUnitTestCase.java @@ -11,15 +11,13 @@ import com.mostc.pftt.model.TestCase; * */ -// TODO @dataProvider support http://phpunit.de/manual/3.7/en/appendixes.annotations.html#appendixes.annotations.dataProvider -// TODO @depends support http://phpunit.de/manual/3.7/en/appendixes.annotations.html#appendixes.annotations.depends public class PhpUnitTestCase extends TestCase { public static final int MAX_TEST_TIME_SECONDS = 60; protected final PhpUnitDist php_unit_dist; - protected final String abs_filename, rel_filename, className, methodName; + protected final String abs_filename, rel_filename, className, methodName, dependsMethodName, dataProviderMethodName; protected final int arg_count; - protected PhpUnitTestCase(PhpUnitDist php_unit_dist, String abs_filename, String rel_filename, String className, String methodName, int arg_count) { + protected PhpUnitTestCase(PhpUnitDist php_unit_dist, String abs_filename, String rel_filename, String className, String methodName, int arg_count, String dataProviderMethodName, String dependsMethodName) { this.php_unit_dist = php_unit_dist; // don't need to call #normalizeFilename here usually. it's called in PhpUnitSourcetestPack#readDir... // calling it (again )here would be a performance hit @@ -30,6 +28,16 @@ public class PhpUnitTestCase extends TestCase { this.className = className; this.methodName = methodName; this.arg_count = arg_count; + this.dataProviderMethodName = dataProviderMethodName; + this.dependsMethodName = dependsMethodName; + } + + public String getDataProviderMethodName() { + return dataProviderMethodName; + } + + public String getDependsMethodName() { + return dependsMethodName; } public int getArgCount() { diff --git a/src/com/mostc/pftt/model/app/RequiredDatabasePhpUnitSourceTestPack.java b/src/com/mostc/pftt/model/app/RequiredDatabasePhpUnitSourceTestPack.java new file mode 100644 index 0000000..7ada2a3 --- /dev/null +++ b/src/com/mostc/pftt/model/app/RequiredDatabasePhpUnitSourceTestPack.java @@ -0,0 +1,14 @@ +package com.mostc.pftt.model.app; + +import com.mostc.pftt.results.ConsoleManager; +import com.mostc.pftt.results.EPrintType; + +public abstract class RequiredDatabasePhpUnitSourceTestPack extends DatabasePhpUnitSourceTestPack { + + @Override + protected boolean handleNoDatabaseScenario(ConsoleManager cm) { + cm.println(EPrintType.CANT_CONTINUE, getClass(), "No database scenario found. Try adding `local_mysql` or other scenario to your -config."); + return false; // stop test-run + } + +} diff --git a/src/com/mostc/pftt/model/core/PhpParser.java b/src/com/mostc/pftt/model/core/PhpParser.java index 606e4d3..9776bc1 100644 --- a/src/com/mostc/pftt/model/core/PhpParser.java +++ b/src/com/mostc/pftt/model/core/PhpParser.java @@ -2,6 +2,7 @@ package com.mostc.pftt.model.core; import java.io.File; +import java.io.BufferedInputStream; import java.io.FileInputStream; import java.io.IOException; import java.util.ArrayList; @@ -38,6 +39,8 @@ import com.caucho.vfs.FileReadStream; import com.caucho.vfs.NullPath; import com.caucho.vfs.ReadStream; import com.caucho.vfs.StringStream; +import com.github.mattficken.io.IOUtil; +import com.github.mattficken.io.StringUtil; import com.mostc.pftt.results.ISerializer; import com.mostc.pftt.results.TestCaseCodeCoverage; @@ -78,11 +81,12 @@ public class PhpParser { new FilePath(file.getAbsolutePath()), new ReadStream(new FileReadStream(new FileInputStream(file))) ); - return new PhpScript(file, new Env(qctx), p.parse()); + String php_code_str = IOUtil.toString(new BufferedInputStream(new FileInputStream(file)), IOUtil.ONE_MEGABYTE); + return new PhpScript(file, php_code_str, new Env(qctx), p.parse()); } catch ( Exception ex ) { //ex.printStackTrace(); } - return new PhpScript(file, null, null); + return new PhpScript(file, "", null, null); } // end public static PhpScript parseScript /** parses PhpScript from string containing php code @@ -99,11 +103,11 @@ public class PhpParser { filename == null ? new NullPath("<unknown>") : new FilePath(filename), StringStream.open(php_code_str) ); - return new PhpScript(php_code_str, new Env(qctx), p.parse()); + return new PhpScript(php_code_str, php_code_str, new Env(qctx), p.parse()); } catch ( Exception ex ) { //ex.printStackTrace(); } - return new PhpScript(php_code_str, null, null); + return new PhpScript(php_code_str, php_code_str, null, null); } public static PhpScript parseScript(String php_code_str) { @@ -131,10 +135,12 @@ public class PhpParser { public static class PhpScript extends PhpCode { protected final QuercusProgram prog; protected final Object source; + protected final String source_code; - protected PhpScript(Object source, Env env, QuercusProgram prog) { + protected PhpScript(Object source, String source_code, Env env, QuercusProgram prog) { super(env); this.source = source; + this.source_code = source_code; this.prog = prog; } @@ -150,7 +156,7 @@ public class PhpParser { ClassDefinition[] defs = new ClassDefinition[clazzes.size()]; int i=0; for ( InterpretedClassDef clazz : clazzes ) - defs[i++] = new ClassDefinition(env, clazz); + defs[i++] = new ClassDefinition(env, this, clazz); return defs; } } @@ -683,9 +689,11 @@ public class PhpParser { public static class ClassDefinition extends CodeBlock { protected final ClassDef clazz; + protected final PhpScript ps; - protected ClassDefinition(Env env, ClassDef clazz) { + protected ClassDefinition(Env env, PhpScript ps, ClassDef clazz) { super(env); + this.ps = ps; this.clazz = clazz; } @@ -771,6 +779,10 @@ public class PhpParser { public String toString() { return clazz.toString(); } + + public PhpScript getPhpScript() { + return ps; + } } // end public static class ClassDefinition @@ -958,7 +970,7 @@ public class PhpParser { out.add( new UserFunctionCall(env, this, call.getLocation(), // TODO lookup the class this function actually belongs to - new FunctionDefinition(env, new ClassDefinition(env, qc.getClassDef()), f) + new FunctionDefinition(env, new ClassDefinition(env, clazz.ps, qc.getClassDef()), f) )); continue; } @@ -987,6 +999,12 @@ public class PhpParser { public void serial(XmlSerializer serial) throws IllegalArgumentException, IllegalStateException, IOException { serial.startTag("pftt", "function"); serial.attribute("pftt", "name", getName()); + final String ds = getDocstring(); + if (StringUtil.isNotEmpty(ds)) { + serial.startTag("pftt", "docstring"); + serial.text(ds); + serial.endTag("pftt", "docstring"); + } serial.startTag("pftt", "arguments"); for ( VariableValue arg : getArguments() ) arg.serial(serial); @@ -1018,6 +1036,55 @@ public class PhpParser { return getName(); } + /** gets docstring (documentation) for this function + * + */ + public String getDocstring() { + PhpScript ps = clazz.getPhpScript(); + int i = ps.source_code.indexOf("function "+getName()); + if (i==-1) + return null; + i = ps.source_code.lastIndexOf("*/", i); + if (i==-1) + return null; + int j = ps.source_code.lastIndexOf("/*", i); + if (j==-1) + return null; + return ps.source_code.substring(j, i); + } + + /** returns names and values of annotations from docstring + * + * @return + */ + public HashMap<String,String> getAnnotations() { + String docstring = getDocstring(); + if (StringUtil.isEmpty(docstring)) + return new HashMap<String,String>(); + HashMap<String,String> map = new HashMap<String,String>(); + int i, j; + for ( String line : StringUtil.splitLines(docstring) ) { + i = line.indexOf('@'); + if (i==-1) + continue; + j = line.indexOf(' ', i+1); + if (j==-1) + map.put(line.substring(i+1), ""); + else + map.put(line.substring(i+1, j), line.substring(j+1)); + } + return map; + } + + /** returns the value of this annotation or null if annotation does not exist + * + * @param name + * @return + */ + public String getAnnotationValue(String name) { + return getAnnotations().get(name); + } + } // end public static class FunctionDefinition } // end public class PhpParser diff --git a/src/com/mostc/pftt/model/core/PhptSourceTestPack.java b/src/com/mostc/pftt/model/core/PhptSourceTestPack.java index 28804e6..a1c7119 100644 --- a/src/com/mostc/pftt/model/core/PhptSourceTestPack.java +++ b/src/com/mostc/pftt/model/core/PhptSourceTestPack.java @@ -198,11 +198,12 @@ public class PhptSourceTestPack implements SourceTestPack<PhptActiveTestPack, Ph host.deleteFileExtension(test_pack+"/sapi", ".php"); } + @Override public void read(Config config, List<PhptTestCase> test_cases, List<String> names, ConsoleManager cm, PhpResultPackWriter twriter, PhpBuild build) throws FileNotFoundException, IOException, Exception { read(config, test_cases, names, cm, twriter, build, false); } - + @Override public void read(Config config, List<PhptTestCase> test_cases, List<String> names, ConsoleManager cm, PhpResultPackWriter twriter, PhpBuild build, boolean ignore_missing) throws FileNotFoundException, IOException, Exception { // ArrayList<PhptTestCase> _test_cases; @@ -275,7 +276,6 @@ public class PhptSourceTestPack implements SourceTestPack<PhptActiveTestPack, Ph _test_cases.addAll(test_cases); _ref_test_cases = new SoftReference<ArrayList<PhptTestCase>>(_test_cases); // - twriter.setTotalCount(test_cases.size()); } // end public void read @Override @@ -296,15 +296,12 @@ public class PhptSourceTestPack implements SourceTestPack<PhptActiveTestPack, Ph test_pack_file = new File(test_pack); test_pack = test_pack_file.getAbsolutePath(); // normalize path add_test_files(config, test_pack_file.listFiles(), test_cases, null, cm, twriter, build, null, new LinkedList<PhptTestCase>()); - twriter.setTotalCount(test_cases.size()); // // cache for use next time _test_cases = new ArrayList<PhptTestCase>(test_cases.size()); _test_cases.addAll(test_cases); _ref_test_cases = new SoftReference<ArrayList<PhptTestCase>>(_test_cases); - // - twriter.setTotalCount(test_cases.size()); } private void add_test_files(Config config, File[] files, List<PhptTestCase> test_files, List<String> names, ConsoleManager cm, ITestResultReceiver twriter, PhpBuild build, PhptTestCase redirect_parent, List<PhptTestCase> redirect_targets) throws FileNotFoundException, IOException, Exception { @@ -471,17 +468,17 @@ public class PhptSourceTestPack implements SourceTestPack<PhptActiveTestPack, Ph } // end public PhptActiveTestPack install /** installs only the named test cases from test pack into to the given location to actively run it from. - * - * @see #read - must have already been called * @param host - * @param test_pack_dir * @param test_cases + * @param test_pack_dir + * + * @see #read - must have already been called * @return * @throws IllegalStateException * @throws IOException * @throws Exception */ - public PhptActiveTestPack installNamed(AHost host, String test_pack_dir, List<PhptTestCase> test_cases) throws IllegalStateException, IOException, Exception { + public PhptActiveTestPack installNamed(ConsoleManager cm, AHost host, String test_pack_dir, List<PhptTestCase> test_cases) throws IllegalStateException, IOException, Exception { if (!this.host.isRemote() || this.host.equals(host)) { // installing from local host to remote host OR from remote host to itself uploadNonTestCaseFiles(host, test_pack, test_pack_dir); @@ -580,5 +577,10 @@ public class PhptSourceTestPack implements SourceTestPack<PhptActiveTestPack, Ph public String getTestPackVersionRevision() { return getVersion(); } + + @Override + public String getNameAndVersionString() { + return AHost.basename(getSourceDirectory()); + } } // end public class PhptSourceTestPack diff --git a/src/com/mostc/pftt/model/sapi/ApacheManager.java b/src/com/mostc/pftt/model/sapi/ApacheManager.java index 089cfaf..b775142 100644 --- a/src/com/mostc/pftt/model/sapi/ApacheManager.java +++ b/src/com/mostc/pftt/model/sapi/ApacheManager.java @@ -11,11 +11,11 @@ import com.github.mattficken.io.StringUtil; import com.mostc.pftt.host.ExecOutput; import com.mostc.pftt.host.AHost; import com.mostc.pftt.host.Host; -import com.mostc.pftt.host.HostGroup; import com.mostc.pftt.host.LocalHost; import com.mostc.pftt.model.core.EPhptTestStatus; import com.mostc.pftt.model.core.PhpBuild; import com.mostc.pftt.model.core.PhpIni; +import com.mostc.pftt.model.core.PhptSourceTestPack; import com.mostc.pftt.model.core.PhptTestCase; import com.mostc.pftt.model.sapi.EApacheVersion.ApacheHttpdAndVersion; import com.mostc.pftt.results.ConsoleManager; @@ -78,10 +78,10 @@ public class ApacheManager extends AbstractManagedProcessesWebServerManager { } } - public static boolean isSupported(ConsoleManager cm, ITestResultReceiver twriter, AHost host, ScenarioSetSetup scenario_set_setup, PhpBuild build, PhptTestCase test_case) { + public static boolean isSupported(ConsoleManager cm, ITestResultReceiver twriter, AHost host, ScenarioSetSetup scenario_set_setup, PhpBuild build, PhptSourceTestPack src_test_pack, PhptTestCase test_case) { if (build.isNTS(host)) { cm.println(EPrintType.SKIP_OPERATION, ApacheManager.class, "Error Apache requires TS Php Build. NTS Php Builds aren't supported with Apache mod_php."); - twriter.addResult(host, scenario_set_setup, new PhptTestResult(host, EPhptTestStatus.XSKIP, test_case, "NTS Build not supported", null, null, null, null, null, null, null, null, null, null, null)); + twriter.addResult(host, scenario_set_setup, src_test_pack, new PhptTestResult(host, EPhptTestStatus.XSKIP, test_case, "NTS Build not supported", null, null, null, null, null, null, null, null, null, null, null)); return false; } else { @@ -341,6 +341,7 @@ public class ApacheManager extends AbstractManagedProcessesWebServerManager { } // end public class ApacheWebServerInstance + @Override public void close(ConsoleManager cm) { super.close(cm); @@ -444,6 +445,7 @@ public class ApacheManager extends AbstractManagedProcessesWebServerManager { try { // install Windows service host.exec(httpd.httpd+" -k install", Host.ONE_MINUTE); + // TODO start(); return new ApacheSetup(apache_version, host, httpd.httpd, httpd.version); } catch ( Exception ex ) { cm.addGlobalException(EPrintType.CANT_CONTINUE, getClass(), "setup", ex, "Couldn't install Apache as a Windows service"); @@ -498,52 +500,6 @@ public class ApacheManager extends AbstractManagedProcessesWebServerManager { } // end public class ApacheSetup @Override - public boolean start(ConsoleManager cm, Host host, PhpBuild build, PhpIni ini) { - if (!(host instanceof AHost)) { - HostGroup group = (HostGroup) host; - for ( Host ghost : group ) { - if (!start(cm, ghost, build, ini)) - return false; - } - return !group.isEmpty(); - } - EApacheVersion apache_version = decideApacheVersion(cm, host, build, this._apache_version); - final String listen_address = "0.0.0.0"; - final int port = 80; - CouldConnect could = canConnect(listen_address, port, false); - if (could.connect) { - cm.println(EPrintType.CLUE, "ApacheManager", "A web server is already running"); - cm.println(EPrintType.TIP, "ApacheManager", "Try `stop -c apache "+build.getBuildPath()+"` to stop Apache"); - return false; - } - final String docroot = getDefaultDocroot(host, build); - - ApacheHttpdAndVersion apache = apache_version.getHttpd(cm, host, build); - // important: see #close - use different name for apache config directory so it won't be deleted - PreparedApache prep = prepareApache("Setup", ini, apache, cm, apache_version, (AHost)host, build, listen_address, port, docroot); - - // XXX will this work on Linux?? - try { - // ensure Windows service is installed - host.exec(prep.httpd+" -f "+prep.apache_conf_file+" -k install", AHost.ONE_MINUTE); - // ensure configured (important to run `config` or `start` will fail or fail to get new configuration) - host.exec(prep.httpd+" -f "+prep.apache_conf_file+" -k config", AHost.ONE_MINUTE); - // start - host.exec(prep.httpd+" -f "+prep.apache_conf_file+" -k start", AHost.ONE_MINUTE); - } catch ( Exception ex ) { - cm.addGlobalException(EPrintType.CANT_CONTINUE, getClass(), "start", ex, "Unable to Start Apache after setup", prep.httpd, prep.apache_conf_file); - return false; - } - if (canConnect(listen_address, port, false).connect) { - cm.println(EPrintType.CLUE, "ApacheManager", "Apache running\nDocument Root: "+docroot+"\nURL: http://"+listen_address+":"+port+"/"); - return true; - } else { - cm.println(EPrintType.CLUE, "ApacheManager", "Apache process appeared to start, but not able to connect after many attempts. \nThis Apache build may be broken: "+prep.httpd); - return false; - } - } - - @Override public boolean stop(ConsoleManager cm, Host host, PhpBuild build, PhpIni ini) { try { EApacheVersion apache_version = decideApacheVersion(cm, host, build, _apache_version); diff --git a/src/com/mostc/pftt/model/sapi/BuiltinWebServerManager.java b/src/com/mostc/pftt/model/sapi/BuiltinWebServerManager.java index 3cac956..e7bb200 100644 --- a/src/com/mostc/pftt/model/sapi/BuiltinWebServerManager.java +++ b/src/com/mostc/pftt/model/sapi/BuiltinWebServerManager.java @@ -169,11 +169,6 @@ public class BuiltinWebServerManager extends AbstractManagedProcessesWebServerMa } @Override - public boolean start(ConsoleManager cm, Host host, PhpBuild build, PhpIni ini) { - return false; // nothing to start - } - - @Override public boolean stop(ConsoleManager cm, Host host, PhpBuild build, PhpIni ini) { return false; // nothing to stop } diff --git a/src/com/mostc/pftt/model/sapi/IISManager.java b/src/com/mostc/pftt/model/sapi/IISManager.java index 3462839..63afec6 100644 --- a/src/com/mostc/pftt/model/sapi/IISManager.java +++ b/src/com/mostc/pftt/model/sapi/IISManager.java @@ -1,18 +1,25 @@ package com.mostc.pftt.model.sapi; +import java.io.IOException; +import java.lang.ref.SoftReference; +import java.util.Collection; import java.util.Map; import javax.annotation.concurrent.ThreadSafe; import com.github.mattficken.io.StringUtil; -import com.mostc.pftt.host.ExecOutput; import com.mostc.pftt.host.AHost; import com.mostc.pftt.host.Host; +import com.mostc.pftt.model.core.EPhptTestStatus; import com.mostc.pftt.model.core.PhpBuild; import com.mostc.pftt.model.core.PhpIni; +import com.mostc.pftt.model.core.PhptSourceTestPack; +import com.mostc.pftt.model.core.PhptTestCase; import com.mostc.pftt.results.ConsoleManager; import com.mostc.pftt.results.EPrintType; +import com.mostc.pftt.results.ITestResultReceiver; +import com.mostc.pftt.results.PhptTestResult; import com.mostc.pftt.scenario.ScenarioSet; -import com.mostc.pftt.util.ErrorUtil; +import com.mostc.pftt.scenario.ScenarioSetSetup; /** manages and monitors IIS and IIS express web servers * @@ -20,353 +27,273 @@ import com.mostc.pftt.util.ErrorUtil; * */ -// XXX need process handle for each IIS process in order to tell for sure if the process crashes -// this class only has to work on windows vista+ @ThreadSafe -public class IISManager extends WebServerManager { - /** To get a list of web applications (web apps registered with IIS): - * `appcmd list app` - * - * To get a list of web sites: - * `appcmd list site` - * - */ - public static final String DEFAULT_SITE_NAME = "Default Web Site"; - public static final String DEFAULT_APP_NAME = ""; - public static final String DEFAULT_SITE_AND_APP_NAME = "Default Web Site/"; +public class IISManager extends AbstractManagedProcessesWebServerManager { - protected String appcmd_path(Host host) { - return host.getSystemRoot()+"\\System32\\inetsrv\\appcmd.exe"; + public IISManager() { } - - protected ExecOutput appcmd(AHost host, String args) throws Exception { - String cmd = appcmd_path(host)+" "+args; - ExecOutput eo = host.execElevatedOut(cmd, AHost.ONE_MINUTE); - //System.err.println(cmd); - //System.err.println(eo.output); - return eo; - } - - @Override - public boolean start(ConsoleManager cm, Host host, PhpBuild build, PhpIni ini) { - try { - return host.execElevated(cm, getClass(), "net start w3svc", AHost.ONE_MINUTE*2); - } catch ( Exception ex ) { - cm.addGlobalException(EPrintType.CANT_CONTINUE, getClass(), "start", ex, ""); + + public static boolean isSupported(ConsoleManager cm, ITestResultReceiver twriter, AHost host, ScenarioSetSetup scenario_set_setup, PhpBuild build, PhptSourceTestPack src_test_pack, PhptTestCase test_case) { + if (build.isTS(host)) { + cm.println(EPrintType.SKIP_OPERATION, IISManager.class, "Error IIS requires NTS Php Build. TS Php Builds aren't supported with IIS."); + twriter.addResult(host, scenario_set_setup, src_test_pack, new PhptTestResult(host, EPhptTestStatus.XSKIP, test_case, "TS Build not supported", null, null, null, null, null, null, null, null, null, null, null)); + return false; + } else { + return true; } } - @Override - public boolean stop(ConsoleManager cm, Host host, PhpBuild build, PhpIni ini) { + protected static class PreparedIIS { + protected PhpIni ini; + protected String iis_conf_file, php_conf_file, error_log, conf_dir, conf_str; + } + + protected PreparedIIS prepareIIS(String temp_file_ctx, PhpIni ini, ConsoleManager cm, AHost host, PhpBuild build, String listen_address, int port, String docroot) { + PreparedIIS prep = new PreparedIIS(); + prep.ini = ini; + + // create a temporary directory to hold(for each httpd.exe instance): + // -IIS HWC config + // -php.ini + // -error.log + prep.conf_dir = host.mktempname(temp_file_ctx); try { - return host.execElevated(cm, getClass(), "net stop w3svc", AHost.ONE_MINUTE*2); + host.mkdirs(prep.conf_dir); } catch ( Exception ex ) { - if (cm==null) - ex.printStackTrace(); - else - cm.addGlobalException(EPrintType.CANT_CONTINUE, getClass(), "stop", ex, ""); - return false; + cm.addGlobalException(EPrintType.CANT_CONTINUE, getClass(), "prepareIIS", ex, "Can't create temporary dir to run IIS", host, prep.conf_dir); + return null; } - } - - public ExecOutput configure(ConsoleManager cm, AHost host, PhpBuild build, String doc_root, PhpIni ini, Map<String,String> env, String listen_address, int listen_port) { - return configure(cm, host, build, DEFAULT_SITE_NAME, DEFAULT_APP_NAME, doc_root, ini, env, listen_address, listen_port); - } - - public ExecOutput configure(ConsoleManager cm, AHost host, PhpBuild build, String site_name, String app_name, String doc_root, PhpIni ini, Map<String,String> env, String listen_address, int listen_port) { - // clear previous configuration from previous interrupted runs - undoConfigure(cm, host); - addToPHPIni(ini); + // CRITICAL: must add extension dir (and fix path) AND it MUST end with \ (Windows) + if (prep.ini==null) + prep.ini = new PhpIni(); + else if (StringUtil.isEmpty(prep.ini.getExtensionDir())) + prep.ini.setExtensionDir(host.fixPath(build.getDefaultExtensionDir())+host.dirSeparator()); + else if (!prep.ini.getExtensionDir().endsWith(host.dirSeparator())) + // extension dir already set, but doesn't end with / or \ + prep.ini.setExtensionDir(host.fixPath(prep.ini.getExtensionDir()+host.dirSeparator())); + // - String php_binary = build.getPhpCgiExe(); - String c_section = "section:system.webServer"; + prep.php_conf_file = host.joinIntoOnePath(prep.conf_dir, "php.ini"); + prep.iis_conf_file = host.joinIntoOnePath(prep.conf_dir, "iis.config"); + prep.error_log = host.joinIntoOnePath(prep.conf_dir, "error.log"); + + prep.conf_str = writeConfigurationFile(host, build.getPhpCgiExe(), prep.conf_dir, prep.error_log, listen_address, port, docroot); - // TODO env = prepareENV(env, php_conf_file, build, scenario_set, httpd); - try { - ExecOutput eo; - - // bind HTTP to listen_port - eo = appcmd(host, "set site /site.name:"+site_name+" /+bindings.[protocol='http',bindingInformation='*:"+listen_port+":']"); - if (eo.isCrashed()) - return eo; - // setup PHP to be run with FastCGI - eo = appcmd(host, "set config /"+c_section+"/fastCGI /+[fullPath='"+php_binary+"',arguments='',instanceMaxRequests='10000',maxInstances='0']"); - if (eo.isCrashed()) - return eo; - // setup important environment variables - eo = appcmd(host, "set config /"+c_section+"/fastCGI /+[fullPath='"+php_binary+"'].environmentVariables.[name='PHPRC',value='"+build.getBuildPath()+"']"); - if (eo.isCrashed()) - return eo; - eo = appcmd(host, "set config /"+c_section+"/fastCGI /+[fullPath='"+php_binary+"'].environmentVariables.[name='PHP_FCGI_MAX_REQUESTS',value='50000']"); - if (eo.isCrashed()) - return eo; - // copy any environment variables that need to be passed to PHP - // - // PHPT database tests need this in order to run - if (env!=null) { - for ( String name : env.keySet() ) { - String value = env.get(name); - - eo = appcmd(host, "set config /"+c_section+"/fastCGI /+[fullPath='"+php_binary+"'].environmentVariables.[name='"+name+"',value='"+value+"']"); - if (eo.isCrashed()) - return eo; - } - } - // - eo = appcmd(host, "set config /"+c_section+"/handlers /+[name='PHP_via_FastCGI',path='*.php',verb='*',modules='FastCgiModule',scriptProcessor='"+php_binary+"']"); - if (eo.isCrashed()) - return eo; - // set docroot to the location of the installed test-pack - return appcmd(host, "set vdir /vdir.name:\""+site_name+"/"+app_name+"\" /physicalPath:\""+doc_root+"\""); + host.saveTextFile(prep.php_conf_file, prep.ini.toString()); } catch ( Exception ex ) { - cm.addGlobalException(EPrintType.CANT_CONTINUE, getClass(), "configure", ex, ""); + cm.addGlobalException(EPrintType.CANT_CONTINUE, getClass(), "prepareIIS", ex, "Unable to save PhpIni: "+prep.php_conf_file, host, prep.php_conf_file); + return null; } - return null; - } // end public ExecOutput configure - - public boolean undoConfigure(ConsoleManager cm, AHost host) { - String c_section = "section:system.webServer"; - try { - return appcmd(host, "clear config /"+c_section+"/fastCGI").printOutputIfCrash(getClass(), cm).isSuccess() && - appcmd(host, "set config /"+c_section+"/handlers /-[name='PHP_via_FastCGI']").printOutputIfCrash(getClass(), cm).isSuccess(); + host.saveTextFile(prep.iis_conf_file, prep.conf_str); } catch ( Exception ex ) { - if (cm==null) - ex.printStackTrace(); - else - cm.addGlobalException(EPrintType.CANT_CONTINUE, getClass(), "undoConfigure", ex, ""); + cm.addGlobalException(EPrintType.CANT_CONTINUE, getClass(), "prepareIIS", ex, "Unable to save IIS configuration: "+prep.iis_conf_file, host, prep.iis_conf_file); + return null; } - return false; - } - - public static void addToPHPIni(PhpIni ini) { - //add these directives to php.ini file used by php.exe - ini.putSingle("fastcgi.impersonate", 1); - ini.putSingle("cgi.fix_path_info", 1); - ini.putSingle("cgi.force_redirect", 0); - ini.putSingle("cgi.rfc2616_headers", 0); - } - - @Override - public String getName() { - return "IIS"; - } - - WebServerInstance wsi; - @Override - public synchronized WebServerInstance getWebServerInstance(ConsoleManager cm, AHost host, ScenarioSet scenario_set, PhpBuild build, PhpIni ini, Map<String,String> env, String docroot, WebServerInstance assigned, boolean debugger_attached, Object server_name) { - if (wsi==null) - wsi = super.getWebServerInstance(cm, host, scenario_set, build, ini, env, docroot, assigned, debugger_attached, server_name); - return wsi; - } + return prep; + } // end protected PreparedIIS prepareIIS @Override - protected WebServerInstance createWebServerInstance(ConsoleManager cm, AHost host, ScenarioSet scenario_set, PhpBuild build, PhpIni ini, Map<String,String> env, String doc_root, boolean debugger_attached, Object server_name, boolean is_replacement) { - final String listen_address = host.getLocalhostListenAddress(); - final int listen_port = 80; + protected ManagedProcessWebServerInstance createManagedProcessWebServerInstance(ConsoleManager cm, AHost host, ScenarioSet scenario_set, PhpBuild build, PhpIni ini, Map<String, String> env, final String docroot, String listen_address, int port) { + if (!host.isWindows()) + // IIS is only supported on Windows + return null; - ExecOutput eo = configure(cm, host, build, doc_root, ini, env, listen_address, listen_port); + PreparedIIS prep = prepareIIS("IISManager", ini, cm, host, build, listen_address, port, docroot); - if (eo.isSuccess()) { - String err_str = ""; - try { - eo = host.execElevatedOut("net start w3svc", AHost.ONE_MINUTE*2); - if (eo.isSuccess()) { - return new IISWebServerInstance(this, StringUtil.EMPTY_ARRAY, ini, env, host, build, listen_address, listen_port); - } else { - err_str = eo.output; - } - } catch ( Exception ex ) { - err_str = ErrorUtil.toString(ex); - } - return new CrashedWebServerInstance(this, ini, env, err_str); - } - return new CrashedWebServerInstance(this, ini, env, eo.output); - } + env = prepareENV(env, prep.php_conf_file, build, scenario_set, build.getPhpCgiExe()); + + + final String cmdline = host.getPfttDir()+"/cache/dep/IIS/IISRunner "+host.fixPath(prep.iis_conf_file); + + // @see #createWebServerInstance for where command is executed to create httpd.exe process + return new IISWebServerInstance(this, docroot, cmdline, env, ini, listen_address, port, prep, host, build); + } // end protected ManagedProcessWebServerInstance createManagedProcessWebServerInstance - public class IISWebServerInstance extends WebServerInstance { + public class IISWebServerInstance extends ManagedProcessWebServerInstance { + protected final PreparedIIS prep; protected final AHost host; protected final PhpBuild build; - protected final String hostname; - protected final int port; - protected boolean running = true; - - public IISWebServerInstance(WebServerManager ws_mgr, String[] cmd_array, PhpIni ini, Map<String,String> env, AHost host, PhpBuild build, String hostname, int port) { - super(ws_mgr, cmd_array, ini, env); - this.host = host; + protected SoftReference<String> log_ref; + + public IISWebServerInstance(IISManager ws_mgr, String docroot, String cmd, Map<String,String> env, PhpIni ini, String hostname, int port, PreparedIIS prep, AHost host, PhpBuild build) { + super(ws_mgr, docroot, cmd, ini, env, hostname, port); this.build = build; - this.hostname = hostname; - this.port = port; - } - - @Override - public String toString() { - return hostname+":"+port; - } - - @Override - public String getHostname() { - return hostname; - } - - @Override - public int getPort() { - return port; - } - - @Override - protected synchronized void do_close(ConsoleManager cm) { - if (!running) - return; - - stop(null, host, build, null); - undoConfigure(null, host); - running = false; + this.host = host; + this.prep = prep; } - - private long last_run_check; + @Override - public boolean isRunning() { - // only check once every 10 seconds - if (last_run_check + 10000 > System.currentTimeMillis()) { - running = checkIsRunning(); - - last_run_check = System.currentTimeMillis(); + public String getSAPIOutput() { + if (StringUtil.isNotEmpty(prep.error_log)) { + // try to include server's error log + try { + String log = readLogCache(); + + if (StringUtil.isNotEmpty(log)) + return super.getSAPIOutput() + "\n" + log; + } catch ( Exception ex ) { + } } - return running; + return super.getSAPIOutput(); } - protected boolean checkIsRunning() { - try { - String out = host.execOut("TASKLIST /NH /FO CSV /FI \"SERVICES eq w3svc\"", AHost.ONE_MINUTE).output; - return StringUtil.isNotEmpty(out) && !out.contains("No tasks"); - } catch ( Exception ex ) { - ex.printStackTrace(); - return false; + protected String readLogCache() throws IllegalStateException, IOException { + String log = null; + if (log_ref!=null) + log = log_ref.get(); + if (log==null) { + log = host.getContents(prep.error_log); + if (StringUtil.isNotEmpty(log)) { + log_ref = new SoftReference<String>(log); + } } + return log; } - + @Override - public String getInstanceInfo(ConsoleManager cm) { - try { - return appcmd(host, "-v").output; - } catch ( Exception ex ) { - cm.addGlobalException(EPrintType.OPERATION_FAILED_CONTINUING, getClass(), "getInstanceInfo", ex, ""); - return StringUtil.EMPTY; + protected void do_close(ConsoleManager cm) { + // do this several times to make sure it gets done successfully + final boolean c = process.isCrashedOrDebuggedAndClosed(); + for ( int i=0; i <3;i++) { + super.do_close(cm); + + if (!c) { + // don't delete temp dir if crashed so user can analyze + try { + if (StringUtil.isEmpty(prep.error_log)) { + // cache log in memory before deleting on disk in case its still needed after #close call + readLogCache(); + } + + host.delete(prep.conf_dir); + } catch ( Exception ex ) { + } + } } } - - @Override - public boolean isDebuggerAttached() { - return false; - } - + @Override - public String getDocroot() { - return null; // TODO + public String getInstanceInfo(ConsoleManager cm) { + return StringUtil.EMPTY; // TODO } @Override public String getSAPIConfig() { - return null; // TODO - } - - @Override - public boolean isCrashedAndDebugged() { - return false; + return prep.conf_str; } @Override public String getNameWithVersionInfo() { - return getName(); + return "IIS"; // TODO version info } @Override public String getName() { return "IIS"; } - - @Override - public void close(ConsoleManager cm) { - } } // end public class IISWebServerInstance - + @Override public boolean allowConcurrentWebServerSAPIInstances() { - return false; + return true; } @Override public boolean isSSLSupported() { return true; } + + @Override + public String getName() { + return "IIS"; + } + + public static String writeConfigurationFile(Host host, String php_cgi_exe, String conf_dir, String error_log, String listen_address, int port, String docroot) { + return null; + } // end public String writeConfigurationFile @Override - public IISScenarioSetup setup(ConsoleManager cm, Host host, PhpBuild build) { - if (!host.isWindows()) { - cm.println(EPrintType.SKIP_OPERATION, IISManager.class, "Only supported OS is Windows"); - return null; - } else if (host.isBeforeVista()) { - cm.println(EPrintType.SKIP_OPERATION, IISManager.class, "Only Windows Vista/2008/7/2008r2/8/2012+ are supported. Upgrade Windows and try again."); - return null; - } else { - if (host.exists(appcmd_path(host))) { - cm.println(EPrintType.OPERATION_FAILED_CONTINUING, getClass(), "IIS already installed"); - - return new IISScenarioSetup(); - } - - try { - if (host.execElevated(cm, getClass(), "pkgmgr /iu:IIS-WebServerRole;IIS-WebServer;IIS-StaticContent;IIS-WebServerManagementTools;IIS-ManagementConsole;IIS-CGI", AHost.HALF_HOUR)) { - cm.println(EPrintType.OPERATION_FAILED_CONTINUING, getClass(), "IIS installed"); - - return new IISScenarioSetup(); - } else { - cm.println(EPrintType.CANT_CONTINUE, getClass(), "IIS install failed"); - } - } catch ( Exception ex ) { - cm.addGlobalException(EPrintType.CANT_CONTINUE, getClass(), "setup", ex, "exception during IIS install.", host); - } + public IISSetup setup(ConsoleManager cm, Host host, PhpBuild build) { + if (!host.isWindows()) return null; + + try { + // TODO install + host.exec("net start w3svc", Host.ONE_MINUTE); + return new IISSetup(host); + } catch ( Exception ex ) { + cm.addGlobalException(EPrintType.CANT_CONTINUE, getClass(), "setup", ex, "Couldn't install IIS as a Windows service"); } - } // end public IISScenarioSetup setup - - public class IISScenarioSetup extends SimpleWebServerSetup { - - @Override - public void close(ConsoleManager cm) { - + return null; + } + + public class IISSetup extends SimpleWebServerSetup { + protected final Host host; + + protected IISSetup(Host host) { + this.host = host; } @Override - public String getNameWithVersionInfo() { - return getName(); + public String getHostname() { + return ((AHost)host).getAddress(); } @Override - public String getName() { - return "IIS"; + public int getPort() { + return 80; } @Override - public String getHostname() { - return "127.0.0.1"; + public void close(ConsoleManager cm) { + try { + host.exec("net stop w3svc", Host.ONE_MINUTE); + } catch ( Exception ex ) { + if (cm==null) + ex.printStackTrace(); + else + cm.addGlobalException(EPrintType.CANT_CONTINUE, getClass(), "close", ex, "Exception stopping IIS"); + } } @Override - public int getPort() { - return 80; + public String getNameWithVersionInfo() { + return "IIS"; // TODO version info } - } // end public class IISScenarioSetup + @Override + public String getName() { + return "IIS"; + } + + } // end public class IISSetup + + @Override + public boolean stop(ConsoleManager cm, Host host, PhpBuild build, PhpIni ini) { + if (!host.isWindows()) + return false; + try { + return host.exec(cm, getClass(), "net stop w3svc", Host.ONE_MINUTE); + } catch ( Exception ex ) { + cm.addGlobalException(EPrintType.CANT_CONTINUE, getClass(), "stop", ex, ""); + } + return false; + } @Override public String getDefaultDocroot(Host host, PhpBuild build) { - return host.getSystemDrive() + "\\inetpub\\wwwroot"; + return host.isWindows() ? host.getSystemDrive()+"/inetpub/wwwroot" : null; } + public void addToDebugPath(ConsoleManager cm, AHost host, PhpBuild build, Collection<String> debug_path) { + if (host.isWindows()) { + // TODO + } + } + } // end public class IISManager diff --git a/src/com/mostc/pftt/model/sapi/WebServerManager.java b/src/com/mostc/pftt/model/sapi/WebServerManager.java index 28700a7..63daa54 100644 --- a/src/com/mostc/pftt/model/sapi/WebServerManager.java +++ b/src/com/mostc/pftt/model/sapi/WebServerManager.java @@ -42,8 +42,6 @@ public abstract class WebServerManager extends SAPIManager { */ public abstract IScenarioSetup setup(ConsoleManager cm, Host host, PhpBuild build); - public abstract boolean start(ConsoleManager cm, Host host, PhpBuild build, PhpIni ini); - public abstract boolean stop(ConsoleManager cm, Host host, PhpBuild build, PhpIni ini); public abstract String getName(); @@ -153,6 +151,7 @@ public abstract class WebServerManager extends SAPIManager { // env.put(AbstractPhptTestCaseRunner.ENV_PFTT_SCENARIO_SET, scenario_set.getName()); env.put(AbstractPhptTestCaseRunner.ENV_PFTT_IS, "1"); + return env; } diff --git a/src/com/mostc/pftt/results/PhpResultPackReader.java b/src/com/mostc/pftt/results/PhpResultPackReader.java index 83b1195..5e1bec2 100644 --- a/src/com/mostc/pftt/results/PhpResultPackReader.java +++ b/src/com/mostc/pftt/results/PhpResultPackReader.java @@ -89,6 +89,8 @@ public class PhpResultPackReader extends PhpResultPack { if (dirs2==null) continue; for ( File scenario_dir : dirs2 ) { + if (!scenario_dir.isDirectory()) + continue; String scenario_set_name = scenario_dir.getName(); PhptResultReader phpt_reader = new PhptResultReader(); diff --git a/src/com/mostc/pftt/results/PhptResultReader.java b/src/com/mostc/pftt/results/PhptResultReader.java index c38943f..50038e6 100644 --- a/src/com/mostc/pftt/results/PhptResultReader.java +++ b/src/com/mostc/pftt/results/PhptResultReader.java @@ -153,9 +153,11 @@ public class PhptResultReader extends AbstractPhptRW { e.test_names.remove("ext/mbstring/tests/mb_output_handler_pattern-13.phpt"); e.test_names.remove("ext/mbstring/tests/mb_output_handler_pattern-14.phpt"); e.test_names.remove("tests/basic/027.phpt"); + e.test_names.remove("tests/func/bug64523.phpt"); e.test_names.remove("ext/mysql/tests/bug53649.phpt"); e.test_names.remove("ext/iconv/tests/ob_iconv_handler.phpt"); e.test_names.remove("ext/mbstring/tests/mb_decode_numericentity.phpt"); + e.test_names.remove("ext/standard/tests/strings/explode_bug.phpt"); } return e.test_names; } diff --git a/src/com/mostc/pftt/runner/AbstractPhpUnitTestCaseRunner.java b/src/com/mostc/pftt/runner/AbstractPhpUnitTestCaseRunner.java index 28c2882..6fb0ba0 100644 --- a/src/com/mostc/pftt/runner/AbstractPhpUnitTestCaseRunner.java +++ b/src/com/mostc/pftt/runner/AbstractPhpUnitTestCaseRunner.java @@ -29,20 +29,27 @@ import com.mostc.pftt.scenario.ScenarioSetSetup; /** runs a single PhpUnitTestCase * + * +having PFTT directly run PhpUnit test cases itself, instead of just wrapping `phpunit` allows for: + -faster execution (threads) + -Web Server support ('cut closer to actual server') + -more accurate results + -usually only a slight or no difference + -but if you care about accurate, quality or thorough testing + -or if care about how well your software actually works + -better analysis of large amounts of phpunit tests + -opcache support + -opcache can break reflection (at least on apache) + -PFTT doesn't use reflection for phpunit tests + so PFTT can run phpunit tests regardless of this problem + ->add `phpunit_reflection_only` to your -config to force PFTT to use reflection to test this problem + -counting additional statuses (ex: xskip) + -accurate CRASH and TIMEOUT detection + * * @author Matt Ficken * */ -// having PFTT directly run PhpUnit test cases itself, instead of just wrapping `phpunit` allows for: -// -faster execution (threads) -// -Web Server support ('cut closer to actual server') -// -more accurate results -// -usually only a slight or no difference -// -but if you care about accurate, quality or thorough testing -// -or if care about how well your software actually works -// -counting additional statuses (ex: xskip) -// -accurate crash detection -// public abstract class AbstractPhpUnitTestCaseRunner extends AbstractTestCaseRunner<LocalPhpUnitTestPackRunner.PhpUnitThread,LocalPhpUnitTestPackRunner> { protected final SAPIScenario sapi_scenario; protected final PhpUnitThread thread; @@ -209,8 +216,8 @@ public abstract class AbstractPhpUnitTestCaseRunner extends AbstractTestCaseRunn // // @see PhpUnitTemplate#renderTemplate for the PHP script // - TestCaseCodeCoverage code_coverage = new TestCaseCodeCoverage(host); - String output_str; + TestCaseCodeCoverage code_coverage = null; + String output_str, output_lc; { List<String> lines = ArrayUtil.toList(StringUtil.splitLines(output)); Iterator<String> line_it = lines.iterator(); @@ -222,14 +229,20 @@ public abstract class AbstractPhpUnitTestCaseRunner extends AbstractTestCaseRunn line_it.remove(); // remove this line from output_str } else if (line.startsWith("exe=")) { + if (code_coverage==null) + code_coverage = new TestCaseCodeCoverage(host); code_coverage.addExecutedLine(file, Integer.parseInt(line.substring("exe=".length()))); line_it.remove(); // remove this line from output_str } else if (line.startsWith("didnt_exe=")) { + if (code_coverage==null) + code_coverage = new TestCaseCodeCoverage(host); code_coverage.addNotExecutedLine(file, Integer.parseInt(line.substring("didnt_exe=".length()))); line_it.remove(); // remove this line from output_str } else if (line.startsWith("no_exe=")) { + if (code_coverage==null) + code_coverage = new TestCaseCodeCoverage(host); code_coverage.addNonExecutableLine(file, Integer.parseInt(line.substring("no_exe=".length()))); line_it.remove(); // remove this line from output_str @@ -251,20 +264,24 @@ public abstract class AbstractPhpUnitTestCaseRunner extends AbstractTestCaseRunn } } output_str = StringUtil.join(lines, "\n"); - if (output_str.contains("Missing arg")||output_str.contains("Argument 1 passed")) - status = EPhpUnitTestStatus.SKIP; // TODO temp + output_lc = output_str.toLowerCase(); + // some tests call code that echos out 'not implemented' (using echo, etc... + // not throwing exception with PhpUnit, so have to search the output for string) + if ((status==EPhpUnitTestStatus.ERROR||status==EPhpUnitTestStatus.FAILURE) + && (output_lc.contains("not been implemented yet") || output_lc.contains("not implemented"))) { + status = EPhpUnitTestStatus.NOT_IMPLEMENTED; + } } // - if (status==null||is_timeout) { + if (is_timeout) { + status = EPhpUnitTestStatus.TIMEOUT; + } else if (status==null) { // if test had a 'Fatal Error', it might not have been able to print the status code at all // (otherwise it should always have a status code) status = EPhpUnitTestStatus.ERROR; - } - - if (status == EPhpUnitTestStatus.SKIP) { + } else if (status == EPhpUnitTestStatus.SKIP) { // check if it should be XSKIP instead - final String output_lc = output_str.toLowerCase(); if (host.isWindows() && output_lc.contains("not ") && output_lc.contains(" windows")) status = EPhpUnitTestStatus.XSKIP; else if (!host.isWindows() && output_lc.contains("only ") && output_lc.contains(" windows")) @@ -300,6 +317,8 @@ public abstract class AbstractPhpUnitTestCaseRunner extends AbstractTestCaseRunn /** configures PhpUnit globals to use the given database. * + * Note: these are standard names for PhpUnit_Framework_Database, many test suites also + * use their own names which you MUST provide in an additional Scenario (which you can load from a config file) * Note: (because of how this is done) PhpUnit tests only test 1 database at a time (unlike PHPTs). * * So if you want to test an application with multiple different databases (ex: MySQL and PostgresQL), you diff --git a/src/com/mostc/pftt/runner/AbstractPhptTestCaseRunner2.java b/src/com/mostc/pftt/runner/AbstractPhptTestCaseRunner2.java index c5180be..2580f56 100644 --- a/src/com/mostc/pftt/runner/AbstractPhptTestCaseRunner2.java +++ b/src/com/mostc/pftt/runner/AbstractPhptTestCaseRunner2.java @@ -143,13 +143,13 @@ public abstract class AbstractPhptTestCaseRunner2 extends AbstractPhptTestCaseRu */ protected boolean prepare() throws IOException, Exception { if (test_case.hasBorkInfo()) { - twriter.addResult(host, scenario_set, new PhptTestResult(host, EPhptTestStatus.BORK, test_case, test_case.getBorkInfo(), null, null, null, null, null, null, null, null, null, null, null)); + twriter.addResult(host, scenario_set, src_test_pack, new PhptTestResult(host, EPhptTestStatus.BORK, test_case, test_case.getBorkInfo(), null, null, null, null, null, null, null, null, null, null, null)); return false; } if (test_case.hasUnsupportedInfo()) { - twriter.addResult(host, scenario_set, new PhptTestResult(host, EPhptTestStatus.UNSUPPORTED, test_case, test_case.getUnsupportedInfo(), null, null, null, null, null, null, null, null, null, null, null)); + twriter.addResult(host, scenario_set, src_test_pack, new PhptTestResult(host, EPhptTestStatus.UNSUPPORTED, test_case, test_case.getUnsupportedInfo(), null, null, null, null, null, null, null, null, null, null, null)); return false; } @@ -217,15 +217,15 @@ public abstract class AbstractPhptTestCaseRunner2 extends AbstractPhptTestCaseRu if (host.isWindows()) { if ( (lc_output.contains("only ")&&(lc_output.contains(" linux")||lc_output.contains(" non windows")||lc_output.contains(" non-windows")))||(lc_output.contains("not ")&&lc_output.contains(" windows"))) // can"t run this test on this OS - twriter.addResult(host, scenario_set, new PhptTestResult(host, is_timeout?EPhptTestStatus.TIMEOUT:EPhptTestStatus.XSKIP, test_case, output, null, null, null, ini, null, null, null, null, null, null, null)); + twriter.addResult(host, scenario_set, src_test_pack, new PhptTestResult(host, is_timeout?EPhptTestStatus.TIMEOUT:EPhptTestStatus.XSKIP, test_case, output, null, null, null, ini, null, null, null, null, null, null, null)); else - twriter.addResult(host, scenario_set, new PhptTestResult(host, is_timeout?EPhptTestStatus.TIMEOUT:EPhptTestStatus.SKIP, test_case, output, null, null, null, ini, null, null, null, null, null, null, null)); + twriter.addResult(host, scenario_set, src_test_pack, new PhptTestResult(host, is_timeout?EPhptTestStatus.TIMEOUT:EPhptTestStatus.SKIP, test_case, output, null, null, null, ini, null, null, null, null, null, null, null)); } else { if ( (lc_output.contains("only ")&&lc_output.contains(" windows"))||(lc_output.contains("not ")&&lc_output.contains(" linux"))) // can"t run this test on this OS - twriter.addResult(host, scenario_set, new PhptTestResult(host, is_timeout?EPhptTestStatus.TIMEOUT:EPhptTestStatus.XSKIP, test_case, output, null, null, null, ini, null, null, null, null, null, null, null)); + twriter.addResult(host, scenario_set, src_test_pack, new PhptTestResult(host, is_timeout?EPhptTestStatus.TIMEOUT:EPhptTestStatus.XSKIP, test_case, output, null, null, null, ini, null, null, null, null, null, null, null)); else - twriter.addResult(host, scenario_set, new PhptTestResult(host, is_timeout?EPhptTestStatus.TIMEOUT:EPhptTestStatus.SKIP, test_case, output, null, null, null, ini, null, null, null, null, null, null, null)); + twriter.addResult(host, scenario_set, src_test_pack, new PhptTestResult(host, is_timeout?EPhptTestStatus.TIMEOUT:EPhptTestStatus.SKIP, test_case, output, null, null, null, ini, null, null, null, null, null, null, null)); } // skip this test @@ -309,7 +309,7 @@ public abstract class AbstractPhptTestCaseRunner2 extends AbstractPhptTestCaseRu setRequestMethod("POST"); if (StringUtil.isEmpty(request)) { - twriter.addResult(host, scenario_set, new PhptTestResult(host, EPhptTestStatus.BORK, test_case, "Request is empty", null, null, null, null, null, null, null, null, null, null, null)); + twriter.addResult(host, scenario_set, src_test_pack, new PhptTestResult(host, EPhptTestStatus.BORK, test_case, "Request is empty", null, null, null, null, null, null, null, null, null, null, null)); return; } @@ -452,7 +452,7 @@ public abstract class AbstractPhptTestCaseRunner2 extends AbstractPhptTestCaseRu } if (expected_re_match) { - twriter.addResult(host, scenario_set, notifyPassOrXFail(new PhptTestResult(host, test_case.isXFail()?EPhptTestStatus.XFAIL:EPhptTestStatus.PASS, test_case, output, null, null, charset, ini, env, splitCmdString(), stdin_post, getShellScript(), null, null, preoverride_actual, getSAPIOutput(), getSAPIConfig()))); + twriter.addResult(host, scenario_set, src_test_pack, notifyPassOrXFail(new PhptTestResult(host, test_case.isXFail()?EPhptTestStatus.XFAIL:EPhptTestStatus.PASS, test_case, output, null, null, charset, ini, env, splitCmdString(), stdin_post, getShellScript(), null, null, preoverride_actual, getSAPIOutput(), getSAPIConfig()))); return; } @@ -465,7 +465,7 @@ public abstract class AbstractPhptTestCaseRunner2 extends AbstractPhptTestCaseRu } if (expected_re_match) { - twriter.addResult(host, scenario_set, notifyPassOrXFail(new PhptTestResult(host, test_case.isXFail()?EPhptTestStatus.XFAIL:EPhptTestStatus.PASS, test_case, output, null, null, charset, ini, env, splitCmdString(), stdin_post, getShellScript(), null, null, preoverride_actual, getSAPIOutput(), getSAPIConfig()))); + twriter.addResult(host, scenario_set, src_test_pack, notifyPassOrXFail(new PhptTestResult(host, test_case.isXFail()?EPhptTestStatus.XFAIL:EPhptTestStatus.PASS, test_case, output, null, null, charset, ini, env, splitCmdString(), stdin_post, getShellScript(), null, null, preoverride_actual, getSAPIOutput(), getSAPIConfig()))); return; } @@ -488,7 +488,7 @@ public abstract class AbstractPhptTestCaseRunner2 extends AbstractPhptTestCaseRu } if (expected_re_match) { - twriter.addResult(host, scenario_set, notifyPassOrXFail(new PhptTestResult(host, test_case.isXFail()?EPhptTestStatus.XFAIL:EPhptTestStatus.PASS, test_case, output, null, null, charset, ini, env, splitCmdString(), stdin_post, getShellScript(), null, null, preoverride_actual, getSAPIOutput(), getSAPIConfig()))); + twriter.addResult(host, scenario_set, src_test_pack, notifyPassOrXFail(new PhptTestResult(host, test_case.isXFail()?EPhptTestStatus.XFAIL:EPhptTestStatus.PASS, test_case, output, null, null, charset, ini, env, splitCmdString(), stdin_post, getShellScript(), null, null, preoverride_actual, getSAPIOutput(), getSAPIConfig()))); return; } @@ -501,7 +501,7 @@ public abstract class AbstractPhptTestCaseRunner2 extends AbstractPhptTestCaseRu } if (expected_re_match) { - twriter.addResult(host, scenario_set, notifyPassOrXFail(new PhptTestResult(host, test_case.isXFail()?EPhptTestStatus.XFAIL:EPhptTestStatus.PASS, test_case, output, null, null, charset, ini, env, splitCmdString(), stdin_post, getShellScript(), null, null, preoverride_actual, getSAPIOutput(), getSAPIConfig()))); + twriter.addResult(host, scenario_set, src_test_pack, notifyPassOrXFail(new PhptTestResult(host, test_case.isXFail()?EPhptTestStatus.XFAIL:EPhptTestStatus.PASS, test_case, output, null, null, charset, ini, env, splitCmdString(), stdin_post, getShellScript(), null, null, preoverride_actual, getSAPIOutput(), getSAPIConfig()))); return; } @@ -514,7 +514,7 @@ public abstract class AbstractPhptTestCaseRunner2 extends AbstractPhptTestCaseRu if (equalsNoWS(output, expected)||(test_case.expectsWarningOrFatalError() && equalsNoWS(output, PhptTestCase.removeWarningAndFatalError(expected)))||(output.contains("<html>")&&!output.contains("404"))||(test_case.isNamed("ext/phar/tests/zip/phar_commitwrite.phpt")&&expected.contains(output.substring(50, 60)))||(test_case.isNamed("ext/phar/tests/tar/phar_commitwrite.phpt")&&expected.contains(output.substring(60, 70)))) { - twriter.addResult(host, scenario_set, notifyPassOrXFail(new PhptTestResult(host, test_case.isXFail()?EPhptTestStatus.XFAIL:EPhptTestStatus.PASS, test_case, output, null, null, charset, ini, env, splitCmdString(), stdin_post, getShellScript(), null, null, null))); + twriter.addResult(host, scenario_set, src_test_pack, notifyPassOrXFail(new PhptTestResult(host, test_case.isXFail()?EPhptTestStatus.XFAIL:EPhptTestStatus.PASS, test_case, output, null, null, charset, ini, env, splitCmdString(), stdin_post, getShellScript(), null, null, null))); return; } @@ -531,7 +531,7 @@ public abstract class AbstractPhptTestCaseRunner2 extends AbstractPhptTestCaseRu // compare again if (equalsNoWS(output, expected)) { - twriter.addResult(host, scenario_set, notifyPassOrXFail(new PhptTestResult(host, test_case.isXFail()?EPhptTestStatus.XFAIL:EPhptTestStatus.PASS, test_case, output, null, null, charset, ini, env, splitCmdString(), stdin_post, getShellScript(), null, null, preoverride_actual, getSAPIOutput(), getSAPIConfig()))); + twriter.addResult(host, scenario_set, src_test_pack, notifyPassOrXFail(new PhptTestResult(host, test_case.isXFail()?EPhptTestStatus.XFAIL:EPhptTestStatus.PASS, test_case, output, null, null, charset, ini, env, splitCmdString(), stdin_post, getShellScript(), null, null, preoverride_actual, getSAPIOutput(), getSAPIConfig()))); return; } // end if @@ -541,7 +541,7 @@ public abstract class AbstractPhptTestCaseRunner2 extends AbstractPhptTestCaseRu String output_trim = output.trim(); if (StringUtil.isEmpty(output_trim)||(output.contains("<html>")&&!output.contains("404"))) { - twriter.addResult(host, scenario_set, notifyPassOrXFail(new PhptTestResult(host, test_case.isXFail()?EPhptTestStatus.XFAIL:EPhptTestStatus.PASS, test_case, output, null, null, charset, ini, env, splitCmdString(), stdin_post, getShellScript(), null, null, preoverride_actual, getSAPIOutput(), getSAPIConfig()))); + twriter.addResult(host, scenario_set, src_test_pack, notifyPassOrXFail(new PhptTestResult(host, test_case.isXFail()?EPhptTestStatus.XFAIL:EPhptTestStatus.PASS, test_case, output, null, null, charset, ini, env, splitCmdString(), stdin_post, getShellScript(), null, null, preoverride_actual, getSAPIOutput(), getSAPIConfig()))); return; } @@ -590,7 +590,7 @@ public abstract class AbstractPhptTestCaseRunner2 extends AbstractPhptTestCaseRu } // - twriter.addResult(host, scenario_set, result); + twriter.addResult(host, scenario_set, src_test_pack, result); } // end protected void evalTest protected PhptTestResult notifyPassOrXFail(PhptTestResult result) { diff --git a/src/com/mostc/pftt/runner/CliPhptTestCaseRunner.java b/src/com/mostc/pftt/runner/CliPhptTestCaseRunner.java index e8a2508..9fd871f 100644 --- a/src/com/mostc/pftt/runner/CliPhptTestCaseRunner.java +++ b/src/com/mostc/pftt/runner/CliPhptTestCaseRunner.java @@ -57,7 +57,7 @@ public class CliPhptTestCaseRunner extends AbstractPhptTestCaseRunner2 { if (build.hasPhpCgiExe()) { exe_type = EExecutableType.CGI; } else { - twriter.addResult(host, scenario_set, new PhptTestResult(host, EPhptTestStatus.XSKIP, test_case, "CGI not available", null, null, null, null, null, null, null, null, null, null, null)); + twriter.addResult(host, scenario_set, src_test_pack, new PhptTestResult(host, EPhptTestStatus.XSKIP, test_case, "CGI not available", null, null, null, null, null, null, null, null, null, null, null)); return false; } @@ -259,7 +259,7 @@ public class CliPhptTestCaseRunner extends AbstractPhptTestCaseRunner2 { int exit_code = running_test_handle.getExitCode(); - twriter.addResult(host, scenario_set, notifyNotPass(new PhptTestResult(host, EPhptTestStatus.CRASH, test_case, "PFTT: exit_code="+exit_code+" status="+AHost.guessExitCodeStatus(host, exit_code)+"\n"+output_str, null, null, null, ini, env, null, stdin_post, null, null, null, null, output_str, null))); + twriter.addResult(host, scenario_set, src_test_pack, notifyNotPass(new PhptTestResult(host, EPhptTestStatus.CRASH, test_case, "PFTT: exit_code="+exit_code+" status="+AHost.guessExitCodeStatus(host, exit_code)+"\n"+output_str, null, null, null, ini, env, null, stdin_post, null, null, null, null, output_str, null))); } running_test_handle = null; diff --git a/src/com/mostc/pftt/runner/HttpPhptTestCaseRunner.java b/src/com/mostc/pftt/runner/HttpPhptTestCaseRunner.java index 8cf92bf..0794afd 100644 --- a/src/com/mostc/pftt/runner/HttpPhptTestCaseRunner.java +++ b/src/com/mostc/pftt/runner/HttpPhptTestCaseRunner.java @@ -102,7 +102,7 @@ public class HttpPhptTestCaseRunner extends AbstractPhptTestCaseRunner2 { return; not_crashed = false; // @see #runTest - twriter.addResult(host, scenario_set, notifyNotPass(new PhptTestResult(host, EPhptTestStatus.CRASH, test_case, null, null, null, null, ini, env, null, stdin_post, null, null, null, null, web==null?null:web.getSAPIOutput(), web==null?null:web.getSAPIConfig()))); + twriter.addResult(host, scenario_set, src_test_pack, notifyNotPass(new PhptTestResult(host, EPhptTestStatus.CRASH, test_case, null, null, null, null, ini, env, null, stdin_post, null, null, null, null, web==null?null:web.getSAPIOutput(), web==null?null:web.getSAPIConfig()))); } /** executes SKIPIF, TEST or CLEAN over http. diff --git a/src/com/mostc/pftt/runner/LocalPhpUnitTestPackRunner.java b/src/com/mostc/pftt/runner/LocalPhpUnitTestPackRunner.java index 6ed2dc3..0ac64b5 100644 --- a/src/com/mostc/pftt/runner/LocalPhpUnitTestPackRunner.java +++ b/src/com/mostc/pftt/runner/LocalPhpUnitTestPackRunner.java @@ -5,8 +5,6 @@ import java.util.HashMap; import java.util.List; import java.util.Map; -import javax.annotation.Nullable; - import com.mostc.pftt.host.AHost; import com.mostc.pftt.model.app.EPhpUnitTestStatus; import com.mostc.pftt.model.app.PhpUnitActiveTestPack; @@ -40,17 +38,6 @@ public class LocalPhpUnitTestPackRunner extends AbstractLocalTestPackRunner<PhpU super(cm, twriter, scenario_set, build, storage_host, runner_host); } - @Override - protected ITestPackStorageDir doSetupStorageAndTestPack(boolean test_cases_read, @Nullable List<PhpUnitTestCase> test_cases) throws Exception { - if (test_cases_read) { - - // TODO cm.println(EPrintType.IN_PROGRESS, getClass(), "installed tests("+test_cases.size()+") from test-pack onto storage: local="+local_test_pack_dir+" remote="+remote_test_pack_dir); - - return null; - } - return super.doSetupStorageAndTestPack(test_cases_read, test_cases); - } - protected String temp_base_dir; protected boolean reflection_only; @Override @@ -222,7 +209,7 @@ public class LocalPhpUnitTestPackRunner extends AbstractLocalTestPackRunner<PhpU @Override protected void recordSkipped(PhpUnitTestCase test_case) { - twriter.addResult(runner_host, scenario_set_setup, new PhpUnitTestResult(test_case, EPhpUnitTestStatus.SKIP, scenario_set_setup, runner_host, null, null, 0, null, "PFTT: Test Timed Out", null)); + twriter.addResult(runner_host, scenario_set_setup, new PhpUnitTestResult(test_case, EPhpUnitTestStatus.TIMEOUT, scenario_set_setup, runner_host, null, null, 0, null, "PFTT: Test Timed Out", null)); } } // end public class PhpUnitThread diff --git a/src/com/mostc/pftt/runner/LocalPhptTestPackRunner.java b/src/com/mostc/pftt/runner/LocalPhptTestPackRunner.java index 8d10fdc..3ae4fa5 100644 --- a/src/com/mostc/pftt/runner/LocalPhptTestPackRunner.java +++ b/src/com/mostc/pftt/runner/LocalPhptTestPackRunner.java @@ -118,14 +118,14 @@ public class LocalPhptTestPackRunner extends AbstractLocalTestPackRunner<PhptAct String name = test_case.getName(); if (name.contains("svsvmsg")||name.contains("sysvshm")||name.contains("posix")||name.contains("ftp")||name.contains("dba")||name.contains("sybase")||name.contains("interbase")||name.contains("ldap")||name.contains("imap")||name.contains("oci")||name.contains("soap")||name.contains("xmlrpc")||name.contains("pcntl")||name.contains("odbc")||name.contains("snmp")) { // TODO temp 5/29 - twriter.addResult(runner_host, scenario_set_setup, new PhptTestResult(runner_host, EPhptTestStatus.SKIP, test_case, "Skip", null, null, null, null, null, null, null, null, null, null, null)); + twriter.addResult(runner_host, scenario_set_setup, src_test_pack, new PhptTestResult(runner_host, EPhptTestStatus.SKIP, test_case, "Skip", null, null, null, null, null, null, null, null, null, null, null)); return null; } final ESAPIType sapi_type = sapi_scenario.getSAPIType(); for ( Scenario scenario : scenario_set ) { // usually just asking sapi_scenario, sometimes file system scenario - if (scenario.willSkip(cm, twriter, runner_host, scenario_set_setup, sapi_type, build, test_case)) { + if (scenario.willSkip(cm, twriter, runner_host, scenario_set_setup, sapi_type, build, src_test_pack, test_case)) { // #willSkip will record the PhptTestResult explaining why it was skipped // // do some checking before making a PhpIni (part of group_key) below @@ -141,7 +141,7 @@ public class LocalPhptTestPackRunner extends AbstractLocalTestPackRunner<PhptAct // // now that PhpIni is generated, we know which extensions will be loaded // so we can now skip tests of extensions that aren't loaded (faster than running every test's SKIPIF section) - if (sapi_scenario.willSkip(cm, twriter, runner_host, scenario_set_setup, sapi_scenario.getSAPIType(), group_key.getPhpIni(), build, test_case)) { + if (sapi_scenario.willSkip(cm, twriter, runner_host, scenario_set_setup, sapi_scenario.getSAPIType(), group_key.getPhpIni(), build, src_test_pack, test_case)) { // #willSkip will record the PhptTestResult explaining why it was skipped return null; } @@ -182,7 +182,7 @@ public class LocalPhptTestPackRunner extends AbstractLocalTestPackRunner<PhptAct } // end protected void postGroup protected void reportGroups() { - PhptResultWriter phpt = (PhptResultWriter) ((PhpResultPackWriter)twriter).getPHPT(runner_host, scenario_set_setup); + PhptResultWriter phpt = (PhptResultWriter) ((PhpResultPackWriter)twriter).getPHPT(runner_host, scenario_set_setup, src_test_pack.getNameAndVersionString()); phpt.reportGroups(thread_safe_groups, non_thread_safe_exts); } @@ -201,7 +201,7 @@ public class LocalPhptTestPackRunner extends AbstractLocalTestPackRunner<PhptAct @Override protected void runTest(TestCaseGroupKey group_key, PhptTestCase test_case) throws IOException, Exception, Throwable { r = sapi_scenario.createPhptTestCaseRunner(this, group_key, test_case, cm, twriter, runner_host, scenario_set_setup, build, src_test_pack, active_test_pack); - twriter.notifyStart(runner_host, scenario_set_setup, test_case); + twriter.notifyStart(runner_host, scenario_set_setup, src_test_pack, test_case); r.runTest(cm, this, LocalPhptTestPackRunner.this); } @@ -218,14 +218,14 @@ public class LocalPhptTestPackRunner extends AbstractLocalTestPackRunner<PhptAct @Override protected void recordSkipped(PhptTestCase test_case) { - twriter.addResult(runner_host, scenario_set_setup, new PhptTestResult(runner_host, EPhptTestStatus.SKIP, test_case, "test timed out", null, null, null, null, null, null, null, null, null, null, null)); + twriter.addResult(runner_host, scenario_set_setup, src_test_pack, new PhptTestResult(runner_host, EPhptTestStatus.TIMEOUT, test_case, "test timed out", null, null, null, null, null, null, null, null, null, null, null)); } } // end public class PhptThread @Override protected void showTally() { - AbstractPhptRW phpt = ((PhpResultPackWriter)twriter).getPHPT(runner_host, scenario_set_setup); + AbstractPhptRW phpt = ((PhpResultPackWriter)twriter).getPHPT(runner_host, scenario_set_setup, src_test_pack.getNameAndVersionString()); for ( EPhptTestStatus status : EPhptTestStatus.values() ) { cm.println(EPrintType.CLUE, getClass(), status+" "+phpt.count(status)+" tests"); } diff --git a/src/com/mostc/pftt/scenario/ApacheScenario.java b/src/com/mostc/pftt/scenario/ApacheScenario.java index 78cb2a5..90cecb8 100644 --- a/src/com/mostc/pftt/scenario/ApacheScenario.java +++ b/src/com/mostc/pftt/scenario/ApacheScenario.java @@ -5,6 +5,7 @@ import java.util.Collection; import com.mostc.pftt.host.AHost; import com.mostc.pftt.model.core.ESAPIType; import com.mostc.pftt.model.core.PhpBuild; +import com.mostc.pftt.model.core.PhptSourceTestPack; import com.mostc.pftt.model.core.PhptTestCase; import com.mostc.pftt.model.sapi.ApacheManager; import com.mostc.pftt.results.ConsoleManager; @@ -28,11 +29,11 @@ public abstract class ApacheScenario extends ProductionWebServerScenario { } @Override - public boolean willSkip(ConsoleManager cm, ITestResultReceiver twriter, AHost host, ScenarioSetSetup setup, ESAPIType type, PhpBuild build, PhptTestCase test_case) throws Exception { - if (!ApacheManager.isSupported(cm, twriter, host, setup, build, test_case)) { + public boolean willSkip(ConsoleManager cm, ITestResultReceiver twriter, AHost host, ScenarioSetSetup setup, ESAPIType type, PhpBuild build, PhptSourceTestPack src_test_pack, PhptTestCase test_case) throws Exception { + if (!ApacheManager.isSupported(cm, twriter, host, setup, build, src_test_pack, test_case)) { return false; } - return super.willSkip(cm, twriter, host, setup, type, build, test_case); + return super.willSkip(cm, twriter, host, setup, type, build, src_test_pack, test_case); } } diff --git a/src/com/mostc/pftt/scenario/BuiltinWebServerScenario.java b/src/com/mostc/pftt/scenario/BuiltinWebServerScenario.java index aed134f..0fd5613 100644 --- a/src/com/mostc/pftt/scenario/BuiltinWebServerScenario.java +++ b/src/com/mostc/pftt/scenario/BuiltinWebServerScenario.java @@ -272,12 +272,12 @@ public class BuiltinWebServerScenario extends WebServerScenario { } @Override - public boolean willSkip(ConsoleManager cm, ITestResultReceiver twriter, AHost host, ScenarioSetSetup setup, ESAPIType type, PhpBuild build, PhptTestCase test_case) throws Exception { - if (super.willSkip(cm, twriter, host, setup, type, build, test_case)) { + public boolean willSkip(ConsoleManager cm, ITestResultReceiver twriter, AHost host, ScenarioSetSetup setup, ESAPIType type, PhpBuild build, PhptSourceTestPack src_test_pack, PhptTestCase test_case) throws Exception { + if (super.willSkip(cm, twriter, host, setup, type, build, src_test_pack, test_case)) { return true; } else if (test_case.isNamed(NOT_ON_BUILTIN_WEB_SERVER)) { - twriter.addResult(host, setup, new PhptTestResult(host, EPhptTestStatus.XSKIP, test_case, "test is not valid on builtin web server", null, null, null, null, null, null, null, null, null, null, null)); + twriter.addResult(host, setup, src_test_pack, new PhptTestResult(host, EPhptTestStatus.XSKIP, test_case, "test is not valid on builtin web server", null, null, null, null, null, null, null, null, null, null, null)); return true; } else { return false; diff --git a/src/com/mostc/pftt/scenario/CLIScenario.java b/src/com/mostc/pftt/scenario/CLIScenario.java index e2124f6..3a1a597 100644 --- a/src/com/mostc/pftt/scenario/CLIScenario.java +++ b/src/com/mostc/pftt/scenario/CLIScenario.java @@ -257,15 +257,15 @@ public class CliScenario extends SAPIScenario { "zend/tests/multibyte/multibyte_encoding_002.phpt" ); @Override - public boolean willSkip(ConsoleManager cm, ITestResultReceiver twriter, AHost host, ScenarioSetSetup setup, ESAPIType type, PhpBuild build, PhptTestCase test_case) throws Exception { - if (super.willSkip(cm, twriter, host, setup, type, build, test_case)) { + public boolean willSkip(ConsoleManager cm, ITestResultReceiver twriter, AHost host, ScenarioSetSetup setup, ESAPIType type, PhpBuild build, PhptSourceTestPack src_test_pack, PhptTestCase test_case) throws Exception { + if (super.willSkip(cm, twriter, host, setup, type, build, src_test_pack, test_case)) { return true; } else if (cm.isDisableDebugPrompt()&&test_case.isNamed(DISABLE_DEBUG_PROMPT)) { - twriter.addResult(host, setup, new PhptTestResult(host, EPhptTestStatus.XSKIP, test_case, "test sometimes randomly fails, ignore it")); + twriter.addResult(host, setup, src_test_pack, new PhptTestResult(host, EPhptTestStatus.XSKIP, test_case, "test sometimes randomly fails, ignore it")); return true; } else if (test_case.isNamed(RANDOMLY_FAIL)) { - twriter.addResult(host, setup, new PhptTestResult(host, EPhptTestStatus.XSKIP, test_case, "test sometimes randomly fails, ignore it")); + twriter.addResult(host, setup, src_test_pack, new PhptTestResult(host, EPhptTestStatus.XSKIP, test_case, "test sometimes randomly fails, ignore it")); return true; } diff --git a/src/com/mostc/pftt/scenario/EnchantScenario.java b/src/com/mostc/pftt/scenario/EnchantScenario.java index 72fece7..e995246 100644 --- a/src/com/mostc/pftt/scenario/EnchantScenario.java +++ b/src/com/mostc/pftt/scenario/EnchantScenario.java @@ -25,6 +25,7 @@ public class EnchantScenario extends INIScenario { // this is only needed for Windows try { + // LATER php on non-windows may need a dictionary too ?? String dst = build.getBuildPath()+"/share/"; if (!host.exists(dst)) { host.copyElevated(host.getPfttDir()+"/cache/util/enchant/share", dst); @@ -37,7 +38,7 @@ public class EnchantScenario extends INIScenario { return SETUP_SUCCESS; } catch ( Exception ex ) { cm.addGlobalException(EPrintType.CANT_CONTINUE, getClass(), "setup", ex, "Unable to install spell checker dictionary"); - return null; + return SETUP_FAILED; } } diff --git a/src/com/mostc/pftt/scenario/IISScenario.java b/src/com/mostc/pftt/scenario/IISScenario.java index 6ad4745..91ea26d 100644 --- a/src/com/mostc/pftt/scenario/IISScenario.java +++ b/src/com/mostc/pftt/scenario/IISScenario.java @@ -3,9 +3,13 @@ package com.mostc.pftt.scenario; import java.util.Collection; import com.mostc.pftt.host.AHost; +import com.mostc.pftt.model.core.ESAPIType; import com.mostc.pftt.model.core.PhpBuild; +import com.mostc.pftt.model.core.PhptSourceTestPack; +import com.mostc.pftt.model.core.PhptTestCase; import com.mostc.pftt.model.sapi.IISManager; import com.mostc.pftt.results.ConsoleManager; +import com.mostc.pftt.results.ITestResultReceiver; /** Abstract scenario for managing and testing IIS * @@ -20,8 +24,16 @@ public abstract class IISScenario extends ProductionWebServerScenario { } @Override + public boolean willSkip(ConsoleManager cm, ITestResultReceiver twriter, AHost host, ScenarioSetSetup setup, ESAPIType type, PhpBuild build, PhptSourceTestPack src_test_pack, PhptTestCase test_case) throws Exception { + if (!IISManager.isSupported(cm, twriter, host, setup, build, src_test_pack, test_case)) { + return false; + } + return super.willSkip(cm, twriter, host, setup, type, build, src_test_pack, test_case); + } + + @Override public void addToDebugPath(ConsoleManager cm, AHost host, PhpBuild build, Collection<String> debug_path) { - + ((IISManager)smgr).addToDebugPath(cm, host, build, debug_path); } @Override diff --git a/src/com/mostc/pftt/scenario/RemoteFileSystemScenario.java b/src/com/mostc/pftt/scenario/RemoteFileSystemScenario.java index 1a44721..fff41a9 100644 --- a/src/com/mostc/pftt/scenario/RemoteFileSystemScenario.java +++ b/src/com/mostc/pftt/scenario/RemoteFileSystemScenario.java @@ -2,10 +2,10 @@ package com.mostc.pftt.scenario; import com.github.mattficken.io.Trie; import com.mostc.pftt.host.AHost; -import com.mostc.pftt.host.Host; import com.mostc.pftt.model.core.EPhptTestStatus; import com.mostc.pftt.model.core.ESAPIType; import com.mostc.pftt.model.core.PhpBuild; +import com.mostc.pftt.model.core.PhptSourceTestPack; import com.mostc.pftt.model.core.PhptTestCase; import com.mostc.pftt.results.ConsoleManager; import com.mostc.pftt.results.ITestResultReceiver; @@ -35,9 +35,9 @@ public abstract class RemoteFileSystemScenario extends FileSystemScenario { "ext/standard/tests/file/windows_links/bug48746_3.phpt" ); @Override - public boolean willSkip(ConsoleManager cm, ITestResultReceiver twriter, AHost host, ScenarioSetSetup setup, ESAPIType type, PhpBuild build, PhptTestCase test_case) throws Exception { + public boolean willSkip(ConsoleManager cm, ITestResultReceiver twriter, AHost host, ScenarioSetSetup setup, ESAPIType type, PhpBuild build, PhptSourceTestPack src_test_pack, PhptTestCase test_case) throws Exception { if (test_case.isNamed(LOCAL_FS_ONLY_TESTS)) { - twriter.addResult(host, setup, new PhptTestResult(host, EPhptTestStatus.XSKIP, test_case, "Not supported on Remote File Systems", null, null, null, null, null, null, null, null, null, null, null)); + twriter.addResult(host, setup, src_test_pack, new PhptTestResult(host, EPhptTestStatus.XSKIP, test_case, "Not supported on Remote File Systems", null, null, null, null, null, null, null, null, null, null, null)); return true; } diff --git a/src/com/mostc/pftt/scenario/SAPIScenario.java b/src/com/mostc/pftt/scenario/SAPIScenario.java index 575a8e7..4198105 100644 --- a/src/com/mostc/pftt/scenario/SAPIScenario.java +++ b/src/com/mostc/pftt/scenario/SAPIScenario.java @@ -189,11 +189,11 @@ public abstract class SAPIScenario extends AbstractSerialScenario { public static Trie SCENARIO_EXTS = PhptTestCase.createExtensions("dba", "sybase", "snmp", "interbase", "ldap", "imap", "oci8", "pcntl", "soap", "xmlrpc", "pdo", "odbc", "pdo_mssql", "mssql", "pdo_pgsql", "sybase_ct", "ftp", "curl"); @Override - public boolean willSkip(ConsoleManager cm, ITestResultReceiver twriter, AHost host, ScenarioSetSetup setup, ESAPIType type, PhpBuild build, PhptTestCase test_case) throws Exception { + public boolean willSkip(ConsoleManager cm, ITestResultReceiver twriter, AHost host, ScenarioSetSetup setup, ESAPIType type, PhpBuild build, PhptSourceTestPack src_test_pack, PhptTestCase test_case) throws Exception { if (host.isWindows()) { if (test_case.isExtension(NON_WINDOWS_EXTS)) { // extensions not supported on Windows - twriter.addResult(host, setup, new PhptTestResult(host, EPhptTestStatus.XSKIP, test_case, "OS not supported", null, null, null, null, null, null, null, null, null, null, null)); + twriter.addResult(host, setup, src_test_pack, new PhptTestResult(host, EPhptTestStatus.XSKIP, test_case, "OS not supported", null, null, null, null, null, null, null, null, null, null, null)); return true; } @@ -202,36 +202,36 @@ public abstract class SAPIScenario extends AbstractSerialScenario { // skip windows specific tests if host is not windows // do an early quick check... also fixes problem with sapi/cli/tests/021.phpt - twriter.addResult(host, setup, new PhptTestResult(host, EPhptTestStatus.XSKIP, test_case, "OS not supported", null, null, null, null, null, null, null, null, null, null, null)); + twriter.addResult(host, setup, src_test_pack, new PhptTestResult(host, EPhptTestStatus.XSKIP, test_case, "OS not supported", null, null, null, null, null, null, null, null, null, null, null)); return true; } if (build.is53(cm, host)) { if (test_case.isNamed(TESTS53)) { - twriter.addResult(host, setup, new PhptTestResult(host, EPhptTestStatus.XSKIP, test_case, "test sometimes randomly fails, ignore it", null, null, null, null, null, null, null, null, null, null, null)); + twriter.addResult(host, setup, src_test_pack, new PhptTestResult(host, EPhptTestStatus.XSKIP, test_case, "test sometimes randomly fails, ignore it", null, null, null, null, null, null, null, null, null, null, null)); return true; } } // TODO || ? if (test_case.containsSection(EPhptSection.REQUEST)||test_case.isNamed(RANDOMLY_FAIL)) { - twriter.addResult(host, setup, new PhptTestResult(host, EPhptTestStatus.XSKIP, test_case, "test sometimes randomly fails, ignore it", null, null, null, null, null, null, null, null, null, null, null)); + twriter.addResult(host, setup, src_test_pack, new PhptTestResult(host, EPhptTestStatus.XSKIP, test_case, "test sometimes randomly fails, ignore it", null, null, null, null, null, null, null, null, null, null, null)); return true; } else if (test_case.isExtension(SCENARIO_EXTS)) { // TODO don't run these SKIPIFs without the scenario loaded - twriter.addResult(host, setup, new PhptTestResult(host, EPhptTestStatus.SKIP, test_case, "test would've been skipped", null, null, null, null, null, null, null, null, null, null, null)); + twriter.addResult(host, setup, src_test_pack, new PhptTestResult(host, EPhptTestStatus.SKIP, test_case, "test would've been skipped", null, null, null, null, null, null, null, null, null, null, null)); return true; } return false; } // end public boolean willSkip - public boolean willSkip(ConsoleManager cm, ITestResultReceiver twriter, AHost host, ScenarioSetSetup scenario_set_setup, ESAPIType type, PhpIni ini, PhpBuild build, PhptTestCase test_case) throws Exception { + public boolean willSkip(ConsoleManager cm, ITestResultReceiver twriter, AHost host, ScenarioSetSetup scenario_set_setup, ESAPIType type, PhpIni ini, PhpBuild build, PhptSourceTestPack src_test_pack, PhptTestCase test_case) throws Exception { if (test_case.isExtensionTest() && !build.isExtensionEnabled(cm, host, type, ini, test_case.getExtensionName())) { // if extension-under-test is not loaded, don't bother running test since it'll just be skipped (or false fail) - twriter.addResult(host, scenario_set_setup, new PhptTestResult(host, EPhptTestStatus.SKIP, test_case, "Extension not loaded", null, null, null, ini, null, null, null, null, null, null, null)); + twriter.addResult(host, scenario_set_setup, src_test_pack, new PhptTestResult(host, EPhptTestStatus.SKIP, test_case, "Extension not loaded", null, null, null, ini, null, null, null, null, null, null, null)); return true; } diff --git a/src/com/mostc/pftt/scenario/Scenario.java b/src/com/mostc/pftt/scenario/Scenario.java index 4297f18..a0b0492 100644 --- a/src/com/mostc/pftt/scenario/Scenario.java +++ b/src/com/mostc/pftt/scenario/Scenario.java @@ -12,6 +12,7 @@ import com.mostc.pftt.host.AHost; import com.mostc.pftt.host.Host; import com.mostc.pftt.model.core.ESAPIType; import com.mostc.pftt.model.core.PhpBuild; +import com.mostc.pftt.model.core.PhptSourceTestPack; import com.mostc.pftt.model.core.PhptTestCase; import com.mostc.pftt.results.ConsoleManager; import com.mostc.pftt.results.ITestResultReceiver; @@ -38,7 +39,7 @@ import com.mostc.pftt.results.ITestResultReceiver; public abstract class Scenario { @Overridable - public boolean willSkip(ConsoleManager cm, ITestResultReceiver twriter, AHost host, ScenarioSetSetup setup, ESAPIType type, PhpBuild build, PhptTestCase test_case) throws Exception { + public boolean willSkip(ConsoleManager cm, ITestResultReceiver twriter, AHost host, ScenarioSetSetup setup, ESAPIType type, PhpBuild build, PhptSourceTestPack src_test_pack, PhptTestCase test_case) throws Exception { return false; } diff --git a/src/com/mostc/pftt/scenario/UserCacheScenario.java b/src/com/mostc/pftt/scenario/UserCacheScenario.java index f96a4eb..b7b3d28 100644 --- a/src/com/mostc/pftt/scenario/UserCacheScenario.java +++ b/src/com/mostc/pftt/scenario/UserCacheScenario.java @@ -1,7 +1,7 @@ package com.mostc.pftt.scenario; public abstract class UserCacheScenario extends INIScenario { - public static final WinCacheUScenario WINCACHEU = new WinCacheUScenario(); + public static final WinCacheUScenario WINCACHEU = new WinCacheU_FileAndUserCacheScenario(); public static final NoUserCacheScenario NO = new NoUserCacheScenario(); public static final APCUScenario APCU = new APCUScenario(); diff --git a/src/com/mostc/pftt/scenario/WebServerScenario.java b/src/com/mostc/pftt/scenario/WebServerScenario.java index a37bbed..2ef8f60 100644 --- a/src/com/mostc/pftt/scenario/WebServerScenario.java +++ b/src/com/mostc/pftt/scenario/WebServerScenario.java @@ -118,7 +118,7 @@ public abstract class WebServerScenario extends SAPIScenario { public TestCaseGroupKey createTestGroupKey(ConsoleManager cm, AHost host, PhpBuild build, ScenarioSetSetup scenario_set_setup, PhptActiveTestPack active_test_pack, PhptTestCase test_case, IENVINIFilter filter, TestCaseGroupKey group_key) throws Exception { Map<String,String> env = null; // ENV vars will be passed to web server manager to wrap the web server in when its executed - if (true) {// TODO temp 6/15 - test_case.containsSection(EPhptSection.ENV)) { + if (scenario_set_setup.hasENV() || test_case.containsSection(EPhptSection.ENV)) { env = AbstractPhptTestCaseRunner.generateENVForTestCase(cm, host, build, scenario_set_setup, test_case); // for most test cases, env will be null|empty, so the TestCaseGroupKey will match (assuming PhpInis match) @@ -156,27 +156,27 @@ public abstract class WebServerScenario extends SAPIScenario { } @Override - public boolean willSkip(ConsoleManager cm, ITestResultReceiver twriter, AHost host, ScenarioSetSetup setup, ESAPIType type, PhpBuild build, PhptTestCase test_case) throws Exception { - if (super.willSkip(cm, twriter, host, setup, type, build, test_case)) { + public boolean willSkip(ConsoleManager cm, ITestResultReceiver twriter, AHost host, ScenarioSetSetup setup, ESAPIType type, PhpBuild build, PhptSourceTestPack src_test_pack, PhptTestCase test_case) throws Exception { + if (super.willSkip(cm, twriter, host, setup, type, build, src_test_pack, test_case)) { return true; } else if (test_case.containsSection(EPhptSection.STDIN)) { - twriter.addResult(host, setup, new PhptTestResult(host, EPhptTestStatus.XSKIP, test_case, "STDIN section not supported for testing against web servers")); + twriter.addResult(host, setup, src_test_pack, new PhptTestResult(host, EPhptTestStatus.XSKIP, test_case, "STDIN section not supported for testing against web servers")); return true; } else if (test_case.containsSection(EPhptSection.ARGS)) { - twriter.addResult(host, setup, new PhptTestResult(host, EPhptTestStatus.XSKIP, test_case, "ARGS section not supported for testing against web servers")); + twriter.addResult(host, setup, src_test_pack, new PhptTestResult(host, EPhptTestStatus.XSKIP, test_case, "ARGS section not supported for testing against web servers")); return true; } else if (cm.isDisableDebugPrompt()&&test_case.isNamed(BLOCKING_WINPOPUP)) { - twriter.addResult(host, setup, new PhptTestResult(host, EPhptTestStatus.XSKIP, test_case, "test shows blocking winpopup msg")); + twriter.addResult(host, setup, src_test_pack, new PhptTestResult(host, EPhptTestStatus.XSKIP, test_case, "test shows blocking winpopup msg")); return true; } else if (test_case.isNamed(NOT_VALID_ON_WEB_SERVERS)) { - twriter.addResult(host, setup, new PhptTestResult(host, EPhptTestStatus.XSKIP, test_case, "test is not valid on web servers")); + twriter.addResult(host, setup, src_test_pack, new PhptTestResult(host, EPhptTestStatus.XSKIP, test_case, "test is not valid on web servers")); return true; } else if (host.isWindows() && test_case.isNamed(NOT_VALID_ON_WEB_SERVERS_WINDOWS)) { - twriter.addResult(host, setup, new PhptTestResult(host, EPhptTestStatus.XSKIP, test_case, "test is not valid on web servers")); + twriter.addResult(host, setup, src_test_pack, new PhptTestResult(host, EPhptTestStatus.XSKIP, test_case, "test is not valid on web servers")); return true; } else { @@ -207,6 +207,8 @@ public abstract class WebServerScenario extends SAPIScenario { public static Trie NOT_VALID_ON_WEB_SERVERS = PhptTestCase.createNamed( // XXX this test crashes on apache b/c the stack size is too small (see #setStackSize in ApacheManager) "ext/pcre/tests/bug47662.phpt", + // PHP outputs some of expected output in its log only + "zend/tests/bug64720.phpt", // fpassthru() system() and exec() doesn't run on Apache "ext/standard/tests/popen_pclose_basic-win32.phpt", "sapi/cli/tests/bug61546.phpt", diff --git a/src/com/mostc/pftt/util/ValgrindMemoryCheckManager.java b/src/com/mostc/pftt/util/ValgrindMemoryCheckManager.java index 68a04be..be952bf 100644 --- a/src/com/mostc/pftt/util/ValgrindMemoryCheckManager.java +++ b/src/com/mostc/pftt/util/ValgrindMemoryCheckManager.java @@ -91,11 +91,15 @@ public class ValgrindMemoryCheckManager extends DebuggerManager { @Override public ExecOutput execOut(RunRequest req) { req.setCommandline("valgrind --leak-check=yes "+req.getCommandline()); + + return null; // TODO temp } @Override public ExecHandle execThread(RunRequest req) { req.setCommandline("valgrind --leak-check=yes "+req.getCommandline()); + + return null; // TODO temp } }
« previous php.qa (#68369) next »