diff --git a/bin/daemon.php b/bin/daemon.php index 385f725e3..f9ed693f3 100755 --- a/bin/daemon.php +++ b/bin/daemon.php @@ -71,7 +71,7 @@ if (DI::mode()->isInstall()) { DI::mode()->setExecutor(Mode::DAEMON); -DI::config()->load(); +DI::config()->reload(); if (empty(DI::config()->get('system', 'pidfile'))) { die(<<config->getCache()->get('system', 'basepath'); + return $this->config->get('system', 'basepath'); } /** diff --git a/src/App/Mode.php b/src/App/Mode.php index ca78ebd5b..514df91c6 100644 --- a/src/App/Mode.php +++ b/src/App/Mode.php @@ -149,16 +149,7 @@ class Mode $mode |= Mode::DBAVAILABLE; - if ($database->fetchFirst("SHOW TABLES LIKE 'config'") === false) { - return new Mode($mode); - } - - $mode |= Mode::DBCONFIGAVAILABLE; - - if (!empty($configCache->get('system', 'maintenance')) || - // Don't use Config or Configuration here because we're possibly BEFORE initializing the Configuration, - // so this could lead to a dependency circle - !empty($database->selectFirst('config', ['v'], ['cat' => 'system', 'k' => 'maintenance'])['v'])) { + if (!empty($configCache->get('system', 'maintenance'))) { return new Mode($mode); } @@ -232,14 +223,14 @@ class Mode } /** - * Install mode is when the local config file is missing or the DB schema hasn't been installed yet. + * Install mode is when the local config file is missing or the database isn't available. * * @return bool Whether installation mode is active (local/database configuration files present or not) */ public function isInstall(): bool { return !$this->has(Mode::LOCALCONFIGPRESENT) || - !$this->has(MODE::DBCONFIGAVAILABLE); + !$this->has(MODE::DBAVAILABLE); } /** @@ -251,7 +242,6 @@ class Mode { return $this->has(Mode::LOCALCONFIGPRESENT) && $this->has(Mode::DBAVAILABLE) && - $this->has(Mode::DBCONFIGAVAILABLE) && $this->has(Mode::MAINTENANCEDISABLED); } diff --git a/src/Console/Cache.php b/src/Console/Cache.php index e4d113533..c55371699 100644 --- a/src/Console/Cache.php +++ b/src/Console/Cache.php @@ -99,7 +99,7 @@ HELP; $this->out('Options: ' . var_export($this->options, true)); } - if (!$this->appMode->has(App\Mode::DBCONFIGAVAILABLE)) { + if (!$this->appMode->has(App\Mode::DBAVAILABLE)) { $this->out('Database isn\'t ready or populated yet, database cache won\'t be available'); } diff --git a/src/Console/Config.php b/src/Console/Config.php index b57cdbeec..efb795360 100644 --- a/src/Console/Config.php +++ b/src/Console/Config.php @@ -115,10 +115,6 @@ HELP; throw new CommandArgsException('Too many arguments'); } - if (!$this->appMode->has(App\Mode::DBCONFIGAVAILABLE)) { - $this->out('Database isn\'t ready or populated yet, showing file config only'); - } - if (count($this->args) == 3) { $cat = $this->getArgument(0); $key = $this->getArgument(1); @@ -157,7 +153,7 @@ HELP; if (count($this->args) == 1) { $cat = $this->getArgument(0); - $this->config->load($cat); + $this->config->reload(); $configCache = $this->config->getCache(); if ($configCache->get($cat) !== null) { @@ -178,11 +174,7 @@ HELP; } if (count($this->args) == 0) { - $this->config->load(); - - if ($this->config->get('system', 'config_adapter') == 'jit' && $this->appMode->has(App\Mode::DBCONFIGAVAILABLE)) { - $this->out('Warning: The JIT (Just In Time) Config adapter doesn\'t support loading the entire configuration, showing file config only'); - } + $this->config->reload(); $config = $this->config->getCache()->getAll(); foreach ($config as $cat => $section) { diff --git a/src/Console/Lock.php b/src/Console/Lock.php index 4e324691c..0acede5df 100644 --- a/src/Console/Lock.php +++ b/src/Console/Lock.php @@ -93,7 +93,7 @@ HELP; $this->out('Options: ' . var_export($this->options, true)); } - if (!$this->appMode->has(App\Mode::DBCONFIGAVAILABLE)) { + if (!$this->appMode->has(App\Mode::DBAVAILABLE)) { $this->out('Database isn\'t ready or populated yet, database cache won\'t be available'); } diff --git a/src/Console/Maintenance.php b/src/Console/Maintenance.php index 97ce9c27f..076b89db8 100644 --- a/src/Console/Maintenance.php +++ b/src/Console/Maintenance.php @@ -100,16 +100,20 @@ HELP; $enabled = intval($this->getArgument(0)); - $this->config->set('system', 'maintenance', $enabled); + $transactionConfig = $this->config->beginTransaction(); + + $transactionConfig->set('system', 'maintenance', $enabled); $reason = $this->getArgument(1); if ($enabled && $this->getArgument(1)) { - $this->config->set('system', 'maintenance_reason', $this->getArgument(1)); + $transactionConfig->set('system', 'maintenance_reason', $this->getArgument(1)); } else { - $this->config->set('system', 'maintenance_reason', ''); + $transactionConfig->delete('system', 'maintenance_reason'); } + $transactionConfig->commit(); + if ($enabled) { $mode_str = "maintenance mode"; } else { diff --git a/src/Console/Relocate.php b/src/Console/Relocate.php index 3d13e10a0..c63434cbb 100644 --- a/src/Console/Relocate.php +++ b/src/Console/Relocate.php @@ -101,9 +101,10 @@ HELP; $old_host = str_replace('http://', '@', Strings::normaliseLink($old_url)); $this->out('Entering maintenance mode'); - $this->config->set('system', 'maintenance', true); - $this->config->set('system', 'maintenance_reason', 'Relocating node to ' . $new_url); - + $this->config->beginTransaction() + ->set('system', 'maintenance', true) + ->set('system', 'maintenance_reason', 'Relocating node to ' . $new_url) + ->commit(); try { if (!$this->database->transaction()) { throw new \Exception('Unable to start a transaction, please retry later.'); @@ -189,8 +190,10 @@ HELP; return 1; } finally { $this->out('Leaving maintenance mode'); - $this->config->set('system', 'maintenance', false); - $this->config->set('system', 'maintenance_reason', ''); + $this->config->beginTransaction() + ->set('system', 'maintenance', false) + ->delete('system', 'maintenance_reason') + ->commit(); } // send relocate diff --git a/src/Core/Config/Capability/IManageConfigValues.php b/src/Core/Config/Capability/IManageConfigValues.php index ecfb2a7aa..715887ddf 100644 --- a/src/Core/Config/Capability/IManageConfigValues.php +++ b/src/Core/Config/Capability/IManageConfigValues.php @@ -22,6 +22,7 @@ namespace Friendica\Core\Config\Capability; use Friendica\Core\Config\Exception\ConfigPersistenceException; +use Friendica\Core\Config\Util\ConfigFileManager; use Friendica\Core\Config\ValueObject\Cache; /** @@ -30,36 +31,46 @@ use Friendica\Core\Config\ValueObject\Cache; interface IManageConfigValues { /** - * Loads all configuration values of family into a cached storage. + * Reloads all configuration values (from filesystem and environment variables) * * All configuration values of the system are stored in the cache. * - * @param string $cat The category of the configuration value - * * @return void * * @throws ConfigPersistenceException In case the persistence layer throws errors */ - public function load(string $cat = 'config'); + public function reload(); /** * Get a particular user's config variable given the category name * ($cat) and a $key. * * Get a particular config value from the given category ($cat) - * and the $key from a cached storage either from the database or from the cache. * * @param string $cat The category of the configuration value * @param string $key The configuration key to query * @param mixed $default_value Deprecated, use `Config->get($cat, $key, null, $refresh) ?? $default_value` instead - * @param boolean $refresh optional, If true the config is loaded from the db and not from the cache (default: false) * * @return mixed Stored value or null if it does not exist * * @throws ConfigPersistenceException In case the persistence layer throws errors * */ - public function get(string $cat, string $key, $default_value = null, bool $refresh = false); + public function get(string $cat, string $key, $default_value = null); + + /** + * Load all configuration values from a given cache and saves it back in the configuration node store + * @see ConfigFileManager::CONFIG_DATA_FILE + * + * All configuration values of the system are stored in the cache. + * + * @param Cache $cache a new cache + * + * @return void + * + * @throws ConfigPersistenceException In case the persistence layer throws errors + */ + public function load(Cache $cache); /** * Sets a configuration value for system config @@ -78,6 +89,15 @@ interface IManageConfigValues */ public function set(string $cat, string $key, $value): bool; + /** + * Creates a transactional config value store, which is used to set a bunch of values at once + * + * It relies on the current instance, so after save(), the values of this config class will get altered at once too. + * + * @return ISetConfigValuesTransactionally + */ + public function beginTransaction(): ISetConfigValuesTransactionally; + /** * Deletes the given key from the system configuration. * diff --git a/src/Core/Config/Capability/ISetConfigValuesTransactionally.php b/src/Core/Config/Capability/ISetConfigValuesTransactionally.php new file mode 100644 index 000000000..501e24f73 --- /dev/null +++ b/src/Core/Config/Capability/ISetConfigValuesTransactionally.php @@ -0,0 +1,68 @@ +. + * + */ + +namespace Friendica\Core\Config\Capability; + +use Friendica\Core\Config\Exception\ConfigPersistenceException; + +/** + * Interface for transactional saving of config values + * It buffers every set/delete until "save()" is called + */ +interface ISetConfigValuesTransactionally +{ + /** + * Sets a configuration value for system config + * + * Stores a config value ($value) in the category ($cat) under the key ($key) + * + * Note: Please do not store booleans - convert to 0/1 integer values! + * + * @param string $cat The category of the configuration value + * @param string $key The configuration key to set + * @param mixed $value The value to store + * + * @return static the current instance + * + * @throws ConfigPersistenceException In case the persistence layer throws errors + */ + public function set(string $cat, string $key, $value): self; + + /** + * Deletes the given key from the system configuration. + * + * @param string $cat The category of the configuration value + * @param string $key The configuration key to delete + * + * @return static the current instance + * + * @throws ConfigPersistenceException In case the persistence layer throws errors + * + */ + public function delete(string $cat, string $key): self; + + /** + * Commits the changes of the current transaction + * + * @throws ConfigPersistenceException In case the persistence layer throws errors + */ + public function commit(): void; +} diff --git a/src/Core/Config/Factory/Config.php b/src/Core/Config/Factory/Config.php index 94293dd17..e1094fd70 100644 --- a/src/Core/Config/Factory/Config.php +++ b/src/Core/Config/Factory/Config.php @@ -21,12 +21,12 @@ namespace Friendica\Core\Config\Factory; -use Friendica\Core\Config\Capability; -use Friendica\Core\Config\Repository; -use Friendica\Core\Config\Type; use Friendica\Core\Config\Util; use Friendica\Core\Config\ValueObject\Cache; +/** + * The config factory for creating either the cache or the whole model + */ class Config { /** @@ -54,9 +54,9 @@ class Config * @param string $basePath The basepath of FRIENDICA * @param array $server The $_SERVER array * - * @return Util\ConfigFileLoader + * @return Util\ConfigFileManager */ - public function createConfigFileLoader(string $basePath, array $server = []): Util\ConfigFileLoader + public function createConfigFileLoader(string $basePath, array $server = []): Util\ConfigFileManager { if (!empty($server[self::CONFIG_DIR_ENV]) && is_dir($server[self::CONFIG_DIR_ENV])) { $configDir = $server[self::CONFIG_DIR_ENV]; @@ -65,37 +65,20 @@ class Config } $staticDir = $basePath . DIRECTORY_SEPARATOR . self::STATIC_DIR; - return new Util\ConfigFileLoader($basePath, $configDir, $staticDir); + return new Util\ConfigFileManager($basePath, $configDir, $staticDir, new Util\ConfigFileTransformer()); } /** - * @param Util\ConfigFileLoader $loader The Config Cache loader (INI/config/.htconfig) - * @param array $server + * @param Util\ConfigFileManager $configFileManager The Config Cache manager (INI/config/.htconfig) + * @param array $server * * @return Cache */ - public function createCache(Util\ConfigFileLoader $loader, array $server = []): Cache + public function createCache(Util\ConfigFileManager $configFileManager, array $server = []): Cache { $configCache = new Cache(); - $loader->setupCache($configCache, $server); + $configFileManager->setupCache($configCache, $server); return $configCache; } - - /** - * @param Cache $configCache The config cache of this adapter - * @param Repository\Config $configRepo The configuration repository - * - * @return Capability\IManageConfigValues - */ - public function create(Cache $configCache, Repository\Config $configRepo) - { - if ($configCache->get('system', 'config_adapter') === 'preload') { - $configuration = new Type\PreloadConfig($configCache, $configRepo); - } else { - $configuration = new Type\JitConfig($configCache, $configRepo); - } - - return $configuration; - } } diff --git a/src/Core/Config/Model/Config.php b/src/Core/Config/Model/Config.php new file mode 100644 index 000000000..29ea6b12d --- /dev/null +++ b/src/Core/Config/Model/Config.php @@ -0,0 +1,131 @@ +. + * + */ + +namespace Friendica\Core\Config\Model; + +use Friendica\Core\Config\Capability\IManageConfigValues; +use Friendica\Core\Config\Capability\ISetConfigValuesTransactionally; +use Friendica\Core\Config\Exception\ConfigFileException; +use Friendica\Core\Config\Exception\ConfigPersistenceException; +use Friendica\Core\Config\Util\ConfigFileManager; +use Friendica\Core\Config\ValueObject\Cache; + +/** + * Configuration model, which manages the whole system configuration + */ +class Config implements IManageConfigValues +{ + /** @var Cache */ + protected $configCache; + + /** @var ConfigFileManager */ + protected $configFileManager; + + /** @var array */ + protected $server; + + /** + * @param ConfigFileManager $configFileManager The configuration file manager to save back configs + * @param Cache $configCache The configuration cache (based on the config-files) + * @param array $server The $_SERVER variable + */ + public function __construct(ConfigFileManager $configFileManager, Cache $configCache, array $server = []) + { + $this->configFileManager = $configFileManager; + $this->configCache = $configCache; + $this->server = $server; + } + + /** + * {@inheritDoc} + */ + public function getCache(): Cache + { + return $this->configCache; + } + + /** {@inheritDoc} */ + public function beginTransaction(): ISetConfigValuesTransactionally + { + return new ConfigTransaction($this); + } + + /** + * Saves the current Configuration back into the data config. + * @see ConfigFileManager::CONFIG_DATA_FILE + */ + protected function save() + { + try { + $this->configFileManager->saveData($this->configCache); + } catch (ConfigFileException $e) { + throw new ConfigPersistenceException('Cannot save config', $e); + } + } + + /** {@inheritDoc} */ + public function reload() + { + $configCache = new Cache(); + + try { + $this->configFileManager->setupCache($configCache, $this->server); + } catch (ConfigFileException $e) { + throw new ConfigPersistenceException('Cannot reload config', $e); + } + $this->configCache = $configCache; + } + + /** {@inheritDoc} */ + public function load(Cache $cache) + { + $this->configCache = $cache; + $this->save(); + } + + /** {@inheritDoc} */ + public function get(string $cat, string $key, $default_value = null) + { + return $this->configCache->get($cat, $key) ?? $default_value; + } + + /** {@inheritDoc} */ + public function set(string $cat, string $key, $value): bool + { + if ($this->configCache->set($cat, $key, $value, Cache::SOURCE_DATA)) { + $this->save(); + return true; + } else { + return false; + } + } + + /** {@inheritDoc} */ + public function delete(string $cat, string $key): bool + { + if ($this->configCache->delete($cat, $key)) { + $this->save(); + return true; + } else { + return false; + } + } +} diff --git a/src/Core/Config/Model/ConfigTransaction.php b/src/Core/Config/Model/ConfigTransaction.php new file mode 100644 index 000000000..296a469c0 --- /dev/null +++ b/src/Core/Config/Model/ConfigTransaction.php @@ -0,0 +1,102 @@ +. + * + */ + +namespace Friendica\Core\Config\Model; + +use Friendica\Core\Config\Capability\IManageConfigValues; +use Friendica\Core\Config\Capability\ISetConfigValuesTransactionally; +use Friendica\Core\Config\Exception\ConfigPersistenceException; +use Friendica\Core\Config\ValueObject\Cache; + +/** + * Transaction class for configurations, which sets values into a temporary buffer until "save()" is called + */ +class ConfigTransaction implements ISetConfigValuesTransactionally +{ + /** @var IManageConfigValues */ + protected $config; + /** @var Cache */ + protected $cache; + /** @var Cache */ + protected $delCache; + + public function __construct(IManageConfigValues $config) + { + $this->config = $config; + $this->cache = new Cache(); + $this->delCache = new Cache(); + } + + /** + * Get a particular user's config variable given the category name + * ($cat) and a $key from the current transaction. + * + * Isn't part of the interface because of it's rare use case + * + * @param string $cat The category of the configuration value + * @param string $key The configuration key to query + * + * @return mixed Stored value or null if it does not exist + * + * @throws ConfigPersistenceException In case the persistence layer throws errors + * + */ + public function get(string $cat, string $key) + { + return !$this->delCache->get($cat, $key) ? + ($this->cache->get($cat, $key) ?? $this->config->get($cat, $key)) : + null; + } + + /** {@inheritDoc} */ + public function set(string $cat, string $key, $value): ISetConfigValuesTransactionally + { + $this->cache->set($cat, $key, $value, Cache::SOURCE_DATA); + + return $this; + } + + + /** {@inheritDoc} */ + public function delete(string $cat, string $key): ISetConfigValuesTransactionally + { + $this->cache->delete($cat, $key); + $this->delCache->set($cat, $key, 'deleted'); + + return $this; + } + + /** {@inheritDoc} */ + public function commit(): void + { + try { + $newCache = $this->config->getCache()->merge($this->cache); + $newCache = $newCache->diff($this->delCache); + $this->config->load($newCache); + + // flush current cache + $this->cache = new Cache(); + $this->delCache = new Cache(); + } catch (\Exception $e) { + throw new ConfigPersistenceException('Cannot save config', $e); + } + } +} diff --git a/src/Core/Config/Repository/Config.php b/src/Core/Config/Repository/Config.php deleted file mode 100644 index 3bec99f84..000000000 --- a/src/Core/Config/Repository/Config.php +++ /dev/null @@ -1,191 +0,0 @@ -. - * - */ - -namespace Friendica\Core\Config\Repository; - -use Friendica\App\Mode; -use Friendica\Core\Config\Exception\ConfigPersistenceException; -use Friendica\Core\Config\Util\ValueConversion; -use Friendica\Database\Database; - -/** - * The Config Repository, which is using the general DB-model backend for configs - */ -class Config -{ - /** @var Database */ - protected $db; - /** @var Mode */ - protected $mode; - - public function __construct(Database $db, Mode $mode) - { - $this->db = $db; - $this->mode = $mode; - } - - protected static $table_name = 'config'; - - /** - * Checks if the model is currently connected - * - * @return bool - */ - public function isConnected(): bool - { - return $this->db->isConnected() && !$this->mode->isInstall(); - } - - /** - * Loads all configuration values and returns the loaded category as an array. - * - * @param string|null $cat The category of the configuration values to load - * - * @return array The config array - * - * @throws ConfigPersistenceException In case the persistence layer throws errors - */ - public function load(?string $cat = null): array - { - $return = []; - - try { - if (empty($cat)) { - $configs = $this->db->select(static::$table_name, ['cat', 'v', 'k']); - } else { - $configs = $this->db->select(static::$table_name, ['cat', 'v', 'k'], ['cat' => $cat]); - } - - while ($config = $this->db->fetch($configs)) { - $key = $config['k']; - $value = ValueConversion::toConfigValue($config['v']); - - // just save it in case it is set - if (isset($value)) { - $return[$config['cat']][$key] = $value; - } - } - } catch (\Exception $exception) { - throw new ConfigPersistenceException(sprintf('Cannot load config category %s', $cat), $exception); - } finally { - $this->db->close($configs); - } - - return $return; - } - - /** - * Get a particular, system-wide config variable out of the DB with the - * given category name ($cat) and a key ($key). - * - * Note: Boolean variables are defined as 0/1 in the database - * - * @param string $cat The category of the configuration value - * @param string $key The configuration key to query - * - * @return array|string|null Stored value or null if it does not exist - * - * @throws ConfigPersistenceException In case the persistence layer throws errors - */ - public function get(string $cat, string $key) - { - if (!$this->isConnected()) { - return null; - } - - try { - $config = $this->db->selectFirst(static::$table_name, ['v'], ['cat' => $cat, 'k' => $key]); - if ($this->db->isResult($config)) { - $value = ValueConversion::toConfigValue($config['v']); - - // just return it in case it is set - if (isset($value)) { - return $value; - } - } - } catch (\Exception $exception) { - throw new ConfigPersistenceException(sprintf('Cannot get config with category %s and key %s', $cat, $key), $exception); - } - - return null; - } - - /** - * Stores a config value ($value) in the category ($cat) under the key ($key). - * - * Note: Please do not store booleans - convert to 0/1 integer values! - * - * @param string $cat The category of the configuration value - * @param string $key The configuration key to set - * @param mixed $value The value to store - * - * @return bool Operation success - * - * @throws ConfigPersistenceException In case the persistence layer throws errors - */ - public function set(string $cat, string $key, $value): bool - { - if (!$this->isConnected()) { - return false; - } - - // We store our setting values in a string variable. - // So we have to do the conversion here so that the compare below works. - // The exception are array values. - $compare_value = (!is_array($value) ? (string)$value : $value); - $stored_value = $this->get($cat, $key); - - if (isset($stored_value) && ($stored_value === $compare_value)) { - return true; - } - - $dbValue = ValueConversion::toDbValue($value); - - try { - return $this->db->update(static::$table_name, ['v' => $dbValue], ['cat' => $cat, 'k' => $key], true); - } catch (\Exception $exception) { - throw new ConfigPersistenceException(sprintf('Cannot set config with category %s and key %s', $cat, $key), $exception); - } - } - - /** - * Removes the configured value from the database. - * - * @param string $cat The category of the configuration value - * @param string $key The configuration key to delete - * - * @return bool Operation success - * - * @throws ConfigPersistenceException In case the persistence layer throws errors - */ - public function delete(string $cat, string $key): bool - { - if (!$this->isConnected()) { - return false; - } - - try { - return $this->db->delete(static::$table_name, ['cat' => $cat, 'k' => $key]); - } catch (\Exception $exception) { - throw new ConfigPersistenceException(sprintf('Cannot delete config with category %s and key %s', $cat, $key), $exception); - } - } -} diff --git a/src/Core/Config/Type/AbstractConfig.php b/src/Core/Config/Type/AbstractConfig.php deleted file mode 100644 index 3ab4f2c5e..000000000 --- a/src/Core/Config/Type/AbstractConfig.php +++ /dev/null @@ -1,63 +0,0 @@ -. - * - */ - -namespace Friendica\Core\Config\Type; - -use Friendica\Core\Config\Repository\Config; -use Friendica\Core\Config\ValueObject\Cache; -use Friendica\Core\Config\Capability\IManageConfigValues; - -/** - * This class is responsible for all system-wide configuration values in Friendica - * There are two types of storage - * - The Config-Files (loaded into the FileCache @see Cache) - * - The Config-Repository (per Config-Repository @see Config ) - */ -abstract class AbstractConfig implements IManageConfigValues -{ - /** - * @var Cache - */ - protected $configCache; - - /** - * @var Config - */ - protected $configRepo; - - /** - * @param Cache $configCache The configuration cache (based on the config-files) - * @param Config $configRepo The configuration repository - */ - public function __construct(Cache $configCache, Config $configRepo) - { - $this->configCache = $configCache; - $this->configRepo = $configRepo; - } - - /** - * {@inheritDoc} - */ - public function getCache(): Cache - { - return $this->configCache; - } -} diff --git a/src/Core/Config/Type/JitConfig.php b/src/Core/Config/Type/JitConfig.php deleted file mode 100644 index 68b437b24..000000000 --- a/src/Core/Config/Type/JitConfig.php +++ /dev/null @@ -1,139 +0,0 @@ -. - * - */ - -namespace Friendica\Core\Config\Type; - -use Friendica\Core\Config\ValueObject\Cache; -use Friendica\Core\Config\Repository\Config; - -/** - * This class implements the Just-In-Time configuration, which will cache - * config values in a cache, once they are retrieved. - * - * Default Configuration type. - * Provides the best performance for pages loading few configuration variables. - */ -class JitConfig extends AbstractConfig -{ - /** - * @var array Array of already loaded db values (even if there was no value) - */ - private $db_loaded; - - /** - * @param Cache $configCache The configuration cache (based on the config-files) - * @param Config $configRepo The configuration model - */ - public function __construct(Cache $configCache, Config $configRepo) - { - parent::__construct($configCache, $configRepo); - $this->db_loaded = []; - - $this->load(); - } - - /** - * {@inheritDoc} - */ - public function load(string $cat = 'config') - { - // If not connected, do nothing - if (!$this->configRepo->isConnected()) { - return; - } - - $config = $this->configRepo->load($cat); - - if (!empty($config[$cat])) { - foreach ($config[$cat] as $key => $value) { - $this->db_loaded[$cat][$key] = true; - } - } - - // load the whole category out of the DB into the cache - $this->configCache->load($config, Cache::SOURCE_DB); - } - - /** - * {@inheritDoc} - */ - public function get(string $cat, string $key, $default_value = null, bool $refresh = false) - { - // if the value isn't loaded or refresh is needed, load it to the cache - if ($this->configRepo->isConnected() && - (empty($this->db_loaded[$cat][$key]) || - $refresh)) { - $dbValue = $this->configRepo->get($cat, $key); - - if (isset($dbValue)) { - $this->configCache->set($cat, $key, $dbValue, Cache::SOURCE_DB); - unset($dbValue); - } - - $this->db_loaded[$cat][$key] = true; - } - - // use the config cache for return - $result = $this->configCache->get($cat, $key); - - return (isset($result)) ? $result : $default_value; - } - - /** - * {@inheritDoc} - */ - public function set(string $cat, string $key, $value): bool - { - // set the cache first - $cached = $this->configCache->set($cat, $key, $value, Cache::SOURCE_DB); - - // If there is no connected adapter, we're finished - if (!$this->configRepo->isConnected()) { - return $cached; - } - - $stored = $this->configRepo->set($cat, $key, $value); - - $this->db_loaded[$cat][$key] = $stored; - - return $cached && $stored; - } - - /** - * {@inheritDoc} - */ - public function delete(string $cat, string $key): bool - { - $cacheRemoved = $this->configCache->delete($cat, $key); - - if (isset($this->db_loaded[$cat][$key])) { - unset($this->db_loaded[$cat][$key]); - } - - if (!$this->configRepo->isConnected()) { - return $cacheRemoved; - } - - $storeRemoved = $this->configRepo->delete($cat, $key); - - return $cacheRemoved || $storeRemoved; - } -} diff --git a/src/Core/Config/Type/PreloadConfig.php b/src/Core/Config/Type/PreloadConfig.php deleted file mode 100644 index 57a0d439d..000000000 --- a/src/Core/Config/Type/PreloadConfig.php +++ /dev/null @@ -1,135 +0,0 @@ -. - * - */ - -namespace Friendica\Core\Config\Type; - -use Friendica\Core\Config\ValueObject\Cache; -use Friendica\Core\Config\Repository\Config; - -/** - * This class implements the preload configuration, which will cache - * all config values per call in a cache. - * - * Minimizes the number of database queries to retrieve configuration values at the cost of memory. - */ -class PreloadConfig extends AbstractConfig -{ - /** @var bool */ - private $config_loaded; - - /** - * @param Cache $configCache The configuration cache (based on the config-files) - * @param Config $configRepo The configuration model - */ - public function __construct(Cache $configCache, Config $configRepo) - { - parent::__construct($configCache, $configRepo); - $this->config_loaded = false; - - $this->load(); - } - - /** - * {@inheritDoc} - * - * This loads all config values everytime load is called - */ - public function load(string $cat = 'config') - { - // Don't load the whole configuration twice - if ($this->config_loaded) { - return; - } - - // If not connected, do nothing - if (!$this->configRepo->isConnected()) { - return; - } - - $config = $this->configRepo->load(); - $this->config_loaded = true; - - // load the whole category out of the DB into the cache - $this->configCache->load($config, Cache::SOURCE_DB); - } - - /** - * {@inheritDoc} - */ - public function get(string $cat, string $key, $default_value = null, bool $refresh = false) - { - if ($refresh) { - if ($this->configRepo->isConnected()) { - $config = $this->configRepo->get($cat, $key); - if (isset($config)) { - $this->configCache->set($cat, $key, $config, Cache::SOURCE_DB); - } - } - } - - // use the config cache for return - $result = $this->configCache->get($cat, $key); - - return (isset($result)) ? $result : $default_value; - } - - /** - * {@inheritDoc} - */ - public function set(string $cat, string $key, $value): bool - { - if (!$this->config_loaded) { - $this->load(); - } - - // set the cache first - $cached = $this->configCache->set($cat, $key, $value, Cache::SOURCE_DB); - - // If there is no connected adapter, we're finished - if (!$this->configRepo->isConnected()) { - return $cached; - } - - $stored = $this->configRepo->set($cat, $key, $value); - - return $cached && $stored; - } - - /** - * {@inheritDoc} - */ - public function delete(string $cat, string $key): bool - { - if ($this->config_loaded) { - $this->load(); - } - - $cacheRemoved = $this->configCache->delete($cat, $key); - - if (!$this->configRepo->isConnected()) { - return $cacheRemoved; - } - - $storeRemoved = $this->configRepo->delete($cat, $key); - - return $cacheRemoved || $storeRemoved; - } -} diff --git a/src/Core/Config/Util/ConfigFileLoader.php b/src/Core/Config/Util/ConfigFileManager.php similarity index 83% rename from src/Core/Config/Util/ConfigFileLoader.php rename to src/Core/Config/Util/ConfigFileManager.php index acf6efa34..378d7fbd4 100644 --- a/src/Core/Config/Util/ConfigFileLoader.php +++ b/src/Core/Config/Util/ConfigFileManager.php @@ -26,22 +26,15 @@ use Friendica\Core\Config\Exception\ConfigFileException; use Friendica\Core\Config\ValueObject\Cache; /** - * The ConfigFileLoader loads config-files and stores them in a ConfigCache ( @see Cache ) + * The ConfigFileLoader loads and saves config-files and stores them in a ConfigCache ( @see Cache ) * * It is capable of loading the following config files: * - *.config.php (current) * - *.ini.php (deprecated) * - *.htconfig.php (deprecated) */ -class ConfigFileLoader +class ConfigFileManager { - /** - * The default name of the user defined ini file - * - * @var string - */ - const CONFIG_INI = 'local'; - /** * The default name of the user defined legacy config file * @@ -49,6 +42,13 @@ class ConfigFileLoader */ const CONFIG_HTCONFIG = 'htconfig'; + /** + * The config file, where overrides per admin page/console are saved at + * + * @var string + */ + const CONFIG_DATA_FILE = 'node.config.php'; + /** * The sample string inside the configs, which shouldn't get loaded * @@ -89,7 +89,7 @@ class ConfigFileLoader * * @param Cache $config The config cache to load to * @param array $server The $_SERVER array - * @param bool $raw Setup the raw config format + * @param bool $raw Set up the raw config format * * @throws ConfigFileException */ @@ -106,6 +106,9 @@ class ConfigFileLoader // Now load every other config you find inside the 'config/' directory $this->loadCoreConfig($config); + // Now load the node.config.php file with the node specific config values (based on admin gui/console actions) + $this->loadDataConfig($config); + $config->load($this->loadEnvConfig($server), Cache::SOURCE_ENV); // In case of install mode, add the found basepath (because there isn't a basepath set yet @@ -158,6 +161,50 @@ class ConfigFileLoader } } + /** + * Tries to load the data config file with the overridden data + * + * @param Cache $config The Config cache + * + * @throws ConfigFileException In case the config file isn't loadable + */ + private function loadDataConfig(Cache $config) + { + $filename = $this->configDir . '/' . self::CONFIG_DATA_FILE; + + if (file_exists($filename)) { + $dataArray = include $filename; + + if (!is_array($dataArray)) { + throw new ConfigFileException(sprintf('Error loading config file %s', $filename)); + } + + $config->load($dataArray, Cache::SOURCE_DATA); + } + } + + /** + * Saves overridden config entries back into the data.config.phpR + * + * @param Cache $config The config cache + * + * @throws ConfigFileException In case the config file isn't writeable or the data is invalid + */ + public function saveData(Cache $config) + { + $data = $config->getDataBySource(Cache::SOURCE_DATA); + + $encodedData = ConfigFileTransformer::encode($data); + + if (!$encodedData) { + throw new ConfigFileException('config source cannot get encoded'); + } + + if (!file_put_contents($this->configDir . '/' . self::CONFIG_DATA_FILE, $encodedData)) { + throw new ConfigFileException(sprintf('Cannot save data to file %s/%s', $this->configDir, self::CONFIG_DATA_FILE)); + } + } + /** * Tries to load the specified addon-configuration and returns the config array. * @@ -353,12 +400,16 @@ class ConfigFileLoader */ private function loadConfigFile(string $filepath): array { - $config = include($filepath); + if (file_exists($filepath)) { + $config = include $filepath; - if (!is_array($config)) { - throw new ConfigFileException('Error loading config file ' . $filepath); + if (!is_array($config)) { + throw new ConfigFileException('Error loading config file ' . $filepath); + } + + return $config; + } else { + return []; } - - return $config; } } diff --git a/src/Core/Config/Util/ConfigFileTransformer.php b/src/Core/Config/Util/ConfigFileTransformer.php new file mode 100644 index 000000000..282714df2 --- /dev/null +++ b/src/Core/Config/Util/ConfigFileTransformer.php @@ -0,0 +1,85 @@ +. + * + */ + +namespace Friendica\Core\Config\Util; + +/** + * Util to transform back the config array into a string + */ +class ConfigFileTransformer +{ + public static function encode(array $data): string + { + $dataString = ' [" . 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; + + return $dataString; + } + + protected static function extractArray(array $config, int $level = 0): string + { + $string = ''; + + foreach ($config as $configKey => $configValue) { + $string .= static::mapConfigValue($configKey, $configValue, $level); + } + + return $string; + } + + protected static function mapConfigValue(string $key, $value, $level = 0): string + { + $string = str_repeat("\t", $level + 2) . "'$key' => "; + + if (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, '\'\\')); + } + + $string .= PHP_EOL; + + return $string; + } +} diff --git a/src/Core/Config/ValueObject/Cache.php b/src/Core/Config/ValueObject/Cache.php index 00f8ad045..b5af3280c 100644 --- a/src/Core/Config/ValueObject/Cache.php +++ b/src/Core/Config/ValueObject/Cache.php @@ -21,13 +21,13 @@ namespace Friendica\Core\Config\ValueObject; -use Friendica\Core\Config\Util\ConfigFileLoader; +use Friendica\Core\Config\Util\ConfigFileManager; use ParagonIE\HiddenString\HiddenString; /** * The Friendica config cache for the application * Initial, all *.config.php files are loaded into this cache with the - * ConfigFileLoader ( @see ConfigFileLoader ) + * ConfigFileManager ( @see ConfigFileManager ) */ class Cache { @@ -35,8 +35,8 @@ class Cache const SOURCE_STATIC = 0; /** @var int Indicates that the cache entry is set by file - Low Priority */ const SOURCE_FILE = 1; - /** @var int Indicates that the cache entry is set by the DB config table - Middle Priority */ - const SOURCE_DB = 2; + /** @var int Indicates that the cache entry is manually set by the application (per admin page/console) - Middle Priority */ + const SOURCE_DATA = 2; /** @var int Indicates that the cache entry is set by a server environment variable - High Priority */ const SOURCE_ENV = 3; /** @var int Indicates that the cache entry is fixed and must not be changed */ @@ -128,6 +128,34 @@ class Cache return $this->source[$cat][$key] ?? -1; } + /** + * Returns the whole config array based on the given source type + * + * @param int $source Indicates the source of the config entry + * + * @return array The config array part of the given source + */ + public function getDataBySource(int $source): array + { + $data = []; + + $categories = array_keys($this->source); + + foreach ($categories as $category) { + if (is_array($this->source[$category])) { + $keys = array_keys($this->source[$category]); + + foreach ($keys as $key) { + if ($this->source[$category][$key] === $source) { + $data[$category][$key] = $this->config[$category][$key]; + } + } + } + } + + return $data; + } + /** * Sets a value in the config cache. Accepts raw output from the config table * @@ -154,6 +182,8 @@ class Cache $key == 'password' && is_string($value)) { $this->config[$cat][$key] = new HiddenString((string)$value); + } else if (is_string($value)) { + $this->config[$cat][$key] = self::toConfigValue($value); } else { $this->config[$cat][$key] = $value; } @@ -163,6 +193,32 @@ class Cache return true; } + /** + * Formats a DB value to a config value + * - null = The db-value isn't set + * - bool = The db-value is either '0' or '1' + * - array = The db-value is a serialized array + * - string = The db-value is a string + * + * Keep in mind that there aren't any numeric/integer config values in the database + * + * @param string|null $value + * + * @return null|array|string + */ + public static function toConfigValue(?string $value) + { + if (!isset($value)) { + return null; + } + + if (preg_match("|^a:[0-9]+:{.*}$|s", $value)) { + return unserialize($value); + } else { + return $value; + } + } + /** * Deletes a value from the config cache. * @@ -223,4 +279,69 @@ class Cache return $return; } + + /** + * Merges a new Cache into the existing one and returns the merged Cache + * + * @param Cache $cache The cache, which should get merged into this Cache + * + * @return Cache The merged Cache + */ + public function merge(Cache $cache): Cache + { + $newConfig = $this->config; + $newSource = $this->source; + + $categories = array_keys($cache->config); + + foreach ($categories as $category) { + if (is_array($cache->config[$category])) { + $keys = array_keys($cache->config[$category]); + + foreach ($keys as $key) { + $newConfig[$category][$key] = $cache->config[$category][$key]; + $newSource[$category][$key] = $cache->source[$category][$key]; + } + } + } + + $newCache = new Cache(); + $newCache->config = $newConfig; + $newCache->source = $newSource; + + return $newCache; + } + + + /** + * Diffs a new Cache into the existing one and returns the diffed Cache + * + * @param Cache $cache The cache, which should get deleted for the current Cache + * + * @return Cache The diffed Cache + */ + public function diff(Cache $cache): Cache + { + $newConfig = $this->config; + $newSource = $this->source; + + $categories = array_keys($cache->config); + + foreach ($categories as $category) { + if (is_array($cache->config[$category])) { + $keys = array_keys($cache->config[$category]); + + foreach ($keys as $key) { + unset($newConfig[$category][$key]); + unset($newSource[$category][$key]); + } + } + } + + $newCache = new Cache(); + $newCache->config = $newConfig; + $newCache->source = $newSource; + + return $newCache; + } } diff --git a/src/Core/KeyValueStorage/Type/DBKeyValueStorage.php b/src/Core/KeyValueStorage/Type/DBKeyValueStorage.php index 35be8b43e..d31f3c1ce 100644 --- a/src/Core/KeyValueStorage/Type/DBKeyValueStorage.php +++ b/src/Core/KeyValueStorage/Type/DBKeyValueStorage.php @@ -21,7 +21,7 @@ namespace Friendica\Core\KeyValueStorage\Type; -use Friendica\Core\Config\Util\ValueConversion; +use Friendica\Core\PConfig\Util\ValueConversion; use Friendica\Core\KeyValueStorage\Exceptions\KeyValueStoragePersistenceException; use Friendica\Database\Database; diff --git a/src/Core/PConfig/Repository/PConfig.php b/src/Core/PConfig/Repository/PConfig.php index 5c9d2d51d..506aaeb5a 100644 --- a/src/Core/PConfig/Repository/PConfig.php +++ b/src/Core/PConfig/Repository/PConfig.php @@ -22,7 +22,7 @@ namespace Friendica\Core\PConfig\Repository; use Friendica\App\Mode; -use Friendica\Core\Config\Util\ValueConversion; +use Friendica\Core\PConfig\Util\ValueConversion; use Friendica\Core\PConfig\Exception\PConfigPersistenceException; use Friendica\Database\Database; diff --git a/src/Core/Config/Util/ValueConversion.php b/src/Core/PConfig/Util/ValueConversion.php similarity index 98% rename from src/Core/Config/Util/ValueConversion.php rename to src/Core/PConfig/Util/ValueConversion.php index a3d9d0146..64a4bfc51 100644 --- a/src/Core/Config/Util/ValueConversion.php +++ b/src/Core/PConfig/Util/ValueConversion.php @@ -19,7 +19,7 @@ * */ -namespace Friendica\Core\Config\Util; +namespace Friendica\Core\PConfig\Util; /** * Util class to help to convert from/to (p)config values diff --git a/src/Core/Update.php b/src/Core/Update.php index 450438118..e5ee587dc 100644 --- a/src/Core/Update.php +++ b/src/Core/Update.php @@ -54,7 +54,7 @@ class Update } // Don't check the status if the last update was failed - if (DI::config()->get('system', 'update', Update::SUCCESS, true) == Update::FAILED) { + if (DI::config()->get('system', 'update', Update::SUCCESS) == Update::FAILED) { return; } @@ -119,7 +119,7 @@ class Update DI::lock()->release('dbupdate', true); } - $build = DI::config()->get('system', 'build', null, true); + $build = DI::config()->get('system', 'build', null); if (empty($build) || ($build > DB_UPDATE_VERSION)) { $build = DB_UPDATE_VERSION - 1; @@ -132,7 +132,7 @@ class Update $stored = intval($build); $current = intval(DB_UPDATE_VERSION); if ($stored < $current || $force) { - DI::config()->load('database'); + DI::config()->reload(); // Compare the current structure with the defined structure // If the Lock is acquired, never release it automatically to avoid double updates @@ -141,7 +141,7 @@ class Update Logger::notice('Update starting.', ['from' => $stored, 'to' => $current]); // Checks if the build changed during Lock acquiring (so no double update occurs) - $retryBuild = DI::config()->get('system', 'build', null, true); + $retryBuild = DI::config()->get('system', 'build', null); if ($retryBuild !== $build) { Logger::notice('Update already done.', ['from' => $stored, 'to' => $current]); DI::lock()->release('dbupdate'); @@ -160,8 +160,10 @@ class Update Logger::warning('Pre update failed', ['version' => $version]); DI::config()->set('system', 'update', Update::FAILED); DI::lock()->release('dbupdate'); - DI::config()->set('system', 'maintenance', 0); - DI::config()->set('system', 'maintenance_reason', ''); + DI::config()->beginTransaction() + ->set('system', 'maintenance', false) + ->delete('system', 'maintenance_reason') + ->commit(); return $r; } else { Logger::notice('Pre update executed.', ['version' => $version]); @@ -181,8 +183,10 @@ class Update Logger::error('Update ERROR.', ['from' => $stored, 'to' => $current, 'retval' => $retval]); DI::config()->set('system', 'update', Update::FAILED); DI::lock()->release('dbupdate'); - DI::config()->set('system', 'maintenance', 0); - DI::config()->set('system', 'maintenance_reason', ''); + DI::config()->beginTransaction() + ->set('system', 'maintenance', false) + ->delete('system', 'maintenance_reason') + ->commit(); return $retval; } else { Logger::notice('Database structure update finished.', ['from' => $stored, 'to' => $current]); @@ -198,8 +202,10 @@ class Update Logger::warning('Post update failed', ['version' => $version]); DI::config()->set('system', 'update', Update::FAILED); DI::lock()->release('dbupdate'); - DI::config()->set('system', 'maintenance', 0); - DI::config()->set('system', 'maintenance_reason', ''); + DI::config()->beginTransaction() + ->set('system', 'maintenance', false) + ->delete('system', 'maintenance_reason') + ->commit(); return $r; } else { DI::config()->set('system', 'build', $version); @@ -210,8 +216,10 @@ class Update DI::config()->set('system', 'build', $current); DI::config()->set('system', 'update', Update::SUCCESS); DI::lock()->release('dbupdate'); - DI::config()->set('system', 'maintenance', 0); - DI::config()->set('system', 'maintenance_reason', ''); + DI::config()->beginTransaction() + ->set('system', 'maintenance', false) + ->delete('system', 'maintenance_reason') + ->commit(); Logger::notice('Update success.', ['from' => $stored, 'to' => $current]); if ($sendMail) { diff --git a/src/Core/Worker.php b/src/Core/Worker.php index 8fc74f1d8..2db9256d1 100644 --- a/src/Core/Worker.php +++ b/src/Core/Worker.php @@ -331,7 +331,7 @@ class Worker $mypid = getmypid(); // Quit when in maintenance - if (DI::config()->get('system', 'maintenance', false, true)) { + if (DI::config()->get('system', 'maintenance', false)) { Logger::notice('Maintenance mode - quit process', ['pid' => $mypid]); return false; } diff --git a/src/Database/DBStructure.php b/src/Database/DBStructure.php index 645084a96..7b284bf6d 100644 --- a/src/Database/DBStructure.php +++ b/src/Database/DBStructure.php @@ -74,7 +74,7 @@ class DBStructure $old_tables = ['fserver', 'gcign', 'gcontact', 'gcontact-relation', 'gfollower' ,'glink', 'item-delivery-data', 'item-activity', 'item-content', 'item_id', 'participation', 'poll', 'poll_result', 'queue', 'retriever_rule', 'deliverq', 'dsprphotoq', 'ffinder', 'sign', 'spam', 'term', 'user-item', 'thread', 'item', 'challenge', - 'auth_codes', 'tokens', 'clients', 'profile_check', 'host', 'conversation', 'fcontact']; + 'auth_codes', 'tokens', 'clients', 'profile_check', 'host', 'conversation', 'fcontact', 'config']; $tables = DBA::selectToArray('INFORMATION_SCHEMA.TABLES', ['TABLE_NAME'], ['TABLE_SCHEMA' => DBA::databaseName(), 'TABLE_TYPE' => 'BASE TABLE']); @@ -176,14 +176,16 @@ class DBStructure public static function performUpdate(bool $enable_maintenance_mode = true, bool $verbose = false): string { if ($enable_maintenance_mode) { - DI::config()->set('system', 'maintenance', 1); + DI::config()->set('system', 'maintenance', true); } $status = self::update($verbose, true); if ($enable_maintenance_mode) { - DI::config()->set('system', 'maintenance', 0); - DI::config()->set('system', 'maintenance_reason', ''); + DI::config()->beginTransaction() + ->set('system', 'maintenance', false) + ->delete('system', 'maintenance_reason') + ->commit(); } return $status; diff --git a/src/Module/Admin/Site.php b/src/Module/Admin/Site.php index 194d2cb2c..39dc9f26d 100644 --- a/src/Module/Admin/Site.php +++ b/src/Module/Admin/Site.php @@ -48,8 +48,6 @@ class Site extends BaseAdmin self::checkFormSecurityTokenRedirectOnError('/admin/site', 'admin_site'); - $a = DI::app(); - if (!empty($_POST['republish_directory'])) { Worker::add(Worker::PRIORITY_LOW, 'Directory'); return; @@ -146,9 +144,11 @@ class Site extends BaseAdmin $relay_user_tags = !empty($_POST['relay_user_tags']); $active_panel = (!empty($_POST['active_panel']) ? "#" . trim($_POST['active_panel']) : ''); + $transactionConfig = DI::config()->beginTransaction(); + // Has the directory url changed? If yes, then resubmit the existing profiles there if ($global_directory != DI::config()->get('system', 'directory') && ($global_directory != '')) { - DI::config()->set('system', 'directory', $global_directory); + $transactionConfig->set('system', 'directory', $global_directory); Worker::add(Worker::PRIORITY_LOW, 'Directory'); } @@ -194,131 +194,133 @@ class Site extends BaseAdmin ); } } - DI::config()->set('system', 'ssl_policy' , $ssl_policy); - DI::config()->set('system', 'maxloadavg' , $maxloadavg); - DI::config()->set('system', 'min_memory' , $min_memory); - DI::config()->set('system', 'optimize_tables' , $optimize_tables); - DI::config()->set('system', 'contact_discovery' , $contact_discovery); - DI::config()->set('system', 'synchronize_directory' , $synchronize_directory); - DI::config()->set('system', 'poco_requery_days' , $poco_requery_days); - DI::config()->set('system', 'poco_discovery' , $poco_discovery); - DI::config()->set('system', 'poco_local_search' , $poco_local_search); - DI::config()->set('system', 'nodeinfo' , $nodeinfo); - DI::config()->set('config', 'sitename' , $sitename); - DI::config()->set('config', 'sender_email' , $sender_email); - DI::config()->set('system', 'suppress_tags' , $suppress_tags); - DI::config()->set('system', 'shortcut_icon' , $shortcut_icon); - DI::config()->set('system', 'touch_icon' , $touch_icon); + $transactionConfig->set('system', 'ssl_policy' , $ssl_policy); + $transactionConfig->set('system', 'maxloadavg' , $maxloadavg); + $transactionConfig->set('system', 'min_memory' , $min_memory); + $transactionConfig->set('system', 'optimize_tables' , $optimize_tables); + $transactionConfig->set('system', 'contact_discovery' , $contact_discovery); + $transactionConfig->set('system', 'synchronize_directory' , $synchronize_directory); + $transactionConfig->set('system', 'poco_requery_days' , $poco_requery_days); + $transactionConfig->set('system', 'poco_discovery' , $poco_discovery); + $transactionConfig->set('system', 'poco_local_search' , $poco_local_search); + $transactionConfig->set('system', 'nodeinfo' , $nodeinfo); + $transactionConfig->set('config', 'sitename' , $sitename); + $transactionConfig->set('config', 'sender_email' , $sender_email); + $transactionConfig->set('system', 'suppress_tags' , $suppress_tags); + $transactionConfig->set('system', 'shortcut_icon' , $shortcut_icon); + $transactionConfig->set('system', 'touch_icon' , $touch_icon); if ($banner == "") { - DI::config()->delete('system', 'banner'); + $transactionConfig->delete('system', 'banner'); } else { - DI::config()->set('system', 'banner', $banner); + $transactionConfig->set('system', 'banner', $banner); } if (empty($email_banner)) { - DI::config()->delete('system', 'email_banner'); + $transactionConfig->delete('system', 'email_banner'); } else { - DI::config()->set('system', 'email_banner', $email_banner); + $transactionConfig->set('system', 'email_banner', $email_banner); } if (empty($additional_info)) { - DI::config()->delete('config', 'info'); + $transactionConfig->delete('config', 'info'); } else { - DI::config()->set('config', 'info', $additional_info); + $transactionConfig->set('config', 'info', $additional_info); } - DI::config()->set('system', 'language', $language); - DI::config()->set('system', 'theme', $theme); + $transactionConfig->set('system', 'language', $language); + $transactionConfig->set('system', 'theme', $theme); Theme::install($theme); if ($theme_mobile == '---') { - DI::config()->delete('system', 'mobile-theme'); + $transactionConfig->delete('system', 'mobile-theme'); } else { - DI::config()->set('system', 'mobile-theme', $theme_mobile); + $transactionConfig->set('system', 'mobile-theme', $theme_mobile); } if ($singleuser == '---') { - DI::config()->delete('system', 'singleuser'); + $transactionConfig->delete('system', 'singleuser'); } else { - DI::config()->set('system', 'singleuser', $singleuser); + $transactionConfig->set('system', 'singleuser', $singleuser); } if (preg_match('/\d+(?:\s*[kmg])?/i', $maximagesize)) { - DI::config()->set('system', 'maximagesize', $maximagesize); + $transactionConfig->set('system', 'maximagesize', $maximagesize); } else { DI::sysmsg()->addNotice(DI::l10n()->t('%s is no valid input for maximum image size', $maximagesize)); } - DI::config()->set('system', 'max_image_length' , $maximagelength); - DI::config()->set('system', 'jpeg_quality' , $jpegimagequality); + $transactionConfig->set('system', 'max_image_length' , $maximagelength); + $transactionConfig->set('system', 'jpeg_quality' , $jpegimagequality); - DI::config()->set('config', 'register_policy' , $register_policy); - DI::config()->set('system', 'max_daily_registrations', $daily_registrations); - DI::config()->set('system', 'account_abandon_days' , $abandon_days); - DI::config()->set('config', 'register_text' , $register_text); - DI::config()->set('system', 'allowed_sites' , $allowed_sites); - DI::config()->set('system', 'allowed_email' , $allowed_email); - DI::config()->set('system', 'forbidden_nicknames' , $forbidden_nicknames); - DI::config()->set('system', 'system_actor_name' , $system_actor_name); - DI::config()->set('system', 'no_oembed_rich_content' , $no_oembed_rich_content); - DI::config()->set('system', 'allowed_oembed' , $allowed_oembed); - DI::config()->set('system', 'block_public' , $block_public); - DI::config()->set('system', 'publish_all' , $force_publish); - DI::config()->set('system', 'newuser_private' , $newuser_private); - DI::config()->set('system', 'enotify_no_content' , $enotify_no_content); - DI::config()->set('system', 'disable_embedded' , $disable_embedded); - DI::config()->set('system', 'allow_users_remote_self', $allow_users_remote_self); - DI::config()->set('system', 'explicit_content' , $explicit_content); - DI::config()->set('system', 'proxify_content' , $proxify_content); - DI::config()->set('system', 'cache_contact_avatar' , $cache_contact_avatar); - DI::config()->set('system', 'check_new_version_url' , $check_new_version_url); + $transactionConfig->set('config', 'register_policy' , $register_policy); + $transactionConfig->set('system', 'max_daily_registrations', $daily_registrations); + $transactionConfig->set('system', 'account_abandon_days' , $abandon_days); + $transactionConfig->set('config', 'register_text' , $register_text); + $transactionConfig->set('system', 'allowed_sites' , $allowed_sites); + $transactionConfig->set('system', 'allowed_email' , $allowed_email); + $transactionConfig->set('system', 'forbidden_nicknames' , $forbidden_nicknames); + $transactionConfig->set('system', 'system_actor_name' , $system_actor_name); + $transactionConfig->set('system', 'no_oembed_rich_content' , $no_oembed_rich_content); + $transactionConfig->set('system', 'allowed_oembed' , $allowed_oembed); + $transactionConfig->set('system', 'block_public' , $block_public); + $transactionConfig->set('system', 'publish_all' , $force_publish); + $transactionConfig->set('system', 'newuser_private' , $newuser_private); + $transactionConfig->set('system', 'enotify_no_content' , $enotify_no_content); + $transactionConfig->set('system', 'disable_embedded' , $disable_embedded); + $transactionConfig->set('system', 'allow_users_remote_self', $allow_users_remote_self); + $transactionConfig->set('system', 'explicit_content' , $explicit_content); + $transactionConfig->set('system', 'proxify_content' , $proxify_content); + $transactionConfig->set('system', 'cache_contact_avatar' , $cache_contact_avatar); + $transactionConfig->set('system', 'check_new_version_url' , $check_new_version_url); - DI::config()->set('system', 'block_extended_register', !$enable_multi_reg); - DI::config()->set('system', 'no_openid' , !$enable_openid); - DI::config()->set('system', 'no_regfullname' , !$enable_regfullname); - DI::config()->set('system', 'register_notification' , $register_notification); - DI::config()->set('system', 'community_page_style' , $community_page_style); - DI::config()->set('system', 'max_author_posts_community_page', $max_author_posts_community_page); - DI::config()->set('system', 'verifyssl' , $verifyssl); - DI::config()->set('system', 'proxyuser' , $proxyuser); - DI::config()->set('system', 'proxy' , $proxy); - DI::config()->set('system', 'curl_timeout' , $timeout); - DI::config()->set('system', 'imap_disabled' , !$mail_enabled && function_exists('imap_open')); - DI::config()->set('system', 'ostatus_disabled' , !$ostatus_enabled); - DI::config()->set('system', 'diaspora_enabled' , $diaspora_enabled); + $transactionConfig->set('system', 'block_extended_register', !$enable_multi_reg); + $transactionConfig->set('system', 'no_openid' , !$enable_openid); + $transactionConfig->set('system', 'no_regfullname' , !$enable_regfullname); + $transactionConfig->set('system', 'register_notification' , $register_notification); + $transactionConfig->set('system', 'community_page_style' , $community_page_style); + $transactionConfig->set('system', 'max_author_posts_community_page', $max_author_posts_community_page); + $transactionConfig->set('system', 'verifyssl' , $verifyssl); + $transactionConfig->set('system', 'proxyuser' , $proxyuser); + $transactionConfig->set('system', 'proxy' , $proxy); + $transactionConfig->set('system', 'curl_timeout' , $timeout); + $transactionConfig->set('system', 'imap_disabled' , !$mail_enabled && function_exists('imap_open')); + $transactionConfig->set('system', 'ostatus_disabled' , !$ostatus_enabled); + $transactionConfig->set('system', 'diaspora_enabled' , $diaspora_enabled); - DI::config()->set('config', 'private_addons' , $private_addons); + $transactionConfig->set('config', 'private_addons' , $private_addons); - DI::config()->set('system', 'force_ssl' , $force_ssl); - DI::config()->set('system', 'hide_help' , !$show_help); + $transactionConfig->set('system', 'force_ssl' , $force_ssl); + $transactionConfig->set('system', 'hide_help' , !$show_help); - DI::config()->set('system', 'dbclean' , $dbclean); - DI::config()->set('system', 'dbclean-expire-days' , $dbclean_expire_days); - DI::config()->set('system', 'dbclean_expire_conversation', $dbclean_expire_conv); + $transactionConfig->set('system', 'dbclean' , $dbclean); + $transactionConfig->set('system', 'dbclean-expire-days' , $dbclean_expire_days); + $transactionConfig->set('system', 'dbclean_expire_conversation', $dbclean_expire_conv); if ($dbclean_unclaimed == 0) { $dbclean_unclaimed = $dbclean_expire_days; } - DI::config()->set('system', 'dbclean-expire-unclaimed', $dbclean_unclaimed); + $transactionConfig->set('system', 'dbclean-expire-unclaimed', $dbclean_unclaimed); - DI::config()->set('system', 'max_comments', $max_comments); - DI::config()->set('system', 'max_display_comments', $max_display_comments); + $transactionConfig->set('system', 'max_comments', $max_comments); + $transactionConfig->set('system', 'max_display_comments', $max_display_comments); if ($temppath != '') { $temppath = BasePath::getRealPath($temppath); } - DI::config()->set('system', 'temppath', $temppath); + $transactionConfig->set('system', 'temppath', $temppath); - DI::config()->set('system', 'only_tag_search' , $only_tag_search); - DI::config()->set('system', 'compute_group_counts', $compute_group_counts); + $transactionConfig->set('system', 'only_tag_search' , $only_tag_search); + $transactionConfig->set('system', 'compute_group_counts', $compute_group_counts); - DI::config()->set('system', 'worker_queues' , $worker_queues); - DI::config()->set('system', 'worker_fastlane' , $worker_fastlane); + $transactionConfig->set('system', 'worker_queues' , $worker_queues); + $transactionConfig->set('system', 'worker_fastlane' , $worker_fastlane); - DI::config()->set('system', 'relay_directly' , $relay_directly); - DI::config()->set('system', 'relay_scope' , $relay_scope); - DI::config()->set('system', 'relay_server_tags', $relay_server_tags); - DI::config()->set('system', 'relay_deny_tags' , $relay_deny_tags); - DI::config()->set('system', 'relay_user_tags' , $relay_user_tags); + $transactionConfig->set('system', 'relay_directly' , $relay_directly); + $transactionConfig->set('system', 'relay_scope' , $relay_scope); + $transactionConfig->set('system', 'relay_server_tags', $relay_server_tags); + $transactionConfig->set('system', 'relay_deny_tags' , $relay_deny_tags); + $transactionConfig->set('system', 'relay_user_tags' , $relay_user_tags); + + $transactionConfig->commit(); DI::baseUrl()->redirect('admin/site' . $active_panel); } diff --git a/src/Module/Friendica.php b/src/Module/Friendica.php index 72360ddca..bbcccd7da 100644 --- a/src/Module/Friendica.php +++ b/src/Module/Friendica.php @@ -157,7 +157,7 @@ class Friendica extends BaseModule $visible_addons = Addon::getVisibleList(); - $config->load('feature_lock'); + $config->reload(); $locked_features = []; $featureLocks = $config->get('config', 'feature_lock'); if (isset($featureLocks)) { diff --git a/src/Worker/DBUpdate.php b/src/Worker/DBUpdate.php index e11f7bf40..7b7c3b8c9 100644 --- a/src/Worker/DBUpdate.php +++ b/src/Worker/DBUpdate.php @@ -32,7 +32,7 @@ class DBUpdate public static function execute() { // Just in case the last update wasn't failed - if (DI::config()->get('system', 'update', Update::SUCCESS, true) != Update::FAILED) { + if (DI::config()->get('system', 'update', Update::SUCCESS) != Update::FAILED) { Update::run(DI::app()->getBasePath()); } } diff --git a/static/dbstructure.config.php b/static/dbstructure.config.php index 48e25961c..018bbf2c3 100644 --- a/static/dbstructure.config.php +++ b/static/dbstructure.config.php @@ -55,7 +55,7 @@ use Friendica\Database\DBA; if (!defined('DB_UPDATE_VERSION')) { - define('DB_UPDATE_VERSION', 1507); + define('DB_UPDATE_VERSION', 1508); } return [ @@ -553,19 +553,6 @@ return [ "k_expires" => ["k", "expires"], ] ], - "config" => [ - "comment" => "main configuration storage", - "fields" => [ - "id" => ["type" => "int unsigned", "not null" => "1", "extra" => "auto_increment", "primary" => "1", "comment" => ""], - "cat" => ["type" => "varbinary(50)", "not null" => "1", "default" => "", "comment" => ""], - "k" => ["type" => "varbinary(50)", "not null" => "1", "default" => "", "comment" => ""], - "v" => ["type" => "mediumtext", "comment" => ""], - ], - "indexes" => [ - "PRIMARY" => ["id"], - "cat_k" => ["UNIQUE", "cat", "k"], - ] - ], "contact-relation" => [ "comment" => "Contact relations", "fields" => [ diff --git a/static/dependencies.config.php b/static/dependencies.config.php index c59d0478a..1844001bb 100644 --- a/static/dependencies.config.php +++ b/static/dependencies.config.php @@ -76,7 +76,7 @@ return [ $_SERVER ] ], - Config\Util\ConfigFileLoader::class => [ + Config\Util\ConfigFileManager::class => [ 'instanceOf' => Config\Factory\Config::class, 'call' => [ ['createConfigFileLoader', [ @@ -98,9 +98,9 @@ return [ ], ], Config\Capability\IManageConfigValues::class => [ - 'instanceOf' => Config\Factory\Config::class, - 'call' => [ - ['create', [], Dice::CHAIN_CALL], + 'instanceOf' => Config\Model\Config::class, + 'constructParams' => [ + $_SERVER, ], ], PConfig\Capability\IManagePersonalConfigValues::class => [ diff --git a/tests/FixtureTest.php b/tests/FixtureTest.php index a57d3aa76..efb928031 100644 --- a/tests/FixtureTest.php +++ b/tests/FixtureTest.php @@ -25,20 +25,24 @@ namespace Friendica\Test; use Dice\Dice; use Friendica\App\Arguments; use Friendica\App\Router; +use Friendica\Core\Config\Factory\Config; +use Friendica\Core\Config\Util\ConfigFileManager; use Friendica\Core\Config\ValueObject\Cache; -use Friendica\Core\Config\Capability\IManageConfigValues; use Friendica\Core\Session\Capability\IHandleSessions; use Friendica\Core\Session\Type\Memory; use Friendica\Database\Database; use Friendica\Database\DBStructure; use Friendica\DI; use Friendica\Test\Util\Database\StaticDatabase; +use Friendica\Test\Util\VFSTrait; /** * Parent class for test cases requiring fixtures */ abstract class FixtureTest extends DatabaseTest { + use VFSTrait; + /** @var Dice */ protected $dice; @@ -47,6 +51,8 @@ abstract class FixtureTest extends DatabaseTest */ protected function setUp(): void { + $this->setUpVfsDir(); + parent::setUp(); $server = $_SERVER; @@ -54,6 +60,10 @@ abstract class FixtureTest extends DatabaseTest $this->dice = (new Dice()) ->addRules(include __DIR__ . '/../static/dependencies.config.php') + ->addRule(ConfigFileManager::class, [ + 'instanceOf' => Config::class, + 'call' => [['createConfigFileLoader', [$this->root->url(), $server,], + Dice::CHAIN_CALL]]]) ->addRule(Database::class, ['instanceOf' => StaticDatabase::class, 'shared' => true]) ->addRule(IHandleSessions::class, ['instanceOf' => Memory::class, 'shared' => true, 'call' => null]) ->addRule(Arguments::class, [ @@ -64,7 +74,6 @@ abstract class FixtureTest extends DatabaseTest ]); DI::init($this->dice); - /** @var IManageConfigValues $config */ $configCache = $this->dice->create(Cache::class); $configCache->set('database', 'disable_pdo', true); diff --git a/tests/Util/VFSTrait.php b/tests/Util/VFSTrait.php index 30c27451e..e36cc1234 100644 --- a/tests/Util/VFSTrait.php +++ b/tests/Util/VFSTrait.php @@ -54,6 +54,21 @@ trait VFSTrait $this->setConfigFile('defaults.config.php', true); $this->setConfigFile('settings.config.php', true); $this->setConfigFile('local.config.php'); + $this->setDataFile('node.config.php'); + } + + protected function setDataFile(string $filename) + { + $file = dirname(__DIR__) . DIRECTORY_SEPARATOR . + 'datasets' . DIRECTORY_SEPARATOR . + 'config' . DIRECTORY_SEPARATOR . + $filename; + + if (file_exists($file)) { + vfsStream::newFile($filename) + ->at($this->root->getChild('config')) + ->setContent(file_get_contents($file)); + } } /** diff --git a/tests/datasets/api.fixture.php b/tests/datasets/api.fixture.php index a8119106e..b50f70625 100644 --- a/tests/datasets/api.fixture.php +++ b/tests/datasets/api.fixture.php @@ -36,33 +36,6 @@ return [ 'mail', 'post-delivery-data', // Base test config to avoid notice messages - 'config' => [ - [ - 'cat' => 'system', - 'k' => 'url', - 'v' => 'http://localhost', - ], - [ - 'cat' => 'config', - 'k' => 'hostname', - 'v' => 'localhost', - ], - [ - 'cat' => 'system', - 'k' => 'worker_dont_fork', - 'v' => '1', - ], - [ - 'cat' => 'system', - 'k' => 'curl_timeout', - 'v' => '1', - ], - [ - 'cat' => 'system', - 'k' => 'xrd_timeout', - 'v' => '1', - ], - ], 'user' => [ [ 'uid' => 42, diff --git a/tests/datasets/config/A.node.config.php b/tests/datasets/config/A.node.config.php new file mode 100644 index 000000000..b81e01737 --- /dev/null +++ b/tests/datasets/config/A.node.config.php @@ -0,0 +1,22 @@ + [ + 'hostname' => 'testhost', + 'username' => 'testuser', + 'password' => 'testpw', + 'database' => 'testdb', + 'charset' => 'utf8mb4', + ], + 'config' => [ + 'admin_email' => 'admin@test.it', + 'sitename' => 'Friendica Social Network', + 'register_policy' => 2, + 'register_text' => '', + ], + 'system' => [ + 'default_timezone' => 'UTC', + 'language' => 'en', + 'theme' => 'frio', + ], +]; diff --git a/tests/datasets/config/B.node.config.php b/tests/datasets/config/B.node.config.php new file mode 100644 index 000000000..499e092a4 --- /dev/null +++ b/tests/datasets/config/B.node.config.php @@ -0,0 +1,39 @@ + [ + 'hostname' => 'testhost', + 'username' => 'testuser', + 'password' => 'testpw', + 'database' => 'testdb', + 'charset' => 'utf8mb4', + ], + 'config' => [ + 'admin_email' => 'admin@test.it', + 'sitename' => 'Friendica Social Network', + 'register_policy' => 2, + 'register_text' => '', + 'test' => [ + 'a' => [ + 'next' => 'value', + 'bool' => false, + 'innerArray' => [ + 'a' => 4.55, + 'b' => false, + 'string2' => 'false', + ], + ], + 'v' => true, + 'v3' => 1, + 'v4' => 5.6443, + ], + ], + 'system' => [ + 'default_timezone' => 'UTC', + 'language' => 'en', + 'theme' => 'frio', + 'int' => 23, + 'float' => 2.5, + 'with special chars' => 'I can\'t follow this "$&§%"$%§$%&\'[),', + ], +]; diff --git a/tests/datasets/config/C.node.config.php b/tests/datasets/config/C.node.config.php new file mode 100644 index 000000000..6d93d8d7a --- /dev/null +++ b/tests/datasets/config/C.node.config.php @@ -0,0 +1,48 @@ + [ + 'hostname' => 'friendica.local', + ], + 'system' => [ + 'disable_email_validation' => 1, + 'disable_password_exposed' => 1, + 'throttle_limit_day' => 100, + 'throttle_limit_week' => 100, + 'throttle_limit_month' => 100, + 'temppath' => '/tmp/friendica.local', + 'theme' => 'frio', + 'url' => 'https://friendica.local', + 'urlpath' => '', + 'build' => 1508, + 'maintenance' => false, + 'dbupdate' => 1, + 'update' => 0, + 'spoolpath' => '/tmp/localhost/spool', + 'actor_name' => 'friendica', + 'site_prvkey' => '-----BEGIN PRIVATE KEY----- +MIICeAIBADANBgkqhkiG9w0BAQEFAASCAmIwggJeAgEAAoGBALgypZoZ2X7rYCHT +pXZRPKZYOJrtzAZoAD6a2FESfax/mW7tGF8/XGcsu4E8a0WUs18CDb09iDlECs0r +WFkyxOsS55FyDPVNOVheU6ziqmjTNggr1qR8iIpPW2xHAnFjCfvJxgaUfszdoeUV +mhA++BrxFGRpfcH49O+dVcjisJEVAgMBAAECgYEAq0QsRkSSvjgMgmdQCdsvEVwm +BafldG9vCsbfK0KOJ73c5A8AAk/fku88yMVs2J2SylwWekakStrBUFNlKkrSXEv3 +r1l0b+dfniaTGJkawqgRh+U/0G9LN+cdZYt5EuhNhCbmIQB+FOI12jAx6COwEENi +824zrrwn0BU1VTOMwwECQQDnBqq0J9JCJAtjqX+3xd8DvTRYjYvtvXlQ8fwrGxBc +GwURNG8aMGTaj+sn2kVWNt4wLQqj/CTJ42y0bkKYMJftAkEAzBwSqfuMZD/+nEkM +wDQb1G2z+BaxLh5JJQo80WX9tORbspOkbEuPgFprO6NB0/vNH5m4AaL3jymokH1p +JfVoyQJBAN+GSsmOMdf+qepeiA0V7OXgPXJkWXvHtEZGK1bFk7maBvgThF+RbTMu +xjZD8IwvACEao03wWuPfIEEe4V4Avi0CQCc5FdUYg+gX7CO4XfzphpeR5U29fprw +MvotN3a99L04TO7KNISjGJZ/ya+SNeo4rzhtX9DgslYOmVf64aPrvxECQQDB79vF +Kx2HyacBSErXrlqqkPdFo8KxhKCAVhrs0VBU1WPswolzsZvRdFuielhGP49DjjE7 +JV1Als1hl1xTduNb +-----END PRIVATE KEY----- + ', + 'site_pubkey' => '-----BEGIN PUBLIC KEY----- +MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQC4MqWaGdl+62Ah06V2UTymWDia +7cwGaAA+mthREn2sf5lu7RhfP1xnLLuBPGtFlLNfAg29PYg5RArNK1hZMsTrEueR +cgz1TTlYXlOs4qpo0zYIK9akfIiKT1tsRwJxYwn7ycYGlH7M3aHlFZoQPvga8RRk +aX3B+PTvnVXI4rCRFQIDAQAB +-----END PUBLIC KEY----- + ', + ], +]; diff --git a/tests/datasets/config/node.config.php b/tests/datasets/config/node.config.php new file mode 100644 index 000000000..335ef19c9 --- /dev/null +++ b/tests/datasets/config/node.config.php @@ -0,0 +1,13 @@ + [ + 'hostname' => 'localhost', + ], + 'system' => [ + 'url' => 'http://localhost', + "worker_dont_fork" => 1, + "curl_timeout"=> 1, + "xrd_timeout"=> 1, + ], +]; diff --git a/tests/functional/DependencyCheckTest.php b/tests/functional/DependencyCheckTest.php index 3b21f7584..a371ffea4 100644 --- a/tests/functional/DependencyCheckTest.php +++ b/tests/functional/DependencyCheckTest.php @@ -31,7 +31,7 @@ use Friendica\Core\Lock\Capability\ICanLock; use Friendica\Database\Database; use Friendica\Test\Util\VFSTrait; use Friendica\Util\BasePath; -use Friendica\Core\Config\Util\ConfigFileLoader; +use Friendica\Core\Config\Util\ConfigFileManager; use Friendica\Util\Profiler; use PHPUnit\Framework\TestCase; use Psr\Log\LoggerInterface; @@ -73,13 +73,13 @@ class DependencyCheckTest extends TestCase */ public function testConfigFileLoader() { - /** @var ConfigFileLoader $configFileLoader */ - $configFileLoader = $this->dice->create(ConfigFileLoader::class); + /** @var ConfigFileManager $configFileManager */ + $configFileManager = $this->dice->create(ConfigFileManager::class); - self::assertInstanceOf(ConfigFileLoader::class, $configFileLoader); + self::assertInstanceOf(ConfigFileManager::class, $configFileManager); $configCache = new Cache(); - $configFileLoader->setupCache($configCache); + $configFileManager->setupCache($configCache); self::assertNotEmpty($configCache->getAll()); self::assertArrayHasKey('database', $configCache->getAll()); @@ -150,7 +150,6 @@ class DependencyCheckTest extends TestCase self::assertTrue($mode->has(App\Mode::LOCALCONFIGPRESENT), 'No local config present'); self::assertTrue($mode->has(App\Mode::DBAVAILABLE), 'Database is not available'); - self::assertTrue($mode->has(App\Mode::DBCONFIGAVAILABLE), 'Database config is not available'); self::assertTrue($mode->has(App\Mode::MAINTENANCEDISABLED), 'In maintenance mode'); self::assertTrue($mode->isNormal(), 'Not in normal mode'); diff --git a/tests/src/App/ModeTest.php b/tests/src/App/ModeTest.php index 86a6c7763..aecd2b175 100644 --- a/tests/src/App/ModeTest.php +++ b/tests/src/App/ModeTest.php @@ -102,29 +102,11 @@ class ModeTest extends MockedTest self::assertFalse($mode->has(Mode::DBAVAILABLE)); } - public function testWithoutDatabaseSetup() - { - $this->basePathMock->shouldReceive('getPath')->andReturn($this->root->url())->once(); - - $this->databaseMock->shouldReceive('connected')->andReturn(true)->once(); - $this->databaseMock->shouldReceive('fetchFirst') - ->with('SHOW TABLES LIKE \'config\'')->andReturn(false)->once(); - - $mode = (new Mode())->determine($this->basePathMock, $this->databaseMock, $this->configCacheMock); - - self::assertFalse($mode->isNormal()); - self::assertTrue($mode->isInstall()); - - self::assertTrue($mode->has(Mode::LOCALCONFIGPRESENT)); - } - public function testWithMaintenanceMode() { $this->basePathMock->shouldReceive('getPath')->andReturn($this->root->url())->once(); $this->databaseMock->shouldReceive('connected')->andReturn(true)->once(); - $this->databaseMock->shouldReceive('fetchFirst') - ->with('SHOW TABLES LIKE \'config\'')->andReturn(true)->once(); $this->configCacheMock->shouldReceive('get')->with('system', 'maintenance') ->andReturn(true)->once(); @@ -133,7 +115,6 @@ class ModeTest extends MockedTest self::assertFalse($mode->isNormal()); self::assertFalse($mode->isInstall()); - self::assertTrue($mode->has(Mode::DBCONFIGAVAILABLE)); self::assertFalse($mode->has(Mode::MAINTENANCEDISABLED)); } @@ -142,20 +123,14 @@ class ModeTest extends MockedTest $this->basePathMock->shouldReceive('getPath')->andReturn($this->root->url())->once(); $this->databaseMock->shouldReceive('connected')->andReturn(true)->once(); - $this->databaseMock->shouldReceive('fetchFirst') - ->with('SHOW TABLES LIKE \'config\'')->andReturn(true)->once(); $this->configCacheMock->shouldReceive('get')->with('system', 'maintenance') ->andReturn(false)->once(); - $this->databaseMock->shouldReceive('selectFirst') - ->with('config', ['v'], ['cat' => 'system', 'k' => 'maintenance']) - ->andReturn(['v' => null])->once(); $mode = (new Mode())->determine($this->basePathMock, $this->databaseMock, $this->configCacheMock); self::assertTrue($mode->isNormal()); self::assertFalse($mode->isInstall()); - self::assertTrue($mode->has(Mode::DBCONFIGAVAILABLE)); self::assertTrue($mode->has(Mode::MAINTENANCEDISABLED)); } @@ -167,20 +142,14 @@ class ModeTest extends MockedTest $this->basePathMock->shouldReceive('getPath')->andReturn($this->root->url())->once(); $this->databaseMock->shouldReceive('connected')->andReturn(true)->once(); - $this->databaseMock->shouldReceive('fetchFirst') - ->with('SHOW TABLES LIKE \'config\'')->andReturn(true)->once(); $this->configCacheMock->shouldReceive('get')->with('system', 'maintenance') ->andReturn(false)->once(); - $this->databaseMock->shouldReceive('selectFirst') - ->with('config', ['v'], ['cat' => 'system', 'k' => 'maintenance']) - ->andReturn(['v' => '0'])->once(); $mode = (new Mode())->determine($this->basePathMock, $this->databaseMock, $this->configCacheMock); self::assertTrue($mode->isNormal()); self::assertFalse($mode->isInstall()); - self::assertTrue($mode->has(Mode::DBCONFIGAVAILABLE)); self::assertTrue($mode->has(Mode::MAINTENANCEDISABLED)); } diff --git a/tests/src/Core/Config/Cache/CacheTest.php b/tests/src/Core/Config/Cache/CacheTest.php index 6de87be5d..2db6196b7 100644 --- a/tests/src/Core/Config/Cache/CacheTest.php +++ b/tests/src/Core/Config/Cache/CacheTest.php @@ -21,7 +21,7 @@ namespace Friendica\Test\src\Core\Config\Cache; -use Friendica\Core\Config\Cache; +use Friendica\Core\Config\ValueObject\Cache; use Friendica\Test\MockedTest; use ParagonIE\HiddenString\HiddenString; use stdClass; @@ -49,7 +49,7 @@ class CacheTest extends MockedTest ]; } - private function assertConfigValues($data, \Friendica\Core\Config\ValueObject\Cache $configCache) + private function assertConfigValues($data, Cache $configCache) { foreach ($data as $cat => $values) { foreach ($values as $key => $value) { @@ -64,7 +64,7 @@ class CacheTest extends MockedTest */ public function testLoadConfigArray($data) { - $configCache = new \Friendica\Core\Config\ValueObject\Cache(); + $configCache = new Cache(); $configCache->load($data); self::assertConfigValues($data, $configCache); @@ -83,27 +83,27 @@ class CacheTest extends MockedTest ] ]; - $configCache = new \Friendica\Core\Config\ValueObject\Cache(); - $configCache->load($data, \Friendica\Core\Config\ValueObject\Cache::SOURCE_DB); + $configCache = new Cache(); + $configCache->load($data, Cache::SOURCE_DATA); // doesn't override - Low Priority due Config file - $configCache->load($override, \Friendica\Core\Config\ValueObject\Cache::SOURCE_FILE); + $configCache->load($override, Cache::SOURCE_FILE); self::assertConfigValues($data, $configCache); // override the value - High Prio due Server Env - $configCache->load($override, \Friendica\Core\Config\ValueObject\Cache::SOURCE_ENV); + $configCache->load($override, Cache::SOURCE_ENV); self::assertEquals($override['system']['test'], $configCache->get('system', 'test')); self::assertEquals($override['system']['boolTrue'], $configCache->get('system', 'boolTrue')); // Don't overwrite server ENV variables - even in load mode - $configCache->load($data, \Friendica\Core\Config\ValueObject\Cache::SOURCE_DB); + $configCache->load($data, Cache::SOURCE_DATA); self::assertEquals($override['system']['test'], $configCache->get('system', 'test')); self::assertEquals($override['system']['boolTrue'], $configCache->get('system', 'boolTrue')); // Overwrite ENV variables with ENV variables - $configCache->load($data, \Friendica\Core\Config\ValueObject\Cache::SOURCE_ENV); + $configCache->load($data, Cache::SOURCE_ENV); self::assertConfigValues($data, $configCache); self::assertNotEquals($override['system']['test'], $configCache->get('system', 'test')); @@ -115,7 +115,7 @@ class CacheTest extends MockedTest */ public function testLoadConfigArrayWrong() { - $configCache = new \Friendica\Core\Config\ValueObject\Cache(); + $configCache = new Cache(); // empty dataset $configCache->load([]); @@ -136,7 +136,7 @@ class CacheTest extends MockedTest */ public function testGetAll($data) { - $configCache = new \Friendica\Core\Config\ValueObject\Cache(); + $configCache = new Cache(); $configCache->load($data); $all = $configCache->getAll(); @@ -151,7 +151,7 @@ class CacheTest extends MockedTest */ public function testSetGet($data) { - $configCache = new \Friendica\Core\Config\ValueObject\Cache(); + $configCache = new Cache(); foreach ($data as $cat => $values) { foreach ($values as $key => $value) { @@ -167,7 +167,7 @@ class CacheTest extends MockedTest */ public function testGetEmpty() { - $configCache = new \Friendica\Core\Config\ValueObject\Cache(); + $configCache = new Cache(); self::assertNull($configCache->get('something', 'value')); } @@ -177,7 +177,7 @@ class CacheTest extends MockedTest */ public function testGetCat() { - $configCache = new \Friendica\Core\Config\ValueObject\Cache([ + $configCache = new Cache([ 'system' => [ 'key1' => 'value1', 'key2' => 'value2', @@ -205,7 +205,7 @@ class CacheTest extends MockedTest */ public function testDelete($data) { - $configCache = new \Friendica\Core\Config\ValueObject\Cache($data); + $configCache = new Cache($data); foreach ($data as $cat => $values) { foreach ($values as $key => $value) { @@ -222,7 +222,7 @@ class CacheTest extends MockedTest */ public function testKeyDiffWithResult($data) { - $configCache = new \Friendica\Core\Config\ValueObject\Cache($data); + $configCache = new Cache($data); $diffConfig = [ 'fakeCat' => [ @@ -239,7 +239,7 @@ class CacheTest extends MockedTest */ public function testKeyDiffWithoutResult($data) { - $configCache = new \Friendica\Core\Config\ValueObject\Cache($data); + $configCache = new Cache($data); $diffConfig = $configCache->getAll(); @@ -251,7 +251,7 @@ class CacheTest extends MockedTest */ public function testPasswordHide() { - $configCache = new \Friendica\Core\Config\ValueObject\Cache([ + $configCache = new Cache([ 'database' => [ 'password' => 'supersecure', 'username' => 'notsecured', @@ -268,7 +268,7 @@ class CacheTest extends MockedTest */ public function testPasswordShow() { - $configCache = new \Friendica\Core\Config\ValueObject\Cache([ + $configCache = new Cache([ 'database' => [ 'password' => 'supersecure', 'username' => 'notsecured', @@ -285,7 +285,7 @@ class CacheTest extends MockedTest */ public function testEmptyPassword() { - $configCache = new \Friendica\Core\Config\ValueObject\Cache([ + $configCache = new Cache([ 'database' => [ 'password' => '', 'username' => '', @@ -299,7 +299,7 @@ class CacheTest extends MockedTest public function testWrongTypePassword() { - $configCache = new \Friendica\Core\Config\ValueObject\Cache([ + $configCache = new Cache([ 'database' => [ 'password' => new stdClass(), 'username' => '', @@ -309,7 +309,7 @@ class CacheTest extends MockedTest self::assertNotEmpty($configCache->get('database', 'password')); self::assertEmpty($configCache->get('database', 'username')); - $configCache = new \Friendica\Core\Config\ValueObject\Cache([ + $configCache = new Cache([ 'database' => [ 'password' => 23, 'username' => '', @@ -327,19 +327,87 @@ class CacheTest extends MockedTest public function testSetOverrides($data) { - $configCache = new \Friendica\Core\Config\ValueObject\Cache(); - $configCache->load($data, \Friendica\Core\Config\ValueObject\Cache::SOURCE_DB); + $configCache = new Cache(); + $configCache->load($data, Cache::SOURCE_DATA); // test with wrong override - self::assertFalse($configCache->set('system', 'test', '1234567', \Friendica\Core\Config\ValueObject\Cache::SOURCE_FILE)); + self::assertFalse($configCache->set('system', 'test', '1234567', Cache::SOURCE_FILE)); self::assertEquals($data['system']['test'], $configCache->get('system', 'test')); // test with override (equal) - self::assertTrue($configCache->set('system', 'test', '8910', \Friendica\Core\Config\ValueObject\Cache::SOURCE_DB)); + self::assertTrue($configCache->set('system', 'test', '8910', Cache::SOURCE_DATA)); self::assertEquals('8910', $configCache->get('system', 'test')); // test with override (over) - self::assertTrue($configCache->set('system', 'test', '111213', \Friendica\Core\Config\ValueObject\Cache::SOURCE_ENV)); + self::assertTrue($configCache->set('system', 'test', '111213', Cache::SOURCE_ENV)); self::assertEquals('111213', $configCache->get('system', 'test')); } + + /** + * @dataProvider dataTests + * + * @return void + */ + public function testSetData($data) + { + $configCache = new Cache(); + $configCache->load($data, Cache::SOURCE_FILE); + + $configCache->set('system', 'test_2','with_data', Cache::SOURCE_DATA); + + $this->assertEquals(['system' => ['test_2' => 'with_data']], $configCache->getDataBySource(Cache::SOURCE_DATA)); + $this->assertEquals($data, $configCache->getDataBySource(Cache::SOURCE_FILE)); + } + + /** + * @dataProvider dataTests + */ + public function testMerge($data) + { + $configCache = new Cache(); + $configCache->load($data, Cache::SOURCE_FILE); + + $configCache->set('system', 'test_2','with_data', Cache::SOURCE_DATA); + $configCache->set('config', 'test_override','with_another_data', Cache::SOURCE_DATA); + $configCache->set('old_category', 'test_45','given category', Cache::SOURCE_DATA); + + $newCache = new Cache(); + $newCache->set('config', 'test_override','override it again', Cache::SOURCE_DATA); + $newCache->set('system', 'test_3','new value', Cache::SOURCE_DATA); + $newCache->set('new_category', 'test_23','added category', Cache::SOURCE_DATA); + + $mergedCache = $configCache->merge($newCache); + + self::assertEquals('with_data', $mergedCache->get('system', 'test_2')); + self::assertEquals('override it again', $mergedCache->get('config', 'test_override')); + self::assertEquals('new value', $mergedCache->get('system', 'test_3')); + self::assertEquals('given category', $mergedCache->get('old_category', 'test_45')); + self::assertEquals('added category', $mergedCache->get('new_category', 'test_23')); + } + + /** + * @dataProvider dataTests + */ + public function testDiff($data) + { + $configCache = new Cache(); + $configCache->load($data, Cache::SOURCE_FILE); + + $configCache->set('system', 'test_2','with_data', Cache::SOURCE_DATA); + $configCache->set('config', 'test_override','with_another_data', Cache::SOURCE_DATA); + + $newCache = new Cache(); + $newCache->set('config', 'test_override','override it again', Cache::SOURCE_DATA); + $newCache->set('system', 'test_3','new value', Cache::SOURCE_DATA); + + $mergedCache = $configCache->diff($newCache); + + print_r($mergedCache); + + self::assertEquals('with_data', $mergedCache->get('system', 'test_2')); + // existing entry was dropped + self::assertNull($mergedCache->get('config', 'test_override')); + // the newCache entry wasn't set, because we Diff + self::assertNull($mergedCache->get('system', 'test_3')); + } } diff --git a/tests/src/Core/Config/Cache/ConfigFileLoaderTest.php b/tests/src/Core/Config/Cache/ConfigFileManagerTest.php similarity index 83% rename from tests/src/Core/Config/Cache/ConfigFileLoaderTest.php rename to tests/src/Core/Config/Cache/ConfigFileManagerTest.php index be1c7def6..99049426b 100644 --- a/tests/src/Core/Config/Cache/ConfigFileLoaderTest.php +++ b/tests/src/Core/Config/Cache/ConfigFileManagerTest.php @@ -21,14 +21,14 @@ namespace Friendica\Test\src\Core\Config\Cache; -use Friendica\Core\Config\Cache; use Friendica\Core\Config\Factory\Config; +use Friendica\Core\Config\ValueObject\Cache; use Friendica\Test\MockedTest; use Friendica\Test\Util\VFSTrait; -use Friendica\Core\Config\Util\ConfigFileLoader; +use Friendica\Core\Config\Util\ConfigFileManager; use org\bovigo\vfs\vfsStream; -class ConfigFileLoaderTest extends MockedTest +class ConfigFileManagerTest extends MockedTest { use VFSTrait; @@ -46,12 +46,12 @@ class ConfigFileLoaderTest extends MockedTest { $this->delConfigFile('local.config.php'); - $configFileLoader = new ConfigFileLoader( + $configFileLoader = new ConfigFileManager( $this->root->url(), $this->root->url() . DIRECTORY_SEPARATOR . Config::CONFIG_DIR, $this->root->url() . DIRECTORY_SEPARATOR . Config::STATIC_DIR ); - $configCache = new \Friendica\Core\Config\ValueObject\Cache(); + $configCache = new Cache(); $configFileLoader->setupCache($configCache); @@ -72,12 +72,12 @@ class ConfigFileLoaderTest extends MockedTest ->at($this->root->getChild('config')) ->setContent('root->url(), $this->root->url() . DIRECTORY_SEPARATOR . Config::CONFIG_DIR, $this->root->url() . DIRECTORY_SEPARATOR . Config::STATIC_DIR ); - $configCache = new \Friendica\Core\Config\ValueObject\Cache(); + $configCache = new Cache(); $configFileLoader->setupCache($configCache); } @@ -101,12 +101,12 @@ class ConfigFileLoaderTest extends MockedTest ->at($this->root->getChild('config')) ->setContent(file_get_contents($file)); - $configFileLoader = new ConfigFileLoader( + $configFileLoader = new ConfigFileManager( $this->root->url(), $this->root->url() . DIRECTORY_SEPARATOR . Config::CONFIG_DIR, $this->root->url() . DIRECTORY_SEPARATOR . Config::STATIC_DIR ); - $configCache = new \Friendica\Core\Config\ValueObject\Cache(); + $configCache = new Cache(); $configFileLoader->setupCache($configCache); @@ -138,12 +138,12 @@ class ConfigFileLoaderTest extends MockedTest ->at($this->root->getChild('config')) ->setContent(file_get_contents($file)); - $configFileLoader = new ConfigFileLoader( + $configFileLoader = new ConfigFileManager( $this->root->url(), $this->root->url() . DIRECTORY_SEPARATOR . Config::CONFIG_DIR, $this->root->url() . DIRECTORY_SEPARATOR . Config::STATIC_DIR ); - $configCache = new \Friendica\Core\Config\ValueObject\Cache(); + $configCache = new Cache(); $configFileLoader->setupCache($configCache); @@ -174,12 +174,12 @@ class ConfigFileLoaderTest extends MockedTest ->at($this->root) ->setContent(file_get_contents($file)); - $configFileLoader = new ConfigFileLoader( + $configFileLoader = new ConfigFileManager( $this->root->url(), $this->root->url() . DIRECTORY_SEPARATOR . Config::CONFIG_DIR, $this->root->url() . DIRECTORY_SEPARATOR . Config::STATIC_DIR ); - $configCache = new \Friendica\Core\Config\ValueObject\Cache(); + $configCache = new Cache(); $configFileLoader->setupCache($configCache); @@ -228,7 +228,7 @@ class ConfigFileLoaderTest extends MockedTest ->at($this->root->getChild('addon')->getChild('test')->getChild('config')) ->setContent(file_get_contents($file)); - $configFileLoader = new ConfigFileLoader( + $configFileLoader = new ConfigFileManager( $this->root->url(), $this->root->url() . DIRECTORY_SEPARATOR . Config::CONFIG_DIR, $this->root->url() . DIRECTORY_SEPARATOR . Config::STATIC_DIR @@ -265,12 +265,12 @@ class ConfigFileLoaderTest extends MockedTest ->at($this->root->getChild('config')) ->setContent(file_get_contents($fileDir . 'B.config.php')); - $configFileLoader = new ConfigFileLoader( + $configFileLoader = new ConfigFileManager( $this->root->url(), $this->root->url() . DIRECTORY_SEPARATOR . Config::CONFIG_DIR, $this->root->url() . DIRECTORY_SEPARATOR . Config::STATIC_DIR ); - $configCache = new \Friendica\Core\Config\ValueObject\Cache(); + $configCache = new Cache(); $configFileLoader->setupCache($configCache); @@ -299,12 +299,12 @@ class ConfigFileLoaderTest extends MockedTest ->at($this->root->getChild('config')) ->setContent(file_get_contents($fileDir . 'B.ini.php')); - $configFileLoader = new ConfigFileLoader( + $configFileLoader = new ConfigFileManager( $this->root->url(), $this->root->url() . DIRECTORY_SEPARATOR . Config::CONFIG_DIR, $this->root->url() . DIRECTORY_SEPARATOR . Config::STATIC_DIR ); - $configCache = new \Friendica\Core\Config\ValueObject\Cache(); + $configCache = new Cache(); $configFileLoader->setupCache($configCache); @@ -333,12 +333,12 @@ class ConfigFileLoaderTest extends MockedTest ->at($this->root->getChild('config')) ->setContent(file_get_contents($fileDir . 'B.ini.php')); - $configFileLoader = new ConfigFileLoader( + $configFileLoader = new ConfigFileManager( $this->root->url(), $this->root->url() . DIRECTORY_SEPARATOR . Config::CONFIG_DIR, $this->root->url() . DIRECTORY_SEPARATOR . Config::STATIC_DIR ); - $configCache = new \Friendica\Core\Config\ValueObject\Cache(); + $configCache = new Cache(); $configFileLoader->setupCache($configCache); @@ -354,7 +354,7 @@ class ConfigFileLoaderTest extends MockedTest $this->delConfigFile('local.config.php'); $configFileLoader = (new Config())->createConfigFileLoader($this->root->url(), ['FRIENDICA_CONFIG_DIR' => '/a/wrong/dir/']); - $configCache = new \Friendica\Core\Config\ValueObject\Cache(); + $configCache = new Cache(); $configFileLoader->setupCache($configCache); @@ -380,10 +380,57 @@ class ConfigFileLoaderTest extends MockedTest ->setContent(file_get_contents($fileDir . 'B.config.php')); $configFileLoader = (new Config())->createConfigFileLoader($this->root->url(), ['FRIENDICA_CONFIG_DIR' => $this->root->getChild('config2')->url()]); - $configCache = new \Friendica\Core\Config\ValueObject\Cache(); + $configCache = new Cache(); $configFileLoader->setupCache($configCache); self::assertEquals('newValue', $configCache->get('system', 'newKey')); } + + public function testSaveData() + { + $this->delConfigFile('local.config.php'); + + $fileDir = dirname(__DIR__) . DIRECTORY_SEPARATOR . + '..' . DIRECTORY_SEPARATOR . + '..' . DIRECTORY_SEPARATOR . + '..' . DIRECTORY_SEPARATOR . + 'datasets' . DIRECTORY_SEPARATOR . + 'config' . DIRECTORY_SEPARATOR; + + vfsStream::newFile('B.config.php') + ->at($this->root->getChild('config2')) + ->setContent(file_get_contents($fileDir . 'B.config.php')); + + $configFileLoader = (new Config())->createConfigFileLoader($this->root->url(), ['FRIENDICA_CONFIG_DIR' => $this->root->getChild('config2')->url()]); + $configCache = new Cache(); + + $configFileLoader->setupCache($configCache); + + $specialChars = '!"§$%&/()(/&%$\'>set('system', 'test', 'it', Cache::SOURCE_DATA); + $configCache->set('config', 'test', 'it', Cache::SOURCE_DATA); + $configCache->set('system', 'test_2', 2, Cache::SOURCE_DATA); + $configCache->set('special_chars', 'special', $specialChars, Cache::SOURCE_DATA); + $configFileLoader->saveData($configCache); + + // Reload the configCache with the new values + $configCache2 = new Cache(); + $configFileLoader->setupCache($configCache2); + + self::assertEquals($configCache, $configCache2); + self::assertEquals([ + 'system' => [ + 'test' => 'it', + 'test_2' => 2 + ], + 'config' => [ + 'test' => 'it', + ], + 'special_chars' => [ + 'special' => $specialChars, + ]], $configCache2->getDataBySource(Cache::SOURCE_DATA)); + } } diff --git a/tests/src/Core/Config/ConfigTest.php b/tests/src/Core/Config/ConfigTest.php index bdcba724e..c85cf3f70 100644 --- a/tests/src/Core/Config/ConfigTest.php +++ b/tests/src/Core/Config/ConfigTest.php @@ -23,22 +23,25 @@ namespace Friendica\Test\src\Core\Config; use DMS\PHPUnitExtensions\ArraySubset\ArraySubsetAsserts; use Friendica\Core\Config\Capability\IManageConfigValues; -use Friendica\Core\Config\Repository\Config as ConfigModel; +use Friendica\Core\Config\Model\Config; +use Friendica\Core\Config\Util\ConfigFileManager; +use Friendica\Core\Config\Util\ConfigFileTransformer; use Friendica\Core\Config\ValueObject\Cache; use Friendica\Test\MockedTest; -use Mockery\MockInterface; -use Mockery; +use Friendica\Test\Util\VFSTrait; +use org\bovigo\vfs\vfsStream; -abstract class ConfigTest extends MockedTest +class ConfigTest extends MockedTest { use ArraySubsetAsserts; - - /** @var ConfigModel|MockInterface */ - protected $configModel; + use VFSTrait; /** @var Cache */ protected $configCache; + /** @var ConfigFileManager */ + protected $configFileManager; + /** @var IManageConfigValues */ protected $testedConfig; @@ -60,17 +63,22 @@ abstract class ConfigTest extends MockedTest protected function setUp(): void { + $this->setUpVfsDir(); + parent::setUp(); - // Create the config model - $this->configModel = Mockery::mock(ConfigModel::class); $this->configCache = new Cache(); + $this->configFileManager = new ConfigFileManager($this->root->url(), $this->root->url() . '/config/', $this->root->url() . '/static/'); } /** * @return IManageConfigValues */ - abstract public function getInstance(); + public function getInstance() + { + $this->configFileManager->setupCache($this->configCache, []); + return new Config($this->configFileManager, $this->configCache); + } public function dataTests() { @@ -156,12 +164,13 @@ abstract class ConfigTest extends MockedTest /** * Test the configuration initialization + * @dataProvider dataConfigLoad */ public function testSetUp(array $data) { - $this->configModel->shouldReceive('isConnected') - ->andReturn(true) - ->once(); + vfsStream::newFile(ConfigFileManager::CONFIG_DATA_FILE) + ->at($this->root->getChild('config')) + ->setContent(ConfigFileTransformer::encode($data)); $this->testedConfig = $this->getInstance(); self::assertInstanceOf(Cache::class, $this->testedConfig->getCache()); @@ -171,19 +180,23 @@ abstract class ConfigTest extends MockedTest } /** - * Test the configuration load() method + * Test the configuration reload() method * * @param array $data * @param array $load + * + * @dataProvider dataConfigLoad */ - public function testLoad(array $data, array $load) + public function testReload(array $data, array $load) { + vfsStream::newFile(ConfigFileManager::CONFIG_DATA_FILE) + ->at($this->root->getChild('config')) + ->setContent(ConfigFileTransformer::encode($data)); + $this->testedConfig = $this->getInstance(); self::assertInstanceOf(Cache::class, $this->testedConfig->getCache()); - foreach ($load as $loadedCats) { - $this->testedConfig->load($loadedCats); - } + $this->testedConfig->reload(); // Assert at least loaded cats are loaded foreach ($load as $loadedCats) { @@ -256,23 +269,31 @@ abstract class ConfigTest extends MockedTest /** * Test the configuration load() method with overwrite + * + * @dataProvider dataDoubleLoad */ public function testCacheLoadDouble(array $data1, array $data2, array $expect = []) { + vfsStream::newFile(ConfigFileManager::CONFIG_DATA_FILE) + ->at($this->root->getChild('config')) + ->setContent(ConfigFileTransformer::encode($data1)); + $this->testedConfig = $this->getInstance(); self::assertInstanceOf(Cache::class, $this->testedConfig->getCache()); - foreach ($data1 as $cat => $data) { - $this->testedConfig->load($cat); - } - // Assert at least loaded cats are loaded foreach ($data1 as $cat => $data) { self::assertConfig($cat, $data); } + vfsStream::newFile(ConfigFileManager::CONFIG_DATA_FILE) + ->at($this->root->getChild('config')) + ->setContent(ConfigFileTransformer::encode($data2)); + + $this->testedConfig->reload(); + foreach ($data2 as $cat => $data) { - $this->testedConfig->load($cat); + self::assertConfig($cat, $data); } } @@ -281,44 +302,19 @@ abstract class ConfigTest extends MockedTest */ public function testLoadWrong() { - $this->configModel->shouldReceive('isConnected')->andReturn(true)->once(); - $this->configModel->shouldReceive('load')->withAnyArgs()->andReturn([])->once(); - - $this->testedConfig = $this->getInstance(); + $this->testedConfig = new Config($this->configFileManager, new Cache()); self::assertInstanceOf(Cache::class, $this->testedConfig->getCache()); self::assertEmpty($this->testedConfig->getCache()->getAll()); } /** - * Test the configuration get() and set() methods without adapter + * Test the configuration get() and set() methods * * @dataProvider dataTests */ - public function testSetGetWithoutDB($data) + public function testSetGet($data) { - $this->configModel->shouldReceive('isConnected') - ->andReturn(false) - ->times(3); - - $this->testedConfig = $this->getInstance(); - self::assertInstanceOf(Cache::class, $this->testedConfig->getCache()); - - self::assertTrue($this->testedConfig->set('test', 'it', $data)); - - self::assertEquals($data, $this->testedConfig->get('test', 'it')); - self::assertEquals($data, $this->testedConfig->getCache()->get('test', 'it')); - } - - /** - * Test the configuration get() and set() methods with a model/db - * - * @dataProvider dataTests - */ - public function testSetGetWithDB($data) - { - $this->configModel->shouldReceive('set')->with('test', 'it', $data)->andReturn(true)->once(); - $this->testedConfig = $this->getInstance(); self::assertInstanceOf(Cache::class, $this->testedConfig->getCache()); @@ -349,41 +345,16 @@ abstract class ConfigTest extends MockedTest self::assertEquals('default', $this->testedConfig->get('test', 'it', 'default', true)); } - /** - * Test the configuration get() method with refresh - * - * @dataProvider dataTests - */ - public function testGetWithRefresh($data) - { - $this->configCache->load(['test' => ['it' => 'now']], Cache::SOURCE_FILE); - - $this->testedConfig = $this->getInstance(); - self::assertInstanceOf(Cache::class, $this->testedConfig->getCache()); - - // without refresh - self::assertEquals('now', $this->testedConfig->get('test', 'it')); - self::assertEquals('now', $this->testedConfig->getCache()->get('test', 'it')); - - // with refresh - self::assertEquals($data, $this->testedConfig->get('test', 'it', null, true)); - self::assertEquals($data, $this->testedConfig->getCache()->get('test', 'it')); - - // without refresh and wrong value and default - self::assertEquals('default', $this->testedConfig->get('test', 'not', 'default')); - self::assertNull($this->testedConfig->getCache()->get('test', 'not')); - } - /** * Test the configuration delete() method without a model/db * * @dataProvider dataTests */ - public function testDeleteWithoutDB($data) + public function testDelete($data) { $this->configCache->load(['test' => ['it' => $data]], Cache::SOURCE_FILE); - $this->testedConfig = $this->getInstance(); + $this->testedConfig = new Config($this->configFileManager, $this->configCache); self::assertInstanceOf(Cache::class, $this->testedConfig->getCache()); self::assertEquals($data, $this->testedConfig->get('test', 'it')); @@ -396,51 +367,6 @@ abstract class ConfigTest extends MockedTest self::assertEmpty($this->testedConfig->getCache()->getAll()); } - /** - * Test the configuration delete() method with a model/db - */ - public function testDeleteWithDB() - { - $this->configCache->load(['test' => ['it' => 'now', 'quarter' => 'true']], Cache::SOURCE_FILE); - - $this->configModel->shouldReceive('delete') - ->with('test', 'it') - ->andReturn(false) - ->once(); - $this->configModel->shouldReceive('delete') - ->with('test', 'second') - ->andReturn(true) - ->once(); - $this->configModel->shouldReceive('delete') - ->with('test', 'third') - ->andReturn(false) - ->once(); - $this->configModel->shouldReceive('delete') - ->with('test', 'quarter') - ->andReturn(true) - ->once(); - - $this->testedConfig = $this->getInstance(); - self::assertInstanceOf(Cache::class, $this->testedConfig->getCache()); - - // directly set the value to the cache - $this->testedConfig->getCache()->set('test', 'it', 'now'); - - self::assertEquals('now', $this->testedConfig->get('test', 'it')); - self::assertEquals('now', $this->testedConfig->getCache()->get('test', 'it')); - - // delete from cache only - self::assertTrue($this->testedConfig->delete('test', 'it')); - // delete from db only - self::assertTrue($this->testedConfig->delete('test', 'second')); - // no delete - self::assertFalse($this->testedConfig->delete('test', 'third')); - // delete both - self::assertTrue($this->testedConfig->delete('test', 'quarter')); - - self::assertEmpty($this->testedConfig->getCache()->getAll()); - } - /** * Test the configuration get() and set() method where the db value has a higher prio than the config file */ @@ -462,6 +388,12 @@ abstract class ConfigTest extends MockedTest */ public function testSetGetLowPrio() { + vfsStream::newFile(ConfigFileManager::CONFIG_DATA_FILE) + ->at($this->root->getChild('config')) + ->setContent(ConfigFileTransformer::encode([ + 'config' => ['test' => 'it'], + ])); + $this->testedConfig = $this->getInstance(); self::assertInstanceOf(Cache::class, $this->testedConfig->getCache()); self::assertEquals('it', $this->testedConfig->get('config', 'test')); diff --git a/tests/src/Core/Config/ConfigTransactionTest.php b/tests/src/Core/Config/ConfigTransactionTest.php new file mode 100644 index 000000000..2eec9b68f --- /dev/null +++ b/tests/src/Core/Config/ConfigTransactionTest.php @@ -0,0 +1,111 @@ +setUpVfsDir(); + + $this->configFileManager = new ConfigFileManager($this->root->url(), $this->root->url() . '/config/', $this->root->url() . '/static/'); + } + + public function dataTests(): array + { + return [ + 'default' => [ + 'data' => include dirname(__FILE__, 4) . '/datasets/B.node.config.php', + ] + ]; + } + + public function testInstance() + { + $config = new Config($this->configFileManager, new Cache()); + $configTransaction = new ConfigTransaction($config); + + self::assertInstanceOf(ISetConfigValuesTransactionally::class, $configTransaction); + self::assertInstanceOf(ConfigTransaction::class, $configTransaction); + } + + public function testConfigTransaction() + { + $config = new Config($this->configFileManager, new Cache()); + $config->set('config', 'key1', 'value1'); + $config->set('system', 'key2', 'value2'); + $config->set('system', 'keyDel', 'valueDel'); + $config->set('delete', 'keyDel', 'catDel'); + + $configTransaction = new ConfigTransaction($config); + self::assertEquals('value1', $configTransaction->get('config', 'key1')); + self::assertEquals('value2', $configTransaction->get('system', 'key2')); + self::assertEquals('valueDel', $configTransaction->get('system', 'keyDel')); + self::assertEquals('catDel', $configTransaction->get('delete', 'keyDel')); + // the config file knows it as well immediately + $tempData = include $this->root->url() . '/config/' . ConfigFileManager::CONFIG_DATA_FILE; + self::assertEquals('value1', $tempData['config']['key1'] ?? null); + self::assertEquals('value2', $tempData['system']['key2'] ?? null); + + // new key-value + $configTransaction->set('transaction', 'key3', 'value3'); + // overwrite key-value + $configTransaction->set('config', 'key1', 'changedValue1'); + // delete key-value + $configTransaction->delete('system', 'keyDel'); + // delete last key of category - so the category is gone + $configTransaction->delete('delete', 'keyDel'); + + // The main config still doesn't know about the change + self::assertNull($config->get('transaction', 'key3')); + self::assertEquals('value1', $config->get('config', 'key1')); + self::assertEquals('valueDel', $config->get('system', 'keyDel')); + self::assertEquals('catDel', $config->get('delete', 'keyDel')); + // but the transaction config of course knows it + self::assertEquals('value3', $configTransaction->get('transaction', 'key3')); + self::assertEquals('changedValue1', $configTransaction->get('config', 'key1')); + self::assertNull($configTransaction->get('system', 'keyDel')); + self::assertNull($configTransaction->get('delete', 'keyDel')); + // The config file still doesn't know it either + $tempData = include $this->root->url() . '/config/' . ConfigFileManager::CONFIG_DATA_FILE; + self::assertEquals('value1', $tempData['config']['key1'] ?? null); + self::assertEquals('value2', $tempData['system']['key2'] ?? null); + self::assertEquals('catDel', $tempData['delete']['keyDel'] ?? null); + self::assertNull($tempData['transaction']['key3'] ?? null); + + // save it back! + $configTransaction->commit(); + + // Now every config and file knows the change + self::assertEquals('changedValue1', $config->get('config', 'key1')); + self::assertEquals('value3', $config->get('transaction', 'key3')); + self::assertNull($config->get('system', 'keyDel')); + self::assertNull($config->get('delete', 'keyDel')); + self::assertEquals('value3', $configTransaction->get('transaction', 'key3')); + self::assertEquals('changedValue1', $configTransaction->get('config', 'key1')); + self::assertNull($configTransaction->get('system', 'keyDel')); + $tempData = include $this->root->url() . '/config/' . ConfigFileManager::CONFIG_DATA_FILE; + self::assertEquals('changedValue1', $tempData['config']['key1'] ?? null); + self::assertEquals('value2', $tempData['system']['key2'] ?? null); + self::assertEquals('value3', $tempData['transaction']['key3'] ?? null); + self::assertNull($tempData['system']['keyDel'] ?? null); + self::assertNull($tempData['delete']['keyDel'] ?? null); + // the whole category should be gone + self::assertNull($tempData['delete'] ?? null); + } +} diff --git a/tests/src/Core/Config/JitConfigTest.php b/tests/src/Core/Config/JitConfigTest.php deleted file mode 100644 index a468ae727..000000000 --- a/tests/src/Core/Config/JitConfigTest.php +++ /dev/null @@ -1,255 +0,0 @@ -. - * - */ - -namespace Friendica\Test\src\Core\Config; - -use Friendica\Core\Config\Type\JitConfig; - -class JitConfigTest extends ConfigTest -{ - public function getInstance() - { - return new JitConfig($this->configCache, $this->configModel); - } - - /** - * @dataProvider dataConfigLoad - */ - public function testSetUp(array $data) - { - $this->configModel->shouldReceive('load') - ->with('config') - ->andReturn(['config' => $data['config']]) - ->once(); - - parent::testSetUp($data); - } - - /** - * @dataProvider dataConfigLoad - * - * @param array $data - * @param array $load - */ - public function testLoad(array $data, array $load) - { - $this->configModel->shouldReceive('isConnected') - ->andReturn(true) - ->times(count($load) + 1); - - $this->configModel->shouldReceive('load') - ->with('config') - ->andReturn(['config' => $data['config']]) - ->once(); - - foreach ($load as $loadCat) { - $this->configModel->shouldReceive('load') - ->with($loadCat) - ->andReturn([$loadCat => $data[$loadCat]]) - ->once(); - } - - parent::testLoad($data, $load); - } - - /** - * @dataProvider dataDoubleLoad - */ - public function testCacheLoadDouble(array $data1, array $data2, array $expect = []) - { - $this->configModel->shouldReceive('isConnected') - ->andReturn(true) - ->times(count($data1) + count($data2) + 1); - - $this->configModel->shouldReceive('load') - ->with('config') - ->andReturn(['config' => $data1['config']]) - ->once(); - - foreach ($data1 as $cat => $data) { - $this->configModel->shouldReceive('load') - ->with($cat) - ->andReturn([$cat => $data]) - ->once(); - } - - - foreach ($data2 as $cat => $data) { - $this->configModel->shouldReceive('load') - ->with($cat) - ->andReturn([$cat => $data]) - ->once(); - } - - parent::testCacheLoadDouble($data1, $data2); - - // Assert the expected categories - foreach ($data2 as $cat => $data) { - self::assertConfig($cat, $expect[$cat]); - } - } - - /** - * @dataProvider dataTests - */ - public function testSetGetWithDB($data) - { - $this->configModel->shouldReceive('isConnected') - ->andReturn(true) - ->times(3); - - $this->configModel->shouldReceive('load')->with('config')->andReturn(['config' => []])->once(); - - parent::testSetGetWithDB($data); - } - - /** - * @dataProvider dataTests - */ - public function testGetWithRefresh($data) - { - $this->configModel->shouldReceive('isConnected') - ->andReturn(true) - ->times(4); - - // constructor loading - $this->configModel->shouldReceive('load') - ->with('config') - ->andReturn(['config' => []]) - ->once(); - - // mocking one get without result - $this->configModel->shouldReceive('get') - ->with('test', 'it') - ->andReturn(null) - ->once(); - - // mocking the data get - $this->configModel->shouldReceive('get') - ->with('test', 'it') - ->andReturn($data) - ->once(); - - // mocking second get - $this->configModel->shouldReceive('get') - ->with('test', 'not') - ->andReturn(null) - ->once(); - - parent::testGetWithRefresh($data); - } - - public function testGetWrongWithoutDB() - { - $this->configModel->shouldReceive('isConnected') - ->andReturn(false) - ->times(4); - - parent::testGetWrongWithoutDB(); - } - - /** - * @dataProvider dataTests - */ - public function testDeleteWithoutDB($data) - { - $this->configModel->shouldReceive('isConnected') - ->andReturn(false) - ->times(4); - - parent::testDeleteWithoutDB($data); - } - - public function testDeleteWithDB() - { - $this->configModel->shouldReceive('isConnected') - ->andReturn(true) - ->times(6); - - // constructor loading - $this->configModel->shouldReceive('load') - ->with('config') - ->andReturn(['config' => []]) - ->once(); - - // mocking one get without result - $this->configModel->shouldReceive('get') - ->with('test', 'it') - ->andReturn(null) - ->once(); - - parent::testDeleteWithDB(); - } - - public function testSetGetHighPrio() - { - $this->configModel->shouldReceive('isConnected') - ->andReturn(true); - - // constructor loading - $this->configModel->shouldReceive('load') - ->with('config') - ->andReturn(['config' => []]) - ->once(); - - $this->configModel->shouldReceive('get') - ->with('config', 'test') - ->andReturn('prio') - ->once(); - - $this->configModel->shouldReceive('set') - ->with('config', 'test', '123') - ->andReturn(true) - ->once(); - - $this->configModel->shouldReceive('get') - ->with('config', 'test') - ->andReturn('123') - ->once(); - - parent::testSetGetHighPrio(); - } - - public function testSetGetLowPrio() - { - $this->configModel->shouldReceive('isConnected') - ->andReturn(true); - - // constructor loading - $this->configModel->shouldReceive('load') - ->with('config') - ->andReturn(['config' => ['test' => 'it']]) - ->once(); - - $this->configModel->shouldReceive('set') - ->with('config', 'test', '123') - ->andReturn(true) - ->once(); - - // mocking one get without result - $this->configModel->shouldReceive('get') - ->with('config', 'test') - ->andReturn('it') - ->once(); - - parent::testSetGetLowPrio(); - } -} diff --git a/tests/src/Core/Config/PreloadConfigTest.php b/tests/src/Core/Config/PreloadConfigTest.php deleted file mode 100644 index 1f5142761..000000000 --- a/tests/src/Core/Config/PreloadConfigTest.php +++ /dev/null @@ -1,213 +0,0 @@ -. - * - */ - -namespace Friendica\Test\src\Core\Config; - -use Friendica\Core\Config\Type\PreloadConfig; - -class PreloadConfigTest extends ConfigTest -{ - public function getInstance() - { - return new PreloadConfig($this->configCache, $this->configModel); - } - - /** - * @dataProvider dataConfigLoad - */ - public function testSetUp(array $data) - { - $this->configModel->shouldReceive('load') - ->andReturn($data) - ->once(); - - parent::testSetUp($data); - } - - /** - * @dataProvider dataConfigLoad - * - * @param array $data - * @param array $load - */ - public function testLoad(array $data, array $load) - { - $this->configModel->shouldReceive('isConnected') - ->andReturn(true) - ->once(); - - $this->configModel->shouldReceive('load') - ->andReturn($data) - ->once(); - - parent::testLoad($data, $load); - - // Assert that every category is loaded everytime - foreach ($data as $cat => $values) { - self::assertConfig($cat, $values); - } - } - - /** - * @dataProvider dataDoubleLoad - * - * @param array $data1 - * @param array $data2 - */ - public function testCacheLoadDouble(array $data1, array $data2, array $expect = []) - { - $this->configModel->shouldReceive('isConnected') - ->andReturn(true) - ->once(); - - $this->configModel->shouldReceive('load') - ->andReturn($data1) - ->once(); - - parent::testCacheLoadDouble($data1, $data2); - - // Assert that every category is loaded everytime and is NOT overwritten - foreach ($data1 as $cat => $values) { - self::assertConfig($cat, $values); - } - } - - /** - * @dataProvider dataTests - */ - public function testSetGetWithDB($data) - { - $this->configModel->shouldReceive('isConnected') - ->andReturn(true) - ->times(2); - - $this->configModel->shouldReceive('load')->andReturn(['config' => []])->once(); - - parent::testSetGetWithDB($data); - } - - /** - * @dataProvider dataTests - */ - public function testGetWithRefresh($data) - { - $this->configModel->shouldReceive('isConnected') - ->andReturn(true) - ->times(2); - - // constructor loading - $this->configModel->shouldReceive('load') - ->andReturn(['config' => []]) - ->once(); - - // mocking one get - $this->configModel->shouldReceive('get') - ->with('test', 'it') - ->andReturn($data) - ->once(); - - parent::testGetWithRefresh($data); - } - - - public function testGetWrongWithoutDB() - { - $this->configModel->shouldReceive('isConnected') - ->andReturn(false) - ->times(2); - - parent::testGetWrongWithoutDB(); - } - - /** - * @dataProvider dataTests - */ - public function testDeleteWithoutDB($data) - { - $this->configModel->shouldReceive('isConnected') - ->andReturn(false) - ->times(2); - - parent::testDeleteWithoutDB($data); - } - - public function testDeleteWithDB() - { - $this->configModel->shouldReceive('isConnected') - ->andReturn(true) - ->times(5); - - // constructor loading - $this->configModel->shouldReceive('load') - ->andReturn(['config' => []]) - ->once(); - - parent::testDeleteWithDB(); - } - - - public function testSetGetHighPrio() - { - $this->configModel->shouldReceive('isConnected') - ->andReturn(true); - - // constructor loading - $this->configModel->shouldReceive('load') - ->andReturn(['config' => []]) - ->once(); - - $this->configModel->shouldReceive('set') - ->with('config', 'test', '123') - ->andReturn(true) - ->once(); - - $this->configModel->shouldReceive('get') - ->with('config', 'test') - ->andReturn('123') - ->once(); - - parent::testSetGetHighPrio(); - } - - public function testSetGetLowPrio() - { - $this->configModel->shouldReceive('isConnected') - ->andReturn(true); - - // constructor loading - $this->configModel->shouldReceive('load') - ->andReturn(['config' => ['test' => 'it']]) - ->once(); - - $this->configModel->shouldReceive('set') - ->with('config', 'test', '123') - ->andReturn(true) - ->once(); - - // mocking one get without result - $this->configModel->shouldReceive('get') - ->with('config', 'test') - ->andReturn('it') - ->once(); - - parent::testSetGetLowPrio(); - } -} diff --git a/tests/src/Core/Config/Util/ConfigFileTransformerTest.php b/tests/src/Core/Config/Util/ConfigFileTransformerTest.php new file mode 100644 index 000000000..5a0ab96a4 --- /dev/null +++ b/tests/src/Core/Config/Util/ConfigFileTransformerTest.php @@ -0,0 +1,57 @@ +. + * + */ + +namespace Friendica\Test\src\Core\Config\Util; + +use Friendica\Core\Config\Util\ConfigFileTransformer; +use Friendica\Test\MockedTest; + +class ConfigFileTransformerTest extends MockedTest +{ + public function dataTests() + { + return [ + 'default' => [ + 'configFile' => (dirname(__DIR__, 4) . '/datasets/config/A.node.config.php'), + ], + 'extended' => [ + 'configFile' => (dirname(__DIR__, 4) . '/datasets/config/B.node.config.php'), + ], + 'friendica.local' => [ + 'configFile' => (dirname(__DIR__, 4) . '/datasets/config/C.node.config.php'), + ], + ]; + } + + /** + * Tests if the given config will be decoded into an array and encoded into the same string again + * + * @dataProvider dataTests + */ + public function testConfigFile(string $configFile) + { + $dataArray = include $configFile; + + $newConfig = ConfigFileTransformer::encode($dataArray); + + self::assertEquals(file_get_contents($configFile), $newConfig); + } +} diff --git a/tests/src/Core/Lock/SemaphoreLockTest.php b/tests/src/Core/Lock/SemaphoreLockTest.php index a8f95f6fc..6473935ca 100644 --- a/tests/src/Core/Lock/SemaphoreLockTest.php +++ b/tests/src/Core/Lock/SemaphoreLockTest.php @@ -24,7 +24,10 @@ namespace Friendica\Test\src\Core\Lock; use Dice\Dice; use Friendica\App; use Friendica\Core\Config\Capability\IManageConfigValues; +use Friendica\Core\Config\Model\Config; use Friendica\Core\Config\Type\JitConfig; +use Friendica\Core\Config\Util\ConfigFileManager; +use Friendica\Core\Config\ValueObject\Cache; use Friendica\Core\Lock\Type\SemaphoreLock; use Friendica\Core\System; use Friendica\DI; @@ -42,11 +45,8 @@ class SemaphoreLockTest extends LockTest $app->shouldReceive('getHostname')->andReturn('friendica.local'); $dice->shouldReceive('create')->with(App::class)->andReturn($app); - $configMock = Mockery::mock(JitConfig::class); - $configMock - ->shouldReceive('get') - ->with('system', 'temppath') - ->andReturn('/tmp/'); + $configCache = new Cache(['system' => ['temppath' => '/tmp']]); + $configMock = new Config(Mockery::mock(ConfigFileManager::class), $configCache); $dice->shouldReceive('create')->with(IManageConfigValues::class)->andReturn($configMock); // @todo Because "get_temppath()" is using static methods, we have to initialize the BaseObject diff --git a/tests/src/Core/Storage/Repository/StorageManagerTest.php b/tests/src/Core/Storage/Repository/StorageManagerTest.php index af198706f..db4ca8ef2 100644 --- a/tests/src/Core/Storage/Repository/StorageManagerTest.php +++ b/tests/src/Core/Storage/Repository/StorageManagerTest.php @@ -22,9 +22,7 @@ namespace Friendica\Test\src\Core\Storage\Repository; use Dice\Dice; -use Friendica\App\Mode; use Friendica\Core\Config\Capability\IManageConfigValues; -use Friendica\Core\Config\Type\PreloadConfig; use Friendica\Core\Hook; use Friendica\Core\L10n; use Friendica\Core\Session\Capability\IHandleSessions; @@ -41,7 +39,6 @@ use Friendica\Database\Definition\DbaDefinition; use Friendica\Database\Definition\ViewDefinition; use Friendica\DI; use Friendica\Core\Config\Factory\Config; -use Friendica\Core\Config\Repository; use Friendica\Core\Storage\Type; use Friendica\Test\DatabaseTest; use Friendica\Test\Util\Database\StaticDatabase; @@ -89,8 +86,7 @@ class StorageManagerTest extends DatabaseTest $this->dba = new StaticDatabase($configCache, $profiler, $dbaDefinition, $viewDefinition); - $configModel = new Repository\Config($this->dba, new Mode(Mode::DBCONFIGAVAILABLE)); - $this->config = new PreloadConfig($configCache, $configModel); + $this->config = new \Friendica\Core\Config\Model\Config($loader, $configCache); $this->config->set('storage', 'name', 'Database'); $this->config->set('storage', 'filesystem_path', $this->root->getChild(Type\FilesystemConfig::DEFAULT_BASE_FOLDER)->url()); diff --git a/tests/src/Database/DBATest.php b/tests/src/Database/DBATest.php index 44a6e01d3..0c3c5e160 100644 --- a/tests/src/Database/DBATest.php +++ b/tests/src/Database/DBATest.php @@ -52,10 +52,7 @@ class DBATest extends DatabaseTest */ public function testExists() { - self::assertTrue(DBA::exists('config', [])); + self::assertTrue(DBA::exists('user', [])); self::assertFalse(DBA::exists('notable', [])); - - self::assertTrue(DBA::exists('config', ['k' => 'hostname'])); - self::assertFalse(DBA::exists('config', ['k' => 'nonsense'])); } } diff --git a/tests/src/Database/DBStructureTest.php b/tests/src/Database/DBStructureTest.php index 67455f851..dfb46514f 100644 --- a/tests/src/Database/DBStructureTest.php +++ b/tests/src/Database/DBStructureTest.php @@ -44,30 +44,30 @@ class DBStructureTest extends DatabaseTest * @small */ public function testExists() { - self::assertTrue(DBStructure::existsTable('config')); + self::assertTrue(DBStructure::existsTable('user')); self::assertFalse(DBStructure::existsTable('notatable')); - self::assertTrue(DBStructure::existsColumn('config', ['k'])); - self::assertFalse(DBStructure::existsColumn('config', ['nonsense'])); - self::assertFalse(DBStructure::existsColumn('config', ['k', 'nonsense'])); + self::assertTrue(DBStructure::existsColumn('user', ['uid'])); + self::assertFalse(DBStructure::existsColumn('user', ['nonsense'])); + self::assertFalse(DBStructure::existsColumn('user', ['uid', 'nonsense'])); } /** * @small */ public function testRename() { - $fromColumn = 'k'; - $toColumn = 'key'; - $fromType = 'varbinary(255) not null'; - $toType = 'varbinary(255) not null comment \'Test To Type\''; + $fromColumn = 'email'; + $toColumn = 'email_key'; + $fromType = 'varchar(255) NOT NULL DEFAULT \'\' COMMENT \'the users email address\''; + $toType = 'varchar(255) NOT NULL DEFAULT \'\' COMMENT \'Adapted column\''; - self::assertTrue(DBStructure::rename('config', [ $fromColumn => [ $toColumn, $toType ]])); - self::assertTrue(DBStructure::existsColumn('config', [ $toColumn ])); - self::assertFalse(DBStructure::existsColumn('config', [ $fromColumn ])); + self::assertTrue(DBStructure::rename('user', [ $fromColumn => [ $toColumn, $toType ]])); + self::assertTrue(DBStructure::existsColumn('user', [ $toColumn ])); + self::assertFalse(DBStructure::existsColumn('user', [ $fromColumn ])); - self::assertTrue(DBStructure::rename('config', [ $toColumn => [ $fromColumn, $fromType ]])); - self::assertTrue(DBStructure::existsColumn('config', [ $fromColumn ])); - self::assertFalse(DBStructure::existsColumn('config', [ $toColumn ])); + self::assertTrue(DBStructure::rename('user', [ $toColumn => [ $fromColumn, $fromType ]])); + self::assertTrue(DBStructure::existsColumn('user', [ $fromColumn ])); + self::assertFalse(DBStructure::existsColumn('user', [ $toColumn ])); } /** diff --git a/tests/src/Module/Api/GnuSocial/GnuSocial/ConfigTest.php b/tests/src/Module/Api/GnuSocial/GnuSocial/ConfigTest.php index 034e1fc99..0d0afa64b 100644 --- a/tests/src/Module/Api/GnuSocial/GnuSocial/ConfigTest.php +++ b/tests/src/Module/Api/GnuSocial/GnuSocial/ConfigTest.php @@ -26,6 +26,7 @@ use Friendica\App\Router; use Friendica\DI; use Friendica\Module\Api\GNUSocial\GNUSocial\Config; use Friendica\Test\src\Module\Api\ApiTest; +use Friendica\Test\Util\VFSTrait; class ConfigTest extends ApiTest { diff --git a/update.php b/update.php index 356877ff9..1dbf78e06 100644 --- a/update.php +++ b/update.php @@ -1148,6 +1148,10 @@ function update_1502() function update_1505() { + if (!DBStructure::existsTable('config')) { + return Update::SUCCESS; + } + $conditions = [ "((`cat` = ?) AND ((`k` LIKE ?) OR (`k` = ?) OR (`k` LIKE ?) OR (`k` = ?))) OR " . "((`cat` != ?) AND (`k` LIKE ?)) OR " . @@ -1175,3 +1179,18 @@ function update_1505() return DBA::delete('config', $conditions) ? Update::SUCCESS : Update::FAILED; } + +function update_1508() +{ + $config = DBA::selectToArray('config'); + + $newConfig = DI::config()->beginTransaction(); + + foreach ($config as $entry) { + $newConfig->set($entry['cat'], $entry['k'], $entry['v']); + } + + $newConfig->commit(); + + DBA::e("TRUNCATE TABLE `config`"); +} diff --git a/view/theme/frio/style.php b/view/theme/frio/style.php index 6e05c6b32..479793b59 100644 --- a/view/theme/frio/style.php +++ b/view/theme/frio/style.php @@ -49,7 +49,7 @@ $login_bg_color = ''; $modified = time(); if (DI::mode()->has(\Friendica\App\Mode::MAINTENANCEDISABLED)) { - DI::config()->load('frio'); + DI::config()->reload(); // Default to hard-coded values for empty settings $scheme = DI::config()->get('frio', 'scheme', DI::config()->get('frio', 'schema'));