Files
provider_imap/tests/php/Unit/MessageFileStoreTest.php
Sebastian 0250b5a847 feat: implement content cache
Signed-off-by: Sebastian Krupinski <krupinski01@gmail.com>
2026-09-29 19:56:30 -04:00

104 lines
3.9 KiB
PHP

<?php
declare(strict_types=1);
namespace KTXT\ProviderImap\Tests\Unit;
use FilesystemIterator;
use InvalidArgumentException;
use KTXM\ProviderImap\Stores\MessageFileStore;
use PHPUnit\Framework\TestCase;
use RecursiveDirectoryIterator;
use RecursiveIteratorIterator;
final class MessageFileStoreTest extends TestCase
{
private string $root;
private MessageFileStore $store;
protected function setUp(): void
{
$this->root = sys_get_temp_dir() . '/ktrix-imap-cache-' . bin2hex(random_bytes(4));
$this->store = new MessageFileStore($this->root);
}
protected function tearDown(): void
{
if (!is_dir($this->root)) {
return;
}
$items = new RecursiveIteratorIterator(
new RecursiveDirectoryIterator($this->root, FilesystemIterator::SKIP_DOTS),
RecursiveIteratorIterator::CHILD_FIRST,
);
foreach ($items as $item) {
$item->isDir() ? rmdir($item->getPathname()) : unlink($item->getPathname());
}
rmdir($this->root);
}
public function testWriteThenReadReturnsContent(): void
{
$content = ['schemaVersion' => 1, 'properties' => ['subject' => 'Grüße / ✓']];
$this->store->write('tenant', 'svc', 'INBOX/Reports', 7, 42, $content);
$this->assertSame($content, $this->store->read('tenant', 'svc', 'INBOX/Reports', 7, 42));
$this->assertFileExists(sprintf(
'%s/storage/tenant/provider_imap/svc/%s/7/42/message.json',
$this->root,
sha1('INBOX/Reports'),
));
}
public function testWriteReplacesAndLeavesNoTemporaryFiles(): void
{
$this->store->write('tenant', 'svc', 'INBOX', 7, 42, ['v' => 1]);
$this->store->write('tenant', 'svc', 'INBOX', 7, 42, ['v' => 2]);
$this->assertSame(['v' => 2], $this->store->read('tenant', 'svc', 'INBOX', 7, 42));
$folder = sprintf('%s/storage/tenant/provider_imap/svc/%s/7/42', $this->root, sha1('INBOX'));
$this->assertSame(['message.json'], array_values(array_diff(scandir($folder), ['.', '..'])));
}
public function testReadOfMissingOrCorruptContentReturnsNull(): void
{
$this->assertNull($this->store->read('tenant', 'svc', 'INBOX', 7, 42));
$this->store->write('tenant', 'svc', 'INBOX', 7, 42, ['v' => 1]);
file_put_contents(
sprintf('%s/storage/tenant/provider_imap/svc/%s/7/42/message.json', $this->root, sha1('INBOX')),
'{truncated',
);
$this->assertNull($this->store->read('tenant', 'svc', 'INBOX', 7, 42));
}
public function testDeleteScopes(): void
{
$this->store->write('tenant', 'svc', 'INBOX', 7, 1, ['v' => 1]);
$this->store->write('tenant', 'svc', 'INBOX', 7, 2, ['v' => 2]);
$this->store->write('tenant', 'svc', 'Sent', 3, 1, ['v' => 3]);
$this->store->write('tenant', 'other', 'INBOX', 7, 1, ['v' => 4]);
$this->store->delete('tenant', 'svc', 'INBOX', 7, 1);
$this->assertNull($this->store->read('tenant', 'svc', 'INBOX', 7, 1));
$this->assertNotNull($this->store->read('tenant', 'svc', 'INBOX', 7, 2));
$this->store->deleteByMailbox('tenant', 'svc', 'INBOX');
$this->assertNull($this->store->read('tenant', 'svc', 'INBOX', 7, 2));
$this->assertNotNull($this->store->read('tenant', 'svc', 'Sent', 3, 1));
$this->store->deleteByService('tenant', 'svc');
$this->assertNull($this->store->read('tenant', 'svc', 'Sent', 3, 1));
$this->assertDirectoryDoesNotExist($this->root . '/storage/tenant/provider_imap/svc');
$this->assertNotNull($this->store->read('tenant', 'other', 'INBOX', 7, 1));
}
public function testIdentifiersThatCouldEscapeTheRootAreRejected(): void
{
$this->expectException(InvalidArgumentException::class);
$this->store->write('tenant', '../escape', 'INBOX', 7, 1, []);
}
}