209 lines
8 KiB
PHP
209 lines
8 KiB
PHP
<?php
|
|
/** @license MIT
|
|
* Copyright 2017 J. King, Dustin Wilson et al.
|
|
* See LICENSE and AUTHORS files for details */
|
|
|
|
declare(strict_types=1);
|
|
namespace JKingWeb\Arsse\TestCase\Service;
|
|
|
|
use JKingWeb\Arsse\Service\Daemon;
|
|
use JKingWeb\Arsse\Service\Exception;
|
|
use org\bovigo\vfs\vfsStream;
|
|
|
|
/** @covers \JKingWeb\Arsse\Service\Daemon */
|
|
class TestDaemon extends \JKingWeb\Arsse\Test\AbstractTest {
|
|
protected $pidfiles = [
|
|
'errors' => [
|
|
'create' => [],
|
|
'read' => "cannot be read",
|
|
'write' => "cannot be written to",
|
|
'readwrite' => "can neither be read nor written to",
|
|
],
|
|
'ok' => [
|
|
'dir' => [],
|
|
'file' => "this file can be fully accessed",
|
|
],
|
|
'pid' => [
|
|
'current' => "2112",
|
|
'stale' => "42",
|
|
"empty" => "",
|
|
'malformed1' => "02112",
|
|
'malformed2' => "2112 ",
|
|
'malformed3' => "2112\n",
|
|
'bogus1' => "bogus",
|
|
'bogus2' => " ",
|
|
'bogus3' => "\n",
|
|
'overlong' => "123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890",
|
|
'locked' => "", // this file will be locked by the test
|
|
'unreadable' => "", // this file will be chmodded by the test
|
|
'unwritable' => "", // this file will be chmodded by the test
|
|
],
|
|
];
|
|
|
|
public function setUp(): void {
|
|
parent::setUp();
|
|
$this->daemon = $this->partialMock(Daemon::class);
|
|
}
|
|
|
|
/** @dataProvider providePathResolutions */
|
|
public function testResolveRelativePaths(string $path, $cwd, $exp): void {
|
|
// set up mock daemon class
|
|
$this->daemon->cwd->returns($cwd);
|
|
$daemon = $this->daemon->get();
|
|
// perform the test
|
|
$this->AssertSame($exp, $daemon->resolveRelativePath($path));
|
|
}
|
|
|
|
public function providePathResolutions(): iterable {
|
|
return [
|
|
["/", "/home/me", "/"],
|
|
["/.", "/home/me", "/"],
|
|
["/..", "/home/me", "/"],
|
|
["/run", "/home/me", "/run"],
|
|
["/./run", "/home/me", "/run"],
|
|
["/../run", "/home/me", "/run"],
|
|
["/run/../run", "/home/me", "/run"],
|
|
["/run/./run", "/home/me", "/run/run"],
|
|
["run", "/home/me", "/home/me/run"],
|
|
["run/..", "/home/me", "/home/me"],
|
|
[".", "/", "/"],
|
|
[".", false, false],
|
|
];
|
|
}
|
|
|
|
/** @dataProvider providePidFileChecks */
|
|
public function testCheckPidFiles(string $file, bool $accessible, $exp): void {
|
|
$vfs = vfsStream::setup("pidtest", 0777, $this->pidfiles);
|
|
$path = $vfs->url()."/";
|
|
// set up access blocks
|
|
chmod($path."errors/create", 0555);
|
|
chmod($path."errors/read", 0333);
|
|
chmod($path."errors/write", 0555);
|
|
chmod($path."errors/readwrite", 0111);
|
|
// set up mock daemon class
|
|
$this->daemon->resolveRelativePath->returns($accessible ? dirname($path.$file) : false);
|
|
$daemon = $this->daemon->get();
|
|
// perform the test
|
|
if ($exp instanceof \Exception) {
|
|
$this->assertException($exp);
|
|
$daemon->checkPIDFilePath($file);
|
|
} else {
|
|
$this->assertSame($path.$exp, $daemon->checkPIDFilePath($file));
|
|
}
|
|
}
|
|
|
|
public function providePidFileChecks(): iterable {
|
|
return [
|
|
["ok/file", false, new Exception("pidDirUnresolvable")],
|
|
["not/found", true, new Exception("pidDirMissing")],
|
|
["errors/create/pid", true, new Exception("pidUncreatable")],
|
|
["errors/read", true, new Exception("pidUnreadable")],
|
|
["errors/write", true, new Exception("pidUnwritable")],
|
|
["errors/readwrite", true, new Exception("pidUnusable")],
|
|
["", true, new Exception("pidNotFile")],
|
|
["ok/dir", true, new Exception("pidNotFile")],
|
|
["ok/file", true, "ok/file"],
|
|
["ok/dir/file", true, "ok/dir/file"],
|
|
];
|
|
}
|
|
|
|
/** @dataProvider providePidReadChecks */
|
|
public function testCheckPidReads(string $file, $exp) {
|
|
$vfs = vfsStream::setup("pidtest", 0777, $this->pidfiles);
|
|
$path = $vfs->url()."/pid/";
|
|
// set up access blocks
|
|
$f = fopen($path."locked", "r+");
|
|
flock($f, \LOCK_EX | \LOCK_NB);
|
|
chmod($path."unreadable", 0333);
|
|
chmod($path."unwritable", 0555);
|
|
// set up mock daemon class
|
|
$this->daemon->processExists->with(2112)->returns(true);
|
|
$this->daemon->processExists->with(42)->returns(false);
|
|
$daemon = $this->daemon->get();
|
|
// perform the test
|
|
try {
|
|
if ($exp instanceof \Exception) {
|
|
$this->assertException($exp);
|
|
$daemon->checkPID($path.$file);
|
|
} else {
|
|
$this->assertSame($exp, $daemon->checkPID($path.$file));
|
|
}
|
|
} finally {
|
|
flock($f, \LOCK_UN);
|
|
fclose($f);
|
|
}
|
|
}
|
|
|
|
public function providePidReadChecks(): iterable {
|
|
return [
|
|
["current", new Exception("pidDuplicate")],
|
|
["malformed1", new Exception("pidCorrupt")],
|
|
["malformed2", new Exception("pidCorrupt")],
|
|
["malformed3", new Exception("pidCorrupt")],
|
|
["bogus1", new Exception("pidCorrupt")],
|
|
["bogus2", new Exception("pidCorrupt")],
|
|
["bogus3", new Exception("pidCorrupt")],
|
|
["overlong", new Exception("pidCorrupt")],
|
|
["unreadable", new Exception("pidInaccessible")],
|
|
["unwritable", null],
|
|
["locked", null],
|
|
["missing", null],
|
|
["stale", null],
|
|
["empty", null],
|
|
];
|
|
}
|
|
|
|
/**
|
|
* @dataProvider providePidWriteChecks
|
|
* @requires extension posix
|
|
*/
|
|
public function testCheckPidWrites(string $file, $exp) {
|
|
$pid = (string) posix_getpid();
|
|
$vfs = vfsStream::setup("pidtest", 0777, $this->pidfiles);
|
|
$path = $vfs->url()."/pid/";
|
|
// set up access blocks
|
|
$f = fopen($path."locked", "r+");
|
|
flock($f, \LOCK_EX | \LOCK_NB);
|
|
chmod($path."unreadable", 0333);
|
|
chmod($path."unwritable", 0555);
|
|
// set up mock daemon class
|
|
$this->daemon->processExists->with(2112)->returns(true);
|
|
$this->daemon->processExists->with(42)->returns(false);
|
|
$daemon = $this->daemon->get();
|
|
// perform the test
|
|
try {
|
|
if ($exp instanceof \Exception) {
|
|
$this->assertException($exp);
|
|
$exp = $this->pidfiles['pid'][$file] ?? false;
|
|
$daemon->writePID($path.$file);
|
|
} else {
|
|
$this->assertSame($exp, $daemon->writePID($path.$file));
|
|
$exp = $pid;
|
|
}
|
|
} finally {
|
|
flock($f, \LOCK_UN);
|
|
fclose($f);
|
|
chmod($path."unreadable", 0777);
|
|
$this->assertSame($exp, @file_get_contents($path.$file));
|
|
}
|
|
}
|
|
|
|
public function providePidWriteChecks(): iterable {
|
|
return [
|
|
["current", new Exception("pidDuplicate")],
|
|
["malformed1", new Exception("pidCorrupt")],
|
|
["malformed2", new Exception("pidCorrupt")],
|
|
["malformed3", new Exception("pidCorrupt")],
|
|
["bogus1", new Exception("pidCorrupt")],
|
|
["bogus2", new Exception("pidCorrupt")],
|
|
["bogus3", new Exception("pidCorrupt")],
|
|
["overlong", new Exception("pidCorrupt")],
|
|
["unreadable", new Exception("pidInaccessible")],
|
|
["unwritable", new Exception("pidInaccessible")],
|
|
["locked", new Exception("pidLocked")],
|
|
["missing", null],
|
|
["stale", null],
|
|
["empty", null],
|
|
];
|
|
}
|
|
}
|