From dcfdcc317e93d7a2d451ca3244ac7a4a3d1aaaf5 Mon Sep 17 00:00:00 2001 From: Stephan Gambke Date: Sat, 24 Aug 2019 21:21:34 +0200 Subject: [PATCH] Setup CI testing (#23) * Initial test setup * Fix extension.json for manifest v2 * Run analysis on installed extension --- .scrutinizer.yml | 63 +++++++++ composer.json | 3 +- extension.json | 4 +- phpunit.xml.dist | 26 ++++ release-notes.md | 2 +- src/SimpleBatchUpload.php | 58 +++++--- tests/phpunit/SimpleBatchUploadTest.php | 167 ++++++++++++++++++++++++ tests/setup/fix-composer.php | 57 ++++++++ tests/setup/run-tests.sh | 84 ++++++++++++ 9 files changed, 440 insertions(+), 24 deletions(-) create mode 100644 .scrutinizer.yml create mode 100644 phpunit.xml.dist create mode 100644 tests/phpunit/SimpleBatchUploadTest.php create mode 100644 tests/setup/fix-composer.php create mode 100755 tests/setup/run-tests.sh diff --git a/.scrutinizer.yml b/.scrutinizer.yml new file mode 100644 index 0000000..248cb8d --- /dev/null +++ b/.scrutinizer.yml @@ -0,0 +1,63 @@ +build: + # The build contains everything related to running test, deployment and analysis commands. + services: + mariadb: 10 + + dependencies: + override: + - true # do not install any dependencies + tests: + override: + - ~/build/tests/setup/run-tests.sh + + nodes: + code-analysis-and-test-mw-master: + environment: + php: 7.3 + variables: + MW: master + SBU: composer + tests: + override: + - command: ~/build/tests/setup/run-tests.sh --coverage-clover ~/coverage.xml + coverage: + file: ~/coverage.xml + format: clover + - command: phpcs-run + use_website_config: true + - php-scrutinizer-run --enable-security-analysis + test-mw-min-version: + environment: + php: 7.0 + variables: + MW: 1.31.0 + SBU: download + test-mw-1.31: + environment: + php: 7.1 + variables: + MW: 1.31.3 + SBU: composer + test-mw-1.32: + environment: + php: 7.2 + variables: + MW: 1.32.3 + SBU: download + test-mw-1.33: + environment: + php: 7.2 + variables: + MW: 1.33.0 + SBU: download + +filter: +# The filter section defines which files are analyzed, where dependencies are located and which files should be completely ignored. + dependency_paths: + - mw + excluded_paths: + - mw/extensions + +build_failure_conditions: {} +# The build failure conditions section allows you to define failure conditions where a build should be failed based on findings in the analysis. +# Findings can be that code coverage has decreased below a certain point, or that new issues have been found, etc. diff --git a/composer.json b/composer.json index ec433ac..ee9092e 100644 --- a/composer.json +++ b/composer.json @@ -24,8 +24,9 @@ "irc": "irc://irc.freenode.org/mediawiki" }, "require": { + "mediawiki/mediawiki": ">=1.31", "php": ">=7.0", - "mediawiki/mediawiki": ">=1.31" + "composer/installers": "1.*,>=1.0.1" }, "extra": { "branch-alias": { diff --git a/extension.json b/extension.json index 5cdba8f..33f4897 100644 --- a/extension.json +++ b/extension.json @@ -18,7 +18,9 @@ }, "config": { "SimpleBatchUploadMaxFilesPerBatch": { - "*": 1000 + "value":{ + "*": 1000 + } } }, "AutoloadNamespaces": { diff --git a/phpunit.xml.dist b/phpunit.xml.dist new file mode 100644 index 0000000..5da0b1e --- /dev/null +++ b/phpunit.xml.dist @@ -0,0 +1,26 @@ + + + + + + tests/phpunit + + + + + src + + + diff --git a/release-notes.md b/release-notes.md index 0e93a2d..722277e 100644 --- a/release-notes.md +++ b/release-notes.md @@ -8,7 +8,7 @@ Changes: * Raise minimum required versions to * MediaWiki 1.31 * PHP 7.0 -* Use MW autoloader (replaces Composer autoloader) +* Add CI testing ### SimpleBatchUpload 1.4.0 diff --git a/src/SimpleBatchUpload.php b/src/SimpleBatchUpload.php index 145a5d0..0b26daa 100644 --- a/src/SimpleBatchUpload.php +++ b/src/SimpleBatchUpload.php @@ -2,7 +2,7 @@ /** * File containing the SimpleBatchUpload class * - * @copyright (C) 2016 - 2017, Stephan Gambke + * @copyright (C) 2016 - 2019, Stephan Gambke * @license GNU General Public License, version 2 (or any later version) * * This software is free software; you can redistribute it and/or @@ -22,6 +22,9 @@ namespace SimpleBatchUpload; +use MediaWiki\MediaWikiServices; +use Parser; + /** * Class ExtensionManager * @@ -37,26 +40,39 @@ class SimpleBatchUpload { public static function initCallback() { $simpleBatchUpload = new self(); + $simpleBatchUpload->registerEarlyConfiguration( $GLOBALS ); + } - $configuration = $simpleBatchUpload->getConfiguration(); - self::mergeConfiguration( $configuration ); + /** + * @param $targetConfiguration + */ + public function registerEarlyConfiguration( &$targetConfiguration ){ + $sourceConfiguration = $this->getEarlyConfiguration(); + $this->mergeConfiguration( $sourceConfiguration, $targetConfiguration ); } + /** + * @param $targetConfiguration + */ + public function registerLateConfiguration( &$targetConfiguration ){ + $sourceConfiguration = $this->getLateConfiguration(); + $this->mergeConfiguration( $sourceConfiguration, $targetConfiguration ); + } /** - * @param $configuration + * @param array $targetConfiguration */ - public static function mergeConfiguration( $configuration ) { - foreach ( $configuration as $varname => $value ) { - $GLOBALS[ $varname ] = array_replace_recursive( $GLOBALS[ $varname ], $value ); + protected function mergeConfiguration( $sourceConfiguration, &$targetConfiguration ) { + foreach ( $sourceConfiguration as $varname => $value ) { + $targetConfiguration[ $varname ] = array_key_exists( $varname, $targetConfiguration )?array_replace_recursive( $targetConfiguration[ $varname ], $value ):$value; } } /** * @return array */ - public function getConfiguration() { + protected function getEarlyConfiguration(): array { $configuration = []; @@ -70,7 +86,18 @@ public function getConfiguration() { $configuration[ 'wgHooks' ][ 'SetupAfterCache' ][ 'ext.simplebatchupload' ] = [ $this, 'onSetupAfterCache']; return $configuration; + } + + /** + * @return array + */ + protected function getLateConfiguration(): array { + + $configuration = []; + $configuration[ 'wgResourceModules' ] = $this->getUploadSupportModuleDefinition() + $this->getUploadModuleDefinition(); + + return $configuration; } /** @@ -80,7 +107,7 @@ public function getConfiguration() { * @throws \MWException */ public function registerParserFunction( &$parser ) { - $parser->setFunctionHook( 'batchupload', [ new UploadButtonRenderer(), 'renderParserFunction' ], SFH_OBJECT_ARGS ); + $parser->setFunctionHook( 'batchupload', [ new UploadButtonRenderer(), 'renderParserFunction' ], Parser::SFH_OBJECT_ARGS ); return true; } @@ -150,10 +177,7 @@ public function onMakeGlobalVariablesScript( &$vars, $out ) { } public function onSetupAfterCache() { - - $configuration = [ 'wgResourceModules' => $this->getUploadSupportModuleDefinition() + $this->getUploadModuleDefinition() ]; - self::mergeConfiguration( $configuration ); - + $this->registerLateConfiguration( $GLOBALS ); } /** @@ -167,12 +191,4 @@ public function getMaxFilesPerBatchConfig() { return $this->maxFilesPerBatchConfig; } - - /** - * @param $maxFilesPerBatchConfig - */ - public function setMaxFilesPerBatchConfig( $maxFilesPerBatchConfig ) { - $this->maxFilesPerBatchConfig = $maxFilesPerBatchConfig; - } - } diff --git a/tests/phpunit/SimpleBatchUploadTest.php b/tests/phpunit/SimpleBatchUploadTest.php new file mode 100644 index 0000000..d0db92e --- /dev/null +++ b/tests/phpunit/SimpleBatchUploadTest.php @@ -0,0 +1,167 @@ +. + * + * @file + * @ingroup SimpleBatchUpload + */ + +use SimpleBatchUpload\SimpleBatchUpload; + +/** + * @covers \SimpleBatchUpload\SimpleBatchUpload + * @group SimpleBatchUpload + * + * @since 1.5 + */ +class SimpleBatchUploadTest extends PHPUnit_Framework_TestCase { + + public function testCanConstruct() { + + $this->assertInstanceOf( + '\SimpleBatchUpload\SimpleBatchUpload', + new SimpleBatchUpload() + ); + } + + public function testRegistersGlobals() { + $this->assertJsonConfiguration( $GLOBALS ); + $this->assertEarlyConfiguration( $GLOBALS ); + $this->assertLateConfiguration( $GLOBALS ); + } + + public function testRegisterEarlyConfiguraion() { + $sbu = new SimpleBatchUpload(); + $config = []; + + $sbu->registerEarlyConfiguration( $config ); + $this->assertEarlyConfiguration( $config ); + } + + public function testRegisterLateConfiguraion() { + $sbu = new SimpleBatchUpload(); + $config = []; + + $sbu->registerLateConfiguration( $config ); + $this->assertLateConfiguration( $config ); + } + + public function testRegisterParserFunction() { + + $parser = $this->getMockBuilder( Parser::class ) + ->disableOriginalConstructor() + ->getMock(); + + $parser->expects( $this->once() ) + ->method( 'setFunctionHook' ) + ->with( + $this->equalTo( 'batchupload' ), + $this->callback( function ( $param ) { + return is_callable( $param ); + } ), + $this->equalTo( Parser::SFH_OBJECT_ARGS ) ) + ->willReturn( null ); + + $sbu = new SimpleBatchUpload(); + $sbu->registerParserFunction( $parser ); + } + + public function testOnMakeGlobalVariablesScript() { + $vars = []; + $out = $this->getMockBuilder( OutputPage::class ) + ->disableOriginalConstructor() + ->getMock(); + + $sbu = new SimpleBatchUpload(); + $sbu->onMakeGlobalVariablesScript( $vars, $out ); + + $this->assertArrayHasKey( 'simpleBatchUploadMaxFilesPerBatch', $vars ); + } + + /** + * @param $configuration + */ + public function assertJsonConfiguration( $configuration ) { + $this->assertArrayHasKey( 'wgSimpleBatchUploadMaxFilesPerBatch', $configuration ); + } + + /** + * @param $configuration + */ + public function assertEarlyConfiguration( $configuration ) { + + //$configuration[ 'wgExtensionMessagesFiles' ][ 'SimpleBatchUploadAlias' ] = __DIR__ . '/SimpleBatchUpload.alias.php'; + //$configuration[ 'wgExtensionMessagesFiles' ][ 'SimpleBatchUploadMagic' ] = __DIR__ . '/SimpleBatchUpload.magic.php'; + $this->assertArrayHasKey( 'wgExtensionMessagesFiles', $configuration ); + $this->assertArrayHasKey( 'SimpleBatchUploadAlias', $configuration[ 'wgExtensionMessagesFiles' ] ); + $this->assertArrayHasKey( 'SimpleBatchUploadMagic', $configuration[ 'wgExtensionMessagesFiles' ] ); + + //$configuration[ 'wgSpecialPages' ][ 'BatchUpload' ] = '\SimpleBatchUpload\SpecialBatchUpload'; + $this->assertArrayHasKey( 'wgSpecialPages', $configuration ); + $this->assertArrayHasKey( 'BatchUpload', $configuration[ 'wgSpecialPages' ] ); + + //$configuration[ 'wgHooks' ][ 'ParserFirstCallInit' ][ 'ext.simplebatchupload' ] = [ $this, 'registerParserFunction' ]; + //$configuration[ 'wgHooks' ][ 'MakeGlobalVariablesScript' ][ 'ext.simplebatchupload' ] = [ $this, 'onMakeGlobalVariablesScript' ]; + //$configuration[ 'wgHooks' ][ 'SetupAfterCache' ][ 'ext.simplebatchupload' ] = [ $this, 'onSetupAfterCache']; + $this->assertArrayHasKey( 'wgHooks', $configuration ); + + foreach ( [ 'ParserFirstCallInit', 'MakeGlobalVariablesScript', 'SetupAfterCache' ] as $hook ) { + $this->assertArrayHasKey( $hook, $configuration[ 'wgHooks' ] ); + $this->assertArrayHasKey( 'ext.simplebatchupload', $configuration[ 'wgHooks' ][ $hook ] ); + $this->assertTrue( is_callable( $configuration[ 'wgHooks' ][ $hook ][ 'ext.simplebatchupload' ] ) ); + } + } + + /** + * @param $configuration + */ + public function assertLateConfiguration( $configuration ) { + + $this->assertArrayHasKey( 'wgResourceModules', $configuration ); + + $this->assertArrayHasKey( 'ext.SimpleBatchUpload.jquery-file-upload', $configuration[ 'wgResourceModules' ] ); + $this->assertTrue( $configuration[ 'wgResourceModules' ][ 'ext.SimpleBatchUpload.jquery-file-upload' ] === [ + 'localBasePath' => dirname( dirname( __DIR__ ) ), + 'remoteBasePath' => $GLOBALS[ 'wgExtensionAssetsPath' ] . '/SimpleBatchUpload', + 'scripts' => [ 'res/jquery.fileupload.js' ], + 'styles' => [ 'res/jquery.fileupload.css' ], + 'position' => 'top', + 'dependencies' => [ 'jquery.ui.widget' ], + ] ); + + $dependencies = [ 'ext.SimpleBatchUpload.jquery-file-upload', 'mediawiki.Title', 'mediawiki.jqueryMsg' ]; + + if ( version_compare( $GLOBALS[ 'wgVersion' ], '1.32.0', '>' ) ) { + $dependencies[] = 'mediawiki.api'; + } else { + $dependencies[] = 'mediawiki.api.edit'; + } + + $this->assertArrayHasKey( 'ext.SimpleBatchUpload', $configuration[ 'wgResourceModules' ] ); + $this->assertTrue( $configuration[ 'wgResourceModules' ][ 'ext.SimpleBatchUpload' ] === [ + 'localBasePath' => dirname( dirname( __DIR__ ) ), + 'remoteBasePath' => $GLOBALS[ 'wgExtensionAssetsPath' ] . '/SimpleBatchUpload', + 'scripts' => [ 'res/ext.SimpleBatchUpload.js' ], + 'styles' => [ 'res/ext.SimpleBatchUpload.css' ], + 'position' => 'top', + 'dependencies' => $dependencies, + 'messages' => [ 'simplebatchupload-comment', 'simplebatchupload-max-files-alert' ], + ]); + + } + +} \ No newline at end of file diff --git a/tests/setup/fix-composer.php b/tests/setup/fix-composer.php new file mode 100644 index 0000000..bcd4a23 --- /dev/null +++ b/tests/setup/fix-composer.php @@ -0,0 +1,57 @@ + composer.local.json +# +# * Reads composer.json-like from stdin +# * Adds requirement for the specified composer package ($argv[1] and $argv[2]) and a repo ($argv[3]) +# * Writes the result to stdout +# +# @copyright (C) 2016 - 2019, Stephan Gambke +# @license GNU General Public License, version 2 (or any later version) + +error_reporting( E_ALL | E_STRICT ); + +/** + * @return string + */ +function read(): string { + $in = ''; + + while ( $f = fgets( STDIN ) ) { + $in .= $f; + } + + return $in; +} + +/** + * @param string $in + * @param string[] $params + * + * @return array + */ +function process( string $in, array $params ) { + $json = json_decode( $in, true ); + + $json[ 'require' ][ $params[ 1 ] ] = $params[ 2 ]; + + $json[ 'repositories' ] = [ + [ + 'type' => 'vcs', + 'url' => 'https://github.com' . substr( $params[ 3 ], 1 ) . '.git', + ], + ]; + + return $json; +} + + +/** + * @param $json + */ +function write( $json ) { + print json_encode( $json, JSON_PRETTY_PRINT ); +} + +$in = read(); +$out = process( $in, $argv ); +write( $out ); \ No newline at end of file diff --git a/tests/setup/run-tests.sh b/tests/setup/run-tests.sh new file mode 100755 index 0000000..0e699e0 --- /dev/null +++ b/tests/setup/run-tests.sh @@ -0,0 +1,84 @@ +#!/bin/bash +# Run tests +# (assumes to be run on scrutinizer.org) +# +# @copyright (C) 2016 - 2019, Stephan Gambke +# @license GNU General Public License, version 2 (or any later version) + +set -xe + +function fetch_mw_from_download() { + + wget "https://releases.wikimedia.org/mediawiki/${MW%.*}/mediawiki-$MW.tar.gz" + tar -zxf "mediawiki-$MW.tar.gz" + mv "mediawiki-$MW" ~/mw + + cd ~/mw + composer require "phpunit/phpunit:^6.5" --update-no-dev --no-scripts +} + +function fetch_mw_from_composer() { + + wget https://github.com/wikimedia/mediawiki/archive/$MW.tar.gz + tar -zxf $MW.tar.gz + mv mediawiki-$MW ~/mw + + cd ~/mw + composer install +} + +function fetch_sbu_from_download() { + cp -R ~/build ~/mw/extensions/SimpleBatchUpload +} + +function fetch_sbu_from_composer() { + + local COMPOSER_VERSION='' + + if [[ "$SCRUTINIZER_PR_SOURCE_BRANCH" == '' ]] + then + COMPOSER_VERSION="dev-${SCRUTINIZER_BRANCH}#${SCRUTINIZER_SHA1}" + else + COMPOSER_VERSION="dev-${SCRUTINIZER_PR_SOURCE_BRANCH}#${SCRUTINIZER_SHA1}" + fi + + php ~/build/tests/setup/fix-composer.php "mediawiki/simple-batch-upload" "$COMPOSER_VERSION" "$SCRUTINIZER_PROJECT" <~/mw/composer.local.json-sample >~/mw/composer.local.json + + cd ~/mw + composer update "mediawiki/simple-batch-upload" +} + +function install() { + mysql -e 'create database wikidb;' + php ~/mw/maintenance/install.php --dbserver $SERVICE_MARIADB_IP --dbuser root --dbname wikidb --pass hugo TestWiki admin + echo "wfLoadExtension( 'SimpleBatchUpload' );" >>~/mw/LocalSettings.php +} + +function run_tests() { + php ~/mw/tests/phpunit/phpunit.php -c ~/mw/extensions/SimpleBatchUpload/phpunit.xml.dist "$@" +} + +function prepare_analysis() { + cd ~/build + mv ~/mw ~/build +} + +if [[ "$MW" =~ 1.[[:digit:]][[:digit:]].[[:digit:]][[:digit:]]? ]] # e.g. 1.33.0 +then + fetch_mw_from_download +else + fetch_mw_from_composer +fi + +if [[ "$SBU" == "download" ]] +then + fetch_sbu_from_download +else + fetch_sbu_from_composer +fi + +install + +run_tests "$@" + +prepare_analysis \ No newline at end of file