Commit:    c111e328b5d7006af11aea6b9d8b4dce94744d9a
Author:    Matt Ficken <v-maf...@microsoft.com>         Fri, 2 Aug 2013 
13:10:37 -0700
Parents:   71e2b172e09ca3ee7179d39c9d63df91eecb4dea
Branches:  master

Link:       
http://git.php.net/?p=pftt2.git;a=commitdiff;h=c111e328b5d7006af11aea6b9d8b4dce94744d9a

Log:
mysql scenario create temp datadir


Former-commit-id: ac7f535a16ed26872b6f8e47273477f21dd37ab8

Changed paths:
  M  conf/app/wordpress.groovy
  M  src/com/mostc/pftt/main/Config.java
  M  src/com/mostc/pftt/main/PfttMain.java
  M  src/com/mostc/pftt/model/app/DatabasePhpUnitSourceTestPack.java
  M  src/com/mostc/pftt/model/app/PhpUnitSourceTestPack.java
  M  src/com/mostc/pftt/model/app/PhpUnitTestCase.java
  M  src/com/mostc/pftt/model/sapi/IWebServerSetup.java
  M  src/com/mostc/pftt/model/sapi/SimpleWebServerSetup.java
  M  src/com/mostc/pftt/model/ui/UITestRunner.java
  M  src/com/mostc/pftt/results/AbstractReportGen.groovy
  M  src/com/mostc/pftt/results/PhpResultPack.java
  M  src/com/mostc/pftt/results/PhpResultPackReader.java
  M  src/com/mostc/pftt/results/PhpResultPackWriter.java
  M  src/com/mostc/pftt/results/PhptResultReader.java
  M  src/com/mostc/pftt/runner/LocalPhpUnitTestPackRunner.java
  M  src/com/mostc/pftt/runner/LocalPhptTestPackRunner.java
  M  src/com/mostc/pftt/scenario/APCScenario.java
  M  src/com/mostc/pftt/scenario/ApplicationScenario.java
  M  src/com/mostc/pftt/scenario/CodeCacheScenario.java
  M  src/com/mostc/pftt/scenario/DatabaseScenario.java
  M  src/com/mostc/pftt/scenario/EScenarioSetPermutationLayer.java
  M  src/com/mostc/pftt/scenario/FTPScenario.java
  M  src/com/mostc/pftt/scenario/FileSystemScenario.java
  M  src/com/mostc/pftt/scenario/HTTPScenario.java
  M  src/com/mostc/pftt/scenario/IMAPScenario.java
  M  src/com/mostc/pftt/scenario/IScenarioSetup.java
  M  src/com/mostc/pftt/scenario/LDAPScenario.java
  M  src/com/mostc/pftt/scenario/LocalFileSystemScenario.java
  M  src/com/mostc/pftt/scenario/MSAccessScenario.java
  M  src/com/mostc/pftt/scenario/MSSQLODBCScenario.java
  M  src/com/mostc/pftt/scenario/MSSQLScenario.java
  M  src/com/mostc/pftt/scenario/MySQLScenario.java
  M  src/com/mostc/pftt/scenario/NetworkedServiceScenario.java
  M  src/com/mostc/pftt/scenario/NoCodeCacheScenario.java
  M  src/com/mostc/pftt/scenario/NormalPathsScenario.java
  M  src/com/mostc/pftt/scenario/ODBCScenario.java
  M  src/com/mostc/pftt/scenario/OpcacheScenario.java
  M  src/com/mostc/pftt/scenario/OptionScenario.java
  M  src/com/mostc/pftt/scenario/PhpUnitInlineReferencesScenario.java
  M  src/com/mostc/pftt/scenario/PhpUnitReflectionOnlyScenario.java
  M  src/com/mostc/pftt/scenario/PhpUnitReflectionScenario.java
  M  src/com/mostc/pftt/scenario/PlainSocketScenario.java
  M  src/com/mostc/pftt/scenario/PostgresSQLScenario.java
  M  src/com/mostc/pftt/scenario/SMBCSCOptionScenario.java
  M  src/com/mostc/pftt/scenario/SMBScenario.java
  M  src/com/mostc/pftt/scenario/SOAPScenario.java
  M  src/com/mostc/pftt/scenario/SSLSocketScenario.java
  M  src/com/mostc/pftt/scenario/Scenario.java
  M  src/com/mostc/pftt/scenario/ScenarioSet.java
  M  src/com/mostc/pftt/scenario/ScenarioSetSetup.java
  M  src/com/mostc/pftt/scenario/SimpleScenarioSetup.java
  M  src/com/mostc/pftt/scenario/UNCPathsScenario.java
  M  src/com/mostc/pftt/scenario/WebServerScenario.java
  M  src/com/mostc/pftt/scenario/WinCacheScenario.java
  M  src/com/mostc/pftt/scenario/XMLRPCScenario.java
  M  src/com/mostc/pftt/scenario/app/HelloWorldScenario.groovy
  M  src/com/mostc/pftt/scenario/app/ZipApplication.java
  M  src/com/mostc/pftt/scenario/app/ZipDbApplication.java
  M  src/com/mostc/pftt/util/HostEnvUtil.java
  M  src/com/mostc/pftt/util/TimerUtil.java

diff --git a/conf/app/wordpress.groovy b/conf/app/wordpress.groovy
index 6b0f969..ff7dc84 100644
--- a/conf/app/wordpress.groovy
+++ b/conf/app/wordpress.groovy
@@ -89,17 +89,22 @@ class WordpressPhpUnitTestPack extends 
RequiredDatabasePhpUnitSourceTestPack {
                // experience has shown that using a separate database per 
thread is required to get consistent test results
                //
                //
+               final def db_host = database.getHostname();
+               final def db_port = database.getPort();
+               final def db_username = "wp_test";
+               final def db_password = "password01!";
                // drop and recreate it from the previous test
                // (in case previous test messed up the database ... happens 
using a single database and different table prefixes too)
-               database.createDatabaseWithUserReplaceOk(db_name, "wp_test", 
"password01!");
+               database.createDatabaseWithUserReplaceOk(db_name, db_username, 
db_password);
                
                
+               // important: specify the port number! database may be using a 
non-standard port number.
                def build_path = build.getPhpExe();
                return """
 define( 'DB_NAME', '$db_name' );
-define( 'DB_USER', 'wp_test' );
-define( 'DB_PASSWORD', 'password01!' );
-define( 'DB_HOST', 'localhost' );
+define( 'DB_USER', '$db_username' );
+define( 'DB_PASSWORD', '$db_password' );
+define( 'DB_HOST', '$db_host:$db_port' );
 define( 'WP_PHP_BINARY', '$build_path' );
 
 \$table_prefix  = 'wp_tests_';
diff --git a/src/com/mostc/pftt/main/Config.java 
b/src/com/mostc/pftt/main/Config.java
index 245edee..1cd19f6 100644
--- a/src/com/mostc/pftt/main/Config.java
+++ b/src/com/mostc/pftt/main/Config.java
@@ -313,7 +313,7 @@ public final class Config implements IENVINIFilter {
         */
        public List<ScenarioSet> getScenarioSets(ConsoleManager cm, 
EScenarioSetPermutationLayer layer) {
                if (layer==null)
-                       layer = EScenarioSetPermutationLayer.PHP_CORE; // 
fallback
+                       layer = 
EScenarioSetPermutationLayer.FUNCTIONAL_TEST_CORE; // fallback
                
                List<ScenarioSet> this_scenario_sets = 
permuted_scenario_sets.get(layer);
                if (this_scenario_sets!=null)
diff --git a/src/com/mostc/pftt/main/PfttMain.java 
b/src/com/mostc/pftt/main/PfttMain.java
index 820168f..584b5f4 100644
--- a/src/com/mostc/pftt/main/PfttMain.java
+++ b/src/com/mostc/pftt/main/PfttMain.java
@@ -58,6 +58,7 @@ import com.mostc.pftt.scenario.ScenarioSetSetup;
 import com.mostc.pftt.util.AlignedTable;
 import com.mostc.pftt.util.DownloadUtil;
 import com.mostc.pftt.util.HostEnvUtil;
+import com.mostc.pftt.util.TimerUtil;
 import com.mostc.pftt.util.WinDebugManager;
 import com.mostc.pftt.util.WindowsSnapshotDownloadUtil;
 import com.mostc.pftt.util.WindowsSnapshotDownloadUtil.FindBuildTestPackPair;
@@ -556,7 +557,7 @@ public class PfttMain {
                                cm.println(EPrintType.IN_PROGRESS, 
"PhpUnitSourceTestPack", "enumerated test cases.");
                                
                                
-                               for ( ScenarioSet scenario_set : 
getScenarioSets(config, EScenarioSetPermutationLayer.WEB_APPLICATION)) {
+                               for ( ScenarioSet scenario_set : 
getScenarioSets(config, 
EScenarioSetPermutationLayer.FUNCTIONAL_TEST_APPLICATION)) {
                                
                                        List<AHost> hosts = config.getHosts();
                                        AHost host = 
hosts.isEmpty()?this.host:hosts.get(0);
@@ -591,7 +592,7 @@ public class PfttMain {
                                
                                cm.println(EPrintType.CLUE, PfttMain.class, 
"Writing Result-Pack: "+tmgr.getResultPackPath());
                                
-                               for (ScenarioSet scenario_set : 
getScenarioSets(config, EScenarioSetPermutationLayer.WEB_APPLICATION)) {
+                               for (ScenarioSet scenario_set : 
getScenarioSets(config, 
EScenarioSetPermutationLayer.FUNCTIONAL_TEST_APPLICATION)) {
                                        List<AHost> hosts = config.getHosts();
                                        AHost host = 
hosts.isEmpty()?this.host:hosts.get(0);
                                        LocalPhpUnitTestPackRunner r = new 
LocalPhpUnitTestPackRunner(cm, tmgr, scenario_set, build, host, host);
@@ -614,7 +615,7 @@ public class PfttMain {
                        hosts.add(this.host);
                }
                for ( int i=0 ; i < cm.getRunTestPack() ; i++ ) {
-                       for ( ScenarioSet scenario_set : 
getScenarioSets(config, EScenarioSetPermutationLayer.PHP_CORE) ) {
+                       for ( ScenarioSet scenario_set : 
getScenarioSets(config, EScenarioSetPermutationLayer.FUNCTIONAL_TEST_CORE) ) {
                                if (!cm.isSkipSmokeTests()) {
                                        {
                                                // TODO test running PHPTs on a 
build that is missing a DLL that is
@@ -676,7 +677,7 @@ public class PfttMain {
                        hosts.add(this.host);
                }
                for ( int i=0 ; i < cm.getRunTestPack() ; i++ ) {
-                       for ( ScenarioSet scenario_set : 
getScenarioSets(config, EScenarioSetPermutationLayer.PHP_CORE) ) {
+                       for ( ScenarioSet scenario_set : 
getScenarioSets(config, EScenarioSetPermutationLayer.FUNCTIONAL_TEST_CORE) ) {
                                //
                                if (!cm.isSkipSmokeTests()) {
                                        {
@@ -1506,7 +1507,7 @@ public class PfttMain {
                                        // TODO open result-packs and process 
them
                                        
                                } else if 
(command.equals("app_named")||command.equals("appnamed")||command.equals("an")) 
{
-                                       checkUAC(is_uac, false, config, cm, 
EScenarioSetPermutationLayer.WEB_APPLICATION);
+                                       checkUAC(is_uac, false, config, cm, 
EScenarioSetPermutationLayer.FUNCTIONAL_TEST_APPLICATION);
                                        
                                        PhpBuild[] builds = newBuilds(cm, 
p.host, args[args_i+1]); 
                                        
@@ -1527,7 +1528,7 @@ public class PfttMain {
                                                return;
                                        }
                                        
-                                       checkUAC(is_uac, false, config, cm, 
EScenarioSetPermutationLayer.WEB_APPLICATION);
+                                       checkUAC(is_uac, false, config, cm, 
EScenarioSetPermutationLayer.FUNCTIONAL_TEST_APPLICATION);
                                        
                                        PhpBuild[] builds = newBuilds(cm, 
p.host, args[args_i+1]);
                                        
@@ -1549,7 +1550,7 @@ public class PfttMain {
                                                return;
                                        }
                                        
-                                       checkUAC(is_uac, false, config, cm, 
EScenarioSetPermutationLayer.WEB_APPLICATION);
+                                       checkUAC(is_uac, false, config, cm, 
EScenarioSetPermutationLayer.FUNCTIONAL_TEST_APPLICATION);
                                        
                                        PhpBuild[] builds = newBuilds(cm, 
p.host, args[args_i+1]);
                                        
@@ -1573,7 +1574,7 @@ public class PfttMain {
                                        }                               
                                        args_i += 3; // skip over build and 
test_pack
                                        
-                                       checkUAC(is_uac, false, config, cm, 
EScenarioSetPermutationLayer.PHP_CORE);
+                                       checkUAC(is_uac, false, config, cm, 
EScenarioSetPermutationLayer.FUNCTIONAL_TEST_CORE);
                                        
                                        // read name fragments from CLI 
arguments
                                        ArrayList<String> names = new 
ArrayList<String>(args.length-args_i);
@@ -1610,7 +1611,7 @@ public class PfttMain {
                                                return;
                                        }
                                        
-                                       checkUAC(is_uac, false, config, cm, 
EScenarioSetPermutationLayer.PHP_CORE);
+                                       checkUAC(is_uac, false, config, cm, 
EScenarioSetPermutationLayer.FUNCTIONAL_TEST_CORE);
                                        
                                        LinkedList<String> names = new 
LinkedList<String>();
                                        readStringListFromFile(names, 
list_file);
@@ -1635,7 +1636,7 @@ public class PfttMain {
                                        }
                                        
                                        cm.println(EPrintType.IN_PROGRESS, 
"Main", "Testing all PHPTs in test pack...");
-                                       checkUAC(is_uac, false, config, cm, 
EScenarioSetPermutationLayer.PHP_CORE);
+                                       checkUAC(is_uac, false, config, cm, 
EScenarioSetPermutationLayer.FUNCTIONAL_TEST_CORE);
                                        
                                        for ( PhpBuild build : builds )
                                                p.coreAll(build, test_pack, 
config, p.getWriter(build, test_pack));
@@ -1670,7 +1671,7 @@ public class PfttMain {
                                                        
cm.println(EPrintType.CLUE, "PfttMain", "Test not found: "+name);
                                                names.add(name);
                                        }
-                                       for ( ScenarioSet set : 
getScenarioSets(config, EScenarioSetPermutationLayer.PHP_CORE) ) {
+                                       for ( ScenarioSet set : 
getScenarioSets(config, EScenarioSetPermutationLayer.FUNCTIONAL_TEST_CORE) ) {
                                                if 
(!set.getName().equalsIgnoreCase("Local-FileSystem_CLI")) {
                                                        
cm.println(EPrintType.CANT_CONTINUE, "PfttMain", "run-tests.php only supports 
the Local-FileSystem_CLI ScenarioSet, not: "+set);
                                                        
cm.println(EPrintType.TIP, "PfttMain", "remove -c console option (so PFTT only 
tests Local-FileSystem_CLI) and try again");
@@ -1721,15 +1722,15 @@ public class PfttMain {
                                        
                                        PhpBuild build = newBuild(cm, p.host, 
args[args_i+1]);
                                        
-                                       checkUAC(is_uac, true, config, cm, 
EScenarioSetPermutationLayer.WEB_SERVER);
+                                       checkUAC(is_uac, true, config, cm, 
EScenarioSetPermutationLayer.PRODUCTION_OR_ALL_UP_TEST);
                                        
                                        PhpIni ini;
                                        ScenarioSetSetup scenario_set_setup;
-                                       for ( ScenarioSet set : 
getScenarioSets(config, EScenarioSetPermutationLayer.WEB_SERVER) ) {
+                                       for ( ScenarioSet set : 
getScenarioSets(config, EScenarioSetPermutationLayer.PRODUCTION_OR_ALL_UP_TEST) 
) {
                                                ini = 
RequiredExtensionsSmokeTest.createDefaultIniCopy(cm, p.host, build);
                                                INIScenario.setupScenarios(cm, 
p.host, set, build, ini);
                                                
-                                               scenario_set_setup = 
ScenarioSetSetup.setupScenarioSet(cm, p.host, build, set, 
EScenarioSetPermutationLayer.WEB_SERVER);
+                                               scenario_set_setup = 
ScenarioSetSetup.setupScenarioSet(cm, p.host, build, set, 
EScenarioSetPermutationLayer.PRODUCTION_OR_ALL_UP_TEST);
                                                
                                                if (scenario_set_setup==null) {
                                                        
cm.println(EPrintType.CANT_CONTINUE, "Stop", "Error opening: "+set.getName());
@@ -1749,16 +1750,16 @@ public class PfttMain {
                                        
                                        PhpBuild build = newBuild(cm, p.host, 
args[args_i+1]);
                                        
-                                       checkUAC(is_uac, true, config, cm, 
EScenarioSetPermutationLayer.WEB_SERVER);
+                                       checkUAC(is_uac, true, config, cm, 
EScenarioSetPermutationLayer.PRODUCTION_OR_ALL_UP_TEST);
                                        
                                        // setup all scenarios
                                        PhpIni ini;
-                                       for ( ScenarioSet set : 
getScenarioSets(config, EScenarioSetPermutationLayer.WEB_SERVER) ) {
+                                       for ( ScenarioSet set : 
getScenarioSets(config, EScenarioSetPermutationLayer.PRODUCTION_OR_ALL_UP_TEST) 
) {
                                                
                                                ini = 
RequiredExtensionsSmokeTest.createDefaultIniCopy(cm, p.host, build);
                                                INIScenario.setupScenarios(cm, 
p.host, set, build, ini);
                                                
-                                               
ScenarioSetSetup.setupScenarioSet(cm, p.host, build, set, 
EScenarioSetPermutationLayer.WEB_SERVER);
+                                               
ScenarioSetSetup.setupScenarioSet(cm, p.host, build, set, 
EScenarioSetPermutationLayer.PRODUCTION_OR_ALL_UP_TEST);
                                                
                                        }
                                } else if 
(command.equals("release_get")||command.equals("rgn")||command.equals("rgnew")||command.equals("rgnewest")||command.equals("rgp")||command.equals("rgprev")||command.equals("rgprevious")||command.equals("rg")||command.equals("rget"))
 {
@@ -1939,10 +1940,10 @@ public class PfttMain {
                                                // TODO install and configure 
wordpress
                                                w = p.getWriter(build);
                                                for ( UITestPack test_pack : 
test_packs ) {
-                                                       for ( ScenarioSet 
scenario_set : getScenarioSets(config, 
EScenarioSetPermutationLayer.WEB_APPLICATION) ) {
+                                                       for ( ScenarioSet 
scenario_set : getScenarioSets(config, 
EScenarioSetPermutationLayer.FUNCTIONAL_TEST_APPLICATION) ) {
                                                                for ( AHost 
host : hosts ) {
                                                                        // XXX 
move to separate class, method, etc...
-                                                                       
ScenarioSetSetup scenario_set_setup = ScenarioSetSetup.setupScenarioSet(cm, 
host, build, scenario_set, EScenarioSetPermutationLayer.WEB_APPLICATION);
+                                                                       
ScenarioSetSetup scenario_set_setup = ScenarioSetSetup.setupScenarioSet(cm, 
host, build, scenario_set, 
EScenarioSetPermutationLayer.FUNCTIONAL_TEST_APPLICATION);
                                                                        if 
(scenario_set_setup==null)
                                                                                
continue;
                                                                        
@@ -2012,9 +2013,7 @@ public class PfttMain {
                //
                // if not:
                // wait 30 seconds for shutdown hooks, etc... then halt for sure
-               try {
-                       Thread.sleep(30000);
-               } catch ( InterruptedException ex ) {}
+               TimerUtil.trySleepSeconds(30);
                System.out.println("PFTT: exiting...");
                Runtime.getRuntime().halt(0);
        }
diff --git a/src/com/mostc/pftt/model/app/DatabasePhpUnitSourceTestPack.java 
b/src/com/mostc/pftt/model/app/DatabasePhpUnitSourceTestPack.java
index 7ed84df..d7c535f 100644
--- a/src/com/mostc/pftt/model/app/DatabasePhpUnitSourceTestPack.java
+++ b/src/com/mostc/pftt/model/app/DatabasePhpUnitSourceTestPack.java
@@ -6,6 +6,7 @@ import com.mostc.pftt.model.core.PhpBuild;
 import com.mostc.pftt.results.ConsoleManager;
 import com.mostc.pftt.results.EPrintType;
 import com.mostc.pftt.scenario.DatabaseScenario;
+import com.mostc.pftt.scenario.EScenarioSetPermutationLayer;
 import com.mostc.pftt.scenario.DatabaseScenario.DatabaseScenarioSetup;
 import com.mostc.pftt.scenario.ScenarioSet;
 
@@ -30,7 +31,7 @@ public abstract class DatabasePhpUnitSourceTestPack extends 
PhpUnitSourceTestPac
                        return handleNoDatabaseScenario(cm);
                }
                
-               database = ds.setup(cm, runner_host, build, scenario_set);
+               database = ds.setup(cm, runner_host, build, scenario_set, 
EScenarioSetPermutationLayer.FUNCTIONAL_TEST_APPLICATION);
                if (database==null) {
                        cm.println(EPrintType.CANT_CONTINUE, getClass(), "Could 
not setup database scenario");
                        return handleNoDatabaseScenario(cm);
diff --git a/src/com/mostc/pftt/model/app/PhpUnitSourceTestPack.java 
b/src/com/mostc/pftt/model/app/PhpUnitSourceTestPack.java
index b9930cc..4e5facc 100644
--- a/src/com/mostc/pftt/model/app/PhpUnitSourceTestPack.java
+++ b/src/com/mostc/pftt/model/app/PhpUnitSourceTestPack.java
@@ -7,6 +7,7 @@ import java.lang.ref.SoftReference;
 import java.util.ArrayList;
 import java.util.Collections;
 import java.util.Comparator;
+import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
 
@@ -202,6 +203,15 @@ public abstract class PhpUnitSourceTestPack implements 
SourceTestPack<PhpUnitAct
                doRead(config, cm, test_cases, names);
        }
        
+       protected static void copyTestsNoDuplicates(List<PhpUnitTestCase> src, 
List<PhpUnitTestCase> dst) {
+               // multiple PhpUnitDist files may reference the same tests, 
just run(load) each one time
+               final HashMap<String,PhpUnitTestCase> by_name = new 
HashMap<String,PhpUnitTestCase>();
+               for ( PhpUnitTestCase test_case : src )
+                       by_name.put(test_case.getName(), test_case);
+               dst.clear(); // TODO temp? prevents enumerating each test twice
+               dst.addAll(by_name.values());
+       }
+       
        /** reads all the PhpUnitTestCases from this test-pack
         * 
         * @param config
@@ -218,17 +228,17 @@ public abstract class PhpUnitSourceTestPack implements 
SourceTestPack<PhpUnitAct
                if (_ref_test_cases!=null) {
                        _test_cases = _ref_test_cases.get();
                        if (_test_cases!=null) {
-                               test_cases.addAll(_test_cases);
+                               copyTestsNoDuplicates(_test_cases, test_cases);
                                return;
                        }
                }
                //
                
-               doRead(config, cm, test_cases, null);
+               _test_cases = new ArrayList<PhpUnitTestCase>(3500);
+               doRead(config, cm, _test_cases, null);
                
                // cache for future use
-               _test_cases = new ArrayList<PhpUnitTestCase>(test_cases.size());
-               _test_cases.addAll(test_cases);
+               copyTestsNoDuplicates(_test_cases, test_cases);
                _ref_test_cases = new 
SoftReference<ArrayList<PhpUnitTestCase>>(_test_cases);
                //
        }
diff --git a/src/com/mostc/pftt/model/app/PhpUnitTestCase.java 
b/src/com/mostc/pftt/model/app/PhpUnitTestCase.java
index e1a6f0a..c2905a4 100644
--- a/src/com/mostc/pftt/model/app/PhpUnitTestCase.java
+++ b/src/com/mostc/pftt/model/app/PhpUnitTestCase.java
@@ -121,6 +121,21 @@ public class PhpUnitTestCase extends TestCase {
                return getName();
        }
        
+       @Override
+       public boolean equals(Object o) {
+               if (o==this)
+                       return true;
+               else if (o instanceof PhpUnitTestCase) 
+                       return o.toString().equals(this.toString());
+               else
+                       return false;
+       }
+       
+       @Override
+       public int hashCode() {
+               return getName().hashCode();
+       }
+       
        /** fixes slashes to Posix forward slash /.
         * 
         * this is case-preserving (to avoid breaking on posix). case is not 
changed.
diff --git a/src/com/mostc/pftt/model/sapi/IWebServerSetup.java 
b/src/com/mostc/pftt/model/sapi/IWebServerSetup.java
index ce720c3..4509bc7 100644
--- a/src/com/mostc/pftt/model/sapi/IWebServerSetup.java
+++ b/src/com/mostc/pftt/model/sapi/IWebServerSetup.java
@@ -6,4 +6,6 @@ public interface IWebServerSetup extends IScenarioSetup {
        public String getHostname();
        public int getPort();
        public String getRootURL();
+       @Override
+       public boolean isRunning();
 }
diff --git a/src/com/mostc/pftt/model/sapi/SimpleWebServerSetup.java 
b/src/com/mostc/pftt/model/sapi/SimpleWebServerSetup.java
index 0715071..7c5cd3e 100644
--- a/src/com/mostc/pftt/model/sapi/SimpleWebServerSetup.java
+++ b/src/com/mostc/pftt/model/sapi/SimpleWebServerSetup.java
@@ -9,4 +9,7 @@ public abstract class SimpleWebServerSetup extends 
SimpleScenarioSetup implement
                return "http://"+getHostname()+":"+getPort()+"/";
        }
        
+       @Override
+       public abstract boolean isRunning();
+       
 }
diff --git a/src/com/mostc/pftt/model/ui/UITestRunner.java 
b/src/com/mostc/pftt/model/ui/UITestRunner.java
index de3ebf0..65fe149 100644
--- a/src/com/mostc/pftt/model/ui/UITestRunner.java
+++ b/src/com/mostc/pftt/model/ui/UITestRunner.java
@@ -45,6 +45,7 @@ import com.mostc.pftt.scenario.EnchantScenario;
 import com.mostc.pftt.scenario.ScenarioSetSetup;
 import com.mostc.pftt.util.ErrorUtil;
 import com.mostc.pftt.util.StringUtil2;
+import com.mostc.pftt.util.TimerUtil;
 
 /** Runs a UI test-pack
  * 
@@ -1267,9 +1268,7 @@ public class UITestRunner implements IUITestBranch {
                                // important: make sure it got typed - part or 
all of value may be missing (may not have been typed)
                                if (StringUtil.equalsCS(value, getValue(we)))
                                        return true;
-                               try {
-                                       Thread.sleep(500);
-                               } catch ( InterruptedException ex ) {}
+                               TimerUtil.trySleepMillis(200);
                        }
                        return true;
                }
diff --git a/src/com/mostc/pftt/results/AbstractReportGen.groovy 
b/src/com/mostc/pftt/results/AbstractReportGen.groovy
index 6f32c7e..def10c6 100644
--- a/src/com/mostc/pftt/results/AbstractReportGen.groovy
+++ b/src/com/mostc/pftt/results/AbstractReportGen.groovy
@@ -1,10 +1,14 @@
 package com.mostc.pftt.results
 
+import com.github.mattficken.io.IOUtil;
 import com.mostc.pftt.host.AHost;
 import com.mostc.pftt.model.core.EBuildBranch;
 
 abstract class AbstractReportGen { 
-       static int ABBREVIATED_MAX_LENGTH = 512*1024;
+       // don't send large email messages
+       // keep in mind: you're probably sending both an HTML and a text/plain 
copy,
+       // so the actual size of the mail message may be as much as double the 
size here
+       static int ABBREVIATED_MAX_LENGTH = IOUtil.HALF_MEGABYTE;
  
        abstract void run(ConsoleManager cm, boolean abbreviated);
        
diff --git a/src/com/mostc/pftt/results/PhpResultPack.java 
b/src/com/mostc/pftt/results/PhpResultPack.java
index 72dc4ed..a46ee7b 100644
--- a/src/com/mostc/pftt/results/PhpResultPack.java
+++ b/src/com/mostc/pftt/results/PhpResultPack.java
@@ -8,6 +8,7 @@ import com.mostc.pftt.model.app.PhpUnitSourceTestPack;
 import com.mostc.pftt.model.core.EBuildBranch;
 import com.mostc.pftt.model.core.PhpBuildInfo;
 import com.mostc.pftt.model.ui.UITestPack;
+import com.mostc.pftt.scenario.ScenarioSet;
 import com.mostc.pftt.scenario.ScenarioSetSetup;
 
 /** Manages PHP test results (PHPT, PhpUnit, etc...)
@@ -73,8 +74,8 @@ public abstract class PhpResultPack {
        public abstract Collection<AbstractUITestRW> getUITest(String 
test_pack_name_and_version);
        public abstract PhpBuildInfo getBuildInfo();
        
-       public AbstractPhpUnitRW getPhpUnit(AHost host, PhpUnitSourceTestPack 
test_pack, ScenarioSetSetup scenario_set_setup) {
-               return getPhpUnit(host, test_pack.getNameAndVersionString(), 
scenario_set_setup);
+       public AbstractPhpUnitRW getPhpUnit(AHost host, PhpUnitSourceTestPack 
test_pack, ScenarioSetSetup scenario_set) {
+               return getPhpUnit(host, test_pack.getNameAndVersionString(), 
scenario_set);
        }
        public Collection<AbstractPhpUnitRW> getPhpUnit(AHost host, 
PhpUnitSourceTestPack test_pack) {
                return getPhpUnit(host, test_pack.getNameAndVersionString());
@@ -100,5 +101,11 @@ public abstract class PhpResultPack {
                else
                        return ret;
        }
+
+       public abstract Collection<AHost> getHosts();
+       public abstract Collection<String> getPhptTestPacks(AHost host);
+       public abstract Collection<ScenarioSet> getPhptScenarioSets(AHost host, 
String phpt_test_pack);
+       public abstract Collection<String> getPhpUnitTestPacks(AHost host);
+       public abstract Collection<ScenarioSet> getPhpUnitScenarioSets(AHost 
host, String phpunit_test_pack);
        
 } // end public abstract class PhpResultPack
diff --git a/src/com/mostc/pftt/results/PhpResultPackReader.java 
b/src/com/mostc/pftt/results/PhpResultPackReader.java
index 5e1bec2..6e483a9 100644
--- a/src/com/mostc/pftt/results/PhpResultPackReader.java
+++ b/src/com/mostc/pftt/results/PhpResultPackReader.java
@@ -6,9 +6,12 @@ import java.util.Collection;
 import java.util.HashMap;
 import java.util.LinkedList;
 
+import com.github.mattficken.io.ArrayUtil;
 import com.mostc.pftt.host.AHost;
+import com.mostc.pftt.host.SSHHost;
 import com.mostc.pftt.model.core.EBuildBranch;
 import com.mostc.pftt.model.core.PhpBuildInfo;
+import com.mostc.pftt.scenario.ScenarioSet;
 import com.mostc.pftt.scenario.ScenarioSetSetup;
 
 /** Reads result-pack of a test run completed in the past.
@@ -454,4 +457,56 @@ public class PhpResultPackReader extends PhpResultPack {
                return file;
        }
 
+       @Override
+       public Collection<AHost> getHosts() {
+               LinkedList<AHost> hosts = new LinkedList<AHost>();
+               for ( File f : file.listFiles() ) {
+                       if (f.isDirectory())
+                               hosts.add(new SSHHost(f.getName(), "", ""));
+               }
+               return hosts;
+       }
+
+       @Override
+       public Collection<String> getPhptTestPacks(AHost host) {
+               return ArrayUtil.toList(new File(file, new File(host.getName(), 
"PHPT").getName()).list());
+       }
+
+       @Override
+       public Collection<ScenarioSet> getPhptScenarioSets(AHost host, String 
phpt_test_pack) {
+               LinkedList<ScenarioSet> out = new LinkedList<ScenarioSet>();
+               for ( File f : new File(file, new File(host.getName(), new 
File("PHPT", phpt_test_pack).getName()).getName()).listFiles() ) {
+                       if (f.isDirectory())
+                               out.add(ScenarioSet.parse(f.getName()));
+               }
+               return out;
+       }
+
+       @Override
+       public Collection<String> getPhpUnitTestPacks(AHost host) {
+               return ArrayUtil.toList(new File(file, new File(host.getName(), 
"PhpUnit").getName()).list());
+       }
+
+       @Override
+       public Collection<ScenarioSet> getPhpUnitScenarioSets(AHost host, 
String phpunit_test_pack) {
+               LinkedList<ScenarioSet> out = new LinkedList<ScenarioSet>();
+               for ( File f : new File(file, new File(host.getName(), new 
File("PhpUnit", phpunit_test_pack).getName()).getName()).listFiles() ) {
+                       if (f.isDirectory())
+                               out.add(ScenarioSet.parse(f.getName()));
+               }
+               return out;
+       }
+
+       public AbstractPhptRW getPHPT(AHost host, ScenarioSet scenario_set, 
String test_pack_name) {
+               return 
phpt_reader_map.get(host).get(scenario_set).get(test_pack_name);
+       }
+
+       public AbstractPhpUnitRW getPhpUnit(AHost host, String 
test_pack_name_and_version, ScenarioSet scenario_set) {
+               return 
php_unit_reader_map.get(host).get(test_pack_name_and_version).get(scenario_set);
+       }
+       
+       public AbstractUITestRW getUITest(AHost host, String 
test_pack_name_and_version, ScenarioSet scenario_set, String 
web_browser_name_and_version) {
+               return 
ui_test_reader_map.get(host).get(test_pack_name_and_version).get(scenario_set).get(web_browser_name_and_version);
+       }
+
 } // end public class PhpResultPackReader
diff --git a/src/com/mostc/pftt/results/PhpResultPackWriter.java 
b/src/com/mostc/pftt/results/PhpResultPackWriter.java
index 03320f0..2aedc7a 100644
--- a/src/com/mostc/pftt/results/PhpResultPackWriter.java
+++ b/src/com/mostc/pftt/results/PhpResultPackWriter.java
@@ -30,6 +30,7 @@ import com.mostc.pftt.model.ui.UITestPack;
 import com.mostc.pftt.scenario.ScenarioSet;
 import com.mostc.pftt.scenario.ScenarioSetSetup;
 import com.mostc.pftt.util.ErrorUtil;
+import com.mostc.pftt.util.TimerUtil;
 
 /** Writes the result-pack from a test run.
  * 
@@ -710,11 +711,8 @@ public class PhpResultPackWriter extends PhpResultPack 
implements ITestResultRec
                        results.add(new CloseQueueEntry());
                        if (block) {
                                while (!results.isEmpty()) {
-                                       try {
-                                               Thread.sleep(100);
-                                       } catch ( InterruptedException ex ) {
+                                       if (!TimerUtil.trySleepMillis(100))
                                                break;
-                                       }
                                }
                        }
                } else {
@@ -725,11 +723,8 @@ public class PhpResultPackWriter extends PhpResultPack 
implements ITestResultRec
        public void wait(AHost host, ScenarioSet scenario_set) {
                // TODO
                while (!results.isEmpty()) {
-                       try {
-                               Thread.sleep(100);
-                       } catch ( InterruptedException ex ) {
+                       if (!TimerUtil.trySleepMillis(100))
                                break;
-                       }
                }
        }
        
@@ -987,5 +982,47 @@ public class PhpResultPackWriter extends PhpResultPack 
implements ITestResultRec
                        ex.printStackTrace();
                }
        }
+
+       @Override
+       public Collection<AHost> getHosts() {
+               // TODO combine phpunit_writer_map and uitest_writer_map
+               return phpt_writer_map.keySet();
+       }
+
+       @Override
+       public Collection<String> getPhptTestPacks(AHost host) {
+               LinkedList<String> out = new LinkedList<String>();
+               for ( HashMap<String,PhptResultWriter> a : 
phpt_writer_map.get(host).values() ) {
+                       for ( String test_pack : a.keySet() ) {
+                               if (!out.contains(test_pack))
+                                       out.add(test_pack);
+                       }
+               }
+               return out;
+       }
+
+       @Override
+       public Collection<ScenarioSet> getPhptScenarioSets(AHost host, String 
phpt_test_pack) {
+               LinkedList<ScenarioSet> out = new LinkedList<ScenarioSet>();
+               for ( ScenarioSetSetup s : phpt_writer_map.get(host).keySet() ) 
{
+                       HashMap<String,PhptResultWriter> a = 
phpt_writer_map.get(host).get(s);
+                       if (a.equals(phpt_test_pack))
+                               out.add(s.getScenarioSet());
+               }
+               return out;
+       }
+
+       @Override
+       public Collection<String> getPhpUnitTestPacks(AHost host) {
+               return phpunit_writer_map.get(host).keySet();
+       }
+
+       @Override
+       public Collection<ScenarioSet> getPhpUnitScenarioSets(AHost host, 
String phpunit_test_pack) {
+               LinkedList<ScenarioSet> out = new LinkedList<ScenarioSet>();
+               for ( ScenarioSetSetup s : 
phpunit_writer_map.get(host).get(phpunit_test_pack).map.keySet() )
+                       out.add(s.getScenarioSet());
+               return out;
+       }
        
 } // end public class PhpResultPackWriter
diff --git a/src/com/mostc/pftt/results/PhptResultReader.java 
b/src/com/mostc/pftt/results/PhptResultReader.java
index 50038e6..40321e9 100644
--- a/src/com/mostc/pftt/results/PhptResultReader.java
+++ b/src/com/mostc/pftt/results/PhptResultReader.java
@@ -158,6 +158,7 @@ public class PhptResultReader extends AbstractPhptRW {
                        
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");
+                       e.test_names.remove("tests/lang/bug35176.phpt");
                }
                return e.test_names;
        }
diff --git a/src/com/mostc/pftt/runner/LocalPhpUnitTestPackRunner.java 
b/src/com/mostc/pftt/runner/LocalPhpUnitTestPackRunner.java
index 0ac64b5..5ee834c 100644
--- a/src/com/mostc/pftt/runner/LocalPhpUnitTestPackRunner.java
+++ b/src/com/mostc/pftt/runner/LocalPhpUnitTestPackRunner.java
@@ -225,7 +225,7 @@ public class LocalPhpUnitTestPackRunner extends 
AbstractLocalTestPackRunner<PhpU
 
        @Override
        public EScenarioSetPermutationLayer getScenarioSetPermutationLayer() {
-               return EScenarioSetPermutationLayer.WEB_APPLICATION;
+               return EScenarioSetPermutationLayer.FUNCTIONAL_TEST_APPLICATION;
        }
 
 } // end public class LocalPhpUnitTestPackRunner
diff --git a/src/com/mostc/pftt/runner/LocalPhptTestPackRunner.java 
b/src/com/mostc/pftt/runner/LocalPhptTestPackRunner.java
index 3ae4fa5..952bff7 100644
--- a/src/com/mostc/pftt/runner/LocalPhptTestPackRunner.java
+++ b/src/com/mostc/pftt/runner/LocalPhptTestPackRunner.java
@@ -247,7 +247,7 @@ public class LocalPhptTestPackRunner extends 
AbstractLocalTestPackRunner<PhptAct
 
        @Override
        public EScenarioSetPermutationLayer getScenarioSetPermutationLayer() {
-               return EScenarioSetPermutationLayer.PHP_CORE;
+               return EScenarioSetPermutationLayer.FUNCTIONAL_TEST_CORE;
        }
        
 } // end public class LocalPhptTestPackRunner
diff --git a/src/com/mostc/pftt/scenario/APCScenario.java 
b/src/com/mostc/pftt/scenario/APCScenario.java
index efdeec7..922e01f 100644
--- a/src/com/mostc/pftt/scenario/APCScenario.java
+++ b/src/com/mostc/pftt/scenario/APCScenario.java
@@ -42,7 +42,7 @@ public class APCScenario extends CodeCacheScenario {
        }
 
        @Override
-       public IScenarioSetup setup(ConsoleManager cm, Host host, PhpBuild 
build, ScenarioSet scenario_set) {
+       public IScenarioSetup setup(ConsoleManager cm, Host host, PhpBuild 
build, ScenarioSet scenario_set, EScenarioSetPermutationLayer layer) {
                return SETUP_FAILED;
        }
        
diff --git a/src/com/mostc/pftt/scenario/ApplicationScenario.java 
b/src/com/mostc/pftt/scenario/ApplicationScenario.java
index 0708f77..7c6c788 100644
--- a/src/com/mostc/pftt/scenario/ApplicationScenario.java
+++ b/src/com/mostc/pftt/scenario/ApplicationScenario.java
@@ -10,7 +10,7 @@ public abstract class ApplicationScenario extends 
AbstractSerialScenario {
        public boolean isPlaceholder(EScenarioSetPermutationLayer layer) {
                if (layer==null)
                        return true;
-               else if 
(layer==EScenarioSetPermutationLayer.WEB_APPLICATION||layer==EScenarioSetPermutationLayer.WEB_SERVER||layer==EScenarioSetPermutationLayer.USER_INTERFACE)
+               else if 
(layer==EScenarioSetPermutationLayer.FUNCTIONAL_TEST_APPLICATION||layer==EScenarioSetPermutationLayer.PRODUCTION_OR_ALL_UP_TEST)
                        return false;
                else
                        return true;
@@ -31,5 +31,5 @@ public abstract class ApplicationScenario extends 
AbstractSerialScenario {
        }
        
        @Override
-       public abstract IScenarioSetup setup(ConsoleManager cm, Host host, 
PhpBuild build, ScenarioSet scenario_set);
+       public abstract IScenarioSetup setup(ConsoleManager cm, Host host, 
PhpBuild build, ScenarioSet scenario_set, EScenarioSetPermutationLayer layer);
 }
diff --git a/src/com/mostc/pftt/scenario/CodeCacheScenario.java 
b/src/com/mostc/pftt/scenario/CodeCacheScenario.java
index dda3ac0..329c58c 100644
--- a/src/com/mostc/pftt/scenario/CodeCacheScenario.java
+++ b/src/com/mostc/pftt/scenario/CodeCacheScenario.java
@@ -22,5 +22,5 @@ public abstract class CodeCacheScenario extends INIScenario {
        public abstract boolean isSupported(ConsoleManager cm, Host host, 
PhpBuild build, ScenarioSet scenario_set);
        
        @Override
-       public abstract IScenarioSetup setup(ConsoleManager cm, Host host, 
PhpBuild build, ScenarioSet scenario_set);
+       public abstract IScenarioSetup setup(ConsoleManager cm, Host host, 
PhpBuild build, ScenarioSet scenario_set, EScenarioSetPermutationLayer layer);
 }
diff --git a/src/com/mostc/pftt/scenario/DatabaseScenario.java 
b/src/com/mostc/pftt/scenario/DatabaseScenario.java
index 78c7515..9cb9c0e 100644
--- a/src/com/mostc/pftt/scenario/DatabaseScenario.java
+++ b/src/com/mostc/pftt/scenario/DatabaseScenario.java
@@ -5,6 +5,7 @@ import java.sql.ResultSet;
 import java.sql.SQLException;
 import java.util.LinkedList;
 import java.util.Map;
+import java.util.Random;
 
 import com.github.mattficken.Overridable;
 import com.github.mattficken.io.StringUtil;
@@ -15,6 +16,7 @@ import com.mostc.pftt.model.core.PhpIni;
 import com.mostc.pftt.results.ConsoleManager;
 import com.mostc.pftt.results.EPrintType;
 import com.mostc.pftt.runner.AbstractPhpUnitTestCaseRunner;
+import com.mostc.pftt.util.TimerUtil;
 
 /** A Scenario that sets up a database service for (an) extension(s) to test.
  * 
@@ -24,24 +26,39 @@ import com.mostc.pftt.runner.AbstractPhpUnitTestCaseRunner;
 
 public abstract class DatabaseScenario extends NetworkedServiceScenario {
        protected final AHost host;
-       protected final int port;
        protected final String default_username, default_password;
        protected final LinkedList<DatabaseScenarioSetup> setups;
-       protected boolean server_started;
+       protected static final Object production_setup_lock = new Object();
+       protected DatabaseScenarioSetup production_setup;
        
-       public DatabaseScenario(AHost host, int port, String default_username, 
String default_password) {
+       public DatabaseScenario(AHost host, String default_username, String 
default_password) {
                this.host = host;
-               this.port = port;
-               // TODO  GRANT ALL ON *.* to root@'192.168.1.4' IDENTIFIED BY 
'your-root-password'; 
                this.default_username = default_username;
                this.default_password = default_password;
                
                setups = new LinkedList<DatabaseScenarioSetup>();
        }
        
+       public String getDefaultPassword() {
+               return default_password;
+       }
+       
+       public String getDefaultUsername() {
+               return default_username;
+       }
+       
        @Override
        public boolean isPlaceholder(EScenarioSetPermutationLayer layer) {
-               return true;
+               if (layer==null)
+                       return true;
+               switch(layer) {
+               case FUNCTIONAL_TEST_APPLICATION:
+               case FUNCTIONAL_TEST_DATABASE:
+               case PRODUCTION_OR_ALL_UP_TEST:
+                       return false;
+               default:
+                       return true;
+               }
        }
        
        @Override
@@ -53,10 +70,9 @@ public abstract class DatabaseScenario extends 
NetworkedServiceScenario {
        public Class<?> getSerialKey(EScenarioSetPermutationLayer layer) {
                switch(layer) {
                // IMPORTANT: when running a web application, it can only have 
1 database scenario
-               case WEB_APPLICATION:
-               case USER_INTERFACE:
-               case DATABASE:
-               case PERFORMANCE:
+               case FUNCTIONAL_TEST_APPLICATION:
+               case FUNCTIONAL_TEST_DATABASE:
+               case PRODUCTION_OR_ALL_UP_TEST:
                        return DatabaseScenario.class;
                default:
                        // whereas, when testing PHP Core, you can run multiple 
database scenarios at the same time (faster)
@@ -73,9 +89,6 @@ public abstract class DatabaseScenario extends 
NetworkedServiceScenario {
                return true;
        }
        
-       protected abstract boolean startServer();
-       protected abstract boolean stopServer();
-       
        protected abstract String getDriverClassName();
        
        protected boolean ensureDriverLoaded() {
@@ -88,26 +101,155 @@ public abstract class DatabaseScenario extends 
NetworkedServiceScenario {
                return false;
        }
        
-       protected synchronized boolean ensureServerStarted(ConsoleManager cm) {
-               //if (server_started)
-                       //return true;
-               
-               //return server_started = startServer();
-               startServer();
-               return true;
+       @Override
+       public DatabaseScenarioSetup setup(ConsoleManager cm, Host host, 
PhpBuild build, ScenarioSet scenario_set, EScenarioSetPermutationLayer layer) {
+               final boolean is_production_database_server = 
layer==EScenarioSetPermutationLayer.PRODUCTION_OR_ALL_UP_TEST;
+               if (is_production_database_server) {
+                       synchronized(production_setup_lock) {
+                               if (production_setup==null)
+                                       return production_setup;
+                               
+                               return production_setup = doSetup(cm, host, 
layer, is_production_database_server);
+                       }
+               } else {
+                       // reuse existing setup if one is currently running
+                       if (setups.size() > 0) {
+                               // randomly distribute
+                               Random r = new Random();
+                               DatabaseScenarioSetup s;
+                               for ( int attempts=0 ; attempts < 5 ; 
attempts++ ) {
+                                       synchronized (setups) {
+                                               if (setups.size()<1)
+                                                       break;
+                                               s = 
setups.get(r.nextInt(setups.size()));
+                                       }
+                                       if (s.isRunning()) {
+                                               cm.println(EPrintType.CLUE, 
getClass(), "Reusing existing MySQL server");
+                                               // TODO
+                                               ProxyDatabaseScenarioSetup p = 
new ProxyDatabaseScenarioSetup(s);
+                                               s.proxies.add(p);
+                                               return p;
+                                       }
+                               }
+                       }
+                       return doSetup(cm, host, layer, 
is_production_database_server);
+               }
        }
        
-       @Override
-       public DatabaseScenarioSetup setup(ConsoleManager cm, Host host, 
PhpBuild build, ScenarioSet scenario_set) {
-               DatabaseScenarioSetup setup = createScenarioSetup();
-               if 
(setup==null||!ensureServerStarted(cm)||!ensureDriverLoaded()||!setup.connect(cm))
+       protected class ProxyDatabaseScenarioSetup extends 
DatabaseScenarioSetup {
+               protected final DatabaseScenarioSetup r;
+               
+               public ProxyDatabaseScenarioSetup(DatabaseScenarioSetup r) {
+                       this.r = r;
+               }
+
+               @Override
+               public String getNameWithVersionInfo() {
+                       return r.getNameWithVersionInfo();
+               }
+               @Override
+               public String getName() {
+                       return r.getName();
+               }
+               @Override
+               protected boolean connect(ConsoleManager cm) {
+                       // doesn't get called
+                       return false;
+               }
+               @Override
+               protected boolean disconnect() {
+                       // don't call r.disconnect  ... r.close() will do that 
if/when it should
+                       return true; 
+               }
+               @Override
+               public boolean databaseExists(String db_name) {
+                       return r.databaseExists(db_name);
+               }
+               @Override
+               public boolean isRunning() {
+                       return r.isRunning();
+               }
+               @Override
+               protected boolean startServer(ConsoleManager cm, boolean 
is_production_database_server) {
+                       return false;
+               }
+               @Override
+               protected boolean stopServer(ConsoleManager cm, boolean 
is_production_database_server) {
+                       return false; // doesn't get called
+               }
+               @Override
+               public void prepareINI(ConsoleManager cm, AHost host, PhpBuild 
build, ScenarioSet scenario_set, PhpIni ini) {
+                       r.prepareINI(cm, host, build, scenario_set, ini);
+               }
+               @Override
+               public String getPdoDbType() {
+                       return r.getPdoDbType();
+               }
+               @Override
+               public String getPassword() {
+                       return r.getPassword();
+               }
+               @Override
+               public String getUsername() {
+                       return r.getUsername();
+               }
+               @Override
+               public String getHostname() {
+                       return r.getHostname();
+               }
+               @Override
+               public int getPort() {
+                       return r.getPort();
+               }
+               @Override
+               public String getDataSourceName() {
+                       return r.getDataSourceName();
+               }
+               @Override
+               public boolean dropDatabase(String db_name) {
+                       return r.dropDatabase(db_name);
+               }
+               @Override
+               public boolean createDatabase(String db_name) {
+                       return r.createDatabase(db_name);
+               }
+               @Override
+               public boolean createDatabaseWithUser(String db_name, String 
user, String password) {
+                       return r.createDatabaseWithUser(db_name, user, 
password);
+               }
+               @Override
+               public boolean createDatabaseReplaceOk(String db_name) {
+                       return r.createDatabaseReplaceOk(db_name);
+               }
+               @Override
+               public boolean createDatabaseWithUserReplaceOk(String db_name, 
String user, String password) {
+                       return r.createDatabaseWithUserReplaceOk(db_name, user, 
password);
+               }
+               @Override
+               public boolean execute(String sql) {
+                       return r.execute(sql);
+               }
+               @Override
+               public ResultSet executeQuery(String sql) {
+                       return r.executeQuery(sql);
+               }
+       } // end protected class ProxyDatabaseScenarioSetup
+       
+       protected DatabaseScenarioSetup doSetup(ConsoleManager cm, Host host, 
EScenarioSetPermutationLayer layer, boolean is_production_database_server) {
+               DatabaseScenarioSetup setup = 
createScenarioSetup(is_production_database_server);
+                       
+               if (setup==null||!setup.ensureServerStarted(cm, 
is_production_database_server)||!ensureDriverLoaded()||!setup.connect(cm))
                        return null;
                
+               
                for ( int i=0 ; i < 30 ; i++ ) {
                        setup.db_name = generateDatabaseName();
                        if (!setup.databaseExists(setup.db_name)) {
                                if (setup.createDatabase(setup.db_name)) {
                                        cm.println(EPrintType.CLUE, getClass(), 
"Created database: "+setup.db_name);
+                                       synchronized(setups) {
+                                               setups.add(setup);
+                                       }
                                        return setup;
                                }
                        }
@@ -122,30 +264,27 @@ public abstract class DatabaseScenario extends 
NetworkedServiceScenario {
                return "pftt_"+getName()+"_"+StringUtil.randomLettersStr(5, 10);
        }
        
-       public String getDefaultPassword() {
-               return default_password;
-       }
-       
-       public String getDefaultUsername() {
-               return default_username;
-       }
-       
-       public String getHostname() {
-               return host.isRemote() ? host.getAddress() : "127.0.0.1";
-       }
-       
-       public int getPort() {
-               return port;
-       }
-       
-       protected abstract DatabaseScenarioSetup createScenarioSetup();
+       protected abstract DatabaseScenarioSetup createScenarioSetup(boolean 
is_production_server);
        
        public abstract class DefaultDatabaseScenarioSetup extends 
DatabaseScenarioSetup {
                protected Connection connection;
+               protected int port;
                
                protected abstract Connection createConnection() throws 
SQLException;
                
                @Override
+               public boolean isRunning() {
+                       if (server_started && connection != null) {
+                               try {
+                                       return !connection.isClosed();
+                               } catch ( SQLException ex ) {
+                                       ex.printStackTrace();
+                               }
+                       }
+                       return false;
+               }
+               
+               @Override
                protected boolean connect(ConsoleManager cm) {
                        Exception ex_out = null;
                        for ( int i=0 ; i < 10 ; i++ ) {
@@ -182,22 +321,22 @@ public abstract class DatabaseScenario extends 
NetworkedServiceScenario {
                
                @Override
                public String getPassword() {
-                       return DatabaseScenario.this.getDefaultPassword();
+                       return DatabaseScenario.this.default_password;
                }
 
                @Override
                public String getUsername() {
-                       return DatabaseScenario.this.getDefaultUsername();
+                       return DatabaseScenario.this.default_username;
                }
                
                @Override
                public String getHostname() {
-                       return DatabaseScenario.this.getHostname();
+                       return host.getLocalhostListenAddress();
                }
                
                @Override
                public int getPort() {
-                       return DatabaseScenario.this.getPort();
+                       return port;
                }
                
                @Override
@@ -269,7 +408,9 @@ public abstract class DatabaseScenario extends 
NetworkedServiceScenario {
        }
        
        public abstract class DatabaseScenarioSetup extends SimpleScenarioSetup 
{
+               protected LinkedList<ProxyDatabaseScenarioSetup> proxies = new 
LinkedList<ProxyDatabaseScenarioSetup>();
                protected String db_name;
+               protected boolean server_started;
                
                protected abstract boolean connect(ConsoleManager cm);
                protected abstract boolean disconnect();
@@ -277,23 +418,59 @@ public abstract class DatabaseScenario extends 
NetworkedServiceScenario {
                public abstract boolean databaseExists(String db_name);
                
                @Override
+               public abstract boolean isRunning();
+               
+               protected boolean ensureServerStarted(ConsoleManager cm, 
boolean is_production_database_server) {
+                       if (!server_started && cm != null)
+                               cm.println(EPrintType.CLUE, getClass(), 
"Starting database server: "+getNameWithVersionInfo());
+                       return server_started = startServer(cm, 
is_production_database_server);
+               }
+               
+               protected abstract boolean startServer(ConsoleManager cm, 
boolean is_production_database_server);
+               protected abstract boolean stopServer(ConsoleManager cm, 
boolean is_production_database_server);
+               
+               private boolean close_called = false;
+               @Override
                public final synchronized void close(ConsoleManager cm) {
+                       if (this instanceof ProxyDatabaseScenarioSetup) {
+                               
synchronized(((ProxyDatabaseScenarioSetup)this).r.proxies) {
+                                       
((ProxyDatabaseScenarioSetup)this).r.proxies.remove(this);
+                               }
+                               // ask real to close (which it will do if this 
was the last proxy and it was already asked to close)
+                               ((ProxyDatabaseScenarioSetup)this).r.close(cm);
+                               return;
+                       }
+                       if (close_called && proxies.isEmpty()) {
+                               // now close
+                       } else if (!proxies.isEmpty()) {
+                               // wait for all proxies to be closed
+                               close_called = true;
+                               return;
+                       }
+                       
                        if 
(!(cm.isDebugAll()||cm.isDebugList()||cm.isPfttDebug())) {
-                               dropDatabase(db_name);
+                               new Thread() {
+                                               public void run() {
+                                                       dropDatabase(db_name);
+                                               }
+                                       }.start();
+                               TimerUtil.trySleepSeconds(2);
                        }
                        
-                       disconnect();
-                       setups.remove(this);
-                       if (setups.isEmpty()) {
-                               cm.println(EPrintType.IN_PROGRESS, getClass(), 
"Stopping database server...");
-                               if (stopServer()) {
-                                       server_started = false;
-                                       cm.println(EPrintType.CLUE, getClass(), 
"Stopped database server");
-                               } else {
-                                       server_started = true;
-                                       cm.println(EPrintType.CLUE, getClass(), 
"Failed to stop database server");
-                               }
+                       synchronized(setups) {
+                               setups.remove(this);
+                       }
+                       cm.println(EPrintType.IN_PROGRESS, getClass(), 
"Stopping database server...");
+                       if (stopServer(cm, production_setup == this)) {
+                               server_started = false;
+                               cm.println(EPrintType.CLUE, getClass(), 
"Stopped database server");
+                       } else {
+                               server_started = true;
+                               cm.println(EPrintType.CLUE, getClass(), "Failed 
to stop database server");
                        }
+                       // disconnect after stopping the server: sometimes the 
disconnect process can fail
+                       //      (sometimes tests really mess up the db server)
+                       disconnect();
                }
 
                @Override
diff --git a/src/com/mostc/pftt/scenario/EScenarioSetPermutationLayer.java 
b/src/com/mostc/pftt/scenario/EScenarioSetPermutationLayer.java
index 244e87b..96573e5 100644
--- a/src/com/mostc/pftt/scenario/EScenarioSetPermutationLayer.java
+++ b/src/com/mostc/pftt/scenario/EScenarioSetPermutationLayer.java
@@ -15,19 +15,19 @@ package com.mostc.pftt.scenario;
  */
 
 public enum EScenarioSetPermutationLayer {
-       USER_INTERFACE,
        /** running PhpUnit, etc... tests */
-       WEB_APPLICATION {
+       FUNCTIONAL_TEST_APPLICATION {
+               @Override
                public boolean reject(Scenario scenario) {
                        return scenario instanceof ApplicationScenario; // TODO 
for wordpress,symfony,joomla
                }
        },
        /** running PHPT tests against php.exe or php-cgi.exe */
-       PHP_CORE,
-       FILE_SYSTEM,
-       PERFORMANCE,
-       DATABASE,
-       WEB_SERVER;
+       FUNCTIONAL_TEST_CORE,
+       FUNCTIONAL_TEST_FILESYSTEM,
+       FUNCTIONAL_TEST_DATABASE,
+       FUNCTIONAL_TEST_WEBSERVER_ONLY,
+       PRODUCTION_OR_ALL_UP_TEST;
 
        public boolean reject(Scenario scenario) {
                return false;
diff --git a/src/com/mostc/pftt/scenario/FTPScenario.java 
b/src/com/mostc/pftt/scenario/FTPScenario.java
index 8b7f001..44d4848 100644
--- a/src/com/mostc/pftt/scenario/FTPScenario.java
+++ b/src/com/mostc/pftt/scenario/FTPScenario.java
@@ -23,7 +23,7 @@ public class FTPScenario extends StreamsScenario {
        }
        
        @Override
-       public IScenarioSetup setup(ConsoleManager cm, Host host, PhpBuild 
build, ScenarioSet scenario_set) {
+       public IScenarioSetup setup(ConsoleManager cm, Host host, PhpBuild 
build, ScenarioSet scenario_set, EScenarioSetPermutationLayer layer) {
                return null;
        }
 
diff --git a/src/com/mostc/pftt/scenario/FileSystemScenario.java 
b/src/com/mostc/pftt/scenario/FileSystemScenario.java
index 42cb01f..c9ff05f 100644
--- a/src/com/mostc/pftt/scenario/FileSystemScenario.java
+++ b/src/com/mostc/pftt/scenario/FileSystemScenario.java
@@ -83,6 +83,8 @@ public abstract class FileSystemScenario extends 
AbstractSerialScenario {
                public void close(ConsoleManager cm) {
                        
                }
+               @Override
+               public abstract boolean isRunning();
        }
        
        public abstract ITestPackStorageDir setup(ConsoleManager cm, Host host, 
PhpBuild build, ScenarioSet scenario_set);
diff --git a/src/com/mostc/pftt/scenario/HTTPScenario.java 
b/src/com/mostc/pftt/scenario/HTTPScenario.java
index 8fda475..b8d3de7 100644
--- a/src/com/mostc/pftt/scenario/HTTPScenario.java
+++ b/src/com/mostc/pftt/scenario/HTTPScenario.java
@@ -70,7 +70,7 @@ public class HTTPScenario extends StreamsScenario {
        }
 
        @Override
-       public IScenarioSetup setup(ConsoleManager cm, Host host, PhpBuild 
build, ScenarioSet scenario_set) {
+       public IScenarioSetup setup(ConsoleManager cm, Host host, PhpBuild 
build, ScenarioSet scenario_set, EScenarioSetPermutationLayer layer) {
                return new HTTPScenarioSetup();
        }
 
diff --git a/src/com/mostc/pftt/scenario/IMAPScenario.java 
b/src/com/mostc/pftt/scenario/IMAPScenario.java
index fe19ffd..ad4a617 100644
--- a/src/com/mostc/pftt/scenario/IMAPScenario.java
+++ b/src/com/mostc/pftt/scenario/IMAPScenario.java
@@ -4,7 +4,9 @@ import com.mostc.pftt.host.Host;
 import com.mostc.pftt.model.core.PhpBuild;
 import com.mostc.pftt.results.ConsoleManager;
 
-/** scenario for interacting with IMAP mail servers
+/** scenario for interacting with IMAP mail servers. (NOT IMPLEMENTED)
+ * 
+ * Use with Mail::IMAP PECL/PEAR package or `imap` extension (deprecated).
  * 
  * @author Matt Ficken
  *
@@ -23,7 +25,7 @@ public class IMAPScenario extends NetworkedServiceScenario {
        }
        
        @Override
-       public IScenarioSetup setup(ConsoleManager cm, Host host, PhpBuild 
build, ScenarioSet scenario_set) {
+       public IScenarioSetup setup(ConsoleManager cm, Host host, PhpBuild 
build, ScenarioSet scenario_set, EScenarioSetPermutationLayer layer) {
                return null;
        }
 
diff --git a/src/com/mostc/pftt/scenario/IScenarioSetup.java 
b/src/com/mostc/pftt/scenario/IScenarioSetup.java
index ac61b23..89fc0f4 100644
--- a/src/com/mostc/pftt/scenario/IScenarioSetup.java
+++ b/src/com/mostc/pftt/scenario/IScenarioSetup.java
@@ -16,4 +16,5 @@ public interface IScenarioSetup extends IClosable {
        public void setGlobals(Map<String, String> globals);
        public boolean hasENV();
        public void notifyScenarioSetSetup(ScenarioSetSetup setup);
+       public boolean isRunning();
 }
\ No newline at end of file
diff --git a/src/com/mostc/pftt/scenario/LDAPScenario.java 
b/src/com/mostc/pftt/scenario/LDAPScenario.java
index 40df4da..1f7f196 100644
--- a/src/com/mostc/pftt/scenario/LDAPScenario.java
+++ b/src/com/mostc/pftt/scenario/LDAPScenario.java
@@ -21,8 +21,8 @@ public class LDAPScenario extends NetworkedServiceScenario {
        }
        
        @Override
-       public IScenarioSetup setup(ConsoleManager cm, Host host, PhpBuild 
build, ScenarioSet scenario_set) {
-               return null;
+       public IScenarioSetup setup(ConsoleManager cm, Host host, PhpBuild 
build, ScenarioSet scenario_set, EScenarioSetPermutationLayer layer) {
+               return SETUP_FAILED;
        }
 
 }
diff --git a/src/com/mostc/pftt/scenario/LocalFileSystemScenario.java 
b/src/com/mostc/pftt/scenario/LocalFileSystemScenario.java
index 2e3cb80..3646052 100644
--- a/src/com/mostc/pftt/scenario/LocalFileSystemScenario.java
+++ b/src/com/mostc/pftt/scenario/LocalFileSystemScenario.java
@@ -21,6 +21,10 @@ public class LocalFileSystemScenario extends 
FileSystemScenario {
                                return true;
                        }
                        @Override
+                       public boolean isRunning() {
+                               return true;
+                       }
+                       @Override
                        public String getLocalPath(AHost host) {
                                return host.getPhpSdkDir();
                        }
diff --git a/src/com/mostc/pftt/scenario/MSAccessScenario.java 
b/src/com/mostc/pftt/scenario/MSAccessScenario.java
index e14c262..535052c 100644
--- a/src/com/mostc/pftt/scenario/MSAccessScenario.java
+++ b/src/com/mostc/pftt/scenario/MSAccessScenario.java
@@ -13,12 +13,12 @@ import com.mostc.pftt.host.AHost;
 
 public class MSAccessScenario extends ODBCScenario {
 
-       public MSAccessScenario(AHost host, int port, String default_username, 
String default_password) {
-               super(host, port, default_username, default_password);
+       public MSAccessScenario(AHost host, String default_username, String 
default_password) {
+               super(host, default_username, default_password);
        }
 
        @Override
-       protected DatabaseScenarioSetup createScenarioSetup() {
+       protected DatabaseScenarioSetup createScenarioSetup(boolean 
is_production_server) {
                return null;
        }
 
@@ -38,16 +38,4 @@ public class MSAccessScenario extends ODBCScenario {
                return null;
        }
 
-       @Override
-       protected boolean startServer() {
-               // TODO Auto-generated method stub
-               return false;
-       }
-
-       @Override
-       protected boolean stopServer() {
-               // TODO Auto-generated method stub
-               return false;
-       }
-       
 }
diff --git a/src/com/mostc/pftt/scenario/MSSQLODBCScenario.java 
b/src/com/mostc/pftt/scenario/MSSQLODBCScenario.java
index 05a96aa..a775a5f 100644
--- a/src/com/mostc/pftt/scenario/MSSQLODBCScenario.java
+++ b/src/com/mostc/pftt/scenario/MSSQLODBCScenario.java
@@ -16,12 +16,12 @@ import com.mostc.pftt.host.AHost;
 
 public class MSSQLODBCScenario extends ODBCScenario {
 
-       public MSSQLODBCScenario(AHost host, int port, String default_username, 
String default_password) {
-               super(host, port, default_username, default_password);
+       public MSSQLODBCScenario(AHost host, String default_username, String 
default_password) {
+               super(host, default_username, default_password);
        }
 
        @Override
-       protected DatabaseScenarioSetup createScenarioSetup() {
+       protected DatabaseScenarioSetup createScenarioSetup(boolean 
is_production_server) {
                return null;
        }
 
@@ -41,16 +41,4 @@ public class MSSQLODBCScenario extends ODBCScenario {
                return null;
        }
 
-       @Override
-       protected boolean startServer() {
-               // TODO Auto-generated method stub
-               return false;
-       }
-
-       @Override
-       protected boolean stopServer() {
-               // TODO Auto-generated method stub
-               return false;
-       }
-
 }
diff --git a/src/com/mostc/pftt/scenario/MSSQLScenario.java 
b/src/com/mostc/pftt/scenario/MSSQLScenario.java
index 82edbb2..0d43f89 100644
--- a/src/com/mostc/pftt/scenario/MSSQLScenario.java
+++ b/src/com/mostc/pftt/scenario/MSSQLScenario.java
@@ -10,12 +10,12 @@ import com.mostc.pftt.host.AHost;
 
 public class MSSQLScenario extends DatabaseScenario {
 
-       public MSSQLScenario(AHost host, int port, String default_username, 
String default_password) {
-               super(host, port, default_username, default_password);
+       public MSSQLScenario(AHost host, String default_username, String 
default_password) {
+               super(host, default_username, default_password);
        }
 
        @Override
-       protected DatabaseScenarioSetup createScenarioSetup() {
+       protected DatabaseScenarioSetup createScenarioSetup(boolean 
is_production_server) {
                return null;
        }
 
@@ -34,17 +34,5 @@ public class MSSQLScenario extends DatabaseScenario {
                // TODO Auto-generated method stub
                return null;
        }
-
-       @Override
-       protected boolean startServer() {
-               // TODO Auto-generated method stub
-               return false;
-       }
-
-       @Override
-       protected boolean stopServer() {
-               // TODO Auto-generated method stub
-               return false;
-       }
        
 }
diff --git a/src/com/mostc/pftt/scenario/MySQLScenario.java 
b/src/com/mostc/pftt/scenario/MySQLScenario.java
index e9b6471..c841d9f 100644
--- a/src/com/mostc/pftt/scenario/MySQLScenario.java
+++ b/src/com/mostc/pftt/scenario/MySQLScenario.java
@@ -1,17 +1,18 @@
 package com.mostc.pftt.scenario;
 
-import java.net.ConnectException;
-import java.net.Socket;
 import java.sql.Connection;
 import java.sql.DriverManager;
 import java.sql.SQLException;
+import java.sql.Statement;
 import java.util.Map;
 
 import com.mostc.pftt.host.AHost;
-import com.mostc.pftt.host.ExecOutput;
+import com.mostc.pftt.host.AHost.ExecHandle;
 import com.mostc.pftt.model.core.PhpBuild;
 import com.mostc.pftt.model.core.PhpIni;
+import com.mostc.pftt.model.sapi.WebServerManager;
 import com.mostc.pftt.results.ConsoleManager;
+import com.mostc.pftt.results.EPrintType;
 
 /** Sets up a MySQL database and tests the mysql, mysqli and pdo_mysql 
extensions against it.
  * 
@@ -24,20 +25,12 @@ public class MySQLScenario extends DatabaseScenario {
        public static final String DEFAULT_USERNAME = "root";
        public static final String DEFAULT_PASSWORD = "password01!";
        
-       public MySQLScenario(AHost host, int mysql_port, String 
default_username, String default_password) {
-               super(host, mysql_port, default_username, default_password);
-       }
-               
        public MySQLScenario(AHost host, String default_username, String 
default_password) {
-               this(host, DEFAULT_MYSQL_PORT, default_username, 
default_password);
-       }
-       
-       public MySQLScenario(AHost host, int mysql_port) {
-               this(host, mysql_port, DEFAULT_USERNAME, DEFAULT_PASSWORD);
+               super(host, default_username, default_password);
        }
                
        public MySQLScenario(AHost host) {
-               this(host, DEFAULT_MYSQL_PORT);
+               this(host, DEFAULT_USERNAME, DEFAULT_PASSWORD);
        }
        
        @Override
@@ -50,12 +43,16 @@ public class MySQLScenario extends DatabaseScenario {
                return "MySQL";
        }
        
-       protected MySQLScenarioSetup createScenarioSetup() {
+       @Override
+       protected MySQLScenarioSetup createScenarioSetup(boolean 
is_production_server) {
                return new MySQLScenarioSetup();
        }
                
        public class MySQLScenarioSetup extends DefaultDatabaseScenarioSetup {
+               protected ExecHandle mysqld_handle;
+               protected String datadir, hostname;
                
+               @Override
                protected Connection createConnection() throws SQLException {
                        String url = 
"jdbc:mysql://"+getHostname()+":"+getPort()+"/?user="+getUsername()+"&password="+getPassword();
                        return DriverManager.getConnection(url);
@@ -63,7 +60,7 @@ public class MySQLScenario extends DatabaseScenario {
                
                @Override
                public String getNameWithVersionInfo() {
-                       return "MySQL-5.6"; // TODO
+                       return "MySQL-5.6"; // TODO detect
                }
 
                @Override
@@ -124,65 +121,130 @@ public class MySQLScenario extends DatabaseScenario {
                public String getPdoDbType() {
                        return "pdo_mysql";
                }
+               public String getHostname() {
+                       return hostname;
+               }
                
-       } // end public class MySQLScenarioSetup
-
-       @Override
-       protected String getDriverClassName() {
-               return "com.mysql.jdbc.Driver";
-       }
-       
-       protected Object start_lock = new Object();
-       @Override
-       protected boolean startServer() {
-               synchronized(start_lock) {
+               @Override
+               protected boolean startServer(ConsoleManager cm, boolean 
is_production_server) {
                        try {
-                               ExecOutput eo = 
((AHost)host).execElevatedOut("net start MySQL56", AHost.ONE_MINUTE);
-                               if (true) {
-                                       // make sure mysql can be connected to
-                                       Socket sock;
-                                       for ( int i=0 ; i < 20 ; i++ ) {
-                                               Thread.sleep(1000*i);
-                                               try {
-                                                       sock = new 
Socket(getHostname(), getPort());
-                                                       if (sock.isConnected()) 
{
-                                                               sock.close();
-                                                               return true;
-                                                       }
-                                               } catch ( ConnectException ex ) 
{
+                               if (is_production_server) {
+                                       // TODO set 
tmpdir=C:/ProgramData/MySQL/temp in my.ini
+                                       //      otherwise will randomly fail to 
startup
+                                       cm.println(EPrintType.IN_PROGRESS, 
getClass(), "Starting MySQL Windows Service for production use...");
+                                       port = DEFAULT_MYSQL_PORT;
+                                       hostname = host.getAddress();
+                                       host.execElevated(cm, getClass(), "net 
start MySQL56", AHost.ONE_MINUTE);
+                               } else {
+                                       // TODO improve comment
+                                       // -delete temporary test databases
+                                       // -some tests seem to corrupt 
databases preventing mysql from being started again
+                                       //    (if using the same data dir, 
which is what happens with `net start MySQL56`)
+                                       String mysql_dir = 
host.getSystemDrive()+"\\Program Files\\MySQL\\MySQL Server 5.6";
+                                       
+                                       cm.println(EPrintType.IN_PROGRESS, 
getClass(), "Using MySQL install: "+mysql_dir);
+                                       cm.println(EPrintType.IN_PROGRESS, 
getClass(), "Creating temporary MySQL datadir");
+                                       
+                                       datadir = host.mktempname(getClass());
+                                       host.mkdirs(datadir);
+                                       
+                                       cm.println(EPrintType.IN_PROGRESS, 
getClass(), "Copying template datadir to temporary MySQL datadir "+datadir);
+                                       host.copy(mysql_dir+"\\data", datadir);
+                                       
+                                       hostname = "127.0.0.1";
+                                       boolean chose = false;
+                                       for(int i = DEFAULT_MYSQL_PORT+1 ; i < 
65535 ; i++ ) {
+                                               if 
(!WebServerManager.isLocalhostTCPPortUsed(i)) {
+                                                       port = i;
+                                                       chose = true;
+                                                       break;
                                                }
                                        }
+                                       if (!chose) {
+                                               
cm.println(EPrintType.CANT_CONTINUE, getClass(), "Could not find unused TCP 
port for MySQL server");
+                                               return false;
+                                       }
+                                       final String cmd = 
"\""+mysql_dir+"\\bin\\mysqld\" --standalone --console 
--bind-address="+hostname+" --port="+port+" --datadir="+datadir;
+                                       
+                                       cm.println(EPrintType.IN_PROGRESS, 
getClass(), "Starting MySQL in standalone mode (directly, using default 
config)...");
+                                       mysqld_handle = 
((AHost)host).execThread(cmd);
+                                       
+                                       // wait for server to output that is 
running before checking below
+                                       while (mysqld_handle.isRunning()) {
+                                               if 
(mysqld_handle.getOutput(50).contains("Server hostname (bind-address)"))
+                                                       break;
+                                       }
+                               } // end if
+                               
+                               cm.println(EPrintType.IN_PROGRESS, getClass(), 
"Checking if MySQL server is connectable...");
+                               // make sure mysql can be connected to
+                               if 
(WebServerManager.isLocalhostTCPPortUsed(port)) {
+                                       cm.println(EPrintType.IN_PROGRESS, 
getClass(), "MySQL server is connectable");
+                                       
+                                       if (!is_production_server) {
+                                               // TODO comment
+                                               
cm.println(EPrintType.IN_PROGRESS, getClass(), "Configuring "+getUsername()+" 
user on MySQL server");
+                                               
+                                               String url = 
"jdbc:mysql://"+getHostname()+":"+getPort()+"/?user="+getUsername();
+                                               
+                                               Connection c = 
DriverManager.getConnection(url);
+                                               
+                                               Statement s = 
c.createStatement();
+                                               s.execute("use mysql");
+                                               // TODO update password for 
specific user?
+                                               s.execute("UPDATE user SET 
password=PASSWORD('"+getPassword()+"')");
+                                               s.execute("flush privileges");
+                                       }
+                                       
+                                       return true;
                                }
+                               cm.println(EPrintType.CLUE, getClass(), "MySQL 
server is not connectable");
                        } catch (Exception ex) {
                                ex.printStackTrace();
+                               // TODO comment
+                               if (mysqld_handle!=null)
+                                       mysqld_handle.close(cm, true);
                        }
-               }
-               return false;
-       }
+                       cm.println(EPrintType.CANT_CONTINUE, getClass(), 
"Failed to start MySQL server");
+                       return false;
+               } // end protected boolean startServer
 
-       @Override
-       protected boolean stopServer() {
-               synchronized(start_lock) {
+               @Override
+               protected boolean stopServer(ConsoleManager cm, boolean 
is_production_server) {
                        try {
-                               host.execElevated("net stop MySQL56", 
AHost.ONE_MINUTE);
+                               if (is_production_server) {
+                                       cm.println(EPrintType.IN_PROGRESS, 
getClass(), "Stopping production MySQL Windows Service...");
+                                       host.execElevated(cm, getClass(), "net 
stop MySQL56", AHost.ONE_MINUTE);
+                               } else {
+                                       cm.println(EPrintType.IN_PROGRESS, 
getClass(), "Stopping MySQL stanadlone process");
+                                       mysqld_handle.close(cm, true);
+                                       
+                               }
+                               
                                // wait until MySQL can't be connected to
-                               Socket sock;
-                               for ( int i=0 ; i < 100 ; i++) {
-                                       Thread.sleep(100*(i+1));
-                                       try {
-                                               sock = new 
Socket(getHostname(), getPort());
-                                               if (!sock.isConnected())
-                                                       return true;
-                                       } catch ( ConnectException ex ) {
-                                               return true;
+                               if 
(!WebServerManager.isLocalhostTCPPortUsed(getPort())) {
+                                       if (!is_production_server) {
+                                               if (datadir!=null && 
!cm.isPfttDebug() && (!cm.isDebugAll()||!cm.isDebugList())) {
+                                                       
cm.println(EPrintType.IN_PROGRESS, getClass(), "Deleting temporary MySQL 
datadir");
+                                                       host.delete(datadir);
+                                                       datadir = null;
+                                               }
                                        }
+                                       cm.println(EPrintType.IN_PROGRESS, 
getClass(), "Stopped MySQL server");
                                }
                                return true;
                        } catch (Exception ex) {
                                ex.printStackTrace();
                        }
-               }
-               return false;
+                       cm.println(EPrintType.CANT_CONTINUE, getClass(), 
"Unable to stop MySQL server");
+                       return false;
+               } // end protected boolean stopServer
+               
+       } // end public class MySQLScenarioSetup
+
+       @Override
+       protected String getDriverClassName() {
+               return "com.mysql.jdbc.Driver";
        }
        
 } // end public class MySQLScenario
diff --git a/src/com/mostc/pftt/scenario/NetworkedServiceScenario.java 
b/src/com/mostc/pftt/scenario/NetworkedServiceScenario.java
index bdce15f..13c2620 100644
--- a/src/com/mostc/pftt/scenario/NetworkedServiceScenario.java
+++ b/src/com/mostc/pftt/scenario/NetworkedServiceScenario.java
@@ -6,5 +6,5 @@ import com.mostc.pftt.results.ConsoleManager;
 
 public abstract class NetworkedServiceScenario extends 
AbstractParallelScenario {
        @Override
-       public abstract IScenarioSetup setup(ConsoleManager cm, Host host, 
PhpBuild build, ScenarioSet scenario_set);
+       public abstract IScenarioSetup setup(ConsoleManager cm, Host host, 
PhpBuild build, ScenarioSet scenario_set, EScenarioSetPermutationLayer layer);
 }
diff --git a/src/com/mostc/pftt/scenario/NoCodeCacheScenario.java 
b/src/com/mostc/pftt/scenario/NoCodeCacheScenario.java
index 4bd6088..6799005 100644
--- a/src/com/mostc/pftt/scenario/NoCodeCacheScenario.java
+++ b/src/com/mostc/pftt/scenario/NoCodeCacheScenario.java
@@ -71,7 +71,7 @@ public class NoCodeCacheScenario extends CodeCacheScenario {
        } // end public boolean setup
 
        @Override
-       public IScenarioSetup setup(ConsoleManager cm, Host host, PhpBuild 
build, ScenarioSet scenario_set) {
+       public IScenarioSetup setup(ConsoleManager cm, Host host, PhpBuild 
build, ScenarioSet scenario_set, EScenarioSetPermutationLayer layer) {
                return SETUP_SUCCESS;
        }
 
diff --git a/src/com/mostc/pftt/scenario/NormalPathsScenario.java 
b/src/com/mostc/pftt/scenario/NormalPathsScenario.java
index 06699ef..4c23db7 100644
--- a/src/com/mostc/pftt/scenario/NormalPathsScenario.java
+++ b/src/com/mostc/pftt/scenario/NormalPathsScenario.java
@@ -19,7 +19,7 @@ public class NormalPathsScenario extends PathsScenario {
        }
 
        @Override
-       public IScenarioSetup setup(ConsoleManager cm, Host host, PhpBuild 
build, ScenarioSet scenario_set) {
+       public IScenarioSetup setup(ConsoleManager cm, Host host, PhpBuild 
build, ScenarioSet scenario_set, EScenarioSetPermutationLayer layer) {
                // TODO Auto-generated method stub
                return SETUP_FAILED;
        }
diff --git a/src/com/mostc/pftt/scenario/ODBCScenario.java 
b/src/com/mostc/pftt/scenario/ODBCScenario.java
index 182842e..f02e756 100644
--- a/src/com/mostc/pftt/scenario/ODBCScenario.java
+++ b/src/com/mostc/pftt/scenario/ODBCScenario.java
@@ -4,8 +4,8 @@ import com.mostc.pftt.host.AHost;
 
 public abstract class ODBCScenario extends DatabaseScenario {
 
-       public ODBCScenario(AHost host, int port, String default_username, 
String default_password) {
-               super(host, port, default_username, default_password);
+       public ODBCScenario(AHost host, String default_username, String 
default_password) {
+               super(host, default_username, default_password);
        }
 
 }
diff --git a/src/com/mostc/pftt/scenario/OpcacheScenario.java 
b/src/com/mostc/pftt/scenario/OpcacheScenario.java
index 07ab84e..7a412ad 100644
--- a/src/com/mostc/pftt/scenario/OpcacheScenario.java
+++ b/src/com/mostc/pftt/scenario/OpcacheScenario.java
@@ -240,7 +240,7 @@ public class OpcacheScenario extends CodeCacheScenario {
        }
 
        @Override
-       public OpcacheSetup setup(ConsoleManager cm, Host host, PhpBuild build, 
ScenarioSet scenario_set) {
+       public OpcacheSetup setup(ConsoleManager cm, Host host, PhpBuild build, 
ScenarioSet scenario_set, EScenarioSetPermutationLayer layer) {
                if (host.isWindows()) {
                        // TODO shouldn't be casting to AHost
                        cleanupBaseAddressFile((AHost)host, build, null);
diff --git a/src/com/mostc/pftt/scenario/OptionScenario.java 
b/src/com/mostc/pftt/scenario/OptionScenario.java
index 22f9ea0..7868817 100644
--- a/src/com/mostc/pftt/scenario/OptionScenario.java
+++ b/src/com/mostc/pftt/scenario/OptionScenario.java
@@ -7,6 +7,6 @@ import com.mostc.pftt.results.ConsoleManager;
 public abstract class OptionScenario extends AbstractSerialScenario {
 
        @Override
-       public abstract IScenarioSetup setup(ConsoleManager cm, Host host, 
PhpBuild build, ScenarioSet scenario_set);
+       public abstract IScenarioSetup setup(ConsoleManager cm, Host host, 
PhpBuild build, ScenarioSet scenario_set, EScenarioSetPermutationLayer layer);
        
 }
diff --git a/src/com/mostc/pftt/scenario/PhpUnitInlineReferencesScenario.java 
b/src/com/mostc/pftt/scenario/PhpUnitInlineReferencesScenario.java
index a562348..ad8c8f8 100644
--- a/src/com/mostc/pftt/scenario/PhpUnitInlineReferencesScenario.java
+++ b/src/com/mostc/pftt/scenario/PhpUnitInlineReferencesScenario.java
@@ -7,7 +7,7 @@ import com.mostc.pftt.results.ConsoleManager;
 public class PhpUnitInlineReferencesScenario extends PhpUnitReflectionScenario 
{
 
        @Override
-       public IScenarioSetup setup(ConsoleManager cm, Host host, PhpBuild 
build, ScenarioSet scenario_set) {
+       public IScenarioSetup setup(ConsoleManager cm, Host host, PhpBuild 
build, ScenarioSet scenario_set, EScenarioSetPermutationLayer layer) {
                return SETUP_SUCCESS;
        }
 
diff --git a/src/com/mostc/pftt/scenario/PhpUnitReflectionOnlyScenario.java 
b/src/com/mostc/pftt/scenario/PhpUnitReflectionOnlyScenario.java
index 8850a75..b6c325f 100644
--- a/src/com/mostc/pftt/scenario/PhpUnitReflectionOnlyScenario.java
+++ b/src/com/mostc/pftt/scenario/PhpUnitReflectionOnlyScenario.java
@@ -7,7 +7,7 @@ import com.mostc.pftt.results.ConsoleManager;
 public class PhpUnitReflectionOnlyScenario extends PhpUnitReflectionScenario {
 
        @Override
-       public IScenarioSetup setup(ConsoleManager cm, Host host, PhpBuild 
build, ScenarioSet scenario_set) {
+       public IScenarioSetup setup(ConsoleManager cm, Host host, PhpBuild 
build, ScenarioSet scenario_set, EScenarioSetPermutationLayer layer) {
                return SETUP_SUCCESS;
        }
 
diff --git a/src/com/mostc/pftt/scenario/PhpUnitReflectionScenario.java 
b/src/com/mostc/pftt/scenario/PhpUnitReflectionScenario.java
index 38f4c53..85e8956 100644
--- a/src/com/mostc/pftt/scenario/PhpUnitReflectionScenario.java
+++ b/src/com/mostc/pftt/scenario/PhpUnitReflectionScenario.java
@@ -4,8 +4,7 @@ public abstract class PhpUnitReflectionScenario extends 
OptionScenario {
        @Override
        public Class<?> getSerialKey(EScenarioSetPermutationLayer layer) {
                switch(layer) {
-               case WEB_APPLICATION:
-               case USER_INTERFACE:
+               case FUNCTIONAL_TEST_APPLICATION:
                        return PhpUnitReflectionScenario.class;
                default:
                        // these scenarios only matter for PhpUnit tests
diff --git a/src/com/mostc/pftt/scenario/PlainSocketScenario.java 
b/src/com/mostc/pftt/scenario/PlainSocketScenario.java
index 1b56472..207df96 100644
--- a/src/com/mostc/pftt/scenario/PlainSocketScenario.java
+++ b/src/com/mostc/pftt/scenario/PlainSocketScenario.java
@@ -29,7 +29,7 @@ public class PlainSocketScenario extends SocketScenario {
        }
 
        @Override
-       public IScenarioSetup setup(ConsoleManager cm, Host host, PhpBuild 
build, ScenarioSet scenario_set) {
+       public IScenarioSetup setup(ConsoleManager cm, Host host, PhpBuild 
build, ScenarioSet scenario_set, EScenarioSetPermutationLayer layer) {
                return SETUP_SUCCESS;
        }
 
diff --git a/src/com/mostc/pftt/scenario/PostgresSQLScenario.java 
b/src/com/mostc/pftt/scenario/PostgresSQLScenario.java
index 4e21b42..6585de0 100644
--- a/src/com/mostc/pftt/scenario/PostgresSQLScenario.java
+++ b/src/com/mostc/pftt/scenario/PostgresSQLScenario.java
@@ -17,12 +17,12 @@ import com.mostc.pftt.results.ConsoleManager;
 
 public class PostgresSQLScenario extends DatabaseScenario {
 
-       public PostgresSQLScenario(AHost host, int port, String 
default_username, String default_password) {
-               super(host, port, default_username, default_password);
+       public PostgresSQLScenario(AHost host, String default_username, String 
default_password) {
+               super(host, default_username, default_password);
        }
 
        @Override
-       protected DatabaseScenarioSetup createScenarioSetup() {
+       protected DatabaseScenarioSetup createScenarioSetup(boolean 
is_production_server) {
                return new PostgresSQLScenarioSetup();
        }
        
@@ -61,6 +61,20 @@ public class PostgresSQLScenario extends DatabaseScenario {
                public String getPdoDbType() {
                        return "pdo_pgsql";
                }
+
+               @Override
+               protected boolean startServer(ConsoleManager cm,
+                               boolean is_production_database_server) {
+                       // TODO Auto-generated method stub
+                       return false;
+               }
+
+               @Override
+               protected boolean stopServer(ConsoleManager cm,
+                               boolean is_production_database_server) {
+                       // TODO Auto-generated method stub
+                       return false;
+               }
                
        } // end public class PostgresSQLScenarioSetup
 
@@ -79,16 +93,4 @@ public class PostgresSQLScenario extends DatabaseScenario {
                return "org.postgres.JDriver";
        }
 
-       @Override
-       protected boolean startServer() {
-               // TODO Auto-generated method stub
-               return false;
-       }
-
-       @Override
-       protected boolean stopServer() {
-               // TODO Auto-generated method stub
-               return false;
-       }
-
 } // end public class PostgresSQLScenario
diff --git a/src/com/mostc/pftt/scenario/SMBCSCOptionScenario.java 
b/src/com/mostc/pftt/scenario/SMBCSCOptionScenario.java
index 216f5da..56d2df1 100644
--- a/src/com/mostc/pftt/scenario/SMBCSCOptionScenario.java
+++ b/src/com/mostc/pftt/scenario/SMBCSCOptionScenario.java
@@ -15,7 +15,7 @@ public abstract class SMBCSCOptionScenario extends 
OptionScenario {
        public abstract boolean isEnable();
        
        @Override
-       public IScenarioSetup setup(ConsoleManager cm, Host host, PhpBuild 
build, ScenarioSet scenario_set) {
+       public IScenarioSetup setup(ConsoleManager cm, Host host, PhpBuild 
build, ScenarioSet scenario_set, EScenarioSetPermutationLayer layer) {
                // XXX linux client support
                StringBuilder ps_sb = new StringBuilder();
                ps_sb.append("$wmi = 
[wmiclass]\"\\\\localhost\\root\\cimv2:win32_offlinefilescache\"");
diff --git a/src/com/mostc/pftt/scenario/SMBScenario.java 
b/src/com/mostc/pftt/scenario/SMBScenario.java
index 9ca3940..6ceacb5 100644
--- a/src/com/mostc/pftt/scenario/SMBScenario.java
+++ b/src/com/mostc/pftt/scenario/SMBScenario.java
@@ -102,7 +102,7 @@ public abstract class SMBScenario extends 
RemoteFileSystemScenario {
                public String getNameWithVersionInfo() {
                        return getName();
                }
-
+               
                @Override
                public String getName() {
                        return SMBScenario.this.getName();
diff --git a/src/com/mostc/pftt/scenario/SOAPScenario.java 
b/src/com/mostc/pftt/scenario/SOAPScenario.java
index 15f4301..b7f45d9 100644
--- a/src/com/mostc/pftt/scenario/SOAPScenario.java
+++ b/src/com/mostc/pftt/scenario/SOAPScenario.java
@@ -23,8 +23,8 @@ public class SOAPScenario extends NetworkedServiceScenario {
        }
        
        @Override
-       public IScenarioSetup setup(ConsoleManager cm, Host host, PhpBuild 
build, ScenarioSet scenario_set) {
-               return null;
+       public IScenarioSetup setup(ConsoleManager cm, Host host, PhpBuild 
build, ScenarioSet scenario_set, EScenarioSetPermutationLayer layer) {
+               return SETUP_FAILED;
        }
 
 }
diff --git a/src/com/mostc/pftt/scenario/SSLSocketScenario.java 
b/src/com/mostc/pftt/scenario/SSLSocketScenario.java
index a1f1896..5d6fe03 100644
--- a/src/com/mostc/pftt/scenario/SSLSocketScenario.java
+++ b/src/com/mostc/pftt/scenario/SSLSocketScenario.java
@@ -23,14 +23,14 @@ public class SSLSocketScenario extends SocketScenario {
        }
 
        @Override
-       public IScenarioSetup setup(ConsoleManager cm, Host host, PhpBuild 
build, ScenarioSet scenario_set) {
+       public IScenarioSetup setup(ConsoleManager cm, Host host, PhpBuild 
build, ScenarioSet scenario_set, EScenarioSetPermutationLayer layer) {
                // TODO configure HttpPhptTestCaseRunner and 
HttpPhpUnitTestCaseRunner to use SSL
                return SETUP_FAILED;
        }
        
        @Override
        public boolean isSupported(ConsoleManager cm, Host host, PhpBuild 
build, ScenarioSet scenario_set) {
-               // only work with AbstractWebServerScenario
+               // only work with web server scenarios
                return WebServerScenario.getWebServerScenario(scenario_set) != 
null;
        }
 
diff --git a/src/com/mostc/pftt/scenario/Scenario.java 
b/src/com/mostc/pftt/scenario/Scenario.java
index a0b0492..b0d2658 100644
--- a/src/com/mostc/pftt/scenario/Scenario.java
+++ b/src/com/mostc/pftt/scenario/Scenario.java
@@ -3,6 +3,8 @@ package com.mostc.pftt.scenario;
 import java.io.IOException;
 import java.util.Collection;
 
+import javax.annotation.Nullable;
+
 import org.xmlpull.v1.XmlPullParser;
 import org.xmlpull.v1.XmlPullParserException;
 import org.xmlpull.v1.XmlSerializer;
@@ -38,11 +40,13 @@ import com.mostc.pftt.results.ITestResultReceiver;
 
 public abstract class Scenario {
 
+       // TODO
        @Overridable
        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;
        }
        
+       // TODO
        @Overridable
        public Class<?> getSerialKey(EScenarioSetPermutationLayer layer) {
                return getClass();
@@ -62,13 +66,18 @@ public abstract class Scenario {
                
        }
        
+       /** does #setup need to be called before this Scenario can be used?
+        * 
+        * @param layer
+        * @return
+        */
        @Overridable
        public boolean setupRequired(EScenarioSetPermutationLayer layer) {
                return !isPlaceholder(layer);
        }
        
        @Overridable
-       public IScenarioSetup setup(ConsoleManager cm, Host host, PhpBuild 
build, ScenarioSet scenario_set) {
+       public IScenarioSetup setup(ConsoleManager cm, Host host, PhpBuild 
build, ScenarioSet scenario_set, EScenarioSetPermutationLayer layer) {
                return SETUP_SUCCESS;
        }
        public static final IScenarioSetup SETUP_SUCCESS = new 
SimpleScenarioSetup() {
@@ -87,11 +96,25 @@ public abstract class Scenario {
                };
        public static final IScenarioSetup SETUP_FAILED = null;
        
+       /** TODO
+        * 
+        * @return
+        */
        public abstract String getName();
+       
+       /** is scenario implemented? if not calling #setup should return 
SETUP_FAILED
+        * 
+        * @return
+        */
        public abstract boolean isImplemented();
                
-       @Overridable
-       public boolean isPlaceholder(EScenarioSetPermutationLayer layer) {
+       /** TODO
+        * 
+        * @param layer
+        * @return
+        */
+       @Overridable 
+       public boolean isPlaceholder(@Nullable EScenarioSetPermutationLayer 
layer) {
                return false;
        }
        
@@ -100,6 +123,11 @@ public abstract class Scenario {
                return isPlaceholder(layer);
        }
        
+       /**
+        * 
+        * @param name
+        * @return
+        */
        @Overridable
        protected String processNameAndVersionInfo(String name) {
                return name;
@@ -116,11 +144,20 @@ public abstract class Scenario {
                return false;
        }
        
+       // TODO
        @Overridable
        public boolean isUACRequiredForSetup() {
                return false;
        }
        
+       /** TODO
+        * 
+        * @param cm
+        * @param host
+        * @param build
+        * @param scenario_set
+        * @return
+        */
        @Overridable
        public boolean isSupported(ConsoleManager cm, Host host, PhpBuild 
build, ScenarioSet scenario_set) {
                return true;
diff --git a/src/com/mostc/pftt/scenario/ScenarioSet.java 
b/src/com/mostc/pftt/scenario/ScenarioSet.java
index 78b6656..f6da09c 100644
--- a/src/com/mostc/pftt/scenario/ScenarioSet.java
+++ b/src/com/mostc/pftt/scenario/ScenarioSet.java
@@ -51,7 +51,7 @@ public class ScenarioSet extends ArrayList<Scenario> {
        private static Comparator<Scenario> COMPARATOR = new 
Comparator<Scenario>() {
                        @Override
                        public int compare(Scenario a, Scenario b) {
-                               return 
a.getSerialKey(EScenarioSetPermutationLayer.PHP_CORE).getName().compareTo(b.getSerialKey(EScenarioSetPermutationLayer.PHP_CORE).getName());
+                               return 
a.getSerialKey(EScenarioSetPermutationLayer.FUNCTIONAL_TEST_CORE).getName().compareTo(b.getSerialKey(EScenarioSetPermutationLayer.FUNCTIONAL_TEST_CORE).getName());
                        }
                };
        private synchronized void sort(EScenarioSetPermutationLayer layer) {
@@ -311,7 +311,7 @@ public class ScenarioSet extends ArrayList<Scenario> {
                return scenario_sets;
        }
        static {
-               scenario_sets = 
permuteScenarioSets(EScenarioSetPermutationLayer.PHP_CORE, 
Arrays.asList(Scenario.getAllDefaultScenarios()));
+               scenario_sets = 
permuteScenarioSets(EScenarioSetPermutationLayer.FUNCTIONAL_TEST_CORE, 
Arrays.asList(Scenario.getAllDefaultScenarios()));
        }
        
        protected String processNameAndVersionInfo(String name) {
@@ -319,5 +319,11 @@ public class ScenarioSet extends ArrayList<Scenario> {
                        name = s.processNameAndVersionInfo(name);
                return name;
        }
+
+       public static ScenarioSet parse(String name) {
+               ScenarioSet s = new ScenarioSet();
+               s.str = name;
+               return s;
+       }
        
 } // end public class ScenarioSet
diff --git a/src/com/mostc/pftt/scenario/ScenarioSetSetup.java 
b/src/com/mostc/pftt/scenario/ScenarioSetSetup.java
index fd0f52f..3331ea9 100644
--- a/src/com/mostc/pftt/scenario/ScenarioSetSetup.java
+++ b/src/com/mostc/pftt/scenario/ScenarioSetSetup.java
@@ -35,7 +35,7 @@ public class ScenarioSetSetup implements IClosable {
                boolean has_env = false;
                for ( Scenario scenario : scenario_set ) {
                        if (scenario.setupRequired(layer)) {
-                               setup = scenario.setup(cm, host, build, 
scenario_set);
+                               setup = scenario.setup(cm, host, build, 
scenario_set, layer);
                        
                                if (setup==null) {
                                        if (cm!=null) {
diff --git a/src/com/mostc/pftt/scenario/SimpleScenarioSetup.java 
b/src/com/mostc/pftt/scenario/SimpleScenarioSetup.java
index 75404a6..479732b 100644
--- a/src/com/mostc/pftt/scenario/SimpleScenarioSetup.java
+++ b/src/com/mostc/pftt/scenario/SimpleScenarioSetup.java
@@ -20,6 +20,11 @@ public abstract class SimpleScenarioSetup implements 
IScenarioSetup {
        }
        
        @Override
+       public boolean isRunning() {
+               return true;
+       }
+       
+       @Override
        public boolean hasENV() {
                return false;
        }
diff --git a/src/com/mostc/pftt/scenario/UNCPathsScenario.java 
b/src/com/mostc/pftt/scenario/UNCPathsScenario.java
index 37ca58a..ef18edf 100644
--- a/src/com/mostc/pftt/scenario/UNCPathsScenario.java
+++ b/src/com/mostc/pftt/scenario/UNCPathsScenario.java
@@ -15,7 +15,7 @@ import com.mostc.pftt.results.ConsoleManager;
 public class UNCPathsScenario extends PathsScenario {
 
        @Override
-       public IScenarioSetup setup(ConsoleManager cm, Host host, PhpBuild 
build, ScenarioSet scenario_set) {
+       public IScenarioSetup setup(ConsoleManager cm, Host host, PhpBuild 
build, ScenarioSet scenario_set, EScenarioSetPermutationLayer layer) {
                // TODO Auto-generated method stub
                return SETUP_FAILED;
        }
diff --git a/src/com/mostc/pftt/scenario/WebServerScenario.java 
b/src/com/mostc/pftt/scenario/WebServerScenario.java
index 2ef8f60..198b8c2 100644
--- a/src/com/mostc/pftt/scenario/WebServerScenario.java
+++ b/src/com/mostc/pftt/scenario/WebServerScenario.java
@@ -96,7 +96,7 @@ public abstract class WebServerScenario extends SAPIScenario {
        }
        
        @Override
-       public IScenarioSetup setup(ConsoleManager cm, Host host, PhpBuild 
build, ScenarioSet scenario_set) {
+       public IScenarioSetup setup(ConsoleManager cm, Host host, PhpBuild 
build, ScenarioSet scenario_set, EScenarioSetPermutationLayer layer) {
                return smgr.setup(cm, host, build);
        }
        
diff --git a/src/com/mostc/pftt/scenario/WinCacheScenario.java 
b/src/com/mostc/pftt/scenario/WinCacheScenario.java
index 20a1936..19dd4a1 100644
--- a/src/com/mostc/pftt/scenario/WinCacheScenario.java
+++ b/src/com/mostc/pftt/scenario/WinCacheScenario.java
@@ -43,7 +43,7 @@ public class WinCacheScenario extends CodeCacheScenario {
        }
 
        @Override
-       public IScenarioSetup setup(ConsoleManager cm, Host host, PhpBuild 
build, ScenarioSet scenario_set) {
+       public IScenarioSetup setup(ConsoleManager cm, Host host, PhpBuild 
build, ScenarioSet scenario_set, EScenarioSetPermutationLayer layer) {
                return SETUP_FAILED;
        }
 
diff --git a/src/com/mostc/pftt/scenario/XMLRPCScenario.java 
b/src/com/mostc/pftt/scenario/XMLRPCScenario.java
index 9395b03..7b9d04d 100644
--- a/src/com/mostc/pftt/scenario/XMLRPCScenario.java
+++ b/src/com/mostc/pftt/scenario/XMLRPCScenario.java
@@ -23,7 +23,7 @@ public class XMLRPCScenario extends NetworkedServiceScenario {
        }
 
        @Override
-       public IScenarioSetup setup(ConsoleManager cm, Host host, PhpBuild 
build, ScenarioSet scenario_set) {
+       public IScenarioSetup setup(ConsoleManager cm, Host host, PhpBuild 
build, ScenarioSet scenario_set, EScenarioSetPermutationLayer layer) {
                return null;
        }
 
diff --git a/src/com/mostc/pftt/scenario/app/HelloWorldScenario.groovy 
b/src/com/mostc/pftt/scenario/app/HelloWorldScenario.groovy
index a1d51b1..debb870 100644
--- a/src/com/mostc/pftt/scenario/app/HelloWorldScenario.groovy
+++ b/src/com/mostc/pftt/scenario/app/HelloWorldScenario.groovy
@@ -4,6 +4,7 @@ import com.mostc.pftt.host.Host;
 import com.mostc.pftt.model.core.PhpBuild;
 import com.mostc.pftt.results.ConsoleManager;
 import com.mostc.pftt.scenario.ApplicationScenario;
+import com.mostc.pftt.scenario.EScenarioSetPermutationLayer;
 import com.mostc.pftt.scenario.IScenarioSetup;
 import com.mostc.pftt.scenario.ScenarioSet;
 
@@ -16,7 +17,7 @@ import com.mostc.pftt.scenario.ScenarioSet;
 public class HelloWorldScenario extends ApplicationScenario {
 
        @Override
-       public IScenarioSetup setup(ConsoleManager cm, Host host, PhpBuild 
build, ScenarioSet scenario_set) {
+       public IScenarioSetup setup(ConsoleManager cm, Host host, PhpBuild 
build, ScenarioSet scenario_set, EScenarioSetPermutationLayer layer) {
                def php_code = """
 <?php
 
diff --git a/src/com/mostc/pftt/scenario/app/ZipApplication.java 
b/src/com/mostc/pftt/scenario/app/ZipApplication.java
index 9e5f619..c68f30e 100644
--- a/src/com/mostc/pftt/scenario/app/ZipApplication.java
+++ b/src/com/mostc/pftt/scenario/app/ZipApplication.java
@@ -5,6 +5,7 @@ import com.mostc.pftt.host.Host;
 import com.mostc.pftt.model.core.PhpBuild;
 import com.mostc.pftt.results.ConsoleManager;
 import com.mostc.pftt.results.EPrintType;
+import com.mostc.pftt.scenario.EScenarioSetPermutationLayer;
 import com.mostc.pftt.scenario.WebServerScenario;
 import com.mostc.pftt.scenario.ApplicationScenario;
 import com.mostc.pftt.scenario.IScenarioSetup;
@@ -15,7 +16,7 @@ public abstract class ZipApplication extends 
ApplicationScenario {
        protected String app_dir;
        
        @Override
-       public IScenarioSetup setup(ConsoleManager cm, Host host, PhpBuild 
build, ScenarioSet scenario_set) {
+       public IScenarioSetup setup(ConsoleManager cm, Host host, PhpBuild 
build, ScenarioSet scenario_set, EScenarioSetPermutationLayer layer) {
                if (true)
                        return SETUP_SUCCESS; // TODO
                WebServerScenario web = 
WebServerScenario.getWebServerScenario(scenario_set);
diff --git a/src/com/mostc/pftt/scenario/app/ZipDbApplication.java 
b/src/com/mostc/pftt/scenario/app/ZipDbApplication.java
index 54afd7b..4e20dfa 100644
--- a/src/com/mostc/pftt/scenario/app/ZipDbApplication.java
+++ b/src/com/mostc/pftt/scenario/app/ZipDbApplication.java
@@ -5,6 +5,7 @@ import com.mostc.pftt.model.core.PhpBuild;
 import com.mostc.pftt.results.ConsoleManager;
 import com.mostc.pftt.results.EPrintType;
 import com.mostc.pftt.scenario.DatabaseScenario;
+import com.mostc.pftt.scenario.EScenarioSetPermutationLayer;
 import com.mostc.pftt.scenario.IScenarioSetup;
 import com.mostc.pftt.scenario.MySQLScenario;
 import com.mostc.pftt.scenario.ScenarioSet;
@@ -27,12 +28,12 @@ public abstract class ZipDbApplication extends 
ZipApplication {
        }
        
        @Override
-       public IScenarioSetup setup(ConsoleManager cm, Host host, PhpBuild 
build, ScenarioSet scenario_set) {
+       public IScenarioSetup setup(ConsoleManager cm, Host host, PhpBuild 
build, ScenarioSet scenario_set, EScenarioSetPermutationLayer layer) {
                if (!scenario_set.contains(DatabaseScenario.class)) {
                        cm.println(EPrintType.SKIP_OPERATION, getClass(), "add 
a database (ex: local_mysql) to -config console option and try again");
                        return SETUP_FAILED;
                } else {
-                       return super.setup(cm, host, build, scenario_set);
+                       return super.setup(cm, host, build, scenario_set, 
layer);
                }
        }
        
diff --git a/src/com/mostc/pftt/util/HostEnvUtil.java 
b/src/com/mostc/pftt/util/HostEnvUtil.java
index 647d80e..1474c3e 100644
--- a/src/com/mostc/pftt/util/HostEnvUtil.java
+++ b/src/com/mostc/pftt/util/HostEnvUtil.java
@@ -63,15 +63,25 @@ public final class HostEnvUtil {
                boolean b = regQueryAdd(cm, host, 
"HKCU\\Software\\Microsoft\\Windows\\Windows Error Reporting", "Disable", 
wer_value, REG_DWORD);
                // this 1 disables the 'Instruction 0xNN referenced memory 
address that could not be read' popup msg (happens on a few PHPTs with remote 
FS for x64 builds)
                boolean c = regQueryAdd(cm, host, 
"HKLM\\SYSTEM\\CurrentControlSet\\Control\\Windows", "ErrorMode", em_value, 
REG_DWORD);
-               if ( a || b || c ) {                    
+               
+               if (!enable_debug_prompt) {
+                       regDel(cm, host, "HKLM\\Software\\Microsoft\\Windows 
NT\\CurrentVersion\\AeDebug", "Debugger");
+                       // IMPORTANT: don't delete this key, change the value 
otherwise (if windbg installed) werfault.exe will
+                       //            still launch windbg... won't if set to 
0x2.
+                       regQueryAdd(cm, host, 
"HKLM\\Software\\Microsoft\\Windows NT\\CurrentVersion\\AeDebug", "Auto", 
"0x2", REG_DWORD);
+               }
+               
+               if ( a || b || c ) {
                        // assume if registry had to be edited, the rest of 
this has to be done, otherwise assume this is all already done
                        // (avoid doing this if possible because it requires 
user to approve elevation)
                        
                        
                        cm.println(EPrintType.IN_PROGRESS, HostEnvUtil.class, 
"disabling Windows Firewall...");
                        
-                       // LATER edit firewall rules instead (what if on public 
network, ex: Azure)
-                       host.execElevated(cm, HostEnvUtil.class, "netsh 
firewall set opmode disable", AHost.ONE_MINUTE);
+                       if (!host.isRemote()) {
+                               // LATER edit firewall rules instead (what if 
on public network, ex: Azure)
+                               host.execElevated(cm, HostEnvUtil.class, "netsh 
firewall set opmode disable", AHost.ONE_MINUTE);
+                       }
                        
                        //
                        if (enable_debug_prompt) {
@@ -92,11 +102,6 @@ public final class HostEnvUtil {
                                        // `windbg -IS`
                                        host.execElevated(cm, 
HostEnvUtil.class, StringUtil.ensureQuoted(win_dbg_exe)+" -IS", 
AHost.ONE_MINUTE);
                                }
-                       } else {
-                               // edit registry to try to undo windbg -I
-                               //
-                               regDel(cm, host, 
"HKLM\\Software\\Microsoft\\Windows NT\\CurrentVersion\\AeDebug", "Debugger");
-                               regDel(cm, host, 
"HKLM\\Software\\Microsoft\\Windows NT\\CurrentVersion\\AeDebug", "Auto");
                        }
                        //
                        
diff --git a/src/com/mostc/pftt/util/TimerUtil.java 
b/src/com/mostc/pftt/util/TimerUtil.java
index 16e5d68..adcd47c 100644
--- a/src/com/mostc/pftt/util/TimerUtil.java
+++ b/src/com/mostc/pftt/util/TimerUtil.java
@@ -4,6 +4,18 @@ import java.util.concurrent.atomic.AtomicBoolean;
 
 public final class TimerUtil {
        
+       public static boolean trySleepSeconds(int seconds) {
+               return trySleepMillis(seconds*1000);
+       }
+       
+       public static boolean trySleepMillis(int millis) {
+               try {
+                       Thread.sleep(millis);
+                       return true;
+               } catch ( Exception ex ) {}
+               return false;
+       }
+       
        public interface RepeatingRunnable {
                public void run(RepeatingThread thread);
        }

Reply via email to