From 4c28f9cf9c882803cc810327b657437f815afa43 Mon Sep 17 00:00:00 2001 From: Philipp Date: Sun, 15 Jan 2023 00:53:51 +0100 Subject: [PATCH 1/6] Config: Improve the node.config.php transformation - Add more types - Improvement for assoziative arrays and key-value arrays - Add a lot more tests --- .../Config/Util/ConfigFileTransformer.php | 202 ++++++++++++++---- tests/datasets/config/B.node.config.php | 8 +- .../{ => transformer}/C.node.config.php | 0 .../config/transformer/D.node.config.php | 8 + .../config/transformer/object.node.config.php | 7 + .../transformer/ressource.node.config.php | 7 + .../transformer/small_types.node.config.php | 12 ++ .../config/transformer/types.node.config.php | 75 +++++++ .../Config/Util/ConfigFileTransformerTest.php | 25 ++- 9 files changed, 301 insertions(+), 43 deletions(-) rename tests/datasets/config/{ => transformer}/C.node.config.php (100%) create mode 100644 tests/datasets/config/transformer/D.node.config.php create mode 100644 tests/datasets/config/transformer/object.node.config.php create mode 100644 tests/datasets/config/transformer/ressource.node.config.php create mode 100644 tests/datasets/config/transformer/small_types.node.config.php create mode 100644 tests/datasets/config/transformer/types.node.config.php diff --git a/src/Core/Config/Util/ConfigFileTransformer.php b/src/Core/Config/Util/ConfigFileTransformer.php index ac4990df13..7cd351ab8f 100644 --- a/src/Core/Config/Util/ConfigFileTransformer.php +++ b/src/Core/Config/Util/ConfigFileTransformer.php @@ -26,67 +26,191 @@ namespace Friendica\Core\Config\Util; */ class ConfigFileTransformer { + /** + * The public method to start the encoding + * + * @param array $data A full config array + * + * @return string The config stream, which can be saved + */ public static function encode(array $data): string { + // Add the typical header values $dataString = ' null," . PHP_EOL; - continue; - } - - $dataString .= "\t'$category' => [" . PHP_EOL; - - if (is_array($data[$category])) { - $keys = array_keys($data[$category]); - - foreach ($keys as $key) { - $dataString .= static::mapConfigValue($key, $data[$category][$key]); - } - } - $dataString .= "\t]," . PHP_EOL; - } - - $dataString .= "];" . PHP_EOL; + // the last array line, close it with a semicolon + $dataString .= ";" . PHP_EOL; return $dataString; } - protected static function extractArray(array $config, int $level = 0): string + /** + * Extracts an inner config array. + * Either as a Key => Value pair array or as an assoziative array + * + * @param array $config The config array which should get extracted + * @param int $level The current level of recursion (necessary for tab-indentation calculation) + * @param bool $inAssoziativeArray If true, the current array resides inside another assoziative array. Different rules may be applicable + * + * @return string The config string + */ + protected static function extractArray(array $config, int $level = 0, bool $inAssoziativeArray = false): string + { + if (array_values($config) === $config) { + return self::extractAssoziativeArray($config, $level, $inAssoziativeArray); + } else { + return self::extractKeyValueArray($config, $level, $inAssoziativeArray); + } + } + + /** + * Extracts a key-value array and save it into a string + * output: + * [ + * 'key' => value, + * 'key' => value, + * ... + * ] + * + * @param array $config The key-value array + * @param int $level The current level of recursion (necessary for tab-indentation calculation) + * @param bool $inAssoziativeArray If true, the current array resides inside another assoziative array. Different rules may be applicable + * + * @return string The config string + */ + protected static function extractKeyValueArray(array $config, int $level = 0, bool $inAssoziativeArray = false): string { $string = ''; - foreach ($config as $configKey => $configValue) { - $string .= static::mapConfigValue($configKey, $configValue, $level); + // Because we're in an assoziative array, we have to add a line-break first + if ($inAssoziativeArray) { + $string .= PHP_EOL . str_repeat("\t", $level); } + // Add a typical Line break for a taxative list of key-value pairs + $string .= '[' . PHP_EOL; + + foreach ($config as $configKey => $configValue) { + $string .= str_repeat("\t", $level + 1) . + "'$configKey' => " . + static::transformConfigValue($configValue, $level) . + ',' . PHP_EOL; + } + + $string .= str_repeat("\t", $level) . ']'; + return $string; } - protected static function mapConfigValue(string $key, $value, $level = 0): string + /** + * Extracts an assoziative array and save it into a string + * output1 - simple: + * [ value, value, value ] + * + * output2 - complex: + * [ + * [ value, value, value ], + * value, + * [ + * key => value, + * key => value, + * ], + * ] + * + * @param array $config The assoziative array + * @param int $level The current level of recursion (necessary for tab-indentation calculation) + * @param bool $inAssoziativeArray If true, the current array resides inside another assoziative array. Different rules may be applicable + * + * @return string The config string + */ + protected static function extractAssoziativeArray(array $config, int $level = 0, bool $inAssoziativeArray = false): string { - $string = str_repeat("\t", $level + 2) . "'$key' => "; + $string = '['; - if (is_null($value)) { - $string .= "null,"; - } elseif (is_array($value)) { - $string .= "[" . PHP_EOL; - $string .= static::extractArray($value, ++$level); - $string .= str_repeat("\t", $level + 1) . '],'; - } elseif (is_bool($value)) { - $string .= ($value ? 'true' : 'false') . ","; - } elseif (is_numeric($value)) { - $string .= $value . ","; - } else { - $string .= sprintf('\'%s\',', addcslashes($value, '\'\\')); + $countConfigValues = count($config); + // multiline defines, if each entry uses a new line + $multiline = false; + + // Search if any value is an array, because then other formatting rules are applicable + foreach ($config as $item) { + if (is_array($item)) { + $multiline = true; + break; + } } - $string .= PHP_EOL; + for ($i = 0; $i < $countConfigValues; $i++) { + $isArray = is_array($config[$i]); + + /** + * In case this is an array in an array, directly extract this array again and continue + * Skip any other logic since this isn't applicable for an array in an array + */ + if ($isArray) { + $string .= PHP_EOL . str_repeat("\t", $level + 1); + $string .= static::extractArray($config[$i], $level + 1, $inAssoziativeArray) . ','; + continue; + } + + if ($multiline) { + $string .= PHP_EOL . str_repeat("\t", $level + 1); + } + + $string .= static::transformConfigValue($config[$i], $level, true); + + // add trailing commas or whitespaces for certain config entries + if (($i < ($countConfigValues - 1))) { + $string .= ','; + if (!$multiline) { + $string .= ' '; + } + } + } + + // Add a new line for the last bracket as well + if ($multiline) { + $string .= PHP_EOL . str_repeat("\t", $level); + } + + $string .= ']'; return $string; } + + /** + * Transforms one config value and returns the corresponding text-representation + * + * @param mixed $value Any value to transform + * @param int $level The current level of recursion (necessary for tab-indentation calculation) + * @param bool $inAssoziativeArray If true, the current array resides inside another assoziative array. Different rules may be applicable + * + * @return string + */ + protected static function transformConfigValue($value, int $level = 0, bool $inAssoziativeArray = false): string + { + switch (gettype($value)) { + case "boolean": + return ($value ? 'true' : 'false'); + case "integer": + case "double": + return $value; + case "string": + return sprintf('\'%s\'', addcslashes($value, '\'\\')); + case "array": + return static::extractArray($value, ++$level, $inAssoziativeArray); + case "NULL": + return "null"; + case "object": + case "resource": + case "resource (closed)": + throw new \InvalidArgumentException(sprintf('%s in configs are not supported yet.', gettype($value))); + case "unknown type": + throw new \InvalidArgumentException(sprintf('%s is an unknown value', $value)); + default: + throw new \InvalidArgumentException(sprintf('%s is currently unsupported', $value)); + } + } } diff --git a/tests/datasets/config/B.node.config.php b/tests/datasets/config/B.node.config.php index 499e092a45..6b0f15ad1e 100644 --- a/tests/datasets/config/B.node.config.php +++ b/tests/datasets/config/B.node.config.php @@ -23,9 +23,13 @@ return [ 'string2' => 'false', ], ], - 'v' => true, - 'v3' => 1, + 'bool_true' => true, + 'bool_false' => false, + 'int_1_not_true' => 1, + 'int_0_not_false' => 0, 'v4' => 5.6443, + 'string_1_not_true' => '1', + 'string_0_not_false' => '0', ], ], 'system' => [ diff --git a/tests/datasets/config/C.node.config.php b/tests/datasets/config/transformer/C.node.config.php similarity index 100% rename from tests/datasets/config/C.node.config.php rename to tests/datasets/config/transformer/C.node.config.php diff --git a/tests/datasets/config/transformer/D.node.config.php b/tests/datasets/config/transformer/D.node.config.php new file mode 100644 index 0000000000..9e5707a9bb --- /dev/null +++ b/tests/datasets/config/transformer/D.node.config.php @@ -0,0 +1,8 @@ + [ + 'string_1_not_true' => '1', + 'string_0_not_false' => '0', + ], +]; diff --git a/tests/datasets/config/transformer/object.node.config.php b/tests/datasets/config/transformer/object.node.config.php new file mode 100644 index 0000000000..f1807199bc --- /dev/null +++ b/tests/datasets/config/transformer/object.node.config.php @@ -0,0 +1,7 @@ + [ + 'objects_not_supported' => new stdClass(), + ], +]; diff --git a/tests/datasets/config/transformer/ressource.node.config.php b/tests/datasets/config/transformer/ressource.node.config.php new file mode 100644 index 0000000000..b83a139e34 --- /dev/null +++ b/tests/datasets/config/transformer/ressource.node.config.php @@ -0,0 +1,7 @@ + [ + 'ressources_not_allowed' => new \GuzzleHttp\Psr7\AppendStream(), + ], +]; diff --git a/tests/datasets/config/transformer/small_types.node.config.php b/tests/datasets/config/transformer/small_types.node.config.php new file mode 100644 index 0000000000..4bf92e3b9b --- /dev/null +++ b/tests/datasets/config/transformer/small_types.node.config.php @@ -0,0 +1,12 @@ + [ + [ + 'key' => 'value', + ], + [ + 'key2' => 'value2', + ], + ], +]; diff --git a/tests/datasets/config/transformer/types.node.config.php b/tests/datasets/config/transformer/types.node.config.php new file mode 100644 index 0000000000..d2a7dfe57d --- /dev/null +++ b/tests/datasets/config/transformer/types.node.config.php @@ -0,0 +1,75 @@ + [ + 'bool_true' => true, + 'bool_false' => false, + 'int_1' => 1, + 'int_0' => 2, + 'int_12345' => 12345, + 'float' => 1.234, + 'double_E+' => 1.24E+20, + 'double_E-' => 7.0E-10, + 'null' => null, + 'array' => [1, '2', '3', 4.0E-10, 12345, 0, false, 'true', true], + 'array_keys' => [ + 'int_1' => 1, + 'string_2' => '2', + 'string_3' => '3', + 'double' => 4.0E-10, + 'int' => 12345, + 'int_0' => 0, + 'false' => false, + 'string_true' => 'true', + 'true' => true, + ], + 'array_extended' => [ + [ + 'key_1' => 'value_1', + 'key_2' => 'value_2', + 'key_3' => [ + 'inner_key' => 'inner_value', + ], + ], + [ + 'key_2' => false, + '0' => [ + 'is_that' => true, + '0' => [ + 'working' => '?', + ], + ], + 'inner_array' => [ + [ + 'key' => 'value', + 'key2' => 12, + ], + ], + 'key_3' => true, + ], + ['value', 'value2'], + [ + [ + 'key' => 123, + ], + 'test', + 'test52', + 'test23', + [ + 'key' => 456, + ], + ], + ], + ], + 'other_cat' => [ + 'key' => 'value', + ], + 'other_cat2' => [ + [ + 'key' => 'value', + ], + [ + 'key2' => 'value2', + ], + ], +]; diff --git a/tests/src/Core/Config/Util/ConfigFileTransformerTest.php b/tests/src/Core/Config/Util/ConfigFileTransformerTest.php index 5a0ab96a46..bb156cf282 100644 --- a/tests/src/Core/Config/Util/ConfigFileTransformerTest.php +++ b/tests/src/Core/Config/Util/ConfigFileTransformerTest.php @@ -36,8 +36,25 @@ class ConfigFileTransformerTest extends MockedTest 'configFile' => (dirname(__DIR__, 4) . '/datasets/config/B.node.config.php'), ], 'friendica.local' => [ - 'configFile' => (dirname(__DIR__, 4) . '/datasets/config/C.node.config.php'), + 'configFile' => (dirname(__DIR__, 4) . '/datasets/config/transformer/C.node.config.php'), ], + 'friendica.local.2' => [ + 'configFile' => (dirname(__DIR__, 4) . '/datasets/config/transformer/D.node.config.php'), + ], + 'object_invalid' => [ + 'configFile' => (dirname(__DIR__, 4) . '/datasets/config/transformer/object.node.config.php'), + 'assertException' => true, + ], + 'ressource_invalid' => [ + 'configFile' => (dirname(__DIR__, 4) . '/datasets/config/transformer/ressource.node.config.php'), + 'assertException' => true, + ], + 'test_types' => [ + 'configFile' => (dirname(__DIR__, 4) . '/datasets/config/transformer/types.node.config.php'), + ], + 'small_types' => [ + 'configFile' => (dirname(__DIR__, 4) . '/datasets/config/transformer/small_types.node.config.php'), + ] ]; } @@ -46,10 +63,14 @@ class ConfigFileTransformerTest extends MockedTest * * @dataProvider dataTests */ - public function testConfigFile(string $configFile) + public function testConfigFile(string $configFile, bool $assertException = false) { $dataArray = include $configFile; + if ($assertException) { + self::expectException(\InvalidArgumentException::class); + } + $newConfig = ConfigFileTransformer::encode($dataArray); self::assertEquals(file_get_contents($configFile), $newConfig); From bc60eb6cb7878745fe76d7998d87d1d611fa47b5 Mon Sep 17 00:00:00 2001 From: Philipp Date: Sun, 15 Jan 2023 11:57:43 +0100 Subject: [PATCH 2/6] Apply feedback and describe the encoding method --- .../Config/Util/ConfigFileTransformer.php | 62 +++++++++++-------- 1 file changed, 36 insertions(+), 26 deletions(-) diff --git a/src/Core/Config/Util/ConfigFileTransformer.php b/src/Core/Config/Util/ConfigFileTransformer.php index 7cd351ab8f..45e7a5522b 100644 --- a/src/Core/Config/Util/ConfigFileTransformer.php +++ b/src/Core/Config/Util/ConfigFileTransformer.php @@ -27,7 +27,17 @@ namespace Friendica\Core\Config\Util; class ConfigFileTransformer { /** - * The public method to start the encoding + * This method takes an array of config values and applies some standard rules for formatting on it + * + * Beware that the applied rules follow some basic formatting principles for node.config.php + * and doesn't support any custom formatting rules. + * + * f.e. associative array and list formatting are very complex with newlines and indentations, thus there are + * three hardcoded types of formatting for them. + * + * a negative example, what's NOT working: + * key => [ value1, [inner_value1, inner_value2], value2] + * Since this isn't necessary for config values, there's no further logic handling such complex-list-in-list scenarios * * @param array $data A full config array * @@ -49,20 +59,20 @@ class ConfigFileTransformer /** * Extracts an inner config array. - * Either as a Key => Value pair array or as an assoziative array + * Either as an associative array or as a list * - * @param array $config The config array which should get extracted - * @param int $level The current level of recursion (necessary for tab-indentation calculation) - * @param bool $inAssoziativeArray If true, the current array resides inside another assoziative array. Different rules may be applicable + * @param array $config The config array which should get extracted + * @param int $level The current level of recursion (necessary for tab-indentation calculation) + * @param bool $inList If true, the current array resides inside another list. Different rules may be applicable * * @return string The config string */ - protected static function extractArray(array $config, int $level = 0, bool $inAssoziativeArray = false): string + protected static function extractArray(array $config, int $level = 0, bool $inList = false): string { if (array_values($config) === $config) { - return self::extractAssoziativeArray($config, $level, $inAssoziativeArray); + return self::extractList($config, $level, $inList); } else { - return self::extractKeyValueArray($config, $level, $inAssoziativeArray); + return self::extractAssociativeArray($config, $level, $inList); } } @@ -75,18 +85,18 @@ class ConfigFileTransformer * ... * ] * - * @param array $config The key-value array - * @param int $level The current level of recursion (necessary for tab-indentation calculation) - * @param bool $inAssoziativeArray If true, the current array resides inside another assoziative array. Different rules may be applicable + * @param array $config The associative/key-value array + * @param int $level The current level of recursion (necessary for tab-indentation calculation) + * @param bool $inList If true, the current array resides inside another list. Different rules may be applicable * * @return string The config string */ - protected static function extractKeyValueArray(array $config, int $level = 0, bool $inAssoziativeArray = false): string + protected static function extractAssociativeArray(array $config, int $level = 0, bool $inList = false): string { $string = ''; - // Because we're in an assoziative array, we have to add a line-break first - if ($inAssoziativeArray) { + // Because we're in a list, we have to add a line-break first + if ($inList) { $string .= PHP_EOL . str_repeat("\t", $level); } @@ -106,7 +116,7 @@ class ConfigFileTransformer } /** - * Extracts an assoziative array and save it into a string + * Extracts a list and save it into a string * output1 - simple: * [ value, value, value ] * @@ -120,13 +130,13 @@ class ConfigFileTransformer * ], * ] * - * @param array $config The assoziative array - * @param int $level The current level of recursion (necessary for tab-indentation calculation) - * @param bool $inAssoziativeArray If true, the current array resides inside another assoziative array. Different rules may be applicable + * @param array $config The list + * @param int $level The current level of recursion (necessary for tab-indentation calculation) + * @param bool $inList If true, the current array resides inside another list. Different rules may be applicable * * @return string The config string */ - protected static function extractAssoziativeArray(array $config, int $level = 0, bool $inAssoziativeArray = false): string + protected static function extractList(array $config, int $level = 0, bool $inList = false): string { $string = '['; @@ -150,8 +160,8 @@ class ConfigFileTransformer * Skip any other logic since this isn't applicable for an array in an array */ if ($isArray) { - $string .= PHP_EOL . str_repeat("\t", $level + 1); - $string .= static::extractArray($config[$i], $level + 1, $inAssoziativeArray) . ','; + $string .= PHP_EOL . str_repeat("\t", $level + 1); + $string .= static::extractArray($config[$i], $level + 1, $inList) . ','; continue; } @@ -183,13 +193,13 @@ class ConfigFileTransformer /** * Transforms one config value and returns the corresponding text-representation * - * @param mixed $value Any value to transform - * @param int $level The current level of recursion (necessary for tab-indentation calculation) - * @param bool $inAssoziativeArray If true, the current array resides inside another assoziative array. Different rules may be applicable + * @param mixed $value Any value to transform + * @param int $level The current level of recursion (necessary for tab-indentation calculation) + * @param bool $inList If true, the current array resides inside another list. Different rules may be applicable * * @return string */ - protected static function transformConfigValue($value, int $level = 0, bool $inAssoziativeArray = false): string + protected static function transformConfigValue($value, int $level = 0, bool $inList = false): string { switch (gettype($value)) { case "boolean": @@ -200,7 +210,7 @@ class ConfigFileTransformer case "string": return sprintf('\'%s\'', addcslashes($value, '\'\\')); case "array": - return static::extractArray($value, ++$level, $inAssoziativeArray); + return static::extractArray($value, ++$level, $inList); case "NULL": return "null"; case "object": From 6e4663e74772c0d19756511bf6503a0f44ee846f Mon Sep 17 00:00:00 2001 From: Hypolite Petovan Date: Sun, 15 Jan 2023 09:42:18 -0500 Subject: [PATCH 3/6] Remove App dependency from addon admin form method --- src/Module/Admin/Addons/Details.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Module/Admin/Addons/Details.php b/src/Module/Admin/Addons/Details.php index 9bca70a203..6786d89eea 100644 --- a/src/Module/Admin/Addons/Details.php +++ b/src/Module/Admin/Addons/Details.php @@ -102,7 +102,7 @@ class Details extends BaseAdmin if (array_key_exists($addon, $addons_admin)) { require_once "addon/$addon/$addon.php"; $func = $addon . '_addon_admin'; - $func($a, $admin_form); + $func($admin_form); } $t = Renderer::getMarkupTemplate('admin/addons/details.tpl'); From a6fb683bcd975c98eeb43b53d70cd1b243f933b4 Mon Sep 17 00:00:00 2001 From: Philipp Date: Sun, 15 Jan 2023 13:46:01 +0100 Subject: [PATCH 4/6] Remove BasePath dependency from App\Mode --- src/App/Mode.php | 11 ++++------- static/dependencies.config.php | 4 +++- tests/src/App/ModeTest.php | 25 ++++++------------------- 3 files changed, 13 insertions(+), 27 deletions(-) diff --git a/src/App/Mode.php b/src/App/Mode.php index 514df91c64..48c88d803a 100644 --- a/src/App/Mode.php +++ b/src/App/Mode.php @@ -24,7 +24,6 @@ namespace Friendica\App; use Detection\MobileDetect; use Friendica\Core\Config\ValueObject\Cache; use Friendica\Database\Database; -use Friendica\Util\BasePath; /** * Mode of the current Friendica Node @@ -129,15 +128,13 @@ class Mode * * @throws \Exception */ - public function determine(BasePath $basepath, Database $database, Cache $configCache): Mode + public function determine(string $basePath, Database $database, Cache $configCache): Mode { $mode = 0; - $basepathName = $basepath->getPath(); - - if (!file_exists($basepathName . '/config/local.config.php') - && !file_exists($basepathName . '/config/local.ini.php') - && !file_exists($basepathName . '/.htconfig.php')) { + if (!file_exists($basePath . '/config/local.config.php') && + !file_exists($basePath . '/config/local.ini.php') && + !file_exists($basePath . '/.htconfig.php')) { return new Mode($mode); } diff --git a/static/dependencies.config.php b/static/dependencies.config.php index 6feb76989b..1836a44dd5 100644 --- a/static/dependencies.config.php +++ b/static/dependencies.config.php @@ -94,7 +94,9 @@ return [ App\Mode::class => [ 'call' => [ ['determineRunMode', [true, $_SERVER], Dice::CHAIN_CALL], - ['determine', [], Dice::CHAIN_CALL], + ['determine', [ + [Dice::INSTANCE => '$basepath'] + ], Dice::CHAIN_CALL], ], ], Config\Capability\IManageConfigValues::class => [ diff --git a/tests/src/App/ModeTest.php b/tests/src/App/ModeTest.php index aecd2b1752..a651a73b1d 100644 --- a/tests/src/App/ModeTest.php +++ b/tests/src/App/ModeTest.php @@ -57,7 +57,6 @@ class ModeTest extends MockedTest $this->setUpVfsDir(); - $this->basePathMock = Mockery::mock(BasePath::class); $this->databaseMock = Mockery::mock(Database::class); $this->configCacheMock = Mockery::mock(Cache::class); } @@ -71,15 +70,13 @@ class ModeTest extends MockedTest public function testWithoutConfig() { - $this->basePathMock->shouldReceive('getPath')->andReturn($this->root->url())->once(); - self::assertTrue($this->root->hasChild('config/local.config.php')); $this->delConfigFile('local.config.php'); self::assertFalse($this->root->hasChild('config/local.config.php')); - $mode = (new Mode())->determine($this->basePathMock, $this->databaseMock, $this->configCacheMock); + $mode = (new Mode())->determine($this->root->url(), $this->databaseMock, $this->configCacheMock); self::assertTrue($mode->isInstall()); self::assertFalse($mode->isNormal()); @@ -89,11 +86,9 @@ class ModeTest extends MockedTest public function testWithoutDatabase() { - $this->basePathMock->shouldReceive('getPath')->andReturn($this->root->url())->once(); - $this->databaseMock->shouldReceive('connected')->andReturn(false)->once(); - $mode = (new Mode())->determine($this->basePathMock, $this->databaseMock, $this->configCacheMock); + $mode = (new Mode())->determine($this->root->url(), $this->databaseMock, $this->configCacheMock); self::assertFalse($mode->isNormal()); self::assertTrue($mode->isInstall()); @@ -104,13 +99,11 @@ class ModeTest extends MockedTest public function testWithMaintenanceMode() { - $this->basePathMock->shouldReceive('getPath')->andReturn($this->root->url())->once(); - $this->databaseMock->shouldReceive('connected')->andReturn(true)->once(); $this->configCacheMock->shouldReceive('get')->with('system', 'maintenance') ->andReturn(true)->once(); - $mode = (new Mode())->determine($this->basePathMock, $this->databaseMock, $this->configCacheMock); + $mode = (new Mode())->determine($this->root->url(), $this->databaseMock, $this->configCacheMock); self::assertFalse($mode->isNormal()); self::assertFalse($mode->isInstall()); @@ -120,13 +113,11 @@ class ModeTest extends MockedTest public function testNormalMode() { - $this->basePathMock->shouldReceive('getPath')->andReturn($this->root->url())->once(); - $this->databaseMock->shouldReceive('connected')->andReturn(true)->once(); $this->configCacheMock->shouldReceive('get')->with('system', 'maintenance') ->andReturn(false)->once(); - $mode = (new Mode())->determine($this->basePathMock, $this->databaseMock, $this->configCacheMock); + $mode = (new Mode())->determine($this->root->url(), $this->databaseMock, $this->configCacheMock); self::assertTrue($mode->isNormal()); self::assertFalse($mode->isInstall()); @@ -139,13 +130,11 @@ class ModeTest extends MockedTest */ public function testDisabledMaintenance() { - $this->basePathMock->shouldReceive('getPath')->andReturn($this->root->url())->once(); - $this->databaseMock->shouldReceive('connected')->andReturn(true)->once(); $this->configCacheMock->shouldReceive('get')->with('system', 'maintenance') ->andReturn(false)->once(); - $mode = (new Mode())->determine($this->basePathMock, $this->databaseMock, $this->configCacheMock); + $mode = (new Mode())->determine($this->root->url(), $this->databaseMock, $this->configCacheMock); self::assertTrue($mode->isNormal()); self::assertFalse($mode->isInstall()); @@ -158,11 +147,9 @@ class ModeTest extends MockedTest */ public function testImmutable() { - $this->basePathMock->shouldReceive('getPath')->andReturn(null)->once(); - $mode = new Mode(); - $modeNew = $mode->determine($this->basePathMock, $this->databaseMock, $this->configCacheMock); + $modeNew = $mode->determine('', $this->databaseMock, $this->configCacheMock); self::assertNotSame($modeNew, $mode); } From ab6efea9b25f082c93ce7cc4c087002d57041d22 Mon Sep 17 00:00:00 2001 From: Philipp Date: Sun, 15 Jan 2023 16:12:25 +0100 Subject: [PATCH 5/6] Replace Config-Cache dependency with Config-Model (no more DB-waiting necessary) --- src/App.php | 2 - src/App/Mode.php | 6 +- src/Console/DatabaseStructure.php | 12 +- src/Core/PConfig/Factory/PConfig.php | 12 +- src/Database/Database.php | 56 ++++----- src/Module/Admin/Summary.php | 2 - src/Util/Profiler.php | 113 +++++++----------- tests/FixtureTest.php | 6 +- tests/Util/CreateDatabaseTrait.php | 53 ++++++++ tests/functional/DependencyCheckTest.php | 28 +---- tests/src/App/ModeTest.php | 28 ++--- tests/src/Core/Cache/DatabaseCacheTest.php | 3 +- .../KeyValueStorage/DBKeyValueStorageTest.php | 19 +-- .../src/Core/Lock/DatabaseLockDriverTest.php | 30 +---- .../src/Core/Storage/DatabaseStorageTest.php | 33 +---- .../Storage/Repository/StorageManagerTest.php | 49 ++++---- tests/src/Util/BaseURLTest.php | 2 - tests/src/Util/ProfilerTest.php | 81 ++----------- 18 files changed, 210 insertions(+), 325 deletions(-) create mode 100644 tests/Util/CreateDatabaseTrait.php diff --git a/src/App.php b/src/App.php index 378ddbc9de..a5ef7970d5 100644 --- a/src/App.php +++ b/src/App.php @@ -357,8 +357,6 @@ class App $this->profiler->reset(); if ($this->mode->has(App\Mode::DBAVAILABLE)) { - $this->profiler->update($this->config); - Core\Hook::loadHooks(); $loader = (new Config())->createConfigFileManager($this->getBasePath(), $_SERVER); Core\Hook::callAll('load_config', $loader); diff --git a/src/App/Mode.php b/src/App/Mode.php index 48c88d803a..7cd16b4bb9 100644 --- a/src/App/Mode.php +++ b/src/App/Mode.php @@ -22,7 +22,7 @@ namespace Friendica\App; use Detection\MobileDetect; -use Friendica\Core\Config\ValueObject\Cache; +use Friendica\Core\Config\Capability\IManageConfigValues; use Friendica\Database\Database; /** @@ -128,7 +128,7 @@ class Mode * * @throws \Exception */ - public function determine(string $basePath, Database $database, Cache $configCache): Mode + public function determine(string $basePath, Database $database, IManageConfigValues $config): Mode { $mode = 0; @@ -146,7 +146,7 @@ class Mode $mode |= Mode::DBAVAILABLE; - if (!empty($configCache->get('system', 'maintenance'))) { + if (!empty($config->get('system', 'maintenance'))) { return new Mode($mode); } diff --git a/src/Console/DatabaseStructure.php b/src/Console/DatabaseStructure.php index c78d8ace85..4d4125e88a 100644 --- a/src/Console/DatabaseStructure.php +++ b/src/Console/DatabaseStructure.php @@ -21,7 +21,7 @@ namespace Friendica\Console; -use Friendica\Core\Config\ValueObject\Cache; +use Friendica\Core\Config\Capability\IManageConfigValues; use Friendica\Core\Update; use Friendica\Database\Database; use Friendica\Database\DBStructure; @@ -43,8 +43,8 @@ class DatabaseStructure extends \Asika\SimpleConsole\Console /** @var Database */ private $dba; - /** @var Cache */ - private $configCache; + /** @var IManageConfigValues */ + private $config; /** @var DbaDefinition */ private $dbaDefinition; @@ -83,14 +83,14 @@ HELP; return $help; } - public function __construct(Database $dba, DbaDefinition $dbaDefinition, ViewDefinition $viewDefinition, BasePath $basePath, Cache $configCache, $argv = null) + public function __construct(Database $dba, DbaDefinition $dbaDefinition, ViewDefinition $viewDefinition, BasePath $basePath, IManageConfigValues $config, $argv = null) { parent::__construct($argv); $this->dba = $dba; $this->dbaDefinition = $dbaDefinition; $this->viewDefinition = $viewDefinition; - $this->configCache = $configCache; + $this->config = $config; $this->basePath = $basePath->getPath(); } @@ -117,7 +117,7 @@ HELP; throw new RuntimeException('Unable to connect to database'); } - $basePath = $this->configCache->get('system', 'basepath'); + $basePath = $this->config->get('system', 'basepath'); switch ($this->getArgument(0)) { case "dryrun": diff --git a/src/Core/PConfig/Factory/PConfig.php b/src/Core/PConfig/Factory/PConfig.php index d388d2b0c4..cde97759e9 100644 --- a/src/Core/PConfig/Factory/PConfig.php +++ b/src/Core/PConfig/Factory/PConfig.php @@ -21,7 +21,7 @@ namespace Friendica\Core\PConfig\Factory; -use Friendica\Core\Config\ValueObject\Cache; +use Friendica\Core\Config\Capability\IManageConfigValues; use Friendica\Core\PConfig\Capability\IManagePersonalConfigValues; use Friendica\Core\PConfig\Repository; use Friendica\Core\PConfig\Type; @@ -30,15 +30,15 @@ use Friendica\Core\PConfig\ValueObject; class PConfig { /** - * @param Cache $configCache The config cache - * @param ValueObject\Cache $pConfigCache The personal config cache - * @param Repository\PConfig $configRepo The configuration model + * @param IManageConfigValues $config The config + * @param ValueObject\Cache $pConfigCache The personal config cache + * @param Repository\PConfig $configRepo The configuration model * * @return IManagePersonalConfigValues */ - public function create(Cache $configCache, ValueObject\Cache $pConfigCache, Repository\PConfig $configRepo): IManagePersonalConfigValues + public function create(IManageConfigValues $config, ValueObject\Cache $pConfigCache, Repository\PConfig $configRepo): IManagePersonalConfigValues { - if ($configCache->get('system', 'config_adapter') === 'preload') { + if ($config->get('system', 'config_adapter') === 'preload') { $configuration = new Type\PreloadPConfig($pConfigCache, $configRepo); } else { $configuration = new Type\JitPConfig($pConfigCache, $configRepo); diff --git a/src/Database/Database.php b/src/Database/Database.php index 7126aa4fad..032a282030 100644 --- a/src/Database/Database.php +++ b/src/Database/Database.php @@ -21,7 +21,7 @@ namespace Friendica\Database; -use Friendica\Core\Config\ValueObject\Cache; +use Friendica\Core\Config\Capability\IManageConfigValues; use Friendica\Core\System; use Friendica\Database\Definition\DbaDefinition; use Friendica\Database\Definition\ViewDefinition; @@ -53,9 +53,9 @@ class Database protected $connected = false; /** - * @var \Friendica\Core\Config\ValueObject\Cache + * @var IManageConfigValues */ - protected $configCache; + protected $config; /** * @var Profiler */ @@ -81,11 +81,11 @@ class Database /** @var ViewDefinition */ protected $viewDefinition; - public function __construct(Cache $configCache, Profiler $profiler, DbaDefinition $dbaDefinition, ViewDefinition $viewDefinition) + public function __construct(IManageConfigValues $config, Profiler $profiler, DbaDefinition $dbaDefinition, ViewDefinition $viewDefinition) { // We are storing these values for being able to perform a reconnect - $this->configCache = $configCache; - $this->profiler = $profiler; + $this->config = $config; + $this->profiler = $profiler; $this->dbaDefinition = $dbaDefinition; $this->viewDefinition = $viewDefinition; @@ -110,32 +110,32 @@ class Database $this->connected = false; $port = 0; - $serveraddr = trim($this->configCache->get('database', 'hostname') ?? ''); + $serveraddr = trim($this->config->get('database', 'hostname') ?? ''); $serverdata = explode(':', $serveraddr); $host = trim($serverdata[0]); if (count($serverdata) > 1) { $port = trim($serverdata[1]); } - if (trim($this->configCache->get('database', 'port') ?? 0)) { - $port = trim($this->configCache->get('database', 'port') ?? 0); + if (trim($this->config->get('database', 'port') ?? 0)) { + $port = trim($this->config->get('database', 'port') ?? 0); } - $user = trim($this->configCache->get('database', 'username')); - $pass = trim($this->configCache->get('database', 'password')); - $database = trim($this->configCache->get('database', 'database')); - $charset = trim($this->configCache->get('database', 'charset')); - $socket = trim($this->configCache->get('database', 'socket')); + $user = trim($this->config->get('database', 'username')); + $pass = trim($this->config->get('database', 'password')); + $database = trim($this->config->get('database', 'database')); + $charset = trim($this->config->get('database', 'charset')); + $socket = trim($this->config->get('database', 'socket')); if (!$host && !$socket || !$user) { return false; } - $persistent = (bool)$this->configCache->get('database', 'persistent'); + $persistent = (bool)$this->config->get('database', 'persistent'); - $this->pdo_emulate_prepares = (bool)$this->configCache->get('database', 'pdo_emulate_prepares'); + $this->pdo_emulate_prepares = (bool)$this->config->get('database', 'pdo_emulate_prepares'); - if (!$this->configCache->get('database', 'disable_pdo') && class_exists('\PDO') && in_array('mysql', PDO::getAvailableDrivers())) { + if (!$this->config->get('database', 'disable_pdo') && class_exists('\PDO') && in_array('mysql', PDO::getAvailableDrivers())) { $this->driver = self::PDO; if ($socket) { $connect = 'mysql:unix_socket=' . $socket; @@ -317,7 +317,7 @@ class Database private function logIndex(string $query) { - if (!$this->configCache->get('system', 'db_log_index')) { + if (!$this->config->get('system', 'db_log_index')) { return; } @@ -336,18 +336,18 @@ class Database return; } - $watchlist = explode(',', $this->configCache->get('system', 'db_log_index_watch')); - $denylist = explode(',', $this->configCache->get('system', 'db_log_index_denylist')); + $watchlist = explode(',', $this->config->get('system', 'db_log_index_watch')); + $denylist = explode(',', $this->config->get('system', 'db_log_index_denylist')); while ($row = $this->fetch($r)) { - if ((intval($this->configCache->get('system', 'db_loglimit_index')) > 0)) { + if ((intval($this->config->get('system', 'db_loglimit_index')) > 0)) { $log = (in_array($row['key'], $watchlist) && - ($row['rows'] >= intval($this->configCache->get('system', 'db_loglimit_index')))); + ($row['rows'] >= intval($this->config->get('system', 'db_loglimit_index')))); } else { $log = false; } - if ((intval($this->configCache->get('system', 'db_loglimit_index_high')) > 0) && ($row['rows'] >= intval($this->configCache->get('system', 'db_loglimit_index_high')))) { + if ((intval($this->config->get('system', 'db_loglimit_index_high')) > 0) && ($row['rows'] >= intval($this->config->get('system', 'db_loglimit_index_high')))) { $log = true; } @@ -358,7 +358,7 @@ class Database if ($log) { $backtrace = debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS); @file_put_contents( - $this->configCache->get('system', 'db_log_index'), + $this->config->get('system', 'db_log_index'), DateTimeFormat::utcNow() . "\t" . $row['key'] . "\t" . $row['rows'] . "\t" . $row['Extra'] . "\t" . basename($backtrace[1]["file"]) . "\t" . @@ -533,7 +533,7 @@ class Database $orig_sql = $sql; - if ($this->configCache->get('system', 'db_callstack') !== null) { + if ($this->config->get('system', 'db_callstack') !== null) { $sql = "/*" . System::callstack() . " */ " . $sql; } @@ -738,16 +738,16 @@ class Database $this->profiler->stopRecording(); - if ($this->configCache->get('system', 'db_log')) { + if ($this->config->get('system', 'db_log')) { $stamp2 = microtime(true); $duration = (float)($stamp2 - $stamp1); - if (($duration > $this->configCache->get('system', 'db_loglimit'))) { + if (($duration > $this->config->get('system', 'db_loglimit'))) { $duration = round($duration, 3); $backtrace = debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS); @file_put_contents( - $this->configCache->get('system', 'db_log'), + $this->config->get('system', 'db_log'), DateTimeFormat::utcNow() . "\t" . $duration . "\t" . basename($backtrace[1]["file"]) . "\t" . $backtrace[1]["line"] . "\t" . $backtrace[2]["function"] . "\t" . diff --git a/src/Module/Admin/Summary.php b/src/Module/Admin/Summary.php index 13ef0fd716..e963e7606d 100644 --- a/src/Module/Admin/Summary.php +++ b/src/Module/Admin/Summary.php @@ -25,14 +25,12 @@ use Friendica\App; use Friendica\Core\Addon; use Friendica\Core\Config\Util\ConfigFileManager; use Friendica\Core\Config\ValueObject\Cache; -use Friendica\Core\Logger; use Friendica\Core\Renderer; use Friendica\Core\Update; use Friendica\Database\DBA; use Friendica\Database\DBStructure; use Friendica\DI; use Friendica\Core\Config\Factory\Config; -use Friendica\Model\Register; use Friendica\Module\BaseAdmin; use Friendica\Network\HTTPClient\Client\HttpClientAccept; use Friendica\Network\HTTPException\ServiceUnavailableException; diff --git a/src/Util/Profiler.php b/src/Util/Profiler.php index 0f68f9bf7f..d626288993 100644 --- a/src/Util/Profiler.php +++ b/src/Util/Profiler.php @@ -21,7 +21,6 @@ namespace Friendica\Util; -use Friendica\Core\Config\ValueObject\Cache; use Friendica\Core\Config\Capability\IManageConfigValues; use Friendica\Core\System; use Psr\Container\ContainerExceptionInterface; @@ -66,30 +65,10 @@ class Profiler implements ContainerInterface return $this->rendertime; } - /** - * Updates the enabling of the current profiler - * - * Note: The reason there are two different ways of updating the configuration of this class is because it can - * be used even with no available database connection which IManageConfigValues doesn't ensure. - * - * @param IManageConfigValues $config - */ - public function update(IManageConfigValues $config) + public function __construct(IManageConfigValues $config) { - $this->enabled = (bool) $config->get('system', 'profiler') ?? false; - $this->rendertime = (bool) $config->get('rendertime', 'callstack') ?? false; - } - - /** - * Note: The reason we are using a Config Cache object to initialize this class is to ensure it'll work even with no - * available database connection. - * - * @param \Friendica\Core\Config\ValueObject\Cache $configCache The configuration cache - */ - public function __construct(Cache $configCache) - { - $this->enabled = (bool) $configCache->get('system', 'profiler') ?? false; - $this->rendertime = (bool) $configCache->get('rendertime', 'callstack') ?? false; + $this->enabled = (bool)$config->get('system', 'profiler') ?? false; + $this->rendertime = (bool)$config->get('rendertime', 'callstack') ?? false; $this->reset(); } @@ -125,7 +104,7 @@ class Profiler implements ContainerInterface $timestamp = array_pop($this->timestamps); $duration = floatval(microtime(true) - $timestamp['stamp'] - $timestamp['credit']); - $value = $timestamp['value']; + $value = $timestamp['value']; foreach ($this->timestamps as $key => $stamp) { $this->timestamps[$key]['credit'] += $duration; @@ -137,15 +116,15 @@ class Profiler implements ContainerInterface $this->performance[$value] = 0; } - $this->performance[$value] += (float) $duration; - $this->performance['marktime'] += (float) $duration; + $this->performance[$value] += (float)$duration; + $this->performance['marktime'] += (float)$duration; if (!isset($this->callstack[$value][$callstack])) { // Prevent ugly E_NOTICE $this->callstack[$value][$callstack] = 0; } - $this->callstack[$value][$callstack] += (float) $duration; + $this->callstack[$value][$callstack] += (float)$duration; } /** @@ -173,15 +152,15 @@ class Profiler implements ContainerInterface $this->performance[$value] = 0; } - $this->performance[$value] += (float) $duration; - $this->performance['marktime'] += (float) $duration; + $this->performance[$value] += (float)$duration; + $this->performance['marktime'] += (float)$duration; if (!isset($this->callstack[$value][$callstack])) { // Prevent ugly E_NOTICE $this->callstack[$value][$callstack] = 0; } - $this->callstack[$value][$callstack] += (float) $duration; + $this->callstack[$value][$callstack] += (float)$duration; } /** @@ -202,23 +181,22 @@ class Profiler implements ContainerInterface */ public function resetPerformance() { - $this->performance = []; - $this->performance['start'] = microtime(true); - $this->performance['ready'] = 0; - $this->performance['database'] = 0; + $this->performance = []; + $this->performance['start'] = microtime(true); + $this->performance['ready'] = 0; + $this->performance['database'] = 0; $this->performance['database_write'] = 0; - $this->performance['cache'] = 0; - $this->performance['cache_write'] = 0; - $this->performance['network'] = 0; - $this->performance['file'] = 0; - $this->performance['rendering'] = 0; - $this->performance['session'] = 0; - $this->performance['marktime'] = 0; - $this->performance['marktime'] = microtime(true); - $this->performance['classcreate'] = 0; - $this->performance['classinit'] = 0; - $this->performance['init'] = 0; - $this->performance['content'] = 0; + $this->performance['cache'] = 0; + $this->performance['cache_write'] = 0; + $this->performance['network'] = 0; + $this->performance['file'] = 0; + $this->performance['rendering'] = 0; + $this->performance['session'] = 0; + $this->performance['marktime'] = microtime(true); + $this->performance['classcreate'] = 0; + $this->performance['classinit'] = 0; + $this->performance['init'] = 0; + $this->performance['content'] = 0; } /** @@ -228,19 +206,20 @@ class Profiler implements ContainerInterface */ public function resetCallstack() { - $this->callstack = []; - $this->callstack['database'] = []; + $this->callstack = []; + $this->callstack['database'] = []; $this->callstack['database_write'] = []; - $this->callstack['cache'] = []; - $this->callstack['cache_write'] = []; - $this->callstack['network'] = []; - $this->callstack['file'] = []; - $this->callstack['rendering'] = []; - $this->callstack['session'] = []; + $this->callstack['cache'] = []; + $this->callstack['cache_write'] = []; + $this->callstack['network'] = []; + $this->callstack['file'] = []; + $this->callstack['rendering'] = []; + $this->callstack['session'] = []; } /** * Returns the rendertime string + * * @param float $limit Minimal limit for displaying the execution duration * * @return string the rendertime @@ -330,17 +309,17 @@ class Profiler implements ContainerInterface $logger->info( $message, [ - 'action' => 'profiling', - 'database_read' => round($this->get('database') - $this->get('database_write'), 3), + 'action' => 'profiling', + 'database_read' => round($this->get('database') - $this->get('database_write'), 3), 'database_write' => round($this->get('database_write'), 3), - 'cache_read' => round($this->get('cache'), 3), - 'cache_write' => round($this->get('cache_write'), 3), - 'network_io' => round($this->get('network'), 2), - 'file_io' => round($this->get('file'), 2), - 'other_io' => round($duration - ($this->get('database') - + $this->get('cache') + $this->get('cache_write') - + $this->get('network') + $this->get('file')), 2), - 'total' => round($duration, 2) + 'cache_read' => round($this->get('cache'), 3), + 'cache_write' => round($this->get('cache_write'), 3), + 'network_io' => round($this->get('network'), 2), + 'file_io' => round($this->get('file'), 2), + 'other_io' => round($duration - ($this->get('database') + + $this->get('cache') + $this->get('cache_write') + + $this->get('network') + $this->get('file')), 2), + 'total' => round($duration, 2) ] ); @@ -355,10 +334,10 @@ class Profiler implements ContainerInterface * * @param string $id Identifier of the entry to look for. * - * @throws NotFoundExceptionInterface No entry was found for **this** identifier. + * @return float Entry. * @throws ContainerExceptionInterface Error while retrieving the entry. * - * @return float Entry. + * @throws NotFoundExceptionInterface No entry was found for **this** identifier. */ public function get(string $id): float { diff --git a/tests/FixtureTest.php b/tests/FixtureTest.php index e0d2f23379..d16119dd91 100644 --- a/tests/FixtureTest.php +++ b/tests/FixtureTest.php @@ -25,9 +25,9 @@ namespace Friendica\Test; use Dice\Dice; use Friendica\App\Arguments; use Friendica\App\Router; +use Friendica\Core\Config\Capability\IManageConfigValues; use Friendica\Core\Config\Factory\Config; use Friendica\Core\Config\Util\ConfigFileManager; -use Friendica\Core\Config\ValueObject\Cache; use Friendica\Core\Session\Capability\IHandleSessions; use Friendica\Core\Session\Type\Memory; use Friendica\Database\Database; @@ -74,8 +74,8 @@ abstract class FixtureTest extends DatabaseTest ]); DI::init($this->dice); - $configCache = $this->dice->create(Cache::class); - $configCache->set('database', 'disable_pdo', true); + $config = $this->dice->create(IManageConfigValues::class); + $config->set('database', 'disable_pdo', true); /** @var Database $dba */ $dba = $this->dice->create(Database::class); diff --git a/tests/Util/CreateDatabaseTrait.php b/tests/Util/CreateDatabaseTrait.php new file mode 100644 index 0000000000..51f74c7a52 --- /dev/null +++ b/tests/Util/CreateDatabaseTrait.php @@ -0,0 +1,53 @@ +. + * + */ + +namespace Friendica\Test\Util; + +use Friendica\Core\Config\Model\Config; +use Friendica\Core\Config\Util\ConfigFileManager; +use Friendica\Core\Config\ValueObject\Cache; +use Friendica\Database\Database; +use Friendica\Database\Definition\DbaDefinition; +use Friendica\Database\Definition\ViewDefinition; +use Friendica\Test\DatabaseTestTrait; +use Friendica\Test\Util\Database\StaticDatabase; +use Friendica\Util\Profiler; + +trait CreateDatabaseTrait +{ + use DatabaseTestTrait; + use VFSTrait; + + public function getDbInstance(): Database + { + $configFileManager = new ConfigFileManager($this->root->url(), $this->root->url() . '/config/', $this->root->url() . '/static/'); + $config = new Config($configFileManager, new Cache([ + 'database' => [ + 'disable_pdo' => true + ], + ])); + + $database = new StaticDatabase($config, new Profiler($config), (new DbaDefinition($this->root->url()))->load(), (new ViewDefinition($this->root->url()))->load()); + $database->setTestmode(true); + + return $database; + } +} diff --git a/tests/functional/DependencyCheckTest.php b/tests/functional/DependencyCheckTest.php index a371ffea4c..86724bf437 100644 --- a/tests/functional/DependencyCheckTest.php +++ b/tests/functional/DependencyCheckTest.php @@ -25,6 +25,7 @@ use Dice\Dice; use Friendica\App; use Friendica\Core\Cache\Capability\ICanCache; use Friendica\Core\Cache\Capability\ICanCacheInMemory; +use Friendica\Core\Config\Model\Config; use Friendica\Core\Config\ValueObject\Cache; use Friendica\Core\Config\Capability\IManageConfigValues; use Friendica\Core\Lock\Capability\ICanLock; @@ -86,33 +87,6 @@ class DependencyCheckTest extends TestCase self::assertArrayHasKey('system', $configCache->getAll()); } - /** - * Test the construction of a profiler class with DI - */ - public function testProfiler() - { - /** @var Profiler $profiler */ - $profiler = $this->dice->create(Profiler::class); - - self::assertInstanceOf(Profiler::class, $profiler); - - $configCache = new Cache([ - 'system' => [ - 'profiler' => true, - ], - 'rendertime' => [ - 'callstack' => true, - ] - ]); - - // create new DI-library because of shared instance rule (so the Profiler wouldn't get created twice) - $this->dice = new Dice(); - $profiler = $this->dice->create(Profiler::class, [$configCache]); - - self::assertInstanceOf(Profiler::class, $profiler); - self::assertTrue($profiler->isRendertime()); - } - public function testDatabase() { // PDO needs to be disabled for PHP 7.2, see https://jira.mariadb.org/browse/MDEV-24121 diff --git a/tests/src/App/ModeTest.php b/tests/src/App/ModeTest.php index a651a73b1d..c70ebf6f6d 100644 --- a/tests/src/App/ModeTest.php +++ b/tests/src/App/ModeTest.php @@ -24,7 +24,7 @@ namespace Friendica\Test\src\App; use Detection\MobileDetect; use Friendica\App\Arguments; use Friendica\App\Mode; -use Friendica\Core\Config\ValueObject\Cache; +use Friendica\Core\Config\Capability\IManageConfigValues; use Friendica\Database\Database; use Friendica\Test\MockedTest; use Friendica\Test\Util\VFSTrait; @@ -47,9 +47,9 @@ class ModeTest extends MockedTest private $databaseMock; /** - * @var Cache|MockInterface + * @var IManageConfigValues|MockInterface */ - private $configCacheMock; + private $configMock; protected function setUp(): void { @@ -57,8 +57,8 @@ class ModeTest extends MockedTest $this->setUpVfsDir(); - $this->databaseMock = Mockery::mock(Database::class); - $this->configCacheMock = Mockery::mock(Cache::class); + $this->databaseMock = Mockery::mock(Database::class); + $this->configMock = Mockery::mock(IManageConfigValues::class); } public function testItEmpty() @@ -76,7 +76,7 @@ class ModeTest extends MockedTest self::assertFalse($this->root->hasChild('config/local.config.php')); - $mode = (new Mode())->determine($this->root->url(), $this->databaseMock, $this->configCacheMock); + $mode = (new Mode())->determine($this->root->url(), $this->databaseMock, $this->configMock); self::assertTrue($mode->isInstall()); self::assertFalse($mode->isNormal()); @@ -88,7 +88,7 @@ class ModeTest extends MockedTest { $this->databaseMock->shouldReceive('connected')->andReturn(false)->once(); - $mode = (new Mode())->determine($this->root->url(), $this->databaseMock, $this->configCacheMock); + $mode = (new Mode())->determine($this->root->url(), $this->databaseMock, $this->configMock); self::assertFalse($mode->isNormal()); self::assertTrue($mode->isInstall()); @@ -100,10 +100,10 @@ class ModeTest extends MockedTest public function testWithMaintenanceMode() { $this->databaseMock->shouldReceive('connected')->andReturn(true)->once(); - $this->configCacheMock->shouldReceive('get')->with('system', 'maintenance') + $this->configMock->shouldReceive('get')->with('system', 'maintenance') ->andReturn(true)->once(); - $mode = (new Mode())->determine($this->root->url(), $this->databaseMock, $this->configCacheMock); + $mode = (new Mode())->determine($this->root->url(), $this->databaseMock, $this->configMock); self::assertFalse($mode->isNormal()); self::assertFalse($mode->isInstall()); @@ -114,10 +114,10 @@ class ModeTest extends MockedTest public function testNormalMode() { $this->databaseMock->shouldReceive('connected')->andReturn(true)->once(); - $this->configCacheMock->shouldReceive('get')->with('system', 'maintenance') + $this->configMock->shouldReceive('get')->with('system', 'maintenance') ->andReturn(false)->once(); - $mode = (new Mode())->determine($this->root->url(), $this->databaseMock, $this->configCacheMock); + $mode = (new Mode())->determine($this->root->url(), $this->databaseMock, $this->configMock); self::assertTrue($mode->isNormal()); self::assertFalse($mode->isInstall()); @@ -131,10 +131,10 @@ class ModeTest extends MockedTest public function testDisabledMaintenance() { $this->databaseMock->shouldReceive('connected')->andReturn(true)->once(); - $this->configCacheMock->shouldReceive('get')->with('system', 'maintenance') + $this->configMock->shouldReceive('get')->with('system', 'maintenance') ->andReturn(false)->once(); - $mode = (new Mode())->determine($this->root->url(), $this->databaseMock, $this->configCacheMock); + $mode = (new Mode())->determine($this->root->url(), $this->databaseMock, $this->configMock); self::assertTrue($mode->isNormal()); self::assertFalse($mode->isInstall()); @@ -149,7 +149,7 @@ class ModeTest extends MockedTest { $mode = new Mode(); - $modeNew = $mode->determine('', $this->databaseMock, $this->configCacheMock); + $modeNew = $mode->determine('', $this->databaseMock, $this->configMock); self::assertNotSame($modeNew, $mode); } diff --git a/tests/src/Core/Cache/DatabaseCacheTest.php b/tests/src/Core/Cache/DatabaseCacheTest.php index 2a837b71f3..e5f3359580 100644 --- a/tests/src/Core/Cache/DatabaseCacheTest.php +++ b/tests/src/Core/Cache/DatabaseCacheTest.php @@ -57,11 +57,12 @@ class DatabaseCacheTest extends CacheTest $configFactory = new Config(); $configFileManager = (new Config())->createConfigFileManager($this->root->url(), []); $configCache = $configFactory->createCache($configFileManager); + $config = new \Friendica\Core\Config\Model\Config($configFileManager, $configCache); $dbaDefinition = (new DbaDefinition($configCache->get('system', 'basepath')))->load(); $viewDefinition = (new ViewDefinition($configCache->get('system', 'basepath')))->load(); - $dba = new StaticDatabase($configCache, $profiler, $dbaDefinition, $viewDefinition); + $dba = new StaticDatabase($config, $profiler, $dbaDefinition, $viewDefinition); $this->cache = new Cache\Type\DatabaseCache('database', $dba); return $this->cache; diff --git a/tests/src/Core/KeyValueStorage/DBKeyValueStorageTest.php b/tests/src/Core/KeyValueStorage/DBKeyValueStorageTest.php index f9c88400a0..8371effefb 100644 --- a/tests/src/Core/KeyValueStorage/DBKeyValueStorageTest.php +++ b/tests/src/Core/KeyValueStorage/DBKeyValueStorageTest.php @@ -21,20 +21,14 @@ namespace Friendica\Test\src\Core\KeyValueStorage; -use Friendica\Core\Config\ValueObject\Cache; use Friendica\Core\KeyValueStorage\Capabilities\IManageKeyValuePairs; use Friendica\Core\KeyValueStorage\Type\DBKeyValueStorage; use Friendica\Database\Database; -use Friendica\Database\Definition\DbaDefinition; -use Friendica\Database\Definition\ViewDefinition; -use Friendica\Test\DatabaseTestTrait; -use Friendica\Test\Util\Database\StaticDatabase; -use Friendica\Util\BasePath; -use Friendica\Util\Profiler; +use Friendica\Test\Util\CreateDatabaseTrait; class DBKeyValueStorageTest extends KeyValueStorageTest { - use DatabaseTestTrait; + use CreateDatabaseTrait; /** @var Database */ protected $database; @@ -43,6 +37,7 @@ class DBKeyValueStorageTest extends KeyValueStorageTest { parent::setUp(); + $this->setUpVfsDir(); $this->setUpDb(); } @@ -55,13 +50,7 @@ class DBKeyValueStorageTest extends KeyValueStorageTest public function getInstance(): IManageKeyValuePairs { - $cache = new Cache(); - $cache->set('database', 'disable_pdo', true); - - $basePath = new BasePath(dirname(__FILE__, 5), $_SERVER); - - $this->database = new StaticDatabase($cache, new Profiler($cache), (new DbaDefinition($basePath->getPath()))->load(), (new ViewDefinition($basePath->getPath()))->load()); - $this->database->setTestmode(true); + $this->database = $this->getDbInstance(); return new DBKeyValueStorage($this->database); } diff --git a/tests/src/Core/Lock/DatabaseLockDriverTest.php b/tests/src/Core/Lock/DatabaseLockDriverTest.php index b18d06ae92..3e8a917ad2 100644 --- a/tests/src/Core/Lock/DatabaseLockDriverTest.php +++ b/tests/src/Core/Lock/DatabaseLockDriverTest.php @@ -21,27 +21,15 @@ namespace Friendica\Test\src\Core\Lock; -use Friendica\Core\Config\ValueObject\Cache; use Friendica\Core\Lock\Type\DatabaseLock; -use Friendica\Database\Database; -use Friendica\Database\Definition\DbaDefinition; -use Friendica\Database\Definition\ViewDefinition; -use Friendica\Test\DatabaseTestTrait; -use Friendica\Test\Util\Database\StaticDatabase; -use Friendica\Test\Util\VFSTrait; -use Friendica\Util\BasePath; -use Friendica\Util\Profiler; +use Friendica\Test\Util\CreateDatabaseTrait; class DatabaseLockDriverTest extends LockTest { - use VFSTrait; - use DatabaseTestTrait; + use CreateDatabaseTrait; protected $pid = 123; - /** @var Database */ - protected $database; - protected function setUp(): void { $this->setUpVfsDir(); @@ -53,21 +41,13 @@ class DatabaseLockDriverTest extends LockTest protected function getInstance() { - $cache = new Cache(); - $cache->set('database', 'disable_pdo', true); - - $basePath = new BasePath(dirname(__FILE__, 5), $_SERVER); - - $this->database = new StaticDatabase($cache, new Profiler($cache), (new DbaDefinition($basePath->getPath()))->load(), (new ViewDefinition($basePath->getPath()))->load()); - $this->database->setTestmode(true); - - return new DatabaseLock($this->database, $this->pid); + return new DatabaseLock($this->getDbInstance(), $this->pid); } protected function tearDown(): void { - $this->tearDownDb(); - parent::tearDown(); + + $this->tearDownDb(); } } diff --git a/tests/src/Core/Storage/DatabaseStorageTest.php b/tests/src/Core/Storage/DatabaseStorageTest.php index 7ac87245a9..093a2353ee 100644 --- a/tests/src/Core/Storage/DatabaseStorageTest.php +++ b/tests/src/Core/Storage/DatabaseStorageTest.php @@ -21,20 +21,12 @@ namespace Friendica\Test\src\Core\Storage; -use Friendica\Core\Config\Factory\Config; use Friendica\Core\Storage\Type\Database; -use Friendica\Database\Definition\DbaDefinition; -use Friendica\Database\Definition\ViewDefinition; -use Friendica\Test\DatabaseTestTrait; -use Friendica\Test\Util\Database\StaticDatabase; -use Friendica\Test\Util\VFSTrait; -use Friendica\Util\Profiler; -use Psr\Log\NullLogger; +use Friendica\Test\Util\CreateDatabaseTrait; class DatabaseStorageTest extends StorageTest { - use DatabaseTestTrait; - use VFSTrait; + use CreateDatabaseTrait; protected function setUp(): void { @@ -47,28 +39,13 @@ class DatabaseStorageTest extends StorageTest protected function getInstance() { - $profiler = \Mockery::mock(Profiler::class); - $profiler->shouldReceive('startRecording'); - $profiler->shouldReceive('stopRecording'); - $profiler->shouldReceive('saveTimestamp')->withAnyArgs()->andReturn(true); - - // load real config to avoid mocking every config-entry which is related to the Database class - $configFactory = new Config(); - $configFileManager = (new Config())->createConfigFileManager($this->root->url()); - $configCache = $configFactory->createCache($configFileManager); - - $dbaDefinition = (new DbaDefinition($configCache->get('system', 'basepath')))->load(); - $viewDefinition = (new ViewDefinition($configCache->get('system', 'basepath')))->load(); - - $dba = new StaticDatabase($configCache, $profiler, $dbaDefinition, $viewDefinition); - - return new Database($dba); + return new Database($this->getDbInstance()); } protected function tearDown(): void { - $this->tearDownDb(); - parent::tearDown(); + + $this->tearDownDb(); } } diff --git a/tests/src/Core/Storage/Repository/StorageManagerTest.php b/tests/src/Core/Storage/Repository/StorageManagerTest.php index a55819ee0b..7a976832f7 100644 --- a/tests/src/Core/Storage/Repository/StorageManagerTest.php +++ b/tests/src/Core/Storage/Repository/StorageManagerTest.php @@ -41,6 +41,7 @@ use Friendica\DI; use Friendica\Core\Config\Factory\Config; use Friendica\Core\Storage\Type; use Friendica\Test\DatabaseTest; +use Friendica\Test\Util\CreateDatabaseTrait; use Friendica\Test\Util\Database\StaticDatabase; use Friendica\Test\Util\VFSTrait; use Friendica\Util\Profiler; @@ -51,10 +52,8 @@ use Friendica\Test\Util\SampleStorageBackend; class StorageManagerTest extends DatabaseTest { - use VFSTrait; + use CreateDatabaseTrait; - /** @var Database */ - private $dba; /** @var IManageConfigValues */ private $config; /** @var LoggerInterface */ @@ -62,37 +61,33 @@ class StorageManagerTest extends DatabaseTest /** @var L10n */ private $l10n; + /** @var Database */ + protected $database; + protected function setUp(): void { parent::setUp(); $this->setUpVfsDir(); + $this->setUpDb(); + vfsStream::newDirectory(Type\FilesystemConfig::DEFAULT_BASE_FOLDER, 0777)->at($this->root); $this->logger = new NullLogger(); - $profiler = \Mockery::mock(Profiler::class); - $profiler->shouldReceive('startRecording'); - $profiler->shouldReceive('stopRecording'); - $profiler->shouldReceive('saveTimestamp')->withAnyArgs()->andReturn(true); - - // load real config to avoid mocking every config-entry which is related to the Database class $configFactory = new Config(); $configFileManager = $configFactory->createConfigFileManager($this->root->url()); $configCache = $configFactory->createCache($configFileManager); - $dbaDefinition = (new DbaDefinition($configCache->get('system', 'basepath')))->load(); - $viewDefinition = (new ViewDefinition($configCache->get('system', 'basepath')))->load(); - - $this->dba = new StaticDatabase($configCache, $profiler, $dbaDefinition, $viewDefinition); - $this->config = new \Friendica\Core\Config\Model\Config($configFileManager, $configCache); $this->config->set('storage', 'name', 'Database'); $this->config->set('storage', 'filesystem_path', $this->root->getChild(Type\FilesystemConfig::DEFAULT_BASE_FOLDER) ->url()); $this->l10n = \Mockery::mock(L10n::class); + + $this->database = $this->getDbInstance(); } protected function tearDown(): void @@ -107,7 +102,7 @@ class StorageManagerTest extends DatabaseTest */ public function testInstance() { - $storageManager = new StorageManager($this->dba, $this->config, $this->logger, $this->l10n, false); + $storageManager = new StorageManager($this->database, $this->config, $this->logger, $this->l10n, false); self::assertInstanceOf(StorageManager::class, $storageManager); } @@ -169,7 +164,7 @@ class StorageManagerTest extends DatabaseTest $this->config->set('storage', 'name', $name); } - $storageManager = new StorageManager($this->dba, $this->config, $this->logger, $this->l10n, false); + $storageManager = new StorageManager($this->database, $this->config, $this->logger, $this->l10n, false); if ($interface === ICanWriteToStorage::class) { $storage = $storageManager->getWritableStorageByName($name); @@ -189,7 +184,7 @@ class StorageManagerTest extends DatabaseTest */ public function testIsValidBackend($name, $valid, $interface, $assert, $assertName) { - $storageManager = new StorageManager($this->dba, $this->config, $this->logger, $this->l10n, false); + $storageManager = new StorageManager($this->database, $this->config, $this->logger, $this->l10n, false); // true in every of the backends self::assertEquals(!empty($assertName), $storageManager->isValidBackend($name)); @@ -203,7 +198,7 @@ class StorageManagerTest extends DatabaseTest */ public function testListBackends() { - $storageManager = new StorageManager($this->dba, $this->config, $this->logger, $this->l10n, false); + $storageManager = new StorageManager($this->database, $this->config, $this->logger, $this->l10n, false); self::assertEquals(StorageManager::DEFAULT_BACKENDS, $storageManager->listBackends()); } @@ -219,7 +214,7 @@ class StorageManagerTest extends DatabaseTest static::markTestSkipped('only works for ICanWriteToStorage'); } - $storageManager = new StorageManager($this->dba, $this->config, $this->logger, $this->l10n, false); + $storageManager = new StorageManager($this->database, $this->config, $this->logger, $this->l10n, false); $selBackend = $storageManager->getWritableStorageByName($name); $storageManager->setBackend($selBackend); @@ -239,7 +234,7 @@ class StorageManagerTest extends DatabaseTest $this->expectException(InvalidClassStorageException::class); } - $storageManager = new StorageManager($this->dba, $this->config, $this->logger, $this->l10n, false); + $storageManager = new StorageManager($this->database, $this->config, $this->logger, $this->l10n, false); self::assertInstanceOf($assert, $storageManager->getBackend()); } @@ -260,7 +255,7 @@ class StorageManagerTest extends DatabaseTest ->addRule(IHandleSessions::class, ['instanceOf' => Memory::class, 'shared' => true, 'call' => null]); DI::init($dice); - $storageManager = new StorageManager($this->dba, $this->config, $this->logger, $this->l10n, false); + $storageManager = new StorageManager($this->database, $this->config, $this->logger, $this->l10n, false); self::assertTrue($storageManager->register(SampleStorageBackend::class)); @@ -288,7 +283,7 @@ class StorageManagerTest extends DatabaseTest ->addRule(IHandleSessions::class, ['instanceOf' => Memory::class, 'shared' => true, 'call' => null]); DI::init($dice); - $storageManager = new StorageManager($this->dba, $this->config, $this->logger, $this->l10n, false); + $storageManager = new StorageManager($this->database, $this->config, $this->logger, $this->l10n, false); self::assertTrue($storageManager->register(SampleStorageBackend::class)); @@ -325,15 +320,15 @@ class StorageManagerTest extends DatabaseTest self::markTestSkipped("No user backend"); } - $this->loadFixture(__DIR__ . '/../../../../datasets/storage/database.fixture.php', $this->dba); + $this->loadFixture(__DIR__ . '/../../../../datasets/storage/database.fixture.php', $this->database); - $storageManager = new StorageManager($this->dba, $this->config, $this->logger, $this->l10n, false); + $storageManager = new StorageManager($this->database, $this->config, $this->logger, $this->l10n, false); $storage = $storageManager->getWritableStorageByName($name); $storageManager->move($storage); - $photos = $this->dba->select('photo', ['backend-ref', 'backend-class', 'id', 'data']); + $photos = $this->database->select('photo', ['backend-ref', 'backend-class', 'id', 'data']); - while ($photo = $this->dba->fetch($photos)) { + while ($photo = $this->database->fetch($photos)) { self::assertEmpty($photo['data']); $storage = $storageManager->getByName($photo['backend-class']); @@ -351,7 +346,7 @@ class StorageManagerTest extends DatabaseTest $this->expectException(InvalidClassStorageException::class); $this->expectExceptionMessage('Backend SystemResource is not valid'); - $storageManager = new StorageManager($this->dba, $this->config, $this->logger, $this->l10n, false); + $storageManager = new StorageManager($this->database, $this->config, $this->logger, $this->l10n, false); $storage = $storageManager->getWritableStorageByName(SystemResource::getName()); $storageManager->move($storage); } diff --git a/tests/src/Util/BaseURLTest.php b/tests/src/Util/BaseURLTest.php index b9c23a1d8b..feda9a7c56 100644 --- a/tests/src/Util/BaseURLTest.php +++ b/tests/src/Util/BaseURLTest.php @@ -23,9 +23,7 @@ namespace Friendica\Test\src\Util; use Friendica\App\BaseURL; use Friendica\Core\Config\Capability\IManageConfigValues; -use Friendica\Core\Config\Capability\ISetConfigValuesTransactionally; use Friendica\Core\Config\Model\Config; -use Friendica\Core\Config\Model\ConfigTransaction; use Friendica\Core\Config\Util\ConfigFileManager; use Friendica\Core\Config\ValueObject\Cache; use Friendica\Test\MockedTest; diff --git a/tests/src/Util/ProfilerTest.php b/tests/src/Util/ProfilerTest.php index 25d044354c..9ca2e664c0 100644 --- a/tests/src/Util/ProfilerTest.php +++ b/tests/src/Util/ProfilerTest.php @@ -21,7 +21,6 @@ namespace Friendica\Test\src\Util; -use Friendica\Core\Config\ValueObject\Cache; use Friendica\Core\Config\Capability\IManageConfigValues; use Friendica\Test\MockedTest; use Friendica\Util\Profiler; @@ -47,12 +46,12 @@ class ProfilerTest extends MockedTest */ public function testSetUp() { - $configCache = \Mockery::mock(Cache::class); - $configCache->shouldReceive('get') + $config = \Mockery::mock(IManageConfigValues::class); + $config->shouldReceive('get') ->withAnyArgs() ->andReturn(true) ->twice(); - $profiler = new Profiler($configCache); + $profiler = new Profiler($config); self::assertInstanceOf(Profiler::class, $profiler); } @@ -124,13 +123,13 @@ class ProfilerTest extends MockedTest */ public function testSaveTimestamp($timestamp, $name, array $functions) { - $configCache = \Mockery::mock(Cache::class); - $configCache->shouldReceive('get') + $config = \Mockery::mock(IManageConfigValues::class); + $config->shouldReceive('get') ->withAnyArgs() ->andReturn(true) ->twice(); - $profiler = new Profiler($configCache); + $profiler = new Profiler($config); foreach ($functions as $function) { $profiler->saveTimestamp($timestamp, $name, $function); @@ -145,13 +144,13 @@ class ProfilerTest extends MockedTest */ public function testReset($timestamp, $name) { - $configCache = \Mockery::mock(Cache::class); - $configCache->shouldReceive('get') + $config = \Mockery::mock(IManageConfigValues::class); + $config->shouldReceive('get') ->withAnyArgs() ->andReturn(true) ->twice(); - $profiler = new Profiler($configCache); + $profiler = new Profiler($config); $profiler->saveTimestamp($timestamp, $name); $profiler->reset(); @@ -208,13 +207,13 @@ class ProfilerTest extends MockedTest ->shouldReceive('info') ->once(); - $configCache = \Mockery::mock(Cache::class); - $configCache->shouldReceive('get') + $config = \Mockery::mock(IManageConfigValues::class); + $config->shouldReceive('get') ->withAnyArgs() ->andReturn(true) ->twice(); - $profiler = new Profiler($configCache); + $profiler = new Profiler($config); foreach ($data as $perf => $items) { foreach ($items['functions'] as $function) { @@ -233,60 +232,4 @@ class ProfilerTest extends MockedTest } } } - - /** - * Test different enable and disable states of the profiler - */ - public function testEnableDisable() - { - $configCache = \Mockery::mock(Cache::class); - $configCache->shouldReceive('get') - ->with('system', 'profiler') - ->andReturn(true) - ->once(); - $configCache->shouldReceive('get') - ->with('rendertime', 'callstack') - ->andReturn(false) - ->once(); - - $profiler = new Profiler($configCache); - - self::assertFalse($profiler->isRendertime()); - self::assertEmpty($profiler->getRendertimeString()); - - $profiler->saveTimestamp(time(), 'network', 'test1'); - - $config = \Mockery::mock(IManageConfigValues::class); - $config->shouldReceive('get') - ->with('system', 'profiler') - ->andReturn(false) - ->once(); - $config->shouldReceive('get') - ->with('rendertime', 'callstack') - ->andReturn(false) - ->once(); - - $profiler->update($config); - - self::assertFalse($profiler->isRendertime()); - self::assertEmpty($profiler->getRendertimeString()); - - $config->shouldReceive('get') - ->with('system', 'profiler') - ->andReturn(true) - ->once(); - $config->shouldReceive('get') - ->with('rendertime', 'callstack') - ->andReturn(true) - ->once(); - - $profiler->update($config); - - $profiler->saveTimestamp(time(), 'database', 'test2'); - - self::assertTrue($profiler->isRendertime()); - $output = $profiler->getRendertimeString(); - self::assertMatchesRegularExpression('/test1: \d+/', $output); - self::assertMatchesRegularExpression('/test2: \d+/', $output); - } } From da58b894a4239e95342524eeacb85af7bf6c5a9d Mon Sep 17 00:00:00 2001 From: Daniel Siepmann Date: Tue, 17 Jan 2023 07:17:01 +0100 Subject: [PATCH 6/6] Properly handle feed item creation date with surrounding whitespace Some feeds might have whitespace around the creation date. This can't be parsed by DateTimeFormat methods. Therefore the incoming creation date is trimmed to not contain any surrounding whitespace for proper handling. Relates: #12686 --- src/Protocol/Feed.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Protocol/Feed.php b/src/Protocol/Feed.php index ccbe35e712..be58b9aa8f 100644 --- a/src/Protocol/Feed.php +++ b/src/Protocol/Feed.php @@ -376,11 +376,11 @@ class Feed } if ($published != '') { - $item['created'] = $published; + $item['created'] = trim($published); } if ($updated != '') { - $item['edited'] = $updated; + $item['edited'] = trim($updated); } if (!$dryRun) {