1<?php 2 3/** 4 * @file 5 * Contains \Drupal\Tests\Core\Logger\LoggerChannelTest. 6 */ 7 8namespace Drupal\Tests\Core\Logger; 9 10use Drupal\Core\Logger\LoggerChannel; 11use Drupal\Core\Session\AccountInterface; 12use Drupal\Tests\UnitTestCase; 13use Symfony\Component\HttpFoundation\Request; 14use Symfony\Component\HttpFoundation\RequestStack; 15use Psr\Log\LoggerInterface; 16use Psr\Log\LoggerTrait; 17 18/** 19 * @coversDefaultClass \Drupal\Core\Logger\LoggerChannel 20 * @group Logger 21 */ 22class LoggerChannelTest extends UnitTestCase { 23 24 /** 25 * Tests LoggerChannel::log(). 26 * 27 * @param callable $expected 28 * An anonymous function to use with $this->callback() of the logger mock. 29 * The function should check the $context array for expected values. 30 * @param \Symfony\Component\HttpFoundation\Request $request 31 * Will be passed to the channel under test if present. 32 * @param \Drupal\Core\Session\AccountInterface $current_user 33 * Will be passed to the channel under test if present. 34 * 35 * @dataProvider providerTestLog 36 * @covers ::log 37 * @covers ::setCurrentUser 38 * @covers ::setRequestStack 39 */ 40 public function testLog(callable $expected, Request $request = NULL, AccountInterface $current_user = NULL) { 41 $channel = new LoggerChannel('test'); 42 $message = $this->randomMachineName(); 43 $logger = $this->createMock('Psr\Log\LoggerInterface'); 44 $logger->expects($this->once()) 45 ->method('log') 46 ->with($this->anything(), $message, $this->callback($expected)); 47 $channel->addLogger($logger); 48 if ($request) { 49 $requestStack = new RequestStack(); 50 $requestStack->push($request); 51 $channel->setRequestStack($requestStack); 52 } 53 if ($current_user) { 54 $channel->setCurrentUser($current_user); 55 } 56 $channel->log(rand(0, 7), $message); 57 } 58 59 /** 60 * Tests LoggerChannel::log() recursion protection. 61 * 62 * @covers ::log 63 */ 64 public function testLogRecursionProtection() { 65 $channel = new LoggerChannel('test'); 66 $logger = $this->createMock('Psr\Log\LoggerInterface'); 67 $logger->expects($this->exactly(LoggerChannel::MAX_CALL_DEPTH)) 68 ->method('log'); 69 $channel->addLogger($logger); 70 $channel->addLogger(new NaughtyRecursiveLogger($channel)); 71 $channel->log(rand(0, 7), $this->randomMachineName()); 72 } 73 74 /** 75 * Tests LoggerChannel::addLoggers(). 76 * 77 * @covers ::addLogger 78 * @covers ::sortLoggers 79 */ 80 public function testSortLoggers() { 81 $channel = new LoggerChannel($this->randomMachineName()); 82 $index_order = ''; 83 for ($i = 0; $i < 4; $i++) { 84 $logger = $this->createMock('Psr\Log\LoggerInterface'); 85 $logger->expects($this->once()) 86 ->method('log') 87 ->will($this->returnCallback(function () use ($i, &$index_order) { 88 // Append the $i to the index order, so that we know the order that 89 // loggers got called with. 90 $index_order .= $i; 91 })); 92 $channel->addLogger($logger, $i); 93 } 94 95 $channel->log(rand(0, 7), $this->randomMachineName()); 96 // Ensure that the logger added in the end fired first. 97 $this->assertEquals($index_order, '3210'); 98 } 99 100 /** 101 * Data provider for self::testLog(). 102 */ 103 public function providerTestLog() { 104 $account_mock = $this->createMock('Drupal\Core\Session\AccountInterface'); 105 $account_mock->expects($this->any()) 106 ->method('id') 107 ->will($this->returnValue(1)); 108 109 $request_mock = $this->getMockBuilder('Symfony\Component\HttpFoundation\Request') 110 ->setMethods(['getClientIp']) 111 ->getMock(); 112 $request_mock->expects($this->any()) 113 ->method('getClientIp') 114 ->will($this->returnValue('127.0.0.1')); 115 $request_mock->headers = $this->createMock('Symfony\Component\HttpFoundation\ParameterBag'); 116 117 // No request or account. 118 $cases[] = [ 119 function ($context) { 120 return $context['channel'] == 'test' && empty($context['uid']) && empty($context['ip']); 121 }, 122 ]; 123 // With account but not request. Since the request is not available the 124 // current user should not be used. 125 $cases[] = [ 126 function ($context) { 127 return $context['uid'] === 0 && empty($context['ip']); 128 }, 129 NULL, 130 $account_mock, 131 ]; 132 // With request but not account. 133 $cases[] = [ 134 function ($context) { 135 return $context['ip'] === '127.0.0.1' && empty($context['uid']); 136 }, 137 $request_mock, 138 ]; 139 // Both request and account. 140 $cases[] = [ 141 function ($context) { 142 return $context['ip'] === '127.0.0.1' && $context['uid'] === 1; 143 }, 144 $request_mock, 145 $account_mock, 146 ]; 147 return $cases; 148 } 149 150} 151 152class NaughtyRecursiveLogger implements LoggerInterface { 153 use LoggerTrait; 154 155 protected $channel; 156 protected $message; 157 158 public function __construct(LoggerChannel $channel) { 159 $this->channel = $channel; 160 } 161 162 public function log($level, $message, array $context = []) { 163 $this->channel->log(rand(0, 7), $message, $context); 164 } 165 166} 167