- Implemented `adminDetail()` method in `BlogController` to retrieve blog posts of any status for admin editing. - Introduced `BlogCacheInvalidator` service to handle cache invalidation after blog create/update/delete actions. - Updated existing methods in `BlogController` and `RepresentationBlogController` to call cache invalidation on blog modifications. - Enhanced `BlogFormPage` and `RepresentationBlogFormPage` to utilize the new admin endpoint for fetching blog data. - Added tests for `BlogCacheInvalidator` to ensure proper functionality and error handling. - Updated documentation to reflect new API endpoint and cache invalidation behavior.
87 lines
3.2 KiB
PHP
87 lines
3.2 KiB
PHP
<?php
|
|
|
|
namespace App\Tests\Blog;
|
|
|
|
use App\Auth\Entity\User;
|
|
use App\Blog\Entity\Blog;
|
|
use App\Blog\Service\BlogCacheInvalidator;
|
|
use PHPUnit\Framework\TestCase;
|
|
use Psr\Log\NullLogger;
|
|
use Symfony\Component\HttpClient\MockHttpClient;
|
|
use Symfony\Component\HttpClient\Response\MockResponse;
|
|
use Symfony\Contracts\HttpClient\Exception\TransportExceptionInterface;
|
|
use Symfony\Contracts\HttpClient\HttpClientInterface;
|
|
|
|
/**
|
|
* باطلسازی کش ISR سایت عمومی پس از هر نوشتن روی بلاگ.
|
|
* fail-open است: شکست شبکه نباید ذخیرهٔ مقاله را بشکند.
|
|
*/
|
|
class BlogCacheInvalidatorTest extends TestCase
|
|
{
|
|
private function makeBlog(): Blog
|
|
{
|
|
return new Blog(new User('09120000000'), 'عنوان آزمایشی', 'متن آزمایشی مقاله');
|
|
}
|
|
|
|
/** @param list<array{0:string,1:string,2:array}> $calls */
|
|
private function recordingClient(array &$calls, int $status = 200): HttpClientInterface
|
|
{
|
|
return new MockHttpClient(function (string $method, string $url, array $options) use (&$calls, $status) {
|
|
$calls[] = [$method, $url, $options];
|
|
|
|
return new MockResponse('{"revalidated":true}', ['http_code' => $status]);
|
|
});
|
|
}
|
|
|
|
public function testSendsTagsForSlugUuidAndList(): void
|
|
{
|
|
$calls = [];
|
|
$blog = $this->makeBlog();
|
|
|
|
(new BlogCacheInvalidator(
|
|
$this->recordingClient($calls),
|
|
new NullLogger(),
|
|
'https://nobat724.com/api/revalidate',
|
|
's3cret',
|
|
))->invalidate($blog);
|
|
|
|
self::assertCount(1, $calls);
|
|
[$method, $url, $options] = $calls[0];
|
|
self::assertSame('POST', $method);
|
|
self::assertSame('https://nobat724.com/api/revalidate', $url);
|
|
self::assertContains('X-Revalidate-Secret: s3cret', $options['headers']);
|
|
|
|
$body = json_decode($options['body'], true);
|
|
self::assertSame(
|
|
['blog-' . $blog->getSlug(), 'blog-' . $blog->getUuid(), 'blog-list'],
|
|
$body['tags']
|
|
);
|
|
}
|
|
|
|
public function testNetworkFailureIsSwallowed(): void
|
|
{
|
|
$client = new MockHttpClient(function (): MockResponse {
|
|
throw new class ('boom') extends \RuntimeException implements TransportExceptionInterface {};
|
|
});
|
|
|
|
$invalidator = new BlogCacheInvalidator($client, new NullLogger(), 'https://nobat724.com/api/revalidate', 's3cret');
|
|
|
|
$invalidator->invalidate($this->makeBlog());
|
|
self::assertTrue(true, 'شکست شبکه نباید exception بدهد');
|
|
}
|
|
|
|
public function testNoRequestWhenWebhookIsNotConfigured(): void
|
|
{
|
|
$calls = [];
|
|
|
|
// URL خالی — محیط dev/تست بدون سایت عمومی
|
|
(new BlogCacheInvalidator($this->recordingClient($calls), new NullLogger(), '', 's3cret'))
|
|
->invalidate($this->makeBlog());
|
|
// سکرت خالی — پیکربندی ناقص نباید درخواست بدون احراز بفرستد
|
|
(new BlogCacheInvalidator($this->recordingClient($calls), new NullLogger(), 'https://nobat724.com/api/revalidate', ''))
|
|
->invalidate($this->makeBlog());
|
|
|
|
self::assertSame([], $calls);
|
|
}
|
|
}
|