From e0f92f09ad8a4c27206c3bc408ade622ab8cee78 Mon Sep 17 00:00:00 2001 From: Vitaly Iskrin Date: Wed, 5 Jun 2024 22:12:21 -0500 Subject: [PATCH] test: add new tests to cover code --- .gitignore | 1 + Tests/TelescopePruneTest.php | 73 +++++++++++- Tests/Traits/SqlMockTrait.php | 138 +++++++++++++++++++++++ src/Console/Commands/TelescopePrune.php | 15 +-- src/Repositories/TelescopeRepository.php | 15 ++- 5 files changed, 222 insertions(+), 20 deletions(-) diff --git a/.gitignore b/.gitignore index 63d6d20..6c68674 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,4 @@ .idea .phpunit.result.cache +.phpunit.cache vendor/ diff --git a/Tests/TelescopePruneTest.php b/Tests/TelescopePruneTest.php index d39a497..8a835fa 100644 --- a/Tests/TelescopePruneTest.php +++ b/Tests/TelescopePruneTest.php @@ -4,7 +4,6 @@ use Carbon\Carbon; use Illuminate\Support\Facades\Artisan; -use Laravel\Telescope\Storage\DatabaseEntriesRepository; use Orchestra\Testbench\TestCase; use RonasIT\TelescopeExtension\Repositories\TelescopeRepository; use RonasIT\TelescopeExtension\TelescopeExtensionServiceProvider; @@ -50,7 +49,6 @@ protected function getEnvironmentSetUp($app): void 'prefix' => '', ]); - //$app->when(DatabaseEntriesRepository::class) $app->when(TelescopeRepository::class) ->needs('$connection') ->give('testbench'); @@ -122,9 +120,74 @@ public function testPruneWithSeveralSetHoursAndHours() ->assertExitCode(0); } - /*public function testPruneRequestsAndOthers() + + public function testPruneWithUnresolvedException() + { + $this->mockQueriesWithUnresolvedException(); + + $this->artisan('telescope:prune --set-hours=request:5,unresolved_exception:20,query:25 --hours=80') + ->expectsOutput("Pruning records of type 'request' older than 5 hours...") + ->expectsOutput('Deleted 200 records.') + ->expectsOutput("Pruning records of type 'unresolved_exception' older than 20 hours...") + ->expectsOutput('Deleted 32 records.') + ->expectsOutput("Pruning records of type 'query' older than 25 hours...") + ->expectsOutput('Deleted 50 records.') + ->expectsOutput('Pruning records of other types older than 80 hours...') + ->expectsOutput('Deleted 200 records.') + ->assertExitCode(0); + } + + public function testPruneWithResolvedExceptionWithoutHours() + { + $this->mockQueriesWithResolvedExceptionWithoutHours(); + + $this->artisan('telescope:prune --set-hours=request:5,resolved_exception:10,query:25') + ->expectsOutput("Pruning records of type 'request' older than 5 hours...") + ->expectsOutput('Deleted 200 records.') + ->expectsOutput("Pruning records of type 'resolved_exception' older than 10 hours...") + ->expectsOutput('Deleted 15 records.') + ->expectsOutput("Pruning records of type 'query' older than 25 hours...") + ->expectsOutput('Deleted 50 records.') + ->assertExitCode(0); + } + + public function testPruneValidateSetHoursType() + { + $this->expectException('Exception'); + $this->expectExceptionMessage("Incorrect type value 'incorrect'."); + + $this->artisan('telescope:prune --set-hours=query:12,incorrect:22'); + } + + public function testPruneValidateSetHoursValueNotSet() + { + $this->expectException('Exception'); + $this->expectExceptionMessage("Incorrect value 'request' of the 'set-hours' option."); + + $this->artisan('telescope:prune --set-hours=query:12,request'); + } + + public function testPruneValidateSetHoursValueEmpty() { - Artisan::call('telescope:prune --set-hours=requests:6 --hours=2'); + $this->expectException('Exception'); + $this->expectExceptionMessage("Hours value for 'request' type must be set."); - }*/ + $this->artisan('telescope:prune --set-hours=query:12,request:'); + } + + public function testPruneValidateSetHoursValueIsNotNumber() + { + $this->expectException('Exception'); + $this->expectExceptionMessage("Hours value for 'request' type must be a number."); + + $this->artisan('telescope:prune --set-hours=query:12,request:ss'); + } + + public function testPruneValidateHoursValueIsNotNumber() + { + $this->expectException('Exception'); + $this->expectExceptionMessage('Hours hours must be a number.'); + + $this->artisan('telescope:prune --set-hours=query:12,request:34 --hours=ss'); + } } diff --git a/Tests/Traits/SqlMockTrait.php b/Tests/Traits/SqlMockTrait.php index 15b66c5..4112e00 100644 --- a/Tests/Traits/SqlMockTrait.php +++ b/Tests/Traits/SqlMockTrait.php @@ -6,6 +6,7 @@ use Laravel\Telescope\EntryType; use Mpyw\LaravelDatabaseMock\Facades\DBMock; use Mpyw\LaravelDatabaseMock\Proxies\SingleConnectionProxy; +use RonasIT\TelescopeExtension\Console\Commands\TelescopePrune; trait SqlMockTrait { @@ -188,6 +189,143 @@ protected function mockQueriesWithSeveralSetHoursAndHours(): void ); } + protected function mockQueriesWithUnresolvedException(): void + { + $this->mockDelete( + 'delete from "telescope_entries" where "rowid" in (select "telescope_entries"."rowid" ' + . 'from "telescope_entries" where "created_at" < ? and ("type" = ?) limit 1000)', + [Carbon::now()->subHours(5)->toDateTimeString(), EntryType::REQUEST], + 200 + ); + + $this->mockDelete( + 'delete from "telescope_entries" where "rowid" in (select "telescope_entries"."rowid" ' + . 'from "telescope_entries" where "created_at" < ? and ("type" = ?) limit 1000)', + [Carbon::now()->subHours(5)->toDateTimeString(), EntryType::REQUEST] + ); + + $this->mockDelete( + 'delete from "telescope_entries" where "rowid" in (select "telescope_entries"."rowid" ' + . 'from "telescope_entries" where "created_at" < ? and (("type" = ? ' + . 'and content::jsonb->>\'resolved_at\' is null)) limit 1000)', + [Carbon::now()->subHours(20)->toDateTimeString(), EntryType::EXCEPTION], + 32 + ); + + $this->mockDelete( + 'delete from "telescope_entries" where "rowid" in (select "telescope_entries"."rowid" ' + . 'from "telescope_entries" where "created_at" < ? and (("type" = ? ' + . 'and content::jsonb->>\'resolved_at\' is null)) limit 1000)', + [Carbon::now()->subHours(20)->toDateTimeString(), EntryType::EXCEPTION] + ); + + $this->mockDelete( + 'delete from "telescope_entries" where "rowid" in (select "telescope_entries"."rowid" ' + . 'from "telescope_entries" where "created_at" < ? and ("type" = ?) limit 1000)', + [Carbon::now()->subHours(25)->toDateTimeString(), EntryType::QUERY], + 50 + ); + + $this->mockDelete( + 'delete from "telescope_entries" where "rowid" in (select "telescope_entries"."rowid" ' + . 'from "telescope_entries" where "created_at" < ? and ("type" = ?) limit 1000)', + [Carbon::now()->subHours(25)->toDateTimeString(), EntryType::QUERY] + ); + + $this->mockDelete( + 'delete from "telescope_entries" where "rowid" in (select "telescope_entries"."rowid" ' + . 'from "telescope_entries" where "created_at" < ? and ("type" = ? or "type" = ? or ' + . '"type" = ? or "type" = ? or "type" = ? or "type" = ? or "type" = ? or "type" = ? or ' + . '"type" = ? or "type" = ? or "type" = ? or "type" = ? or "type" = ? or ("type" = ? and content::jsonb->>\'resolved_at\' is not null)) limit 1000)', + [ + Carbon::now()->subHours(80)->toDateTimeString(), + EntryType::BATCH, + EntryType::CACHE, + EntryType::DUMP, + EntryType::EVENT, + EntryType::JOB, + EntryType::LOG, + EntryType::MAIL, + EntryType::MODEL, + EntryType::NOTIFICATION, + EntryType::REDIS, + EntryType::SCHEDULED_TASK, + EntryType::GATE, + EntryType::VIEW, + EntryType::EXCEPTION + ], + 200 + ); + + $this->mockDelete( + 'delete from "telescope_entries" where "rowid" in (select "telescope_entries"."rowid" ' + . 'from "telescope_entries" where "created_at" < ? and ("type" = ? or "type" = ? or ' + . '"type" = ? or "type" = ? or "type" = ? or "type" = ? or "type" = ? or "type" = ? or ' + . '"type" = ? or "type" = ? or "type" = ? or "type" = ? or "type" = ? or ("type" = ? and content::jsonb->>\'resolved_at\' is not null)) limit 1000)', + [ + Carbon::now()->subHours(80)->toDateTimeString(), + EntryType::BATCH, + EntryType::CACHE, + EntryType::DUMP, + EntryType::EVENT, + EntryType::JOB, + EntryType::LOG, + EntryType::MAIL, + EntryType::MODEL, + EntryType::NOTIFICATION, + EntryType::REDIS, + EntryType::SCHEDULED_TASK, + EntryType::GATE, + EntryType::VIEW, + EntryType::EXCEPTION + ] + ); + } + + protected function mockQueriesWithResolvedExceptionWithoutHours(): void + { + $this->mockDelete( + 'delete from "telescope_entries" where "rowid" in (select "telescope_entries"."rowid" ' + . 'from "telescope_entries" where "created_at" < ? and ("type" = ?) limit 1000)', + [Carbon::now()->subHours(5)->toDateTimeString(), EntryType::REQUEST], + 200 + ); + + $this->mockDelete( + 'delete from "telescope_entries" where "rowid" in (select "telescope_entries"."rowid" ' + . 'from "telescope_entries" where "created_at" < ? and ("type" = ?) limit 1000)', + [Carbon::now()->subHours(5)->toDateTimeString(), EntryType::REQUEST] + ); + + $this->mockDelete( + 'delete from "telescope_entries" where "rowid" in (select "telescope_entries"."rowid" ' + . 'from "telescope_entries" where "created_at" < ? and (("type" = ? ' + . 'and content::jsonb->>\'resolved_at\' is not null)) limit 1000)', + [Carbon::now()->subHours(10)->toDateTimeString(), EntryType::EXCEPTION], + 15 + ); + + $this->mockDelete( + 'delete from "telescope_entries" where "rowid" in (select "telescope_entries"."rowid" ' + . 'from "telescope_entries" where "created_at" < ? and (("type" = ? ' + . 'and content::jsonb->>\'resolved_at\' is not null)) limit 1000)', + [Carbon::now()->subHours(10)->toDateTimeString(), EntryType::EXCEPTION] + ); + + $this->mockDelete( + 'delete from "telescope_entries" where "rowid" in (select "telescope_entries"."rowid" ' + . 'from "telescope_entries" where "created_at" < ? and ("type" = ?) limit 1000)', + [Carbon::now()->subHours(25)->toDateTimeString(), EntryType::QUERY], + 50 + ); + + $this->mockDelete( + 'delete from "telescope_entries" where "rowid" in (select "telescope_entries"."rowid" ' + . 'from "telescope_entries" where "created_at" < ? and ("type" = ?) limit 1000)', + [Carbon::now()->subHours(25)->toDateTimeString(), EntryType::QUERY] + ); + } + protected function mockDelete(string $sql, array $bindings = [], ?int $rowCount = 0): void { $this->getPdo()->shouldDeleteForRows($sql, $bindings, $rowCount); diff --git a/src/Console/Commands/TelescopePrune.php b/src/Console/Commands/TelescopePrune.php index 6b7f830..7453b62 100644 --- a/src/Console/Commands/TelescopePrune.php +++ b/src/Console/Commands/TelescopePrune.php @@ -7,7 +7,6 @@ use Illuminate\Console\Command; use Laravel\Telescope\EntryType; use Exception; -use Throwable; class TelescopePrune extends Command { @@ -57,14 +56,10 @@ public function handle(): void { $this->defaultExpirationHours = 0; - //try { - $this->validateSetHoursOption(); - $this->validateHoursOption(); - $this->pruneSetHours(); - $this->pruneHours(); - //} catch (Throwable $exception) { - // $this->error($exception->getMessage()); - //} + $this->validateSetHoursOption(); + $this->validateHoursOption(); + $this->pruneSetHours(); + $this->pruneHours(); } protected function validateSetHoursOption(): void @@ -160,7 +155,7 @@ protected function filterTypes(): array in_array(self::UNRESOLVED_EXCEPTION, $excludeTypes) || in_array(self::RESOLVED_EXCEPTION, $excludeTypes) ) { - $types = array_diff($types, EntryType::EXCEPTION); + $types = array_diff($types, [EntryType::EXCEPTION]); if (!in_array(self::EXCEPTION_TYPES, $excludeTypes)) { $types = [ diff --git a/src/Repositories/TelescopeRepository.php b/src/Repositories/TelescopeRepository.php index 088ca54..3fd0cac 100644 --- a/src/Repositories/TelescopeRepository.php +++ b/src/Repositories/TelescopeRepository.php @@ -4,6 +4,7 @@ use DateTimeInterface; use Illuminate\Database\Query\Builder; +use Laravel\Telescope\EntryType; use Laravel\Telescope\Storage\DatabaseEntriesRepository; use RonasIT\TelescopeExtension\Console\Commands\TelescopePrune; @@ -19,11 +20,15 @@ public function prune(DateTimeInterface $before): int ->where(function(Builder $subQuery) { foreach ($this->pruneTypes as $type) { if (in_array($type, TelescopePrune::EXCEPTION_TYPES)) { - $subQuery->orWhereRaw( - ($type === TelescopePrune::UNRESOLVED_EXCEPTION) - ? "content::jsonb->>'resolved_at' is null" - : "content::jsonb->>'resolved_at' is not null" - ); + $subQuery->orWhere(function ($subSubQuery) use ($type) { + $subSubQuery + ->where('type', EntryType::EXCEPTION) + ->whereRaw( + ($type === TelescopePrune::UNRESOLVED_EXCEPTION) + ? "content::jsonb->>'resolved_at' is null" + : "content::jsonb->>'resolved_at' is not null" + ); + }); } else { $subQuery->orWhere('type', $type); }