[TASK] Run tests on new bamboo infrastructure 04/57604/11
authorChristian Kuhn <lolli@schwarzbu.ch>
Sun, 15 Jul 2018 16:33:59 +0000 (18:33 +0200)
committerChristian Kuhn <lolli@schwarzbu.ch>
Sun, 15 Jul 2018 20:16:54 +0000 (22:16 +0200)
A new bamboo agent infrastructure has been deployed that
significantly changes how tests are executed: The agent
docker containers are now "stupid" and no longer bundle
specific php versions or daemons. Instead, they can run
own containers to start needed daemons for specific jobs
and execute needed php commands in ad-hoc containers that
provide the required php version.
Daemons needed for single jobs are defined in a
docker-compose.yml file provided by core itself.
This docker-compose.yml file can not be used directly for
local test execution since it has to fiddle quite a bit
with docker volume mounts, networks and executing users
that is specific to the bamboo environment.
However, another yml file can be added later to ease local
test execution in a similar way.
The patch rewrites the bamboo plan pre-merge and nightly
specs of core master to use the new infrastructure and brings
a couple of minor changes to tests that rely on a running
memcached or redis to retrieve the daemon host from an
environment variable.

Patch for core v8 - note the installer acceptance tests
are disabled for now since they need preparation patches
in typo3/testing-framework v8 flavor first.

Change-Id: I65777eeee6e28fca5b3d3d979498293cc91a77af
Resolves: #85563
Resolves: #36934
Releases: 8.7
Reviewed-on: https://review.typo3.org/57604
Tested-by: TYPO3com <no-reply@typo3.com>
Reviewed-by: Christian Kuhn <lolli@schwarzbu.ch>
Tested-by: Christian Kuhn <lolli@schwarzbu.ch>
Build/bamboo/src/main/java/core/AbstractCoreSpec.java
Build/bamboo/src/main/java/core/NightlySpec.java
Build/bamboo/src/main/java/core/PreMergeSpec.java
Build/testing-docker/bamboo/docker-compose.yml [new file with mode: 0644]
typo3/sysext/core/Tests/Functional/Database/DatabaseConnectionTest.php
typo3/sysext/core/Tests/Functional/Session/Backend/RedisSessionBackendTest.php
typo3/sysext/core/Tests/Unit/Cache/Backend/MemcachedBackendTest.php
typo3/sysext/core/Tests/Unit/Cache/Backend/RedisBackendTest.php

index 9a10cd7..51e91a4 100644 (file)
@@ -49,6 +49,9 @@ abstract public class AbstractCoreSpec {
 
     protected String testingFrameworkBuildPath = "vendor/typo3/testing-framework/Resources/Core/Build/";
 
+    /**
+     * @todo This can be removed if acceptance mysql tests are rewritten and active again
+     */
     protected String credentialsMysql =
         "typo3DatabaseName=\"func\"" +
         " typo3DatabaseUsername=\"funcu\"" +
@@ -56,6 +59,9 @@ abstract public class AbstractCoreSpec {
         " typo3DatabaseHost=\"localhost\"" +
         " typo3InstallToolPassword=\"klaus\"";
 
+    /**
+     * @todo This can be removed if acceptance mssql functional tests work again
+     */
     protected String credentialsMssql =
         "typo3DatabaseDriver=\"sqlsrv\"" +
         " typo3DatabaseName=\"func\"" +
@@ -66,6 +72,9 @@ abstract public class AbstractCoreSpec {
         " typo3DatabaseCharset=\"utf-8\"" +
         " typo3InstallToolPassword=\"klaus\"";
 
+    /**
+     * @todo This can be removed if acceptance pgsql tests are rewritten and active again
+     */
     protected String credentialsPgsql =
         "typo3DatabaseDriver=\"pdo_pgsql\"" +
         " typo3DatabaseName=\"func\"" +
@@ -147,36 +156,45 @@ abstract public class AbstractCoreSpec {
 
     /**
      * Job composer validate
+     *
+     * @param String requirementIdentifier
      */
-    protected Job getJobComposerValidate() {
+    protected Job getJobComposerValidate(String requirementIdentifier) {
         return new Job("Validate composer.json", new BambooKey("VC"))
         .description("Validate composer.json before actual tests are executed")
         .pluginConfigurations(this.getDefaultJobPluginConfiguration())
         .tasks(
             this.getTaskGitCloneRepository(),
             this.getTaskGitCherryPick(),
-            new CommandTask()
+            new ScriptTask()
                 .description("composer validate")
-                .executable("composer").argument("validate")
+                .interpreter(ScriptTaskProperties.Interpreter.BINSH_OR_CMDEXE)
+                .inlineBody(
+                    this.getScriptTaskBashInlineBody() +
+                    this.getScriptTaskComposer(requirementIdentifier) +
+                    "composer validate"
+                )
                 .environmentVariables(this.composerRootVersionEnvironment)
         )
+        .requirements(
+            this.getRequirementDocker10()
+        )
         .cleanWorkingDirectory(true);
     }
 
     /**
      * Job acceptance test installs system on mysql
      *
-     * @param Requirement requirement
      * @param String requirementIdentfier
      */
-    protected Job getJobAcceptanceTestInstallMysql(Requirement requirement, String requirementIdentifier) {
+    protected Job getJobAcceptanceTestInstallMysql(String requirementIdentifier) {
         return new Job("Accept inst my " + requirementIdentifier, new BambooKey("ACINSTMY" + requirementIdentifier))
             .description("Install TYPO3 on mysql and create empty frontend page " + requirementIdentifier)
             .pluginConfigurations(this.getDefaultJobPluginConfiguration())
             .tasks(
                 this.getTaskGitCloneRepository(),
                 this.getTaskGitCherryPick(),
-                this.getTaskComposerInstall(),
+                this.getTaskComposerInstall(requirementIdentifier),
                 this.getTaskPrepareAcceptanceTest(),
                 new CommandTask()
                     .description("Execute codeception AcceptanceInstallMysql suite")
@@ -186,35 +204,33 @@ abstract public class AbstractCoreSpec {
             )
             .finalTasks(
                 new TestParserTask(TestParserTaskProperties.TestType.JUNIT)
-                    .resultDirectories("typo3temp/var/tests/AcceptanceReportsInstallMysql/reports.xml"),
-                this.getTaskDeleteMysqlDatabases(),
-                this.getTaskTearDownAcceptanceTestSetup()
+                    .resultDirectories("typo3temp/var/tests/AcceptanceReportsInstallMysql/reports.xml")
             )
             .requirements(
-                requirement
+                this.getRequirementDocker10()
             )
             .artifacts(new Artifact()
                 .name("Test Report")
                 .copyPattern("typo3temp/var/tests/AcceptanceReportsInstallMysql/")
                 .shared(false)
             )
-            .cleanWorkingDirectory(true);
+            .cleanWorkingDirectory(true)
+            .enabled(false);
     }
 
     /**
      * Job acceptance test installs system and introduction package on pgsql
      *
-     * @param Requirement requirement
      * @param String requirementIdentfier
      */
-    protected Job getJobAcceptanceTestInstallPgsql(Requirement requirement, String requirementIdentifier) {
+    protected Job getJobAcceptanceTestInstallPgsql(String requirementIdentifier) {
         return new Job("Accept inst pg " + requirementIdentifier, new BambooKey("ACINSTPG" + requirementIdentifier))
         .description("Install TYPO3 on pgsql and load introduction package " + requirementIdentifier)
         .pluginConfigurations(this.getDefaultJobPluginConfiguration())
         .tasks(
             this.getTaskGitCloneRepository(),
             this.getTaskGitCherryPick(),
-            this.getTaskComposerInstall(),
+            this.getTaskComposerInstall(requirementIdentifier),
             this.getTaskPrepareAcceptanceTest(),
             new CommandTask()
                 .description("Execute codeception AcceptanceInstallPgsql suite")
@@ -224,29 +240,27 @@ abstract public class AbstractCoreSpec {
         )
         .finalTasks(
             new TestParserTask(TestParserTaskProperties.TestType.JUNIT)
-                .resultDirectories("typo3temp/var/tests/AcceptanceReportsInstallPgsql/reports.xml"),
-            this.getTaskDeletePgsqlDatabases(),
-            this.getTaskTearDownAcceptanceTestSetup()
+                .resultDirectories("typo3temp/var/tests/AcceptanceReportsInstallPgsql/reports.xml")
         )
         .requirements(
-            requirement
+            this.getRequirementDocker10()
         )
         .artifacts(new Artifact()
             .name("Test Report")
             .copyPattern("typo3temp/var/tests/AcceptanceReportsInstallPgsql/")
             .shared(false)
         )
-        .cleanWorkingDirectory(true);
+        .cleanWorkingDirectory(true)
+        .enabled(false);
     }
 
     /**
      * Jobs for mysql based acceptance tests
      *
      * @param int numberOfChunks
-     * @param Requirement requirement
      * @param String requirementIdentifier
      */
-    protected ArrayList<Job> getJobsAcceptanceTestsMysql(int numberOfChunks, Requirement requirement, String requirementIdentifier) {
+    protected ArrayList<Job> getJobsAcceptanceTestsMysql(int numberOfChunks, String requirementIdentifier) {
         ArrayList<Job> jobs = new ArrayList<Job>();
 
         for (int i=1; i<=numberOfChunks; i++) {
@@ -256,7 +270,7 @@ abstract public class AbstractCoreSpec {
                 .tasks(
                     this.getTaskGitCloneRepository(),
                     this.getTaskGitCherryPick(),
-                    this.getTaskComposerInstall(),
+                    this.getTaskComposerInstall(requirementIdentifier),
                     this.getTaskPrepareAcceptanceTest(),
                     new ScriptTask()
                         .description("Split acceptance tests")
@@ -273,12 +287,10 @@ abstract public class AbstractCoreSpec {
                 )
                 .finalTasks(
                     new TestParserTask(TestParserTaskProperties.TestType.JUNIT)
-                        .resultDirectories("typo3temp/var/tests/AcceptanceReports/reports.xml"),
-                    this.getTaskDeleteMysqlDatabases(),
-                    this.getTaskTearDownAcceptanceTestSetup()
+                        .resultDirectories("typo3temp/var/tests/AcceptanceReports/reports.xml")
                 )
                 .requirements(
-                    requirement
+                    this.getRequirementDocker10()
                 )
                 .artifacts(new Artifact()
                     .name("Test Report")
@@ -286,6 +298,7 @@ abstract public class AbstractCoreSpec {
                     .shared(false)
                 )
                 .cleanWorkingDirectory(true)
+                .enabled(false)
             );
         }
 
@@ -296,10 +309,9 @@ abstract public class AbstractCoreSpec {
      * Jobs for mysql based functional tests
      *
      * @param int numberOfChunks
-     * @param Requirement requirement
      * @param String requirementIdentifier
      */
-    protected ArrayList<Job> getJobsFunctionalTestsMysql(int numberOfChunks, Requirement requirement, String requirementIdentifier) {
+    protected ArrayList<Job> getJobsFunctionalTestsMysql(int numberOfChunks, String requirementIdentifier) {
         ArrayList<Job> jobs = new ArrayList<Job>();
 
         for (int i=0; i<numberOfChunks; i++) {
@@ -309,24 +321,42 @@ abstract public class AbstractCoreSpec {
                 .tasks(
                     this.getTaskGitCloneRepository(),
                     this.getTaskGitCherryPick(),
-                    this.getTaskComposerInstall(),
+                    this.getTaskComposerInstall(requirementIdentifier),
+                    this.getTaskDockerDependenciesFunctionalMariadb10(),
                     this.getTaskSplitFunctionalJobs(numberOfChunks),
                     new ScriptTask()
                         .description("Run phpunit with functional chunk 0" + i)
                         .interpreter(ScriptTaskProperties.Interpreter.BINSH_OR_CMDEXE)
                         .inlineBody(
                             this.getScriptTaskBashInlineBody() +
-                            "./bin/phpunit --log-junit test-reports/phpunit.xml -c " + this.testingFrameworkBuildPath + "FunctionalTests-Job-" + i + ".xml"
+                            "function phpunit() {\n" +
+                            "    docker run \\\n" +
+                            "        -u ${HOST_UID} \\\n" +
+                            "        -v /etc/passwd:/etc/passwd \\\n" +
+                            "        -v ${BAMBOO_COMPOSE_PROJECT_NAME}_bamboo-data:/srv/bamboo/xml-data/build-dir/ \\\n" +
+                            "        -e typo3DatabaseName=func_test \\\n" +
+                            "        -e typo3DatabaseUsername=root \\\n" +
+                            "        -e typo3DatabasePassword=funcp \\\n" +
+                            "        -e typo3DatabaseHost=mariadb10 \\\n" +
+                            "        -e typo3TestingRedisHost=${BAMBOO_COMPOSE_PROJECT_NAME}sib_redis4_1 \\\n" +
+                            "        -e typo3TestingMemcachedHost=${BAMBOO_COMPOSE_PROJECT_NAME}sib_memcached1-5_1 \\\n" +
+                            "        --name ${BAMBOO_COMPOSE_PROJECT_NAME}sib_adhoc \\\n" +
+                            "        --network ${BAMBOO_COMPOSE_PROJECT_NAME}_test \\\n" +
+                            "        --rm \\\n" +
+                            "        typo3gmbh/" + requirementIdentifier.toLowerCase() + ":latest \\\n" +
+                            "        bin/bash -c \"cd ${PWD}; ./bin/phpunit $*\"\n" +
+                            "}\n" +
+                            "\n" +
+                            "phpunit --log-junit test-reports/phpunit.xml -c " + this.testingFrameworkBuildPath + "FunctionalTests-Job-" + i + ".xml"
                         )
-                        .environmentVariables(this.credentialsMysql)
                 )
                 .finalTasks(
-                    this.getTaskDeleteMysqlDatabases(),
+                    this.getTaskStopDockerDependencies(),
                     new TestParserTask(TestParserTaskProperties.TestType.JUNIT)
                         .resultDirectories("test-reports/phpunit.xml")
                 )
                 .requirements(
-                    requirement
+                    this.getRequirementDocker10()
                 )
                 .cleanWorkingDirectory(true)
             );
@@ -339,10 +369,9 @@ abstract public class AbstractCoreSpec {
      * Jobs for mssql based functional tests
      *
      * @param int numberOfChunks
-     * @param Requirement requirement
      * @param String requirementIdentifier
      */
-    protected ArrayList<Job> getJobsFunctionalTestsMssql(int numberOfChunks, Requirement requirement, String requirementIdentifier) {
+    protected ArrayList<Job> getJobsFunctionalTestsMssql(int numberOfChunks, String requirementIdentifier) {
         ArrayList<Job> jobs = new ArrayList<Job>();
 
         for (int i=0; i<numberOfChunks; i++) {
@@ -352,7 +381,7 @@ abstract public class AbstractCoreSpec {
                 .tasks(
                     this.getTaskGitCloneRepository(),
                     this.getTaskGitCherryPick(),
-                    this.getTaskComposerInstall(),
+                    this.getTaskComposerInstall(requirementIdentifier),
                     this.getTaskSplitFunctionalJobs(numberOfChunks),
                     new ScriptTask()
                         .description("Run phpunit with functional chunk 0" + i)
@@ -364,12 +393,11 @@ abstract public class AbstractCoreSpec {
                         .environmentVariables(this.credentialsMssql)
                 )
                 .finalTasks(
-                    this.getTaskDeleteMssqlDatabases(),
                     new TestParserTask(TestParserTaskProperties.TestType.JUNIT)
                         .resultDirectories("test-reports/phpunit.xml")
                 )
                 .requirements(
-                    requirement
+                    this.getRequirementDocker10()
                 )
                 .cleanWorkingDirectory(true)
                 .enabled(false)
@@ -383,10 +411,9 @@ abstract public class AbstractCoreSpec {
      * Jobs for pgsql based functional tests
      *
      * @param int numberOfChunks
-     * @param Requirement requirement
      * @param String requirementIdentifier
      */
-    protected ArrayList<Job> getJobsFunctionalTestsPgsql(int numberOfChunks, Requirement requirement, String requirementIdentifier) {
+    protected ArrayList<Job> getJobsFunctionalTestsPgsql(int numberOfChunks, String requirementIdentifier) {
         ArrayList<Job> jobs = new ArrayList<Job>();
 
         for (int i=0; i<numberOfChunks; i++) {
@@ -396,24 +423,43 @@ abstract public class AbstractCoreSpec {
                 .tasks(
                     this.getTaskGitCloneRepository(),
                     this.getTaskGitCherryPick(),
-                    this.getTaskComposerInstall(),
+                    this.getTaskComposerInstall(requirementIdentifier),
+                    this.getTaskDockerDependenciesFunctionalPostgres95(),
                     this.getTaskSplitFunctionalJobs(numberOfChunks),
                     new ScriptTask()
                         .description("Run phpunit with functional chunk 0" + i)
                         .interpreter(ScriptTaskProperties.Interpreter.BINSH_OR_CMDEXE)
                         .inlineBody(
                             this.getScriptTaskBashInlineBody() +
-                            "./bin/phpunit --exclude-group not-postgres --log-junit test-reports/phpunit.xml -c " + this.testingFrameworkBuildPath + "FunctionalTests-Job-" + i + ".xml"
+                            "function phpunit() {\n" +
+                            "    docker run \\\n" +
+                            "        -u ${HOST_UID} \\\n" +
+                            "        -v /etc/passwd:/etc/passwd \\\n" +
+                            "        -v ${BAMBOO_COMPOSE_PROJECT_NAME}_bamboo-data:/srv/bamboo/xml-data/build-dir/ \\\n" +
+                            "        -e typo3DatabaseDriver=pdo_pgsql \\\n" +
+                            "        -e typo3DatabaseName=bamboo \\\n" +
+                            "        -e typo3DatabaseUsername=bamboo \\\n" +
+                            "        -e typo3DatabaseHost=postgres9-5 \\\n" +
+                            "        -e typo3DatabasePassword=funcp \\\n" +
+                            "        -e typo3TestingRedisHost=redis4 \\\n" +
+                            "        -e typo3TestingMemcachedHost=memcached1-5 \\\n" +
+                            "        --name ${BAMBOO_COMPOSE_PROJECT_NAME}sib_adhoc \\\n" +
+                            "        --network ${BAMBOO_COMPOSE_PROJECT_NAME}_test \\\n" +
+                            "        --rm \\\n" +
+                            "        typo3gmbh/" + requirementIdentifier.toLowerCase() + ":latest \\\n" +
+                            "        bin/bash -c \"cd ${PWD}; ./bin/phpunit $*\"\n" +
+                            "}\n" +
+                            "\n" +
+                            "phpunit --exclude-group not-postgres --log-junit test-reports/phpunit.xml -c " + this.testingFrameworkBuildPath + "FunctionalTests-Job-" + i + ".xml"
                         )
-                        .environmentVariables(this.credentialsPgsql)
                 )
                 .finalTasks(
-                    this.getTaskDeletePgsqlDatabases(),
+                    this.getTaskStopDockerDependencies(),
                     new TestParserTask(TestParserTaskProperties.TestType.JUNIT)
                         .resultDirectories("test-reports/phpunit.xml")
                 )
                 .requirements(
-                    requirement
+                    this.getRequirementDocker10()
                 )
                 .cleanWorkingDirectory(true)
             );
@@ -424,8 +470,10 @@ abstract public class AbstractCoreSpec {
 
     /**
      * Job with various smaller script tests
+     *
+     * @param String requirementIdentifier
      */
-    protected Job getJobIntegrationVarious() {
+    protected Job getJobIntegrationVarious(String requirementIdentifier) {
         // Exception code checker, xlf, permissions, rst file check
         return new Job("Integration various", new BambooKey("CDECC"))
             .description("Checks duplicate exceptions, git submodules, xlf files, permissions, rst")
@@ -433,7 +481,7 @@ abstract public class AbstractCoreSpec {
             .tasks(
                 this.getTaskGitCloneRepository(),
                 this.getTaskGitCherryPick(),
-                this.getTaskComposerInstall(),
+                this.getTaskComposerInstall(requirementIdentifier),
                 new ScriptTask()
                     .description("Run duplicate exception code check script")
                     .interpreter(ScriptTaskProperties.Interpreter.BINSH_OR_CMDEXE)
@@ -470,7 +518,18 @@ abstract public class AbstractCoreSpec {
                     .interpreter(ScriptTaskProperties.Interpreter.BINSH_OR_CMDEXE)
                     .inlineBody(
                         this.getScriptTaskBashInlineBody() +
-                        "./Build/Scripts/validateRstFiles.php"
+                        "function validateRstFiles() {\n" +
+                        "    docker run \\\n" +
+                        "        -u ${HOST_UID} \\\n" +
+                        "        -v /etc/passwd:/etc/passwd \\\n" +
+                        "        -v ${BAMBOO_COMPOSE_PROJECT_NAME}_bamboo-data:/srv/bamboo/xml-data/build-dir/ \\\n" +
+                        "        --name ${BAMBOO_COMPOSE_PROJECT_NAME}sib_adhoc \\\n" +
+                        "        --rm \\\n" +
+                        "        typo3gmbh/" + requirementIdentifier.toLowerCase() + ":latest \\\n" +
+                        "        bin/bash -c \"cd ${PWD}; ./Build/Scripts/validateRstFiles.php $*\"\n" +
+                        "}\n" +
+                        "\n" +
+                        "validateRstFiles"
                     ),
                 new ScriptTask()
                     .description("Run path length check")
@@ -484,56 +543,100 @@ abstract public class AbstractCoreSpec {
                     .interpreter(ScriptTaskProperties.Interpreter.BINSH_OR_CMDEXE)
                     .inlineBody(
                         this.getScriptTaskBashInlineBody() +
-                        "./Build/Scripts/checkIntegrityCsvFixtures.php"
+                        "function checkIntegrityCsvFixtures() {\n" +
+                        "    docker run \\\n" +
+                        "        -u ${HOST_UID} \\\n" +
+                        "        -v /etc/passwd:/etc/passwd \\\n" +
+                        "        -v ${BAMBOO_COMPOSE_PROJECT_NAME}_bamboo-data:/srv/bamboo/xml-data/build-dir/ \\\n" +
+                        "        --name ${BAMBOO_COMPOSE_PROJECT_NAME}sib_adhoc \\\n" +
+                        "        --rm \\\n" +
+                        "        typo3gmbh/" + requirementIdentifier.toLowerCase() + ":latest \\\n" +
+                        "        bin/bash -c \"cd ${PWD}; ./Build/Scripts/checkIntegrityCsvFixtures.php $*\"\n" +
+                        "}\n" +
+                        "\n" +
+                        "checkIntegrityCsvFixtures"
                     ),
                 new ScriptTask()
                     .description("Run composer.json integrity check")
                     .interpreter(ScriptTaskProperties.Interpreter.BINSH_OR_CMDEXE)
                     .inlineBody(
                         this.getScriptTaskBashInlineBody() +
-                        "./Build/Scripts/checkIntegrityComposer.php"
-                   )
+                        "function checkIntegrityComposer() {\n" +
+                        "    docker run \\\n" +
+                        "        -u ${HOST_UID} \\\n" +
+                        "        -v /etc/passwd:/etc/passwd \\\n" +
+                        "        -v ${BAMBOO_COMPOSE_PROJECT_NAME}_bamboo-data:/srv/bamboo/xml-data/build-dir/ \\\n" +
+                        "        --name ${BAMBOO_COMPOSE_PROJECT_NAME}sib_adhoc \\\n" +
+                        "        --rm \\\n" +
+                        "        typo3gmbh/" + requirementIdentifier.toLowerCase() + ":latest \\\n" +
+                        "        bin/bash -c \"cd ${PWD}; ./Build/Scripts/checkIntegrityComposer.php $*\"\n" +
+                        "}\n" +
+                        "\n" +
+                        "checkIntegrityComposer"
+                    )
            )
             .requirements(
-                this.getRequirementPhpVersion70Or71Or72()
+                this.getRequirementDocker10()
             )
             .cleanWorkingDirectory(true);
     }
 
     /**
      * Job for javascript unit tests
+     *
+     * @param String requirementIdentifier
      */
-    protected Job getJobUnitJavaScript() {
+    protected Job getJobUnitJavaScript(String requirementIdentifier) {
         return new Job("Unit JavaScript", new BambooKey("JSUT"))
             .description("Run JavaScript unit tests")
             .pluginConfigurations(this.getDefaultJobPluginConfiguration())
             .tasks(
                 this.getTaskGitCloneRepository(),
                 this.getTaskGitCherryPick(),
-                this.getTaskComposerInstall(),
+                this.getTaskComposerInstall(requirementIdentifier),
                 new ScriptTask()
                     .description("yarn install in Build/ dir")
                     .interpreter(ScriptTaskProperties.Interpreter.BINSH_OR_CMDEXE)
                     .inlineBody(
                         this.getScriptTaskBashInlineBody() +
+                        "function yarn() {\n" +
+                        "    docker run \\\n" +
+                        "        -u ${HOST_UID} \\\n" +
+                        "        -v /etc/passwd:/etc/passwd \\\n" +
+                        "        -v ${BAMBOO_COMPOSE_PROJECT_NAME}_bamboo-data:/srv/bamboo/xml-data/build-dir/ \\\n" +
+                        "        -e HOME=${HOME} \\\n" +
+                        "        --name ${BAMBOO_COMPOSE_PROJECT_NAME}sib_adhoc \\\n" +
+                        "        --rm \\\n" +
+                        "        typo3gmbh/" + requirementIdentifier.toLowerCase() + ":latest \\\n" +
+                        "        bin/bash -c \"cd ${PWD}/Build; yarn $*\"\n" +
+                        "}\n" +
+                        "\n" +
                         "yarn install"
-                    )
-                    .workingSubdirectory("Build/"),
+                    ),
                 new ScriptTask()
                     .description("Run tests")
                     .interpreter(ScriptTaskProperties.Interpreter.BINSH_OR_CMDEXE)
                     .inlineBody(
                         this.getScriptTaskBashInlineBody() +
-                        "./Build/node_modules/karma/bin/karma start " + this.testingFrameworkBuildPath + "Configuration/JSUnit/karma.conf.js --single-run"
+                        "function karma() {\n" +
+                        "    docker run \\\n" +
+                        "        -u ${HOST_UID} \\\n" +
+                        "        -v /etc/passwd:/etc/passwd \\\n" +
+                        "        -v ${BAMBOO_COMPOSE_PROJECT_NAME}_bamboo-data:/srv/bamboo/xml-data/build-dir/ \\\n" +
+                        "        -e HOME=${HOME} \\\n" +
+                        "        --name ${BAMBOO_COMPOSE_PROJECT_NAME}sib_adhoc \\\n" +
+                        "        --rm \\\n" +
+                        "        typo3gmbh/" + requirementIdentifier.toLowerCase() + ":latest \\\n" +
+                        "        bin/bash -c \"cd ${PWD}; ./Build/node_modules/karma/bin/karma $*\"\n" +
+                        "}\n" +
+                        "\n" +
+                        "karma start " + this.testingFrameworkBuildPath + "Configuration/JSUnit/karma.conf.js --single-run"
                     )
             )
             .finalTasks(
                 new TestParserTask(TestParserTaskProperties.TestType.JUNIT)
                     .resultDirectories("typo3temp/var/tests/*")
             )
-            .requirements(
-                this.getRequirementPhpVersion70Or71Or72()
-            )
             .artifacts(
                 new Artifact()
                     .name("Clover Report (System)")
@@ -541,16 +644,18 @@ abstract public class AbstractCoreSpec {
                     .location("Build/target/site/clover")
                     .shared(false)
             )
+            .requirements(
+                this.getRequirementDocker10()
+            )
             .cleanWorkingDirectory(true);
     }
 
     /**
      * Job for PHP lint
      *
-     * @param Requirement requirement
      * @param String requirementIdentfier
      */
-    protected Job getJobLintPhp(Requirement requirement, String requirementIdentifier) {
+    protected Job getJobLintPhp(String requirementIdentifier) {
         return new Job("Lint " + requirementIdentifier, new BambooKey("L" + requirementIdentifier))
             .description("Run php -l on source files for linting " + requirementIdentifier)
             .pluginConfigurations(this.getDefaultJobPluginConfiguration())
@@ -562,19 +667,33 @@ abstract public class AbstractCoreSpec {
                     .interpreter(ScriptTaskProperties.Interpreter.BINSH_OR_CMDEXE)
                     .inlineBody(
                         this.getScriptTaskBashInlineBody() +
-                        "find . -name \\*.php -print0 | xargs -0 -n1 -P2 php -l >/dev/null\n"
+                        "function runLint() {\n" +
+                        "    docker run \\\n" +
+                        "        -u ${HOST_UID} \\\n" +
+                        "        -v /etc/passwd:/etc/passwd \\\n" +
+                        "        -v ${BAMBOO_COMPOSE_PROJECT_NAME}_bamboo-data:/srv/bamboo/xml-data/build-dir/ \\\n" +
+                        "        -e HOME=${HOME} \\\n" +
+                        "        --name ${BAMBOO_COMPOSE_PROJECT_NAME}sib_adhoc \\\n" +
+                        "        --rm \\\n" +
+                        "        typo3gmbh/" + requirementIdentifier.toLowerCase() + ":latest \\\n" +
+                        "        bin/bash -c \"cd ${PWD}; find . -name \\*.php -print0 | xargs -0 -n1 -P2 php -n -c /etc/php/cli-no-xdebug/php.ini -l >/dev/null\"\n" +
+                        "}\n" +
+                        "\n" +
+                        "runLint"
                     )
             )
             .requirements(
-                requirement
+                this.getRequirementDocker10()
             )
             .cleanWorkingDirectory(true);
     }
 
     /**
      * Job for lint npm scss and typescript
+     *
+     * @param String requirementIdentifier
      */
-    protected Job getJobLintScssTs() {
+    protected Job getJobLintScssTs(String requirementIdentifier) {
         return new Job("Lint scss ts", new BambooKey("LSTS"))
             .description("Run npm lint, run npm run build-js")
             .pluginConfigurations(this.getDefaultJobPluginConfiguration())
@@ -586,19 +705,58 @@ abstract public class AbstractCoreSpec {
                     .interpreter(ScriptTaskProperties.Interpreter.BINSH_OR_CMDEXE)
                     .inlineBody(
                         this.getScriptTaskBashInlineBody() +
+                        "function yarn() {\n" +
+                        "    docker run \\\n" +
+                        "        -u ${HOST_UID} \\\n" +
+                        "        -v /etc/passwd:/etc/passwd \\\n" +
+                        "        -v ${BAMBOO_COMPOSE_PROJECT_NAME}_bamboo-data:/srv/bamboo/xml-data/build-dir/ \\\n" +
+                        "        -e HOME=${HOME} \\\n" +
+                        "        --name ${BAMBOO_COMPOSE_PROJECT_NAME}sib_adhoc \\\n" +
+                        "        --rm \\\n" +
+                        "        typo3gmbh/" + requirementIdentifier.toLowerCase() + ":latest \\\n" +
+                        "        bin/bash -c \"cd ${PWD}/Build; yarn $*\"\n" +
+                        "}\n" +
+                        "\n" +
                         "yarn install"
-                    )
-                    .workingSubdirectory("Build/"),
-                new NpmTask()
+                    ),
+                new ScriptTask()
                     .description("Run npm lint")
-                    .nodeExecutable("Node.js")
-                    .workingSubdirectory("Build/")
-                    .command("run lint"),
-                new NpmTask()
+                    .interpreter(ScriptTaskProperties.Interpreter.BINSH_OR_CMDEXE)
+                    .inlineBody(
+                        this.getScriptTaskBashInlineBody() +
+                        "function npm() {\n" +
+                        "    docker run \\\n" +
+                        "        -u ${HOST_UID} \\\n" +
+                        "        -v /etc/passwd:/etc/passwd \\\n" +
+                        "        -v ${BAMBOO_COMPOSE_PROJECT_NAME}_bamboo-data:/srv/bamboo/xml-data/build-dir/ \\\n" +
+                        "        -e HOME=${HOME} \\\n" +
+                        "        --name ${BAMBOO_COMPOSE_PROJECT_NAME}sib_adhoc \\\n" +
+                        "        --rm \\\n" +
+                        "        typo3gmbh/" + requirementIdentifier.toLowerCase() + ":latest \\\n" +
+                        "        bin/bash -c \"cd ${PWD}/Build; npm $*\"\n" +
+                        "}\n" +
+                        "\n" +
+                        "npm run lint"
+                    ),
+                new ScriptTask()
                     .description("Run npm build-js")
-                    .nodeExecutable("Node.js")
-                    .workingSubdirectory("Build/")
-                    .command("run build-js"),
+                    .interpreter(ScriptTaskProperties.Interpreter.BINSH_OR_CMDEXE)
+                    .inlineBody(
+                        this.getScriptTaskBashInlineBody() +
+                        "function npm() {\n" +
+                        "    docker run \\\n" +
+                        "        -u ${HOST_UID} \\\n" +
+                        "        -v /etc/passwd:/etc/passwd \\\n" +
+                        "        -v ${BAMBOO_COMPOSE_PROJECT_NAME}_bamboo-data:/srv/bamboo/xml-data/build-dir/ \\\n" +
+                        "        -e HOME=${HOME} \\\n" +
+                        "        --name ${BAMBOO_COMPOSE_PROJECT_NAME}sib_adhoc \\\n" +
+                        "        --rm \\\n" +
+                        "        typo3gmbh/" + requirementIdentifier.toLowerCase() + ":latest \\\n" +
+                        "        bin/bash -c \"cd ${PWD}/Build; npm $*\"\n" +
+                        "}\n" +
+                        "\n" +
+                        "npm run build-js"
+                    ),
                 new ScriptTask()
                     .description("git status to check for changed files after build-js")
                     .interpreter(ScriptTaskProperties.Interpreter.BINSH_OR_CMDEXE)
@@ -608,7 +766,7 @@ abstract public class AbstractCoreSpec {
                     )
             )
             .requirements(
-                new Requirement("system.imageVersion")
+                this.getRequirementDocker10()
             )
             .cleanWorkingDirectory(true);
     }
@@ -616,31 +774,46 @@ abstract public class AbstractCoreSpec {
     /**
      * Job for unit testing PHP
      *
-     * @param Requirement requirement
      * @param String requirementIdentfier
      */
-    protected Job getJobUnitPhp(Requirement requirement, String requirementIdentifier) {
+    protected Job getJobUnitPhp(String requirementIdentifier) {
         return new Job("Unit " + requirementIdentifier, new BambooKey("UT" + requirementIdentifier))
             .description("Run unit tests " + requirementIdentifier)
             .pluginConfigurations(this.getDefaultJobPluginConfiguration())
             .tasks(
                 this.getTaskGitCloneRepository(),
                 this.getTaskGitCherryPick(),
-                this.getTaskComposerInstall(),
+                this.getTaskComposerInstall(requirementIdentifier),
+                this.getTaskDockerDependenciesUnit(),
                 new ScriptTask()
                     .description("Run phpunit")
                     .interpreter(ScriptTaskProperties.Interpreter.BINSH_OR_CMDEXE)
                     .inlineBody(
                         this.getScriptTaskBashInlineBody() +
-                        "php -n -c /etc/php/cli-no-xdebug/php.ini bin/phpunit --log-junit test-reports/phpunit.xml -c " + this.testingFrameworkBuildPath + "UnitTests.xml"
+                        "function phpunit() {\n" +
+                        "    docker run \\\n" +
+                        "        -u ${HOST_UID} \\\n" +
+                        "        -v /etc/passwd:/etc/passwd \\\n" +
+                        "        -v ${BAMBOO_COMPOSE_PROJECT_NAME}_bamboo-data:/srv/bamboo/xml-data/build-dir/ \\\n" +
+                        "        -e typo3TestingRedisHost=redis4 \\\n" +
+                        "        -e typo3TestingMemcachedHost=memcached1-5 \\\n" +
+                        "        --name ${BAMBOO_COMPOSE_PROJECT_NAME}sib_adhoc \\\n" +
+                        "        --network ${BAMBOO_COMPOSE_PROJECT_NAME}_test \\\n" +
+                        "        --rm \\\n" +
+                        "        typo3gmbh/" + requirementIdentifier.toLowerCase() + ":latest \\\n" +
+                        "        bin/bash -c \"cd ${PWD}; php -n -c /etc/php/cli-no-xdebug/php.ini bin/phpunit $*\"\n" +
+                        "}\n" +
+                        "\n" +
+                        "phpunit --log-junit test-reports/phpunit.xml -c " + this.testingFrameworkBuildPath + "UnitTests.xml"
                     )
             )
             .finalTasks(
+                this.getTaskStopDockerDependencies(),
                 new TestParserTask(TestParserTaskProperties.TestType.JUNIT)
                     .resultDirectories("test-reports/phpunit.xml")
             )
             .requirements(
-                requirement
+                this.getRequirementDocker10()
             )
             .cleanWorkingDirectory(true);
     }
@@ -649,10 +822,9 @@ abstract public class AbstractCoreSpec {
      * Jobs for unit testing PHP in random test order
      *
      * @param int numberOfRuns
-     * @param Requirement requirement
      * @param String requirementIdentfier
      */
-    protected ArrayList<Job> getJobUnitPhpRandom(int numberOfRuns, Requirement requirement, String requirementIdentifier) {
+    protected ArrayList<Job> getJobUnitPhpRandom(int numberOfRuns, String requirementIdentifier) {
         ArrayList<Job> jobs = new ArrayList<Job>();
 
         for (int i=0; i<numberOfRuns; i++) {
@@ -662,13 +834,28 @@ abstract public class AbstractCoreSpec {
                 .tasks(
                     this.getTaskGitCloneRepository(),
                     this.getTaskGitCherryPick(),
-                    this.getTaskComposerInstall(),
+                    this.getTaskComposerInstall(requirementIdentifier),
+                    this.getTaskDockerDependenciesUnit(),
                     new ScriptTask()
                         .description("Run phpunit-randomizer")
                         .interpreter(ScriptTaskProperties.Interpreter.BINSH_OR_CMDEXE)
                         .inlineBody(
                             this.getScriptTaskBashInlineBody() +
-                            "php -n -c /etc/php/cli-no-xdebug/php.ini bin/phpunit-randomizer --log-junit test-reports/phpunit.xml -c " + this.testingFrameworkBuildPath + "UnitTests.xml --order rand"
+                            "function phpunitRandomizer() {\n" +
+                            "    docker run \\\n" +
+                            "        -u ${HOST_UID} \\\n" +
+                            "        -v /etc/passwd:/etc/passwd \\\n" +
+                            "        -v ${BAMBOO_COMPOSE_PROJECT_NAME}_bamboo-data:/srv/bamboo/xml-data/build-dir/ \\\n" +
+                            "        -e typo3TestingRedisHost=redis4 \\\n" +
+                            "        -e typo3TestingMemcachedHost=memcached1-5 \\\n" +
+                            "        --name ${BAMBOO_COMPOSE_PROJECT_NAME}sib_adhoc \\\n" +
+                            "        --network ${BAMBOO_COMPOSE_PROJECT_NAME}_test \\\n" +
+                            "        --rm \\\n" +
+                            "        typo3gmbh/" + requirementIdentifier.toLowerCase() + ":latest \\\n" +
+                            "        bin/bash -c \"cd ${PWD}; php -n -c /etc/php/cli-no-xdebug/php.ini bin/phpunit-randomizer $*\"\n" +
+                            "}\n" +
+                            "\n" +
+                            "phpunitRandomizer --log-junit test-reports/phpunit.xml -c " + this.testingFrameworkBuildPath + "UnitTests.xml --order rand"
                         )
                 )
                 .finalTasks(
@@ -676,7 +863,7 @@ abstract public class AbstractCoreSpec {
                         .resultDirectories("test-reports/phpunit.xml")
                 )
                 .requirements(
-                    requirement
+                    this.getRequirementDocker10()
                 )
                 .cleanWorkingDirectory(true)
             );
@@ -691,8 +878,7 @@ abstract public class AbstractCoreSpec {
     protected Task getTaskGitCloneRepository() {
         return new VcsCheckoutTask()
             .description("Checkout git core")
-            .checkoutItems(new CheckoutItem().defaultRepository())
-            .cleanCheckout(true);
+            .checkoutItems(new CheckoutItem().defaultRepository());
     }
 
     /**
@@ -716,12 +902,18 @@ abstract public class AbstractCoreSpec {
 
     /**
      * Task definition to execute composer install
+     *
+     * @param String requirementIdentifier
      */
-    protected Task getTaskComposerInstall() {
-        return new CommandTask()
+    protected Task getTaskComposerInstall(String requirementIdentifier) {
+        return new ScriptTask()
             .description("composer install")
-            .executable("composer")
-            .argument("install -n")
+            .interpreter(ScriptTaskProperties.Interpreter.BINSH_OR_CMDEXE)
+            .inlineBody(
+                this.getScriptTaskBashInlineBody() +
+                this.getScriptTaskComposer(requirementIdentifier) +
+                "composer install -n"
+            )
             .environmentVariables(this.composerRootVersionEnvironment);
     }
 
@@ -745,80 +937,61 @@ abstract public class AbstractCoreSpec {
     }
 
     /**
-     * Task to delete any created mysql test databases, used as final task
+     * Start docker sibling containers to execute functional tests on mariadb
      */
-    protected Task getTaskDeleteMysqlDatabases() {
+    protected Task getTaskDockerDependenciesFunctionalMariadb10() {
         return new ScriptTask()
-            .description("Delete mysql test dbs")
+            .description("Start docker siblings for functional tests on mariadb")
             .interpreter(ScriptTaskProperties.Interpreter.BINSH_OR_CMDEXE)
             .inlineBody(
                 this.getScriptTaskBashInlineBody() +
-                "DB_STARTS_WITH=\"func_\"\n" +
-                "MUSER=\"funcu\"\n" +
-                "MPWD=\"funcp\"\n" +
-                "MYSQL=\"mysql\"\n" +
-                "DBS=\"$($MYSQL -u $MUSER -p\"$MPWD\" -Bse 'show databases')\"\n" +
-                "\n" +
-                "for db in $DBS; do\n" +
-                "    if [[ \"$db\" == $DB_STARTS_WITH* ]]; then\n" +
-                "        echo \"Deleting $db\"\n" +
-                "        $MYSQL -u $MUSER -p\"$MPWD\" -Bse \"drop database $db\"\n" +
-                "    fi\n" +
-                "done\n"
+                "cd Build/testing-docker/bamboo\n" +
+                "echo COMPOSE_PROJECT_NAME=${BAMBOO_COMPOSE_PROJECT_NAME}sib > .env\n" +
+                "docker-compose run start_dependencies_functional_mariadb10"
             );
     }
 
     /**
-     * Task to delete any created mssql test databases, used as final task
+     * Start docker sibling containers to execute functional tests on postgres
      */
-    protected Task getTaskDeleteMssqlDatabases() {
+    protected Task getTaskDockerDependenciesFunctionalPostgres95() {
         return new ScriptTask()
-            .description("Delete mssql test dbs")
+            .description("Start docker siblings for functional tests on postgres9-5")
             .interpreter(ScriptTaskProperties.Interpreter.BINSH_OR_CMDEXE)
             .inlineBody(
                 this.getScriptTaskBashInlineBody() +
-                "DBS=`/opt/mssql-tools/bin/sqlcmd -S localhost -U SA -P 'Test1234!' -Q 'select name from sys.databases' | grep '^func_'`\n" +
-                "\n" +
-                "for db in $DBS; do\n" +
-                "    echo \"Deleteing $db\"\n" +
-                "    /opt/mssql-tools/bin/sqlcmd -S localhost -U SA -P 'Test1234!' -Q \"drop database $db\"\n" +
-                "done\n"
+                "cd Build/testing-docker/bamboo\n" +
+                "echo COMPOSE_PROJECT_NAME=${BAMBOO_COMPOSE_PROJECT_NAME}sib > .env\n" +
+                "docker-compose run start_dependencies_functional_postgres9-5"
             );
     }
 
     /**
-     * Task to delete any created pgsql test databases, used as final task
+     * Start docker sibling containers to execute unit tests
      */
-    protected Task getTaskDeletePgsqlDatabases() {
+    protected Task getTaskDockerDependenciesUnit() {
         return new ScriptTask()
-            .description("Delete pgsql test dbs")
+            .description("Start docker siblings for unit tests")
             .interpreter(ScriptTaskProperties.Interpreter.BINSH_OR_CMDEXE)
             .inlineBody(
                 this.getScriptTaskBashInlineBody() +
-                "DB_STARTS_WITH=\"func_\"\n" +
-                "PGUSER=\"bamboo\"\n" +
-                "DBS=\"$(/usr/bin/psql -qtA -p 5433 -c 'SELECT datname FROM pg_database WHERE datistemplate = false;' postgres)\"\n" +
-                "\n" +
-                "for db in $DBS; do\n" +
-                "    if [[ \"$db\" == $DB_STARTS_WITH* ]]; then\n" +
-                "        echo \"Deleting $db\"\n" +
-                "        /usr/bin/psql -qtA -p 5433 -c \"DROP DATABASE $db\" postgres\n" +
-                "    fi\n" +
-                "done\n"
+                "cd Build/testing-docker/bamboo\n" +
+                "echo COMPOSE_PROJECT_NAME=${BAMBOO_COMPOSE_PROJECT_NAME}sib > .env\n" +
+                "docker-compose run start_dependencies_unit"
             );
     }
 
     /**
-     * Task to stop selenium and friends, opposite of getTaskPrepareAcceptanceTest, used as final task
+     * Stop started docker containers
      */
-    protected Task getTaskTearDownAcceptanceTestSetup() {
+    protected Task getTaskStopDockerDependencies() {
         return new ScriptTask()
-            .description("Stop acceptance test services like chromedriver and friends")
+            .description("Stop docker siblings")
             .interpreter(ScriptTaskProperties.Interpreter.BINSH_OR_CMDEXE)
             .inlineBody(
                 this.getScriptTaskBashInlineBody() +
-                "kill -9 `cat phpserver.pid`\n" +
-                "kill `cat chromedriver.pid`\n"
+                "cd Build/testing-docker/bamboo\n" +
+                "docker-compose down -v"
             );
     }
 
@@ -836,51 +1009,15 @@ abstract public class AbstractCoreSpec {
     }
 
     /**
-     * Requirement for php 7.0
-     */
-    protected Requirement getRequirementPhpVersion70() {
-        return new Requirement("system.phpVersion")
-            .matchValue("7.0")
-            .matchType(Requirement.MatchType.EQUALS);
-    }
-
-    /**
-     * Requirement for php 7.1
+     * Requirement for docker 1.0 set by bamboo-agents
      */
-    protected Requirement getRequirementPhpVersion71() {
-        return new Requirement("system.phpVersion")
-            .matchValue("7.1")
+    protected Requirement getRequirementDocker10() {
+        return new Requirement("system.hasDocker")
+            .matchValue("1.0")
             .matchType(Requirement.MatchType.EQUALS);
     }
 
     /**
-     * Requirement for php 7.2
-     */
-    protected Requirement getRequirementPhpVersion72() {
-        return new Requirement("system.phpVersion")
-            .matchValue("7.2")
-            .matchType(Requirement.MatchType.EQUALS);
-    }
-
-    /**
-     * Requirement for php 7.0 or 7.1
-     */
-    protected Requirement getRequirementPhpVersion70Or71() {
-        return new Requirement("system.phpVersion")
-            .matchValue("7\\.0|7\\.1")
-            .matchType(Requirement.MatchType.MATCHES);
-    }
-
-    /**
-     * Requirement for php 7.0 or 7.1 or 7.2
-     */
-    protected Requirement getRequirementPhpVersion70Or71Or72() {
-        return new Requirement("system.phpVersion")
-            .matchValue("7\\.0|7\\.1|7\\.2")
-            .matchType(Requirement.MatchType.MATCHES);
-    }
-
-    /**
      * A bash header for script tasks forking a bash if needed
      */
     protected String getScriptTaskBashInlineBody() {
@@ -891,6 +1028,30 @@ abstract public class AbstractCoreSpec {
             "    bash \"$0\" \"$@\"\n" +
             "    exit \"$?\"\n" +
             "fi\n" +
+            "\n" +
+            "set -x\n" +
+            "\n";
+    }
+
+    /**
+     * A bash function aliasing 'composer' as docker command
+     *
+     * @param String requirementIdentifier
+     */
+    protected String getScriptTaskComposer(String requirementIdentifier) {
+        return
+            "function composer() {\n" +
+            "    docker run \\\n" +
+            "        -u ${HOST_UID} \\\n" +
+            "        -v /etc/passwd:/etc/passwd \\\n" +
+            "        -v ${BAMBOO_COMPOSE_PROJECT_NAME}_bamboo-data:/srv/bamboo/xml-data/build-dir/ \\\n" +
+            "        -e COMPOSER_ROOT_VERSION=${COMPOSER_ROOT_VERSION} \\\n" +
+            "        -e HOME=${HOME} \\\n" +
+            "        --name ${BAMBOO_COMPOSE_PROJECT_NAME}sib_adhoc \\\n" +
+            "        --rm \\\n" +
+            "        typo3gmbh/" + requirementIdentifier.toLowerCase() + ":latest \\\n" +
+            "        bin/bash -c \"cd ${PWD}; composer $*\"\n" +
+            "}\n" +
             "\n";
     }
 }
index 1b842d7..0d0bd83 100644 (file)
@@ -65,61 +65,54 @@ public class NightlySpec extends AbstractCoreSpec {
      * Returns full Plan definition
      */
     Plan createPlan() {
-        // PREPARATION stage
-        ArrayList<Job> jobsPreparationStage = new ArrayList<Job>();
-
-        jobsPreparationStage.add(this.getJobComposerValidate());
-
-        Stage stagePreparation = new Stage("Preparation")
-            .jobs(jobsPreparationStage.toArray(new Job[jobsPreparationStage.size()]));
-
-
         // MAIN stage
         ArrayList<Job> jobsMainStage = new ArrayList<Job>();
 
-        jobsMainStage.add(this.getJobAcceptanceTestInstallMysql(this.getRequirementPhpVersion70(), "PHP70"));
-        jobsMainStage.add(this.getJobAcceptanceTestInstallMysql(this.getRequirementPhpVersion71(), "PHP71"));
-        jobsMainStage.add(this.getJobAcceptanceTestInstallMysql(this.getRequirementPhpVersion72(), "PHP72"));
+        jobsMainStage.add(this.getJobComposerValidate("PHP72"));
+
+        jobsMainStage.add(this.getJobAcceptanceTestInstallMysql("PHP70"));
+        jobsMainStage.add(this.getJobAcceptanceTestInstallMysql("PHP71"));
+        jobsMainStage.add(this.getJobAcceptanceTestInstallMysql("PHP72"));
 
-        jobsMainStage.add(this.getJobAcceptanceTestInstallPgsql(this.getRequirementPhpVersion70(), "PHP70"));
-        jobsMainStage.add(this.getJobAcceptanceTestInstallPgsql(this.getRequirementPhpVersion71(), "PHP71"));
-        jobsMainStage.add(this.getJobAcceptanceTestInstallPgsql(this.getRequirementPhpVersion72(), "PHP72"));
+        jobsMainStage.add(this.getJobAcceptanceTestInstallPgsql("PHP70"));
+        jobsMainStage.add(this.getJobAcceptanceTestInstallPgsql("PHP71"));
+        jobsMainStage.add(this.getJobAcceptanceTestInstallPgsql("PHP72"));
 
-        jobsMainStage.addAll(this.getJobsAcceptanceTestsMysql(this.numberOfAcceptanceTestJobs, this.getRequirementPhpVersion70(), "PHP70"));
-        jobsMainStage.addAll(this.getJobsAcceptanceTestsMysql(this.numberOfAcceptanceTestJobs, this.getRequirementPhpVersion71(), "PHP71"));
-        jobsMainStage.addAll(this.getJobsAcceptanceTestsMysql(this.numberOfAcceptanceTestJobs, this.getRequirementPhpVersion72(), "PHP72"));
+        jobsMainStage.addAll(this.getJobsAcceptanceTestsMysql(this.numberOfAcceptanceTestJobs, "PHP70"));
+        jobsMainStage.addAll(this.getJobsAcceptanceTestsMysql(this.numberOfAcceptanceTestJobs, "PHP71"));
+        jobsMainStage.addAll(this.getJobsAcceptanceTestsMysql(this.numberOfAcceptanceTestJobs, "PHP72"));
 
-        jobsMainStage.add(this.getJobCglCheckFullCore());
+        jobsMainStage.add(this.getJobCglCheckFullCore("PHP72"));
 
-        jobsMainStage.add(this.getJobIntegrationVarious());
+        jobsMainStage.add(this.getJobIntegrationVarious("PHP72"));
 
-        jobsMainStage.addAll(this.getJobsFunctionalTestsMysql(this.numberOfFunctionalMysqlJobs, this.getRequirementPhpVersion70(), "PHP70"));
-        jobsMainStage.addAll(this.getJobsFunctionalTestsMysql(this.numberOfFunctionalMysqlJobs, this.getRequirementPhpVersion71(), "PHP71"));
-        jobsMainStage.addAll(this.getJobsFunctionalTestsMysql(this.numberOfFunctionalMysqlJobs, this.getRequirementPhpVersion72(), "PHP72"));
+        jobsMainStage.addAll(this.getJobsFunctionalTestsMysql(this.numberOfFunctionalMysqlJobs, "PHP70"));
+        jobsMainStage.addAll(this.getJobsFunctionalTestsMysql(this.numberOfFunctionalMysqlJobs, "PHP71"));
+        jobsMainStage.addAll(this.getJobsFunctionalTestsMysql(this.numberOfFunctionalMysqlJobs, "PHP72"));
 
-        jobsMainStage.addAll(this.getJobsFunctionalTestsMssql(this.numberOfFunctionalMssqlJobs, this.getRequirementPhpVersion70(), "PHP70"));
-        jobsMainStage.addAll(this.getJobsFunctionalTestsMssql(this.numberOfFunctionalMssqlJobs, this.getRequirementPhpVersion71(), "PHP71"));
-        jobsMainStage.addAll(this.getJobsFunctionalTestsMssql(this.numberOfFunctionalMssqlJobs, this.getRequirementPhpVersion72(), "PHP72"));
+        jobsMainStage.addAll(this.getJobsFunctionalTestsMssql(this.numberOfFunctionalMssqlJobs, "PHP70"));
+        jobsMainStage.addAll(this.getJobsFunctionalTestsMssql(this.numberOfFunctionalMssqlJobs, "PHP71"));
+        jobsMainStage.addAll(this.getJobsFunctionalTestsMssql(this.numberOfFunctionalMssqlJobs, "PHP72"));
 
-        jobsMainStage.addAll(this.getJobsFunctionalTestsPgsql(this.numberOfFunctionalPgsqlJobs, this.getRequirementPhpVersion70(), "PHP70"));
-        jobsMainStage.addAll(this.getJobsFunctionalTestsPgsql(this.numberOfFunctionalPgsqlJobs, this.getRequirementPhpVersion71(), "PHP71"));
-        jobsMainStage.addAll(this.getJobsFunctionalTestsPgsql(this.numberOfFunctionalPgsqlJobs, this.getRequirementPhpVersion72(), "PHP72"));
+        jobsMainStage.addAll(this.getJobsFunctionalTestsPgsql(this.numberOfFunctionalPgsqlJobs, "PHP70"));
+        jobsMainStage.addAll(this.getJobsFunctionalTestsPgsql(this.numberOfFunctionalPgsqlJobs, "PHP71"));
+        jobsMainStage.addAll(this.getJobsFunctionalTestsPgsql(this.numberOfFunctionalPgsqlJobs, "PHP72"));
 
-        jobsMainStage.add(this.getJobUnitJavaScript());
+        jobsMainStage.add(this.getJobUnitJavaScript("PHP72"));
 
-        jobsMainStage.add(this.getJobLintPhp(this.getRequirementPhpVersion70(), "PHP70"));
-        jobsMainStage.add(this.getJobLintPhp(this.getRequirementPhpVersion71(), "PHP71"));
-        jobsMainStage.add(this.getJobLintPhp(this.getRequirementPhpVersion72(), "PHP72"));
+        jobsMainStage.add(this.getJobLintPhp("PHP70"));
+        jobsMainStage.add(this.getJobLintPhp("PHP71"));
+        jobsMainStage.add(this.getJobLintPhp("PHP72"));
 
-        jobsMainStage.add(this.getJobLintScssTs());
+        jobsMainStage.add(this.getJobLintScssTs("PHP72"));
 
-        jobsMainStage.add(this.getJobUnitPhp(this.getRequirementPhpVersion70(), "PHP70"));
-        jobsMainStage.add(this.getJobUnitPhp(this.getRequirementPhpVersion71(), "PHP71"));
-        jobsMainStage.add(this.getJobUnitPhp(this.getRequirementPhpVersion72(), "PHP72"));
+        jobsMainStage.add(this.getJobUnitPhp("PHP70"));
+        jobsMainStage.add(this.getJobUnitPhp("PHP71"));
+        jobsMainStage.add(this.getJobUnitPhp("PHP72"));
 
-        jobsMainStage.addAll(this.getJobUnitPhpRandom(this.numberOfUnitRandomOrderJobs, this.getRequirementPhpVersion70(), "PHP70"));
-        jobsMainStage.addAll(this.getJobUnitPhpRandom(this.numberOfUnitRandomOrderJobs, this.getRequirementPhpVersion71(), "PHP71"));
-        jobsMainStage.addAll(this.getJobUnitPhpRandom(this.numberOfUnitRandomOrderJobs, this.getRequirementPhpVersion72(), "PHP72"));
+        jobsMainStage.addAll(this.getJobUnitPhpRandom(this.numberOfUnitRandomOrderJobs, "PHP70"));
+        jobsMainStage.addAll(this.getJobUnitPhpRandom(this.numberOfUnitRandomOrderJobs, "PHP71"));
+        jobsMainStage.addAll(this.getJobUnitPhpRandom(this.numberOfUnitRandomOrderJobs, "PHP72"));
 
         Stage stageMainStage = new Stage("Main stage")
             .jobs(jobsMainStage.toArray(new Job[jobsMainStage.size()]));
@@ -130,7 +123,6 @@ public class NightlySpec extends AbstractCoreSpec {
             .description("Execute TYPO3 core 8.7 nightly tests. Auto generated! See Build/bamboo of core git repository.")
             .pluginConfigurations(this.getDefaultPlanPluginConfiguration())
             .stages(
-                stagePreparation,
                 stageMainStage
             )
             .linkedRepositories("git.typo3.org Core 8.7")
@@ -154,26 +146,39 @@ public class NightlySpec extends AbstractCoreSpec {
 
     /**
      * Job checking CGL of all core php files
+     *
+     * @param String requirementIdentifier
      */
-    protected Job getJobCglCheckFullCore() {
+    protected Job getJobCglCheckFullCore(String requirementIdentifier) {
         return new Job("Integration CGL", new BambooKey("CGLCHECK"))
             .description("Check coding guidelines of full core")
             .pluginConfigurations(this.getDefaultJobPluginConfiguration())
             .tasks(
                 this.getTaskGitCloneRepository(),
                 this.getTaskGitCherryPick(),
-                this.getTaskComposerInstall(),
+                this.getTaskComposerInstall(requirementIdentifier),
                 new ScriptTask()
                     .description("Execute cgl check")
                     .interpreter(ScriptTaskProperties.Interpreter.BINSH_OR_CMDEXE)
                     .inlineBody(
                         this.getScriptTaskBashInlineBody() +
-                        "php -n -c /etc/php/cli-no-xdebug/php.ini bin/php-cs-fixer fix -v --dry-run --path-mode intersection --config=Build/.php_cs typo3/\n" +
-                        "exit $?\n"
+                        "function phpCsFixer() {\n" +
+                        "    docker run \\\n" +
+                        "        -u ${HOST_UID} \\\n" +
+                        "        -v /etc/passwd:/etc/passwd \\\n" +
+                        "        -v ${BAMBOO_COMPOSE_PROJECT_NAME}_bamboo-data:/srv/bamboo/xml-data/build-dir/ \\\n" +
+                        "        --name ${BAMBOO_COMPOSE_PROJECT_NAME}sib_adhoc \\\n" +
+                        "        --rm \\\n" +
+                        "        typo3gmbh/" + requirementIdentifier.toLowerCase() + ":latest \\\n" +
+                        "        bin/bash -c \"cd ${PWD}; php -n -c /etc/php/cli-no-xdebug/php.ini bin/php-cs-fixer $*\"\n" +
+                        "}\n" +
+                        "\n" +
+                        "phpCsFixer fix -v --dry-run --path-mode intersection --config=Build/.php_cs typo3/\n" +
+                        "exit $?"
                     )
             )
             .requirements(
-                this.getRequirementPhpVersion70Or71Or72()
+                this.getRequirementDocker10()
             )
             .cleanWorkingDirectory(true);
     }
index 6ea6e9c..0374c48 100644 (file)
@@ -75,47 +75,48 @@ public class PreMergeSpec extends AbstractCoreSpec {
     Plan createPlan() {
         // PREPARATION stage
         ArrayList<Job> jobsPreparationStage = new ArrayList<Job>();
-
         jobsPreparationStage.add(this.getJobBuildLabels());
-
-        jobsPreparationStage.add(this.getJobCglCheckGitCommit());
-
-        jobsPreparationStage.add(this.getJobComposerValidate());
-
         Stage stagePreparation = new Stage("Preparation")
             .jobs(jobsPreparationStage.toArray(new Job[jobsPreparationStage.size()]));
 
+        // EARLY stage
+        ArrayList<Job> jobsEarlyStage = new ArrayList<Job>();
+        jobsEarlyStage.add(this.getJobCglCheckGitCommit("PHP72"));
+        jobsEarlyStage.add(this.getJobComposerValidate("PHP72"));
+        Stage stageEarly = new Stage("Early")
+            .jobs(jobsEarlyStage.toArray(new Job[jobsEarlyStage.size()]));
+
         // MAIN stage
         ArrayList<Job> jobsMainStage = new ArrayList<Job>();
 
-        jobsMainStage.add(this.getJobAcceptanceTestInstallMysql(this.getRequirementPhpVersion70Or71Or72(), "PHP707172"));
-        jobsMainStage.add(this.getJobAcceptanceTestInstallPgsql(this.getRequirementPhpVersion70Or71Or72(), "PHP707172"));
+        // @todo: decide on specific php version this should run on
+        jobsMainStage.add(this.getJobAcceptanceTestInstallMysql("PHP72"));
+        jobsMainStage.add(this.getJobAcceptanceTestInstallPgsql("PHP72"));
 
-        jobsMainStage.addAll(this.getJobsAcceptanceTestsMysql(this.numberOfAcceptanceTestJobs, this.getRequirementPhpVersion70Or71Or72(), "PHP707172"));
+        // @todo: decide on specific php version this should run on
+        jobsMainStage.addAll(this.getJobsAcceptanceTestsMysql(this.numberOfAcceptanceTestJobs, "PHP72"));
 
-        jobsMainStage.add(this.getJobIntegrationVarious());
+        jobsMainStage.add(this.getJobIntegrationVarious("PHP72"));
 
-        jobsMainStage.addAll(this.getJobsFunctionalTestsMysql(this.numberOfFunctionalMysqlJobs, this.getRequirementPhpVersion70Or71Or72(), "PHP707172"));
+        jobsMainStage.addAll(this.getJobsFunctionalTestsMysql(this.numberOfFunctionalMysqlJobs, "PHP70"));
+        jobsMainStage.addAll(this.getJobsFunctionalTestsMssql(this.numberOfFunctionalMssqlJobs, "PHP71"));
+        jobsMainStage.addAll(this.getJobsFunctionalTestsPgsql(this.numberOfFunctionalPgsqlJobs, "PHP72"));
 
-        jobsMainStage.addAll(this.getJobsFunctionalTestsMssql(this.numberOfFunctionalMssqlJobs, this.getRequirementPhpVersion70Or71Or72(), "PHP707172"));
+        jobsMainStage.add(this.getJobUnitJavaScript("PHP72"));
 
-        jobsMainStage.addAll(this.getJobsFunctionalTestsPgsql(this.numberOfFunctionalPgsqlJobs, this.getRequirementPhpVersion70Or71Or72(), "PHP707172"));
+        jobsMainStage.add(this.getJobLintPhp("PHP70"));
+        jobsMainStage.add(this.getJobLintPhp("PHP71"));
+        jobsMainStage.add(this.getJobLintPhp("PHP72"));
 
-        jobsMainStage.add(this.getJobUnitJavaScript());
+        jobsMainStage.add(this.getJobLintScssTs("PHP72"));
 
-        jobsMainStage.add(this.getJobLintPhp(this.getRequirementPhpVersion70(), "PHP70"));
-        jobsMainStage.add(this.getJobLintPhp(this.getRequirementPhpVersion71(), "PHP71"));
-        jobsMainStage.add(this.getJobLintPhp(this.getRequirementPhpVersion72(), "PHP72"));
+        jobsMainStage.add(this.getJobUnitPhp("PHP70"));
+        jobsMainStage.add(this.getJobUnitPhp("PHP71"));
+        jobsMainStage.add(this.getJobUnitPhp("PHP72"));
 
-        jobsMainStage.add(this.getJobLintScssTs());
-
-        jobsMainStage.add(this.getJobUnitPhp(this.getRequirementPhpVersion70(), "PHP70"));
-        jobsMainStage.add(this.getJobUnitPhp(this.getRequirementPhpVersion71(), "PHP71"));
-        jobsMainStage.add(this.getJobUnitPhp(this.getRequirementPhpVersion72(), "PHP72"));
-
-        jobsMainStage.addAll(this.getJobUnitPhpRandom(this.numberOfUnitRandomOrderJobs, this.getRequirementPhpVersion70(), "PHP70"));
-        jobsMainStage.addAll(this.getJobUnitPhpRandom(this.numberOfUnitRandomOrderJobs, this.getRequirementPhpVersion71(), "PHP71"));
-        jobsMainStage.addAll(this.getJobUnitPhpRandom(this.numberOfUnitRandomOrderJobs, this.getRequirementPhpVersion72(), "PHP72"));
+        jobsMainStage.addAll(this.getJobUnitPhpRandom(this.numberOfUnitRandomOrderJobs, "PHP70"));
+        jobsMainStage.addAll(this.getJobUnitPhpRandom(this.numberOfUnitRandomOrderJobs, "PHP71"));
+        jobsMainStage.addAll(this.getJobUnitPhpRandom(this.numberOfUnitRandomOrderJobs, "PHP72"));
 
         Stage stageMainStage = new Stage("Main stage")
             .jobs(jobsMainStage.toArray(new Job[jobsMainStage.size()]));
@@ -126,6 +127,7 @@ public class PreMergeSpec extends AbstractCoreSpec {
             .pluginConfigurations(this.getDefaultPlanPluginConfiguration())
             .stages(
                 stagePreparation,
+                stageEarly,
                 stageMainStage
             )
             .linkedRepositories("git.typo3.org Core 8.7")
@@ -186,30 +188,46 @@ public class PreMergeSpec extends AbstractCoreSpec {
                     .interpreter(ScriptTaskProperties.Interpreter.BINSH_OR_CMDEXE)
                     .inlineBody("echo \"I'm just here for the labels!\"")
             )
+            .requirements(
+                this.getRequirementDocker10()
+            )
             .cleanWorkingDirectory(true);
     }
 
     /**
      * Job checking CGL of last git commit
+     *
+     * @param String requirementIdentifier
      */
-    protected Job getJobCglCheckGitCommit() {
+    protected Job getJobCglCheckGitCommit(String requirementIdentifier) {
         return new Job("Integration CGL", new BambooKey("CGLCHECK"))
             .description("Check coding guidelines by executing Build/Scripts/cglFixMyCommit.sh script")
             .pluginConfigurations(this.getDefaultJobPluginConfiguration())
             .tasks(
                 this.getTaskGitCloneRepository(),
                 this.getTaskGitCherryPick(),
-                this.getTaskComposerInstall(),
+                this.getTaskComposerInstall(requirementIdentifier),
                 new ScriptTask()
                     .description("Execute cgl check script")
                     .interpreter(ScriptTaskProperties.Interpreter.BINSH_OR_CMDEXE)
                     .inlineBody(
                         this.getScriptTaskBashInlineBody() +
-                        "./Build/Scripts/cglFixMyCommit.sh dryrun\n"
+                        "function cglFixMyCommit() {\n" +
+                        "    docker run \\\n" +
+                        "        -u ${HOST_UID} \\\n" +
+                        "        -v /etc/passwd:/etc/passwd \\\n" +
+                        "        -v ${BAMBOO_COMPOSE_PROJECT_NAME}_bamboo-data:/srv/bamboo/xml-data/build-dir/ \\\n" +
+                        "        --name ${BAMBOO_COMPOSE_PROJECT_NAME}sib_adhoc \\\n" +
+                        "        --rm \\\n" +
+                        "        typo3gmbh/" + requirementIdentifier.toLowerCase() + ":latest \\\n" +
+                        "        bin/bash -c \"cd ${PWD}; ./Build/Scripts/cglFixMyCommit.sh $*\"\n" +
+                        "}\n" +
+                        "\n" +
+                        "cglFixMyCommit dryrun\n"
                     )
             )
             .requirements(
-                this.getRequirementPhpVersion70Or71Or72()
+                this.getRequirementDocker10()
             )
             .cleanWorkingDirectory(true);
     }
diff --git a/Build/testing-docker/bamboo/docker-compose.yml b/Build/testing-docker/bamboo/docker-compose.yml
new file mode 100644 (file)
index 0000000..adc3648
--- /dev/null
@@ -0,0 +1,134 @@
+version: '2.3'
+services:
+  chrome:
+    image: selenium/standalone-chrome:3.12
+    networks:
+      - test
+  mariadb10:
+    image: mariadb:10.1
+    environment:
+      MYSQL_ROOT_PASSWORD: funcp
+    tmpfs:
+      - /var/lib/mysql/:rw,noexec,nosuid
+    networks:
+      - test
+  postgres9-5:
+    image: postgres:9.5
+    environment:
+      POSTGRES_PASSWORD: funcp
+      POSTGRES_USER: ${HOST_USER}
+    volumes:
+      - /etc/passwd:/etc/passwd,ro
+    tmpfs:
+      - /var/lib/postgresql/data:rw,noexec,nosuid
+    networks:
+      - test
+  redis4:
+    image: redis:4-alpine
+    networks:
+      - test
+  memcached1-5:
+    image: memcached:1.5-alpine
+    networks:
+      - test
+  web:
+    image: typo3gmbh/php72:latest
+    user: ${HOST_UID}
+    stop_grace_period: 1s
+    networks:
+      - test
+    volumes:
+      - bamboo-data:/srv/bamboo/xml-data/build-dir
+    command: php -n -c /etc/php/cli-no-xdebug/php.ini -S web:8000 -t /srv/bamboo/xml-data/build-dir/${bamboo_buildKey}
+
+  start_dependencies_acceptance_install_mariadb10:
+    image: alpine:3.8
+    links:
+      - mariadb10
+      - chrome
+      - web
+    networks:
+      - test
+    command: >
+      /bin/sh -c "
+        echo Waiting for db start...;
+        while ! nc -z mariadb10 3306;
+        do
+          sleep 1;
+        done;
+        echo Connected!;
+      "
+
+  start_dependencies_acceptance_install_postgres9-5:
+    image: alpine:3.8
+    links:
+      - postgres9-5
+      - chrome
+      - web
+    networks:
+      - test
+    command: >
+      /bin/sh -c "
+        echo Waiting for db start...;
+        while ! nc -z postgres9-5 5432;
+        do
+          sleep 1;
+        done;
+        echo Connected!;
+      "
+
+  start_dependencies_functional_mariadb10:
+    image: alpine:3.8
+    links:
+      - mariadb10
+      - redis4
+      - memcached1-5
+    networks:
+      - test
+    command: >
+      /bin/sh -c "
+        echo Waiting for db start...;
+        while ! nc -z mariadb10 3306;
+        do
+          sleep 1;
+        done;
+        echo Connected!;
+      "
+
+  start_dependencies_functional_postgres9-5:
+    image: alpine:3.8
+    links:
+      - postgres9-5
+      - redis4
+      - memcached1-5
+    networks:
+      - test
+    command: >
+      /bin/sh -c "
+        echo Waiting for db start...;
+        while ! nc -z postgres9-5 5432;
+        do
+          sleep 1;
+        done;
+        echo Connected!;
+      "
+
+  start_dependencies_unit:
+    image: alpine:3.8
+    links:
+      - redis4
+      - memcached1-5
+    command: >
+      /bin/sh -c "
+        sleep 1;
+      "
+
+networks:
+  test:
+    external:
+      name: ${BAMBOO_COMPOSE_PROJECT_NAME}_test
+
+volumes:
+  bamboo-data:
+    external:
+      name: ${BAMBOO_COMPOSE_PROJECT_NAME}_bamboo-data
\ No newline at end of file
index eb386c8..b235394 100644 (file)
@@ -216,7 +216,9 @@ class DatabaseConnectionTest extends \TYPO3\TestingFramework\Core\Functional\Fun
     public function disconnectIfConnectedDisconnects()
     {
         $this->assertTrue($this->subject->isConnected());
-        $this->subject->setDatabaseHost('127.0.0.1');
+        $env = getenv('typo3DatabaseHost');
+        $databaseHost = is_string($env) ? trim($env) : '127.0.0.1';
+        $this->subject->setDatabaseHost($databaseHost);
         $this->assertFalse($this->subject->isConnected());
     }
 
index 76a8bc3..1a98c0b 100644 (file)
@@ -51,15 +51,20 @@ class RedisSessionBackendTest extends FunctionalTestCase
         if (!extension_loaded('redis')) {
             $this->markTestSkipped('redis extension was not available');
         }
-        try {
-            if (!@fsockopen('127.0.0.1', 6379)) {
-                $this->markTestSkipped('redis server not reachable');
-            }
-        } catch (\Exception $e) {
-            $this->markTestSkipped('redis server not reachable');
+        if (!getenv('typo3TestingRedisHost')) {
+            $this->markTestSkipped('environment variable "typo3TestingRedisHost" must be set to run this test');
         }
+        // Note we assume that if that typo3TestingRedisHost env is set, we can use that for testing,
+        // there is no test to see if the daemon is actually up and running. Tests will fail if env
+        // is set but daemon is down.
+
+        // We know this env is set, otherwise setUp() would skip the tests
+        $redisHost = getenv('typo3TestingRedisHost');
+        // If typo3TestingRedisPort env is set, use it, otherwise fall back to standard port
+        $env = getenv('typo3TestingRedisPort');
+        $redisPort = is_string($env) ? (int)$env : 6379;
         $redis = new \Redis();
-        $redis->connect('127.0.0.1');
+        $redis->connect($redisHost, $redisPort);
         $redis->select(0);
         // Clear db to ensure no sessions exist currently
         $redis->flushDB();
@@ -69,8 +74,8 @@ class RedisSessionBackendTest extends FunctionalTestCase
             'default',
             [
                 'database' => 0,
-                'port' => 6379,
-                'hostname' => 'localhost',
+                'port' => $redisPort,
+                'hostname' => $redisHost
             ]
         );
     }
index 2fa908a..8b501f8 100644 (file)
@@ -15,13 +15,14 @@ namespace TYPO3\CMS\Core\Tests\Unit\Cache\Backend;
  */
 
 use TYPO3\CMS\Core\Cache\Backend\MemcachedBackend;
+use TYPO3\TestingFramework\Core\Unit\UnitTestCase;
 
 /**
  * Testcase for the cache to memcached backend
  *
  * This file is a backport from FLOW3
  */
-class MemcachedBackendTest extends \TYPO3\TestingFramework\Core\Unit\UnitTestCase
+class MemcachedBackendTest extends UnitTestCase
 {
     /**
      * Sets up this testcase
@@ -31,13 +32,32 @@ class MemcachedBackendTest extends \TYPO3\TestingFramework\Core\Unit\UnitTestCas
         if (!extension_loaded('memcache') && !extension_loaded('memcached')) {
             $this->markTestSkipped('Neither "memcache" nor "memcached" extension was available');
         }
-        try {
-            if (!@fsockopen('localhost', 11211)) {
-                $this->markTestSkipped('memcached not reachable');
-            }
-        } catch (\Exception $e) {
-            $this->markTestSkipped('memcached not reachable');
+        if (!getenv('typo3TestingMemcachedHost')) {
+            $this->markTestSkipped('environment variable "typo3TestingMemcachedHost" must be set to run this test');
         }
+        // Note we assume that if that typo3TestingMemcachedHost env is set, we can use that for testing,
+        // there is no test to see if the daemon is actually up and running. Tests will fail if env
+        // is set but daemon is down.
+    }
+
+    /**
+     * Initialize MemcacheBackend ($subject)
+     */
+    protected function initializeSubject(): MemcachedBackend
+    {
+        // We know this env is set, otherwise setUp() would skip the tests
+        $memcachedHost = getenv('typo3TestingMemcachedHost');
+        // If typo3TestingMemcachedPort env is set, use it, otherwise fall back to standard port
+        $env = getenv('typo3TestingMemcachedPort');
+        $memcachedPort = is_string($env) ? (int)$env : 11211;
+
+        /** @var \PHPUnit_Framework_MockObject_MockObject|\TYPO3\CMS\Core\Cache\Frontend\FrontendInterface $cache */
+        $cache = $this->createMock(\TYPO3\CMS\Core\Cache\Frontend\FrontendInterface::class);
+
+        $subject = new MemcachedBackend('Testing', [ 'servers' => [$memcachedHost . ':' . $memcachedPort] ]);
+        $subject->setCache($cache);
+        $subject->initializeObject();
+        return $subject;
     }
 
     /**
@@ -45,11 +65,16 @@ class MemcachedBackendTest extends \TYPO3\TestingFramework\Core\Unit\UnitTestCas
      */
     public function setThrowsExceptionIfNoFrontEndHasBeenSet()
     {
+        // We know this env is set, otherwise setUp() would skip the tests
+        $memcachedHost = getenv('typo3TestingMemcachedHost');
+        // If typo3TestingMemcachedPort env is set, use it, otherwise fall back to standard port
+        $env = getenv('typo3TestingMemcachedPort');
+        $memcachedPort = is_string($env) ? (int)$env : 11211;
+
         $this->expectException(\TYPO3\CMS\Core\Cache\Exception::class);
         $this->expectExceptionCode(1207149215);
 
-        $backendOptions = ['servers' => ['localhost:11211']];
-        $backend = new MemcachedBackend('Testing', $backendOptions);
+        $backend = new MemcachedBackend('Testing', [ 'servers' => [$memcachedHost . ':' . $memcachedPort] ]);
         $backend->initializeObject();
         $data = 'Some data';
         $identifier = $this->getUniqueId('MyIdentifier');
@@ -73,7 +98,7 @@ class MemcachedBackendTest extends \TYPO3\TestingFramework\Core\Unit\UnitTestCas
      */
     public function itIsPossibleToSetAndCheckExistenceInCache()
     {
-        $backend = $this->setUpBackend();
+        $backend = $this->initializeSubject();
         $data = 'Some data';
         $identifier = $this->getUniqueId('MyIdentifier');
         $backend->set($identifier, $data);
@@ -86,7 +111,7 @@ class MemcachedBackendTest extends \TYPO3\TestingFramework\Core\Unit\UnitTestCas
      */
     public function itIsPossibleToSetAndGetEntry()
     {
-        $backend = $this->setUpBackend();
+        $backend = $this->initializeSubject();
         $data = 'Some data';
         $identifier = $this->getUniqueId('MyIdentifier');
         $backend->set($identifier, $data);
@@ -99,7 +124,7 @@ class MemcachedBackendTest extends \TYPO3\TestingFramework\Core\Unit\UnitTestCas
      */
     public function itIsPossibleToRemoveEntryFromCache()
     {
-        $backend = $this->setUpBackend();
+        $backend = $this->initializeSubject();
         $data = 'Some data';
         $identifier = $this->getUniqueId('MyIdentifier');
         $backend->set($identifier, $data);
@@ -113,7 +138,7 @@ class MemcachedBackendTest extends \TYPO3\TestingFramework\Core\Unit\UnitTestCas
      */
     public function itIsPossibleToOverwriteAnEntryInTheCache()
     {
-        $backend = $this->setUpBackend();
+        $backend = $this->initializeSubject();
         $data = 'Some data';
         $identifier = $this->getUniqueId('MyIdentifier');
         $backend->set($identifier, $data);
@@ -128,7 +153,7 @@ class MemcachedBackendTest extends \TYPO3\TestingFramework\Core\Unit\UnitTestCas
      */
     public function findIdentifiersByTagFindsCacheEntriesWithSpecifiedTag()
     {
-        $backend = $this->setUpBackend();
+        $backend = $this->initializeSubject();
         $data = 'Some data';
         $identifier = $this->getUniqueId('MyIdentifier');
         $backend->set($identifier, $data, ['UnitTestTag%tag1', 'UnitTestTag%tag2']);
@@ -143,7 +168,7 @@ class MemcachedBackendTest extends \TYPO3\TestingFramework\Core\Unit\UnitTestCas
      */
     public function setRemovesTagsFromPreviousSet()
     {
-        $backend = $this->setUpBackend();
+        $backend = $this->initializeSubject();
         $data = 'Some data';
         $identifier = $this->getUniqueId('MyIdentifier');
         $backend->set($identifier, $data, ['UnitTestTag%tag1', 'UnitTestTag%tag2']);
@@ -157,7 +182,7 @@ class MemcachedBackendTest extends \TYPO3\TestingFramework\Core\Unit\UnitTestCas
      */
     public function hasReturnsFalseIfTheEntryDoesntExist()
     {
-        $backend = $this->setUpBackend();
+        $backend = $this->initializeSubject();
         $identifier = $this->getUniqueId('NonExistingIdentifier');
         $inCache = $backend->has($identifier);
         $this->assertFalse($inCache, '"has" did not return FALSE when checking on non existing identifier');
@@ -168,7 +193,7 @@ class MemcachedBackendTest extends \TYPO3\TestingFramework\Core\Unit\UnitTestCas
      */
     public function removeReturnsFalseIfTheEntryDoesntExist()
     {
-        $backend = $this->setUpBackend();
+        $backend = $this->initializeSubject();
         $identifier = $this->getUniqueId('NonExistingIdentifier');
         $inCache = $backend->remove($identifier);
         $this->assertFalse($inCache, '"remove" did not return FALSE when checking on non existing identifier');
@@ -179,7 +204,7 @@ class MemcachedBackendTest extends \TYPO3\TestingFramework\Core\Unit\UnitTestCas
      */
     public function flushByTagRemovesCacheEntriesWithSpecifiedTag()
     {
-        $backend = $this->setUpBackend();
+        $backend = $this->initializeSubject();
         $data = 'some data' . microtime();
         $backend->set('BackendMemcacheTest1', $data, ['UnitTestTag%test', 'UnitTestTag%boring']);
         $backend->set('BackendMemcacheTest2', $data, ['UnitTestTag%test', 'UnitTestTag%special']);
@@ -195,7 +220,7 @@ class MemcachedBackendTest extends \TYPO3\TestingFramework\Core\Unit\UnitTestCas
      */
     public function flushByTagsRemovesCacheEntriesWithSpecifiedTags()
     {
-        $backend = $this->setUpBackend();
+        $backend = $this->initializeSubject();
         $data = 'some data' . microtime();
         $backend->set('BackendMemcacheTest1', $data, ['UnitTestTag%test', 'UnitTestTag%boring']);
         $backend->set('BackendMemcacheTest2', $data, ['UnitTestTag%test', 'UnitTestTag%special']);
@@ -211,7 +236,7 @@ class MemcachedBackendTest extends \TYPO3\TestingFramework\Core\Unit\UnitTestCas
      */
     public function flushRemovesAllCacheEntries()
     {
-        $backend = $this->setUpBackend();
+        $backend = $this->initializeSubject();
         $data = 'some data' . microtime();
         $backend->set('BackendMemcacheTest1', $data);
         $backend->set('BackendMemcacheTest2', $data);
@@ -227,18 +252,23 @@ class MemcachedBackendTest extends \TYPO3\TestingFramework\Core\Unit\UnitTestCas
      */
     public function flushRemovesOnlyOwnEntries()
     {
-        $backendOptions = ['servers' => ['localhost:11211']];
+        // We know this env is set, otherwise setUp() would skip the tests
+        $memcachedHost = getenv('typo3TestingMemcachedHost');
+        // If typo3TestingMemcachedPort env is set, use it, otherwise fall back to standard port
+        $env = getenv('typo3TestingMemcachedPort');
+        $memcachedPort = is_string($env) ? (int)$env : 11211;
+
         /** @var \PHPUnit_Framework_MockObject_MockObject|\TYPO3\CMS\Core\Cache\Frontend\FrontendInterface $thisCache */
         $thisCache = $this->createMock(\TYPO3\CMS\Core\Cache\Frontend\AbstractFrontend::class);
         $thisCache->expects($this->any())->method('getIdentifier')->will($this->returnValue('thisCache'));
-        $thisBackend = new MemcachedBackend('Testing', $backendOptions);
+        $thisBackend = new MemcachedBackend('Testing', [ 'servers' => [$memcachedHost . ':' . $memcachedPort] ]);
         $thisBackend->setCache($thisCache);
         $thisBackend->initializeObject();
 
         /** @var \PHPUnit_Framework_MockObject_MockObject|\TYPO3\CMS\Core\Cache\Frontend\FrontendInterface $thatCache */
         $thatCache = $this->createMock(\TYPO3\CMS\Core\Cache\Frontend\AbstractFrontend::class);
         $thatCache->expects($this->any())->method('getIdentifier')->will($this->returnValue('thatCache'));
-        $thatBackend = new MemcachedBackend('Testing', $backendOptions);
+        $thatBackend = new MemcachedBackend('Testing', [ 'servers' => [$memcachedHost . ':' . $memcachedPort] ]);
         $thatBackend->setCache($thatCache);
         $thatBackend->initializeObject();
         $thisBackend->set('thisEntry', 'Hello');
@@ -256,7 +286,7 @@ class MemcachedBackendTest extends \TYPO3\TestingFramework\Core\Unit\UnitTestCas
      */
     public function largeDataIsStored()
     {
-        $backend = $this->setUpBackend();
+        $backend = $this->initializeSubject();
         $data = str_repeat('abcde', 1024 * 1024);
         $backend->set('tooLargeData', $data);
         $this->assertTrue($backend->has('tooLargeData'));
@@ -268,11 +298,23 @@ class MemcachedBackendTest extends \TYPO3\TestingFramework\Core\Unit\UnitTestCas
      */
     public function setTagsOnlyOnceToIdentifier()
     {
-        $backendOptions = ['servers' => ['localhost:11211']];
+        // We know this env is set, otherwise setUp() would skip the tests
+        $memcachedHost = getenv('typo3TestingMemcachedHost');
+        // If typo3TestingMemcachedPort env is set, use it, otherwise fall back to standard port
+        $env = getenv('typo3TestingMemcachedPort');
+        $memcachedPort = is_string($env) ? (int)$env : 11211;
+
+        $accessibleClassName = $this->buildAccessibleProxy(MemcachedBackend::class);
+        $backend = new $accessibleClassName('Testing', [ 'servers' => [$memcachedHost . ':' . $memcachedPort] ]);
+
+        /** @var \PHPUnit_Framework_MockObject_MockObject|\TYPO3\CMS\Core\Cache\Frontend\FrontendInterface $cache */
+        $cache = $this->createMock(\TYPO3\CMS\Core\Cache\Frontend\FrontendInterface::class);
+        $backend->setCache($cache);
+        $backend->initializeObject();
+
         $identifier = $this->getUniqueId('MyIdentifier');
         $tags = ['UnitTestTag%test', 'UnitTestTag%boring'];
 
-        $backend = $this->setUpBackend($backendOptions, true);
         $backend->_call('addIdentifierToTags', $identifier, $tags);
         $this->assertSame(
             $tags,
@@ -285,29 +327,4 @@ class MemcachedBackendTest extends \TYPO3\TestingFramework\Core\Unit\UnitTestCas
             $backend->_call('findTagsByIdentifier', $identifier)
         );
     }
-
-    /**
-     * Sets up the memcached backend used for testing
-     *
-     * @param array $backendOptions Options for the memcache backend
-     * @param bool $accessible TRUE if backend should be encapsulated in accessible proxy otherwise FALSE.
-     * @return \TYPO3\TestingFramework\Core\AccessibleObjectInterface|MemcachedBackend
-     */
-    protected function setUpBackend(array $backendOptions = [], $accessible = false)
-    {
-        /** @var \PHPUnit_Framework_MockObject_MockObject|\TYPO3\CMS\Core\Cache\Frontend\FrontendInterface $cache */
-        $cache = $this->createMock(\TYPO3\CMS\Core\Cache\Frontend\FrontendInterface::class);
-        if ($backendOptions == []) {
-            $backendOptions = ['servers' => ['localhost:11211']];
-        }
-        if ($accessible) {
-            $accessibleClassName = $this->buildAccessibleProxy(MemcachedBackend::class);
-            $backend = new $accessibleClassName('Testing', $backendOptions);
-        } else {
-            $backend = new MemcachedBackend('Testing', $backendOptions);
-        }
-        $backend->setCache($cache);
-        $backend->initializeObject();
-        return $backend;
-    }
 }
index b39a2ce..49c81e2 100644 (file)
@@ -14,6 +14,7 @@ namespace TYPO3\CMS\Core\Tests\Unit\Cache\Backend;
  * The TYPO3 project - inspiring people to share!
  */
 use TYPO3\CMS\Core\Cache\Exception\InvalidDataException;
+use TYPO3\TestingFramework\Core\Unit\UnitTestCase;
 
 /**
  * Testcase for the cache to redis backend
@@ -26,9 +27,10 @@ use TYPO3\CMS\Core\Cache\Exception\InvalidDataException;
  * to the internal data structure are done.
  *
  * Warning:
- * The unit tests use and flush redis database numbers 0 and 1!
+ * The unit tests use and flush redis database numbers 0 and 1 on the
+ * redis host specified by environment variable typo3RedisHost
  */
-class RedisBackendTest extends \TYPO3\TestingFramework\Core\Unit\UnitTestCase
+class RedisBackendTest extends UnitTestCase
 {
     /**
      * If set, the tearDown() method will flush the cache used by this unit test.
@@ -40,7 +42,7 @@ class RedisBackendTest extends \TYPO3\TestingFramework\Core\Unit\UnitTestCase
     /**
      * Own redis instance used in implementation tests
      *
-     * @var Redis
+     * @var \Redis
      */
     protected $redis = null;
 
@@ -52,13 +54,12 @@ class RedisBackendTest extends \TYPO3\TestingFramework\Core\Unit\UnitTestCase
         if (!extension_loaded('redis')) {
             $this->markTestSkipped('redis extension was not available');
         }
-        try {
-            if (!@fsockopen('127.0.0.1', 6379)) {
-                $this->markTestSkipped('redis server not reachable');
-            }
-        } catch (\Exception $e) {
-            $this->markTestSkipped('redis server not reachable');
+        if (!getenv('typo3TestingRedisHost')) {
+            $this->markTestSkipped('environment variable "typo3TestingRedisHost" must be set to run this test');
         }
+        // Note we assume that if that typo3TestingRedisHost env is set, we can use that for testing,
+        // there is no test to see if the daemon is actually up and running. Tests will fail if env
+        // is set but daemon is down.
     }
 
     /**
@@ -68,6 +69,11 @@ class RedisBackendTest extends \TYPO3\TestingFramework\Core\Unit\UnitTestCase
     {
         $mockCache = $this->createMock(\TYPO3\CMS\Core\Cache\Frontend\FrontendInterface::class);
         $mockCache->expects($this->any())->method('getIdentifier')->will($this->returnValue('TestCache'));
+        // We know this env is set, otherwise setUp() would skip the tests
+        $backendOptions['hostname'] = getenv('typo3TestingRedisHost');
+        // If typo3TestingRedisPort env is set, use it, otherwise fall back to standard port
+        $env = getenv('typo3TestingRedisPort');
+        $backendOptions['port'] = is_string($env) ? (int)$env : 6379;
         $this->backend = new \TYPO3\CMS\Core\Cache\Backend\RedisBackend('Testing', $backendOptions);
         $this->backend->setCache($mockCache);
         $this->backend->initializeObject();
@@ -78,8 +84,14 @@ class RedisBackendTest extends \TYPO3\TestingFramework\Core\Unit\UnitTestCase
      */
     protected function setUpRedis()
     {
+        // We know this env is set, otherwise setUp() would skip the tests
+        $redisHost = getenv('typo3TestingRedisHost');
+        // If typo3TestingRedisPort env is set, use it, otherwise fall back to standard port
+        $env = getenv('typo3TestingRedisPort');
+        $redisPort = is_string($env) ? (int)$env : 6379;
+
         $this->redis = new \Redis();
-        $this->redis->connect('127.0.0.1', 6379);
+        $this->redis->connect($redisHost, $redisPort);
     }
 
     /**