diff --git a/.travis.yml b/.travis.yml index 315cbf56..1930e55c 100644 --- a/.travis.yml +++ b/.travis.yml @@ -17,4 +17,4 @@ before_script: - if [ "$deps" == "low" ]; then composer update --prefer-source --prefer-lowest --prefer-stable; fi - if [ "$deps" != "low" ]; then composer install --prefer-source; fi -script: vendor/bin/phpunit --debug +script: composer test diff --git a/composer.json b/composer.json index d298fb65..a55d1a44 100644 --- a/composer.json +++ b/composer.json @@ -27,7 +27,6 @@ "swiftmailer/swiftmailer": "~5.3", "php-console/php-console": "^3.1.3", "jakub-onderka/php-parallel-lint": "^0.9", - "symfony/process": "^3.1", "predis/predis": "^1.1", "phpspec/prophecy": "^1.6.1" }, diff --git a/tests/Monolog/Handler/AmqpHandlerTest.php b/tests/Monolog/Handler/AmqpHandlerTest.php index 2ee9ba1e..680de290 100644 --- a/tests/Monolog/Handler/AmqpHandlerTest.php +++ b/tests/Monolog/Handler/AmqpHandlerTest.php @@ -33,7 +33,11 @@ class AmqpHandlerTest extends TestCase $messages = []; - $exchange = $this->createMock('AMQPExchange', ['publish', 'setName'], [], '', false); + $exchange = $this->getMockBuilder('AMQPExchange') + ->setMethods(['publish', 'setName']) + ->disableOriginalConstructor() + ->getMock(); + $exchange->expects($this->any()) ->method('publish') ->will($this->returnCallback(function ($message, $routing_key, $flags = 0, $attributes = []) use (&$messages) { @@ -81,7 +85,10 @@ class AmqpHandlerTest extends TestCase $messages = []; - $exchange = $this->createMock('PhpAmqpLib\Channel\AMQPChannel', ['basic_publish', '__destruct'], [], '', false); + $exchange = $this->getMockBuilder('PhpAmqpLib\Channel\AMQPChannel') + ->setMethods(['basic_publish', '__destruct']) + ->disableOriginalConstructor() + ->getMock(); $exchange->expects($this->any()) ->method('basic_publish') diff --git a/tests/Monolog/Handler/DynamoDbHandlerTest.php b/tests/Monolog/Handler/DynamoDbHandlerTest.php index d6554247..d29f6e8a 100644 --- a/tests/Monolog/Handler/DynamoDbHandlerTest.php +++ b/tests/Monolog/Handler/DynamoDbHandlerTest.php @@ -25,7 +25,8 @@ class DynamoDbHandlerTest extends TestCase $this->client = $this->getMockBuilder('Aws\DynamoDb\DynamoDbClient') ->setMethods(['formatAttributes', '__call']) - ->disableOriginalConstructor()->getMock(); + ->disableOriginalConstructor() + ->getMock(); } public function testConstruct() diff --git a/tests/Monolog/Handler/FlowdockHandlerTest.php b/tests/Monolog/Handler/FlowdockHandlerTest.php index 742d8081..d8e1b991 100644 --- a/tests/Monolog/Handler/FlowdockHandlerTest.php +++ b/tests/Monolog/Handler/FlowdockHandlerTest.php @@ -14,7 +14,6 @@ namespace Monolog\Handler; use Monolog\Formatter\FlowdockFormatter; use Monolog\Test\TestCase; use Monolog\Logger; -use Monolog\Util\LocalSocket; /** * @author Dominik Liebler @@ -41,9 +40,10 @@ class FlowdockHandlerTest extends TestCase public function testWriteHeader() { - $this->initHandlerAndSocket(); + $this->createHandler(); $this->handler->handle($this->getRecord(Logger::CRITICAL, 'test1')); - $content = $this->socket->getOutput(); + fseek($this->res, 0); + $content = fread($this->res, 1024); $this->assertRegexp('/POST \/v1\/messages\/team_inbox\/.* HTTP\/1.1\\r\\nHost: api.flowdock.com\\r\\nContent-Type: application\/json\\r\\nContent-Length: \d{2,4}\\r\\n\\r\\n/', $content); @@ -53,27 +53,35 @@ class FlowdockHandlerTest extends TestCase /** * @depends testWriteHeader */ - public function testWriteContent(string $content) + public function testWriteContent($content) { $this->assertRegexp('/"source":"test_source"/', $content); $this->assertRegexp('/"from_address":"source@test\.com"/', $content); } - - private function initHandlerAndSocket($token = 'myToken') + private function createHandler($token = 'myToken') { - $this->socket = LocalSocket::initSocket(); - $this->handler = new FlowdockHandler($token); + $constructorArgs = [$token, Logger::DEBUG]; + $this->res = fopen('php://memory', 'a'); + $this->handler = $this->getMockBuilder('Monolog\Handler\FlowdockHandler') + ->setConstructorArgs($constructorArgs) + ->setMethods(['fsockopen', 'streamSetTimeout', 'closeSocket']) + ->getMock(); $reflectionProperty = new \ReflectionProperty('\Monolog\Handler\SocketHandler', 'connectionString'); $reflectionProperty->setAccessible(true); - $reflectionProperty->setValue($this->handler, '127.0.0.1:51984'); + $reflectionProperty->setValue($this->handler, 'localhost:1234'); + + $this->handler->expects($this->any()) + ->method('fsockopen') + ->will($this->returnValue($this->res)); + $this->handler->expects($this->any()) + ->method('streamSetTimeout') + ->will($this->returnValue(true)); + $this->handler->expects($this->any()) + ->method('closeSocket') + ->will($this->returnValue(true)); $this->handler->setFormatter(new FlowdockFormatter('test_source', 'source@test.com')); } - - public function tearDown() - { - unset($this->socket, $this->handler); - } } diff --git a/tests/Monolog/Handler/GelfHandlerTest.php b/tests/Monolog/Handler/GelfHandlerTest.php index 6e38ce61..12e5f8b1 100644 --- a/tests/Monolog/Handler/GelfHandlerTest.php +++ b/tests/Monolog/Handler/GelfHandlerTest.php @@ -43,7 +43,10 @@ class GelfHandlerTest extends TestCase protected function getMessagePublisher() { - return $this->createMock('Gelf\Publisher', ['publish'], [], '', false); + return $this->getMockBuilder('Gelf\Publisher') + ->setMethods(['publish']) + ->disableOriginalConstructor() + ->getMock(); } public function testDebug() diff --git a/tests/Monolog/Handler/HipChatHandlerTest.php b/tests/Monolog/Handler/HipChatHandlerTest.php index 4e24af33..6eefd27d 100644 --- a/tests/Monolog/Handler/HipChatHandlerTest.php +++ b/tests/Monolog/Handler/HipChatHandlerTest.php @@ -13,7 +13,6 @@ namespace Monolog\Handler; use Monolog\Test\TestCase; use Monolog\Logger; -use Monolog\Util\LocalSocket; /** * @author Rafael Dohms @@ -27,15 +26,56 @@ class HipChatHandlerTest extends TestCase public function testWriteV2() { - $this->initHandlerAndSocket('myToken', 'room1', 'Monolog', false, 'hipchat.foo.bar', 'v2'); + $this->createHandler('myToken', 'room1', 'Monolog', false, 'hipchat.foo.bar', 'v2'); $this->handler->handle($this->getRecord(Logger::CRITICAL, 'test1')); - $content = $this->socket->getOutput(); + fseek($this->res, 0); + $content = fread($this->res, 1024); $this->assertRegexp('{POST /v2/room/room1/notification\?auth_token=.* HTTP/1.1\\r\\nHost: hipchat.foo.bar\\r\\nContent-Type: application/x-www-form-urlencoded\\r\\nContent-Length: \d{2,4}\\r\\n\\r\\n}', $content); return $content; } + public function testWriteV2Notify() + { + $this->createHandler('myToken', 'room1', 'Monolog', true, 'hipchat.foo.bar', 'v2'); + $this->handler->handle($this->getRecord(Logger::CRITICAL, 'test1')); + fseek($this->res, 0); + $content = fread($this->res, 1024); + + $this->assertRegexp('{POST /v2/room/room1/notification\?auth_token=.* HTTP/1.1\\r\\nHost: hipchat.foo.bar\\r\\nContent-Type: application/x-www-form-urlencoded\\r\\nContent-Length: \d{2,4}\\r\\n\\r\\n}', $content); + + return $content; + } + + public function testRoomSpaces() + { + $this->createHandler('myToken', 'room name', 'Monolog', false, 'hipchat.foo.bar', 'v2'); + $this->handler->handle($this->getRecord(Logger::CRITICAL, 'test1')); + fseek($this->res, 0); + $content = fread($this->res, 1024); + + $this->assertRegexp('{POST /v2/room/room%20name/notification\?auth_token=.* HTTP/1.1\\r\\nHost: hipchat.foo.bar\\r\\nContent-Type: application/x-www-form-urlencoded\\r\\nContent-Length: \d{2,4}\\r\\n\\r\\n}', $content); + + return $content; + } + + /** + * @depends testWriteHeader + */ + public function testWriteContent($content) + { + $this->assertRegexp('/notify=0&message=test1&message_format=text&color=red&room_id=room1&from=Monolog$/', $content); + } + + /** + * @depends testWriteCustomHostHeader + */ + public function testWriteContentNotify($content) + { + $this->assertRegexp('/notify=1&message=test1&message_format=text&color=red&room_id=room1&from=Monolog$/', $content); + } + /** * @depends testWriteV2 */ @@ -44,17 +84,6 @@ class HipChatHandlerTest extends TestCase $this->assertRegexp('/notify=false&message=test1&message_format=text&color=red&from=Monolog$/', $content); } - public function testWriteV2Notify() - { - $this->initHandlerAndSocket('myToken', 'room2', 'Monolog', true, 'hipchat.foo.bar', 'v2'); - $this->handler->handle($this->getRecord(Logger::CRITICAL, 'test1')); - $content = $this->socket->getOutput(); - - $this->assertRegexp('{POST /v2/room/room2/notification\?auth_token=.* HTTP/1.1\\r\\nHost: hipchat.foo.bar\\r\\nContent-Type: application/x-www-form-urlencoded\\r\\nContent-Length: \d{2,4}\\r\\n\\r\\n}', $content); - - return $content; - } - /** * @depends testWriteV2Notify */ @@ -63,22 +92,12 @@ class HipChatHandlerTest extends TestCase $this->assertRegexp('/notify=true&message=test1&message_format=text&color=red&from=Monolog$/', $content); } - public function testRoomSpaces() - { - $this->initHandlerAndSocket('myToken', 'room name', 'Monolog', false, 'hipchat.foo.bar', 'v2'); - $this->handler->handle($this->getRecord(Logger::CRITICAL, 'test1')); - $content = $this->socket->getOutput(); - - $this->assertRegexp('{POST /v2/room/room%20name/notification\?auth_token=.* HTTP/1.1\\r\\nHost: hipchat.foo.bar\\r\\nContent-Type: application/x-www-form-urlencoded\\r\\nContent-Length: \d{2,4}\\r\\n\\r\\n}', $content); - - return $content; - } - public function testWriteContentV2WithoutName() { - $this->initHandlerAndSocket('myToken', 'room1', null, false, 'hipchat.foo.bar', 'v2'); + $this->createHandler('myToken', 'room1', null, false, 'hipchat.foo.bar', 'v2'); $this->handler->handle($this->getRecord(Logger::CRITICAL, 'test1')); - $content = $this->socket->getOutput(); + fseek($this->res, 0); + $content = fread($this->res, 1024); $this->assertRegexp('/notify=false&message=test1&message_format=text&color=red$/', $content); @@ -87,19 +106,21 @@ class HipChatHandlerTest extends TestCase public function testWriteWithComplexMessage() { - $this->initHandlerAndSocket(); + $this->createHandler(); $this->handler->handle($this->getRecord(Logger::CRITICAL, 'Backup of database "example" finished in 16 minutes.')); + fseek($this->res, 0); + $content = fread($this->res, 1024); - $content = $this->socket->getOutput(); $this->assertRegexp('/message=Backup\+of\+database\+%22example%22\+finished\+in\+16\+minutes\./', $content); } public function testWriteTruncatesLongMessage() { - $this->initHandlerAndSocket(); + $this->createHandler(); $this->handler->handle($this->getRecord(Logger::CRITICAL, str_repeat('abcde', 2000))); + fseek($this->res, 0); + $content = fread($this->res, 12000); - $content = $this->socket->getOutput(); $this->assertRegexp('/message='.str_repeat('abcde', 1900).'\+%5Btruncated%5D/', $content); } @@ -108,10 +129,11 @@ class HipChatHandlerTest extends TestCase */ public function testWriteWithErrorLevelsAndColors($level, $expectedColor) { - $this->initHandlerAndSocket(); + $this->createHandler(); $this->handler->handle($this->getRecord($level, 'Backup of database "example" finished in 16 minutes.')); + fseek($this->res, 0); + $content = fread($this->res, 1024); - $content = $this->socket->getOutput(); $this->assertRegexp('/color='.$expectedColor.'/', $content); } @@ -134,10 +156,13 @@ class HipChatHandlerTest extends TestCase */ public function testHandleBatch($records, $expectedColor) { - $this->initHandlerAndSocket(); + $this->createHandler(); + $this->handler->handleBatch($records); - $content = $this->socket->getOutput(); + fseek($this->res, 0); + $content = fread($this->res, 1024); + $this->assertRegexp('/color='.$expectedColor.'/', $content); } @@ -175,26 +200,35 @@ class HipChatHandlerTest extends TestCase ]; } + private function createHandler($token = 'myToken', $room = 'room1', $name = 'Monolog', $notify = false, $host = 'api.hipchat.com', $version = 'v1') + { + $constructorArgs = [$token, $room, $name, $notify, Logger::DEBUG, true, true, 'text', $host, $version]; + $this->res = fopen('php://memory', 'a'); + $this->handler = $this->getMockBuilder('Monolog\Handler\HipChatHandler') + ->setConstructorArgs($constructorArgs) + ->setMethods(['fsockopen', 'streamSetTimeout', 'closeSocket']) + ->getMock(); + + $reflectionProperty = new \ReflectionProperty('\Monolog\Handler\SocketHandler', 'connectionString'); + $reflectionProperty->setAccessible(true); + $reflectionProperty->setValue($this->handler, 'localhost:1234'); + + $this->handler->expects($this->any()) + ->method('fsockopen') + ->will($this->returnValue($this->res)); + $this->handler->expects($this->any()) + ->method('streamSetTimeout') + ->will($this->returnValue(true)); + $this->handler->expects($this->any()) + ->method('closeSocket') + ->will($this->returnValue(true)); + + $this->handler->setFormatter($this->getIdentityFormatter()); + } + public function testCreateWithTooLongNameV2() { // creating a handler with too long of a name but using the v2 api doesn't matter. $hipChatHandler = new HipChatHandler('token', 'room', 'SixteenCharsHere', false, Logger::CRITICAL, true, true, 'test', 'api.hipchat.com', 'v2'); } - - private function initHandlerAndSocket($token = 'myToken', $room = 'room1', $name = 'Monolog', $notify = false, $host = 'api.hipchat.com', $version = 'v1') - { - $this->socket = LocalSocket::initSocket(); - $this->handler = new HipChatHandler($token, $room, $name, $notify, Logger::DEBUG, true, true, 'text', $host, $version); - - $reflectionProperty = new \ReflectionProperty('\Monolog\Handler\SocketHandler', 'connectionString'); - $reflectionProperty->setAccessible(true); - $reflectionProperty->setValue($this->handler, '127.0.0.1:51984'); - - $this->handler->setFormatter($this->getIdentityFormatter()); - } - - public function tearDown() - { - unset($this->socket, $this->handler); - } } diff --git a/tests/Monolog/Handler/LogEntriesHandlerTest.php b/tests/Monolog/Handler/LogEntriesHandlerTest.php index ce0df94e..d4f920ea 100644 --- a/tests/Monolog/Handler/LogEntriesHandlerTest.php +++ b/tests/Monolog/Handler/LogEntriesHandlerTest.php @@ -13,7 +13,6 @@ namespace Monolog\Handler; use Monolog\Test\TestCase; use Monolog\Logger; -use Monolog\Util\LocalSocket; /** * @author Robert Kaufmann III @@ -32,10 +31,12 @@ class LogEntriesHandlerTest extends TestCase public function testWriteContent() { - $this->initHandlerAndSocket(); + $this->createHandler(); $this->handler->handle($this->getRecord(Logger::CRITICAL, 'Critical write test')); - $content = $this->socket->getOutput(); + fseek($this->res, 0); + $content = fread($this->res, 1024); + $this->assertRegexp('/testToken \[\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}\.\d{6}\+00:00\] test.CRITICAL: Critical write test/', $content); } @@ -46,27 +47,37 @@ class LogEntriesHandlerTest extends TestCase $this->getRecord(), $this->getRecord(), ]; - $this->initHandlerAndSocket(); + $this->createHandler(); $this->handler->handleBatch($records); - $content = $this->socket->getOutput(); + fseek($this->res, 0); + $content = fread($this->res, 1024); + $this->assertRegexp('/(testToken \[\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}\.\d{6}\+00:00\] .* \[\] \[\]\n){3}/', $content); } - private function initHandlerAndSocket() + private function createHandler() { - $this->socket = LocalSocket::initSocket(); - $useSSL = extension_loaded('openssl'); - $this->handler = new LogEntriesHandler('testToken', $useSSL, Logger::DEBUG, true); + $args = ['testToken', $useSSL, Logger::DEBUG, true]; + $this->res = fopen('php://memory', 'a'); + $this->handler = $this->getMockBuilder('Monolog\Handler\LogEntriesHandler') + ->setConstructorArgs($args) + ->setMethods(['fsockopen', 'streamSetTimeout', 'closeSocket']) + ->getMock(); $reflectionProperty = new \ReflectionProperty('\Monolog\Handler\SocketHandler', 'connectionString'); $reflectionProperty->setAccessible(true); - $reflectionProperty->setValue($this->handler, '127.0.0.1:51984'); - } + $reflectionProperty->setValue($this->handler, 'localhost:1234'); - public function tearDown() - { - unset($this->socket, $this->handler); + $this->handler->expects($this->any()) + ->method('fsockopen') + ->will($this->returnValue($this->res)); + $this->handler->expects($this->any()) + ->method('streamSetTimeout') + ->will($this->returnValue(true)); + $this->handler->expects($this->any()) + ->method('closeSocket') + ->will($this->returnValue(true)); } } diff --git a/tests/Monolog/Handler/LogmaticHandlerTest.php b/tests/Monolog/Handler/LogmaticHandlerTest.php index b667a218..71b87d03 100644 --- a/tests/Monolog/Handler/LogmaticHandlerTest.php +++ b/tests/Monolog/Handler/LogmaticHandlerTest.php @@ -13,7 +13,6 @@ namespace Monolog\Handler; use Monolog\Test\TestCase; use Monolog\Logger; -use Monolog\Util\LocalSocket; /** * @author Julien Breux @@ -32,10 +31,11 @@ class LogmaticHandlerTest extends TestCase public function testWriteContent() { - $this->initHandlerAndSocket(); + $this->createHandler(); $this->handler->handle($this->getRecord(Logger::CRITICAL, 'Critical write test')); - $content = $this->socket->getOutput(); + fseek($this->res, 0); + $content = fread($this->res, 1024); $this->assertRegexp('/testToken {"message":"Critical write test","context":\[\],"level":500,"level_name":"CRITICAL","channel":"test","datetime":"(.*)","extra":\[\],"hostname":"testHostname","appname":"testAppname"}/', $content); } @@ -47,28 +47,37 @@ class LogmaticHandlerTest extends TestCase $this->getRecord(), $this->getRecord(), ]; - $this->initHandlerAndSocket(); + $this->createHandler(); $this->handler->handleBatch($records); - $content = $this->socket->getOutput(); + fseek($this->res, 0); + $content = fread($this->res, 1024); $this->assertRegexp('/testToken {"message":"test","context":\[\],"level":300,"level_name":"WARNING","channel":"test","datetime":"(.*)","extra":\[\],"hostname":"testHostname","appname":"testAppname"}/', $content); } - private function initHandlerAndSocket() + private function createHandler() { - $this->socket = LocalSocket::initSocket(); - $useSSL = extension_loaded('openssl'); - $this->handler = new LogmaticHandler('testToken', 'testHostname', 'testAppname', $useSSL, Logger::DEBUG, true); + $args = ['testToken', 'testHostname', 'testAppname', $useSSL, Logger::DEBUG, true]; + $this->res = fopen('php://memory', 'a'); + $this->handler = $this->getMockBuilder('Monolog\Handler\LogmaticHandler') + ->setConstructorArgs($args) + ->setMethods(['fsockopen', 'streamSetTimeout', 'closeSocket']) + ->getMock(); $reflectionProperty = new \ReflectionProperty('\Monolog\Handler\SocketHandler', 'connectionString'); $reflectionProperty->setAccessible(true); - $reflectionProperty->setValue($this->handler, '127.0.0.1:51984'); - } + $reflectionProperty->setValue($this->handler, 'localhost:1234'); - public function tearDown() - { - unset($this->socket, $this->handler); + $this->handler->expects($this->any()) + ->method('fsockopen') + ->will($this->returnValue($this->res)); + $this->handler->expects($this->any()) + ->method('streamSetTimeout') + ->will($this->returnValue(true)); + $this->handler->expects($this->any()) + ->method('closeSocket') + ->will($this->returnValue(true)); } } diff --git a/tests/Monolog/Handler/PushoverHandlerTest.php b/tests/Monolog/Handler/PushoverHandlerTest.php index 7ac995dc..6c11a01f 100644 --- a/tests/Monolog/Handler/PushoverHandlerTest.php +++ b/tests/Monolog/Handler/PushoverHandlerTest.php @@ -13,7 +13,6 @@ namespace Monolog\Handler; use Monolog\Test\TestCase; use Monolog\Logger; -use Monolog\Util\LocalSocket; /** * Almost all examples (expected header, titles, messages) taken from @@ -28,10 +27,11 @@ class PushoverHandlerTest extends TestCase public function testWriteHeader() { - $this->initHandlerAndSocket(); + $this->createHandler(); $this->handler->setHighPriorityLevel(Logger::EMERGENCY); // skip priority notifications $this->handler->handle($this->getRecord(Logger::CRITICAL, 'test1')); - $content = $this->socket->getOutput(); + fseek($this->res, 0); + $content = fread($this->res, 1024); $this->assertRegexp('/POST \/1\/messages.json HTTP\/1.1\\r\\nHost: api.pushover.net\\r\\nContent-Type: application\/x-www-form-urlencoded\\r\\nContent-Length: \d{2,4}\\r\\n\\r\\n/', $content); @@ -48,19 +48,21 @@ class PushoverHandlerTest extends TestCase public function testWriteWithComplexTitle() { - $this->initHandlerAndSocket('myToken', 'myUser', 'Backup finished - SQL1'); + $this->createHandler('myToken', 'myUser', 'Backup finished - SQL1'); $this->handler->handle($this->getRecord(Logger::CRITICAL, 'test1')); - $content = $this->socket->getOutput(); + fseek($this->res, 0); + $content = fread($this->res, 1024); $this->assertRegexp('/title=Backup\+finished\+-\+SQL1/', $content); } public function testWriteWithComplexMessage() { - $this->initHandlerAndSocket(); + $this->createHandler(); $this->handler->setHighPriorityLevel(Logger::EMERGENCY); // skip priority notifications $this->handler->handle($this->getRecord(Logger::CRITICAL, 'Backup of database "example" finished in 16 minutes.')); - $content = $this->socket->getOutput(); + fseek($this->res, 0); + $content = fread($this->res, 1024); $this->assertRegexp('/message=Backup\+of\+database\+%22example%22\+finished\+in\+16\+minutes\./', $content); } @@ -68,10 +70,11 @@ class PushoverHandlerTest extends TestCase public function testWriteWithTooLongMessage() { $message = str_pad('test', 520, 'a'); - $this->initHandlerAndSocket(); + $this->createHandler(); $this->handler->setHighPriorityLevel(Logger::EMERGENCY); // skip priority notifications $this->handler->handle($this->getRecord(Logger::CRITICAL, $message)); - $content = $this->socket->getOutput(); + fseek($this->res, 0); + $content = fread($this->res, 1024); $expectedMessage = substr($message, 0, 505); @@ -80,48 +83,58 @@ class PushoverHandlerTest extends TestCase public function testWriteWithHighPriority() { - $this->initHandlerAndSocket(); + $this->createHandler(); $this->handler->handle($this->getRecord(Logger::CRITICAL, 'test1')); - $content = $this->socket->getOutput(); + fseek($this->res, 0); + $content = fread($this->res, 1024); $this->assertRegexp('/token=myToken&user=myUser&message=test1&title=Monolog×tamp=\d{10}&priority=1$/', $content); } public function testWriteWithEmergencyPriority() { - $this->initHandlerAndSocket(); + $this->createHandler(); $this->handler->handle($this->getRecord(Logger::EMERGENCY, 'test1')); - $content = $this->socket->getOutput(); + fseek($this->res, 0); + $content = fread($this->res, 1024); $this->assertRegexp('/token=myToken&user=myUser&message=test1&title=Monolog×tamp=\d{10}&priority=2&retry=30&expire=25200$/', $content); } public function testWriteToMultipleUsers() { - $this->markTestIncomplete('LocalSocket buffer does not support multiple-connections'); - - $this->initHandlerAndSocket('myToken', ['userA', 'userB']); + $this->createHandler('myToken', ['userA', 'userB']); $this->handler->handle($this->getRecord(Logger::EMERGENCY, 'test1')); - $content = $this->socket->getOutput(); + fseek($this->res, 0); + $content = fread($this->res, 1024); $this->assertRegexp('/token=myToken&user=userA&message=test1&title=Monolog×tamp=\d{10}&priority=2&retry=30&expire=25200POST/', $content); $this->assertRegexp('/token=myToken&user=userB&message=test1&title=Monolog×tamp=\d{10}&priority=2&retry=30&expire=25200$/', $content); } - private function initHandlerAndSocket($token = 'myToken', $user = 'myUser', $title = 'Monolog') + private function createHandler($token = 'myToken', $user = 'myUser', $title = 'Monolog') { - $this->socket = LocalSocket::initSocket(); - $this->handler = new PushoverHandler($token, $user, $title); + $constructorArgs = [$token, $user, $title]; + $this->res = fopen('php://memory', 'a'); + $this->handler = $this->getMockBuilder('Monolog\Handler\PushoverHandler') + ->setConstructorArgs($constructorArgs) + ->setMethods(['fsockopen', 'streamSetTimeout', 'closeSocket']) + ->getMock(); $reflectionProperty = new \ReflectionProperty('\Monolog\Handler\SocketHandler', 'connectionString'); $reflectionProperty->setAccessible(true); - $reflectionProperty->setValue($this->handler, '127.0.0.1:51984'); + $reflectionProperty->setValue($this->handler, 'localhost:1234'); + + $this->handler->expects($this->any()) + ->method('fsockopen') + ->will($this->returnValue($this->res)); + $this->handler->expects($this->any()) + ->method('streamSetTimeout') + ->will($this->returnValue(true)); + $this->handler->expects($this->any()) + ->method('closeSocket') + ->will($this->returnValue(true)); $this->handler->setFormatter($this->getIdentityFormatter()); } - - public function tearDown() - { - unset($this->socket, $this->handler); - } } diff --git a/tests/Monolog/Handler/RavenHandlerTest.php b/tests/Monolog/Handler/RavenHandlerTest.php index 6e231b5c..a7b3eca5 100644 --- a/tests/Monolog/Handler/RavenHandlerTest.php +++ b/tests/Monolog/Handler/RavenHandlerTest.php @@ -189,7 +189,10 @@ class RavenHandlerTest extends TestCase $this->getRecord(Logger::INFO, 'information'), ]; - $handler = $this->createMock('Monolog\Handler\RavenHandler', ['handle'], [$this->getRavenClient()]); + $handler = $this->getMockBuilder('Monolog\Handler\RavenHandler') + ->setMethods(['handle']) + ->setConstructorArgs([$this->getRavenClient()]) + ->getMock(); $handler->expects($this->never())->method('handle'); $handler->setLevel(Logger::ERROR); $handler->handleBatch($records); diff --git a/tests/Monolog/Handler/RedisHandlerTest.php b/tests/Monolog/Handler/RedisHandlerTest.php index 6aa95bd9..c84c3c71 100644 --- a/tests/Monolog/Handler/RedisHandlerTest.php +++ b/tests/Monolog/Handler/RedisHandlerTest.php @@ -39,12 +39,12 @@ class RedisHandlerTest extends TestCase public function testPredisHandle() { - $redis = $this->createMock('Predis\Client', ['__call']); + $redis = $this->createPartialMock('Predis\Client', ['rpush']); // Predis\Client uses rpush $redis->expects($this->once()) - ->method('__call') - ->with('rpush', ['key', 'test']); + ->method('rpush') + ->with('key', 'test'); $record = $this->getRecord(Logger::WARNING, 'test', ['data' => new \stdClass, 'foo' => 34]); @@ -55,7 +55,7 @@ class RedisHandlerTest extends TestCase public function testRedisHandle() { - $redis = $this->createMock('Redis', ['rpush']); + $redis = $this->createPartialMock('Redis', ['rpush']); // Redis uses rPush $redis->expects($this->once()) @@ -71,7 +71,7 @@ class RedisHandlerTest extends TestCase public function testRedisHandleCapped() { - $redis = $this->createMock('Redis', ['multi', 'rpush', 'ltrim', 'exec']); + $redis = $this->createPartialMock('Redis', ['multi', 'rpush', 'ltrim', 'exec']); // Redis uses multi $redis->expects($this->once()) @@ -99,18 +99,16 @@ class RedisHandlerTest extends TestCase public function testPredisHandleCapped() { - $redis = $this->createMock('Predis\Client', ['transaction']); + $redis = $this->createPartialMock('Predis\Client', ['transaction']); - $redisTransaction = $this->createMock('Predis\Client', ['__call']); + $redisTransaction = $this->createPartialMock('Predis\Client', ['rpush', 'ltrim']); - $redisTransaction->expects($this->at(0)) - ->method('__call') - ->with('rpush') + $redisTransaction->expects($this->once()) + ->method('rpush') ->will($this->returnSelf()); - $redisTransaction->expects($this->at(1)) - ->method('__call') - ->with('ltrim') + $redisTransaction->expects($this->once()) + ->method('ltrim') ->will($this->returnSelf()); // Redis uses multi diff --git a/tests/Monolog/Handler/SlackHandlerTest.php b/tests/Monolog/Handler/SlackHandlerTest.php index ee8d8dc0..8bec3379 100644 --- a/tests/Monolog/Handler/SlackHandlerTest.php +++ b/tests/Monolog/Handler/SlackHandlerTest.php @@ -14,7 +14,6 @@ namespace Monolog\Handler; use Monolog\Test\TestCase; use Monolog\Logger; use Monolog\Formatter\LineFormatter; -use Monolog\Util\LocalSocket; /** * @author Greg Kedzierski @@ -41,32 +40,36 @@ class SlackHandlerTest extends TestCase public function testWriteHeader() { - $this->initHandlerAndSocket(); + $this->createHandler(); $this->handler->handle($this->getRecord(Logger::CRITICAL, 'test1')); + fseek($this->res, 0); + $content = fread($this->res, 1024); - $content = $this->socket->getOutput(); - $this->assertRegexp('/POST \/api\/chat.postMessage HTTP\/1.1\\r\\nHost: slack.com\\r\\nContent-Type: application\/x-www-form-urlencoded\\r\\nContent-Length: \d{2,4}\\r\\n\\r\\n/', $content); + $this->assertRegexp('{POST /api/chat.postMessage HTTP/1.1\\r\\nHost: slack.com\\r\\nContent-Type: application/x-www-form-urlencoded\\r\\nContent-Length: \d{2,4}\\r\\n\\r\\n}', $content); } public function testWriteContent() { - $this->initHandlerAndSocket(); + $this->createHandler(); $this->handler->handle($this->getRecord(Logger::CRITICAL, 'test1')); + fseek($this->res, 0); + $content = fread($this->res, 1024); - $content = $this->socket->getOutput(); $this->assertRegexp('/token=myToken&channel=channel1&username=Monolog&text=&attachments=.*$/', $content); } public function testWriteContentUsesFormatterIfProvided() { - $this->initHandlerAndSocket('myToken', 'channel1', 'Monolog', false); + $this->createHandler('myToken', 'channel1', 'Monolog', false); $this->handler->handle($this->getRecord(Logger::CRITICAL, 'test1')); - $content = $this->socket->getOutput(); + fseek($this->res, 0); + $content = fread($this->res, 1024); - $this->initHandlerAndSocket('myToken', 'channel1', 'Monolog', false); + $this->createHandler('myToken', 'channel1', 'Monolog', false); $this->handler->setFormatter(new LineFormatter('foo--%message%')); $this->handler->handle($this->getRecord(Logger::CRITICAL, 'test2')); - $content2 = $this->socket->getOutput(); + fseek($this->res, 0); + $content2 = fread($this->res, 1024); $this->assertRegexp('/token=myToken&channel=channel1&username=Monolog&text=test1.*$/', $content); $this->assertRegexp('/token=myToken&channel=channel1&username=Monolog&text=foo--test2.*$/', $content2); @@ -74,10 +77,11 @@ class SlackHandlerTest extends TestCase public function testWriteContentWithEmoji() { - $this->initHandlerAndSocket('myToken', 'channel1', 'Monolog', true, 'alien'); + $this->createHandler('myToken', 'channel1', 'Monolog', true, 'alien'); $this->handler->handle($this->getRecord(Logger::CRITICAL, 'test1')); + fseek($this->res, 0); + $content = fread($this->res, 1024); - $content = $this->socket->getOutput(); $this->assertRegexp('/icon_emoji=%3Aalien%3A$/', $content); } @@ -86,19 +90,21 @@ class SlackHandlerTest extends TestCase */ public function testWriteContentWithColors($level, $expectedColor) { - $this->initHandlerAndSocket(); + $this->createHandler(); $this->handler->handle($this->getRecord($level, 'test1')); + fseek($this->res, 0); + $content = fread($this->res, 1024); - $content = $this->socket->getOutput(); $this->assertRegexp('/color%22%3A%22'.$expectedColor.'/', $content); } public function testWriteContentWithPlainTextMessage() { - $this->initHandlerAndSocket('myToken', 'channel1', 'Monolog', false); + $this->createHandler('myToken', 'channel1', 'Monolog', false); $this->handler->handle($this->getRecord(Logger::CRITICAL, 'test1')); + fseek($this->res, 0); + $content = fread($this->res, 1024); - $content = $this->socket->getOutput(); $this->assertRegexp('/text=test1/', $content); } @@ -116,20 +122,29 @@ class SlackHandlerTest extends TestCase ]; } - private function initHandlerAndSocket($token = 'myToken', $channel = 'channel1', $username = 'Monolog', $useAttachment = true, $iconEmoji = null, $useShortAttachment = false, $includeExtra = false) + private function createHandler($token = 'myToken', $channel = 'channel1', $username = 'Monolog', $useAttachment = true, $iconEmoji = null, $useShortAttachment = false, $includeExtra = false) { - $this->socket = LocalSocket::initSocket(); - $this->handler = new SlackHandler($token, $channel, $username, $useAttachment, $iconEmoji, Logger::DEBUG, true, $useShortAttachment, $includeExtra); + $constructorArgs = [$token, $channel, $username, $useAttachment, $iconEmoji, Logger::DEBUG, true, $useShortAttachment, $includeExtra]; + $this->res = fopen('php://memory', 'a'); + $this->handler = $this->getMockBuilder('Monolog\Handler\SlackHandler') + ->setConstructorArgs($constructorArgs) + ->setMethods(['fsockopen', 'streamSetTimeout', 'closeSocket']) + ->getMock(); $reflectionProperty = new \ReflectionProperty('\Monolog\Handler\SocketHandler', 'connectionString'); $reflectionProperty->setAccessible(true); - $reflectionProperty->setValue($this->handler, '127.0.0.1:51984'); + $reflectionProperty->setValue($this->handler, 'localhost:1234'); + + $this->handler->expects($this->any()) + ->method('fsockopen') + ->will($this->returnValue($this->res)); + $this->handler->expects($this->any()) + ->method('streamSetTimeout') + ->will($this->returnValue(true)); + $this->handler->expects($this->any()) + ->method('closeSocket') + ->will($this->returnValue(true)); $this->handler->setFormatter($this->getIdentityFormatter()); } - - public function tearDown() - { - unset($this->socket, $this->handler); - } } diff --git a/tests/Monolog/Handler/SocketHandlerTest.php b/tests/Monolog/Handler/SocketHandlerTest.php index e37ce180..c0080e84 100644 --- a/tests/Monolog/Handler/SocketHandlerTest.php +++ b/tests/Monolog/Handler/SocketHandlerTest.php @@ -13,7 +13,6 @@ namespace Monolog\Handler; use Monolog\Test\TestCase; use Monolog\Logger; -use Monolog\Util\LocalSocket; /** * @author Pablo de Leon Belloc @@ -89,8 +88,10 @@ class SocketHandlerTest extends TestCase */ public function testExceptionIsThrownOnFsockopenError() { - $this->createHandler('tcp://127.0.0.1:51985'); - + $this->setMockHandler(['fsockopen']); + $this->handler->expects($this->once()) + ->method('fsockopen') + ->will($this->returnValue(false)); $this->writeRecord('Hello world'); } @@ -99,9 +100,23 @@ class SocketHandlerTest extends TestCase */ public function testExceptionIsThrownOnPfsockopenError() { - $this->createHandler('tcp://127.0.0.1:51985'); + $this->setMockHandler(['pfsockopen']); + $this->handler->expects($this->once()) + ->method('pfsockopen') + ->will($this->returnValue(false)); $this->handler->setPersistent(true); + $this->writeRecord('Hello world'); + } + /** + * @expectedException UnexpectedValueException + */ + public function testExceptionIsThrownIfCannotSetTimeout() + { + $this->setMockHandler(['streamSetTimeout']); + $this->handler->expects($this->once()) + ->method('streamSetTimeout') + ->will($this->returnValue(false)); $this->writeRecord('Hello world'); } @@ -110,49 +125,141 @@ class SocketHandlerTest extends TestCase */ public function testWriteFailsOnIfFwriteReturnsFalse() { - $this->initHandlerAndSocket(); + $this->setMockHandler(['fwrite']); + + $callback = function ($arg) { + $map = [ + 'Hello world' => 6, + 'world' => false, + ]; + + return $map[$arg]; + }; + + $this->handler->expects($this->exactly(2)) + ->method('fwrite') + ->will($this->returnCallback($callback)); + $this->writeRecord('Hello world'); - - LocalSocket::shutdownSocket(); - - $this->writeRecord('Hello world2'); } - public function testWriteRealSocket() + /** + * @expectedException RuntimeException + */ + public function testWriteFailsIfStreamTimesOut() { - $this->initHandlerAndSocket(); - $this->writeRecord("foo bar baz content test1\n"); - $this->writeRecord("foo bar baz content test2\n"); - $this->writeRecord("foo bar baz content test3\n"); + $this->setMockHandler(['fwrite', 'streamGetMetadata']); - $this->assertEquals("foo bar baz content test1\nfoo bar baz content test2\nfoo bar baz content test3\n", $this->socket->getOutput()); + $callback = function ($arg) { + $map = [ + 'Hello world' => 6, + 'world' => 5, + ]; + + return $map[$arg]; + }; + + $this->handler->expects($this->exactly(1)) + ->method('fwrite') + ->will($this->returnCallback($callback)); + $this->handler->expects($this->exactly(1)) + ->method('streamGetMetadata') + ->will($this->returnValue(['timed_out' => true])); + + $this->writeRecord('Hello world'); + } + + /** + * @expectedException RuntimeException + */ + public function testWriteFailsOnIncompleteWrite() + { + $this->setMockHandler(['fwrite', 'streamGetMetadata']); + + $res = $this->res; + $callback = function ($string) use ($res) { + fclose($res); + + return strlen('Hello'); + }; + + $this->handler->expects($this->exactly(1)) + ->method('fwrite') + ->will($this->returnCallback($callback)); + $this->handler->expects($this->exactly(1)) + ->method('streamGetMetadata') + ->will($this->returnValue(['timed_out' => false])); + + $this->writeRecord('Hello world'); + } + + public function testWriteWithMemoryFile() + { + $this->setMockHandler(); + $this->writeRecord('test1'); + $this->writeRecord('test2'); + $this->writeRecord('test3'); + fseek($this->res, 0); + $this->assertEquals('test1test2test3', fread($this->res, 1024)); + } + + public function testWriteWithMock() + { + $this->setMockHandler(['fwrite']); + + $callback = function ($arg) { + $map = [ + 'Hello world' => 6, + 'world' => 5, + ]; + + return $map[$arg]; + }; + + $this->handler->expects($this->exactly(2)) + ->method('fwrite') + ->will($this->returnCallback($callback)); + + $this->writeRecord('Hello world'); } public function testClose() { - $this->initHandlerAndSocket(); + $this->setMockHandler(); $this->writeRecord('Hello world'); - - $reflectionProperty = new \ReflectionProperty('\Monolog\Handler\SocketHandler', 'resource'); - $reflectionProperty->setAccessible(true); - - $this->assertInternalType('resource', $reflectionProperty->getValue($this->handler)); + $this->assertInternalType('resource', $this->res); $this->handler->close(); - $this->assertFalse(is_resource($reflectionProperty->getValue($this->handler)), "Expected resource to be closed after closing handler"); + $this->assertFalse(is_resource($this->res), "Expected resource to be closed after closing handler"); } public function testCloseDoesNotClosePersistentSocket() { - $this->initHandlerAndSocket(); + $this->setMockHandler(); $this->handler->setPersistent(true); $this->writeRecord('Hello world'); - - $reflectionProperty = new \ReflectionProperty('\Monolog\Handler\SocketHandler', 'resource'); - $reflectionProperty->setAccessible(true); - - $this->assertTrue(is_resource($reflectionProperty->getValue($this->handler))); + $this->assertTrue(is_resource($this->res)); $this->handler->close(); - $this->assertTrue(is_resource($reflectionProperty->getValue($this->handler))); + $this->assertTrue(is_resource($this->res)); + } + + /** + * @expectedException \RuntimeException + */ + public function testAvoidInfiniteLoopWhenNoDataIsWrittenForAWritingTimeoutSeconds() + { + $this->setMockHandler(['fwrite', 'streamGetMetadata']); + + $this->handler->expects($this->any()) + ->method('fwrite') + ->will($this->returnValue(0)); + + $this->handler->expects($this->any()) + ->method('streamGetMetadata') + ->will($this->returnValue(['timed_out' => false])); + + $this->handler->setWritingTimeout(1); + + $this->writeRecord('Hello world'); } private function createHandler($connectionString) @@ -166,16 +273,38 @@ class SocketHandlerTest extends TestCase $this->handler->handle($this->getRecord(Logger::WARNING, $string)); } - private function initHandlerAndSocket() + private function setMockHandler(array $methods = []) { - $this->socket = LocalSocket::initSocket(); + $this->res = fopen('php://memory', 'a'); + + $defaultMethods = ['fsockopen', 'pfsockopen', 'streamSetTimeout']; + $newMethods = array_diff($methods, $defaultMethods); + + $finalMethods = array_merge($defaultMethods, $newMethods); + + $this->handler = $this->getMockBuilder('Monolog\Handler\SocketHandler') + ->setMethods($finalMethods) + ->setConstructorArgs(['localhost:1234']) + ->getMock(); + + if (!in_array('fsockopen', $methods)) { + $this->handler->expects($this->any()) + ->method('fsockopen') + ->will($this->returnValue($this->res)); + } + + if (!in_array('pfsockopen', $methods)) { + $this->handler->expects($this->any()) + ->method('pfsockopen') + ->will($this->returnValue($this->res)); + } + + if (!in_array('streamSetTimeout', $methods)) { + $this->handler->expects($this->any()) + ->method('streamSetTimeout') + ->will($this->returnValue(true)); + } - $this->handler = new SocketHandler('tcp://127.0.0.1:51984'); $this->handler->setFormatter($this->getIdentityFormatter()); } - - public function tearDown() - { - unset($this->socket, $this->handler); - } } diff --git a/tests/Monolog/Handler/SyslogUdpHandlerTest.php b/tests/Monolog/Handler/SyslogUdpHandlerTest.php index 9c15aa5a..c7cf6d26 100644 --- a/tests/Monolog/Handler/SyslogUdpHandlerTest.php +++ b/tests/Monolog/Handler/SyslogUdpHandlerTest.php @@ -29,7 +29,10 @@ class SyslogUdpHandlerTest extends \PHPUnit_Framework_TestCase $handler = new SyslogUdpHandler("127.0.0.1", 514, "authpriv"); $handler->setFormatter(new \Monolog\Formatter\ChromePHPFormatter()); - $socket = $this->createMock('\Monolog\Handler\SyslogUdp\UdpSocket', ['write'], ['lol', 'lol']); + $socket = $this->getMockBuilder('\Monolog\Handler\SyslogUdp\UdpSocket') + ->setMethods(['write']) + ->setConstructorArgs(['lol', 'lol']) + ->getMock(); $socket->expects($this->at(0)) ->method('write') ->with("lol", "<".(LOG_AUTHPRIV + LOG_WARNING).">1 "); diff --git a/tests/Monolog/Handler/UdpSocketTest.php b/tests/Monolog/Handler/UdpSocketTest.php index 4c7d5b28..c13d0cb3 100644 --- a/tests/Monolog/Handler/UdpSocketTest.php +++ b/tests/Monolog/Handler/UdpSocketTest.php @@ -13,7 +13,6 @@ namespace Monolog\Handler; use Monolog\Test\TestCase; use Monolog\Handler\SyslogUdp\UdpSocket; -use Monolog\Util\LocalSocket; /** * @requires extension sockets @@ -22,25 +21,34 @@ class UdpSocketTest extends TestCase { public function testWeDoNotTruncateShortMessages() { - $this->initSocket(); + $socket = $this->getMockBuilder('\Monolog\Handler\SyslogUdp\UdpSocket') + ->setMethods(['send']) + ->setConstructorArgs(['lol', 'lol']) + ->getMock(); + + $socket->expects($this->at(0)) + ->method('send') + ->with("HEADER: The quick brown fox jumps over the lazy dog"); - $socket = new UdpSocket('127.0.0.1', 51983); $socket->write("The quick brown fox jumps over the lazy dog", "HEADER: "); - - $this->assertEquals('HEADER: The quick brown fox jumps over the lazy dog', $this->socket->getOutput()); } public function testLongMessagesAreTruncated() { - $this->initSocket(); - - $socket = new UdpSocket('127.0.0.1', 51983); - - $longString = str_repeat("derp", 20000); - $socket->write($longString, "HEADER"); + $socket = $this->getMockBuilder('\Monolog\Handler\SyslogUdp\UdpSocket') + ->setMethods(['send']) + ->setConstructorArgs(['lol', 'lol']) + ->getMock(); $truncatedString = str_repeat("derp", 16254).'d'; - $this->assertEquals('HEADER'.$truncatedString, $this->socket->getOutput()); + + $socket->expects($this->exactly(1)) + ->method('send') + ->with("HEADER" . $truncatedString); + + $longString = str_repeat("derp", 20000); + + $socket->write($longString, "HEADER"); } public function testDoubleCloseDoesNotError() @@ -59,14 +67,4 @@ class UdpSocketTest extends TestCase $socket->close(); $socket->write('foo', "HEADER"); } - - private function initSocket() - { - $this->socket = LocalSocket::initSocket(51983, LocalSocket::UDP); - } - - public function tearDown() - { - unset($this->socket, $this->handler); - } } diff --git a/tests/Monolog/Util/LocalSocket.php b/tests/Monolog/Util/LocalSocket.php deleted file mode 100644 index 59ab1d55..00000000 --- a/tests/Monolog/Util/LocalSocket.php +++ /dev/null @@ -1,234 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Monolog\Util; - -use Symfony\Component\Process\Process; - -class LocalSocket -{ - const TCP = 'tcp'; - const UDP = 'udp'; - - private static $sockets = []; - private static $shutdownHandler = false; - - public static function initSocket(int $port = 51984, string $proto = LocalSocket::TCP) - { - if (!isset(self::$sockets[$proto][$port])) { - $file = self::initFile($port, $proto); - - $process = new Process(escapeshellarg(PHP_BINARY).' '.escapeshellarg($file)); - $process->start(function ($type, $out) use ($proto, $port) { - if ($type === 'err') { - if (substr($out, 0, 4) === 'INIT') { - if ($proto === LocalSocket::UDP) { - self::$sockets[$proto][$port]['comms'] = null; - } else { - $sock = socket_create(AF_INET, SOCK_STREAM, getprotobyname($proto)); - socket_connect($sock, '127.0.0.1', $port); - socket_write($sock, "MONITOR\n"); - self::$sockets[$proto][$port]['comms'] = $sock; - } - } - } - }); - - self::$sockets[$proto][$port] = [ - 'file' => $file, - 'process' => $process, - 'busy' => false, - ]; - - // make sure the socket is listening - while (true) { - if ($process->getErrorOutput() === 'INIT') { - break; - } - usleep(100); - } - - if (!self::$shutdownHandler) { - register_shutdown_function(function () { - LocalSocket::shutdownSockets(); - }); - self::$shutdownHandler = true; - } - } - - $sock = self::$sockets[$proto][$port]; - if (!$sock['process']->isRunning()) { - throw new \RuntimeException( - 'LocalSocket '.$proto.'://127.0.0.1:'.$port.' appears to have died unexpectedly: ' . "\n\n" . - $sock['process']->getOutput() - ); - } - - self::clearSocket($port, $proto); - - return new class($sock['process'], $sock['comms']) { - public function __construct(Process $proc, $comms) - { - $this->process = $proc; - $this->comms = $comms; - } - - public function getOutput() - { - // read out until getting a !DONE! ack and then tell the socket to terminate the connection - if ($this->comms) { - $out = ''; - socket_write($this->comms, "DONE?\n"); - while ($data = socket_read($this->comms, 2048)) { - $out .= $data; - if (substr($out, -6) === '!DONE!') { - $out = substr($out, 0, -6); - break; - } - } - $out = preg_replace('{.*!BEGIN!}', '', $out); - - socket_write($this->comms, "TERMINATE\n"); - - return $out; - } - - // wait 3 seconds max for output for UDP - $retries = 3000; - while (!$this->process->getOutput() && $retries-- && $this->process->getStatus()) { - usleep(100); - } - - return $this->process->getOutput(); - } - }; - } - - private static function clearSocket(int $port = 51984, string $proto = LocalSocket::TCP) - { - if (isset(self::$sockets[$proto][$port])) { - self::$sockets[$proto][$port]['process']->clearOutput(); - } - } - - public static function shutdownSocket(int $port = 51984, string $proto = LocalSocket::TCP) - { - if (!isset(self::$sockets[$proto][$port])) { - return; - } - - if (is_resource(self::$sockets[$proto][$port]['comms'])) { - socket_write(self::$sockets[$proto][$port]['comms'], "EXIT\n"); - socket_close(self::$sockets[$proto][$port]['comms']); - } - $sock = self::$sockets[$proto][$port]; - $sock['process']->stop(); - @unlink($sock['file']); - unset(self::$sockets[$proto][$port]); - } - - public static function shutdownSockets() - { - foreach (self::$sockets as $proto => $ports) { - foreach ($ports as $port => $sock) { - self::shutdownSocket($port, $proto); - } - } - } - - private static function initFile(int $port, string $proto): string - { - $tmpFile = sys_get_temp_dir().'/monolog-test-'.$proto.'-socket-'.$port.'.php'; - - if ($proto === self::UDP) { - file_put_contents($tmpFile, <<