Testing your integration¶
Replace the transport and the logger in the test container and read what left:
use IndexNowKit\Http\TransportInterface;
use IndexNowKit\Testing\{ArrayLogger, FakeTransport};
use IndexNowKit\Yii3\IndexNow;
use Psr\Log\LoggerInterface;
$transport = new FakeTransport();
$logger = new ArrayLogger();
$container = new Container(ContainerConfig::create()->withDefinitions([
...$config->get('di'), // the application's definitions, the package's included
TransportInterface::class => $transport,
LoggerInterface::class => $logger,
]));
// run the bootstrap group the way the runner does: ObserverProvider::set() lives there
foreach ($config->get('bootstrap') as $callback) { $callback($container); }
$post = new Post();
$post->slug = 'hello';
$post->save();
$container->get(IndexNow::class)->flush(); // in a request this happens after the response is sent
$transport->posts[0]['body']['urlList']; // ['https://www.example.com/posts/hello']
$logger->messages('error'); // []
FakeTransport::willRespond(new Response(429)) and onGet($url, new Response(200, $key)) script the engines and the
key file; ArrayLogger::messages($level) returns interpolated lines. Put 'dry_run' => false in the test params:
YII_ENV of a test run is not production, and without a key dry_run switches on.
The package's own suite (tests/) runs the core conformance kits (OrmConformanceTestCase, CoreConformanceTestCase)
through a container built from the package's config/*.php; Yii3TestCase and Support\Fixtures are a template
for an application test case: Fixtures::container() builds the container (sqlite in memory, the routes, the PSR-14
dispatcher from events-web.php), Fixtures::destroy() resets ObserverProvider, EventDispatcherProvider and
ConnectionProvider between tests — three static providers of the process.
Several containers in one process¶
ObserverProvider and EventDispatcherProvider of yiisoft/active-record are process-wide, so a test suite (or a
per-request container in a worker) that builds a second container hands the same classes a second observer. Two
things keep that honest, and both are automatic:
IndexNow::observe()and theactive_record.modelslist replace the observed dispatcher of a class instead of wrapping another one around it, so a class is never observed twice and the old container is not held alive by the static provider.ObserverProvider::reset()(test support,@internal) gives every class its own dispatcher back before it drops the observer. Call it between tests —Fixtures::destroy()does.
Without the reset, the classes of the previous test keep pointing at the previous container's observer, and a save in the next test submits through a graph whose transport you already stopped looking at.
Without HTTP at all¶
$container->get(IndexNow::class)->urlsFor($post) (or explain($post)) returns the URLs a record would announce,
with the rule that produced each — the assertion for a rule test that should not build a transport.
Transactions and verify-on-commit¶
Inside $db->transaction() (or an explicit beginTransaction()), URLs are held with a verifier and re-read by
primary key at the next flush after the transaction ended; a rollback leaves no row and drops them. In a test:
$tx = $db->beginTransaction();
$post = new Post();
$post->slug = 'held';
$post->save();
$indexNow->flush();
self::assertSame([], $transport->posts); // nothing until the commit (a warning says the URLs wait)
$tx->commit();
$indexNow->flush();
self::assertCount(1, $transport->posts); // now it left
A test that wraps every case in a transaction it rolls back at the end therefore never sees a submission: assert on
urlsFor() there, or commit. Details: commit-safety.md.
The key file¶
Send a request through the router (Yiisoft\Router\Middleware\Router over the UrlMatcherInterface of the
container) and hand the response to Testing\Conformance\KeyFileAssertions — tests/Support/Web.php of the package
shows the ten lines.
Commands¶
new CommandTester($container->get(CheckCommand::class)) runs a command the way ./yii does; the package's
tests/Feature/CommandsTest.php covers every one.
dry_run¶
Outside production_environments a missing key enables dry_run: the whole pipeline runs — rules, guards, URL
generation, host and key selection — and the request is logged (ArrayLogger::messages('info') contains the body)
instead of sent. Set dry_run: false for a test that must reach the transport.
Conformance¶
tests/Conformance/ runs the core kits against this package (CoreConformanceTestCase: C01–C22 through the
container; OrmConformanceTestCase: A01–A21 through #[IndexNowEvents]; the H01–H06 assertions KeyFileAssertions
/ CheckOutputAssertions through the key file handler and the commands). An application that replaces a piece
(UrlResolverInterface, DispatcherInterface) can extend the same abstract cases to prove nothing regressed.