Testovanie
Sentinel::fake() vymení manažéra — vo fasáde aj v kontajneri, takže sa podvrhne aj injektovaný SentinelManager — za nahrávací fake, ktorý nepotrebuje kľúče a nezapisuje pečate ani záznamy denníka:
use RoundlyConsulting\Sentinel\Enums\VerificationStatus;
use RoundlyConsulting\Sentinel\Facades\Sentinel;
$fake = Sentinel::fake();
$fake->fakeStatus($invoice, VerificationStatus::Tampered, 'financial', changed: ['a:amount']);
$this->get("/invoices/{$invoice->id}")->assertStatus(409);
Sentinel::assertVerified($invoice);
Sentinel::assertNothingAcknowledged();
$fake->fakeLedgerFindings(new LedgerFinding(LedgerFindingKind::ChainBroken, 3, 17, Invoice::class, 1, 'financial', 'previous digest', 'mysql'));
$this->artisan('sentinel:verify --ledger --allow-empty')->assertExitCode(1);Produkčná sémantika, ktorú zachováva
- Definície kompiluje skutočný register: neznáma pečať, model bez pečatí alebo neplatná definícia vyhodí výnimku presne ako v produkcii.
- Politika zápisu do zmeneného modelu platí aj pre naskriptované stavy: pri refuse vyhodí Eloquent aktualizácia modelu podvrhnutého ako zmenený TamperedModelException.
- Dôvody, aktéri, politika potvrdenia aj sealing.allow_suspension sa vynucujú s tými istými výnimkami.
- Idempotencia (aj middleware jobov) a nonce bežia na skutočnom stavovom automate nad úložiskami v pamäti: prehratie, 409, 422, jediné spotrebovanie.
- sentinel.signed a verify() vrátia syntetický VerifiedSignature (id kľúča fake), pokiaľ ho nenaskriptujete; odchádzajúce sign() požiadavku zaznamená a vráti nepodpísanú.
- Importy kľúčov sa overia a rozparsujú ako v produkcii; výsledkom sú syntetické KeyInfo a nič sa neuloží.
- Skeny rešpektujú where a progress a fakeLedgerFindings() riadi verifyLedger() so skutočnou sémantikou LedgerReport, takže sentinel:verify --ledger pri naskriptovanom porušení skončí kódom 1.
- Zaznamená každé volanie, aj cez HasSeals, handly a pod-prístupy — a nespustí žiadne udalosti.
Ovládanie
Predvolené overenie je Intact. Každé ovládanie vracia fake, takže sa dajú reťaziť, a ovládanie aj asercie sa dajú volať aj staticky na fasáde:
| Ovládanie | Účinok |
|---|---|
fakeStatus(Model $model, VerificationStatus $status, ?string $seal = null, ?array $changed = null, ?string $reason = null) | Každé overenie modelu (jednej pečate alebo všetkých) vráti tento stav, kým ho nezmeníte — alebo kým fake pečať znovu nezapečatí či nepotvrdí. Missing má predvolene seal_deleted (ktoré seal() odmietne); pre nikdy nezapečatený riadok nastavte never_sealed. |
fakeStatusOnce(...) | Len najbližšie overenie. |
fakeVerifiedSignature(?VerifiedSignature $signature = null) | Čo vráti overenie podpisu. |
rejectSignatures(SignatureRejection $reason) | Každé overenie podpisu sa odmietne (401). |
fakeLedgerFindings(LedgerFinding ...$findings) | Každé overenie denníka hlási tieto zistenia, kým metódu nezavoláte znova — bez argumentov pre čistý denník. |
recorded(?string $method = null) | list<RecordedCall> (method, arguments, result). |
use RoundlyConsulting\Sentinel\DataTransferObjects\LedgerFinding;
use RoundlyConsulting\Sentinel\DataTransferObjects\VerifiedSignature;
use RoundlyConsulting\Sentinel\Enums\{Algorithm, LedgerFindingKind, SignatureRejection};
$fake->fakeStatusOnce($invoice, VerificationStatus::Stale, 'financial'); // the next verification only
$fake->fakeVerifiedSignature(new VerifiedSignature('sig1', 'http', 'acme-2026-10', Algorithm::Ed25519, time(), null, 'n-1', null, ['@method'], 'partner', 7));
$fake->rejectSignatures(SignatureRejection::Replayed); // sentinel.signed answers 401
$fake->fakeLedgerFindings(new LedgerFinding(LedgerFindingKind::AnchorAhead, 12, null, null, null, null, 'anchor seq 14 > 12', 'mysql'));
$fake->fakeLedgerFindings(); // a clean ledger again
foreach ($fake->recorded('acknowledge') as $call) {
$call->method; // 'acknowledge'
$call->arguments; // the request DTO, or the list of scalar arguments
$call->result; // what the fake returned
}Asercie
Tridsaťšesť asercií, každá prechádza a zlyháva ako v PHPUnite — neúspešná vyhodí ExpectationFailedException:
| Oblasť | Asercie |
|---|---|
| Pečate | assertSealed, assertNotSealed, assertNothingSealed, assertVerified, assertNotVerified, assertNothingVerified, assertAcknowledged, assertNotAcknowledged, assertNothingAcknowledged, assertUnsealed, assertNothingUnsealed, assertSealingSuspended, assertSealingNotSuspended |
| Hromadné operácie a denník | assertScanned, assertResealed, assertNothingResealed, assertCheckpointed, assertLedgerVerified |
| Kľúče | assertKeyGenerated, assertKeyImported, assertKeyRotated, assertKeyRevoked, assertKeyRetired, assertNoKeyChanges |
| Idempotencia a nonce | assertIdempotentRun, assertNoIdempotentRuns, assertIdempotencyKeyForgotten, assertNonceIssued, assertNoNoncesIssued, assertNonceConsumed, assertNonceNotConsumed, assertSingleUseUrlIssued, assertPruned |
| Podpisy | assertRequestSigned, assertNothingSigned, assertSignatureVerified |
$fake = Sentinel::fake();
$invoice->update(['amount' => '12.00']); // through the model trait
$fake->assertSealed($invoice, 'financial', fn (SealResult $seal) => $seal->event === SealEvent::Resealed);
Sentinel::idempotency()->run('charge:42', 'billing', fn () => ['ok' => true]);
Sentinel::idempotency()->run('charge:42', 'billing', fn () => ['ok' => true]);
$fake->assertIdempotentRun('charge:42', replayed: true);
Http::fake();
Http::withSignature('acme-2026-10')->post('https://partner.example/events', []);
$fake->assertRequestSigned('acme-2026-10');Skutočné pečate v testoch
Factory zapečatiteľného modelu potrebuje podpisový kľúč a testovacie prostredie ho zvyčajne nemá — prvé create() vyhodí NoSigningKeyException, ktorej správa odkáže sem. Pridajte do testovacej triedy WithSentinelKeys: pred každým testom dostane každý kruh z konfigurácie bez kľúča nový dočasný kľúč HMAC-SHA-256 (kid test-<ring>, len v pamäti procesu — nič sa nezapíše do .env ani do databázy):
use RoundlyConsulting\Sentinel\Testing\WithSentinelKeys;
uses(TestCase::class, RefreshDatabase::class, WithSentinelKeys::class)->in('Feature');SentinelTestKeys::install(app(), Algorithm::Ed25519, rings: ['http']) urobí to isté na požiadanie — s iným algoritmom alebo pre databázový kruh (zreťazený za kľúčom z konfigurácie). Kruh, ktorý už nakonfigurovaný kľúč má, ostane nedotknutý.
Úložiská v pamäti
Fake drží idempotenčné kľúče a nonce vo vlastných InMemoryIdempotencyStore / InMemoryNonceStore — jeden na fake, takže medzi testami nič nepresiakne. Ak chcete spustiť skutočného manažéra bez tabuliek, naviažte jedno z nich samostatne:
use RoundlyConsulting\Sentinel\Contracts\IdempotencyStore;
use RoundlyConsulting\Sentinel\Testing\InMemoryIdempotencyStore;
$this->app->instance(IdempotencyStore::class, new InMemoryIdempotencyStore);Prejavte lásku k open source
Tento balík je zadarmo pod licenciou MIT. Ak vám šetrí čas, jednorazový príspevok alebo členstvo na Patreone nám pomôže ho ďalej udržiavať, testovať a dokumentovať.
Ďalšie spôsoby podpory vrátane kryptomienOdoslaním daru súhlasíte s našimi podmienkami prijímania darov.
Chcete to zabudovať do svojho produktu?
Naše balíky integrujeme do zákazkových Laravel a AI riešení. Napíšte nám, na čom pracujete, a ozveme sa do 48 hodín.