Commit: d7291de64a909becc9e73030a1aadcd35c827072 Author: Matt Ficken <mattfic...@php.net> Wed, 20 Jun 2018 19:36:17 -0700 Parents: f6829c2bfc1e7535808c09b78256e6eb6a30d3ab Branches: master
Link: http://git.php.net/?p=pftt2.git;a=commitdiff;h=d7291de64a909becc9e73030a1aadcd35c827072 Log: updates for Azure App Services, Nanoserver and other changes Former-commit-id: d718fd0f726cc04289b74f3a7ec3466d0a79ad9b Changed paths: A bin/NanoServerApiScan.exe A src/com/mostc/pftt/model/ApplicationSourceTestPack.java A src/com/mostc/pftt/model/app/AppUnitTestCase.java A src/com/mostc/pftt/model/sapi/GenericWebServerManager.java A src/com/mostc/pftt/runner/AbstractApplicationUnitTestCaseRunner.java A src/com/mostc/pftt/runner/CliSimpleTestCaseRunner.java A src/com/mostc/pftt/runner/HttpSimpleTestCaseRunner.java A src/com/mostc/pftt/runner/LocalSimpleTestPackRunner.java
diff --git a/bin/NanoServerApiScan.exe b/bin/NanoServerApiScan.exe new file mode 100644 index 0000000..4fbbea9 Binary files /dev/null and b/bin/NanoServerApiScan.exe differ diff --git a/src/com/mostc/pftt/model/ApplicationSourceTestPack.java b/src/com/mostc/pftt/model/ApplicationSourceTestPack.java new file mode 100644 index 0000000..ce4a290 --- /dev/null +++ b/src/com/mostc/pftt/model/ApplicationSourceTestPack.java @@ -0,0 +1,155 @@ +package com.mostc.pftt.model; + +import java.io.File; +import java.io.IOException; + +import javax.annotation.Nullable; + +import com.github.mattficken.Overridable; +import com.github.mattficken.io.StringUtil; +import com.mostc.pftt.host.AHost; +import com.mostc.pftt.host.LocalHost; +import com.mostc.pftt.model.core.EBuildBranch; +import com.mostc.pftt.results.ConsoleManager; +import com.mostc.pftt.scenario.AzureWebsitesScenario; +import com.mostc.pftt.scenario.FileSystemScenario; +import com.mostc.pftt.scenario.SAPIScenario; + +public abstract class ApplicationSourceTestPack<A extends ActiveTestPack, T extends TestCase> extends SourceTestPack<A,T> { + protected String test_pack_root; + + /** installs the tests after they have been copied to storage (if needed) + * + * @see #getRoot() returns the location the tests and their php files have been copied to (if they were + * copied, if not copied, returns location they are stored at) + * + * @param cm + * @param host + * @return + * @throws Exception + */ + protected abstract boolean openAfterInstall(ConsoleManager cm, AHost host) throws Exception; + + /** the base directory within the PFTT directory to find the test case files and required php files + * + * Typically, test-packs will call #ensureAppDecompressed + * + * @param cm + * @param host - determine the absolute path on this host + * @see AHost#getPfttDir + * @return + */ + protected abstract String getSourceRoot(ConsoleManager cm, AHost host); + + protected void doInstallInPlace(ConsoleManager cm, AHost host) throws IOException, Exception { + final String src_root = getSourceRoot(cm, LocalHost.getInstance()); + if (!new File(src_root).isDirectory()) { + throw new IOException("source-test-pack not found: "+src_root); + } + setRoot(src_root); + + openAfterInstall(cm, host); + } + + protected void doInstallNamed(ConsoleManager cm, AHost host) throws IOException, Exception { + final String src_root = getSourceRoot(cm, LocalHost.getInstance()); + if (!new File(src_root).isDirectory()) { + throw new IOException("source-test-pack not found: "+src_root); + } + setRoot(src_root); + + openAfterInstall(cm, host); + } + + protected void doInstall(SAPIScenario sapi_scenario, ConsoleManager cm, AHost host, String local_test_pack_dir, String remote_test_pack_dir) throws IOException, Exception { + LocalHost local_host = LocalHost.getInstance(); + final String src_root = getSourceRoot(cm, local_host); + if (!new File(src_root).isDirectory()) { + throw new IOException("source-test-pack not found: "+src_root); + } + + // using #uploadCompressWith7Zip instead of just #upload makes a huge difference + // for PhpUnit test-packs because of the large number of small files that have to be uploaded + // TODO temp azure host.uploadCompressWith7Zip(cm, getClass(), src_root, local_host, remote_test_pack_dir); + System.out.println("71 "+local_test_pack_dir); + //System.exit(0); + + if (AzureWebsitesScenario.check(sapi_scenario)) { + setRoot("D:\\HOME\\SITE\\WWWROOT\\"+FileSystemScenario.basename(getName()).replace("-12.3", "").replace("-1.20.2", ""));//MEDIAWIKI");//local_test_pack_dir); + } else { + setRoot(src_root);// TODO temp azure ?? local_test_pack_dir); + } + + openAfterInstall(cm, local_host); + } + + private boolean decompressed = false; + protected void ensureAppDecompressed(ConsoleManager cm, AHost host, String zip7_file) throws IllegalStateException, IOException, Exception { + if (decompressed) + return; + decompressed = true; + if (!StringUtil.endsWithIC(zip7_file, ".7z")) + zip7_file += ".7z"; + + // TODO temp azure host.decompress(cm, host, host.getPfttDir()+"/app/"+zip7_file, host.getPfttDir()+"/cache/working/"); + } + + /** Sometimes there are multiple tests that share a common resource (such as a file directory + * or database) and can not be run at the same time. Such tests are non-thread-safe (known as NTS tests). + * + * Return the full or partial filenames of NTS tests here. The returned array is processed in + * order. If any string from the same string array matches, all tests matching that array will + * be run in the same thread. + * + * @return + */ + @Nullable + public String[][] getNonThreadSafeTestFileNames() { + return null; + } + + public String getName() { + return getNameAndVersionString(); + } + + /** file path to test-pack */ + public void setRoot(String test_pack_root) { + this.test_pack_root = test_pack_root; + } + @Override + public String getSourceDirectory() { + return getRoot(); + } + /** file path to test-pack */ + public String getRoot() { + return this.test_pack_root; + } + + /** TRUE if test-pack is 'under development'. FALSE if its stable. + * + * test runner will include extra info(stack traces, etc...) for test-packs that are under development + * + * @return + */ + @Overridable + public boolean isDevelopment() { + return false; + } + + @Override + public EBuildBranch getTestPackBranch() { + return null; + } + + @Override + public String getTestPackVersionRevision() { + return getNameAndVersionString(); + } + + @Override + public String toString() { + return getName(); + } + +} // end public abstract class ApplicationSourceTestPack + \ No newline at end of file diff --git a/src/com/mostc/pftt/model/app/AppUnitTestCase.java b/src/com/mostc/pftt/model/app/AppUnitTestCase.java new file mode 100644 index 0000000..707620c --- /dev/null +++ b/src/com/mostc/pftt/model/app/AppUnitTestCase.java @@ -0,0 +1,77 @@ +package com.mostc.pftt.model.app; + +import com.github.mattficken.io.StringUtil; +import com.mostc.pftt.model.TestCase; +import com.mostc.pftt.scenario.FileSystemScenario; + +public abstract class AppUnitTestCase extends TestCase { + protected final String rel_filename, abs_filename; + + public AppUnitTestCase(String rel_filename, String abs_filename) { + this.rel_filename = rel_filename; + // don't need to call #normalizeFilename here usually. it's called in PhpUnitSourcetestPack#readDir... + // calling it (again )here would be a performance hit + this.abs_filename = abs_filename; + } + + public boolean fileNameStartsWithAny(String[] ext_names) { + return StringUtil.startsWithAnyIC(getFileName(), ext_names); + } + + /** name of file. + * + * file is case preserved to avoid breaking posix. + * + * windows slashes \\ are standardized to / posix. + * + * for case-insensitive matching @see #isFileName or @see #fileNameStartsWithAny + * + * @return + */ + public String getFileName() { + return rel_filename; + } + + public String getAbsoluteFileName() { + return abs_filename; + } + + public boolean isFileName(String file_name) { + return this.rel_filename.toLowerCase().equals(file_name.toLowerCase()) + || this.abs_filename.toLowerCase().equals(file_name.toLowerCase()); + } + + @Override + public String toString() { + return getName(); + } + + @Override + public boolean equals(Object o) { + if (o==this) + return true; + else if (o instanceof AppUnitTestCase) + 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. + * + * to do case-insenstive matching @see #isFileName + * + * @param test_name + * @return + */ + public static String normalizeFileName(String test_name) { + return FileSystemScenario.toUnixPath(test_name); + } + +} // end public abstract class AppUnitTestCase diff --git a/src/com/mostc/pftt/model/sapi/GenericWebServerManager.java b/src/com/mostc/pftt/model/sapi/GenericWebServerManager.java new file mode 100644 index 0000000..8c97afa --- /dev/null +++ b/src/com/mostc/pftt/model/sapi/GenericWebServerManager.java @@ -0,0 +1,74 @@ +package com.mostc.pftt.model.sapi; + +import java.util.Map; + +import com.mostc.pftt.host.AHost; +import com.mostc.pftt.model.core.PhpIni; +import com.mostc.pftt.scenario.FileSystemScenario; + +public class GenericWebServerManager extends UnmanagedWebServerManager { + protected final String hostname, web_server_software, docroot; + protected final int port; + protected final boolean ssl; + + public GenericWebServerManager(String hostname, int port, String docroot, String web_server_software, boolean ssl) { + if (port<1) + port = 80; + + this.hostname = hostname; + this.port = port; + this.docroot = docroot; + this.web_server_software = web_server_software; + this.ssl = ssl; + } + + public GenericWebServerManager(String hostname, int port, String docroot, String web_server_software) { + this(hostname, port, docroot, web_server_software, false); + } + + @Override + protected UnmanagedWebServerInstance createUnmanagedWebServerInstance() { + return new GenericWebServerInstance(null, null, null, null, null, null); + } + + protected class GenericWebServerInstance extends UnmanagedWebServerInstance { + + public GenericWebServerInstance(FileSystemScenario fs, AHost host, + WebServerManager ws_mgr, String[] cmd_array, PhpIni ini, + Map<String, String> env) { + super(fs, host, ws_mgr, cmd_array, ini, env); + } + + @Override + public String getName() { + return web_server_software; + } + + @Override + public String getHostname() { + return hostname; + } + + @Override + public int getPort() { + return port; + } + + @Override + public String getDocroot() { + return docroot; + } + + } + + @Override + public String getName() { + return "Generic-Web-Server"; + } + + @Override + public boolean isSSLSupported() { + return ssl; + } + +} diff --git a/src/com/mostc/pftt/runner/AbstractApplicationUnitTestCaseRunner.java b/src/com/mostc/pftt/runner/AbstractApplicationUnitTestCaseRunner.java new file mode 100644 index 0000000..730d06a --- /dev/null +++ b/src/com/mostc/pftt/runner/AbstractApplicationUnitTestCaseRunner.java @@ -0,0 +1,34 @@ +package com.mostc.pftt.runner; + +import java.util.regex.Pattern; + +import com.mostc.pftt.host.AHost; +import com.mostc.pftt.model.core.PhpBuild; +import com.mostc.pftt.model.core.PhpIni; +import com.mostc.pftt.results.ConsoleManager; +import com.mostc.pftt.results.ITestResultReceiver; +import com.mostc.pftt.runner.AbstractLocalTestPackRunner.TestPackThread; +import com.mostc.pftt.scenario.FileSystemScenario; +import com.mostc.pftt.scenario.SAPIScenario; +import com.mostc.pftt.scenario.ScenarioSetSetup; + +public abstract class AbstractApplicationUnitTestCaseRunner<T extends TestPackThread,R extends AbstractLocalTestPackRunner> extends AbstractTestCaseRunner<T,R> { + protected final T thread; + protected boolean is_crashed, is_timeout; + + protected static Pattern PAT_CLASS_NOT_FOUND, PAT_REQUIRE_ONCE_FAIL, PAT_SYNTAX_ERROR, PAT_FATAL_ERROR; + static { + PAT_CLASS_NOT_FOUND = Pattern.compile(".*Fatal error.*Class '.*' not found.*"); + PAT_REQUIRE_ONCE_FAIL = Pattern.compile(".*Fatal error.*require_once.*Failed opening required.*"); + PAT_FATAL_ERROR = Pattern.compile(".*Fatal error.*"); + PAT_SYNTAX_ERROR = Pattern.compile(".*No syntax errors detected.*"); + } + + public AbstractApplicationUnitTestCaseRunner(FileSystemScenario fs, SAPIScenario sapi_scenario, T thread, ITestResultReceiver twriter, ConsoleManager cm, AHost host, ScenarioSetSetup scenario_set, PhpBuild build, PhpIni ini) { + super(fs, sapi_scenario, twriter, cm, host, scenario_set, build, ini); + this.thread = thread; + } + + protected abstract String generatePhpScript(); + +} // end public abstract class AbstractApplicationUnitTestCaseRunner diff --git a/src/com/mostc/pftt/runner/CliSimpleTestCaseRunner.java b/src/com/mostc/pftt/runner/CliSimpleTestCaseRunner.java new file mode 100644 index 0000000..b104c52 --- /dev/null +++ b/src/com/mostc/pftt/runner/CliSimpleTestCaseRunner.java @@ -0,0 +1,100 @@ +package com.mostc.pftt.runner; + +import java.io.IOException; + +import com.github.mattficken.io.IOUtil; +import com.mostc.pftt.host.AHost; +import com.mostc.pftt.host.AHost.ExecHandle; +import com.mostc.pftt.model.app.SimpleTestCase; +import com.mostc.pftt.model.core.PhpBuild; +import com.mostc.pftt.model.core.PhpIni; +import com.mostc.pftt.results.ConsoleManager; +import com.mostc.pftt.results.ITestResultReceiver; +import com.mostc.pftt.runner.LocalSimpleTestPackRunner.SimpleTestThread; +import com.mostc.pftt.scenario.FileSystemScenario; +import com.mostc.pftt.scenario.SAPIScenario; +import com.mostc.pftt.scenario.ScenarioSetSetup; +import com.mostc.pftt.util.NTStatus; + +public class CliSimpleTestCaseRunner extends AbstractSimpleTestCaseRunner { + protected ExecHandle running_test_handle; + protected String output_str; + + public CliSimpleTestCaseRunner(FileSystemScenario fs, SAPIScenario sapi_scenario, SimpleTestThread thread, ITestResultReceiver tmgr, ConsoleManager cm, AHost host, ScenarioSetSetup scenario_set, PhpBuild build, PhpIni ini, SimpleTestCase test_case) { + super(fs, sapi_scenario, thread, tmgr, cm, host, scenario_set, build, ini, test_case); + } + + @Override + public String getSAPIOutput() { + // TODO Auto-generated method stub + return null; + } + + @Override + public String getSAPIConfig() { + // TODO Auto-generated method stub + return null; + } + + //@Override + protected void stop(boolean force) { + if (running_test_handle==null) + return; + running_test_handle.close(cm, force); + } + + private void doExecute(String template_file, String ini_dir) throws Exception { + template_file = fs.fixPath(template_file); + + String cmd = build.getPhpExe()+" "+template_file; + System.out.println("49 "+cmd); + running_test_handle = host.execThread( + //build.getPhpExe()+" -c "+ini_dir+" "+template_file//, + build.getPhpExe()+" "+template_file//, + //env, + //test_case.getPhpUnitDist().getPath().getAbsolutePath() + ); + + StringBuilder output_sb = new StringBuilder(128); + System.out.println(output_sb); + running_test_handle.run( + cm, + output_sb, + null, + SimpleTestCase.MAX_TEST_TIME_SECONDS,//getMaxTestRuntimeSeconds(), + null, + 0, cm.getSuspendSeconds(), + IOUtil.HALF_MEGABYTE + ); + + output_str = output_sb.toString(); + + is_crashed = running_test_handle.isCrashed(); + is_timeout = running_test_handle.isTimedOut(); + } + + @Override + protected String execute(String template_file) throws IOException, Exception { + final String ini_dir = build.prepare(cm, fs, host); // XXX store PhpIni in my_temp_dir ? + + doExecute(template_file, ini_dir); + if (is_crashed && running_test_handle.getExitCode() != -2 + && running_test_handle.getExitCode() != NTStatus.STATUS_ACCESS_VIOLATION) { + // try a second time to be sure + is_crashed = false; + + doExecute(template_file, ini_dir); + } + + if (is_crashed) { + int exit_code = running_test_handle.getExitCode(); + + output_str += "PFTT: crashed: exit_code="+exit_code+" status="+AHost.guessExitCodeStatus(host, exit_code); + } + + running_test_handle = null; + + return output_str; + } + +} diff --git a/src/com/mostc/pftt/runner/HttpSimpleTestCaseRunner.java b/src/com/mostc/pftt/runner/HttpSimpleTestCaseRunner.java new file mode 100644 index 0000000..975a97c --- /dev/null +++ b/src/com/mostc/pftt/runner/HttpSimpleTestCaseRunner.java @@ -0,0 +1,42 @@ +package com.mostc.pftt.runner; + +import java.io.IOException; + +import com.mostc.pftt.host.AHost; +import com.mostc.pftt.model.app.SimpleTestCase; +import com.mostc.pftt.model.core.PhpBuild; +import com.mostc.pftt.model.core.PhpIni; +import com.mostc.pftt.results.ConsoleManager; +import com.mostc.pftt.results.ITestResultReceiver; +import com.mostc.pftt.runner.LocalSimpleTestPackRunner.SimpleTestThread; +import com.mostc.pftt.scenario.FileSystemScenario; +import com.mostc.pftt.scenario.SAPIScenario; +import com.mostc.pftt.scenario.ScenarioSetSetup; + +public class HttpSimpleTestCaseRunner extends AbstractSimpleTestCaseRunner { + + public HttpSimpleTestCaseRunner(FileSystemScenario fs, SAPIScenario sapi_scenario, SimpleTestThread thread, ITestResultReceiver tmgr, ConsoleManager cm, AHost host, ScenarioSetSetup scenario_set, PhpBuild build, PhpIni ini, SimpleTestCase test_case) { + super(fs, sapi_scenario, thread, tmgr, cm, host, scenario_set, build, ini, test_case); + } + + @Override + public String getSAPIOutput() { + // TODO Auto-generated method stub + return null; + } + + @Override + public String getSAPIConfig() { + // TODO Auto-generated method stub + return null; + } + + @Override + protected String execute(String template_file) throws IOException, + Exception { + // TODO Auto-generated method stub + return null; + } + + +} diff --git a/src/com/mostc/pftt/runner/LocalSimpleTestPackRunner.java b/src/com/mostc/pftt/runner/LocalSimpleTestPackRunner.java new file mode 100644 index 0000000..2e8f331 --- /dev/null +++ b/src/com/mostc/pftt/runner/LocalSimpleTestPackRunner.java @@ -0,0 +1,81 @@ +package com.mostc.pftt.runner; + +import java.io.IOException; +import java.util.Map; + +import com.mostc.pftt.host.AHost; +import com.mostc.pftt.model.app.SimpleTestActiveTestPack; +import com.mostc.pftt.model.app.SimpleTestCase; +import com.mostc.pftt.model.app.SimpleTestSourceTestPack; +import com.mostc.pftt.model.core.PhpBuild; +import com.mostc.pftt.model.core.PhpIni; +import com.mostc.pftt.model.sapi.TestCaseGroupKey; +import com.mostc.pftt.results.LocalConsoleManager; +import com.mostc.pftt.results.PhpResultPackWriter; +import com.mostc.pftt.scenario.IScenarioSetup; +import com.mostc.pftt.scenario.ScenarioSet; + +public class LocalSimpleTestPackRunner extends AbstractLocalApplicationTestPackRunner<SimpleTestActiveTestPack, SimpleTestSourceTestPack, SimpleTestCase> { + + public LocalSimpleTestPackRunner(LocalConsoleManager cm, + PhpResultPackWriter tmgr, ScenarioSet scenario_set, PhpBuild build, + AHost host, AHost host2) { + super(cm, tmgr, scenario_set, build, host, host2); + } + + @Override + protected void showTally() { + + } + + @Override + protected boolean tryPrepare(PhpIni ini) { + return true; + } + + @Override + protected TestPackThread<SimpleTestCase> createTestPackThread(boolean parallel) throws IllegalStateException, IOException { + return new SimpleTestThread(parallel); + } + + public class SimpleTestThread extends TestPackThread<SimpleTestCase> { + + protected SimpleTestThread(boolean parallel) { + super(parallel); + } + + @Override + protected void prepareExec(TestCaseGroupKey group_key, PhpIni ini, Map<String, String> env, IScenarioSetup s) { + } + + @Override + protected void runTest(TestCaseGroupKey group_key, SimpleTestCase test_case, boolean debugger_attached) throws IOException, Exception, Throwable { + sapi_scenario.createSimpleTestCaseRunner( + this, + twriter, + cm, + runner_fs, + runner_host, + scenario_set_setup, + build, + group_key.getPhpIni(), test_case + ).runTest(cm, this, LocalSimpleTestPackRunner.this); + } + + @Override + protected void stopRunningCurrentTest() { + } + + @Override + protected int getMaxTestRuntimeSeconds() { + return SimpleTestCase.MAX_TEST_TIME_SECONDS; + } + + @Override + protected void recordSkipped(SimpleTestCase test_case) { + + } + + } // end public class SimpleTestThread + +} // end public class LocalSimpleTestPackRunner