diff --git a/core/Plugin/Settings.php b/core/Plugin/Settings.php index 0b0bb0953aa7eb015823535001411c2858e3b6d5..23d1472ca96b251f1f097a4d3702ccb364481c4a 100644 --- a/core/Plugin/Settings.php +++ b/core/Plugin/Settings.php @@ -8,11 +8,11 @@ */ namespace Piwik\Plugin; -use Piwik\Option; use Piwik\Piwik; use Piwik\Settings\Setting; +use Piwik\Settings\Storage; use Piwik\Settings\StorageInterface; -use Piwik\SettingsServer; +use Piwik\Tracker\SettingsStorage; /** * Base class of all plugin settings providers. Plugins that define their own configuration settings @@ -25,7 +25,7 @@ use Piwik\SettingsServer; * * @api */ -abstract class Settings implements StorageInterface +abstract class Settings { const TYPE_INT = 'integer'; const TYPE_FLOAT = 'float'; @@ -48,18 +48,13 @@ abstract class Settings implements StorageInterface */ private $settings = array(); - /** - * Array containing all plugin settings values: Array( [setting-key] => [setting-value] ). - * - * @var array - */ - private $settingsValues = array(); - private $introduction; private $pluginName; - // for lazy loading of setting values - private $settingValuesLoaded = false; + /** + * @var StorageInterface + */ + private $storage; /** * Constructor. @@ -70,14 +65,16 @@ abstract class Settings implements StorageInterface $this->pluginName = $pluginName; } else { - $classname = get_class($this); - $parts = explode('\\', $classname); + $classname = get_class($this); + $parts = explode('\\', $classname); if (3 <= count($parts)) { $this->pluginName = $parts[2]; } } + $this->storage = Storage\Factory::make($this->pluginName); + $this->init(); } @@ -89,6 +86,17 @@ abstract class Settings implements StorageInterface return $this->pluginName; } + /** + * @ignore + * @return Setting + */ + public function getSetting($name) + { + if (array_key_exists($name, $this->settings)) { + return $this->settings[$name]; + } + } + /** * Implemented by descendants. This method should define plugin settings (via the * {@link addSetting()}) method and set the introduction text (via the @@ -163,118 +171,6 @@ abstract class Settings implements StorageInterface return $this->settings; } - /** - * Saves (persists) the current setting values in the database. - */ - public function save() - { - $this->loadSettingsIfNotDoneYet(); - - Option::set($this->getOptionKey(), serialize($this->settingsValues)); - - $pluginName = $this->getPluginName(); - - /** - * Triggered after a plugin settings have been updated. - * - * **Example** - * - * Piwik::addAction('Settings.MyPlugin.settingsUpdated', function (Settings $settings) { - * $value = $settings->someSetting->getValue(); - * // Do something with the new setting value - * }); - * - * @param Settings $settings The plugin settings object. - */ - Piwik::postEvent(sprintf('Settings.%s.settingsUpdated', $pluginName), array($this)); - } - - /** - * Removes all settings for this plugin from the database. Useful when uninstalling - * a plugin. - */ - public function removeAllPluginSettings() - { - Piwik::checkUserHasSuperUserAccess(); - - Option::delete($this->getOptionKey()); - $this->settingsValues = array(); - $this->settingValuesLoaded = false; - } - - /** - * Returns the current value for a setting. If no value is stored, the default value - * is be returned. - * - * @param Setting $setting - * @return mixed - * @throws \Exception If the setting does not exist or if the current user is not allowed to change the value - * of this setting. - */ - public function getSettingValue(Setting $setting) - { - $this->checkIsValidSetting($setting->getName()); - $this->checkHasEnoughReadPermission($setting); - $this->loadSettingsIfNotDoneYet(); - - if (array_key_exists($setting->getKey(), $this->settingsValues)) { - - return $this->settingsValues[$setting->getKey()]; - } - - return $setting->defaultValue; - } - - /** - * Sets (overwrites) the value of a setting in memory. To persist the change, {@link save()} must be - * called afterwards, otherwise the change has no effect. - * - * Before the setting is changed, the {@link Piwik\Settings\Setting::$validate} and - * {@link Piwik\Settings\Setting::$transform} closures will be invoked (if defined). If there is no validation - * filter, the setting value will be casted to the appropriate data type. - * - * @param Setting $setting - * @param string $value - * @throws \Exception If the setting does not exist or if the current user is not allowed to change the value - * of this setting. - */ - public function setSettingValue(Setting $setting, $value) - { - $this->checkIsValidSetting($setting->getName()); - $this->checkHasEnoughWritePermission($setting); - - if ($setting->validate && $setting->validate instanceof \Closure) { - call_user_func($setting->validate, $value, $setting); - } - - if ($setting->transform && $setting->transform instanceof \Closure) { - $value = call_user_func($setting->transform, $value, $setting); - } elseif (isset($setting->type)) { - settype($value, $setting->type); - } - - $this->loadSettingsIfNotDoneYet(); - $this->settingsValues[$setting->getKey()] = $value; - } - - /** - * Unsets a setting value in memory. To persist the change, {@link save()} must be - * called afterwards, otherwise the change has no effect. - * - * @param Setting $setting - */ - public function removeSettingValue(Setting $setting) - { - $this->checkHasEnoughWritePermission($setting); - $this->loadSettingsIfNotDoneYet(); - - $key = $setting->getKey(); - - if (array_key_exists($key, $this->settingsValues)) { - unset($this->settingsValues[$key]); - } - } - /** * Makes a new plugin setting available. * @@ -296,53 +192,47 @@ abstract class Settings implements StorageInterface $this->setDefaultTypeAndFieldIfNeeded($setting); $this->addValidatorIfNeeded($setting); - $setting->setStorage($this); + $setting->setStorage($this->storage); + $setting->setPluginName($this->pluginName); $this->settings[$setting->getName()] = $setting; } - private function getOptionKey() - { - return 'Plugin_' . $this->pluginName . '_Settings'; - } - - private function loadSettingsIfNotDoneYet() - { - if ($this->settingValuesLoaded) { - return; - } - - $this->settingValuesLoaded = true; - $this->loadSettings(); - } - - private function loadSettings() + /** + * Saves (persists) the current setting values in the database. + */ + public function save() { - $values = Option::get($this->getOptionKey()); + $this->storage->save(); - if (!empty($values)) { - $this->settingsValues = unserialize($values); - } - } + SettingsStorage::clearCache(); - private function checkIsValidSetting($name) - { - $setting = $this->getSetting($name); - - if (empty($setting)) { - throw new \Exception(sprintf('The setting %s does not exist', $name)); - } + /** + * Triggered after a plugin settings have been updated. + * + * **Example** + * + * Piwik::addAction('Settings.MyPlugin.settingsUpdated', function (Settings $settings) { + * $value = $settings->someSetting->getValue(); + * // Do something with the new setting value + * }); + * + * @param Settings $settings The plugin settings object. + */ + Piwik::postEvent(sprintf('Settings.%s.settingsUpdated', $this->pluginName), array($this)); } /** - * @param $name - * @return Setting|null + * Removes all settings for this plugin from the database. Useful when uninstalling + * a plugin. */ - private function getSetting($name) + public function removeAllPluginSettings() { - if (array_key_exists($name, $this->settings)) { - return $this->settings[$name]; - } + Piwik::checkUserHasSuperUserAccess(); + + $this->storage->deleteAllValues(); + + SettingsStorage::clearCache(); } private function getDefaultType($controlType) @@ -373,40 +263,6 @@ abstract class Settings implements StorageInterface return $defaultControlTypes[$type]; } - /** - * @param $setting - * @throws \Exception - */ - private function checkHasEnoughWritePermission(Setting $setting) - { - // When the request is a Tracker request, allow plugins to write settings - if (SettingsServer::isTrackerApiRequest()) { - return; - } - - if (!$setting->isWritableByCurrentUser()) { - $errorMsg = Piwik::translate('CoreAdminHome_PluginSettingChangeNotAllowed', array($setting->getName(), $this->pluginName)); - throw new \Exception($errorMsg); - } - } - - /** - * @param $setting - * @throws \Exception - */ - private function checkHasEnoughReadPermission(Setting $setting) - { - // When the request is a Tracker request, allow plugins to read settings - if (SettingsServer::isTrackerApiRequest()) { - return; - } - - if (!$setting->isReadableByCurrentUser()) { - $errorMsg = Piwik::translate('CoreAdminHome_PluginSettingReadNotAllowed', array($setting->getName(), $this->pluginName)); - throw new \Exception($errorMsg); - } - } - private function setDefaultTypeAndFieldIfNeeded(Setting $setting) { if (!is_null($setting->uiControlType) && is_null($setting->type)) { diff --git a/core/Settings/Setting.php b/core/Settings/Setting.php index be35345b2db522961eeacb51eff632555a5cc8d1..32883876715e9aaf8c44e4e87fc4bbfea1aad1a3 100644 --- a/core/Settings/Setting.php +++ b/core/Settings/Setting.php @@ -8,6 +8,8 @@ */ namespace Piwik\Settings; +use Piwik\Piwik; +use Piwik\SettingsServer; /** * Base setting type class. @@ -152,6 +154,7 @@ abstract class Setting * @var StorageInterface */ private $storage; + private $pluginName; /** * Constructor. @@ -201,13 +204,33 @@ abstract class Setting /** * Sets the object used to persist settings. * - * @return StorageInterface + * @param StorageInterface $storage */ public function setStorage(StorageInterface $storage) { $this->storage = $storage; } + /** + * @internal + * @ignore + * @return StorageInterface + */ + public function getStorage() + { + return $this->storage; + } + + /** + * Sets th name of the plugin the setting belongs to + * + * @param string $pluginName + */ + public function setPluginName($pluginName) + { + $this->pluginName = $pluginName; + } + /** * Returns the previously persisted setting value. If no value was set, the default value * is returned. @@ -217,7 +240,23 @@ abstract class Setting */ public function getValue() { - return $this->storage->getSettingValue($this); + $this->checkHasEnoughReadPermission(); + + return $this->storage->getValue($this); + } + + /** + * Returns the previously persisted setting value. If no value was set, the default value + * is returned. + * + * @return mixed + * @throws \Exception If the current user is not allowed to change the value of this setting. + */ + public function removeValue() + { + $this->checkHasEnoughWritePermission(); + + return $this->storage->deleteValue($this); } /** @@ -228,7 +267,51 @@ abstract class Setting */ public function setValue($value) { - return $this->storage->setSettingValue($this, $value); + $this->checkHasEnoughWritePermission(); + + if ($this->validate && $this->validate instanceof \Closure) { + call_user_func($this->validate, $value, $this); + } + + if ($this->transform && $this->transform instanceof \Closure) { + $value = call_user_func($this->transform, $value, $this); + } elseif (isset($this->type)) { + settype($value, $this->type); + } + + return $this->storage->setValue($this, $value); + } + + /** + * @throws \Exception + */ + private function checkHasEnoughWritePermission() + { + // When the request is a Tracker request, allow plugins to write settings + if (SettingsServer::isTrackerApiRequest()) { + return; + } + + if (!$this->isWritableByCurrentUser()) { + $errorMsg = Piwik::translate('CoreAdminHome_PluginSettingChangeNotAllowed', array($this->getName(), $this->pluginName)); + throw new \Exception($errorMsg); + } + } + + /** + * @throws \Exception + */ + private function checkHasEnoughReadPermission() + { + // When the request is a Tracker request, allow plugins to read settings + if (SettingsServer::isTrackerApiRequest()) { + return; + } + + if (!$this->isReadableByCurrentUser()) { + $errorMsg = Piwik::translate('CoreAdminHome_PluginSettingReadNotAllowed', array($this->getName(), $this->pluginName)); + throw new \Exception($errorMsg); + } } /** diff --git a/core/Settings/Storage.php b/core/Settings/Storage.php new file mode 100644 index 0000000000000000000000000000000000000000..09525cb6d3fb535a397486746d9c852e026b49d2 --- /dev/null +++ b/core/Settings/Storage.php @@ -0,0 +1,144 @@ +<?php +/** + * Piwik - free/libre analytics platform + * + * @link http://piwik.org + * @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later + * + */ + +namespace Piwik\Settings; +use Piwik\Option; + +/** + * Base setting type class. + * + * @api + */ +class Storage implements StorageInterface +{ + + /** + * Array containing all plugin settings values: Array( [setting-key] => [setting-value] ). + * + * @var array + */ + private $settingsValues = array(); + + // for lazy loading of setting values + private $settingValuesLoaded = false; + + private $pluginName; + + public function __construct($pluginName) + { + $this->pluginName = $pluginName; + } + + /** + * Saves (persists) the current setting values in the database. + */ + public function save() + { + $this->loadSettingsIfNotDoneYet(); + + Option::set($this->getOptionKey(), serialize($this->settingsValues)); + } + + /** + * Removes all settings for this plugin from the database. Useful when uninstalling + * a plugin. + */ + public function deleteAllValues() + { + Option::delete($this->getOptionKey()); + + $this->settingsValues = array(); + $this->settingValuesLoaded = false; + } + + /** + * Returns the current value for a setting. If no value is stored, the default value + * is be returned. + * + * @param Setting $setting + * @return mixed + * @throws \Exception If the setting does not exist or if the current user is not allowed to change the value + * of this setting. + */ + public function getValue(Setting $setting) + { + $this->loadSettingsIfNotDoneYet(); + + if (array_key_exists($setting->getKey(), $this->settingsValues)) { + + return $this->settingsValues[$setting->getKey()]; + } + + return $setting->defaultValue; + } + + /** + * Sets (overwrites) the value of a setting in memory. To persist the change, {@link save()} must be + * called afterwards, otherwise the change has no effect. + * + * Before the setting is changed, the {@link Piwik\Settings\Setting::$validate} and + * {@link Piwik\Settings\Setting::$transform} closures will be invoked (if defined). If there is no validation + * filter, the setting value will be casted to the appropriate data type. + * + * @param Setting $setting + * @param string $value + * @throws \Exception If the setting does not exist or if the current user is not allowed to change the value + * of this setting. + */ + public function setValue(Setting $setting, $value) + { + $this->loadSettingsIfNotDoneYet(); + + $this->settingsValues[$setting->getKey()] = $value; + } + + /** + * Unsets a setting value in memory. To persist the change, {@link save()} must be + * called afterwards, otherwise the change has no effect. + * + * @param Setting $setting + */ + public function deleteValue(Setting $setting) + { + $this->loadSettingsIfNotDoneYet(); + + $key = $setting->getKey(); + + if (array_key_exists($key, $this->settingsValues)) { + unset($this->settingsValues[$key]); + } + } + + public function getOptionKey() + { + return 'Plugin_' . $this->pluginName . '_Settings'; + } + + private function loadSettingsIfNotDoneYet() + { + if ($this->settingValuesLoaded) { + return; + } + + $this->settingValuesLoaded = true; + $this->settingsValues = $this->loadSettings(); + } + + protected function loadSettings() + { + $values = Option::get($this->getOptionKey()); + + if (!empty($values)) { + return unserialize($values); + } + + return array(); + } + +} diff --git a/core/Settings/Storage/Factory.php b/core/Settings/Storage/Factory.php new file mode 100644 index 0000000000000000000000000000000000000000..c007e30e9f77e3474d10d44bc4d7ab61a100181c --- /dev/null +++ b/core/Settings/Storage/Factory.php @@ -0,0 +1,29 @@ +<?php +/** + * Piwik - free/libre analytics platform + * + * @link http://piwik.org + * @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later + * + */ + +namespace Piwik\Settings\Storage; + +use Piwik\Settings\Storage; +use Piwik\SettingsServer; +use Piwik\Tracker\SettingsStorage; + +class Factory +{ + public static function make($pluginName) + { + if (SettingsServer::isTrackerApiRequest()) { + $storage = new SettingsStorage($pluginName); + } else { + $storage = new Storage($pluginName); + } + + return $storage; + } + +} diff --git a/core/Settings/StorageInterface.php b/core/Settings/StorageInterface.php index 74693f9ddb0b4f30641556431339aa6a5ba418dc..7ffcac0d607ac512b4c5acc9567b6cad243fd12a 100644 --- a/core/Settings/StorageInterface.php +++ b/core/Settings/StorageInterface.php @@ -22,7 +22,7 @@ interface StorageInterface * @throws \Exception In case the setting does not exist or if the current user is not allowed to change the value * of this setting. */ - public function getSettingValue(Setting $setting); + public function getValue(Setting $setting); /** * Removes the value for the given setting. Make sure to call `save()` afterwards, otherwise the removal has no @@ -30,7 +30,7 @@ interface StorageInterface * * @param Setting $setting */ - public function removeSettingValue(Setting $setting); + public function deleteValue(Setting $setting); /** * Sets (overwrites) the value for the given setting. Make sure to call `save()` afterwards, otherwise the change @@ -43,7 +43,13 @@ interface StorageInterface * @throws \Exception In case the setting does not exist or if the current user is not allowed to change the value * of this setting. */ - public function setSettingValue(Setting $setting, $value); + public function setValue(Setting $setting, $value); + + /** + * Removes all settings for this plugin from the database. Useful when uninstalling + * a plugin. + */ + public function deleteAllValues(); /** * Saves (persists) the current setting values in the database. diff --git a/core/Settings/UserSetting.php b/core/Settings/UserSetting.php index fa29269707b4e39193944a3c9af931fe7bf7d9f3..80cf66ebf21a63a7053149b1a1a58e8a0851e563 100644 --- a/core/Settings/UserSetting.php +++ b/core/Settings/UserSetting.php @@ -108,7 +108,7 @@ class UserSetting extends Setting if ($setting instanceof UserSetting) { $setting->setUserLogin($userLogin); - $pluginSettings->removeSettingValue($setting); + $setting->removeValue(); } } diff --git a/core/Tracker/SettingsStorage.php b/core/Tracker/SettingsStorage.php new file mode 100644 index 0000000000000000000000000000000000000000..6c54b1b993b6f6344bddbbe8bc8bf8de4a83bfca --- /dev/null +++ b/core/Tracker/SettingsStorage.php @@ -0,0 +1,57 @@ +<?php +/** + * Piwik - free/libre analytics platform + * + * @link http://piwik.org + * @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later + * + */ + +namespace Piwik\Tracker; + +use Piwik\Settings\Storage; +use Piwik\Tracker; + +/** + * Loads settings from tracker cache instead of database. If not yet present in tracker cache will cache it. + */ +class SettingsStorage extends Storage +{ + + protected function loadSettings() + { + $trackerCache = Cache::getCacheGeneral(); + $settings = null; + + if (array_key_exists('settingsStorage', $trackerCache)) { + $allSettings = $trackerCache['settingsStorage']; + + if (is_array($allSettings) && array_key_exists($this->getOptionKey(), $allSettings)) { + $settings = $allSettings[$this->getOptionKey()]; + } + } else { + $trackerCache['settingsStorage'] = array(); + } + + if (is_null($settings)) { + $settings = parent::loadSettings(); + + $trackerCache['settingsStorage'][$this->getOptionKey()] = $settings; + Cache::setCacheGeneral($trackerCache); + } + + return $settings; + } + + public function save() + { + parent::save(); + self::clearCache(); + } + + public static function clearCache() + { + Cache::clearCacheGeneral(); + } + +} diff --git a/tests/PHPUnit/Integration/Plugin/SettingsTest.php b/tests/PHPUnit/Integration/Plugin/SettingsTest.php index 3c146f5d31a6eb8476ff6aed17296e1ce07fe6f7..f8802674a4c0003d9732a8369b58a90ed8cc4ac5 100644 --- a/tests/PHPUnit/Integration/Plugin/SettingsTest.php +++ b/tests/PHPUnit/Integration/Plugin/SettingsTest.php @@ -8,55 +8,19 @@ namespace Piwik\Tests\Integration\Plugin; -use Piwik\Access; use Piwik\Db; use Piwik\Plugin\Settings as PluginSettings; -use Piwik\Settings\Setting; -use Piwik\Tests\Framework\Mock\FakeAccess; -use Piwik\Tests\Framework\TestCase\IntegrationTestCase; - -class CorePluginSettingsTest extends \Piwik\Plugins\ExampleSettingsPlugin\Settings { - - public function init() - { - - } - - public function addSetting(Setting $setting) - { - parent::addSetting($setting); - } -} +use Piwik\Settings\Storage; +use Piwik\Tests\Integration\Settings\CorePluginTestSettings; +use Piwik\Tests\Integration\Settings\IntegrationTestCase; +use Piwik\Tracker\Cache; +use Piwik\Tracker\SettingsStorage; /** - * @group Core * @group PluginSettings */ class SettingsTest extends IntegrationTestCase { - /** - * @var CorePluginSettingsTest - */ - private $settings; - - public function setUp() - { - parent::setUp(); - Access::setSingletonInstance(null); - Db::destroyDatabaseObject(); - - $this->settings = $this->createSettingsInstance(); - } - - public function tearDown() - { - $this->setSuperUser(); - if ($this->settings) { - $this->settings->removeAllPluginSettings(); - } - - parent::tearDown(); - } public function test_constructor_shouldNotEstablishADatabaseConnection() { @@ -69,38 +33,6 @@ class SettingsTest extends IntegrationTestCase $this->assertNotDbConnectionCreated(); } - public function test_constructor_shouldEstablishADatabaseConnection_AsSoonAsWeGetAValue() - { - $this->setSuperUser(); - Db::destroyDatabaseObject(); - - $setting = $this->buildUserSetting('testSetting', 'Test Setting'); - $settings = $this->createSettingsInstance(); - $settings->addSetting($setting); - - $this->assertNotDbConnectionCreated(); - - $settings->getSettingValue($setting); - - $this->assertDbConnectionCreated(); - } - - public function test_constructor_shouldEstablishADatabaseConnection_AsSoonAsWeSetAValue() - { - $this->setSuperUser(); - Db::destroyDatabaseObject(); - - $setting = $this->buildUserSetting('testSetting', 'Test Setting'); - $settings = $this->createSettingsInstance(); - $settings->addSetting($setting); - - $this->assertNotDbConnectionCreated(); - - $settings->setSettingValue($setting, '5'); - - $this->assertDbConnectionCreated(); - } - /** * @expectedException \Exception * @expectedExceptionMessage A setting with name "myname" does already exist for plugin "ExampleSettingsPlugin" @@ -126,21 +58,21 @@ class SettingsTest extends IntegrationTestCase public function test_addSetting_shouldAssignDefaultType_IfFieldIsGivenButNoType() { $setting = $this->buildUserSetting('myname', 'mytitle'); - $setting->uiControlType = CorePluginSettingsTest::CONTROL_MULTI_SELECT; + $setting->uiControlType = CorePluginTestSettings::CONTROL_MULTI_SELECT; $this->settings->addSetting($setting); - $this->assertEquals(CorePluginSettingsTest::TYPE_ARRAY, $setting->type); + $this->assertEquals(CorePluginTestSettings::TYPE_ARRAY, $setting->type); } public function test_addSetting_shouldAssignDefaultField_IfTypeIsGivenButNoField() { $setting = $this->buildUserSetting('myname', 'mytitle'); - $setting->type = CorePluginSettingsTest::TYPE_ARRAY; + $setting->type = CorePluginTestSettings::TYPE_ARRAY; $this->settings->addSetting($setting); - $this->assertEquals(CorePluginSettingsTest::CONTROL_MULTI_SELECT, $setting->uiControlType); + $this->assertEquals(CorePluginTestSettings::CONTROL_MULTI_SELECT, $setting->uiControlType); } public function test_addSetting_shouldAddAValidator_IfFieldOptionsAreGiven() @@ -167,82 +99,29 @@ class SettingsTest extends IntegrationTestCase $setting = $this->buildUserSetting('myname', 'mytitle', 'myRandomName'); $this->settings->addSetting($setting); - $this->settings->setSettingValue($setting, 5); - $this->assertSettingHasValue($setting, 5); - - $this->assertEquals($setting->getValue(), 5); - - $this->settings->setSettingValue($setting, 'test3434'); - $this->assertEquals($setting->getValue(), 'test3434'); - } + $storage = $setting->getStorage(); + $this->assertTrue($storage instanceof Storage); - /** - * @expectedException \Exception - * @expectedExceptionMessage The setting myname2 does not exist - */ - public function test_setSettingValue_shouldThrowException_IfTryingToSetAValueForNotAvailableSetting() - { - $this->addUserSetting('myname', 'mytitle'); - - $setting = $this->buildUserSetting('myname2', 'mytitle2'); - $this->settings->setSettingValue($setting, 2); - } - - /** - * @expectedException \Exception - * @expectedExceptionMessage CoreAdminHome_PluginSettingChangeNotAllowed - */ - public function test_setSettingValue_shouldThrowException_IfAUserIsTryingToSetASettingWhichNeedsSuperUserPermission() - { - $this->setUser(); - $setting = $this->addSystemSetting('mysystem', 'mytitle'); - - $this->settings->setSettingValue($setting, 2); - } - - /** - * @expectedException \Exception - * @expectedExceptionMessage CoreAdminHome_PluginSettingChangeNotAllowed - */ - public function test_setSettingValue_shouldThrowException_IfAnonymousIsTryingToSetASettingWhichNeedsUserPermission() - { - $setting = $this->addUserSetting('mysystem', 'mytitle'); - - $this->settings->setSettingValue($setting, 2); - } - - public function test_setSettingValue_shouldSucceed_IfUserIsTryingToSetASettingWhichNeedsUserPermission() - { - $this->setUser(); - $setting = $this->addUserSetting('mysystem', 'mytitle'); - - $this->settings->setSettingValue($setting, 2); + $setting->setValue(5); + $this->assertSettingHasValue($setting, 5); - $this->assertSettingHasValue($setting, 2); + $this->assertEquals($this->settings->getSetting('myname')->getValue(), 5); } - public function test_setSettingValue_shouldSucceed_IfSuperUserTriesToSaveASettingWhichRequiresSuperUserPermission() + public function test_addSetting_shouldPassTrackerStorage_IfInTrackerMode() { $this->setSuperUser(); - $setting = $this->addSystemSetting('mysystem', 'mytitle'); - - $this->settings->setSettingValue($setting, 2); - - $this->assertSettingHasValue($setting, 2); - } + $GLOBALS['PIWIK_TRACKER_MODE'] = true; - public function test_setSettingValue_shouldNotPersistValueInDatabase_OnSuccess() - { - $this->setSuperUser(); + $settings = $this->createSettingsInstance(); + $setting = $this->buildUserSetting('myname', 'mytitle', 'myRandomName'); + $settings->addSetting($setting); - $setting = $this->buildSystemSetting('mysystem', 'mytitle'); - $this->settings->addSetting($setting); - $this->settings->setSettingValue($setting, 2); + unset($GLOBALS['PIWIK_TRACKER_MODE']); - // make sure stored on the instance - $this->assertSettingHasValue($setting, 2); - $this->assertSettingIsNotSavedInTheDb('mysystem', null); + $storage = $setting->getStorage(); + $this->assertTrue($storage instanceof SettingsStorage); } /** @@ -254,10 +133,8 @@ class SettingsTest extends IntegrationTestCase $this->setUser(); $setting = $this->buildUserSetting('mysystem', 'mytitle'); $setting->availableValues = array('allowed' => 'text', 'allowed2' => 'text2'); - $this->settings->addSetting($setting); - - $this->settings->setSettingValue($setting, 'notallowed'); + $setting->setValue('notallowed'); } /** @@ -273,7 +150,7 @@ class SettingsTest extends IntegrationTestCase $this->settings->addSetting($setting); - $this->settings->setSettingValue($setting, array('allowed', 'notallowed')); + $setting->setValue(array('allowed', 'notallowed')); } public function test_setSettingValue_shouldApplyValidationAndSucceed_IfOptionsAreSet() @@ -285,167 +162,14 @@ class SettingsTest extends IntegrationTestCase $this->settings->addSetting($setting); - $this->settings->setSettingValue($setting, array('allowed', 'allowed2')); + $setting->setValue(array('allowed', 'allowed2')); $this->assertSettingHasValue($setting, array('allowed', 'allowed2')); $setting->type = PluginSettings::TYPE_STRING; - $this->settings->setSettingValue($setting, 'allowed'); + $setting->setValue('allowed'); $this->assertSettingHasValue($setting, 'allowed'); } - public function test_setSettingValue_shouldCastValue_IfTypeIsSetButNoFilter() - { - $this->setUser(); - - // cast to INT - $setting = $this->addUserSetting('mysystem', 'mytitle'); - $setting->type = PluginSettings::TYPE_INT; - $this->settings->setSettingValue($setting, '31xm42'); - $this->assertSettingHasValue($setting, 31, 'integer'); - - // ARRAY - $setting->type = PluginSettings::TYPE_ARRAY; - $this->settings->setSettingValue($setting, '31xm42'); - $this->assertSettingHasValue($setting, array('31xm42'), 'array'); - - // BOOL - $setting->type = PluginSettings::TYPE_BOOL; - $this->settings->setSettingValue($setting, '1'); - $this->assertSettingHasValue($setting, true, 'boolean'); - - // FLOAT - $setting->type = PluginSettings::TYPE_FLOAT; - $this->settings->setSettingValue($setting, '1.21'); - $this->assertSettingHasValue($setting, 1.21, 'float'); - - // STRING - $setting->type = PluginSettings::TYPE_STRING; - $this->settings->setSettingValue($setting, '31xm42'); - $this->assertSettingHasValue($setting, '31xm42'); - } - - public function test_setSettingValue_shouldApplyFilterAndNotCast_IfAFilterIsSet() - { - $this->setUser(); - - $setting = $this->buildUserSetting('mysystem', 'mytitle'); - $setting->type = PluginSettings::TYPE_INT; - - $self = $this; - $setting->transform = function ($value, $userSetting) use ($self, $setting) { - $self->assertEquals('31xm42', $value); - $self->assertEquals($setting, $userSetting); - - return '43939kmf3m3'; - }; - - $this->settings->addSetting($setting); - $this->settings->setSettingValue($setting, '31xm42'); - - // should not be casted to int - $this->assertSettingHasValue($setting, '43939kmf3m3', 'string'); - } - - public function test_getSettingValue_shouldReturnUncastedDefaultValue_IfNoValueIsSet() - { - $this->setUser(); - - $setting = $this->addUserSetting('mydefaultsystem', 'mytitle'); - $setting->type = PluginSettings::TYPE_INT; - $setting->defaultValue ='mytestvalue'; - - // should not be casted to int - $this->assertSettingHasValue($setting, 'mytestvalue', 'string'); - } - - /** - * @expectedException \Exception - * @expectedExceptionMessage The setting myusersetting does not exist - */ - public function test_getSettingValue_shouldThrowException_IfGivenSettingDoesNotExist() - { - $setting = $this->buildUserSetting('myusersetting', 'mytitle'); - - $this->settings->getSettingValue($setting); - } - - /** - * @expectedException \Exception - * @expectedExceptionMessage CoreAdminHome_PluginSettingReadNotAllowed - */ - public function test_getSettingValue_shouldThrowException_IfUserHasNotEnoughPermissionToReadValue() - { - $this->setUser(); - $setting = $this->addSystemSetting('myusersetting', 'mytitle'); - $this->settings->getSettingValue($setting); - } - - public function test_getSettingValue_shouldReturnValue_IfReadbleByCurrentUserIsAllowed() - { - $this->setUser(); - $setting = $this->addSystemSetting('myusersetting', 'mytitle'); - $setting->readableByCurrentUser = true; - - $this->assertEquals('', $this->settings->getSettingValue($setting)); - } - - public function test_getSettingValue_shouldReturnValue_IfValueExistsAndUserHasPermission() - { - $this->setUser(); - $setting = $this->addUserSetting('myusersetting', 'mytitle'); - $setting->type = PluginSettings::TYPE_ARRAY; - $this->settings->setSettingValue($setting, array(2,3,4)); - - $this->assertSettingHasValue($setting, array(2,3,4)); - } - - /** - * @expectedException \Exception - * @expectedExceptionMessage CoreAdminHome_PluginSettingChangeNotAllowed - */ - public function test_removeSettingValue_shouldThrowException_IfUserHasNotEnoughUserPermissions() - { - $setting = $this->addUserSetting('myusersetting', 'mytitle'); - $this->settings->removeSettingValue($setting); - } - - /** - * @expectedException \Exception - * @expectedExceptionMessage CoreAdminHome_PluginSettingChangeNotAllowed - */ - public function test_removeSettingValue_shouldThrowException_IfUserHasNotEnoughAdminPermissions() - { - $this->setUser(); - $setting = $this->addSystemSetting('mysystemsetting', 'mytitle'); - $this->settings->removeSettingValue($setting); - } - - public function test_removeSettingValue_shouldRemoveValue_IfValueExistsAndHasEnoughPermissions() - { - $this->setUser(); - $setting = $this->addUserSetting('myusersetting', 'mytitle'); - $this->settings->setSettingValue($setting, '12345657'); - $this->assertSettingHasValue($setting, '12345657'); - - $this->settings->removeSettingValue($setting); - $this->assertSettingHasValue($setting, null); - } - - public function test_removeSettingValue_shouldRemoveValue_ShouldNotSaveValueInDb() - { - $this->setSuperUser(); - - $setting = $this->addSystemSetting('myusersetting', 'mytitle'); - $this->settings->setSettingValue($setting, '12345657'); - $this->settings->save(); - - $this->settings->removeSettingValue($setting); - $this->assertSettingHasValue($setting, null); - - // should still have same value - $this->assertSettingIsNotSavedInTheDb('myusersetting', '12345657'); - } - public function test_getSettingsForCurrentUser_shouldOnlyReturnSettingsHavingEnoughAdminPermissions() { $this->setUser(); @@ -483,12 +207,14 @@ class SettingsTest extends IntegrationTestCase $this->setSuperUser(); $this->addSystemSetting('mysystemsetting2', 'mytitle2'); - $this->settings->setSettingValue($this->addSystemSetting('mysystemsetting1', 'mytitle1'), '111'); - $this->settings->setSettingValue($this->addSystemSetting('mysystemsetting4', 'mytitle4'), '4444'); - $this->settings->setSettingValue($this->addUserSetting('myusersetting1', 'mytitle5'), '55555'); + $this->addSystemSetting('mysystemsetting1', 'mytitle1')->setValue('111'); + $this->addSystemSetting('mysystemsetting4', 'mytitle4')->setValue('4444'); + $this->addUserSetting('myusersetting1', 'mytitle5')->setValue('55555'); $this->addSystemSetting('mysystemsetting3', 'mytitle3'); + $this->settings->save(); + // verify actually saved $verifySettings = $this->createSettingsInstance(); $setting1 = $this->buildSystemSetting('mysystemsetting1', 'mytitle1'); @@ -503,11 +229,26 @@ class SettingsTest extends IntegrationTestCase $verifySettings->addSetting($setting4); $verifySettings->addSetting($setting5); - $this->assertEquals('111', $verifySettings->getSettingValue($setting1)); - $this->assertEquals(null, $verifySettings->getSettingValue($setting2)); - $this->assertEquals(null, $verifySettings->getSettingValue($setting3)); - $this->assertEquals('4444', $verifySettings->getSettingValue($setting4)); - $this->assertEquals('55555', $verifySettings->getSettingValue($setting5)); + $this->assertEquals('111', $setting1->getValue()); + $this->assertEquals(null, $setting2->getValue()); + $this->assertEquals(null, $setting3->getValue()); + $this->assertEquals('4444', $setting4->getValue()); + $this->assertEquals('55555', $setting5->getValue()); + } + + + public function test_save_shouldClearTrackerCacheEntries() + { + $this->setSuperUser(); + + Cache::setCacheGeneral(array('testSetting' => 1)); + + $this->assertArrayHasKey('testSetting', Cache::getCacheGeneral()); + + $this->addSystemSetting('mysystemsetting2', 'mytitle2'); + $this->settings->save(); + + $this->assertArrayNotHasKey('testSetting', Cache::getCacheGeneral()); } public function test_removeAllPluginSettings_shouldRemoveAllSettings() @@ -516,9 +257,9 @@ class SettingsTest extends IntegrationTestCase $this->addSystemSetting('mysystemsetting3', 'mytitle3'); $this->addSystemSetting('mysystemsetting4', 'mytitle4'); - $this->settings->setSettingValue($this->addSystemSetting('mysystemsetting1', 'mytitle1'), '111'); - $this->settings->setSettingValue($this->addSystemSetting('mysystemsetting2', 'mytitle2'), '4444'); - $this->settings->setSettingValue($this->addUserSetting('myusersetting1', 'mytitle5'), '55555'); + $this->addSystemSetting('mysystemsetting1', 'mytitle1')->setValue('111'); + $this->addSystemSetting('mysystemsetting2', 'mytitle2')->setValue('4444'); + $this->addUserSetting('myusersetting1', 'mytitle5')->setValue('55555'); $this->settings->save(); $this->settings->removeAllPluginSettings(); @@ -537,11 +278,11 @@ class SettingsTest extends IntegrationTestCase $verifySettings->addSetting($setting4); $verifySettings->addSetting($setting5); - $this->assertEquals(null, $verifySettings->getSettingValue($setting1)); - $this->assertEquals(null, $verifySettings->getSettingValue($setting2)); - $this->assertEquals(null, $verifySettings->getSettingValue($setting3)); - $this->assertEquals(null, $verifySettings->getSettingValue($setting4)); - $this->assertEquals(null, $verifySettings->getSettingValue($setting5)); + $this->assertEquals(null, $setting1->getValue()); + $this->assertEquals(null, $setting2->getValue()); + $this->assertEquals(null, $setting3->getValue()); + $this->assertEquals(null, $setting4->getValue()); + $this->assertEquals(null, $setting5->getValue()); } /** @@ -555,6 +296,15 @@ class SettingsTest extends IntegrationTestCase $this->settings->removeAllPluginSettings(); } + /** + * @expectedException \Exception + * @expectedExceptionMessage General_ExceptionPrivilege + */ + public function test_removeAllPluginSettings_shouldThrowException_InCaseAnonymousUser() + { + $this->settings->removeAllPluginSettings(); + } + public function test_userSetting_shouldGenerateDifferentKey_ThenSystemSetting() { $this->setSuperUser(); @@ -567,19 +317,6 @@ class SettingsTest extends IntegrationTestCase $this->assertEquals('myname#superUserLogin#', $user->getKey()); } - public function test_userSetting_shouldGenerateDifferentKey_ForDifferentUsers() - { - $this->setSuperUser(); - - $user1 = $this->buildUserSetting('myname', 'mytitle', 'user1'); - $user2 = $this->buildUserSetting('myname', 'mytitle', '_user2_'); - $user3 = $this->buildUserSetting('myname', 'mytitle'); - - $this->assertEquals('myname#user1#', $user1->getKey()); - $this->assertEquals('myname#_user2_#', $user2->getKey()); - $this->assertEquals('myname#superUserLogin#', $user3->getKey()); - } - public function test_userSetting_shouldSaveValuesPerUser() { $this->setSuperUser(); @@ -591,11 +328,11 @@ class SettingsTest extends IntegrationTestCase $this->settings->addSetting($user); - $this->settings->setSettingValue($user, '111'); + $user->setValue('111'); $user->setUserLogin($user2Login); - $this->settings->setSettingValue($user, '222'); + $user->setValue('222'); $user->setUserLogin($user3Login); - $this->settings->setSettingValue($user, '333'); + $user->setValue('333'); $user->setUserLogin($user1Login); $this->assertSettingHasValue($user, '111'); @@ -605,7 +342,7 @@ class SettingsTest extends IntegrationTestCase $this->assertSettingHasValue($user, '333'); $user->setUserLogin($user2Login); - $this->settings->removeSettingValue($user); + $user->removeValue(); $user->setUserLogin($user1Login); $this->assertSettingHasValue($user, '111'); @@ -624,98 +361,10 @@ class SettingsTest extends IntegrationTestCase $this->assertSettingHasValue($user, null); } - /** - * @expectedException \Exception - * @expectedExceptionMessage You do not have the permission to read the settings of a different user - */ - public function test_userSetting_shouldThrowException_IfSomeoneTriesToReadSettingsFromAnotherUserAndIsNotSuperuser() - { - $this->setUser(); - - $this->buildUserSetting('myname', 'mytitle', 'myRandomName'); - } - - public function test_userSetting_shouldBeAbleToSetLoginAndChangeValues_IfUserHasSuperUserAccess() - { - $this->setSuperUser(); - - $setting = $this->buildUserSetting('myname', 'mytitle', 'myRandomName'); - $this->settings->addSetting($setting); - - $this->settings->setSettingValue($setting, 5); - $this->assertSettingHasValue($setting, 5); - - $this->settings->removeSettingValue($setting); - $this->assertSettingHasValue($setting, null); - } - public function test_construct_shouldDetectTheNameOfThePluginAutomatically_IfPluginNameNotGiven() { $setting = new \Piwik\Plugins\ExampleSettingsPlugin\Settings(); $this->assertEquals('ExampleSettingsPlugin', $setting->getPluginName()); } - - private function buildUserSetting($name, $title, $userLogin = null) - { - return new \Piwik\Settings\UserSetting($name, $title, $userLogin); - } - - private function buildSystemSetting($name, $title) - { - return new \Piwik\Settings\SystemSetting($name, $title); - } - - private function setSuperUser() - { - $pseudoMockAccess = new FakeAccess; - FakeAccess::$superUser = true; - Access::setSingletonInstance($pseudoMockAccess); - } - - private function setUser() - { - $pseudoMockAccess = new FakeAccess; - FakeAccess::$idSitesView = array(1); - Access::setSingletonInstance($pseudoMockAccess); - } - - private function addSystemSetting($name, $title) - { - $setting = $this->buildSystemSetting($name, $title); - $this->settings->addSetting($setting); - return $setting; - } - - private function addUserSetting($name, $title) - { - $setting = $this->buildUserSetting($name, $title); - $this->settings->addSetting($setting); - return $setting; - } - - private function assertSettingHasValue($setting, $expectedValue, $expectedType = null) - { - $value = $this->settings->getSettingValue($setting); - $this->assertEquals($expectedValue, $value); - - if (!is_null($expectedType)) { - $this->assertInternalType($expectedType, $value); - } - } - - private function assertSettingIsNotSavedInTheDb($settingName, $expectedValue) - { - // by creating a new instance... - $setting = $this->buildSystemSetting($settingName, 'mytitle'); - $verifySettings = $this->createSettingsInstance(); - $verifySettings->addSetting($setting); - - $this->assertEquals($expectedValue, $verifySettings->getSettingValue($setting)); - } - - private function createSettingsInstance() - { - return new CorePluginSettingsTest('ExampleSettingsPlugin'); - } } diff --git a/tests/PHPUnit/Integration/Settings/CorePluginTestSettings.php b/tests/PHPUnit/Integration/Settings/CorePluginTestSettings.php new file mode 100644 index 0000000000000000000000000000000000000000..7792f1f3534619355dbf776a96368814047583a7 --- /dev/null +++ b/tests/PHPUnit/Integration/Settings/CorePluginTestSettings.php @@ -0,0 +1,25 @@ +<?php +/** + * Piwik - free/libre analytics platform + * + * @link http://piwik.org + * @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later + */ + +namespace Piwik\Tests\Integration\Settings; + +use Piwik\Settings\Setting; + +class CorePluginTestSettings extends \Piwik\Plugins\ExampleSettingsPlugin\Settings { + + public function init() + { + + } + + public function addSetting(Setting $setting) + { + parent::addSetting($setting); + } +} + diff --git a/tests/PHPUnit/Integration/Settings/IntegrationTestCase.php b/tests/PHPUnit/Integration/Settings/IntegrationTestCase.php new file mode 100644 index 0000000000000000000000000000000000000000..de16fc20f55c0f7aef8f46e49bbadbed7a722f5c --- /dev/null +++ b/tests/PHPUnit/Integration/Settings/IntegrationTestCase.php @@ -0,0 +1,125 @@ +<?php +/** + * Piwik - free/libre analytics platform + * + * @link http://piwik.org + * @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later + */ + +namespace Piwik\Tests\Integration\Settings; + +use Piwik\Access; +use Piwik\Db; +use Piwik\Settings\Setting; +use Piwik\Settings\Storage; +use Piwik\Tests\Framework\Mock\FakeAccess; + +/** + * @group PluginSettings + * @group Settings + * @group Storage + */ +class IntegrationTestCase extends \Piwik\Tests\Framework\TestCase\IntegrationTestCase +{ + /** + * @var CorePluginTestSettings + */ + protected $settings; + + public function setUp() + { + parent::setUp(); + Access::setSingletonInstance(null); + Db::destroyDatabaseObject(); + $this->settings = $this->createSettingsInstance(); + } + + public function tearDown() + { + $this->setSuperUser(); + if ($this->settings) { + $this->settings->removeAllPluginSettings(); + } + + parent::tearDown(); + } + + public function test_constructor_shouldNotEstablishADatabaseConnection() + { + $this->assertNotDbConnectionCreated(); + + new Storage('PluginName'); + + $this->assertNotDbConnectionCreated(); + } + + protected function assertSettingHasValue(Setting $setting, $expectedValue, $expectedType = null) + { + $value = $setting->getValue($setting); + $this->assertEquals($expectedValue, $value); + + if (!is_null($expectedType)) { + $this->assertInternalType($expectedType, $value); + } + } + + protected function buildUserSetting($name, $title, $userLogin = null) + { + $userSetting = new \Piwik\Settings\UserSetting($name, $title, $userLogin); + $userSetting->setStorage(new Storage('ExampleSettingsPlugin')); + + return $userSetting; + } + + protected function buildSystemSetting($name, $title) + { + $systemSetting = new \Piwik\Settings\SystemSetting($name, $title); + $systemSetting->setStorage(new Storage('ExampleSettingsPlugin')); + + return $systemSetting; + } + + protected function setSuperUser() + { + $pseudoMockAccess = new FakeAccess; + FakeAccess::$superUser = true; + Access::setSingletonInstance($pseudoMockAccess); + } + + protected function setUser() + { + $pseudoMockAccess = new FakeAccess(); + FakeAccess::$idSitesView = array(1); + Access::setSingletonInstance($pseudoMockAccess); + } + + protected function createSettingsInstance() + { + return new CorePluginTestSettings('ExampleSettingsPlugin'); + } + + protected function addSystemSetting($name, $title) + { + $setting = $this->buildSystemSetting($name, $title); + $this->settings->addSetting($setting); + return $setting; + } + + protected function addUserSetting($name, $title) + { + $setting = $this->buildUserSetting($name, $title); + $this->settings->addSetting($setting); + return $setting; + } + + + protected function assertSettingIsNotSavedInTheDb($settingName, $expectedValue) + { + // by creating a new instance... + $setting = $this->buildSystemSetting($settingName, 'mytitle'); + $verifySettings = $this->createSettingsInstance(); + $verifySettings->addSetting($setting); + + $this->assertEquals($expectedValue, $setting->getValue()); + } +} diff --git a/tests/PHPUnit/Integration/Settings/Storage/FactoryTest.php b/tests/PHPUnit/Integration/Settings/Storage/FactoryTest.php new file mode 100644 index 0000000000000000000000000000000000000000..0c63124dfe9b65d22a7af8bc5d5fd830c83b52a0 --- /dev/null +++ b/tests/PHPUnit/Integration/Settings/Storage/FactoryTest.php @@ -0,0 +1,62 @@ +<?php +/** + * Piwik - free/libre analytics platform + * + * @link http://piwik.org + * @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later + */ + +namespace Piwik\Tests\Integration\Settings\Storage; + +use Piwik\Settings\Storage; +use Piwik\Settings\Storage\Factory; +use Piwik\Tests\Framework\TestCase\IntegrationTestCase; +use Piwik\Tracker\SettingsStorage; + +/** + * @group Tracker + * @group Handler + * @group Visit + * @group Factory + * @group FactoryTest + */ +class FactoryTest extends IntegrationTestCase +{ + + public function test_make_shouldCreateDefaultInstance() + { + $storage = Factory::make('PluginName'); + $this->assertTrue($storage instanceof Storage); + } + + public function test_make_shouldCreateTrackerInstance_IfInTrackerMode() + { + $storage = $this->makeTrackerInstance(); + + $this->assertTrue($storage instanceof SettingsStorage); + } + + public function test_make_shouldPassThePluginNameToTheStorage() + { + $storage = Factory::make('PluginName'); + $this->assertEquals('Plugin_PluginName_Settings', $storage->getOptionKey()); + } + + public function test_make_shouldPassThePluginNameToTheSettingsStorage() + { + $storage = $this->makeTrackerInstance(); + + $this->assertEquals('Plugin_PluginName_Settings', $storage->getOptionKey()); + } + + private function makeTrackerInstance() + { + $GLOBALS['PIWIK_TRACKER_MODE'] = true; + + $storage = Factory::make('PluginName'); + + unset($GLOBALS['PIWIK_TRACKER_MODE']); + + return $storage; + } +} diff --git a/tests/PHPUnit/Integration/Settings/StorageTest.php b/tests/PHPUnit/Integration/Settings/StorageTest.php new file mode 100644 index 0000000000000000000000000000000000000000..20a5652e676fd96bca37e103e722160b0d9404c8 --- /dev/null +++ b/tests/PHPUnit/Integration/Settings/StorageTest.php @@ -0,0 +1,162 @@ +<?php +/** + * Piwik - free/libre analytics platform + * + * @link http://piwik.org + * @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later + */ + +namespace Piwik\Tests\Integration\Settings; + +use Piwik\Option; +use Piwik\Settings\Storage; +use Piwik\Settings\Setting; + +/** + * @group PluginSettings + * @group Storage + */ +class StorageTest extends IntegrationTestCase +{ + /** + * @var Storage + */ + protected $storage; + + /** + * @var Setting + */ + protected $setting; + + public function setUp() + { + parent::setUp(); + + $this->setSuperUser(); + $this->storage = $this->buildStorage(); + $this->setting = $this->buildUserSetting('myname', 'My Name'); + } + + public function test_constructor_shouldNotEstablishADatabaseConnection() + { + $this->assertNotDbConnectionCreated(); + + $this->buildStorage(); + + $this->assertNotDbConnectionCreated(); + } + + public function test_getValue_shouldEstablishADatabaseConnection() + { + $this->assertNotDbConnectionCreated(); + + $this->storage->getValue($this->setting); + + $this->assertDbConnectionCreated(); + } + + public function test_setValue_shouldEstablishADatabaseConnection() + { + $this->assertNotDbConnectionCreated(); + + $this->storage->setValue($this->setting, 5); + + $this->assertDbConnectionCreated(); + } + + public function test_deleteValue_shouldEstablishADatabaseConnection() + { + $this->assertNotDbConnectionCreated(); + + $this->storage->deleteValue($this->setting, 5); + + $this->assertDbConnectionCreated(); + } + + public function test_deleteAll_shouldEstablishADatabaseConnection() + { + $this->assertNotDbConnectionCreated(); + + $this->storage->deleteAllValues(); + + $this->assertDbConnectionCreated(); + } + + public function test_save_shouldEstablishADatabaseConnection() + { + $this->assertNotDbConnectionCreated(); + + $this->storage->save(); + + $this->assertDbConnectionCreated(); + } + + public function test_getValue_shouldReturnNullByDefault() + { + $value = $this->storage->getValue($this->setting); + $this->assertNull($value); + } + + public function test_getValue_shouldReturnADefaultValueIfOneIsSet() + { + $this->setting->defaultValue = 194.34; + $value = $this->storage->getValue($this->setting); + $this->assertSame(194.34, $value); + } + + public function test_setValue_getValue_shouldSetAndGetActualValue() + { + $this->storage->setValue($this->setting, 'myRandomVal'); + $value = $this->storage->getValue($this->setting); + $this->assertEquals('myRandomVal', $value); + } + + public function test_setValue_shouldNotSaveItInDatabase() + { + $this->storage->setValue($this->setting, 'myRandomVal'); + + $this->assertFalse($this->getValueFromOptionTable()); + } + + public function test_save_shouldPersistValueInDatabase() + { + $this->storage->setValue($this->setting, 'myRandomVal'); + $this->storage->save(); + + $this->assertEquals('a:1:{s:22:"myname#superUserLogin#";s:11:"myRandomVal";}', $this->getValueFromOptionTable()); + } + + public function test_save_shouldPersistMultipleValues_ContainingInt() + { + $this->storage->setValue($this->setting, 'myRandomVal'); + $this->storage->setValue($this->buildUserSetting('mySecondName', 'My Name'), 5); + $this->storage->save(); + + $this->assertEquals('a:2:{s:22:"myname#superUserLogin#";s:11:"myRandomVal";s:28:"mySecondName#superUserLogin#";i:5;}', $this->getValueFromOptionTable()); + } + + public function test_deleteAll_ShouldRemoveTheEntireEntry() + { + $this->storage->setValue($this->setting, 'myRandomVal'); + $this->storage->save(); + $this->storage->deleteAllValues(); + + $this->assertFalse($this->getValueFromOptionTable()); + } + + public function test_getOptionKey_shouldContainThePluginName() + { + $this->assertEquals('Plugin_PluginName_Settings', $this->storage->getOptionKey()); + } + + protected function buildStorage() + { + return new Storage('PluginName'); + } + + protected function getValueFromOptionTable() + { + return Option::get($this->storage->getOptionKey()); + } + +} diff --git a/tests/PHPUnit/Integration/Settings/SystemSettingTest.php b/tests/PHPUnit/Integration/Settings/SystemSettingTest.php new file mode 100644 index 0000000000000000000000000000000000000000..79eaf084ab856597e0d58d5cd72762062aa69b8b --- /dev/null +++ b/tests/PHPUnit/Integration/Settings/SystemSettingTest.php @@ -0,0 +1,149 @@ +<?php +/** + * Piwik - free/libre analytics platform + * + * @link http://piwik.org + * @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later + */ + +namespace Piwik\Tests\Integration\Settings; + +use Piwik\Db; +use Piwik\Settings\SystemSetting; + +/** + * @group PluginSettings + * @group Settings + * @group SystemSetting + */ +class SystemSettingTest extends IntegrationTestCase +{ + + public function test_constructor_shouldNotEstablishADatabaseConnection() + { + $this->assertNotDbConnectionCreated(); + + new SystemSetting('name', 'title'); + + $this->assertNotDbConnectionCreated(); + } + + /** + * @expectedException \Exception + * @expectedExceptionMessage CoreAdminHome_PluginSettingChangeNotAllowed + */ + public function test_setSettingValue_shouldThrowException_IfAUserIsTryingToSetASettingWhichNeedsSuperUserPermission() + { + $this->setUser(); + $setting = $this->addSystemSetting('mysystem', 'mytitle'); + + $setting->setValue(2); + } + + /** + * @expectedException \Exception + * @expectedExceptionMessage CoreAdminHome_PluginSettingChangeNotAllowed + */ + public function test_setSettingValue_shouldThrowException_IfAnonymousIsTryingToSetASettingWhichNeedsSuperUserPermission() + { + $setting = $this->addSystemSetting('mysystem', 'mytitle'); + + $setting->setValue(2); + } + + public function test_setSettingValue_shouldSucceed_IfSuperUserTriesToSaveASettingWhichRequiresSuperUserPermission() + { + $this->setSuperUser(); + + $setting = $this->addSystemSetting('mysystem', 'mytitle'); + $setting->setValue(2); + + $this->assertSettingHasValue($setting, 2); + } + + public function test_setSettingValue_shouldNotPersistValueInDatabase_OnSuccess() + { + $this->setSuperUser(); + + $setting = $this->buildSystemSetting('mysystem', 'mytitle'); + $this->settings->addSetting($setting); + $setting->setValue(2); + + // make sure stored on the instance + $this->assertSettingHasValue($setting, 2); + $this->assertSettingIsNotSavedInTheDb('mysystem', null); + } + + /** + * @expectedException \Exception + * @expectedExceptionMessage CoreAdminHome_PluginSettingReadNotAllowed + */ + public function test_getSettingValue_shouldThrowException_IfUserHasNotEnoughPermissionToReadValue() + { + $this->setUser(); + $setting = $this->addSystemSetting('myusersetting', 'mytitle'); + $setting->getValue(); + } + + /** + * @expectedException \Exception + * @expectedExceptionMessage CoreAdminHome_PluginSettingReadNotAllowed + */ + public function test_getSettingValue_shouldThrowException_IfAnonymousTriedToReadValue() + { + $setting = $this->addSystemSetting('myusersetting', 'mytitle'); + $setting->getValue(); + } + + public function test_getSettingValue_shouldBeReadableBySuperUser() + { + $this->setSuperUser(); + $setting = $this->addSystemSetting('myusersetting', 'mytitle'); + $this->assertEquals('', $setting->getValue()); + } + + public function test_getSettingValue_shouldReturnValue_IfReadbleByCurrentUserIsAllowed() + { + $this->setUser(); + $setting = $this->addSystemSetting('myusersetting', 'mytitle'); + $setting->readableByCurrentUser = true; + + $this->assertEquals('', $setting->getValue()); + } + + /** + * @expectedException \Exception + * @expectedExceptionMessage CoreAdminHome_PluginSettingChangeNotAllowed + */ + public function test_removeSettingValue_shouldThrowException_IfUserHasNotEnoughAdminPermissions() + { + $this->setUser(); + $setting = $this->addSystemSetting('mysystemsetting', 'mytitle'); + $setting->removeValue(); + } + + /** + * @expectedException \Exception + * @expectedExceptionMessage CoreAdminHome_PluginSettingChangeNotAllowed + */ + public function test_removeSettingValue_shouldThrowException_IfAnonymousTriesToRemoveValue() + { + $setting = $this->addSystemSetting('mysystemsetting', 'mytitle'); + $setting->removeValue(); + } + + public function test_removeSettingValue_shouldRemoveValue_ShouldNotSaveValueInDb() + { + $this->setSuperUser(); + + $setting = $this->addSystemSetting('myusersetting', 'mytitle'); + $setting->setValue('12345657'); + $this->settings->save(); + + $setting->removeValue(); + $this->assertSettingHasValue($setting, null); + + // should still have same value + $this->assertSettingIsNotSavedInTheDb('myusersetting', '12345657'); + } +} diff --git a/tests/PHPUnit/Integration/Settings/UserSettingTest.php b/tests/PHPUnit/Integration/Settings/UserSettingTest.php new file mode 100644 index 0000000000000000000000000000000000000000..5d9c089dc249eaa0c516b799351297cc2017a780 --- /dev/null +++ b/tests/PHPUnit/Integration/Settings/UserSettingTest.php @@ -0,0 +1,246 @@ +<?php +/** + * Piwik - free/libre analytics platform + * + * @link http://piwik.org + * @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later + */ + +namespace Piwik\Tests\Integration\Settings; + +use Piwik\Db; +use Piwik\Settings\UserSetting; +use Piwik\Plugin\Settings as PluginSettings; + +/** + * @group PluginSettings + * @group Settings + * @group UserSetting + */ +class UserSettingTest extends IntegrationTestCase +{ + public function test_constructor_shouldNotEstablishADatabaseConnection() + { + $this->assertNotDbConnectionCreated(); + + new UserSetting('name', 'title'); + + $this->assertNotDbConnectionCreated(); + } + + public function test_constructor_shouldEstablishADatabaseConnection_AsSoonAsWeGetAValue() + { + $this->setSuperUser(); + Db::destroyDatabaseObject(); + + $setting = $this->buildUserSetting('testSetting', 'Test Setting'); + + $this->assertNotDbConnectionCreated(); + + $setting->getValue($setting); + + $this->assertDbConnectionCreated(); + } + + public function test_constructor_shouldEstablishADatabaseConnection_AsSoonAsWeSetAValue() + { + $this->setSuperUser(); + Db::destroyDatabaseObject(); + + $setting = $this->buildUserSetting('testSetting', 'Test Setting'); + $settings = $this->createSettingsInstance(); + $settings->addSetting($setting); + + $this->assertNotDbConnectionCreated(); + + $setting->setValue('5'); + + $this->assertDbConnectionCreated(); + } + + /** + * @expectedException \Exception + * @expectedExceptionMessage CoreAdminHome_PluginSettingChangeNotAllowed + */ + public function test_setSettingValue_shouldThrowException_IfAnonymousIsTryingToSetASettingWhichNeedsUserPermission() + { + $setting = $this->addUserSetting('mysystem', 'mytitle'); + + $setting->setValue(2); + } + + public function test_setSettingValue_shouldSucceed_IfUserIsTryingToSetASettingWhichNeedsUserPermission() + { + $this->setUser(); + $setting = $this->addUserSetting('mysystem', 'mytitle'); + $setting->setValue(2); + + $this->assertSettingHasValue($setting, 2); + } + + public function test_setSettingValue_shouldCastValue_IfTypeIsSetButNoFilter() + { + $this->setUser(); + + // cast to INT + $setting = $this->addUserSetting('mysystem', 'mytitle'); + $setting->type = PluginSettings::TYPE_INT; + $setting->setValue('31xm42'); + $this->assertSettingHasValue($setting, 31, 'integer'); + + // ARRAY + $setting->type = PluginSettings::TYPE_ARRAY; + $setting->setValue('31xm42'); + $this->assertSettingHasValue($setting, array('31xm42'), 'array'); + + // BOOL + $setting->type = PluginSettings::TYPE_BOOL; + $setting->setValue('1'); + $this->assertSettingHasValue($setting, true, 'boolean'); + + // FLOAT + $setting->type = PluginSettings::TYPE_FLOAT; + $setting->setValue('1.21'); + $this->assertSettingHasValue($setting, 1.21, 'float'); + + // STRING + $setting->type = PluginSettings::TYPE_STRING; + $setting->setValue('31xm42'); + $this->assertSettingHasValue($setting, '31xm42'); + } + + public function test_setSettingValue_shouldApplyFilterAndNotCast_IfAFilterIsSet() + { + $this->setUser(); + + $setting = $this->buildUserSetting('mysystem', 'mytitle'); + $setting->type = PluginSettings::TYPE_INT; + + $self = $this; + $setting->transform = function ($value, $userSetting) use ($self, $setting) { + $self->assertEquals('31xm42', $value); + $self->assertEquals($setting, $userSetting); + + return '43939kmf3m3'; + }; + + $setting->setValue('31xm42'); + + // should not be casted to int + $this->assertSettingHasValue($setting, '43939kmf3m3', 'string'); + } + + /** + * @expectedException \Exception + * @expectedExceptionMessage Validation Fail + */ + public function test_setSettingValue_shouldValidateAValue_IfAFilterIsSet() + { + $this->setUser(); + + $setting = $this->buildUserSetting('mysystem', 'mytitle'); + $setting->type = PluginSettings::TYPE_INT; + + $self = $this; + $setting->validate = function ($value, $userSetting) use ($self, $setting) { + $self->assertEquals('31xm42', $value); + $self->assertEquals($setting, $userSetting); + + throw new \Exception('Validation Fail'); + }; + + $setting->setValue('31xm42'); + } + + public function test_getSettingValue_shouldReturnUncastedDefaultValue_IfNoValueIsSet() + { + $this->setUser(); + + $setting = $this->addUserSetting('mydefaultsystem', 'mytitle'); + $setting->type = PluginSettings::TYPE_INT; + $setting->defaultValue ='mytestvalue'; + + // should not be casted to int + $this->assertSettingHasValue($setting, 'mytestvalue', 'string'); + } + + /** + * @expectedException \Exception + * @expectedExceptionMessage CoreAdminHome_PluginSettingReadNotAllowed + */ + public function test_getSettingValue_shouldThrowException_IfGivenSettingDoesNotExist() + { + $setting = $this->buildUserSetting('myusersetting', 'mytitle'); + $setting->getValue(); + } + + public function test_getSettingValue_shouldReturnValue_IfValueExistsAndUserHasPermission() + { + $this->setUser(); + $setting = $this->addUserSetting('myusersetting', 'mytitle'); + $setting->type = PluginSettings::TYPE_ARRAY; + $setting->setValue(array(2,3,4)); + + $this->assertSettingHasValue($setting, array(2,3,4)); + } + + /** + * @expectedException \Exception + * @expectedExceptionMessage CoreAdminHome_PluginSettingChangeNotAllowed + */ + public function test_removeSettingValue_shouldThrowException_IfUserHasNotEnoughUserPermissions() + { + $setting = $this->addUserSetting('myusersetting', 'mytitle'); + $setting->removeValue(); + } + + public function test_removeSettingValue_shouldRemoveValue_IfValueExistsAndHasEnoughPermissions() + { + $this->setUser(); + $setting = $this->addUserSetting('myusersetting', 'mytitle'); + $setting->setValue('12345657'); + $this->assertSettingHasValue($setting, '12345657'); + + $setting->removeValue(); + $this->assertSettingHasValue($setting, null); + } + + public function test_userSetting_shouldGenerateDifferentKey_ForDifferentUsers() + { + $this->setSuperUser(); + + $user1 = $this->buildUserSetting('myname', 'mytitle', 'user1'); + $user2 = $this->buildUserSetting('myname', 'mytitle', '_user2_'); + $user3 = $this->buildUserSetting('myname', 'mytitle'); + + $this->assertEquals('myname#user1#', $user1->getKey()); + $this->assertEquals('myname#_user2_#', $user2->getKey()); + $this->assertEquals('myname#superUserLogin#', $user3->getKey()); + } + + /** + * @expectedException \Exception + * @expectedExceptionMessage You do not have the permission to read the settings of a different user + */ + public function test_userSetting_shouldThrowException_IfSomeoneTriesToReadSettingsFromAnotherUserAndIsNotSuperuser() + { + $this->setUser(); + + $this->buildUserSetting('myname', 'mytitle', 'myRandomName'); + } + + public function test_userSetting_shouldBeAbleToSetLoginAndChangeValues_IfUserHasSuperUserAccess() + { + $this->setSuperUser(); + + $setting = $this->buildUserSetting('myname', 'mytitle', 'myRandomName'); + $this->settings->addSetting($setting); + + $setting->setValue(5); + $this->assertSettingHasValue($setting, 5); + + $setting->removeValue(); + $this->assertSettingHasValue($setting, null); + } + +} diff --git a/tests/PHPUnit/Integration/Tracker/SettingsStorageTest.php b/tests/PHPUnit/Integration/Tracker/SettingsStorageTest.php new file mode 100644 index 0000000000000000000000000000000000000000..1bda1105e69bfef5bbf2ee859e954ad9aa1103d6 --- /dev/null +++ b/tests/PHPUnit/Integration/Tracker/SettingsStorageTest.php @@ -0,0 +1,138 @@ +<?php +/** + * Piwik - free/libre analytics platform + * + * @link http://piwik.org + * @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later + */ + +namespace Piwik\Tests\Integration\Tracker; + +use Piwik\Option; +use Piwik\Settings\Storage; +use Piwik\Settings\Setting; +use Piwik\Tests\Integration\Settings\IntegrationTestCase; +use Piwik\Tests\Integration\Settings\StorageTest; +use Piwik\Tracker\Cache; +use Piwik\Tracker\SettingsStorage; + +/** + * @group PluginSettings + * @group Storage + * @group SettingStorage + */ +class SettingsStorageTest extends StorageTest +{ + + public function test_storageShouldLoadSettingsFromCacheIfPossible() + { + $this->setSettingValueInCache('my0815RandomName'); + + $this->assertEquals('my0815RandomName', $this->storage->getValue($this->setting)); + } + + public function test_storageShouldLoadSettingsFromCache_AndNotCreateADatabaseInstance() + { + $this->setSettingValueInCache('my0815RandomName'); + + $this->storage->getValue($this->setting); + + $this->assertNotDbConnectionCreated(); + } + + public function test_clearCache_shouldActuallyClearTheCacheEntry() + { + $this->setSettingValueInCache('my0815RandomName'); + + $this->assertArrayHasKey('settingsStorage', Cache::getCacheGeneral()); + + SettingsStorage::clearCache(); + + $this->assertArrayNotHasKey('settingsStorage', Cache::getCacheGeneral()); + } + + public function test_storageShouldNotCastAnyCachedValue() + { + $this->setSettingValueInCache(5); + + $this->assertEquals(5, $this->storage->getValue($this->setting)); + } + + public function test_storageShouldFallbackToDatebaseInCaseNoCacheExists() + { + $this->storage->setValue($this->setting, 5); + $this->storage->save(); + + $this->assertNotFalse($this->getValueFromOptionTable()); // make sure saved in db + + $storage = $this->buildStorage(); + $this->assertEquals(5, $storage->getValue($this->setting)); + } + + public function test_storageCreateACacheEntryIfNoCacheExistsYet() + { + $cache = Cache::getCacheGeneral(); + $this->assertArrayNotHasKey('settingsStorage', $cache); // make sure there is no cache entry yet + + $this->setSettingValueAndMakeSureCacheGetsCreated('myVal'); + + $cache = Cache::getCacheGeneral(); + + $this->assertEquals(array( + $this->storage->getOptionKey() => array( + $this->setting->getKey() => 'myVal' + ) + ), $cache['settingsStorage']); + } + + public function test_shouldAddACacheEntryToAnotherCacheEntryAndNotOverwriteAll() + { + $dummyCacheEntry = array( + 'Plugin_PluginNameOther_Settings' => array( + 'anything' => 'anyval', + 'any' => 'other' + ) + ); + Cache::setCacheGeneral(array( + 'settingsStorage' => $dummyCacheEntry + )); + + Option::set($this->storage->getOptionKey(), serialize(array('mykey' => 'myVal'))); + + $this->buildStorage()->getValue($this->setting); // force adding new cache entry + + $cache = Cache::getCacheGeneral(); + + $dummyCacheEntry[$this->storage->getOptionKey()] = array( + 'mykey' => 'myVal' + ); + + $this->assertEquals($dummyCacheEntry, $cache['settingsStorage']); + } + + protected function buildStorage() + { + return new SettingsStorage('PluginName'); + } + + private function setSettingValueInCache($value) + { + Cache::setCacheGeneral(array( + 'settingsStorage' => array( + $this->storage->getOptionKey() => array( + $this->setting->getKey() => $value + ) + ) + )); + } + + private function setSettingValueAndMakeSureCacheGetsCreated($value) + { + $this->storage->setValue($this->setting, $value); + $this->storage->save(); + + $storage = $this->buildStorage(); + $storage->getValue($this->setting); // force creation of cache by loading settings + } + +}