From e439f32927636c1e47f0d6ddd21540d0acc7d262 Mon Sep 17 00:00:00 2001 From: Richan Fongdasen Date: Tue, 16 Apr 2024 18:03:59 +0700 Subject: [PATCH] Add error handling in sync command --- config/turso-laravel.php | 1 + src/Commands/TursoSyncCommand.php | 19 +++++++++++++++---- tests/Unit/TursoManagerTest.php | 14 ++++++++++---- tests/Unit/TursoSyncCommandTest.php | 23 ++++++++++++++++++----- 4 files changed, 44 insertions(+), 13 deletions(-) diff --git a/config/turso-laravel.php b/config/turso-laravel.php index bd8f814..006f8ac 100644 --- a/config/turso-laravel.php +++ b/config/turso-laravel.php @@ -3,6 +3,7 @@ // config for RichanFongdasen/TursoLaravel return [ 'sync_command' => [ + 'node_path' => env('NODE_PATH'), // Full path to the node executable. E.g: /usr/bin/node 'script_filename' => 'turso-sync.mjs', 'script_path' => realpath(__DIR__ . '/..'), 'timeout' => 60, diff --git a/src/Commands/TursoSyncCommand.php b/src/Commands/TursoSyncCommand.php index 024a09d..740a911 100644 --- a/src/Commands/TursoSyncCommand.php +++ b/src/Commands/TursoSyncCommand.php @@ -6,6 +6,7 @@ use Illuminate\Console\Command; use Illuminate\Support\Facades\Process; +use RuntimeException; class TursoSyncCommand extends Command { @@ -16,7 +17,8 @@ class TursoSyncCommand extends Command protected function compileRunProcess(): string { return sprintf( - 'node %s "%s" "%s" "%s"', + '%s %s "%s" "%s" "%s"', + $this->getNodePath(), config('turso-laravel.sync_command.script_filename'), config('database.connections.turso.db_url'), config('database.connections.turso.access_token'), @@ -24,6 +26,17 @@ protected function compileRunProcess(): string ); } + protected function getNodePath(): string + { + $nodePath = config('turso-laravel.sync_command.node_path') ?? trim((string) Process::run('which node')->output()); + + if (($nodePath === '') || ! file_exists($nodePath)) { + throw new RuntimeException('Node executable not found.'); + } + + return $nodePath; + } + public function handle(): int { $timeout = (int) config('turso-laravel.sync_command.timeout'); @@ -33,9 +46,7 @@ public function handle(): int ->run($this->compileRunProcess()); if ($result->failed()) { - $this->error($result->errorOutput()); - - return self::FAILURE; + throw new RuntimeException('Turso sync command failed: ' . $result->errorOutput()); } $this->info($result->output()); diff --git a/tests/Unit/TursoManagerTest.php b/tests/Unit/TursoManagerTest.php index 186a7e5..f4043e5 100644 --- a/tests/Unit/TursoManagerTest.php +++ b/tests/Unit/TursoManagerTest.php @@ -51,14 +51,17 @@ test('it can trigger the sync command immediately', function () { Process::fake(); - config(['database.connections.turso.db_replica' => '/tmp/turso.sqlite']); + config([ + 'database.connections.turso.db_replica' => '/tmp/turso.sqlite', + 'turso-laravel.sync_command.node_path' => '/dev/null', + ]); Turso::sync(); Process::assertRan(function (PendingProcess $process) { $expectedPath = realpath(__DIR__ . '/../..'); - expect($process->command)->toBe('node turso-sync.mjs "http://127.0.0.1:8080" "your-access-token" "/tmp/turso.sqlite"') + expect($process->command)->toBe('/dev/null turso-sync.mjs "http://127.0.0.1:8080" "your-access-token" "/tmp/turso.sqlite"') ->and($process->timeout)->toBe(60) ->and($process->path)->toBe($expectedPath); @@ -79,14 +82,17 @@ test('it can run the sync background job and call the sync artisan command', function () { Process::fake(); - config(['database.connections.turso.db_replica' => '/tmp/turso.sqlite']); + config([ + 'database.connections.turso.db_replica' => '/tmp/turso.sqlite', + 'turso-laravel.sync_command.node_path' => '/dev/null', + ]); Turso::backgroundSync(); Process::assertRan(function (PendingProcess $process) { $expectedPath = realpath(__DIR__ . '/../..'); - expect($process->command)->toBe('node turso-sync.mjs "http://127.0.0.1:8080" "your-access-token" "/tmp/turso.sqlite"') + expect($process->command)->toBe('/dev/null turso-sync.mjs "http://127.0.0.1:8080" "your-access-token" "/tmp/turso.sqlite"') ->and($process->timeout)->toBe(60) ->and($process->path)->toBe($expectedPath); diff --git a/tests/Unit/TursoSyncCommandTest.php b/tests/Unit/TursoSyncCommandTest.php index 0ede505..9f132be 100644 --- a/tests/Unit/TursoSyncCommandTest.php +++ b/tests/Unit/TursoSyncCommandTest.php @@ -7,14 +7,17 @@ test('it can run the cli script to sync the database', function () { Process::fake(); - config(['database.connections.turso.db_replica' => '/tmp/turso.sqlite']); + config([ + 'database.connections.turso.db_replica' => '/tmp/turso.sqlite', + 'turso-laravel.sync_command.node_path' => '/dev/null', + ]); Artisan::call('turso:sync'); Process::assertRan(function (PendingProcess $process) { $expectedPath = realpath(__DIR__ . '/../..'); - expect($process->command)->toBe('node turso-sync.mjs "http://127.0.0.1:8080" "your-access-token" "/tmp/turso.sqlite"') + expect($process->command)->toBe('/dev/null turso-sync.mjs "http://127.0.0.1:8080" "your-access-token" "/tmp/turso.sqlite"') ->and($process->timeout)->toBe(60) ->and($process->path)->toBe($expectedPath); @@ -31,9 +34,19 @@ ), ]); - config(['database.connections.turso.db_replica' => '/tmp/turso.sqlite']); + config([ + 'database.connections.turso.db_replica' => '/tmp/turso.sqlite', + 'turso-laravel.sync_command.node_path' => '/dev/null', + ]); $result = Artisan::call('turso:sync'); +})->throws(RuntimeException::class)->group('TursoSyncCommandTest', 'UnitTest'); - expect($result)->toBe(1); -})->group('TursoSyncCommandTest', 'UnitTest'); +test('it raises exception on failing to find node executable file', function () { + config([ + 'database.connections.turso.db_replica' => '/tmp/turso.sqlite', + 'turso-laravel.sync_command.node_path' => '/usr/invalid/bin/node', + ]); + + $result = Artisan::call('turso:sync'); +})->throws(RuntimeException::class)->group('TursoSyncCommandTest', 'UnitTest');