diff --git a/.circleci/README.md b/.circleci/README.md new file mode 100644 index 00000000..0a7f24a5 --- /dev/null +++ b/.circleci/README.md @@ -0,0 +1,4 @@ +# Continuous Integration + +Continuous integration for this module has been set up in CircleCI using +[deviantintegral/drupal_tests](https://github.com/deviantintegral/drupal_tests) as as a base. diff --git a/.circleci/RoboFile.php b/.circleci/RoboFile.php new file mode 100644 index 00000000..9adc0c6b --- /dev/null +++ b/.circleci/RoboFile.php @@ -0,0 +1,437 @@ +stopOnFail(); + } + + /** + * Files which we don't want to copy into the module directory. + */ + static $excludeFiles = [ + '.', + '..', + 'vendor', + 'RoboFile.php', + '.git', + '.idea', + ]; + + /** + * Set up the Drupal skeleton. + */ + public function setupSkeleton() + { + // composer config doesn't allow us to set arrays, so we have to do this by + // hand. + $config = json_decode(file_get_contents('composer.json')); + $config->require->{"drush/drush"} = "~9.0"; + $config->extra->{"enable-patching"} = 'true'; + $config->extra->{"patches"} = new \stdClass(); + file_put_contents('composer.json', json_encode($config)); + + // Create a directory for our artifacts. + $this->taskFilesystemStack() + ->mkdir('artifacts') + ->mkdir('artifacts/phpcs') + ->mkdir('artifacts/phpmd') + ->mkdir('artifacts/phpmetrics') + ->mkdir('/tmp/artifacts/phpunit') + ->mkdir('/tmp/artifacts/phpmd') + ->run(); + + $this->taskFilesystemStack() + ->chown('/tmp/artifacts', 'www-data', TRUE) + ->run(); + } + + /** + * Adds coding standard dependencies. + */ + public function addCodingStandardsDeps() + { + $config = json_decode(file_get_contents('composer.json')); + $config->require->{"drupal/coder"} = "^2.0|^8.2"; + file_put_contents('composer.json', json_encode($config)); + } + + /** + * Adds Behat dependencies. + */ + public function addBehatDeps() + { + $config = json_decode(file_get_contents('composer.json')); + $config->require->{"behat/mink-selenium2-driver"} = "^1.3"; + $config->require->{"drupal/drupal-extension"} = "master-dev"; + $config->require->{"drush/drush"} = "~9.0"; + $config->require->{"guzzlehttp/guzzle"} = "^6.0@dev"; + file_put_contents('composer.json', json_encode($config)); + } + + /** + * Adds modules to the merge section. + * + * @param array $modules + * The list of modules. + */ + public function addModules(array $modules) + { + $config = json_decode(file_get_contents('composer.json')); + + foreach ($modules as $module) { + list($module,) = explode(':', $module); + $config->extra->{"merge-plugin"}->include[] = "modules/$module/composer.json"; + $base = isset($config->extra->{"patches"}) ? (array)$config->extra->{"patches"} : []; + $config->extra->{"patches"} = (object)array_merge($base, + (array)$this->getPatches($module)); + } + + file_put_contents('composer.json', json_encode($config)); + } + + /** + * Adds contrib modules to the require section. + * + * @param array $modules + * The list of modules. + */ + public function addContribModules(array $modules) + { + $config = json_decode(file_get_contents('composer.json')); + + foreach ($modules as $module) { + list($module, $version) = explode(':', $module); + $config->require->{"drupal/" . $module} = $version; + } + + file_put_contents('composer.json', json_encode($config)); + } + + /** + * Updates modules. + * + * @param array $modules + * The list of modules. + */ + public function updateModules(array $modules) + { + $config = json_decode(file_get_contents('composer.json')); + + // Rebuild the patches array. + $config->extra->{"patches"} = new \stdClass(); + foreach ($modules as $module) { + list($module,) = explode(':', $module); + $config->extra->{"patches"} = (object)array_merge((array)$config->extra->{"patches"}, + (array)$this->getPatches($module)); + } + + file_put_contents('composer.json', json_encode($config)); + } + + /** + * Updates contrib modules. + * + * @param array $modules + * The list of modules. + */ + public function updateContribModules(array $modules) + { + // The implementation is the same as adding modules but for + // readability we have this alias when updating sites. + $this->addContribModules($modules); + } + + /** + * Updates composer dependencies. + */ + public function updateDependencies() + { + // Disable xdebug. + $this->taskExec('sed -i \'s/^zend_extension/;zend_extension/g\' /usr/local/etc/php/conf.d/xdebug.ini') + ->run(); + + // The git checkout includes a composer.lock, and running composer update + // on it fails for the first time. + $this->taskFilesystemStack()->remove('composer.lock')->run(); + + $this->taskDeleteDir('vendor/behat/mink')->run(); + + // Composer often runs out of memory when installing drupal. + $this->taskComposerUpdate('php -d memory_limit=-1 /usr/local/bin/composer') + ->optimizeAutoloader() + ->run(); + + // Preserve composer.lock as an artifact for future debugging. + $this->taskFilesystemStack() + ->copy('composer.json', '/tmp/artifacts/composer.json') + ->copy('composer.lock', '/tmp/artifacts/composer.lock') + ->run(); + + // Write drush status results to an artifact file. + $this->taskExec('vendor/bin/drush status > /tmp/artifacts/core-stats.txt') + ->run(); + $this->taskExec('cat /tmp/artifacts/core-stats.txt') + ->run(); + + // Add php info to an artifact file. + $this->taskExec('php -i > /tmp/artifacts/phpinfo.txt') + ->run(); + + // Add composer version info to an artifact file. + $this->taskExec('composer show > /tmp/artifacts/composer-show.txt') + ->run(); + } + + /** + * Returns an array of patches to apply for a given module. + * + * @param string $module + * The name of the module. + * + * @return \stdClass + * An object containing a list of patches to apply via Composer Patches. + */ + protected function getPatches($module) + { + $path = 'modules/' . $module . '/patches.json'; + if (file_exists($path)) { + return json_decode(file_get_contents($path)); + } else { + return new stdClass(); + } + } + + /** + * Install Drupal. + * + * @param array $opts + * (optional) The array of options. + */ + public function setupDrupal($opts = [ + 'admin-user' => null, + 'admin-password' => null, + 'site-name' => null, + 'db-url' => 'mysql://root@127.0.0.1/drupal8', + ] + ) { + $task = $this->drush() + ->args('site-install') + ->option('yes') + ->option('db-url', $opts['db-url'], '='); + + if ($opts['admin-user']) { + $task->option('account-name', $admin_user, '='); + } + + if ($opts['admin-password']) { + $task->option('account-pass', $admin_password, '='); + } + + if ($opts['site-name']) { + $task->option('site-name', $site_name, '='); + } + + // Sending email will fail, so we need to allow this to always pass. + $this->stopOnFail(false); + $task->run(); + $this->stopOnFail(); + } + + /** + * Return drush with default arguments. + * + * @return \Robo\Task\Base\Exec + * A drush exec command. + */ + protected function drush() + { + // Drush needs an absolute path to the docroot. + $docroot = $this->getDocroot(); + return $this->taskExec('vendor/bin/drush') + ->option('root', $docroot, '='); + } + + /** + * Get the absolute path to the docroot. + * + * @return string + */ + protected function getDocroot() + { + $docroot = (getcwd()); + return $docroot; + } + + /** + * Overrides phpunit's configuration with module specific one. + * + * @param string $module + * The module name where phpunit config files may be located. + */ + public function overridePhpunitConfig($module) + { + $module_path = "modules/$module"; + // Copy in our custom phpunit.xml.core.dist file. + if (file_exists("$module_path/phpunit.core.xml")) { + $this->taskFilesystemStack() + ->copy("$module_path/phpunit.core.xml", 'core/phpunit.xml') + ->run(); + } elseif (file_exists("$module_path/phpunit.core.xml.dist")) { + $this->taskFilesystemStack() + ->copy("$module_path/phpunit.core.xml.dist", 'core/phpunit.xml') + ->run(); + } + } + + /** + * Run PHPUnit and simpletests for the module. + * + * @param string $module + * The module name. + */ + public function test($module) + { + $this->phpUnit($module) + ->run(); + } + + /** + * Run tests with code coverage reports. + * + * @param string $module + * The module name. + * @param string $report_output_path + * The full path of the report to generate. + */ + public function testCoverage($module, $report_output_path) + { + $this->phpUnit($module) + ->option('coverage-xml', $report_output_path . '/coverage-xml') + ->option('coverage-html', $report_output_path . '/coverage-html') + ->option('testsuite', 'nonfunctional') + ->run(); + } + + /** + * Return a configured phpunit task. + * + * This will check for PHPUnit configuration first in the module directory. + * If no configuration is found, it will fall back to Drupal's core + * directory. + * + * @param string $module + * The module name. + * + * @return \Robo\Task\Testing\PHPUnit + */ + private function phpUnit($module) + { + return $this->taskPhpUnit('vendor/bin/phpunit') + ->option('verbose') + ->option('debug') + ->option('log-junit', '/tmp/artifacts/phpunit/phpunit.xml') + ->configFile('core') + ->group($module); + } + + /** + * Gathers coding standard statistics from a module. + * + * @param string $path + * Path were cs.json and cs-practice.json files have been stored + * by the container where phpcs was executed. + * + * @return string + * A short string with the total violations. + */ + public function extractCodingStandardsStats($path) + { + $errors = 0; + $warnings = 0; + + if (file_exists($path . '/cs.json')) { + $stats = json_decode(file_get_contents($path . '/cs.json')); + $errors += $stats->totals->errors; + $warnings += $stats->totals->warnings; + } + + return $errors . ' errors and ' . $warnings . ' warnings.'; + } + + /** + * Gathers code coverage stats from a module. + * + * @param string $path + * Path to a Clover report file. + * + * @return string + * A short string with the coverage percentage. + */ + public function extractCoverageStats($path) + { + if (file_exists($path . '/index.xml')) { + $data = file_get_contents($path . '/index.xml'); + $xml = simplexml_load_string($data); + $totals = $xml->project->directory->totals; + $lines = (string)$totals->lines['percent']; + $methods = (string)$totals->methods['percent']; + $classes = (string)$totals->classes['percent']; + return 'Lines ' . $lines . ' Methods ' . $methods . ' Classes ' . $classes; + } else { + return 'Clover report was not found at ' . $path; + } + } + + /** + * Adds modules to the merge section. + */ + public function configureModuleDependencies() + { + $config = json_decode(file_get_contents('composer.json')); + + // The Drupal core image might need updating. Request the newest stable. + $config->require->{"drupal/core"} = "~8.8"; + $config->require->{"drupal/core-recommended"} = "~8.8"; + + // We require Drupal console and drush for some tests. + $config->require->{"drupal/console"} = "~1.0"; + $config->require->{"drush/drush"} = "^9.7"; + + // If you require core, you must not replace it. + unset($config->replace); + + // You can't merge from a package that is required. + foreach ($config->extra->{"merge-plugin"}->include as $index => $merge_entry) { + if ($merge_entry === 'core/composer.json') { + unset($config->extra->{"merge-plugin"}->include[$index]); + } + } + $config->extra->{"merge-plugin"}->include = array_values($config->extra->{"merge-plugin"}->include); + + // Add dependencies for phpunit tests. + $config->require->{"drupal/core-dev"} = "~8.8"; + + file_put_contents('composer.json', json_encode($config, JSON_PRETTY_PRINT)); + } + +} diff --git a/.circleci/code-coverage-stats.sh b/.circleci/code-coverage-stats.sh new file mode 100644 index 00000000..e456b7c1 --- /dev/null +++ b/.circleci/code-coverage-stats.sh @@ -0,0 +1,15 @@ +#!/bin/bash -ex + +export SIMPLETEST_BASE_URL="http://localhost" +export SIMPLETEST_DB="sqlite://localhost//tmp/drupal.sqlite" +export BROWSERTEST_OUTPUT_DIRECTORY="/var/www/html/sites/simpletest" + +if [ ! -f dependencies_updated ] +then + ./update-dependencies.sh $1 +fi + +robo override:phpunit-config $1 + +timeout 60m sudo -E -u www-data robo test:coverage $1 /tmp/artifacts || true +tar czf artifacts/coverage.tar.gz -C artifacts coverage-html coverage-xml diff --git a/.circleci/code-sniffer.sh b/.circleci/code-sniffer.sh new file mode 100644 index 00000000..97e0d8a7 --- /dev/null +++ b/.circleci/code-sniffer.sh @@ -0,0 +1,17 @@ +#!/bin/bash -ex + +# Runs CodeSniffer checks on a Drupal module. + +if [ ! -f dependencies_updated ] +then + ./update-dependencies.sh $1 +fi + +# Install dependencies and configure phpcs +vendor/bin/phpcs --config-set installed_paths vendor/drupal/coder/coder_sniffer + +vendor/bin/phpmd modules/$1/src html cleancode,codesize,design,unusedcode --ignore-violations-on-exit --reportfile artifacts/phpmd/index.html +vendor/bin/phpmetrics --extensions=php,inc,module --report-html=artifacts/phpmetrics --git modules/$1 + +# Check coding standards +vendor/bin/phpcs -p -s -n --colors --standard=modules/apigee_edge/phpcs.xml.dist --report=junit --report-junit=artifacts/phpcs/phpcs.xml modules/$1 diff --git a/.circleci/config.yml b/.circleci/config.yml new file mode 100644 index 00000000..d4b5044f --- /dev/null +++ b/.circleci/config.yml @@ -0,0 +1,215 @@ +# Default configuration file for Drupal modules. +# +# Use setup.sh to automate setting this up. Otherwise, to use this in a new +# module: +# 1. Copy config.yml to the module's .circleci directory. +# 2. Change 'latest' in the image tag to the latest tag. +# 3. Update the working_directory key. +# 4. Connect CircleCI to the repository through the Circle UI. +# 5. Set the COMPOSER_AUTH environment variable in Circle to grant access to +# any private repositories. +# 6. Create a status badge embed code in Circle and add it to the README.md. +# +# Check https://circleci.com/docs/2.0/language-php/ for more details +# + +defaults: &defaults + docker: + # specify the version you desire here (avoid latest except for testing) + - image: andrewberry/drupal_tests:0.4.0 + + - image: selenium/standalone-chrome-debug:3.141.59-neon + + - image: mariadb:10.4 + environment: + MYSQL_ALLOW_EMPTY_PASSWORD: 1 + + # Specify service dependencies here if necessary + # CircleCI maintains a library of pre-built images + # documented at https://circleci.com/docs/2.0/circleci-images/ + # - image: circleci/mysql:9.4 + + # 'checkout' supports a path key, but not on locals where you test with the + # circleci CLI tool. + # https://discuss.circleci.com/t/bug-circleci-build-command-ignores-checkout-path-config/13004 + working_directory: /var/www/html/modules/apigee_edge + +# YAML does not support merging of lists. That means we can't have a default +# 'steps' configuration, though we can have defaults for individual step +# properties. + +# We use the composer.json as a way to determine if we can cache our build. +restore_cache: &restore_cache + keys: + - v4-dependencies-{{ checksum "composer.json" }}-{{ checksum "../../composer.json" }} + # fallback to using the latest cache if no exact match is found + - v4-dependencies- + +# If composer.json hasn't changed, restore the Composer cache directory. We +# don't restore the lock file so we ensure we get updated dependencies. +save_cache: &save_cache + paths: + - /root/.composer/cache/files + key: v4-dependencies-{{ checksum "composer.json" }}-{{ checksum "../../composer.json" }} + +# Install composer dependencies into the workspace to share with all jobs. +update_dependencies: &update_dependencies + <<: *defaults + steps: + - checkout + + - restore_cache: *restore_cache + + - run: + working_directory: /var/www/html + command: | + cp ./modules/apigee_edge/.circleci/update-dependencies.sh /var/www/html + ./update-dependencies.sh apigee_edge + + - save_cache: *save_cache + + - persist_to_workspace: + root: /var/www/html + paths: + - . + + - store_artifacts: + path: /tmp/artifacts + +# Run Drupal unit and kernel tests as one job. This command invokes the test.sh +# hook. +unit_kernel_tests: &unit_kernel_tests + <<: *defaults + steps: + - attach_workspace: + at: /var/www/html + + - checkout + + - run: + working_directory: /var/www/html + command: | + cp ./modules/apigee_edge/.circleci/test.sh /var/www/html + ./test.sh apigee_edge + + - store_test_results: + path: /tmp/artifacts/phpunit + - store_artifacts: + path: /tmp/artifacts + +# Run Drupal functional tests. This command invokes the test-functional.sh +# hook. +functional_tests: &functional_tests + <<: *defaults + steps: + - attach_workspace: + at: /var/www/html + + - checkout + + - run: + working_directory: /var/www/html + command: | + cp ./modules/apigee_edge/.circleci/test-functional.sh /var/www/html + ./test-functional.sh apigee_edge + + - store_test_results: + path: /tmp/artifacts/phpunit + - store_artifacts: + path: /tmp/artifacts + +# Run Drupal functional tests. This command invokes test-functional-js.sh. +functional_js_tests: &functional_js_tests + <<: *defaults + steps: + - attach_workspace: + at: /var/www/html + + - checkout + + - run: + working_directory: /var/www/html + command: | + cp ./modules/apigee_edge/.circleci/test-functional-js.sh /var/www/html + ./test-functional-js.sh apigee_edge + + - store_test_results: + path: /tmp/artifacts/phpunit + - store_artifacts: + path: /tmp/artifacts + +# Run code quality tests. This invokes code-sniffer.sh. +code_sniffer: &code_sniffer + <<: *defaults + steps: + - attach_workspace: + at: /var/www/html + + - checkout + + - run: + working_directory: /var/www/html + command: | + cp ./modules/apigee_edge/.circleci/code-sniffer.sh /var/www/html + ./code-sniffer.sh apigee_edge + + - store_test_results: + path: /var/www/html/artifacts + - store_artifacts: + path: /var/www/html/artifacts + +# Run code coverage tests. This invokes code-coverage-stats.sh. +code_coverage: &code_coverage + <<: *defaults + steps: + - attach_workspace: + at: /var/www/html + + - checkout + + - run: + working_directory: /var/www/html + command: | + ./code-coverage-stats.sh apigee_edge + - store_artifacts: + path: /var/www/html/artifacts + +# Declare all of the jobs we should run. +version: 2 +jobs: + update-dependencies: + <<: *update_dependencies + run-unit-kernel-tests: + <<: *unit_kernel_tests + run-functional-tests: + <<: *functional_tests + run-functional-js-tests: + <<: *functional_js_tests + run-code-sniffer: + <<: *code_sniffer + run-code-coverage: + <<: *code_coverage + +workflows: + version: 2 + + # Declare a workflow that runs all of our jobs in parallel. + test_and_lint: + jobs: + - update-dependencies +# - run-unit-kernel-tests: +# requires: +# - update-dependencies +# - run-functional-tests: +# requires: +# - update-dependencies +# - run-functional-js-tests: +# requires: +# - update-dependencies + - run-code-sniffer: + requires: + - update-dependencies +# - run-code-coverage: +# requires: +# - update-dependencies +# - run-unit-kernel-tests diff --git a/.circleci/test-functional-js.sh b/.circleci/test-functional-js.sh new file mode 100644 index 00000000..1a5175a7 --- /dev/null +++ b/.circleci/test-functional-js.sh @@ -0,0 +1,20 @@ +#!/bin/bash -ex + +# CI test-functional-js.sh hook implementation. + +export SIMPLETEST_BASE_URL="http://localhost" +export SIMPLETEST_DB="sqlite://localhost//tmp/drupal.sqlite" +export BROWSERTEST_OUTPUT_DIRECTORY="/var/www/html/sites/simpletest" +export MINK_DRIVER_ARGS_WEBDRIVER='["chrome", null, "http://localhost:4444/wd/hub"]' + +if [ ! -f dependencies_updated ] +then + ./update-dependencies.sh $1 +fi + +# This is the command used by the base image to serve Drupal. +apache2-foreground& + +robo override:phpunit-config $1 + +sudo -E -u www-data vendor/bin/phpunit -c core --group $1 --testsuite functional-javascript --debug --verbose --log-junit /tmp/artifacts/phpunit/phpunit.xml diff --git a/.circleci/test-functional.sh b/.circleci/test-functional.sh new file mode 100644 index 00000000..9f3d4f18 --- /dev/null +++ b/.circleci/test-functional.sh @@ -0,0 +1,19 @@ +#!/bin/bash -ex + +# CI test-functional.sh hook implementation. + +export SIMPLETEST_BASE_URL="http://localhost" +export SIMPLETEST_DB="sqlite://localhost//tmp/drupal.sqlite" +export BROWSERTEST_OUTPUT_DIRECTORY="/var/www/html/sites/simpletest" + +if [ ! -f dependencies_updated ] +then + ./update-dependencies.sh $1 +fi + +# This is the command used by the base image to serve Drupal. +apache2-foreground& + +robo override:phpunit-config $1 + +sudo -E -u www-data vendor/bin/phpunit -c core --group $1 --testsuite functional --debug --verbose --log-junit /tmp/artifacts/phpunit/phpunit.xml diff --git a/.circleci/test.sh b/.circleci/test.sh new file mode 100644 index 00000000..c593bd08 --- /dev/null +++ b/.circleci/test.sh @@ -0,0 +1,19 @@ +#!/bin/bash -ex + +# CI test.sh hook implementation. + +export SIMPLETEST_BASE_URL="http://localhost" +export SIMPLETEST_DB="sqlite://localhost//tmp/drupal.sqlite" +export BROWSERTEST_OUTPUT_DIRECTORY="/var/www/html/sites/simpletest" + +if [ ! -f dependencies_updated ] +then + ./update-dependencies.sh $1 +fi + +# This is the command used by the base image to serve Drupal. +apache2-foreground& + +robo override:phpunit-config $1 + +sudo -E -u www-data vendor/bin/phpunit -c core --group $1 --testsuite unit,kernel --debug --verbose --log-junit /tmp/artifacts/phpunit/phpunit.xml diff --git a/.circleci/update-dependencies.sh b/.circleci/update-dependencies.sh new file mode 100644 index 00000000..41b46e9b --- /dev/null +++ b/.circleci/update-dependencies.sh @@ -0,0 +1,14 @@ +#!/bin/bash -ex + +# Make sure the robofile is in the correct location. +cp modules/apigee_edge/.circleci/RoboFile.php ./ + +robo setup:skeleton +robo add:modules $1 +robo configure:module-dependencies +robo update:dependencies + +# Touch a flag so we know dependencies have been set. Otherwise, there is no +# easy way to know this step needs to be done when running circleci locally since +# it does not support workflows. +touch dependencies_updated diff --git a/.gitignore b/.gitignore index 3b54f6c5..1ad38b3a 100644 --- a/.gitignore +++ b/.gitignore @@ -1,5 +1,6 @@ # Ignore all hidden files exept these. .* +!/.circleci !/.github !/.gitignore !/.gitattributes @@ -10,3 +11,4 @@ # Other ignored paths and files. /vendor composer.lock +tests/src/Behat/behat.local.yml diff --git a/.travis/.env b/.travis/.env deleted file mode 100644 index fbf99e39..00000000 --- a/.travis/.env +++ /dev/null @@ -1 +0,0 @@ -COMPOSE_PROJECT_NAME=apigee_edge_module_tests diff --git a/.travis/Dockerfile b/.travis/Dockerfile deleted file mode 100644 index bc65b611..00000000 --- a/.travis/Dockerfile +++ /dev/null @@ -1,10 +0,0 @@ -ARG PHP_IMAGE="wodby/drupal-php:7.1-dev-4.5.0" - -FROM ${PHP_IMAGE} - -COPY --chown=wodby:www-data . /opt/drupal-module - -USER wodby - -RUN composer global require --no-suggest dealerdirect/phpcodesniffer-composer-installer \ - drupal/coder diff --git a/.travis/composer.json b/.travis/composer.json deleted file mode 100644 index 4c5962f0..00000000 --- a/.travis/composer.json +++ /dev/null @@ -1,60 +0,0 @@ -{ - "name": "drupal/apigee_edge_travis", - "license": "GPL-2.0", - "type": "project", - "description": "Builds a test environment for the Apigee Edge module.", - "require": { - "php": ">=7.1", - "composer/installers": "^1.6", - "drupal-composer/drupal-scaffold": "^2.5.4", - "wikimedia/composer-merge-plugin": "dev-capture-input-options", - "zaporylie/composer-drupal-optimizations": "^1.0", - "drupal/console": "~1.0", - "drush/drush": "^9.7" - }, - "repositories": [ - { - "type": "composer", - "url": "https://packages.drupal.org/8" - }, - { - "type": "vcs", - "_comment1": "We have to install it from here until this PR is open: https://github.com/wikimedia/composer-merge-plugin/pull/169.", - "url": "https://github.com/mxr576/composer-merge-plugin", - "no-api": true - } - ], - "config": { - "sort-packages": true, - "optimize-autoloader": true, - "_comment1": "PHP API Client patches that modifies tests files only apply if it is installed from source.", - "preferred-install": { - "*": "dist", - "apigee/apigee-client-php": "source" - } - }, - "minimum-stability": "dev", - "prefer-stable": true, - "extra": { - "merge-plugin": { - "include": [ - "../composer.json" - ], - "merge-extra": true, - "merge-extra-deep": true - }, - "installer-paths": { - "build/core": ["type:drupal-core"], - "build/modules/contrib/{$name}": ["type:drupal-module"], - "build/profiles/contrib/{$name}": ["type:drupal-profile"], - "build/themes/contrib/{$name}": ["type:drupal-theme"], - "build/drush/contrib/{$name}": ["type:drupal-drush"], - "build/modules/custom/{$name}": ["type:drupal-custom-module"], - "build/themes/custom/{$name}": ["type:drupal-custom-theme"] - }, - "enable-patching": true, - "patchLevel": { - "drupal/core": "-p2" - } - } -} diff --git a/.travis/docker-compose.override.yml b/.travis/docker-compose.override.yml deleted file mode 100644 index eeef28d9..00000000 --- a/.travis/docker-compose.override.yml +++ /dev/null @@ -1,37 +0,0 @@ -version: "3" - -services: - database: - environment: - MYSQL_MAX_ALLOWED_PACKET: 512M - MYSQL_WAIT_TIMEOUT: 28800 - php: - volumes: - - log:/mnt/files/log - environment: - DRUPAL_CORE: ${DRUPAL_CORE:-} - DEPENDENCIES: ${DEPENDENCIES:-} - # We can not pass these environment variables with `docker-compose run -e` until - # this has not been improved. https://github.com/wodby/php/pull/21#issuecomment-361200733 - DRUPAL_MODULE_NAME: apigee_edge - APIGEE_EDGE_AUTH_TYPE: ${APIGEE_EDGE_AUTH_TYPE} - APIGEE_EDGE_ENDPOINT: ${APIGEE_EDGE_ENDPOINT} - APIGEE_EDGE_USERNAME: ${APIGEE_EDGE_USERNAME} - APIGEE_EDGE_PASSWORD: ${APIGEE_EDGE_PASSWORD} - APIGEE_EDGE_ORGANIZATION: ${APIGEE_EDGE_ORGANIZATION} - APIGEE_EDGE_TEST_LOG_DIR: "/mnt/files/log" - # Suppress deprecation warnings. - # https://api.drupal.org/api/drupal/vendor%21symfony%21phpunit-bridge%21DeprecationErrorHandler.php/8.5.x - SYMFONY_DEPRECATIONS_HELPER: disabled - THREADS: ${THREADS:-2} - TEST_ROOT: ${TEST_ROOT:-modules/contrib/apigee_edge/tests} - # We have to set this variable even if we set this to disabled, because - # otherwise xDebug does not get enabled and we need that for code coverage - # generation. - PHP_XDEBUG: 0 - webserver: - environment: - APACHE_FCGI_PROXY_TIMEOUT: 180 # Just in case, wait more than usual in tests. - -volumes: - log: diff --git a/.travis/docker-compose.yml b/.travis/docker-compose.yml deleted file mode 100644 index 630d33c5..00000000 --- a/.travis/docker-compose.yml +++ /dev/null @@ -1,62 +0,0 @@ -version: "3" - -services: - database: - image: ${DB_IMAGE:-wodby/mariadb:10.2-3.1.3} - container_name: "${COMPOSE_PROJECT_NAME:-my_project}_database" - stop_grace_period: 30s - environment: - MYSQL_ROOT_PASSWORD: ${DB_ROOT_PASSWORD:-password} - MYSQL_DATABASE: ${DB_NAME:-drupal} - MYSQL_USER: ${DB_USER:-drupal} - MYSQL_PASSWORD: ${DB_PASSWORD:-password} - POSTGRES_PASSWORD: ${DB_PASSWORD:-password} - POSTGRES_DB: ${DB_NAME:-drupal} - POSTGRES_USER: ${DB_USER:-drupal} - - php: - build: - context: .. - dockerfile: .travis/Dockerfile - args: - - PHP_IMAGE=${PHP_IMAGE:-wodby/drupal-php:7.1-dev-4.5.0} - container_name: "${COMPOSE_PROJECT_NAME:-my_project}_php" - environment: - DB_HOST: ${DB_HOST:-database} - DB_USER: ${DB_USER:-drupal} - DB_PASSWORD: ${DB_PASSWORD-password} - DB_NAME: ${DB_NAME:-drupal} - DB_DRIVER: ${DB_DRIVER:-mysql} - SIMPLETEST_BASE_URL: http://webserver - SIMPLETEST_DB: ${DB_DRIVER:-mysql}://${DB_USER:-drupal}:${DB_PASSWORD-password}@${DB_HOST:-database}/${DB_NAME:-drupal} - MINK_DRIVER_ARGS_WEBDRIVER: '["chrome", { "chromeOptions": { "w3c": false } }, "http://webdriver:4444/wd/hub"]' - BROWSERTEST_OUTPUT_DIRECTORY: "/mnt/files/log/simpletest" - COMPOSER_AUTH: ${COMPOSER_AUTH:-} - volumes: - - codebase:/var/www/html - - $HOME/.composer/cache/files:/home/wodby/.composer/cache/files - - webserver: - image: ${WEBSERVER_IMAGE:-wodby/php-apache:2.4-3.0.5} - container_name: "${COMPOSE_PROJECT_NAME:-my_project}_webserver" - depends_on: - - php - environment: - APACHE_LOG_LEVEL: debug - APACHE_BACKEND_HOST: php - APACHE_SERVER_ROOT: /var/www/html/build - NGINX_STATIC_CONTENT_OPEN_FILE_CACHE: "off" - NGINX_ERROR_LOG_LEVEL: debug - NGINX_BACKEND_HOST: php - NGINX_SERVER_ROOT: /var/www/html/build - volumes: - - codebase:/var/www/html - - webdriver: - image: selenium/standalone-chrome:3 - # Unfortunatelly its seems this image is not working at this moment. - # https://www.drupal.org/project/drupalci_environments/issues/2978243 - # image: drupalci/webdriver-chromedriver:dev - -volumes: - codebase: diff --git a/.travis/prepare-test-env.sh b/.travis/prepare-test-env.sh deleted file mode 100755 index 84c97d31..00000000 --- a/.travis/prepare-test-env.sh +++ /dev/null @@ -1,109 +0,0 @@ -#!/usr/bin/env bash - -set -e - -IS_ENV_VARS_SET=1 -for VAR in APIGEE_EDGE_AUTH_TYPE APIGEE_EDGE_ENDPOINT APIGEE_EDGE_ORGANIZATION APIGEE_EDGE_USERNAME APIGEE_EDGE_PASSWORD; do - if [[ -z "${!VAR}" ]] ; then - IS_ENV_VARS_SET=0 - echo "Incomplete configuration. The variable ${VAR} should exist and not be empty." - fi -done - -if [[ ${IS_ENV_VARS_SET} -eq 0 ]]; then - echo "Exiting" - exit 1 -fi - -# Make sure that script is standalone (it can be used even if it is not called -# by run-test.sh). -THREADS=${THREADS:-4} -MODULE_PATH=${MODULE_PATH:-"/opt/drupal-module"} -WEB_ROOT=${WEB_ROOT:-"/var/www/html/build"} -WEB_ROOT_PARENT=${WEB_ROOT_PARENT:-"/var/www/html"} -TEST_ROOT=${TEST_ROOT:-modules/custom} -TESTRUNNER=${TESTRUNNER:-"/var/www/html/testrunner"} - -COMPOSER_GLOBAL_OPTIONS="--no-interaction --no-suggest -o" - -# We mounted the cache/files folder from the host so we have to fix permissions -# on the parent cache folder because it did not exist before. -sudo -u root sh -c "chown -R wodby:wodby /home/wodby/.composer/cache" - -cd ${MODULE_PATH}/.travis - -# Install module with the highest dependencies first. -composer update ${COMPOSER_GLOBAL_OPTIONS} - -# Allow to run tests with a specific Drupal core version (ex.: latest dev). -if [[ -n "${DRUPAL_CORE}" ]]; then - composer require drupal/core:${DRUPAL_CORE} drupal/core-dev:${DRUPAL_CORE} ${COMPOSER_GLOBAL_OPTIONS}; -fi - -# Downgrade dependencies if needed. -# (This fix is necessary since PR#130 had been merged because after that lowest -# builds started to fail. Probably caused by a merge plugin issue because this -# problem could be reproduced only in this environment.) -if [[ -n "${DEPENDENCIES}" ]]; then - composer update ${COMPOSER_GLOBAL_OPTIONS} ${DEPENDENCIES} --with-dependencies -fi - -# Die if environment preparation has failed. -if [[ ! -d ${MODULE_PATH}/.travis/build ]]; then - exit 1; -fi - -# Copying Drupal to the right place. -# Symlinking is not an option because the webserver container would not be -# able to access to files. -cp -R ${MODULE_PATH}/.travis/build ${WEB_ROOT_PARENT} -cp -R ${MODULE_PATH}/.travis/vendor ${WEB_ROOT_PARENT} - -# Symlink module to the contrib folder. -ln -s ${MODULE_PATH} ${WEB_ROOT}/modules/contrib/${DRUPAL_MODULE_NAME} - -# Pre-create simpletest and screenshots directories... -sudo -u root -E mkdir -p ${WEB_ROOT}/sites/simpletest -sudo -u root mkdir -p /mnt/files/log/screenshots -# and some other. -# (These are required by core/phpunit.xml.dist). -sudo -u root mkdir -p ${WEB_ROOT}/profiles -sudo -u root mkdir -p ${WEB_ROOT}/themes - -# Based on https://www.drupal.org/node/244924, but we had to grant read -# access to files and read + execute access to directories to "others" -# otherwise Javascript tests failed by using webdriver. -# (Error: jQuery was not found an AJAX form.) -sudo -u root -E sh -c "chown -R wodby:www-data $WEB_ROOT \ - && find $WEB_ROOT -type d -exec chmod 6755 '{}' \; \ - && find $WEB_ROOT -type f -exec chmod 0644 '{}' \;" - -sudo -u root -E sh -c "mkdir -p $WEB_ROOT/sites/default/files \ - && chown -R wodby:www-data $WEB_ROOT/sites/default/files \ - && chmod 6770 $WEB_ROOT/sites/default/files" - -# Make sure that the log folder is writable for both www-data and wodby users. -# Also create a dedicated folder for PHPUnit outputs. -sudo -u root sh -c "chown -R www-data:wodby /mnt/files/log \ - && chmod -R 6750 /mnt/files/log \ - && mkdir -p /mnt/files/log/simpletest/browser_output \ - && chown -R www-data:wodby /mnt/files/log/simpletest \ - && chmod -R 6750 /mnt/files/log/simpletest \ - && chown -R www-data:wodby /mnt/files/log/screenshots \ - && chmod -R 6750 /mnt/files/log/screenshots" - -# Change location of the browser_output folder, because it seems even if -# BROWSERTEST_OUTPUT_DIRECTORY is set the html output is printed out to -# https://github.com/drupal/core/blob/8.5.0/tests/Drupal/Tests/BrowserTestBase.php#L1086 -sudo -u root ln -s /mnt/files/log/simpletest/browser_output ${WEB_ROOT}/sites/simpletest/browser_output - -# Fix permissions on on simpletest and its sub-folders. -sudo -u root sh -c "chown -R www-data:wodby $WEB_ROOT/sites/simpletest \ - && chmod -R 6750 $WEB_ROOT/sites/simpletest" - -# Let's display installed dependencies and their versions. -composer show - -# Downloading the test runner. -curl -s -L -o ${TESTRUNNER} https://github.com/Pronovix/testrunner/releases/download/v0.4/testrunner-linux-amd64 -chmod +x ${TESTRUNNER} diff --git a/.travis/push-logs.sh b/.travis/push-logs.sh deleted file mode 100755 index c95a269f..00000000 --- a/.travis/push-logs.sh +++ /dev/null @@ -1,23 +0,0 @@ -#!/usr/bin/env bash - -set -e - -if [[ -z "${LOGS_REPO_USER}" ]] || [[ -z "${LOGS_REPO_PASSWORD}" ]] || [[ -z "${LOGS_REPO_HOST}" ]] || [[ -z "${LOGS_REPO_NAME}" ]]; then - echo "There is at least one missing information about the destination repo. Make sure the following environment variables exist and not empty: LOGS_REPO_USER, LOGS_REPO_PASSWORD, LOGS_REPO_HOST, LOGS_REPO_NAME." - exit 0 -fi - -# Initial GIT setup. -git config --global user.email "travis@travis-ci.org" -git config --global user.name "Travis CI" -# Copy logs from the PHP container. -docker cp $(docker ps -f "name=.*_php" --format "{{.ID}}"):/mnt/files/log . -cd log -# Commit and push logs to the git repo. -git init -BRANCH_NAME=${TRAVIS_JOB_NUMBER}-$(date +"%y%m%d-%H%M") -git checkout -b ${BRANCH_NAME} -git add . -git commit -am "Travis build: ${TRAVIS_JOB_NUMBER}" -git remote add origin https://${LOGS_REPO_USER}:${LOGS_REPO_PASSWORD}@${LOGS_REPO_HOST}/${LOGS_REPO_USER}/${LOGS_REPO_NAME}.git -git push -u origin ${BRANCH_NAME} diff --git a/.travis/run-test.sh b/.travis/run-test.sh deleted file mode 100755 index aa3f031c..00000000 --- a/.travis/run-test.sh +++ /dev/null @@ -1,29 +0,0 @@ -#!/usr/bin/env bash - -set -e - -# Register shared variables. -export THREADS=${THREADS:-4} -export MODULE_PATH="/opt/drupal-module" -export WEB_ROOT="/var/www/html/build" -export WEB_ROOT_PARENT="/var/www/html" -export TEST_ROOT=${TEST_ROOT:-modules/custom} -export TESTRUNNER="/var/www/html/testrunner" - -if [[ ! -f ${TESTRUNNER} ]]; then - echo "Preparing test environment..." - /opt/drupal-module/.travis/prepare-test-env.sh -fi - -PHPUNIT="${WEB_ROOT_PARENT}/vendor/bin/phpunit -c ${WEB_ROOT}/core -v --debug --printer \Drupal\Tests\Listeners\HtmlOutputPrinter" - -# Do not exit if any PHPUnit test fails. -set +e - -# If no argument passed start the testrunner and start running ALL tests -# concurrently, otherwise pass them directly to PHPUnit. -if [[ $# -eq 0 ]]; then - sudo -u root -E sudo -u www-data -E ${TESTRUNNER} -verbose -threads=${THREADS} -root=${WEB_ROOT}/${TEST_ROOT} -command="$PHPUNIT" -else - sudo -u root -E sudo -u www-data -E ${PHPUNIT} ${@} -fi diff --git a/composer.json b/composer.json index dad3ec5f..db55ea85 100644 --- a/composer.json +++ b/composer.json @@ -7,7 +7,6 @@ "php": ">=7.1", "ext-json": "*", "apigee/apigee-client-php": "^2.0.4", - "cweagans/composer-patches": "^1.6.5", "drupal/core": "~8.7", "drupal/entity": "^1.0", "drupal/key": "^1.8", @@ -16,9 +15,18 @@ "require-dev": { "apigee/apigee-mock-client-php": "^1.0", "behat/mink" : "dev-master#9ea1cebe", + "behat/mink-extension": "v2.2", + "behat/mink-selenium2-driver": "1.3.x-dev", + "bex/behat-screenshot": "^1.2", + "cweagans/composer-patches": "^1.6", + "drupal/coder": "^8.3", + "drupal/core-dev": "^8.7", + "drupal/drupal-extension": "master-dev", "drush/drush": "^9.0", + "phpmd/phpmd": "^2.8", + "phpmetrics/phpmetrics": "^2.5", "phpunit/phpunit": "^6.5", - "drupal/core-dev": "^8.7" + "drupal/console": "~1.0" }, "config": { "sort-packages": true diff --git a/phpunit.core.xml.dist b/phpunit.core.xml.dist new file mode 100644 index 00000000..f01c49f4 --- /dev/null +++ b/phpunit.core.xml.dist @@ -0,0 +1,84 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + ./tests/TestSuites/UnitTestSuite.php + + + ./tests/TestSuites/KernelTestSuite.php + + + ./tests/TestSuites/FunctionalTestSuite.php + + + ./tests/TestSuites/UnitTestSuite.php + ./tests/TestSuites/KernelTestSuite.php + + + ./tests/TestSuites/FunctionalJavascriptTestSuite.php + + + + + + + + + + + + + ../modules/apigee_edge + + + ../modules/apigee_edge/tests + ../modules/apigee_edge/test_modules + + + +