diff --git a/composer.json b/composer.json index cb0b96e9..ea851fe5 100644 --- a/composer.json +++ b/composer.json @@ -1,8 +1,7 @@ { "prefer-stable": true, "require": { - "ext-json": "*", - "php": ">=7.0" + "ext-json": "*" }, "require-dev": { "yoast/phpunit-polyfills": "2.0.0" @@ -20,9 +19,9 @@ "Pimple\\": "src/pimple/pimple/src/Pimple", "Psr\\Container\\": "src/psr/container", "Psr\\SimpleCache\\": "src/psr/simple-cache", - "Symfony\\Component\\Process\\": "src/Symfony/process", - "Symfony\\Component\\EventDispatcher\\": "src/Symfony/event-dispatcher", - "Symfony\\Component\\filesystem\\": "src/Symfony/filesystem", + "Symfony\\Component\\Process\\": "src/symfony/process", + "Symfony\\Component\\EventDispatcher\\": "src/symfony/event-dispatcher", + "Symfony\\Component\\filesystem\\": "src/symfony/filesystem", "Opis\\JsonSchema\\": "src/opis/json-schema/src", "Opis\\String\\": "src/opis/string/src", "Opis\\Uri\\": "src/opis/uri/src" @@ -38,5 +37,8 @@ "classmap": [ "tests/" ] + }, + "scripts": { + "test": [ "Composer\\Config::disableProcessTimeout", "@php ./vendor/phpunit/phpunit/phpunit --testdox" ] } } diff --git a/dev/composer.json b/dev/composer.json index 8fb7fa66..336bf18b 100644 --- a/dev/composer.json +++ b/dev/composer.json @@ -17,9 +17,9 @@ "Pimple\\": "../src/pimple/pimple/src/Pimple", "Psr\\Container\\": "../src/psr/container", "Psr\\SimpleCache\\": "../src/psr/simple-cache", - "Symfony\\Component\\Process\\": "../src/Symfony/process", - "Symfony\\Component\\EventDispatcher\\": "../src/Symfony/event-dispatcher", - "Symfony\\Component\\Filesystem\\": "../src/Symfony/filesystem", + "Symfony\\Component\\Process\\": "../src/symfony/process", + "Symfony\\Component\\EventDispatcher\\": "../src/symfony/event-dispatcher", + "Symfony\\Component\\Filesystem\\": "../src/symfony/filesystem", "Opis\\JsonSchema\\": "../src/opis/json-schema/src", "Opis\\String\\": "../src/opis/string/src", "Opis\\Uri\\": "../src/opis/uri/src" diff --git a/examples/json_string_compiling.php b/examples/json_string_compiling.php index 012426a0..2a564f90 100644 --- a/examples/json_string_compiling.php +++ b/examples/json_string_compiling.php @@ -1,9 +1,5 @@ 'onProgress', - DoneEvent::class => 'onDone', - ); + DoneEvent::class => 'onDone', + ]; } protected $progress_bar; - public function __construct() { - ProgressBar::setFormatDefinition( 'custom', ' [%bar%] %current%/%max% -- %message%' ); + public function __construct() {} - $this->progress_bar = ( new SymfonyStyle( - new StringInput( '' ), - new ConsoleOutput() - ) )->createProgressBar( 100 ); - $this->progress_bar->setFormat( 'custom' ); - $this->progress_bar->setMessage( 'Start' ); - $this->progress_bar->start(); - } - - public function onProgress( ProgressEvent $event ) { - $this->progress_bar->setMessage( $event->caption ); - $this->progress_bar->setProgress( (int) $event->progress ); - } + public function onProgress( ProgressEvent $event ) {} - public function onDone( DoneEvent $event ) { - $this->progress_bar->finish(); - } + public function onDone( DoneEvent $event ) {} }; $results = run_blueprint( diff --git a/phpunit.xml.dist b/phpunit.xml.dist index 6d629d8a..a0f8297d 100644 --- a/phpunit.xml.dist +++ b/phpunit.xml.dist @@ -4,6 +4,7 @@ bootstrap="vendor/autoload.php" colors="true" beStrictAboutOutputDuringTests="true" + cacheResultFile=".cache" > diff --git a/src/WordPress/AsyncHttp/async_http_streams.php b/src/WordPress/AsyncHttp/async_http_streams.php index 71d4581b..de9e52e8 100644 --- a/src/WordPress/AsyncHttp/async_http_streams.php +++ b/src/WordPress/AsyncHttp/async_http_streams.php @@ -229,8 +229,7 @@ function stream_http_prepare_request_bytes( $url ) { REQUEST; // @TODO: Add support for Accept-Encoding: gzip - - return str_replace( "\n", "\r\n", $request ) . "\r\n\r\n"; + return $request . "\r\n\r\n"; } /** @@ -262,7 +261,6 @@ function streams_http_response_await_headers( $streams ) { foreach ( $headers as $k => $header ) { $headers[ $k ] = parse_http_headers( $header ); } - return $headers; } diff --git a/src/WordPress/Blueprints/Compile/BlueprintCompiler.php b/src/WordPress/Blueprints/Compile/BlueprintCompiler.php index 6baba8a0..654846b3 100644 --- a/src/WordPress/Blueprints/Compile/BlueprintCompiler.php +++ b/src/WordPress/Blueprints/Compile/BlueprintCompiler.php @@ -72,7 +72,7 @@ protected function expandShorthandsIntoSteps( $blueprint ) { $additional_steps[] = ( new RunWordPressInstallerStep() ) ->setOptions( new WordPressInstallationOptions() ); } - if ( $blueprint->constants ) { + if ( $blueprint->constants && $blueprint->constants->count() > 0 ) { $step = new DefineWpConfigConstsStep(); $step->consts = $blueprint->constants; $additional_steps[] = $step; @@ -84,7 +84,7 @@ protected function expandShorthandsIntoSteps( $blueprint ) { $additional_steps[] = $step; } } - if ( $blueprint->siteOptions ) { + if ( $blueprint->siteOptions && $blueprint->siteOptions->count() > 0) { $step = new SetSiteOptionsStep(); $step->setOptions( $blueprint->siteOptions ); $additional_steps[] = $step; diff --git a/src/WordPress/Blueprints/Model/BlueprintBuilder.php b/src/WordPress/Blueprints/Model/BlueprintBuilder.php index 0a3abc53..d2f37fcf 100644 --- a/src/WordPress/Blueprints/Model/BlueprintBuilder.php +++ b/src/WordPress/Blueprints/Model/BlueprintBuilder.php @@ -31,6 +31,8 @@ class BlueprintBuilder { public function __construct() { $this->blueprint = new Blueprint(); + $this->blueprint->setConstants( new \ArrayObject() ); + $this->blueprint->setSiteOptions( new \ArrayObject() ); } public static function create() { diff --git a/src/WordPress/Blueprints/Runner/Step/MkdirStepRunner.php b/src/WordPress/Blueprints/Runner/Step/MkdirStepRunner.php index 86d99370..c0562eaf 100644 --- a/src/WordPress/Blueprints/Runner/Step/MkdirStepRunner.php +++ b/src/WordPress/Blueprints/Runner/Step/MkdirStepRunner.php @@ -2,19 +2,24 @@ namespace WordPress\Blueprints\Runner\Step; +use Symfony\Component\Filesystem\Exception\IOException; +use Symfony\Component\Filesystem\Filesystem; +use WordPress\Blueprints\BlueprintException; use WordPress\Blueprints\Model\DataClass\MkdirStep; class MkdirStepRunner extends BaseStepRunner { /** - * @param \WordPress\Blueprints\Model\DataClass\MkdirStep $input + * @param MkdirStep $input */ - function run( $input ) { - // @TODO: Treat $input->path as relative path to the document root (unless it's absolute) - $success = mkdir( $input->path ); - if ( ! $success ) { - throw new \Exception( "Failed to create directory at {$input->path}" ); + function run( MkdirStep $input ) { + $resolvedPath = $this->getRuntime()->resolvePath( $input->path ); + $fileSystem = new Filesystem(); + try { + $fileSystem->mkdir( $resolvedPath ); + } catch ( IOException $exception ) { + throw new BlueprintException( "Failed to create a directory at \"$resolvedPath\"", 0, $exception ); } } } diff --git a/src/WordPress/Blueprints/Runner/Step/RunWordPressInstallerStepRunner.php b/src/WordPress/Blueprints/Runner/Step/RunWordPressInstallerStepRunner.php index bfd75a32..2ab371ea 100644 --- a/src/WordPress/Blueprints/Runner/Step/RunWordPressInstallerStepRunner.php +++ b/src/WordPress/Blueprints/Runner/Step/RunWordPressInstallerStepRunner.php @@ -2,6 +2,7 @@ namespace WordPress\Blueprints\Runner\Step; +use PHPUnit\Exception; use WordPress\Blueprints\Model\DataClass\RunWordPressInstallerStep; use WordPress\Blueprints\Progress\Tracker; @@ -11,21 +12,28 @@ class RunWordPressInstallerStepRunner extends BaseStepRunner { * @param \WordPress\Blueprints\Progress\Tracker $tracker */ function run( $input, $tracker ) { - return $this->getRuntime()->runShellCommand( - array( - 'php', - 'wp-cli.phar', - '--allow-root', - 'core', - 'install', - '--url=http://localhost:8081', - '--title=Playground Site', - '--admin_user=' . $input->options->adminUsername, - '--admin_password=' . $input->options->adminPassword, - '--admin_email=admin@wordpress.internal', - ), - $this->getRuntime()->getDocumentRoot() - ); + var_dump( $input ); + try { + $result = $this->getRuntime()->runShellCommand( + array( + 'php', + 'wp-cli.phar', + '--allow-root', + 'core', + 'install', + '--url=http://localhost:8081', + '--title=Playground Site', + '--admin_user=' . $input->options->adminUsername, + '--admin_password=' . $input->options->adminPassword, + '--admin_email=admin@wordpress.internal', + ), + $this->getRuntime()->getDocumentRoot() + ); + return trim( $result ); + } catch ( Exception $exception ) { + var_dump( $exception ); + } + return null; } public function getDefaultCaption( $input ) { diff --git a/src/WordPress/Blueprints/functions.php b/src/WordPress/Blueprints/functions.php index 83d233bc..3c3b56f9 100644 --- a/src/WordPress/Blueprints/functions.php +++ b/src/WordPress/Blueprints/functions.php @@ -18,11 +18,10 @@ function run_blueprint( $json, $options = array() ) { $environment, new Runtime( $documentRoot ) ); - + /** @var $engine Engine */ $engine = $c['blueprint.engine']; $compiledBlueprint = $engine->parseAndCompile( $json ); - /** @var $engine Engine */ if ( $progressSubscriber ) { if ( $progressType === 'steps' ) { $compiledBlueprint->stepsProgressStage->events->addSubscriber( $progressSubscriber ); diff --git a/tests/e2e/JsonBlueprintTest.php b/tests/e2e/JsonBlueprintTest.php new file mode 100644 index 00000000..b91757f6 --- /dev/null +++ b/tests/e2e/JsonBlueprintTest.php @@ -0,0 +1,119 @@ +document_root = Path::makeAbsolute('test', sys_get_temp_dir()); + + $this->subscriber = new TestResourceClassSimpleSubscriber(); + } + + /** + * @after + */ + public function after() { + ( new Filesystem() )->remove( $this->document_root ); + } + public function testRunningJsonBlueprintWithWordPressVersion() { + $blueprint = '{"WordPressVersion":"https://wordpress.org/latest.zip"}'; + + $results = run_blueprint( + $blueprint, + array( + 'environment' => ContainerBuilder::ENVIRONMENT_NATIVE, + 'documentRoot' => $this->document_root, + 'progressSubscriber' => $this->subscriber, + ) + ); + + $word_press_zip = ( new UrlResource() ) + ->setResource( 'url' ) + ->setUrl('https://wordpress.org/latest.zip'); + $download_word_press_step = ( new DownloadWordPressStep() ) + ->setWordPressZip( $word_press_zip ); + + $sqlite_plugin_zip = ( new UrlResource() ) + ->setResource('url' ) + ->setUrl( 'https://downloads.wordpress.org/plugin/sqlite-database-integration.zip' ); + $install_sqlite_integration_step = ( new InstallSqliteIntegrationStep() ) + ->setSqlitePluginZip( $sqlite_plugin_zip ); + + $wp_cli = ( new UrlResource() ) + ->setResource('url' ) + ->setUrl('https://playground.wordpress.net/wp-cli.phar' ); + $write_file_step = ( new WriteFileStep() ) + ->setPath( 'wp-cli.phar' ) + ->setData( $wp_cli ); + + $run_word_press_installer_step = ( new RunWordPressInstallerStep() ) + ->setOptions( new WordPressInstallationOptions() ); + + $expected = array( + 0 => new StepSuccess( $download_word_press_step, null ), + 1 => new StepSuccess( $install_sqlite_integration_step, null ), + 2 => new StepSuccess( $write_file_step, null ), + 3 => new StepSuccess( $run_word_press_installer_step, 'Success: WordPress installed successfully.' ) + ); + + //@TODO Assert WP files exist + + self::assertEquals( $expected, $results ); + } + + public function testRunningJsonBlueprintWithSteps() { + $blueprint = '{"steps":[{"step":"mkdir","path":"dir1"},{"step": "rm","path": "dir1"},{"step":"mkdir","path":"dir2"}]}'; + + $results = run_blueprint( + $blueprint, + array( + 'environment' => ContainerBuilder::ENVIRONMENT_NATIVE, + 'documentRoot' => $this->document_root, + 'progressSubscriber' => $this->subscriber, + ) + ); + + $expected = array( + 0 => new StepSuccess( ( new MkdirStep() )->setPath( 'dir1' ), null ), + 1 => new StepSuccess( ( new RmStep() )->setPath( 'dir1' ), null ), + 2 => new StepSuccess( ( new MkdirStep() )->setPath( 'dir2' ), null ), + ); + + self::assertDirectoryDoesNotExist( Path::makeAbsolute( 'dir1', $this->document_root ) ); + self::assertDirectoryExists( Path::makeAbsolute( 'dir2', $this->document_root ) ); + self::assertEquals( $expected, $results ); + } +} \ No newline at end of file diff --git a/tests/e2e/PhpBlueprintTest.php b/tests/e2e/PhpBlueprintTest.php new file mode 100644 index 00000000..7be07255 --- /dev/null +++ b/tests/e2e/PhpBlueprintTest.php @@ -0,0 +1,130 @@ +document_root = Path::makeAbsolute( 'test', sys_get_temp_dir() ); + + $this->subscriber = new TestResourceClassSimpleSubscriber(); + } + + /** + * @after + */ + public function after() { + ( new Filesystem() )->remove( $this->document_root ); + } + + public function testRunningPhpBlueprintWithWordPressVersion() { + $blueprint = BlueprintBuilder::create() + ->withWordPressVersion( 'https://wordpress.org/latest.zip' ) + ->toBlueprint(); + + $results = run_blueprint( + $blueprint, + array( + 'environment' => ContainerBuilder::ENVIRONMENT_NATIVE, + 'documentRoot' => $this->document_root, + 'progressSubscriber' => $this->subscriber, + ) + ); + + $word_press_zip = ( new UrlResource() ) + ->setResource( 'url' ) + ->setUrl('https://wordpress.org/latest.zip'); + $download_word_press_step = ( new DownloadWordPressStep() ) + ->setWordPressZip( $word_press_zip ); + + $sqlite_plugin_zip = ( new UrlResource() ) + ->setResource('url' ) + ->setUrl( 'https://downloads.wordpress.org/plugin/sqlite-database-integration.zip' ); + $install_sqlite_integration_step = ( new InstallSqliteIntegrationStep() ) + ->setSqlitePluginZip( $sqlite_plugin_zip ); + + $wp_cli = ( new UrlResource() ) + ->setResource('url' ) + ->setUrl('https://playground.wordpress.net/wp-cli.phar' ); + $write_file_step = ( new WriteFileStep() ) + ->setPath( 'wp-cli.phar' ) + ->setData( $wp_cli ); + + $run_word_press_installer_step = ( new RunWordPressInstallerStep() ) + ->setOptions( new WordPressInstallationOptions() ); + + $expected = array( + 0 => new StepSuccess( $download_word_press_step, null ), + 1 => new StepSuccess( $install_sqlite_integration_step, null ), + 2 => new StepSuccess( $write_file_step, null ), + 3 => new StepSuccess( $run_word_press_installer_step, 'Success: WordPress installed successfully.' ) + ); + +// - 'result' => 'Success: WordPress installed successfully.' +// + 'result' => '#!/usr/bin/env php\n +// + Success: WordPress installed successfully.' + + //@TODO Assert WP files exist + + self::assertEquals( $expected, $results ); + } + + public function testRunningPhpBlueprintWithSteps() { + $blueprint = BlueprintBuilder::create() + ->addStep( ( new MkdirStep() )->setPath( 'dir1' ) ) + ->addStep( ( new RmStep() )->setPath( 'dir1' ) ) + ->addStep( ( new MkdirStep() )->setPath( 'dir2' ) ) + ->toBlueprint(); + + $results = run_blueprint( + $blueprint, + array( + 'environment' => ContainerBuilder::ENVIRONMENT_NATIVE, + 'documentRoot' => $this->document_root, + 'progressSubscriber' => $this->subscriber, + ) + ); + + $expected = array( + 0 => new StepSuccess( ( new MkdirStep() )->setPath( 'dir1' ), null ), + 1 => new StepSuccess( ( new RmStep() )->setPath( 'dir1' ), null ), + 2 => new StepSuccess( ( new MkdirStep() )->setPath( 'dir2' ), null ), + ); + + self::assertDirectoryDoesNotExist( Path::makeAbsolute( 'dir1', $this->document_root ) ); + self::assertDirectoryExists( Path::makeAbsolute( 'dir2', $this->document_root ) ); + self::assertEquals( $expected, $results ); + } +} diff --git a/tests/e2e/configuration/E2ETestCase.php b/tests/e2e/configuration/E2ETestCase.php new file mode 100644 index 00000000..544ca2dd --- /dev/null +++ b/tests/e2e/configuration/E2ETestCase.php @@ -0,0 +1,5 @@ + 'onProgress', + DoneEvent::class => 'onDone', + ]; + } + + protected $progress_bar; + + public function __construct() {} + + public function onProgress( ProgressEvent $event ) {} + + public function onDone( DoneEvent $event ) {} +} diff --git a/tests/unit/json_mapper/JsonMapperTest.php b/tests/unit/json_mapper/JsonMapperTest.php index 88117c48..2100957c 100644 --- a/tests/unit/json_mapper/JsonMapperTest.php +++ b/tests/unit/json_mapper/JsonMapperTest.php @@ -26,20 +26,21 @@ public function before() { } public function testCustomFactory() { - $mapper = new JsonMapper( array( + $custom_factories = array( Item::class => function ( $json ) { $item = new Item(); $item->name = $json->name; return $item; }, - ) ); - - $result = $mapper->hydrate( - json_decode( '{"name":"test","items":[{"name":"test"}]}' ), - Bag::class ); + $mapper = new JsonMapper($custom_factories); + + $raw_json = '{"name":"test","items":[{"name":"test"}]}'; + + $result = $mapper->hydrate( json_decode( $raw_json ), Bag::class ); + $expected = new Bag(); $expected->name = 'test'; $expected->items = [ new Item() ];