Skip to content

Commit

Permalink
Adds the ability to fake registered checks.
Browse files Browse the repository at this point in the history
  • Loading branch information
lukeraymonddowning committed Nov 17, 2022
1 parent a258670 commit d45d9c3
Show file tree
Hide file tree
Showing 5 changed files with 188 additions and 0 deletions.
24 changes: 24 additions & 0 deletions src/Facades/Health.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,37 @@

namespace Spatie\Health\Facades;

use Closure;
use Illuminate\Support\Facades\Facade;
use Spatie\Health\Checks\Check;
use Spatie\Health\Checks\Result;
use Spatie\Health\Testing\FakeHealth;
use Spatie\Health\Testing\FakeValues;

/**
* @see \Spatie\Health\Health
*/
class Health extends Facade
{
/**
* @param array<class-string<Check>, Result|FakeValues|(Closure(Check): Result|FakeValues)> $checks
*/
public static function fake(array $checks): FakeHealth
{
$fake = (new FakeHealth(static::getFacadeRoot(), $checks));

static::swap($fake);
static::swapAlias($fake);

return $fake;
}

protected static function swapAlias(FakeHealth $fakeHealth): void
{
static::$resolvedInstance[\Spatie\Health\Health::class] = $fakeHealth;
static::$app->instance(\Spatie\Health\Health::class, $fakeHealth);
}

protected static function getFacadeAccessor()
{
return 'health';
Expand Down
45 changes: 45 additions & 0 deletions src/Testing/FakeCheck.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
<?php

namespace Spatie\Health\Testing;

use Spatie\Health\Checks\Check;
use Spatie\Health\Checks\Result;

class FakeCheck extends Check
{
private Check $fakedCheck;
private FakeValues $fakeValues;

public static function result(Result $result, bool $shouldRun = null): FakeValues
{
return new FakeValues($result, $shouldRun);
}

public function fake(Check $fakedCheck, FakeValues $values): self
{
$this->fakedCheck = $fakedCheck;
$this->fakeValues = $values;

$this->name($fakedCheck->getName());
$this->label($fakedCheck->getLabel());

return $this;
}

public function shouldRun(): bool
{
return $this->fakeValues->shouldRun() === null
? $this->fakedCheck->shouldRun()
: $this->fakeValues->shouldRun();
}

public function onTerminate(mixed $request, mixed $response): void
{
$this->fakedCheck->onTerminate($request, $response);
}

public function run(): Result
{
return $this->fakeValues->getResult();
}
}
39 changes: 39 additions & 0 deletions src/Testing/FakeHealth.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
<?php

namespace Spatie\Health\Testing;

use Closure;
use Illuminate\Support\Collection;
use Spatie\Health\Checks\Check;
use Spatie\Health\Checks\Result;
use Spatie\Health\Health;

class FakeHealth extends Health
{
/**
* @param array<class-string<Check>, Result|FakeValues|(Closure(Check): Result|FakeValues)> $fakeChecks
*/
public function __construct(private Health $decoratedHealth, private array $fakeChecks)
{
}

public function registeredChecks(): Collection
{
return $this->decoratedHealth->registeredChecks()->map(
fn(Check $check) => array_key_exists($check::class, $this->fakeChecks)
? $this->buildFakeCheck($check, $this->fakeChecks[$check::class])
: $check
);
}

/**
* @param Result|FakeValues|(Closure(Check): Result|FakeValues) $result
*/
protected function buildFakeCheck(Check $decoratedCheck, Result|FakeValues|Closure $result): FakeCheck
{
// @phpstan-ignore-next-line
$result = FakeValues::from(value($result, $decoratedCheck));

return FakeCheck::new()->fake($decoratedCheck, $result);
}
}
34 changes: 34 additions & 0 deletions src/Testing/FakeValues.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
<?php

namespace Spatie\Health\Testing;

use Spatie\Health\Checks\Result;

class FakeValues
{
public function __construct(
private Result $result,
private ?bool $shouldRun = null,
)
{
}

public static function from(Result|self $values): self
{
if ($values instanceof Result) {
return new self($values);
}

return $values;
}

public function getResult(): Result
{
return $this->result;
}

public function shouldRun(): ?bool
{
return $this->shouldRun;
}
}
46 changes: 46 additions & 0 deletions tests/HealthTest.php
Original file line number Diff line number Diff line change
@@ -1,10 +1,14 @@
<?php

use Spatie\Health\Checks\Checks\DatabaseCheck;
use Spatie\Health\Checks\Checks\PingCheck;
use Spatie\Health\Checks\Checks\UsedDiskSpaceCheck;
use Spatie\Health\Checks\Result;
use Spatie\Health\Enums\Status;
use Spatie\Health\Exceptions\DuplicateCheckNamesFound;
use Spatie\Health\Exceptions\InvalidCheck;
use Spatie\Health\Facades\Health;
use Spatie\Health\Testing\FakeCheck;

it('can register checks', function () {
Health::checks([
Expand Down Expand Up @@ -44,3 +48,45 @@
PingCheck::class,
]);
})->throws(InvalidCheck::class);

it('can fake checks', function () {
Health::checks([
DatabaseCheck::new(),
PingCheck::new(),
]);

Health::fake([
DatabaseCheck::class => new Result(
Status::crashed(),
"We're just making sure faking works",
"Hey, faking works!",
),
PingCheck::class => FakeCheck::result(
new Result(Status::warning()),
true
),
]);

$this->artisan('health:check')
->expectsOutputToContain(ucfirst((string) Status::crashed()->value))
->expectsOutputToContain(ucfirst((string) Status::warning()->value));
});

it('can pass a closure to fake checks', function () {
Health::checks([
DatabaseCheck::new()->name('MySQL')->connectionName('mysql'),
DatabaseCheck::new()->name('DB SQLite')->connectionName('sqlite'),
]);

Health::fake([
DatabaseCheck::class => function (DatabaseCheck $check) {
return $check->getName() === 'MySQL'
? new Result(Status::crashed())
: new Result(Status::warning());
}
]);

$this->artisan('health:check')
->expectsOutputToContain(ucfirst((string) Status::crashed()->value))
->expectsOutputToContain(ucfirst((string) Status::warning()->value));
});

0 comments on commit d45d9c3

Please sign in to comment.