Reworked the DaemonCommand.
* Accepts options for PID and log file. * Uses posix_kill whenever available. * Checks that the daemon actually started or stopped. * Try to terminate then kill the daemon. * Uses the logger or output instead of "echo". Added a ProcessControl interface and implementations. Closed #908
This commit is contained in:
parent
8fc4c51d54
commit
7de9023810
|
@ -1,4 +1,5 @@
|
||||||
<?php
|
<?php
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* PHPCI - Continuous Integration for PHP
|
* PHPCI - Continuous Integration for PHP
|
||||||
*
|
*
|
||||||
|
@ -10,28 +11,48 @@
|
||||||
namespace PHPCI\Command;
|
namespace PHPCI\Command;
|
||||||
|
|
||||||
use Monolog\Logger;
|
use Monolog\Logger;
|
||||||
|
use PHPCI\ProcessControl\Factory;
|
||||||
|
use PHPCI\ProcessControl\ProcessControlInterface;
|
||||||
use Symfony\Component\Console\Command\Command;
|
use Symfony\Component\Console\Command\Command;
|
||||||
use Symfony\Component\Console\Input\InputArgument;
|
use Symfony\Component\Console\Input\InputArgument;
|
||||||
use Symfony\Component\Console\Input\InputInterface;
|
use Symfony\Component\Console\Input\InputInterface;
|
||||||
|
use Symfony\Component\Console\Input\InputOption;
|
||||||
use Symfony\Component\Console\Output\OutputInterface;
|
use Symfony\Component\Console\Output\OutputInterface;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Daemon that loops and call the run-command.
|
* Daemon that loops and call the run-command.
|
||||||
* @author Gabriel Baker <gabriel.baker@autonomicpilot.co.uk>
|
* @author Gabriel Baker <gabriel.baker@autonomicpilot.co.uk>
|
||||||
* @package PHPCI
|
* @package PHPCI
|
||||||
* @subpackage Console
|
* @subpackage Console
|
||||||
*/
|
*/
|
||||||
class DaemonCommand extends Command
|
class DaemonCommand extends Command
|
||||||
{
|
{
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @var \Monolog\Logger
|
* @var Logger
|
||||||
*/
|
*/
|
||||||
protected $logger;
|
protected $logger;
|
||||||
|
|
||||||
public function __construct(Logger $logger, $name = null)
|
/**
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
|
protected $pidFilePath;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
|
protected $logFilePath;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var ProcessControlInterface
|
||||||
|
*/
|
||||||
|
protected $processControl;
|
||||||
|
|
||||||
|
public function __construct(Logger $logger, ProcessControlInterface $processControl = null, $name = null)
|
||||||
{
|
{
|
||||||
parent::__construct($name);
|
parent::__construct($name);
|
||||||
$this->logger = $logger;
|
$this->logger = $logger;
|
||||||
|
$this->processControl = $processControl ?: Factory::getInstance();
|
||||||
}
|
}
|
||||||
|
|
||||||
protected function configure()
|
protected function configure()
|
||||||
|
@ -40,17 +61,30 @@ class DaemonCommand extends Command
|
||||||
->setName('phpci:daemon')
|
->setName('phpci:daemon')
|
||||||
->setDescription('Initiates the daemon to run commands.')
|
->setDescription('Initiates the daemon to run commands.')
|
||||||
->addArgument(
|
->addArgument(
|
||||||
'state',
|
'state', InputArgument::REQUIRED, 'start|stop|status'
|
||||||
InputArgument::REQUIRED,
|
)
|
||||||
'start|stop|status'
|
->addOption(
|
||||||
);
|
'pid-file', 'p', InputOption::VALUE_REQUIRED,
|
||||||
|
'Path of the PID file',
|
||||||
|
implode(DIRECTORY_SEPARATOR,
|
||||||
|
array(PHPCI_DIR, 'daemon', 'daemon.pid'))
|
||||||
|
)
|
||||||
|
->addOption(
|
||||||
|
'log-file', 'l', InputOption::VALUE_REQUIRED,
|
||||||
|
'Path of the log file',
|
||||||
|
implode(DIRECTORY_SEPARATOR,
|
||||||
|
array(PHPCI_DIR, 'daemon', 'daemon.log'))
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Loops through running.
|
* Loops through running.
|
||||||
*/
|
*/
|
||||||
protected function execute(InputInterface $input, OutputInterface $output)
|
protected function execute(InputInterface $input, OutputInterface $output)
|
||||||
{
|
{
|
||||||
|
$this->pidFilePath = $input->getOption('pid-file');
|
||||||
|
$this->logFilePath = $input->getOption('log-file');
|
||||||
|
|
||||||
$state = $input->getArgument('state');
|
$state = $input->getArgument('state');
|
||||||
|
|
||||||
switch ($state) {
|
switch ($state) {
|
||||||
|
@ -61,64 +95,108 @@ class DaemonCommand extends Command
|
||||||
$this->stopDaemon();
|
$this->stopDaemon();
|
||||||
break;
|
break;
|
||||||
case 'status':
|
case 'status':
|
||||||
$this->statusDaemon();
|
$this->statusDaemon($output);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
echo "Not a valid choice, please use start stop or status";
|
$this->output->writeln("<error>Not a valid choice, please use start, stop or status</error>");
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
protected function startDaemon()
|
protected function startDaemon()
|
||||||
{
|
{
|
||||||
|
$pid = $this->getRunningPid();
|
||||||
if (file_exists(PHPCI_DIR.'/daemon/daemon.pid')) {
|
if ($pid) {
|
||||||
echo "Already started\n";
|
$this->logger->notice("Daemon already started", array('pid' => $pid));
|
||||||
$this->logger->warning("Daemon already started");
|
|
||||||
return "alreadystarted";
|
return "alreadystarted";
|
||||||
}
|
}
|
||||||
|
|
||||||
$logfile = PHPCI_DIR."/daemon/daemon.log";
|
$this->logger->info("Trying to start the daemon");
|
||||||
|
|
||||||
$cmd = "nohup %s/daemonise phpci:daemonise > %s 2>&1 &";
|
$cmd = "nohup %s/daemonise phpci:daemonise > %s 2>&1 &";
|
||||||
$command = sprintf($cmd, PHPCI_DIR, $logfile);
|
$command = sprintf($cmd, PHPCI_DIR, $this->logFilePath);
|
||||||
$this->logger->info("Daemon started");
|
$output = $exitCode = null;
|
||||||
exec($command);
|
exec($command, $output, $exitCode);
|
||||||
|
|
||||||
|
if ($exitCode !== 0) {
|
||||||
|
$this->logger->error(sprintf("daemonise exited with status %d", $exitCode));
|
||||||
|
return "notstarted";
|
||||||
|
}
|
||||||
|
|
||||||
|
for ($i = 0; !($pid = $this->getRunningPid()) && $i < 5; $i++) {
|
||||||
|
sleep(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!$pid) {
|
||||||
|
$this->logger->error("Could not start the daemon");
|
||||||
|
return "notstarted";
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->logger->notice("Daemon started", array('pid' => $pid));
|
||||||
|
return "started";
|
||||||
}
|
}
|
||||||
|
|
||||||
protected function stopDaemon()
|
protected function stopDaemon()
|
||||||
{
|
{
|
||||||
|
$pid = $this->getRunningPid();
|
||||||
if (!file_exists(PHPCI_DIR.'/daemon/daemon.pid')) {
|
if (!$pid) {
|
||||||
echo "Not started\n";
|
$this->logger->notice("Cannot stop the daemon as it is not started");
|
||||||
$this->logger->warning("Can't stop daemon as not started");
|
|
||||||
return "notstarted";
|
return "notstarted";
|
||||||
}
|
}
|
||||||
|
|
||||||
$cmd = "kill $(cat %s/daemon/daemon.pid)";
|
$this->logger->info("Trying to terminate the daemon", array('pid' => $pid));
|
||||||
$command = sprintf($cmd, PHPCI_DIR);
|
$this->processControl->kill($pid);
|
||||||
exec($command);
|
|
||||||
$this->logger->info("Daemon stopped");
|
|
||||||
unlink(PHPCI_DIR.'/daemon/daemon.pid');
|
|
||||||
}
|
|
||||||
|
|
||||||
protected function statusDaemon()
|
for ($i = 0; ($pid = $this->getRunningPid()) && $i < 5; $i++) {
|
||||||
{
|
sleep(1);
|
||||||
|
|
||||||
if (!file_exists(PHPCI_DIR.'/daemon/daemon.pid')) {
|
|
||||||
echo "Not running\n";
|
|
||||||
return "notrunning";
|
|
||||||
}
|
}
|
||||||
|
|
||||||
$pid = trim(file_get_contents(PHPCI_DIR.'/daemon/daemon.pid'));
|
if ($pid) {
|
||||||
$pidcheck = sprintf("/proc/%s", $pid);
|
$this->logger->warning("The daemon is resiting, trying to kill it", array('pid' => $pid));
|
||||||
if (is_dir($pidcheck)) {
|
$this->processControl->kill($pid, true);
|
||||||
echo "Running\n";
|
|
||||||
|
for ($i = 0; ($pid = $this->getRunningPid()) && $i < 5; $i++) {
|
||||||
|
sleep(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!$pid) {
|
||||||
|
$this->logger->notice("Daemon stopped");
|
||||||
|
return "stopped";
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->logger->error("Could not stop the daemon");
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function statusDaemon(OutputInterface $output)
|
||||||
|
{
|
||||||
|
$pid = $this->getRunningPid();
|
||||||
|
if ($pid) {
|
||||||
|
$output->writeln(sprintf('The daemon is running, PID: %d', $pid));
|
||||||
return "running";
|
return "running";
|
||||||
}
|
}
|
||||||
|
|
||||||
unlink(PHPCI_DIR.'/daemon/daemon.pid');
|
$output->writeln('The daemon is not running');
|
||||||
echo "Not running\n";
|
|
||||||
return "notrunning";
|
return "notrunning";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Check if there is a running daemon
|
||||||
|
*
|
||||||
|
* @return int|null
|
||||||
|
*/
|
||||||
|
protected function getRunningPid()
|
||||||
|
{
|
||||||
|
if (!file_exists($this->pidFilePath)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
$pid = intval(trim(file_get_contents($this->pidFilePath)));
|
||||||
|
|
||||||
|
if($this->processControl->isRunning($pid, true)) {
|
||||||
|
return $pid;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Not found, remove the stale PID file
|
||||||
|
unlink($this->pidFilePath);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
63
PHPCI/ProcessControl/Factory.php
Normal file
63
PHPCI/ProcessControl/Factory.php
Normal file
|
@ -0,0 +1,63 @@
|
||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* PHPCI - Continuous Integration for PHP
|
||||||
|
*
|
||||||
|
* @copyright Copyright 2015, Block 8 Limited.
|
||||||
|
* @license https://github.com/Block8/PHPCI/blob/master/LICENSE.md
|
||||||
|
* @link https://www.phptesting.org/
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace PHPCI\ProcessControl;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Construct an appropriate ProcessControl instance.
|
||||||
|
*
|
||||||
|
* @author Adirelle <adirelle@gmail.com>
|
||||||
|
*/
|
||||||
|
class Factory
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* ProcessControl singleton.
|
||||||
|
*
|
||||||
|
* @var ProcessControlInterface
|
||||||
|
*/
|
||||||
|
protected static $instance = null;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the ProcessControl singleton.
|
||||||
|
*
|
||||||
|
* @return ProcessControlInterface
|
||||||
|
*/
|
||||||
|
public static function getInstance()
|
||||||
|
{
|
||||||
|
if (static::$instance === null) {
|
||||||
|
static::$instance = static::createProcessControl();
|
||||||
|
}
|
||||||
|
return static::$instance;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a ProcessControl depending on available extensions and the underlying OS.
|
||||||
|
*
|
||||||
|
* Check PosixProcessControl, WindowsProcessControl and UnixProcessControl, in that order.
|
||||||
|
*
|
||||||
|
* @return ProcessControlInterface
|
||||||
|
*
|
||||||
|
* @internal
|
||||||
|
*/
|
||||||
|
public static function createProcessControl()
|
||||||
|
{
|
||||||
|
switch(true) {
|
||||||
|
case PosixProcessControl::isAvailable():
|
||||||
|
return new PosixProcessControl();
|
||||||
|
|
||||||
|
case WindowsProcessControl::isAvailable():
|
||||||
|
return new WindowsProcessControl();
|
||||||
|
|
||||||
|
case UnixProcessControl::isAvailable():
|
||||||
|
return new UnixProcessControl();
|
||||||
|
}
|
||||||
|
|
||||||
|
throw new \Exception("No ProcessControl implementation available.");
|
||||||
|
}
|
||||||
|
}
|
52
PHPCI/ProcessControl/PosixProcessControl.php
Normal file
52
PHPCI/ProcessControl/PosixProcessControl.php
Normal file
|
@ -0,0 +1,52 @@
|
||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* PHPCI - Continuous Integration for PHP
|
||||||
|
*
|
||||||
|
* @copyright Copyright 2015, Block 8 Limited.
|
||||||
|
* @license https://github.com/Block8/PHPCI/blob/master/LICENSE.md
|
||||||
|
* @link https://www.phptesting.org/
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace PHPCI\ProcessControl;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Control process using the POSIX extension.
|
||||||
|
*
|
||||||
|
* @author Adirelle <adirelle@gmail.com>
|
||||||
|
*/
|
||||||
|
class PosixProcessControl implements ProcessControlInterface
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @param int $pid
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
public function isRunning($pid)
|
||||||
|
{
|
||||||
|
// Signal "0" is not sent to the process, but posix_kill checks the process anyway;
|
||||||
|
return posix_kill($pid, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sends a TERMINATE or KILL signal to the process using posix_kill.
|
||||||
|
*
|
||||||
|
* @param int $pid
|
||||||
|
* @param bool $forcefully Whetehr to send TERMINATE (false) or KILL (true).
|
||||||
|
*/
|
||||||
|
public function kill($pid, $forcefully = false)
|
||||||
|
{
|
||||||
|
posix_kill($pid, $forcefully ? 9 : 15);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check whether this posix_kill is available.
|
||||||
|
*
|
||||||
|
* @return bool
|
||||||
|
*
|
||||||
|
* @internal
|
||||||
|
*/
|
||||||
|
public static function isAvailable()
|
||||||
|
{
|
||||||
|
return function_exists('posix_kill');
|
||||||
|
}
|
||||||
|
}
|
33
PHPCI/ProcessControl/ProcessControlInterface.php
Normal file
33
PHPCI/ProcessControl/ProcessControlInterface.php
Normal file
|
@ -0,0 +1,33 @@
|
||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* PHPCI - Continuous Integration for PHP
|
||||||
|
*
|
||||||
|
* @copyright Copyright 2015, Block 8 Limited.
|
||||||
|
* @license https://github.com/Block8/PHPCI/blob/master/LICENSE.md
|
||||||
|
* @link https://www.phptesting.org/
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace PHPCI\ProcessControl;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A stateless service to check and kill system processes.
|
||||||
|
*
|
||||||
|
* @author Adirelle <adirelle@gmail.com>
|
||||||
|
*/
|
||||||
|
interface ProcessControlInterface
|
||||||
|
{
|
||||||
|
/** Checks if a process exists.
|
||||||
|
*
|
||||||
|
* @param int $pid The process identifier.
|
||||||
|
*
|
||||||
|
* @return boolean true is the process is running, else false.
|
||||||
|
*/
|
||||||
|
public function isRunning($pid);
|
||||||
|
|
||||||
|
/** Terminate a running process.
|
||||||
|
*
|
||||||
|
* @param int $pid The process identifier.
|
||||||
|
* @param bool $forcefully Whether to gently (false) or forcefully (true) terminate the process.
|
||||||
|
*/
|
||||||
|
public function kill($pid, $forcefully = false);
|
||||||
|
}
|
54
PHPCI/ProcessControl/UnixProcessControl.php
Normal file
54
PHPCI/ProcessControl/UnixProcessControl.php
Normal file
|
@ -0,0 +1,54 @@
|
||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* PHPCI - Continuous Integration for PHP
|
||||||
|
*
|
||||||
|
* @copyright Copyright 2015, Block 8 Limited.
|
||||||
|
* @license https://github.com/Block8/PHPCI/blob/master/LICENSE.md
|
||||||
|
* @link https://www.phptesting.org/
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace PHPCI\ProcessControl;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Control processes using the "ps" and "kill" commands.
|
||||||
|
*
|
||||||
|
* @author Adirelle <adirelle@gmail.com>
|
||||||
|
*/
|
||||||
|
class UnixProcessControl implements ProcessControlInterface
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Check process using the "ps" command.
|
||||||
|
*
|
||||||
|
* @param int $pid
|
||||||
|
* @return boolean
|
||||||
|
*/
|
||||||
|
public function isRunning($pid)
|
||||||
|
{
|
||||||
|
$output = $exitCode = null;
|
||||||
|
exec(sprintf("ps %d", $pid), $output, $exitCode);
|
||||||
|
return $exitCode === 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sends a signal using the "kill" command.
|
||||||
|
*
|
||||||
|
* @param int $pid
|
||||||
|
* @param bool $forcefully
|
||||||
|
*/
|
||||||
|
public function kill($pid, $forcefully = false)
|
||||||
|
{
|
||||||
|
exec(sprintf("kill -%d %d", $forcefully ? 9 : 15, $pid));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check whether the commands "ps" and "kill" are available.
|
||||||
|
*
|
||||||
|
* @return bool
|
||||||
|
*
|
||||||
|
* @internal
|
||||||
|
*/
|
||||||
|
public static function isAvailable()
|
||||||
|
{
|
||||||
|
return DIRECTORY_SEPARATOR === '/' && exec("which ps") && exec("which kill");
|
||||||
|
}
|
||||||
|
}
|
54
PHPCI/ProcessControl/WindowsProcessControl.php
Normal file
54
PHPCI/ProcessControl/WindowsProcessControl.php
Normal file
|
@ -0,0 +1,54 @@
|
||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* PHPCI - Continuous Integration for PHP
|
||||||
|
*
|
||||||
|
* @copyright Copyright 2015, Block 8 Limited.
|
||||||
|
* @license https://github.com/Block8/PHPCI/blob/master/LICENSE.md
|
||||||
|
* @link https://www.phptesting.org/
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace PHPCI\ProcessControl;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Control processes using the "tasklist" and "taskkill" commands.
|
||||||
|
*
|
||||||
|
* @author Adirelle <adirelle@gmail.com>
|
||||||
|
*/
|
||||||
|
class WindowsProcessControl implements ProcessControlInterface
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Check if the process is running using the "tasklist" command.
|
||||||
|
*
|
||||||
|
* @param type $pid
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
public function isRunning($pid)
|
||||||
|
{
|
||||||
|
$lastLine = exec(sprintf('tasklist /fi "PID eq %d" /nh /fo csv 2>nul:', $pid));
|
||||||
|
$record = str_getcsv($lastLine);
|
||||||
|
return isset($record[1]) && intval($record[1]) === $pid;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Terminate the process using the "taskkill" command.
|
||||||
|
*
|
||||||
|
* @param type $pid
|
||||||
|
* @param bool $forcefully
|
||||||
|
*/
|
||||||
|
public function kill($pid, $forcefully = false)
|
||||||
|
{
|
||||||
|
exec(sprintf("taskkill /t /pid %d %s 2>nul:", $pid, $forcefully ? '/f' : ''));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check whether the commands "tasklist" and "taskkill" are available.
|
||||||
|
*
|
||||||
|
* @return bool
|
||||||
|
*
|
||||||
|
* @internal
|
||||||
|
*/
|
||||||
|
public static function isAvailable()
|
||||||
|
{
|
||||||
|
return DIRECTORY_SEPARATOR === '\\' && exec("where tasklist") && exec("where taskkill");
|
||||||
|
}
|
||||||
|
}
|
17
Tests/PHPCI/ProcessControl/PosixProcessControlTest.php
Normal file
17
Tests/PHPCI/ProcessControl/PosixProcessControlTest.php
Normal file
|
@ -0,0 +1,17 @@
|
||||||
|
<?php
|
||||||
|
namespace Tests\PHPCI\ProcessControl;
|
||||||
|
|
||||||
|
use PHPCI\ProcessControl\PosixProcessControl;
|
||||||
|
|
||||||
|
class PosixProcessControlTest extends UnixProcessControlTest
|
||||||
|
{
|
||||||
|
protected function setUp()
|
||||||
|
{
|
||||||
|
$this->object = new PosixProcessControl();
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testIsAvailable()
|
||||||
|
{
|
||||||
|
$this->assertEquals(function_exists('posix_kill'), PosixProcessControl::isAvailable());
|
||||||
|
}
|
||||||
|
}
|
126
Tests/PHPCI/ProcessControl/ProcessControlTest.php
Normal file
126
Tests/PHPCI/ProcessControl/ProcessControlTest.php
Normal file
|
@ -0,0 +1,126 @@
|
||||||
|
<?php
|
||||||
|
namespace Tests\PHPCI\ProcessControl;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Some helpers to
|
||||||
|
*/
|
||||||
|
abstract class ProcessControlTest extends \PHPUnit_Framework_TestCase
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* @var type
|
||||||
|
*/
|
||||||
|
protected $process;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var array
|
||||||
|
*/
|
||||||
|
protected $pipes;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var \PHPCI\ProcessControl\ProcessControlInterface
|
||||||
|
*/
|
||||||
|
protected $object;
|
||||||
|
|
||||||
|
/** Starts a process.
|
||||||
|
*
|
||||||
|
* @return int The PID of the process.
|
||||||
|
*/
|
||||||
|
protected function startProcess()
|
||||||
|
{
|
||||||
|
$desc = array(array("pipe", "r"), array("pipe", "w"), array("pipe", "w"));
|
||||||
|
$this->pipes = array();
|
||||||
|
|
||||||
|
$this->process = proc_open($this->getTestCommand(), $desc, $this->pipes);
|
||||||
|
usleep(500);
|
||||||
|
|
||||||
|
$this->assertTrue(is_resource($this->process));
|
||||||
|
$this->assertTrue($this->isRunning());
|
||||||
|
|
||||||
|
$status = proc_get_status($this->process);
|
||||||
|
return $status['pid'];
|
||||||
|
}
|
||||||
|
|
||||||
|
/** End the running process.
|
||||||
|
*
|
||||||
|
* @return int
|
||||||
|
*/
|
||||||
|
protected function endProcess()
|
||||||
|
{
|
||||||
|
if (!is_resource($this->process)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
array_map('fclose', $this->pipes);
|
||||||
|
$exitCode = proc_close($this->process);
|
||||||
|
$this->assertFalse($this->isRunning());
|
||||||
|
$this->process = null;
|
||||||
|
return $exitCode;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
protected function isRunning()
|
||||||
|
{
|
||||||
|
if (!is_resource($this->process)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
$status = proc_get_status($this->process);
|
||||||
|
return $status['running'];
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testIsRunning()
|
||||||
|
{
|
||||||
|
if (!$this->object->isAvailable()) {
|
||||||
|
$this->markTestSkipped();
|
||||||
|
}
|
||||||
|
|
||||||
|
$pid = $this->startProcess();
|
||||||
|
|
||||||
|
$this->assertTrue($this->object->isRunning($pid));
|
||||||
|
|
||||||
|
fwrite($this->pipes[0], PHP_EOL);
|
||||||
|
|
||||||
|
$exitCode = $this->endProcess();
|
||||||
|
|
||||||
|
$this->assertEquals(0, $exitCode);
|
||||||
|
$this->assertFalse($this->object->isRunning($pid));
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testSoftKill()
|
||||||
|
{
|
||||||
|
if (!$this->object->isAvailable()) {
|
||||||
|
$this->markTestSkipped();
|
||||||
|
}
|
||||||
|
|
||||||
|
$pid = $this->startProcess();
|
||||||
|
|
||||||
|
$this->object->kill($pid);
|
||||||
|
usleep(500);
|
||||||
|
|
||||||
|
$this->assertFalse($this->isRunning());
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testForcefullyKill()
|
||||||
|
{
|
||||||
|
if (!$this->object->isAvailable()) {
|
||||||
|
$this->markTestSkipped();
|
||||||
|
}
|
||||||
|
|
||||||
|
$pid = $this->startProcess();
|
||||||
|
|
||||||
|
$this->object->kill($pid, true);
|
||||||
|
usleep(500);
|
||||||
|
|
||||||
|
$this->assertFalse($this->isRunning());
|
||||||
|
}
|
||||||
|
|
||||||
|
abstract public function testIsAvailable();
|
||||||
|
|
||||||
|
abstract public function getTestCommand();
|
||||||
|
|
||||||
|
protected function tearDown()
|
||||||
|
{
|
||||||
|
parent::tearDown();
|
||||||
|
$this->endProcess();
|
||||||
|
}
|
||||||
|
}
|
22
Tests/PHPCI/ProcessControl/UnixProcessControlTest.php
Normal file
22
Tests/PHPCI/ProcessControl/UnixProcessControlTest.php
Normal file
|
@ -0,0 +1,22 @@
|
||||||
|
<?php
|
||||||
|
namespace Tests\PHPCI\ProcessControl;
|
||||||
|
|
||||||
|
use PHPCI\ProcessControl\UnixProcessControl;
|
||||||
|
|
||||||
|
class UnixProcessControlTest extends ProcessControlTest
|
||||||
|
{
|
||||||
|
protected function setUp()
|
||||||
|
{
|
||||||
|
$this->object = new UnixProcessControl();
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getTestCommand()
|
||||||
|
{
|
||||||
|
return "read SOMETHING";
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testIsAvailable()
|
||||||
|
{
|
||||||
|
$this->assertEquals(DIRECTORY_SEPARATOR === '/', UnixProcessControl::isAvailable());
|
||||||
|
}
|
||||||
|
}
|
22
Tests/PHPCI/ProcessControl/WindowsProcessControlTest.php
Normal file
22
Tests/PHPCI/ProcessControl/WindowsProcessControlTest.php
Normal file
|
@ -0,0 +1,22 @@
|
||||||
|
<?php
|
||||||
|
namespace Tests\PHPCI\ProcessControl;
|
||||||
|
|
||||||
|
use PHPCI\ProcessControl\WindowsProcessControl;
|
||||||
|
|
||||||
|
class WindowsProcessControlTest extends ProcessControlTest
|
||||||
|
{
|
||||||
|
protected function setUp()
|
||||||
|
{
|
||||||
|
$this->object = new WindowsProcessControl;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getTestCommand()
|
||||||
|
{
|
||||||
|
return "pause";
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testIsAvailable()
|
||||||
|
{
|
||||||
|
$this->assertEquals(DIRECTORY_SEPARATOR === '\\', WindowsProcessControl::isAvailable());
|
||||||
|
}
|
||||||
|
}
|
|
@ -28,6 +28,12 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
"autoload-dev": {
|
||||||
|
"psr-4": {
|
||||||
|
"Tests\\PHPCI\\": "Tests/PHPCI/"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
"require": {
|
"require": {
|
||||||
"php": ">=5.3.8",
|
"php": ">=5.3.8",
|
||||||
"ext-pdo": "*",
|
"ext-pdo": "*",
|
||||||
|
|
Loading…
Reference in a new issue