Przeglądaj źródła

Replaced indention tabs with 4 spaces in ProcessHandler and its test.

kolja 10 lat temu
rodzic
commit
fbe0bae8c9

+ 193 - 193
src/Monolog/Handler/ProcessHandler.php

@@ -26,197 +26,197 @@ use Monolog\Logger;
  */
 class ProcessHandler extends AbstractProcessingHandler
 {
-	/**
-	 * Holds the process to receive data on its STDIN.
-	 *
-	 * @var resource
-	 */
-	private $process;
-
-	/**
-	 * @var string
-	 */
-	private $command;
-
-	/**
-	 * @var string
-	 */
-	private $cwd;
-
-	/**
-	 * @var array
-	 */
-	private $pipes = [];
-
-	/**
-	 * @var array
-	 */
-	const DESCRIPTOR_SPEC = [
-		0 => ['pipe', 'r'],  // STDIN is a pipe that the child will read from
-		1 => ['pipe', 'w'],  // STDOUT is a pipe that the child will write to
-		2 => ['pipe', 'w'],  // STDERR is a pipe to catch the any errors
-	];
-
-	/**
-	 * @param int $command Command for the process to start. Absolute paths are recommended,
-	 * especially if you do not use the $cwd parameter.
-	 * @param bool|int $level The minimum logging level at which this handler will be triggered.
-	 * @param bool|true $bubble Whether the messages that are handled can bubble up the stack or not.
-	 * @param string|null $cwd "Current working directory" (CWD) for the process to be executed in.
-	 * @throws \InvalidArgumentException
-	 */
-	public function __construct($command, $level = Logger::DEBUG, $bubble = true, $cwd = null)
-	{
-		$this->guardAgainstInvalidCommand($command);
-		$this->guardAgainstInvalidCwd($cwd);
-
-		parent::__construct($level, $bubble);
-
-		$this->command = $command;
-		$this->cwd = $cwd;
-	}
-
-	/**
-	 * @param string $command
-	 * @throws \InvalidArgumentException
-	 * @return void
-	 */
-	private function guardAgainstInvalidCommand($command)
-	{
-		if (empty($command) || is_string($command) === false) {
-			throw new \InvalidArgumentException('The command argument must be a non-empty string.');
-		}
-	}
-
-	/**
-	 * @param string $cwd
-	 * @throws \InvalidArgumentException
-	 * @return void
-	 */
-	private function guardAgainstInvalidCwd($cwd)
-	{
-		if ($cwd !== null && (empty($cwd) || is_string($cwd) === false)) {
-			throw new \InvalidArgumentException('The optional CWD argument must be a non-empty string, if any.');
-		}
-	}
-
-	/**
-	 * Writes the record down to the log of the implementing handler
-	 *
-	 * @param  array $record
-	 * @throws \UnexpectedValueException
-	 * @return void
-	 */
-	protected function write(array $record)
-	{
-		$this->ensureProcessIsStarted();
-
-		$this->writeProcessInput($record['formatted']);
-
-		$errors = $this->readProcessErrors();
-		if (empty($errors) === false) {
-			throw new \UnexpectedValueException(sprintf('Errors while writing to process: %s', $errors));
-		}
-	}
-
-	/**
-	 * Makes sure that the process is actually started, and if not, starts it,
-	 * assigns the stream pipes, and handles startup errors, if any.
-	 *
-	 * @return void
-	 */
-	private function ensureProcessIsStarted()
-	{
-		if (is_resource($this->process) === false) {
-			$this->startProcess();
-
-			$this->handleStartupErrors();
-		}
-	}
-
-	/**
-	 * Starts the actual process and sets all streams to non-blocking.
-	 *
-	 * @return void
-	 */
-	private function startProcess()
-	{
-		$this->process = proc_open($this->command, self::DESCRIPTOR_SPEC, $this->pipes, $this->cwd);
-
-		foreach ($this->pipes as $pipe) {
-			stream_set_blocking($pipe, false);
-		}
-	}
-
-	/**
-	 * Selects the STDERR stream, handles upcoming startup errors, and throws an exception, if any.
-	 *
-	 * @throws \UnexpectedValueException
-	 * @return void
-	 */
-	private function handleStartupErrors()
-	{
-
-		$selected = $this->selectErrorStream();
-		if (false === $selected) {
-			throw new \UnexpectedValueException('Something went wrong while selecting a stream.');
-		}
-
-		$errors = $this->readProcessErrors();
-
-		if (is_resource($this->process) === false || empty($errors) === false) {
-			throw new \UnexpectedValueException(
-					sprintf('The process "%s" could not be opened: ' . $errors, $this->command)
-			);
-		}
-	}
-
-	/**
-	 * Selects the STDERR stream.
-	 *
-	 * @return int|bool
-	 */
-	protected function selectErrorStream()
-	{
-		$empty = [];
-		$errorPipes = [$this->pipes[2]];
-		return stream_select($errorPipes, $empty, $empty, 1);
-	}
-
-	/**
-	 * Reads the errors of the process, if there are any.
-	 *
-	 * @codeCoverageIgnore
-	 * @return string Empty string if there are no errors.
-	 */
-	protected function readProcessErrors()
-	{
-		return stream_get_contents($this->pipes[2]);
-	}
-
-	/**
-	 * Writes to the input stream of the opened process.
-	 *
-	 * @codeCoverageIgnore
-	 * @param $string
-	 * @return void
-	 */
-	protected function writeProcessInput($string)
-	{
-		fwrite($this->pipes[0], (string)$string);
-	}
-
-	/**
-	 * {@inheritdoc}
-	 */
-	public function close()
-	{
-		if (is_resource($this->process)) {
-			foreach ($this->pipes as $pipe) {
-				fclose($pipe);
-			}
-			proc_close($this->process);
-		}
-		$this->process = null;
-	}
+    /**
+     * Holds the process to receive data on its STDIN.
+     *
+     * @var resource
+     */
+    private $process;
+
+    /**
+     * @var string
+     */
+    private $command;
+
+    /**
+     * @var string
+     */
+    private $cwd;
+
+    /**
+     * @var array
+     */
+    private $pipes = [];
+
+    /**
+     * @var array
+     */
+    const DESCRIPTOR_SPEC = [
+        0 => ['pipe', 'r'],  // STDIN is a pipe that the child will read from
+        1 => ['pipe', 'w'],  // STDOUT is a pipe that the child will write to
+        2 => ['pipe', 'w'],  // STDERR is a pipe to catch the any errors
+    ];
+
+    /**
+     * @param int $command Command for the process to start. Absolute paths are recommended,
+     * especially if you do not use the $cwd parameter.
+     * @param bool|int $level The minimum logging level at which this handler will be triggered.
+     * @param bool|true $bubble Whether the messages that are handled can bubble up the stack or not.
+     * @param string|null $cwd "Current working directory" (CWD) for the process to be executed in.
+     * @throws \InvalidArgumentException
+     */
+    public function __construct($command, $level = Logger::DEBUG, $bubble = true, $cwd = null)
+    {
+        $this->guardAgainstInvalidCommand($command);
+        $this->guardAgainstInvalidCwd($cwd);
+
+        parent::__construct($level, $bubble);
+
+        $this->command = $command;
+        $this->cwd = $cwd;
+    }
+
+    /**
+     * @param string $command
+     * @throws \InvalidArgumentException
+     * @return void
+     */
+    private function guardAgainstInvalidCommand($command)
+    {
+        if (empty($command) || is_string($command) === false) {
+            throw new \InvalidArgumentException('The command argument must be a non-empty string.');
+        }
+    }
+
+    /**
+     * @param string $cwd
+     * @throws \InvalidArgumentException
+     * @return void
+     */
+    private function guardAgainstInvalidCwd($cwd)
+    {
+        if ($cwd !== null && (empty($cwd) || is_string($cwd) === false)) {
+            throw new \InvalidArgumentException('The optional CWD argument must be a non-empty string, if any.');
+        }
+    }
+
+    /**
+     * Writes the record down to the log of the implementing handler
+     *
+     * @param  array $record
+     * @throws \UnexpectedValueException
+     * @return void
+     */
+    protected function write(array $record)
+    {
+        $this->ensureProcessIsStarted();
+
+        $this->writeProcessInput($record['formatted']);
+
+        $errors = $this->readProcessErrors();
+        if (empty($errors) === false) {
+            throw new \UnexpectedValueException(sprintf('Errors while writing to process: %s', $errors));
+        }
+    }
+
+    /**
+     * Makes sure that the process is actually started, and if not, starts it,
+     * assigns the stream pipes, and handles startup errors, if any.
+     *
+     * @return void
+     */
+    private function ensureProcessIsStarted()
+    {
+        if (is_resource($this->process) === false) {
+            $this->startProcess();
+
+            $this->handleStartupErrors();
+        }
+    }
+
+    /**
+     * Starts the actual process and sets all streams to non-blocking.
+     *
+     * @return void
+     */
+    private function startProcess()
+    {
+        $this->process = proc_open($this->command, self::DESCRIPTOR_SPEC, $this->pipes, $this->cwd);
+
+        foreach ($this->pipes as $pipe) {
+            stream_set_blocking($pipe, false);
+        }
+    }
+
+    /**
+     * Selects the STDERR stream, handles upcoming startup errors, and throws an exception, if any.
+     *
+     * @throws \UnexpectedValueException
+     * @return void
+     */
+    private function handleStartupErrors()
+    {
+
+        $selected = $this->selectErrorStream();
+        if (false === $selected) {
+            throw new \UnexpectedValueException('Something went wrong while selecting a stream.');
+        }
+
+        $errors = $this->readProcessErrors();
+
+        if (is_resource($this->process) === false || empty($errors) === false) {
+            throw new \UnexpectedValueException(
+                sprintf('The process "%s" could not be opened: ' . $errors, $this->command)
+            );
+        }
+    }
+
+    /**
+     * Selects the STDERR stream.
+     *
+     * @return int|bool
+     */
+    protected function selectErrorStream()
+    {
+        $empty = [];
+        $errorPipes = [$this->pipes[2]];
+        return stream_select($errorPipes, $empty, $empty, 1);
+    }
+
+    /**
+     * Reads the errors of the process, if there are any.
+     *
+     * @codeCoverageIgnore
+     * @return string Empty string if there are no errors.
+     */
+    protected function readProcessErrors()
+    {
+        return stream_get_contents($this->pipes[2]);
+    }
+
+    /**
+     * Writes to the input stream of the opened process.
+     *
+     * @codeCoverageIgnore
+     * @param $string
+     * @return void
+     */
+    protected function writeProcessInput($string)
+    {
+        fwrite($this->pipes[0], (string)$string);
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function close()
+    {
+        if (is_resource($this->process)) {
+            foreach ($this->pipes as $pipe) {
+                fclose($pipe);
+            }
+            proc_close($this->process);
+        }
+        $this->process = null;
+    }
 }

+ 176 - 176
tests/Monolog/Handler/ProcessHandlerTest.php

@@ -16,180 +16,180 @@ use Monolog\Logger;
 
 class ProcessHandlerTest extends TestCase
 {
-	/**
-	 * Dummy command to be used by tests that should not fail due to the command.
-	 *
-	 * @var string
-	 */
-	const DUMMY_COMMAND = 'echo';
-
-	/**
-	 * @covers Monolog\Handler\ProcessHandler::__construct
-	 * @covers Monolog\Handler\ProcessHandler::guardAgainstInvalidCommand
-	 * @covers Monolog\Handler\ProcessHandler::guardAgainstInvalidCwd
-	 * @covers Monolog\Handler\ProcessHandler::write
-	 * @covers Monolog\Handler\ProcessHandler::ensureProcessIsStarted
-	 * @covers Monolog\Handler\ProcessHandler::startProcess
-	 * @covers Monolog\Handler\ProcessHandler::handleStartupErrors
-	 */
-	public function testWriteOpensProcessAndWritesToStdInOfProcess()
-	{
-		$fixtures = array(
-			'chuck norris',
-			'foobar1337'
-		);
-
-		$mockBuilder = $this->getMockBuilder('Monolog\Handler\ProcessHandler');
-		$mockBuilder->setMethods(array('writeProcessInput'));
-		// using echo as command, as it is most probably available
-		$mockBuilder->setConstructorArgs(array(self::DUMMY_COMMAND));
-
-		$handler = $mockBuilder->getMock();
-
-		$handler->expects($this->exactly(2))
-			->method('writeProcessInput')
-			->withConsecutive($this->stringContains($fixtures[0]), $this->stringContains($fixtures[1]));
-
-		/** @var ProcessHandler $handler */
-		$handler->handle($this->getRecord(Logger::WARNING, $fixtures[0]));
-		$handler->handle($this->getRecord(Logger::ERROR, $fixtures[1]));
-	}
-
-	/**
-	 * Data provider for invalid commands.
-	 *
-	 * @return array
-	 */
-	public function invalidCommandProvider()
-	{
-		return [
-			[1337],
-			[''],
-			[null],
-			[fopen('php://input', 'r')],
-		];
-	}
-
-	/**
-	 * @dataProvider invalidCommandProvider
-	 * @param mixed $invalidCommand
-	 * @covers Monolog\Handler\ProcessHandler::guardAgainstInvalidCommand
-	 */
-	public function testConstructWithInvalidCommandThrowsInvalidArgumentException($invalidCommand)
-	{
-		$this->setExpectedException('\InvalidArgumentException');
-		new ProcessHandler($invalidCommand, Logger::DEBUG);
-	}
-
-	/**
-	 * Data provider for invalid CWDs.
-	 *
-	 * @return array
-	 */
-	public function invalidCwdProvider()
-	{
-		return [
-			[1337],
-			[''],
-			[fopen('php://input', 'r')],
-		];
-	}
-
-	/**
-	 * @dataProvider invalidCwdProvider
-	 * @param mixed $invalidCwd
-	 * @covers Monolog\Handler\ProcessHandler::guardAgainstInvalidCwd
-	 */
-	public function testConstructWithInvalidCwdThrowsInvalidArgumentException($invalidCwd)
-	{
-		$this->setExpectedException('\InvalidArgumentException');
-		new ProcessHandler(self::DUMMY_COMMAND, Logger::DEBUG, true, $invalidCwd);
-	}
-
-	/**
-	 * @covers Monolog\Handler\ProcessHandler::__construct
-	 * @covers Monolog\Handler\ProcessHandler::guardAgainstInvalidCwd
-	 */
-	public function testConstructWithValidCwdWorks()
-	{
-		$handler = new ProcessHandler(self::DUMMY_COMMAND, Logger::DEBUG, true, sys_get_temp_dir());
-		$this->assertInstanceOf(
-			'Monolog\Handler\ProcessHandler',
-			$handler,
-			'Constructed handler is not a ProcessHandler.'
-		);
-	}
-
-	/**
-	 * @covers Monolog\Handler\ProcessHandler::handleStartupErrors
-	 */
-	public function testStartupWithFailingToSelectErrorStreamThrowsUnexpectedValueException()
-	{
-		$mockBuilder = $this->getMockBuilder('Monolog\Handler\ProcessHandler');
-		$mockBuilder->setMethods(array('selectErrorStream'));
-		$mockBuilder->setConstructorArgs(array(self::DUMMY_COMMAND));
-
-		$handler = $mockBuilder->getMock();
-
-		$handler->expects($this->once())
-			->method('selectErrorStream')
-			->will($this->returnValue(false));
-
-		$this->setExpectedException('\UnexpectedValueException');
-		/** @var ProcessHandler $handler */
-		$handler->handle($this->getRecord(Logger::WARNING, 'stream failing, whoops'));
-	}
-
-	/**
-	 * @covers Monolog\Handler\ProcessHandler::handleStartupErrors
-	 * @covers Monolog\Handler\ProcessHandler::selectErrorStream
-	 */
-	public function testStartupWithErrorsThrowsUnexpectedValueException()
-	{
-		$handler = new ProcessHandler('>&2 echo "some fake error message"');
-		$this->setExpectedException('\UnexpectedValueException');
-		$handler->handle($this->getRecord(Logger::WARNING, 'some warning in the house'));
-	}
-
-	/**
-	 * @covers Monolog\Handler\ProcessHandler::write
-	 */
-	public function testWritingWithErrorsOnStdOutOfProcessThrowsInvalidArgumentException()
-	{
-		$mockBuilder = $this->getMockBuilder('Monolog\Handler\ProcessHandler');
-		$mockBuilder->setMethods(array('readProcessErrors'));
-		// using echo as command, as it is most probably available
-		$mockBuilder->setConstructorArgs(array(self::DUMMY_COMMAND));
-
-		$handler = $mockBuilder->getMock();
-
-		$handler->expects($this->exactly(2))
-			->method('readProcessErrors')
-			->willReturnOnConsecutiveCalls('', $this->returnValue('some fake error message here'));
-
-		$this->setExpectedException('\UnexpectedValueException');
-		/** @var ProcessHandler $handler */
-		$handler->handle($this->getRecord(Logger::WARNING, 'some test stuff'));
-	}
-
-	/**
-	 * @covers Monolog\Handler\ProcessHandler::close
-	 */
-	public function testCloseClosesProcess()
-	{
-		$class = new \ReflectionClass('Monolog\Handler\ProcessHandler');
-		$property = $class->getProperty('process');
-		$property->setAccessible(true);
-
-		$handler = new ProcessHandler(self::DUMMY_COMMAND);
-		$handler->handle($this->getRecord(Logger::WARNING, '21 is only the half truth'));
-
-		$process = $property->getValue($handler);
-		$this->assertTrue(is_resource($process), 'Process is not running although it should.');
-
-		$handler->close();
-
-		$process = $property->getValue($handler);
-		$this->assertFalse(is_resource($process), 'Process is still running although it should not.');
-	}
+    /**
+     * Dummy command to be used by tests that should not fail due to the command.
+     *
+     * @var string
+     */
+    const DUMMY_COMMAND = 'echo';
+
+    /**
+     * @covers Monolog\Handler\ProcessHandler::__construct
+     * @covers Monolog\Handler\ProcessHandler::guardAgainstInvalidCommand
+     * @covers Monolog\Handler\ProcessHandler::guardAgainstInvalidCwd
+     * @covers Monolog\Handler\ProcessHandler::write
+     * @covers Monolog\Handler\ProcessHandler::ensureProcessIsStarted
+     * @covers Monolog\Handler\ProcessHandler::startProcess
+     * @covers Monolog\Handler\ProcessHandler::handleStartupErrors
+     */
+    public function testWriteOpensProcessAndWritesToStdInOfProcess()
+    {
+        $fixtures = array(
+            'chuck norris',
+            'foobar1337'
+        );
+
+        $mockBuilder = $this->getMockBuilder('Monolog\Handler\ProcessHandler');
+        $mockBuilder->setMethods(array('writeProcessInput'));
+        // using echo as command, as it is most probably available
+        $mockBuilder->setConstructorArgs(array(self::DUMMY_COMMAND));
+
+        $handler = $mockBuilder->getMock();
+
+        $handler->expects($this->exactly(2))
+            ->method('writeProcessInput')
+            ->withConsecutive($this->stringContains($fixtures[0]), $this->stringContains($fixtures[1]));
+
+        /** @var ProcessHandler $handler */
+        $handler->handle($this->getRecord(Logger::WARNING, $fixtures[0]));
+        $handler->handle($this->getRecord(Logger::ERROR, $fixtures[1]));
+    }
+
+    /**
+     * Data provider for invalid commands.
+     *
+     * @return array
+     */
+    public function invalidCommandProvider()
+    {
+        return [
+            [1337],
+            [''],
+            [null],
+            [fopen('php://input', 'r')],
+        ];
+    }
+
+    /**
+     * @dataProvider invalidCommandProvider
+     * @param mixed $invalidCommand
+     * @covers Monolog\Handler\ProcessHandler::guardAgainstInvalidCommand
+     */
+    public function testConstructWithInvalidCommandThrowsInvalidArgumentException($invalidCommand)
+    {
+        $this->setExpectedException('\InvalidArgumentException');
+        new ProcessHandler($invalidCommand, Logger::DEBUG);
+    }
+
+    /**
+     * Data provider for invalid CWDs.
+     *
+     * @return array
+     */
+    public function invalidCwdProvider()
+    {
+        return [
+            [1337],
+            [''],
+            [fopen('php://input', 'r')],
+        ];
+    }
+
+    /**
+     * @dataProvider invalidCwdProvider
+     * @param mixed $invalidCwd
+     * @covers Monolog\Handler\ProcessHandler::guardAgainstInvalidCwd
+     */
+    public function testConstructWithInvalidCwdThrowsInvalidArgumentException($invalidCwd)
+    {
+        $this->setExpectedException('\InvalidArgumentException');
+        new ProcessHandler(self::DUMMY_COMMAND, Logger::DEBUG, true, $invalidCwd);
+    }
+
+    /**
+     * @covers Monolog\Handler\ProcessHandler::__construct
+     * @covers Monolog\Handler\ProcessHandler::guardAgainstInvalidCwd
+     */
+    public function testConstructWithValidCwdWorks()
+    {
+        $handler = new ProcessHandler(self::DUMMY_COMMAND, Logger::DEBUG, true, sys_get_temp_dir());
+        $this->assertInstanceOf(
+            'Monolog\Handler\ProcessHandler',
+            $handler,
+            'Constructed handler is not a ProcessHandler.'
+        );
+    }
+
+    /**
+     * @covers Monolog\Handler\ProcessHandler::handleStartupErrors
+     */
+    public function testStartupWithFailingToSelectErrorStreamThrowsUnexpectedValueException()
+    {
+        $mockBuilder = $this->getMockBuilder('Monolog\Handler\ProcessHandler');
+        $mockBuilder->setMethods(array('selectErrorStream'));
+        $mockBuilder->setConstructorArgs(array(self::DUMMY_COMMAND));
+
+        $handler = $mockBuilder->getMock();
+
+        $handler->expects($this->once())
+            ->method('selectErrorStream')
+            ->will($this->returnValue(false));
+
+        $this->setExpectedException('\UnexpectedValueException');
+        /** @var ProcessHandler $handler */
+        $handler->handle($this->getRecord(Logger::WARNING, 'stream failing, whoops'));
+    }
+
+    /**
+     * @covers Monolog\Handler\ProcessHandler::handleStartupErrors
+     * @covers Monolog\Handler\ProcessHandler::selectErrorStream
+     */
+    public function testStartupWithErrorsThrowsUnexpectedValueException()
+    {
+        $handler = new ProcessHandler('>&2 echo "some fake error message"');
+        $this->setExpectedException('\UnexpectedValueException');
+        $handler->handle($this->getRecord(Logger::WARNING, 'some warning in the house'));
+    }
+
+    /**
+     * @covers Monolog\Handler\ProcessHandler::write
+     */
+    public function testWritingWithErrorsOnStdOutOfProcessThrowsInvalidArgumentException()
+    {
+        $mockBuilder = $this->getMockBuilder('Monolog\Handler\ProcessHandler');
+        $mockBuilder->setMethods(array('readProcessErrors'));
+        // using echo as command, as it is most probably available
+        $mockBuilder->setConstructorArgs(array(self::DUMMY_COMMAND));
+
+        $handler = $mockBuilder->getMock();
+
+        $handler->expects($this->exactly(2))
+            ->method('readProcessErrors')
+            ->willReturnOnConsecutiveCalls('', $this->returnValue('some fake error message here'));
+
+        $this->setExpectedException('\UnexpectedValueException');
+        /** @var ProcessHandler $handler */
+        $handler->handle($this->getRecord(Logger::WARNING, 'some test stuff'));
+    }
+
+    /**
+     * @covers Monolog\Handler\ProcessHandler::close
+     */
+    public function testCloseClosesProcess()
+    {
+        $class = new \ReflectionClass('Monolog\Handler\ProcessHandler');
+        $property = $class->getProperty('process');
+        $property->setAccessible(true);
+
+        $handler = new ProcessHandler(self::DUMMY_COMMAND);
+        $handler->handle($this->getRecord(Logger::WARNING, '21 is only the half truth'));
+
+        $process = $property->getValue($handler);
+        $this->assertTrue(is_resource($process), 'Process is not running although it should.');
+
+        $handler->close();
+
+        $process = $property->getValue($handler);
+        $this->assertFalse(is_resource($process), 'Process is still running although it should not.');
+    }
 }