LoggerTest.php 6.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222
  1. <?php
  2. /**
  3. * Copyright (c) 2014 Thomas Müller <thomas.mueller@tmit.eu>
  4. *
  5. * @author Thomas Citharel <nextcloud@tcit.fr>
  6. *
  7. * This file is licensed under the Affero General Public License version 3 or
  8. * later.
  9. * See the COPYING-README file.
  10. */
  11. namespace Test;
  12. use OC\Log;
  13. use OC\SystemConfig;
  14. use OCP\ILogger;
  15. use OCP\Log\IWriter;
  16. use OCP\Support\CrashReport\IRegistry;
  17. use PHPUnit\Framework\MockObject\MockObject;
  18. class LoggerTest extends TestCase implements IWriter {
  19. /** @var SystemConfig|MockObject */
  20. private $config;
  21. /** @var IRegistry|MockObject */
  22. private $registry;
  23. /** @var ILogger */
  24. private $logger;
  25. /** @var array */
  26. private array $logs = [];
  27. protected function setUp(): void {
  28. parent::setUp();
  29. $this->logs = [];
  30. $this->config = $this->createMock(SystemConfig::class);
  31. $this->registry = $this->createMock(IRegistry::class);
  32. $this->logger = new Log($this, $this->config, null, $this->registry);
  33. }
  34. public function testInterpolation() {
  35. $logger = $this->logger;
  36. $logger->warning('{Message {nothing} {user} {foo.bar} a}', ['user' => 'Bob', 'foo.bar' => 'Bar']);
  37. $expected = ['2 {Message {nothing} Bob Bar a}'];
  38. $this->assertEquals($expected, $this->getLogs());
  39. }
  40. public function testAppCondition() {
  41. $this->config->expects($this->any())
  42. ->method('getValue')
  43. ->will(($this->returnValueMap([
  44. ['loglevel', ILogger::WARN, ILogger::WARN],
  45. ['log.condition', [], ['apps' => ['files']]]
  46. ])));
  47. $logger = $this->logger;
  48. $logger->info('Don\'t display info messages');
  49. $logger->info('Show info messages of files app', ['app' => 'files']);
  50. $logger->warning('Show warning messages of other apps');
  51. $expected = [
  52. '1 Show info messages of files app',
  53. '2 Show warning messages of other apps',
  54. ];
  55. $this->assertEquals($expected, $this->getLogs());
  56. }
  57. public function testLoggingWithDataArray(): void {
  58. $writerMock = $this->createMock(IWriter::class);
  59. $logFile = new Log($writerMock, $this->config);
  60. $writerMock->expects($this->once())->method('write')->with('no app in context', ['something' => 'extra', 'message' => 'Testing logging with john']);
  61. $logFile->error('Testing logging with {user}', ['something' => 'extra', 'user' => 'john']);
  62. }
  63. private function getLogs(): array {
  64. return $this->logs;
  65. }
  66. public function write(string $app, $message, int $level) {
  67. $textMessage = $message;
  68. if (is_array($message)) {
  69. $textMessage = $message['message'];
  70. }
  71. $this->logs[] = $level . " " . $textMessage;
  72. }
  73. public function userAndPasswordData(): array {
  74. return [
  75. ['mySpecialUsername', 'MySuperSecretPassword'],
  76. ['my-user', '324324()#ä234'],
  77. ['my-user', ')qwer'],
  78. ['my-user', 'qwer)asdf'],
  79. ['my-user', 'qwer)'],
  80. ['my-user', '(qwer'],
  81. ['my-user', 'qwer(asdf'],
  82. ['my-user', 'qwer('],
  83. ];
  84. }
  85. /**
  86. * @dataProvider userAndPasswordData
  87. */
  88. public function testDetectlogin(string $user, string $password): void {
  89. $e = new \Exception('test');
  90. $this->registry->expects($this->once())
  91. ->method('delegateReport')
  92. ->with($e, ['level' => 3]);
  93. $this->logger->logException($e);
  94. $logLines = $this->getLogs();
  95. foreach ($logLines as $logLine) {
  96. if (is_array($logLine)) {
  97. $logLine = json_encode($logLine);
  98. }
  99. $this->assertStringNotContainsString($user, $logLine);
  100. $this->assertStringNotContainsString($password, $logLine);
  101. $this->assertStringContainsString('*** sensitive parameters replaced ***', $logLine);
  102. }
  103. }
  104. /**
  105. * @dataProvider userAndPasswordData
  106. */
  107. public function testDetectcheckPassword(string $user, string $password): void {
  108. $e = new \Exception('test');
  109. $this->registry->expects($this->once())
  110. ->method('delegateReport')
  111. ->with($e, ['level' => 3]);
  112. $this->logger->logException($e);
  113. $logLines = $this->getLogs();
  114. foreach ($logLines as $logLine) {
  115. if (is_array($logLine)) {
  116. $logLine = json_encode($logLine);
  117. }
  118. $this->assertStringNotContainsString($user, $logLine);
  119. $this->assertStringNotContainsString($password, $logLine);
  120. $this->assertStringContainsString('*** sensitive parameters replaced ***', $logLine);
  121. }
  122. }
  123. /**
  124. * @dataProvider userAndPasswordData
  125. */
  126. public function testDetectvalidateUserPass(string $user, string $password): void {
  127. $e = new \Exception('test');
  128. $this->registry->expects($this->once())
  129. ->method('delegateReport')
  130. ->with($e, ['level' => 3]);
  131. $this->logger->logException($e);
  132. $logLines = $this->getLogs();
  133. foreach ($logLines as $logLine) {
  134. if (is_array($logLine)) {
  135. $logLine = json_encode($logLine);
  136. }
  137. $this->assertStringNotContainsString($user, $logLine);
  138. $this->assertStringNotContainsString($password, $logLine);
  139. $this->assertStringContainsString('*** sensitive parameters replaced ***', $logLine);
  140. }
  141. }
  142. /**
  143. * @dataProvider userAndPasswordData
  144. */
  145. public function testDetecttryLogin(string $user, string $password): void {
  146. $e = new \Exception('test');
  147. $this->registry->expects($this->once())
  148. ->method('delegateReport')
  149. ->with($e, ['level' => 3]);
  150. $this->logger->logException($e);
  151. $logLines = $this->getLogs();
  152. foreach ($logLines as $logLine) {
  153. if (is_array($logLine)) {
  154. $logLine = json_encode($logLine);
  155. }
  156. $this->assertStringNotContainsString($user, $logLine);
  157. $this->assertStringNotContainsString($password, $logLine);
  158. $this->assertStringContainsString('*** sensitive parameters replaced ***', $logLine);
  159. }
  160. }
  161. /**
  162. * @dataProvider userAndPasswordData
  163. */
  164. public function testDetectclosure(string $user, string $password): void {
  165. $a = function ($user, $password) {
  166. throw new \Exception('test');
  167. };
  168. $this->registry->expects($this->once())
  169. ->method('delegateReport');
  170. try {
  171. $a($user, $password);
  172. } catch (\Exception $e) {
  173. $this->logger->logException($e);
  174. }
  175. $logLines = $this->getLogs();
  176. foreach ($logLines as $logLine) {
  177. if (is_array($logLine)) {
  178. $logLine = json_encode($logLine);
  179. }
  180. $log = explode('\n', $logLine);
  181. unset($log[1]); // Remove `testDetectclosure(` because we are not testing this here, but the closure on stack trace 0
  182. $logLine = implode('\n', $log);
  183. $this->assertStringNotContainsString($user, $logLine);
  184. $this->assertStringNotContainsString($password, $logLine);
  185. $this->assertStringContainsString('*** sensitive parameters replaced ***', $logLine);
  186. }
  187. }
  188. }