Files
weerscherm/tests/TokenStoreTest.php

88 lines
2.8 KiB
PHP

<?php
declare(strict_types=1);
namespace Weerscherm\Tests;
use PHPUnit\Framework\TestCase;
use Weerscherm\TokenStore;
final class TokenStoreTest extends TestCase
{
private string $dir;
private string $file;
protected function setUp(): void
{
$this->dir = sys_get_temp_dir() . '/weerscherm-token-' . uniqid();
$this->file = $this->dir . '/netatmo-token.json';
}
protected function tearDown(): void
{
array_map('unlink', glob($this->dir . '/*') ?: []);
@rmdir($this->dir);
}
public function testWriteReadRoundTripAndMode(): void
{
$store = new TokenStore($this->file);
$store->write(['access_token' => 'a', 'refresh_token' => 'r', 'expires_at' => 123]);
self::assertSame(['access_token' => 'a', 'refresh_token' => 'r', 'expires_at' => 123], $store->read());
self::assertSame('0600', substr(sprintf('%o', fileperms($this->file)), -4));
self::assertSame([], glob($this->dir . '/*.tmp.*') ?: [], 'geen tijdelijke bestanden achtergelaten');
}
public function testMissingOrInvalidFileReadsNull(): void
{
self::assertNull((new TokenStore($this->file))->read());
mkdir($this->dir, 0700, true);
file_put_contents($this->file, '{"access_token":"a"}');
self::assertNull((new TokenStore($this->file))->read(), 'zonder refresh token is het bestand onbruikbaar');
}
public function testWithLockReturnsValueAndReleasesAfterException(): void
{
$store = new TokenStore($this->file);
self::assertSame(42, $store->withLock(fn() => 42));
try {
$store->withLock(function (): void {
throw new \RuntimeException('boem');
});
self::fail('exception verwacht');
} catch (\RuntimeException) {
}
$handle = fopen($this->file . '.lock', 'c');
self::assertTrue(flock($handle, LOCK_EX | LOCK_NB), 'lock is weer vrij');
fclose($handle);
}
public function testConcurrentProcessesAreSerialised(): void
{
$store = new TokenStore($this->file);
$script = sprintf(
'<?php require %s; $s = new Weerscherm\TokenStore(%s); $s->withLock(function () { usleep(400000); });',
var_export(__DIR__ . '/../vendor/autoload.php', true),
var_export($this->file, true),
);
$scriptFile = $this->dir . '/hold.php';
mkdir($this->dir, 0700, true);
file_put_contents($scriptFile, $script);
$proc = proc_open([PHP_BINARY, $scriptFile], [], $pipes);
usleep(150000); // geef het andere proces tijd om de lock te pakken
$start = microtime(true);
$store->withLock(fn() => null);
$waited = microtime(true) - $start;
proc_close($proc);
self::assertGreaterThan(0.15, $waited, 'tweede proces moest wachten op de lock');
}
}