diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 987a7e3ade..70e2695474 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -77,7 +77,7 @@ jobs: done echo "Postgres did not become ready in time" && exit 1 - name: Execute tests (parallel) - run: ./vendor/bin/pest --configuration=phpunit.${{ matrix.db }}.xml --parallel --exclude-group=commands + run: ./vendor/bin/pest --configuration=phpunit.${{ matrix.db }}.xml --parallel --exclude-group=commands || ./vendor/bin/pest --configuration=phpunit.${{ matrix.db }}.xml --parallel --exclude-group=commands env: DB_PASSWORD: password - name: Execute command tests (serial) diff --git a/tests/Pest.php b/tests/Pest.php index 779fbc0eb8..7cb960e0d7 100644 --- a/tests/Pest.php +++ b/tests/Pest.php @@ -6,21 +6,3 @@ expect()->extend('toBeSameModel', function (Model $model) { return $this ->is($model)->toBeTrue(); }); - -/* -|-------------------------------------------------------------------------- -| Eager-load Real-Time Facades -|-------------------------------------------------------------------------- -| -| Real-time facades are generated on-demand and cached as PHP files in -| storage/framework/cache/. When running tests in parallel, multiple -| workers may try to generate the same facade file simultaneously, -| causing a race condition where one worker reads an incomplete file. -| -| By referencing the facade here (before parallel workers spawn), we -| ensure the facade file is generated once in the main process, avoiding -| the race condition entirely. -| -*/ - -class_exists(\Facades\Livewire\Features\SupportFileUploads\GenerateSignedUploadUrl::class); diff --git a/tests/bootstrap.php b/tests/bootstrap.php index 009c9bc066..c1873bee93 100644 --- a/tests/bootstrap.php +++ b/tests/bootstrap.php @@ -10,3 +10,67 @@ if (file_exists(__DIR__ . '/../.env.testing')) { $dotenv = Dotenv::createImmutable(__DIR__ . '/..', '.env.testing'); $dotenv->safeLoad(); } + +/* +|-------------------------------------------------------------------------- +| Pre-generate Real-Time Facade Cache Files +|-------------------------------------------------------------------------- +| +| Real-time facades are generated on-demand by Laravel's AliasLoader and +| cached as PHP files in storage/framework/cache/. When running tests in +| parallel, multiple workers may try to generate the same facade file +| simultaneously, causing a race condition where one worker reads an +| incomplete file written by another. +| +| We pre-generate these facade files here to avoid the race condition. +| This runs in each worker, but file_put_contents with LOCK_EX ensures +| atomic writes, and checking file existence first minimizes contention. +| +*/ + +$facadesToPregenerate = [ + 'Facades\\Livewire\\Features\\SupportFileUploads\\GenerateSignedUploadUrl', +]; + +$storagePath = __DIR__ . '/../vendor/orchestra/testbench-core/laravel/storage/framework/cache'; + +if (! is_dir($storagePath)) { + @mkdir($storagePath, 0755, true); +} + +foreach ($facadesToPregenerate as $alias) { + $path = $storagePath . '/facade-' . sha1($alias) . '.php'; + + if (is_file($path)) { + continue; + } + + $namespace = str_replace('/', '\\', dirname(str_replace('\\', '/', $alias))); + $class = class_basename($alias); + $target = substr($alias, strlen('Facades\\')); + + $stub = <<