Added StreamLoggerTest
authorPhilipp Holzer <admin@philipp.info>
Sun, 3 Mar 2019 20:25:18 +0000 (21:25 +0100)
committerPhilipp Holzer <admin@philipp.info>
Sun, 3 Mar 2019 20:26:00 +0000 (21:26 +0100)
src/Util/Logger/StreamLogger.php
tests/src/Util/Logger/StreamLoggerTest.php [new file with mode: 0644]

index ad1b152..10ad0a0 100644 (file)
@@ -35,6 +35,12 @@ class StreamLogger extends AbstractFriendicaLogger
         */
        private $pid;
 
+       /**
+        * An error message
+        * @var string
+        */
+       private $errorMessage;
+
        /**
         * Translates LogLevel log levels to integer values
         * @var array
@@ -98,7 +104,7 @@ class StreamLogger extends AbstractFriendicaLogger
        protected function addEntry($level, $message, $context = [])
        {
                if (!array_key_exists($level, $this->levelToInt)) {
-                       throw new \InvalidArgumentException('The level "%s" is not valid', $level);
+                       throw new \InvalidArgumentException(sprintf('The level "%s" is not valid.', $level));
                }
 
                $logLevel = $this->levelToInt[$level];
@@ -151,12 +157,14 @@ class StreamLogger extends AbstractFriendicaLogger
                }
 
                $this->createDir();
-               $this->stream = fopen($this->url, 'a');
+               set_error_handler([$this, 'customErrorHandler']);
+               $this->stream = fopen($this->url, 'ab');
+               restore_error_handler();
 
                if (!is_resource($this->stream)) {
                        $this->stream = null;
 
-                       throw new \UnexpectedValueException(sprintf('The stream or file "%s" could not be opened.', $this->url));
+                       throw new \UnexpectedValueException(sprintf('The stream or file "%s" could not be opened: ' . $this->errorMessage, $this->url));
                }
        }
 
@@ -173,10 +181,18 @@ class StreamLogger extends AbstractFriendicaLogger
                }
 
                if (isset($dirname) && !is_dir($dirname)) {
+                       set_error_handler([$this, 'customErrorHandler']);
                        $status = mkdir($dirname, 0777, true);
+                       restore_error_handler();
+
                        if (!$status && !is_dir($dirname)) {
-                               throw new \UnexpectedValueException(sprintf('Directory "%s" cannot get created.', $dirname));
+                               throw new \UnexpectedValueException(sprintf('Directory "%s" cannot get created: ' . $this->errorMessage, $dirname));
                        }
                }
        }
+
+       private function customErrorHandler($code, $msg)
+       {
+               $this->errorMessage = preg_replace('{^(fopen|mkdir)\(.*?\): }', '', $msg);
+       }
 }
diff --git a/tests/src/Util/Logger/StreamLoggerTest.php b/tests/src/Util/Logger/StreamLoggerTest.php
new file mode 100644 (file)
index 0000000..a2e8144
--- /dev/null
@@ -0,0 +1,203 @@
+<?php
+
+namespace Friendica\Test\src\Util\Logger;
+
+use Friendica\Test\MockedTest;
+use Friendica\Test\Util\VFSTrait;
+use Friendica\Util\Introspection;
+use Friendica\Util\Logger\StreamLogger;
+use Mockery\MockInterface;
+use org\bovigo\vfs\vfsStream;
+use Psr\Log\LogLevel;
+
+class StreamLoggerTest extends MockedTest
+{
+       const LOGLINE = '/\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2} .* \[.*\]: .* \{.*\"file\":\".*\".*,.*\"line\":\d*,.*\"function\":\".*\".*,.*\"uid\":\".*\".*,.*\"process_id\":\d*.*\}/';
+
+       const FILE = 'test';
+       const LINE = 666;
+       const FUNC = 'myfunction';
+
+       use VFSTrait;
+
+       /**
+        * @var Introspection|MockInterface
+        */
+       private $introspection;
+
+       protected function setUp()
+       {
+               parent::setUp();
+
+               $this->setUpVfsDir();
+
+               $this->introspection = \Mockery::mock(Introspection::class);
+               $this->introspection->shouldReceive('getRecord')->andReturn([
+                       'file'     => self::FILE,
+                       'line'     => self::LINE,
+                       'function' => self::FUNC
+               ]);
+       }
+
+       public function assertLogline($string)
+       {
+               $this->assertRegExp(self::LOGLINE, $string);
+       }
+
+       public function assertLoglineNums($assertNum, $string)
+       {
+               $this->assertEquals($assertNum, preg_match_all(self::LOGLINE, $string));
+       }
+
+       public function testNormal()
+       {
+               $logfile = vfsStream::newFile('friendica.log')
+                       ->at($this->root);
+
+               $logger = new StreamLogger('test', $logfile->url(), $this->introspection);
+               $logger->emergency('working!');
+               $logger->alert('working too!');
+               $logger->debug('and now?');
+               $logger->notice('message', ['an' => 'context']);
+
+               $text = $logfile->getContent();
+               $this->assertLogline($text);
+               $this->assertLoglineNums(4, $text);
+       }
+
+       /**
+        * Test if a log entry is correctly interpolated
+        */
+       public function testPsrInterpolate()
+       {
+               $logfile = vfsStream::newFile('friendica.log')
+                       ->at($this->root);
+
+               $logger = new StreamLogger('test', $logfile->url(), $this->introspection);
+
+               $logger->emergency('A {psr} test', ['psr' => 'working']);
+               $logger->alert('An {array} test', ['array' => ['it', 'is', 'working']]);
+               $text = $logfile->getContent();
+               $this->assertContains('A working test', $text);
+               $this->assertContains('An ["it","is","working"] test', $text);
+       }
+
+       /**
+        * Test if a log entry contains all necessary information
+        */
+       public function testContainsInformation()
+       {
+               $logfile = vfsStream::newFile('friendica.log')
+                       ->at($this->root);
+
+               $logger = new StreamLogger('test', $logfile->url(), $this->introspection);
+
+               $logger->emergency('A test');
+
+               $text = $logfile->getContent();
+               $this->assertContains('"process_id":' . getmypid(), $text);
+               $this->assertContains('"file":"' . self::FILE . '"', $text);
+               $this->assertContains('"line":' . self::LINE, $text);
+               $this->assertContains('"function":"' . self::FUNC . '"', $text);
+       }
+
+       /**
+        * Test if the minimum level is working
+        */
+       public function testMinimumLevel()
+       {
+               $logfile = vfsStream::newFile('friendica.log')
+                       ->at($this->root);
+
+               $logger = new StreamLogger('test', $logfile->url(), $this->introspection, LogLevel::NOTICE);
+
+               $logger->emergency('working');
+               $logger->alert('working');
+               $logger->error('working');
+               $logger->warning('working');
+               $logger->notice('working');
+               $logger->info('not working');
+               $logger->debug('not working');
+
+               $text = $logfile->getContent();
+
+               $this->assertLoglineNums(5, $text);
+       }
+
+
+       /**
+        * Test if a file cannot get opened
+        * @expectedException \UnexpectedValueException
+        */
+       public function testNoFile()
+       {
+               $logfile = vfsStream::newFile('friendica.log')
+                       ->at($this->root)
+                       ->chmod(0);
+
+               $logger = new StreamLogger('test', $logfile->url(), $this->introspection);
+
+               $logger->emergency('not working');
+       }
+
+       /**
+        * Test when a file isn't set
+        * @expectedException \LogicException
+        * @expectedExceptionMessage Missing stream URL.
+        */
+       public function testNoUrl()
+       {
+               $logger = new StreamLogger('test', '', $this->introspection);
+
+               $logger->emergency('not working');
+       }
+
+       /**
+        * Test when a file doesn't exist
+        * @expectedException \UnexpectedValueException
+        * @expectedExceptionMessageRegExp /The stream or file .* could not be opened: .* /
+        */
+       public function testWrongUrl()
+       {
+               $logger = new StreamLogger('test', 'wrongfile', $this->introspection);
+
+               $logger->emergency('not working');
+       }
+
+       /**
+        * Test when the directory cannot get created
+        * @expectedException \UnexpectedValueException
+        * @expectedExceptionMessageRegExp /Directory .* cannot get created: .* /
+        */
+       public function testWrongDir()
+       {
+               $logger = new StreamLogger('test', 'a/wrong/directory/file.txt', $this->introspection);
+
+               $logger->emergency('not working');
+       }
+
+       /**
+        * Test when the minimum level is not valid
+        * @expectedException \InvalidArgumentException
+        * @expectedExceptionMessageRegExp /The level ".*" is not valid./
+        */
+       public function testWrongMinimumLevel()
+       {
+               $logger = new StreamLogger('test', 'file.text', $this->introspection, 'NOPE');
+       }
+
+       /**
+        * Test when the minimum level is not valid
+        * @expectedException \InvalidArgumentException
+        * @expectedExceptionMessageRegExp /The level ".*" is not valid./
+        */
+       public function testWrongLogLevel()
+       {
+               $logfile = vfsStream::newFile('friendica.log')
+                       ->at($this->root);
+
+               $logger = new StreamLogger('test', $logfile->url(), $this->introspection);
+
+               $logger->log('NOPE', 'a test');
+       }
+}