45 lines
1.9 KiB
PHP
45 lines
1.9 KiB
PHP
<?php
|
|
require __DIR__ . '/HomeNewsCache.php';
|
|
$directory = $argv[1];
|
|
if (!is_dir($directory)) {
|
|
mkdir($directory, 0700, true);
|
|
}
|
|
$file = $directory . '/news-list-v1.json';
|
|
$calls = 0;
|
|
$loader = function () use (&$calls) {
|
|
$calls++;
|
|
return array(array('news_id' => $calls, 'news_name' => 'Public article'));
|
|
};
|
|
function expect_cache($condition, $message)
|
|
{
|
|
if (!$condition) {
|
|
throw new Exception($message);
|
|
}
|
|
}
|
|
$first = txiaw_home_news_cached($directory, $loader);
|
|
$second = txiaw_home_news_cached($directory, $loader);
|
|
expect_cache($first === $second && $calls === 1, 'Fresh cache must avoid a second query');
|
|
|
|
file_put_contents($file, json_encode(array('created' => time() - 61, 'items' => $first)));
|
|
$third = txiaw_home_news_cached($directory, $loader);
|
|
expect_cache($calls === 2 && $third[0]['news_id'] === 2, 'Expired cache must refresh');
|
|
|
|
file_put_contents($file, json_encode(array('created' => time() - 61, 'items' => $third)));
|
|
$held = fopen($directory . '/news-list-v1.lock', 'c');
|
|
flock($held, LOCK_EX);
|
|
$started = microtime(true);
|
|
$stale = txiaw_home_news_cached($directory, $loader);
|
|
expect_cache($stale === $third && $calls === 2, 'Busy refresher must serve existing stale data');
|
|
expect_cache(microtime(true) - $started < 0.1, 'Stale read must not wait for the lock');
|
|
flock($held, LOCK_UN);
|
|
fclose($held);
|
|
|
|
$failedLoader = function () { throw new Exception('Simulated database failure'); };
|
|
expect_cache(txiaw_home_news_cached($directory, $failedLoader) === $third, 'Recent stale cache should survive a transient database failure');
|
|
|
|
file_put_contents($file, '{corrupt');
|
|
$recovered = txiaw_home_news_cached($directory, $loader);
|
|
expect_cache($calls === 3 && $recovered[0]['news_id'] === 3, 'Corrupt cache must recover');
|
|
expect_cache(txiaw_read_home_news_cache($file) !== false, 'Recovery must write a valid cache');
|
|
echo "PASS: cache hit, TTL refresh, nonblocking stale read, transient error fallback, corrupt cache recovery.\n";
|