Next healthcheck due date, plus a test suite (hc-nkq)
Lets a technician record when a site should next be looked at, and surfaces that in the dashboard so it can be used for planning. Server: - migration 0002 adds healthchecks.next_due, a VARCHAR(10) 'YYYY-MM-DD' calendar date rather than a timestamp — it's a diary date with no time-of-day, and a timestamp would render as the wrong day off-server. - Kept per-session rather than on a sites table, so the history of what was scheduled when is preserved. A site's current next-due is the value on its most recent session: if the latest visit scheduled nothing, the site reads as unscheduled rather than showing the just-completed visit as overdue. - Validate::optionalDate() round-trips through createFromFormat, which rejects both '2026-2-3' and '2026-02-30' (silently rolled to March 2nd). - next_due follows the same missing-vs-null PUT contract as finished_at, and lives in its own Store::setNextDue() so finishing or reopening a session never disturbs the date and vice versa. - Dashboard shows it on the site list, the per-site session table and the session detail, flagged overdue / today / soon (within a fortnight). Plugin: - Date control on both the active and finished panels — the moment you know when to return is often wrap-up, after the report is generated. - Write-through like every other mutation. Bad input is rejected with a notice rather than silently clearing an existing date. - Included in both the Markdown and HTML reports. Tests (new — tests/, export-ignored from the plugin zip): - Hand-rolled harness, no composer/PHPUnit, in keeping with the repo. - 42 tests: plugin-side date parsing units, plus server integration tests driven over real HTTP against a temp `php -S` instance with a throwaway SQLite DB, so a real server/config.php is never touched. - Mutation-checked: dropping the array_key_exists guard on PUT fails three tests, as intended.
This commit is contained in:
67
tests/run.php
Normal file
67
tests/run.php
Normal file
@@ -0,0 +1,67 @@
|
||||
<?php
|
||||
declare(strict_types=1);
|
||||
|
||||
/**
|
||||
* Test entry point.
|
||||
*
|
||||
* php tests/run.php # everything
|
||||
* php tests/run.php plugin # plugin unit tests only (runs on PHP 7.4+)
|
||||
* php tests/run.php server # server integration tests only (needs PHP 8.1+)
|
||||
*
|
||||
* Exits non-zero if anything fails, so it works as a pre-push gate.
|
||||
*/
|
||||
|
||||
$root = dirname(__DIR__);
|
||||
|
||||
require __DIR__ . '/lib/harness.php';
|
||||
require __DIR__ . '/lib/test-server.php';
|
||||
|
||||
$suite = $argv[1] ?? 'all';
|
||||
if (!in_array($suite, ['all', 'plugin', 'server'], true)) {
|
||||
fwrite(STDERR, "usage: php tests/run.php [all|plugin|server]\n");
|
||||
exit(2);
|
||||
}
|
||||
|
||||
if ($suite === 'all' || $suite === 'plugin') {
|
||||
require __DIR__ . '/plugin_test.php';
|
||||
}
|
||||
|
||||
if ($suite === 'all' || $suite === 'server') {
|
||||
if (!TestServer::sqliteAvailable()) {
|
||||
echo "\n\033[33mSKIPPED\033[0m server tests — this PHP build has no pdo_sqlite.\n"
|
||||
. " Install php-sqlite3 (or run the suite on a box that has it).\n";
|
||||
} elseif (PHP_VERSION_ID < 80100) {
|
||||
echo "\n\033[33mSKIPPED\033[0m server tests — the server needs PHP 8.1+, this is " . PHP_VERSION . ".\n";
|
||||
} else {
|
||||
$server = new TestServer($root);
|
||||
|
||||
// Shutdown hook as well as the finally below: a fatal error skips
|
||||
// finally, and an orphaned `php -S` would hold its port.
|
||||
register_shutdown_function(static function () use ($server) { $server->stop(); });
|
||||
|
||||
$server->start();
|
||||
$GLOBALS['att_hc_base_url'] = $server->baseUrl();
|
||||
$GLOBALS['att_hc_db_path'] = $server->dbPath();
|
||||
|
||||
try {
|
||||
require __DIR__ . '/server_test.php';
|
||||
} finally {
|
||||
// Only on failure, and only the interesting lines — the built-in
|
||||
// server logs two access lines per request, which buries anything real.
|
||||
if (count(TestRun::$failures) > 0) {
|
||||
$lines = array_filter(
|
||||
explode("\n", $server->log()),
|
||||
static function (string $l): bool {
|
||||
return trim($l) !== '' && strpos($l, 'Accepted') === false && strpos($l, 'Closing') === false;
|
||||
}
|
||||
);
|
||||
if ($lines) {
|
||||
echo "\n\033[33mtest server log:\033[0m\n" . implode("\n", array_slice($lines, -40)) . "\n";
|
||||
}
|
||||
}
|
||||
$server->stop();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
report_and_exit();
|
||||
Reference in New Issue
Block a user