Skip to content
This repository was archived by the owner on May 30, 2025. It is now read-only.

Commit 695dc55

Browse files
committed
Test the Blueprints package, remove HTTP cache
1 parent c6accbb commit 695dc55

35 files changed

+117
-4468
lines changed

components/Blueprints/Runner.php

Lines changed: 6 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,6 @@
5151
use WordPress\Filesystem\LocalFilesystem;
5252
use WordPress\HttpClient\ByteStream\RequestReadStream;
5353
use WordPress\HttpClient\Client;
54-
use WordPress\HttpClient\FilesystemCache;
5554
use WordPress\Zip\ZipFilesystem;
5655

5756
use function WordPress\Encoding\utf8_is_valid_byte_stream;
@@ -112,29 +111,18 @@ public function __construct( RunnerConfiguration $configuration ) {
112111
$this->configuration = $configuration;
113112
$this->validateConfiguration( $configuration );
114113

115-
$this->client = new Client( [
116-
/**
117-
* !! DO NOT USE IN PRODUCTION !!
118-
*
119-
* Store cached HTTP responses in a temporary directory with a stable path
120-
* to reuse across multiple runs.
121-
*
122-
* HTTP cache support is experimental. Sometimes it loses data and
123-
* reuses incomplete cache. Sometimes it gets the fetch stream into an infinite loop.
124-
*/
125-
// 'cache' => new FilesystemCache(
126-
// LocalFilesystem::create(
127-
// sys_get_temp_dir() . '/wp-blueprints'
128-
// )
129-
// ),
130-
] );
114+
$this->client = new Client();
131115
$this->mainTracker = new Tracker();
132116

133117
// Set up progress logging
134118
$this->progressObserver = $configuration->getProgressObserver() ?? new ProgressObserver();
135119
$this->progressObserver->attachTo( $this->mainTracker );
136120
}
137121

122+
public function getExecutionContext(): Filesystem {
123+
return $this->blueprintExecutionContext;
124+
}
125+
138126
private function validateConfiguration( RunnerConfiguration $config ): void {
139127
// Validate blueprint reference
140128
$blueprint = $config->getBlueprint();
@@ -197,7 +185,7 @@ private function validateConfiguration( RunnerConfiguration $config ): void {
197185
}
198186
} elseif ( $dbEngine === 'sqlite' ) {
199187
if ( empty( $dbCreds['path'] ) ) {
200-
throw new BlueprintExecutionException( "SQLite file path is required when database engine is 'sqlite'." );
188+
$dbCreds['path'] = 'wp-content/.ht.sqlite';
201189
}
202190
}
203191
}

components/Blueprints/Steps/MkdirStep.php

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
namespace WordPress\Blueprints\Steps;
44

5+
use WordPress\Blueprints\Exception\BlueprintExecutionException;
56
use WordPress\Blueprints\Progress\Tracker;
67
use WordPress\Blueprints\Runtime;
78

@@ -26,7 +27,10 @@ public function __construct( string $path ) {
2627
*/
2728
public function run( Runtime $runtime, Tracker $tracker ) {
2829
$tracker->setCaption( 'Creating directory ' . $this->path );
29-
// @TODO: Throw exception in the LocalFilesystem class if the creation fails
30-
$runtime->getTargetFilesystem()->mkdir( $this->path, [ 'recursive' => true ] );
30+
$fs = $runtime->getTargetFilesystem();
31+
if($fs->exists($this->path)) {
32+
throw new BlueprintExecutionException(sprintf('Path already exists: %s', $this->path));
33+
}
34+
$fs->mkdir( $this->path, [ 'recursive' => true ] );
3135
}
3236
}

components/Blueprints/Tests/Unit/DataReference/DataReferenceResolverTest.php

Lines changed: 4 additions & 61 deletions
Original file line numberDiff line numberDiff line change
@@ -14,9 +14,7 @@
1414
use WordPress\Blueprints\DataReference\GitPath;
1515
use WordPress\Blueprints\DataReference\InlineDirectory;
1616
use WordPress\Blueprints\DataReference\InlineFile;
17-
use WordPress\Blueprints\DataReference\URLReference;
18-
use WordPress\Blueprints\DataReference\WordPressOrgPlugin;
19-
use WordPress\Blueprints\DataReference\WordPressOrgTheme;
17+
use WordPress\Blueprints\Exception\DataResolutionException;
2018
use WordPress\Blueprints\Progress\Tracker;
2119
use WordPress\ByteStream\MemoryPipe;
2220
use WordPress\ByteStream\ReadStream\ByteReadStream;
@@ -32,59 +30,14 @@ class DataReferenceResolverTest extends TestCase {
3230
protected $tracker;
3331

3432
protected function setUp(): void {
35-
// TODO: Mock Client and Filesystem as needed
36-
$this->client = $this->createMock( Client::class );
33+
// @TODO: Don't mock. Just test actual resolution.
34+
$this->client = new Client();
3735
$this->resolver = new DataReferenceResolver( $this->client );
3836
$this->executionContext = $this->createMock( Filesystem::class );
3937
$this->tracker = $this->createMock( Tracker::class );
4038
$this->resolver->setExecutionContext( $this->executionContext );
4139
}
4240

43-
public function testResolveURLReference() {
44-
$url = 'https://example.com/file.zip';
45-
$reference = new URLReference( $url );
46-
$dummyStream = $this->createMock( ByteReadStream::class );
47-
$this->client->expects( $this->once() )
48-
->method( 'fetch' )
49-
->with( $url, $this->arrayHasKey( 'progress_tracker' ) )
50-
->willReturn( $dummyStream );
51-
52-
$result = $this->resolver->resolve( $reference );
53-
$this->assertInstanceOf( File::class, $result );
54-
$this->assertSame( $dummyStream, $result->getStream() );
55-
$this->assertEquals( 'file.zip', $result->filename );
56-
}
57-
58-
public function testResolveWordPressOrgPlugin() {
59-
$reference = new WordPressOrgPlugin( 'akismet' );
60-
$expectedUrl = 'https://downloads.wordpress.org/plugin/akismet.latest-stable.zip';
61-
$dummyStream = $this->createMock( ByteReadStream::class );
62-
$this->client->expects( $this->once() )
63-
->method( 'fetch' )
64-
->with( $expectedUrl, $this->arrayHasKey( 'progress_tracker' ) )
65-
->willReturn( $dummyStream );
66-
67-
$result = $this->resolver->resolve( $reference );
68-
$this->assertInstanceOf( File::class, $result );
69-
$this->assertSame( $dummyStream, $result->getStream() );
70-
$this->assertEquals( 'akismet.latest-stable.zip', $result->filename );
71-
}
72-
73-
public function testResolveWordPressOrgTheme() {
74-
$reference = new WordPressOrgTheme( 'twentytwentyfour' );
75-
$expectedUrl = 'https://downloads.wordpress.org/theme/twentytwentyfour.latest-stable.zip';
76-
$dummyStream = $this->createMock( ByteReadStream::class );
77-
$this->client->expects( $this->once() )
78-
->method( 'fetch' )
79-
->with( $expectedUrl, $this->arrayHasKey( 'progress_tracker' ) )
80-
->willReturn( $dummyStream );
81-
82-
$result = $this->resolver->resolve( $reference );
83-
$this->assertInstanceOf( File::class, $result );
84-
$this->assertSame( $dummyStream, $result->getStream() );
85-
$this->assertEquals( 'twentytwentyfour.latest-stable.zip', $result->filename );
86-
}
87-
8841
public function testResolveExecutionContextPathFile() {
8942
$reference = new ExecutionContextPath( './foo.txt' );
9043
$this->executionContext->method( 'exists' )->with( './foo.txt' )->willReturn( true );
@@ -158,7 +111,7 @@ public function testResolveGitPath() {
158111
public function testResolveMissingExecutionContextFileThrows() {
159112
$reference = new ExecutionContextPath( './missing.txt' );
160113
$this->executionContext->method( 'exists' )->with( './missing.txt' )->willReturn( false );
161-
$this->expectException( RuntimeException::class );
114+
$this->expectException( DataResolutionException::class );
162115
$this->resolver->resolve( $reference );
163116
}
164117

@@ -168,14 +121,4 @@ public function testResolveUnsupportedReferenceTypeThrows() {
168121
$this->resolver->resolve( $reference );
169122
}
170123

171-
public function testResolveURLReferenceFetchFailureThrows() {
172-
$url = 'https://example.com/fail.zip';
173-
$reference = new URLReference( $url );
174-
$this->client->expects( $this->once() )
175-
->method( 'fetch' )
176-
->with( $url, $this->arrayHasKey( 'progress_tracker' ) )
177-
->will( $this->throwException( new RuntimeException( 'Fetch failed' ) ) );
178-
$this->expectException( RuntimeException::class );
179-
$this->resolver->resolve( $reference );
180-
}
181124
}

components/Blueprints/Tests/Unit/Steps/MkdirStepTest.php

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,12 @@
22

33
namespace WordPress\Blueprints\Tests\Unit\Steps;
44

5+
use WordPress\Blueprints\Exception\BlueprintExecutionException;
56
use WordPress\Blueprints\Progress\Tracker;
67
use WordPress\Blueprints\Steps\MkdirStep;
78
use WordPress\Filesystem\FilesystemException;
89

9-
class MkdirStepRunnerTest extends StepTestCase {
10+
class MkdirStepTest extends StepTestCase {
1011

1112
public function testCreateDirectoryWhenUsingRelativePath() {
1213
$path = 'dir';
@@ -75,7 +76,7 @@ public function testThrowExceptionWhenCreatingDirectoryAndItAlreadyExists() {
7576
);
7677

7778
$tracker = new Tracker();
78-
$this->expectException( FilesystemException::class );
79+
$this->expectException( BlueprintExecutionException::class );
7980
$this->expectExceptionMessageMatches( "/Path already exists:/" );
8081
$step->run( $this->runtime, $tracker );
8182
}

components/Blueprints/Tests/Unit/Steps/RmDirStepTest.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
use WordPress\Blueprints\Steps\RmDirStep;
77
use WordPress\Filesystem\FilesystemException;
88

9-
class RmDirStepRunnerTest extends StepTestCase {
9+
class RmDirStepTest extends StepTestCase {
1010

1111
public function testRemoveEmptyDirectory() {
1212
$fs = $this->runtime->getTargetFilesystem();

components/Blueprints/Tests/Unit/Steps/RunPHPStepTest.php

Lines changed: 49 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
namespace WordPress\Blueprints\Tests\Unit\Steps;
44

55
use Exception;
6+
use WordPress\Blueprints\DataReference\InlineFile;
67
use WordPress\Blueprints\Progress\Tracker;
78
use WordPress\Blueprints\Steps\RunPHPStep;
89

@@ -14,37 +15,49 @@ class RunPHPStepTest extends StepTestCase {
1415
* Test running simple PHP code
1516
*/
1617
public function testRunSimplePHPCode() {
17-
$step = new RunPHPStep(
18-
'<?php echo "Hello World";'
19-
);
18+
$output_file = wp_join_paths( $this->runtime->getConfiguration()->getTargetSiteRoot(), 'output.txt' );
19+
20+
$step = new RunPHPStep(new InlineFile(
21+
'script.php',
22+
<<<PHP
23+
<?php
24+
file_put_contents(getenv('DOCROOT') . '/output.txt', 'Hello World');
25+
PHP
26+
));
2027

2128
$tracker = new Tracker();
22-
$result = $step->run( $this->runtime, $tracker );
29+
$step->run( $this->runtime, $tracker );
2330

24-
$this->assertEquals( 'Hello World', $result );
31+
$this->assertFileExists( $output_file );
32+
$this->assertEquals( 'Hello World', file_get_contents( $output_file ) );
2533
}
2634

2735
/**
2836
* Test running PHP code that creates a file
2937
*/
3038
public function testRunPHPCodeCreatingFile() {
3139
$test_file_path = wp_join_paths( $this->runtime->getConfiguration()->getTargetSiteRoot(), 'test_file.txt' );
32-
$test_content = 'This is a test file created by PHP';
40+
$output_file = wp_join_paths( $this->runtime->getConfiguration()->getTargetSiteRoot(), 'output.txt' );
41+
$test_content = 'This is a test file created by PHP';
3342

3443
$step = new RunPHPStep(
35-
<<<PHP
44+
new InlineFile(
45+
'script.php',
46+
<<<PHP
3647
<?php
3748
\$docroot = getenv('DOCROOT');
3849
\$test_file_path = \$docroot . '/test_file.txt';
3950
file_put_contents(\$test_file_path, 'This is a test file created by PHP');
40-
echo "File created";
51+
file_put_contents(\$docroot . '/output.txt', 'File created');
4152
PHP
53+
)
4254
);
4355

4456
$tracker = new Tracker();
45-
$result = $step->run( $this->runtime, $tracker );
57+
$step->run( $this->runtime, $tracker );
4658

47-
$this->assertEquals( 'File created', $result );
59+
$this->assertFileExists( $output_file );
60+
$this->assertEquals( 'File created', file_get_contents( $output_file ) );
4861
$this->assertFileExists( $test_file_path );
4962
$this->assertEquals( $test_content, file_get_contents( $test_file_path ) );
5063
}
@@ -53,23 +66,29 @@ public function testRunPHPCodeCreatingFile() {
5366
* Test running PHP code that loads WordPress
5467
*/
5568
public function testRunPHPCodeWithWordPress() {
69+
$output_file = wp_join_paths( $this->runtime->getConfiguration()->getTargetSiteRoot(), 'output.txt' );
70+
5671
$step = new RunPHPStep(
57-
<<<PHP
72+
new InlineFile(
73+
'script.php',
74+
<<<PHP
5875
<?php
5976
require_once getenv('DOCROOT') . '/wp-load.php';
6077
6178
// Create a test option
6279
update_option('test_option', 'test_value');
6380
64-
// Return the option value
65-
echo get_option('test_option');
81+
// Write the option value to an output file
82+
file_put_contents(getenv('DOCROOT') . '/output.txt', get_option('test_option'));
6683
PHP
84+
)
6785
);
6886

6987
$tracker = new Tracker();
70-
$result = $step->run( $this->runtime, $tracker );
88+
$step->run( $this->runtime, $tracker );
7189

72-
$this->assertEquals( 'test_value', $result );
90+
$this->assertFileExists( $output_file );
91+
$this->assertEquals( 'test_value', file_get_contents( $output_file ) );
7392

7493
// Verify the option was actually set in WordPress
7594
$option_value = $this->runtime->evalPhpCodeInSubProcess(
@@ -88,8 +107,12 @@ public function testRunPHPCodeWithWordPress() {
88107
* Test running PHP code that returns complex data
89108
*/
90109
public function testRunPHPCodeReturningComplexData() {
110+
$output_file = wp_join_paths( $this->runtime->getConfiguration()->getTargetSiteRoot(), 'output.txt' );
111+
91112
$step = new RunPHPStep(
92-
<<<PHP
113+
new InlineFile(
114+
'script.php',
115+
<<<PHP
93116
<?php
94117
\$data = [
95118
'string' => 'Hello',
@@ -99,13 +122,16 @@ public function testRunPHPCodeReturningComplexData() {
99122
'object' => (object)['name' => 'Test']
100123
];
101124
102-
echo json_encode(\$data);
125+
file_put_contents(getenv('DOCROOT') . '/output.txt', json_encode(\$data));
103126
PHP
127+
)
104128
);
105129

106130
$tracker = new Tracker();
107-
$result = $step->run( $this->runtime, $tracker );
108-
$data = json_decode( $result, true );
131+
$step->run( $this->runtime, $tracker );
132+
133+
$this->assertFileExists( $output_file );
134+
$data = json_decode( file_get_contents( $output_file ), true );
109135

110136
$this->assertIsArray( $data );
111137
$this->assertEquals( 'Hello', $data['string'] );
@@ -120,7 +146,10 @@ public function testRunPHPCodeReturningComplexData() {
120146
*/
121147
public function testRunPHPCodeWithSyntaxError() {
122148
$step = new RunPHPStep(
123-
'<?php echo "Missing semicolon" echo "Another string";'
149+
new InlineFile(
150+
'script.php',
151+
'<?php echo "Missing semicolon" echo "Another string";'
152+
)
124153
);
125154

126155
$tracker = new Tracker();

components/Blueprints/Tests/Unit/Steps/StepTestCase.php

Lines changed: 23 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
namespace WordPress\Blueprints\Tests\Unit\Steps;
44

55
use PHPUnit\Framework\TestCase;
6+
use WordPress\Blueprints\DataReference\DataReference;
67
use WordPress\Blueprints\Runner;
78
use WordPress\Blueprints\RunnerConfiguration;
89
use WordPress\Blueprints\Runtime;
@@ -40,14 +41,29 @@ public function setUp(): void {
4041
$this->execution_context_path = wp_join_paths( sys_get_temp_dir(), 'test_' . uniqid() );
4142
$this->execution_context = LocalFilesystem::create( $this->execution_context_path );
4243

43-
$config = ( new RunnerConfiguration() )
44-
->setBlueprint( [ "version" => 2 ] )
44+
$base_site_root = wp_join_paths( sys_get_temp_dir(), 'blueprint_test_base_site' );
45+
if ( is_dir( $base_site_root ) ) {
46+
LocalFilesystem::create()->copy( $base_site_root, $this->document_root, [ 'recursive' => true ] );
47+
$config = ( new RunnerConfiguration() )
48+
->setExecutionMode( 'apply-to-existing-site' )
49+
->setTargetSiteRoot( $this->document_root ) // Arbitrary URL for the new site
50+
;
51+
} else {
52+
$config = ( new RunnerConfiguration() )
53+
->setExecutionMode( 'create-new-site' )
54+
->setTargetSiteRoot( $base_site_root ) // Arbitrary URL for the new site
55+
;
56+
}
57+
58+
file_put_contents(
59+
wp_join_paths( $this->execution_context_path, 'blueprint.json' ),
60+
json_encode( [ "version" => 2 ] )
61+
);
62+
63+
$config
64+
->setBlueprint( DataReference::create( wp_join_paths($this->execution_context_path, 'blueprint.json' ) ) )
4565
->setDatabaseEngine( 'sqlite' )
46-
->setExecutionMode( 'create-new-site' )
47-
->setExecutionContext( $this->execution_context )
48-
->setTargetSiteRoot( $this->document_root )
49-
->setTargetSiteUrl( 'http://127.0.0.1:2456' ) // Arbitrary URL for the new site
50-
;
66+
->setTargetSiteUrl( 'http://127.0.0.1:2456' );
5167

5268
$runner = new Runner( $config );
5369
$runner->run();

0 commit comments

Comments
 (0)