88 lines
2.8 KiB
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');
|
|
}
|
|
}
|