diff options
Diffstat (limited to 'tests/lib/Log')
-rw-r--r-- | tests/lib/Log/ExceptionSerializerTest.php | 67 | ||||
-rw-r--r-- | tests/lib/Log/FileTest.php | 67 | ||||
-rw-r--r-- | tests/lib/Log/LogFactoryTest.php | 72 | ||||
-rw-r--r-- | tests/lib/Log/PsrLoggerAdapterTest.php | 82 |
4 files changed, 221 insertions, 67 deletions
diff --git a/tests/lib/Log/ExceptionSerializerTest.php b/tests/lib/Log/ExceptionSerializerTest.php new file mode 100644 index 00000000000..6d5bc5cf19f --- /dev/null +++ b/tests/lib/Log/ExceptionSerializerTest.php @@ -0,0 +1,67 @@ +<?php + +declare(strict_types=1); + +/** + * SPDX-FileCopyrightText: 2021 Nextcloud GmbH and Nextcloud contributors + * SPDX-License-Identifier: AGPL-3.0-or-later + */ + +namespace lib\Log; + +use OC\Log\ExceptionSerializer; +use OC\SystemConfig; +use Test\TestCase; + +class ExceptionSerializerTest extends TestCase { + private ExceptionSerializer $serializer; + + public function setUp(): void { + parent::setUp(); + + $config = $this->createMock(SystemConfig::class); + $this->serializer = new ExceptionSerializer($config); + } + + private function emit($arguments) { + \call_user_func_array([$this, 'bind'], $arguments); + } + + private function bind(array &$myValues): void { + throw new \Exception('my exception'); + } + + private function customMagicAuthThing(string $login, string $parole): void { + throw new \Exception('expected custom auth exception'); + } + + /** + * this test ensures that the serializer does not overwrite referenced + * variables. It is crafted after a scenario we experienced: the DAV server + * emitting the "validateTokens" event, of which later on a handled + * exception was passed to the logger. The token was replaced, the original + * variable overwritten. + */ + public function testSerializer(): void { + try { + $secret = ['Secret']; + $this->emit([&$secret]); + } catch (\Exception $e) { + $serializedData = $this->serializer->serializeException($e); + $this->assertSame(['Secret'], $secret); + $this->assertSame(ExceptionSerializer::SENSITIVE_VALUE_PLACEHOLDER, $serializedData['Trace'][0]['args'][0]); + } + } + + public function testSerializerWithRegisteredMethods(): void { + $this->serializer->enlistSensitiveMethods(self::class, ['customMagicAuthThing']); + try { + $this->customMagicAuthThing('u57474', 'Secret'); + } catch (\Exception $e) { + $serializedData = $this->serializer->serializeException($e); + $this->assertSame('customMagicAuthThing', $serializedData['Trace'][0]['function']); + $this->assertSame(ExceptionSerializer::SENSITIVE_VALUE_PLACEHOLDER, $serializedData['Trace'][0]['args'][0]); + $this->assertFalse(isset($serializedData['Trace'][0]['args'][1])); + } + } +} diff --git a/tests/lib/Log/FileTest.php b/tests/lib/Log/FileTest.php index 937b3c75448..3f030665fb4 100644 --- a/tests/lib/Log/FileTest.php +++ b/tests/lib/Log/FileTest.php @@ -1,24 +1,18 @@ <?php + /** * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE - * License as published by the Free Software Foundation; either - * version 3 of the License, or any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU AFFERO GENERAL PUBLIC LICENSE for more details. - * - * You should have received a copy of the GNU Affero General Public - * License along with this library. If not, see <http://www.gnu.org/licenses/>. + * SPDX-FileCopyrightText: 2016-2024 Nextcloud GmbH and Nextcloud contributors + * SPDX-License-Identifier: AGPL-3.0-or-later */ namespace Test\Log; use OC\Log\File; +use OC\SystemConfig; +use OCP\IConfig; use OCP\ILogger; +use OCP\Server; use Test\TestCase; /** @@ -33,31 +27,52 @@ class FileTest extends TestCase { protected function setUp(): void { parent::setUp(); - $config = \OC::$server->getSystemConfig(); - $this->restore_logfile = $config->getValue("logfile"); + $config = Server::get(SystemConfig::class); + $this->restore_logfile = $config->getValue('logfile'); $this->restore_logdateformat = $config->getValue('logdateformat'); - - $config->setValue("logfile", $config->getValue('datadirectory') . "/logtest.log"); + + $config->setValue('logfile', $config->getValue('datadirectory') . '/logtest.log'); $this->logFile = new File($config->getValue('datadirectory') . '/logtest.log', '', $config); } protected function tearDown(): void { - $config = \OC::$server->getSystemConfig(); + $config = Server::get(SystemConfig::class); if (isset($this->restore_logfile)) { - $config->getValue("logfile", $this->restore_logfile); + $config->getValue('logfile', $this->restore_logfile); } else { - $config->deleteValue("logfile"); + $config->deleteValue('logfile'); } if (isset($this->restore_logdateformat)) { - $config->getValue("logdateformat", $this->restore_logdateformat); + $config->getValue('logdateformat', $this->restore_logdateformat); } else { - $config->deleteValue("logdateformat"); + $config->deleteValue('logdateformat'); } $this->logFile = new File($this->restore_logfile, '', $config); parent::tearDown(); } - - public function testMicrosecondsLogTimestamp() { - $config = \OC::$server->getConfig(); + + public function testLogging(): void { + $config = Server::get(IConfig::class); + # delete old logfile + unlink($config->getSystemValue('logfile')); + + # set format & write log line + $config->setSystemValue('logdateformat', 'u'); + $this->logFile->write('code', ['something' => 'extra', 'message' => 'Testing logging'], ILogger::ERROR); + + # read log line + $handle = @fopen($config->getSystemValue('logfile'), 'r'); + $line = fread($handle, 1000); + fclose($handle); + + # check log has data content + $values = (array)json_decode($line, true); + $this->assertArrayNotHasKey('message', $values['data']); + $this->assertEquals('extra', $values['data']['something']); + $this->assertEquals('Testing logging', $values['message']); + } + + public function testMicrosecondsLogTimestamp(): void { + $config = Server::get(IConfig::class); # delete old logfile unlink($config->getSystemValue('logfile')); @@ -69,9 +84,9 @@ class FileTest extends TestCase { $handle = @fopen($config->getSystemValue('logfile'), 'r'); $line = fread($handle, 1000); fclose($handle); - + # check timestamp has microseconds part - $values = (array) json_decode($line); + $values = (array)json_decode($line); $microseconds = $values['time']; $this->assertNotEquals(0, $microseconds); } diff --git a/tests/lib/Log/LogFactoryTest.php b/tests/lib/Log/LogFactoryTest.php index 91ff79369bf..b1adbd0e823 100644 --- a/tests/lib/Log/LogFactoryTest.php +++ b/tests/lib/Log/LogFactoryTest.php @@ -1,25 +1,8 @@ <?php + /** - * @copyright Copyright (c) 2018 Arthur Schiwon <blizzz@arthur-schiwon.de> - * - * @author Arthur Schiwon <blizzz@arthur-schiwon.de> - * @author Johannes Ernst <jernst@indiecomputing.com> - * - * @license GNU AGPL version 3 or any later version - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see <http://www.gnu.org/licenses/>. - * + * SPDX-FileCopyrightText: 2018 Nextcloud GmbH and Nextcloud contributors + * SPDX-License-Identifier: AGPL-3.0-or-later */ namespace Test\Log; @@ -30,6 +13,7 @@ use OC\Log\LogFactory; use OC\Log\Syslog; use OC\Log\Systemdlog; use OC\SystemConfig; +use OCP\AppFramework\QueryException; use OCP\IServerContainer; use Test\TestCase; @@ -57,7 +41,7 @@ class LogFactoryTest extends TestCase { $this->factory = new LogFactory($this->c, $this->systemConfig); } - public function fileTypeProvider(): array { + public static function fileTypeProvider(): array { return [ [ 'file' @@ -76,23 +60,26 @@ class LogFactoryTest extends TestCase { /** * @param string $type - * @dataProvider fileTypeProvider - * @throws \OCP\AppFramework\QueryException + * @throws QueryException */ - public function testFile(string $type) { - $datadir = \OC::$SERVERROOT.'/data'; + #[\PHPUnit\Framework\Attributes\DataProvider('fileTypeProvider')] + public function testFile(string $type): void { + $datadir = \OC::$SERVERROOT . '/data'; $defaultLog = $datadir . '/nextcloud.log'; $this->systemConfig->expects($this->exactly(3)) ->method('getValue') - ->withConsecutive(['datadirectory', $datadir], ['logfile', $defaultLog], ['logfilemode', 0640]) - ->willReturnOnConsecutiveCalls($datadir, $defaultLog, 0640); + ->willReturnMap([ + ['datadirectory', $datadir, $datadir], + ['logfile', $defaultLog, $defaultLog], + ['logfilemode', 0640, 0640], + ]); $log = $this->factory->get($type); $this->assertInstanceOf(File::class, $log); } - public function logFilePathProvider():array { + public static function logFilePathProvider():array { return [ [ '/dev/null', @@ -100,23 +87,26 @@ class LogFactoryTest extends TestCase { ], [ '/xdev/youshallfallback', - \OC::$SERVERROOT.'/data/nextcloud.log' + \OC::$SERVERROOT . '/data/nextcloud.log' ] ]; } /** - * @dataProvider logFilePathProvider - * @throws \OCP\AppFramework\QueryException + * @throws QueryException */ - public function testFileCustomPath($path, $expected) { - $datadir = \OC::$SERVERROOT.'/data'; + #[\PHPUnit\Framework\Attributes\DataProvider('logFilePathProvider')] + public function testFileCustomPath($path, $expected): void { + $datadir = \OC::$SERVERROOT . '/data'; $defaultLog = $datadir . '/nextcloud.log'; $this->systemConfig->expects($this->exactly(3)) ->method('getValue') - ->withConsecutive(['datadirectory', $datadir], ['logfile', $defaultLog], ['logfilemode', 0640]) - ->willReturnOnConsecutiveCalls($datadir, $path, 0640); + ->willReturnMap([ + ['datadirectory', $datadir, $datadir], + ['logfile', $defaultLog, $path], + ['logfilemode', 0640, 0640], + ]); $log = $this->factory->get('file'); $this->assertInstanceOf(File::class, $log); @@ -124,17 +114,17 @@ class LogFactoryTest extends TestCase { } /** - * @throws \OCP\AppFramework\QueryException + * @throws QueryException */ - public function testErrorLog() { + public function testErrorLog(): void { $log = $this->factory->get('errorlog'); $this->assertInstanceOf(Errorlog::class, $log); } /** - * @throws \OCP\AppFramework\QueryException + * @throws QueryException */ - public function testSystemLog() { + public function testSystemLog(): void { $this->c->expects($this->once()) ->method('resolve') ->with(Syslog::class) @@ -145,9 +135,9 @@ class LogFactoryTest extends TestCase { } /** - * @throws \OCP\AppFramework\QueryException + * @throws QueryException */ - public function testSystemdLog() { + public function testSystemdLog(): void { $this->c->expects($this->once()) ->method('resolve') ->with(Systemdlog::class) diff --git a/tests/lib/Log/PsrLoggerAdapterTest.php b/tests/lib/Log/PsrLoggerAdapterTest.php new file mode 100644 index 00000000000..c11af7a12c2 --- /dev/null +++ b/tests/lib/Log/PsrLoggerAdapterTest.php @@ -0,0 +1,82 @@ +<?php + +declare(strict_types=1); + +/** + * SPDX-FileCopyrightText: 2024 Nextcloud GmbH and Nextcloud contributors + * SPDX-License-Identifier: AGPL-3.0-or-later + */ + +namespace Test\Log; + +use OC\Log; +use OC\Log\PsrLoggerAdapter; +use OCP\ILogger; +use PHPUnit\Framework\MockObject\MockObject; +use Psr\Log\InvalidArgumentException; +use Psr\Log\LogLevel; +use Test\TestCase; + +class PsrLoggerAdapterTest extends TestCase { + protected Log&MockObject $logger; + protected PsrLoggerAdapter $loggerAdapter; + + protected function setUp(): void { + parent::setUp(); + + $this->logger = $this->createMock(Log::class); + $this->loggerAdapter = new PsrLoggerAdapter($this->logger); + } + + #[\PHPUnit\Framework\Attributes\DataProvider('dataPsrLoggingLevels')] + public function testLoggingWithPsrLogLevels(string $level, int $expectedLevel): void { + $this->logger->expects(self::once()) + ->method('log') + ->with($expectedLevel, 'test message', ['app' => 'test']); + $this->loggerAdapter->log($level, 'test message', ['app' => 'test']); + } + + #[\PHPUnit\Framework\Attributes\DataProvider('dataPsrLoggingLevels')] + public function testLogLevelToInt(string $level, int $expectedLevel): void { + $this->assertEquals($expectedLevel, PsrLoggerAdapter::logLevelToInt($level)); + } + + public static function dataPsrLoggingLevels(): array { + return [ + [LogLevel::ALERT, ILogger::ERROR], + [LogLevel::CRITICAL, ILogger::ERROR], + [LogLevel::DEBUG, ILogger::DEBUG], + [LogLevel::EMERGENCY, ILogger::FATAL], + [LogLevel::ERROR, ILogger::ERROR], + [LogLevel::INFO, ILogger::INFO], + [LogLevel::NOTICE, ILogger::INFO], + [LogLevel::WARNING, ILogger::WARN], + ]; + } + + #[\PHPUnit\Framework\Attributes\DataProvider('dataInvalidLoggingLevel')] + public function testInvalidLoggingLevel($level): void { + $this->logger->expects(self::never()) + ->method('log'); + $this->expectException(InvalidArgumentException::class); + + $this->loggerAdapter->log($level, 'valid message'); + } + + public static function dataInvalidLoggingLevel(): array { + return [ + // invalid string + ['this is not a level'], + // int out of range + [ILogger::DEBUG - 1], + [ILogger::FATAL + 1], + // float is not allowed + [1.2345], + // boolean is not a level + [true], + [false], + // + [null], + ]; + } +} |