diff --git a/core/command/base.php b/core/command/base.php
index f84dcb1aeafecfaa08a4aeb0d67d0813dde3252f..7e61c0cb9ab262b9f5c09c4949ee956804c32d61 100644
--- a/core/command/base.php
+++ b/core/command/base.php
@@ -43,8 +43,9 @@ class Base extends Command {
 	 * @param InputInterface $input
 	 * @param OutputInterface $output
 	 * @param array $items
+	 * @param string $prefix
 	 */
-	protected function writeArrayInOutputFormat(InputInterface $input, OutputInterface $output, $items) {
+	protected function writeArrayInOutputFormat(InputInterface $input, OutputInterface $output, $items, $prefix = '  - ') {
 		switch ($input->getOption('output')) {
 			case 'json':
 				$output->writeln(json_encode($items));
@@ -54,28 +55,57 @@ class Base extends Command {
 				break;
 			default:
 				foreach ($items as $key => $item) {
+					if (is_array($item)) {
+						$output->writeln($prefix . $key . ':');
+						$this->writeArrayInOutputFormat($input, $output, $item, '  ' . $prefix);
+						continue;
+					}
 					if (!is_int($key)) {
 						$value = $this->valueToString($item);
 						if (!is_null($value)) {
-							$output->writeln(' - ' . $key . ': ' . $value);
+							$output->writeln($prefix . $key . ': ' . $value);
 						} else {
-							$output->writeln(' - ' . $key);
+							$output->writeln($prefix . $key);
 						}
 					} else {
-						$output->writeln(' - ' . $this->valueToString($item));
+						$output->writeln($prefix . $this->valueToString($item));
 					}
 				}
 				break;
 		}
 	}
 
-	protected function valueToString($value) {
+	/**
+	 * @param InputInterface $input
+	 * @param OutputInterface $output
+	 * @param mixed $item
+	 */
+	protected function writeMixedInOutputFormat(InputInterface $input, OutputInterface $output, $item) {
+		if (is_array($item)) {
+			$this->writeArrayInOutputFormat($input, $output, $item, '');
+			return;
+		}
+
+		switch ($input->getOption('output')) {
+			case 'json':
+				$output->writeln(json_encode($item));
+				break;
+			case 'json_pretty':
+				$output->writeln(json_encode($item, JSON_PRETTY_PRINT));
+				break;
+			default:
+				$output->writeln($this->valueToString($item, false));
+				break;
+		}
+	}
+
+	protected function valueToString($value, $returnNull = true) {
 		if ($value === false) {
 			return 'false';
 		} else if ($value === true) {
 			return 'true';
 		} else if ($value === null) {
-			null;
+			return ($returnNull) ? null : 'null';
 		} else {
 			return $value;
 		}
diff --git a/core/command/config/app/deleteconfig.php b/core/command/config/app/deleteconfig.php
new file mode 100644
index 0000000000000000000000000000000000000000..0031142358e4bf9e3eb875f68c770e4f1bfe5304
--- /dev/null
+++ b/core/command/config/app/deleteconfig.php
@@ -0,0 +1,81 @@
+<?php
+/**
+ * @author Joas Schilling <nickvergessen@owncloud.com>
+ *
+ * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @license AGPL-3.0
+ *
+ * This code is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License, version 3,
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License, version 3,
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>
+ *
+ */
+
+namespace OC\Core\Command\Config\App;
+
+use OC\Core\Command\Base;
+use OCP\IConfig;
+use Symfony\Component\Console\Input\InputArgument;
+use Symfony\Component\Console\Input\InputInterface;
+use Symfony\Component\Console\Input\InputOption;
+use Symfony\Component\Console\Output\OutputInterface;
+
+class DeleteConfig extends Base {
+	/** * @var IConfig */
+	protected $config;
+
+	/**
+	 * @param IConfig $config
+	 */
+	public function __construct(IConfig $config) {
+		parent::__construct();
+		$this->config = $config;
+	}
+
+	protected function configure() {
+		parent::configure();
+
+		$this
+			->setName('config:app:delete')
+			->setDescription('Delete an app config value')
+			->addArgument(
+				'app',
+				InputArgument::REQUIRED,
+				'Name of the app'
+			)
+			->addArgument(
+				'name',
+				InputArgument::REQUIRED,
+				'Name of the config to delete'
+			)
+			->addOption(
+				'error-if-not-exists',
+				null,
+				InputOption::VALUE_NONE,
+				'Checks whether the config exists before deleting it'
+			)
+		;
+	}
+
+	protected function execute(InputInterface $input, OutputInterface $output) {
+		$appName = $input->getArgument('app');
+		$configName = $input->getArgument('name');
+
+		if ($input->hasParameterOption('--error-if-not-exists') && !in_array($configName, $this->config->getAppKeys($appName))) {
+			$output->writeln('<error>Config ' . $configName . ' could not be deleted because it did not exist</error>');
+			return 1;
+		}
+
+		$this->config->deleteAppValue($appName, $configName);
+		$output->writeln('<info>System config value ' . $configName . ' deleted</info>');
+		return 0;
+	}
+}
diff --git a/core/command/config/app/getconfig.php b/core/command/config/app/getconfig.php
new file mode 100644
index 0000000000000000000000000000000000000000..186ed46999f2aa7a07d274ebf368ab6319ecdecd
--- /dev/null
+++ b/core/command/config/app/getconfig.php
@@ -0,0 +1,93 @@
+<?php
+/**
+ * @author Joas Schilling <nickvergessen@owncloud.com>
+ *
+ * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @license AGPL-3.0
+ *
+ * This code is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License, version 3,
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License, version 3,
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>
+ *
+ */
+
+namespace OC\Core\Command\Config\App;
+
+use OC\Core\Command\Base;
+use OCP\IConfig;
+use Symfony\Component\Console\Input\InputArgument;
+use Symfony\Component\Console\Input\InputInterface;
+use Symfony\Component\Console\Input\InputOption;
+use Symfony\Component\Console\Output\OutputInterface;
+
+class GetConfig extends Base {
+	/** * @var IConfig */
+	protected $config;
+
+	/**
+	 * @param IConfig $config
+	 */
+	public function __construct(IConfig $config) {
+		parent::__construct();
+		$this->config = $config;
+	}
+
+	protected function configure() {
+		parent::configure();
+
+		$this
+			->setName('config:app:get')
+			->setDescription('Get an app config value')
+			->addArgument(
+				'app',
+				InputArgument::REQUIRED,
+				'Name of the app'
+			)
+			->addArgument(
+				'name',
+				InputArgument::REQUIRED,
+				'Name of the config to get'
+			)
+			->addOption(
+				'default-value',
+				null,
+				InputOption::VALUE_OPTIONAL,
+				'If no default value is set and the config does not exist, the command will exit with 1'
+			)
+		;
+	}
+
+	/**
+	 * Executes the current command.
+	 *
+	 * @param InputInterface  $input  An InputInterface instance
+	 * @param OutputInterface $output An OutputInterface instance
+	 * @return null|int null or 0 if everything went fine, or an error code
+	 */
+	protected function execute(InputInterface $input, OutputInterface $output) {
+		$appName = $input->getArgument('app');
+		$configName = $input->getArgument('name');
+		$defaultValue = $input->getOption('default-value');
+
+		if (!in_array($configName, $this->config->getAppKeys($appName)) && !$input->hasParameterOption('--default-value')) {
+			return 1;
+		}
+
+		if (!in_array($configName, $this->config->getAppKeys($appName))) {
+			$configValue = $defaultValue;
+		} else {
+			$configValue = $this->config->getAppValue($appName, $configName);
+		}
+
+		$this->writeMixedInOutputFormat($input, $output, $configValue);
+		return 0;
+	}
+}
diff --git a/core/command/config/app/setconfig.php b/core/command/config/app/setconfig.php
new file mode 100644
index 0000000000000000000000000000000000000000..91775094fdd8bd2c259d9f885913cf80bd1bc82b
--- /dev/null
+++ b/core/command/config/app/setconfig.php
@@ -0,0 +1,89 @@
+<?php
+/**
+ * @author Joas Schilling <nickvergessen@owncloud.com>
+ *
+ * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @license AGPL-3.0
+ *
+ * This code is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License, version 3,
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License, version 3,
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>
+ *
+ */
+
+namespace OC\Core\Command\Config\App;
+
+use OC\Core\Command\Base;
+use OCP\IConfig;
+use Symfony\Component\Console\Input\InputArgument;
+use Symfony\Component\Console\Input\InputInterface;
+use Symfony\Component\Console\Input\InputOption;
+use Symfony\Component\Console\Output\OutputInterface;
+
+class SetConfig extends Base {
+	/** * @var IConfig */
+	protected $config;
+
+	/**
+	 * @param IConfig $config
+	 */
+	public function __construct(IConfig $config) {
+		parent::__construct();
+		$this->config = $config;
+	}
+
+	protected function configure() {
+		parent::configure();
+
+		$this
+			->setName('config:app:set')
+			->setDescription('Set an app config value')
+			->addArgument(
+				'app',
+				InputArgument::REQUIRED,
+				'Name of the app'
+			)
+			->addArgument(
+				'name',
+				InputArgument::REQUIRED,
+				'Name of the config to set'
+			)
+			->addOption(
+				'value',
+				null,
+				InputOption::VALUE_REQUIRED,
+				'The new value of the config'
+			)
+			->addOption(
+				'update-only',
+				null,
+				InputOption::VALUE_NONE,
+				'Only updates the value, if it is not set before, it is not being added'
+			)
+		;
+	}
+
+	protected function execute(InputInterface $input, OutputInterface $output) {
+		$appName = $input->getArgument('app');
+		$configName = $input->getArgument('name');
+
+		if (!in_array($configName, $this->config->getAppKeys($appName)) && $input->hasParameterOption('--update-only')) {
+			$output->writeln('<comment>Value not updated, as it has not been set before.</comment>');
+			return 1;
+		}
+
+		$configValue = $input->getOption('value');
+		$this->config->setAppValue($appName, $configName, $configValue);
+
+		$output->writeln('<info>Config value ' . $configName . ' for app ' . $appName . ' set to ' . $configValue . '</info>');
+		return 0;
+	}
+}
diff --git a/core/command/config/import.php b/core/command/config/import.php
new file mode 100644
index 0000000000000000000000000000000000000000..c53fd7255f9777fe35bda53d6eb59123de531b65
--- /dev/null
+++ b/core/command/config/import.php
@@ -0,0 +1,195 @@
+<?php
+/**
+ * @author Joas Schilling <nickvergessen@owncloud.com>
+ *
+ * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @license AGPL-3.0
+ *
+ * This code is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License, version 3,
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License, version 3,
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>
+ *
+ */
+
+namespace OC\Core\Command\Config;
+
+use OCP\IConfig;
+use Symfony\Component\Console\Command\Command;
+use Symfony\Component\Console\Input\InputArgument;
+use Symfony\Component\Console\Input\InputInterface;
+use Symfony\Component\Console\Output\OutputInterface;
+
+class Import extends Command {
+	protected $validRootKeys = ['system', 'apps'];
+
+	/** @var IConfig */
+	protected $config;
+
+	/**
+	 * @param IConfig $config
+	 */
+	public function __construct(IConfig $config) {
+		parent::__construct();
+		$this->config = $config;
+	}
+
+	protected function configure() {
+		$this
+			->setName('config:import')
+			->setDescription('Import a list of configs')
+			->addArgument(
+				'file',
+				InputArgument::OPTIONAL,
+				'File with the json array to import'
+			)
+		;
+	}
+
+	protected function execute(InputInterface $input, OutputInterface $output) {
+		$importFile = $input->getArgument('file');
+		if ($importFile !== null) {
+			$content = $this->getArrayFromFile($importFile);
+		} else {
+			$content = $this->getArrayFromStdin();
+		}
+
+		try {
+			$configs = $this->validateFileContent($content);
+		} catch (\UnexpectedValueException $e) {
+			$output->writeln('<error>' . $e->getMessage(). '</error>');
+			return;
+		}
+
+		if (!empty($configs['system'])) {
+			$this->config->setSystemValues($configs['system']);
+		}
+
+		if (!empty($configs['apps'])) {
+			foreach ($configs['apps'] as $app => $appConfigs) {
+				foreach ($appConfigs as $key => $value) {
+					if ($value === null) {
+						$this->config->deleteAppValue($app, $key);
+					} else {
+						$this->config->setAppValue($app, $key, $value);
+					}
+				}
+			}
+		}
+
+		$output->writeln('<info>Config successfully imported from: ' . $importFile . '</info>');
+	}
+
+	/**
+	 * Get the content from stdin ("config:import < file.json")
+	 *
+	 * @return string
+	 */
+	protected function getArrayFromStdin() {
+		// Read from stdin. stream_set_blocking is used to prevent blocking
+		// when nothing is passed via stdin.
+		stream_set_blocking(STDIN, 0);
+		$content = file_get_contents('php://stdin');
+		stream_set_blocking(STDIN, 1);
+		return $content;
+	}
+
+	/**
+	 * Get the content of the specified file ("config:import file.json")
+	 *
+	 * @param string $importFile
+	 * @return string
+	 */
+	protected function getArrayFromFile($importFile) {
+		$content = file_get_contents($importFile);
+		return $content;
+	}
+
+	/**
+	 * @param string $content
+	 * @return array
+	 * @throws \UnexpectedValueException when the array is invalid
+	 */
+	protected function validateFileContent($content) {
+		$decodedContent = json_decode($content, true);
+		if (!is_array($decodedContent) || empty($decodedContent)) {
+			throw new \UnexpectedValueException('The file must contain a valid json array');
+		}
+
+		$this->validateArray($decodedContent);
+
+		return $decodedContent;
+	}
+
+	/**
+	 * Validates that the array only contains `system` and `apps`
+	 *
+	 * @param array $array
+	 */
+	protected function validateArray($array) {
+		$arrayKeys = array_keys($array);
+		$additionalKeys = array_diff($arrayKeys, $this->validRootKeys);
+		$commonKeys = array_intersect($arrayKeys, $this->validRootKeys);
+		if (!empty($additionalKeys)) {
+			throw new \UnexpectedValueException('Found invalid entries in root: ' . implode(', ', $additionalKeys));
+		}
+		if (empty($commonKeys)) {
+			throw new \UnexpectedValueException('At least one key of the following is expected: ' . implode(', ', $this->validRootKeys));
+		}
+
+		if (isset($array['system'])) {
+			if (is_array($array['system'])) {
+				foreach ($array['system'] as $name => $value) {
+					$this->checkTypeRecursively($value, $name);
+				}
+			} else {
+				throw new \UnexpectedValueException('The system config array is not an array');
+			}
+		}
+
+		if (isset($array['apps'])) {
+			if (is_array($array['apps'])) {
+				$this->validateAppsArray($array['apps']);
+			} else {
+				throw new \UnexpectedValueException('The apps config array is not an array');
+			}
+		}
+	}
+
+	/**
+	 * @param mixed $configValue
+	 * @param string $configName
+	 */
+	protected function checkTypeRecursively($configValue, $configName) {
+		if (!is_array($configValue) && !is_bool($configValue) && !is_int($configValue) && !is_string($configValue) && !is_null($configValue)) {
+			throw new \UnexpectedValueException('Invalid system config value for "' . $configName . '". Only arrays, bools, integers, strings and null (delete) are allowed.');
+		}
+		if (is_array($configValue)) {
+			foreach ($configValue as $key => $value) {
+				$this->checkTypeRecursively($value, $configName);
+			}
+		}
+	}
+
+	/**
+	 * Validates that app configs are only integers and strings
+	 *
+	 * @param array $array
+	 */
+	protected function validateAppsArray($array) {
+		foreach ($array as $app => $configs) {
+			foreach ($configs as $name => $value) {
+				if (!is_int($value) && !is_string($value) && !is_null($value)) {
+					throw new \UnexpectedValueException('Invalid app config value for "' . $app . '":"' . $name . '". Only integers, strings and null (delete) are allowed.');
+				}
+			}
+		}
+	}
+}
diff --git a/core/command/config/listconfigs.php b/core/command/config/listconfigs.php
new file mode 100644
index 0000000000000000000000000000000000000000..be3073e54d98f168e590a84f5c30b32ae93df853
--- /dev/null
+++ b/core/command/config/listconfigs.php
@@ -0,0 +1,141 @@
+<?php
+/**
+ * @author Joas Schilling <nickvergessen@owncloud.com>
+ *
+ * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @license AGPL-3.0
+ *
+ * This code is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License, version 3,
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License, version 3,
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>
+ *
+ */
+
+namespace OC\Core\Command\Config;
+
+use OC\Core\Command\Base;
+use OC\SystemConfig;
+use OCP\IAppConfig;
+use Symfony\Component\Console\Input\InputArgument;
+use Symfony\Component\Console\Input\InputInterface;
+use Symfony\Component\Console\Input\InputOption;
+use Symfony\Component\Console\Output\OutputInterface;
+
+class ListConfigs extends Base {
+	/** @var array */
+	protected $sensitiveValues = [
+		'dbpassword',
+		'dbuser',
+		'mail_smtpname',
+		'mail_smtppassword',
+		'passwordsalt',
+		'secret',
+	];
+
+	/** * @var SystemConfig */
+	protected $systemConfig;
+
+	/** @var IAppConfig */
+	protected $appConfig;
+
+	/**
+	 * @param SystemConfig $systemConfig
+	 * @param IAppConfig $appConfig
+	 */
+	public function __construct(SystemConfig $systemConfig, IAppConfig $appConfig) {
+		parent::__construct();
+		$this->systemConfig = $systemConfig;
+		$this->appConfig = $appConfig;
+	}
+
+	protected function configure() {
+		parent::configure();
+
+		$this
+			->setName('config:list')
+			->setDescription('List all configs')
+			->addArgument(
+				'app',
+				InputArgument::OPTIONAL,
+				'Name of the app ("system" to get the config.php values, "all" for all apps and system)',
+				'all'
+			)
+			->addOption(
+				'private',
+				null,
+				InputOption::VALUE_NONE,
+				'Use this option when you want to include sensitive configs like passwords, salts, ...'
+			)
+		;
+	}
+
+	protected function execute(InputInterface $input, OutputInterface $output) {
+		$app = $input->getArgument('app');
+		$noSensitiveValues = !$input->getOption('private');
+
+		if ($noSensitiveValues && !$input->hasParameterOption('--output')) {
+			// If you post this publicly we prefer the json format
+			$input->setOption('output', 'json_pretty');
+		}
+
+		switch ($app) {
+			case 'system':
+				$configs = [
+					'system' => $this->getSystemConfigs($noSensitiveValues),
+				];
+			break;
+
+			case 'all':
+				$apps = $this->appConfig->getApps();
+				$configs = [
+					'system' => $this->getSystemConfigs($noSensitiveValues),
+					'apps' => [],
+				];
+				foreach ($apps as $appName) {
+					$configs['apps'][$appName] = $this->appConfig->getValues($appName, false);
+				}
+			break;
+
+			default:
+				$configs = [
+					'apps' => [
+						$app => $this->appConfig->getValues($app, false),
+					],
+				];
+		}
+
+		$this->writeArrayInOutputFormat($input, $output, $configs);
+	}
+
+	/**
+	 * Get the system configs
+	 *
+	 * @param bool $noSensitiveValues
+	 * @return array
+	 */
+	protected function getSystemConfigs($noSensitiveValues) {
+		$keys = $this->systemConfig->getKeys();
+
+		$configs = [];
+		foreach ($keys as $key) {
+			if ($noSensitiveValues && in_array($key, $this->sensitiveValues)) {
+				continue;
+			}
+
+			$value = $this->systemConfig->getValue($key, serialize(null));
+			if ($value !== 'N;') {
+				$configs[$key] = $value;
+			}
+		}
+
+		return $configs;
+	}
+}
diff --git a/core/command/config/system/deleteconfig.php b/core/command/config/system/deleteconfig.php
new file mode 100644
index 0000000000000000000000000000000000000000..49bc2bc8c0304c2d0e21761f9194f0a25ebdd0a4
--- /dev/null
+++ b/core/command/config/system/deleteconfig.php
@@ -0,0 +1,75 @@
+<?php
+/**
+ * @author Joas Schilling <nickvergessen@owncloud.com>
+ *
+ * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @license AGPL-3.0
+ *
+ * This code is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License, version 3,
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License, version 3,
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>
+ *
+ */
+
+namespace OC\Core\Command\Config\System;
+
+use OC\Core\Command\Base;
+use OC\SystemConfig;
+use Symfony\Component\Console\Input\InputArgument;
+use Symfony\Component\Console\Input\InputInterface;
+use Symfony\Component\Console\Input\InputOption;
+use Symfony\Component\Console\Output\OutputInterface;
+
+class DeleteConfig extends Base {
+	/** * @var SystemConfig */
+	protected $systemConfig;
+
+	/**
+	 * @param SystemConfig $systemConfig
+	 */
+	public function __construct(SystemConfig $systemConfig) {
+		parent::__construct();
+		$this->systemConfig = $systemConfig;
+	}
+
+	protected function configure() {
+		parent::configure();
+
+		$this
+			->setName('config:system:delete')
+			->setDescription('Delete a system config value')
+			->addArgument(
+				'name',
+				InputArgument::REQUIRED,
+				'Name of the config to delete'
+			)
+			->addOption(
+				'error-if-not-exists',
+				null,
+				InputOption::VALUE_NONE,
+				'Checks whether the config exists before deleting it'
+			)
+		;
+	}
+
+	protected function execute(InputInterface $input, OutputInterface $output) {
+		$configName = $input->getArgument('name');
+
+		if ($input->hasParameterOption('--error-if-not-exists') && !in_array($configName, $this->systemConfig->getKeys())) {
+			$output->writeln('<error>Config ' . $configName . ' could not be deleted because it did not exist</error>');
+			return 1;
+		}
+
+		$this->systemConfig->deleteValue($configName);
+		$output->writeln('<info>System config value ' . $configName . ' deleted</info>');
+		return 0;
+	}
+}
diff --git a/core/command/config/system/getconfig.php b/core/command/config/system/getconfig.php
new file mode 100644
index 0000000000000000000000000000000000000000..d53de18a0bb132388747a4d27b9627b0b7e404a4
--- /dev/null
+++ b/core/command/config/system/getconfig.php
@@ -0,0 +1,87 @@
+<?php
+/**
+ * @author Joas Schilling <nickvergessen@owncloud.com>
+ *
+ * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @license AGPL-3.0
+ *
+ * This code is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License, version 3,
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License, version 3,
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>
+ *
+ */
+
+namespace OC\Core\Command\Config\System;
+
+use OC\Core\Command\Base;
+use OC\SystemConfig;
+use Symfony\Component\Console\Input\InputArgument;
+use Symfony\Component\Console\Input\InputInterface;
+use Symfony\Component\Console\Input\InputOption;
+use Symfony\Component\Console\Output\OutputInterface;
+
+class GetConfig extends Base {
+	/** * @var SystemConfig */
+	protected $systemConfig;
+
+	/**
+	 * @param SystemConfig $systemConfig
+	 */
+	public function __construct(SystemConfig $systemConfig) {
+		parent::__construct();
+		$this->systemConfig = $systemConfig;
+	}
+
+	protected function configure() {
+		parent::configure();
+
+		$this
+			->setName('config:system:get')
+			->setDescription('Get a system config value')
+			->addArgument(
+				'name',
+				InputArgument::REQUIRED,
+				'Name of the config to get'
+			)
+			->addOption(
+				'default-value',
+				null,
+				InputOption::VALUE_OPTIONAL,
+				'If no default value is set and the config does not exist, the command will exit with 1'
+			)
+		;
+	}
+
+	/**
+	 * Executes the current command.
+	 *
+	 * @param InputInterface  $input  An InputInterface instance
+	 * @param OutputInterface $output An OutputInterface instance
+	 * @return null|int null or 0 if everything went fine, or an error code
+	 */
+	protected function execute(InputInterface $input, OutputInterface $output) {
+		$configName = $input->getArgument('name');
+		$defaultValue = $input->getOption('default-value');
+
+		if (!in_array($configName, $this->systemConfig->getKeys()) && !$input->hasParameterOption('--default-value')) {
+			return 1;
+		}
+
+		if (!in_array($configName, $this->systemConfig->getKeys())) {
+			$configValue = $defaultValue;
+		} else {
+			$configValue = $this->systemConfig->getValue($configName);
+		}
+
+		$this->writeMixedInOutputFormat($input, $output, $configValue);
+		return 0;
+	}
+}
diff --git a/core/command/config/system/setconfig.php b/core/command/config/system/setconfig.php
new file mode 100644
index 0000000000000000000000000000000000000000..cb2f9fe616fa16606f8d5a422fbdd438965cc641
--- /dev/null
+++ b/core/command/config/system/setconfig.php
@@ -0,0 +1,82 @@
+<?php
+/**
+ * @author Joas Schilling <nickvergessen@owncloud.com>
+ *
+ * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @license AGPL-3.0
+ *
+ * This code is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License, version 3,
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License, version 3,
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>
+ *
+ */
+
+namespace OC\Core\Command\Config\System;
+
+use OC\Core\Command\Base;
+use OC\SystemConfig;
+use Symfony\Component\Console\Input\InputArgument;
+use Symfony\Component\Console\Input\InputInterface;
+use Symfony\Component\Console\Input\InputOption;
+use Symfony\Component\Console\Output\OutputInterface;
+
+class SetConfig extends Base {
+	/** * @var SystemConfig */
+	protected $systemConfig;
+
+	/**
+	 * @param SystemConfig $systemConfig
+	 */
+	public function __construct(SystemConfig $systemConfig) {
+		parent::__construct();
+		$this->systemConfig = $systemConfig;
+	}
+
+	protected function configure() {
+		parent::configure();
+
+		$this
+			->setName('config:system:set')
+			->setDescription('Set a system config value')
+			->addArgument(
+				'name',
+				InputArgument::REQUIRED,
+				'Name of the config to set'
+			)
+			->addOption(
+				'value',
+				null,
+				InputOption::VALUE_REQUIRED,
+				'The new value of the config'
+			)
+			->addOption(
+				'update-only',
+				null,
+				InputOption::VALUE_NONE,
+				'Only updates the value, if it is not set before, it is not being added'
+			)
+		;
+	}
+
+	protected function execute(InputInterface $input, OutputInterface $output) {
+		$configName = $input->getArgument('name');
+
+		if (!in_array($configName, $this->systemConfig->getKeys()) && $input->hasParameterOption('--update-only')) {
+			$output->writeln('<comment>Value not updated, as it has not been set before.</comment>');
+			return 1;
+		}
+		$configValue = $input->getOption('value');
+
+		$this->systemConfig->setValue($configName, $configValue);
+		$output->writeln('<info>System config value ' . $configName . ' set to ' . $configValue . '</info>');
+		return 0;
+	}
+}
diff --git a/core/register_command.php b/core/register_command.php
index 13010b93a934fdb803c4d2cb4512d0d12d373fc8..8815eca6b6b337eb2cc347dc6c332f3d6a5b10b3 100644
--- a/core/register_command.php
+++ b/core/register_command.php
@@ -32,31 +32,44 @@ $application->add(new OC\Core\Command\App\CheckCode());
 $application->add(new OC\Core\Command\L10n\CreateJs());
 
 if (\OC::$server->getConfig()->getSystemValue('installed', false)) {
-	$repair = new \OC\Repair(\OC\Repair::getRepairSteps());
-
-	$application->add(new OC\Core\Command\Db\GenerateChangeScript());
-	$application->add(new OC\Core\Command\Db\ConvertType(\OC::$server->getConfig(), new \OC\DB\ConnectionFactory()));
-	$application->add(new OC\Core\Command\Upgrade(\OC::$server->getConfig()));
-	$application->add(new OC\Core\Command\Maintenance\SingleUser());
-	$application->add(new OC\Core\Command\Maintenance\Mode(\OC::$server->getConfig()));
 	$application->add(new OC\Core\Command\App\Disable());
 	$application->add(new OC\Core\Command\App\Enable());
 	$application->add(new OC\Core\Command\App\ListApps());
-	$application->add(new OC\Core\Command\Maintenance\Repair($repair, \OC::$server->getConfig()));
-	$application->add(new OC\Core\Command\User\Add(\OC::$server->getUserManager(), \OC::$server->getGroupManager()));
-	$application->add(new OC\Core\Command\User\Delete(\OC::$server->getUserManager()));
-	$application->add(new OC\Core\Command\User\LastSeen(\OC::$server->getUserManager()));
-	$application->add(new OC\Core\Command\User\Report(\OC::$server->getUserManager()));
-	$application->add(new OC\Core\Command\User\ResetPassword(\OC::$server->getUserManager()));
+
 	$application->add(new OC\Core\Command\Background\Cron(\OC::$server->getConfig()));
 	$application->add(new OC\Core\Command\Background\WebCron(\OC::$server->getConfig()));
 	$application->add(new OC\Core\Command\Background\Ajax(\OC::$server->getConfig()));
+
+	$application->add(new OC\Core\Command\Config\App\DeleteConfig(\OC::$server->getConfig()));
+	$application->add(new OC\Core\Command\Config\App\GetConfig(\OC::$server->getConfig()));
+	$application->add(new OC\Core\Command\Config\App\SetConfig(\OC::$server->getConfig()));
+	$application->add(new OC\Core\Command\Config\Import(\OC::$server->getConfig()));
+	$application->add(new OC\Core\Command\Config\ListConfigs(\OC::$server->getSystemConfig(), \OC::$server->getAppConfig()));
+	$application->add(new OC\Core\Command\Config\System\DeleteConfig(\OC::$server->getSystemConfig()));
+	$application->add(new OC\Core\Command\Config\System\GetConfig(\OC::$server->getSystemConfig()));
+	$application->add(new OC\Core\Command\Config\System\SetConfig(\OC::$server->getSystemConfig()));
+
+	$application->add(new OC\Core\Command\Db\GenerateChangeScript());
+	$application->add(new OC\Core\Command\Db\ConvertType(\OC::$server->getConfig(), new \OC\DB\ConnectionFactory()));
+
 	$application->add(new OC\Core\Command\Encryption\Disable(\OC::$server->getConfig()));
 	$application->add(new OC\Core\Command\Encryption\Enable(\OC::$server->getConfig(), \OC::$server->getEncryptionManager()));
 	$application->add(new OC\Core\Command\Encryption\ListModules(\OC::$server->getEncryptionManager()));
 	$application->add(new OC\Core\Command\Encryption\SetDefaultModule(\OC::$server->getEncryptionManager()));
 	$application->add(new OC\Core\Command\Encryption\Status(\OC::$server->getEncryptionManager()));
+
 	$application->add(new OC\Core\Command\Maintenance\MimeTypesJS());
+	$application->add(new OC\Core\Command\Maintenance\Mode(\OC::$server->getConfig()));
+	$application->add(new OC\Core\Command\Maintenance\Repair(new \OC\Repair(\OC\Repair::getRepairSteps()), \OC::$server->getConfig()));
+	$application->add(new OC\Core\Command\Maintenance\SingleUser());
+
+	$application->add(new OC\Core\Command\Upgrade(\OC::$server->getConfig()));
+
+	$application->add(new OC\Core\Command\User\Add(\OC::$server->getUserManager(), \OC::$server->getGroupManager()));
+	$application->add(new OC\Core\Command\User\Delete(\OC::$server->getUserManager()));
+	$application->add(new OC\Core\Command\User\LastSeen(\OC::$server->getUserManager()));
+	$application->add(new OC\Core\Command\User\Report(\OC::$server->getUserManager()));
+	$application->add(new OC\Core\Command\User\ResetPassword(\OC::$server->getUserManager()));
 } else {
 	$application->add(new OC\Core\Command\Maintenance\Install(\OC::$server->getConfig()));
 }
diff --git a/issue_template.md b/issue_template.md
index b0b24e56df04e753fd5e4c2739f19a5b4c327b83..3859ea1c414f51310a18cd8b5861b0b6b252b48c 100644
--- a/issue_template.md
+++ b/issue_template.md
@@ -33,6 +33,12 @@ from within your ownCloud installation folder
 **The content of config/config.php:**
 
 ```
+If you have access to your command line run e.g.:
+sudo -u www-data php occ config:list system --public
+from within your ownCloud installation folder
+
+or 
+
 Insert your config.php content here
 (Without the database password, passwordsalt and secret)
 ```
diff --git a/lib/private/systemconfig.php b/lib/private/systemconfig.php
index 451ccd85e2fde94ef96121e76c0ae60ce6ca6ef9..13b0959768ae1aa0338c579e2ec9deda2b4a93e9 100644
--- a/lib/private/systemconfig.php
+++ b/lib/private/systemconfig.php
@@ -28,6 +28,14 @@ namespace OC;
  * fixes cyclic DI: AllConfig needs AppConfig needs Database needs AllConfig
  */
 class SystemConfig {
+	/**
+	 * Lists all available config keys
+	 * @return array an array of key names
+	 */
+	public function getKeys() {
+		return \OC_Config::getKeys();
+	}
+
 	/**
 	 * Sets a new system wide value
 	 *
diff --git a/tests/core/command/config/app/deleteconfigtest.php b/tests/core/command/config/app/deleteconfigtest.php
new file mode 100644
index 0000000000000000000000000000000000000000..7056e1b1ff93816a895bdbb0cbd10f2cf4af8806
--- /dev/null
+++ b/tests/core/command/config/app/deleteconfigtest.php
@@ -0,0 +1,123 @@
+<?php
+/**
+ * @author Joas Schilling <nickvergessen@owncloud.com>
+ *
+ * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @license AGPL-3.0
+ *
+ * This code is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License, version 3,
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License, version 3,
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>
+ *
+ */
+
+namespace Tests\Core\Command\Config\App;
+
+
+use OC\Core\Command\Config\App\DeleteConfig;
+use Test\TestCase;
+
+class DeleteConfigTest extends TestCase {
+	/** @var \PHPUnit_Framework_MockObject_MockObject */
+	protected $config;
+
+	/** @var \PHPUnit_Framework_MockObject_MockObject */
+	protected $consoleInput;
+	/** @var \PHPUnit_Framework_MockObject_MockObject */
+	protected $consoleOutput;
+
+	/** @var \Symfony\Component\Console\Command\Command */
+	protected $command;
+
+	protected function setUp() {
+		parent::setUp();
+
+		$config = $this->config = $this->getMockBuilder('OCP\IConfig')
+			->disableOriginalConstructor()
+			->getMock();
+		$this->consoleInput = $this->getMock('Symfony\Component\Console\Input\InputInterface');
+		$this->consoleOutput = $this->getMock('Symfony\Component\Console\Output\OutputInterface');
+
+		/** @var \OCP\IConfig $config */
+		$this->command = new DeleteConfig($config);
+	}
+
+
+	public function deleteData() {
+		return [
+			[
+				'name',
+				true,
+				true,
+				0,
+				'info',
+			],
+			[
+				'name',
+				true,
+				false,
+				0,
+				'info',
+			],
+			[
+				'name',
+				false,
+				false,
+				0,
+				'info',
+			],
+			[
+				'name',
+				false,
+				true,
+				1,
+				'error',
+			],
+		];
+	}
+
+	/**
+	 * @dataProvider deleteData
+	 *
+	 * @param string $configName
+	 * @param bool $configExists
+	 * @param bool $checkIfExists
+	 * @param int $expectedReturn
+	 * @param string $expectedMessage
+	 */
+	public function testDelete($configName, $configExists, $checkIfExists, $expectedReturn, $expectedMessage) {
+		$this->config->expects(($checkIfExists) ? $this->once() : $this->never())
+			->method('getAppKeys')
+			->with('app-name')
+			->willReturn($configExists ? [$configName] : []);
+
+		$this->config->expects(($expectedReturn === 0) ? $this->once() : $this->never())
+			->method('deleteAppValue')
+			->with('app-name', $configName);
+
+		$this->consoleInput->expects($this->exactly(2))
+			->method('getArgument')
+			->willReturnMap([
+				['app', 'app-name'],
+				['name', $configName],
+			]);
+		$this->consoleInput->expects($this->any())
+			->method('hasParameterOption')
+			->with('--error-if-not-exists')
+			->willReturn($checkIfExists);
+
+		$this->consoleOutput->expects($this->any())
+			->method('writeln')
+			->with($this->stringContains($expectedMessage));
+
+		$this->assertSame($expectedReturn, $this->invokePrivate($this->command, 'execute', [$this->consoleInput, $this->consoleOutput]));
+	}
+}
diff --git a/tests/core/command/config/app/getconfigtest.php b/tests/core/command/config/app/getconfigtest.php
new file mode 100644
index 0000000000000000000000000000000000000000..1ceeb16ccf4ff946940c84e2601d31d935680603
--- /dev/null
+++ b/tests/core/command/config/app/getconfigtest.php
@@ -0,0 +1,163 @@
+<?php
+/**
+ * @author Joas Schilling <nickvergessen@owncloud.com>
+ *
+ * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @license AGPL-3.0
+ *
+ * This code is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License, version 3,
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License, version 3,
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>
+ *
+ */
+
+namespace Tests\Core\Command\Config\App;
+
+
+use OC\Core\Command\Config\App\GetConfig;
+use Test\TestCase;
+
+class GetConfigTest extends TestCase {
+	/** @var \PHPUnit_Framework_MockObject_MockObject */
+	protected $config;
+
+	/** @var \PHPUnit_Framework_MockObject_MockObject */
+	protected $consoleInput;
+	/** @var \PHPUnit_Framework_MockObject_MockObject */
+	protected $consoleOutput;
+
+	/** @var \Symfony\Component\Console\Command\Command */
+	protected $command;
+
+	protected function setUp() {
+		parent::setUp();
+
+		$config = $this->config = $this->getMockBuilder('OCP\IConfig')
+			->disableOriginalConstructor()
+			->getMock();
+		$this->consoleInput = $this->getMock('Symfony\Component\Console\Input\InputInterface');
+		$this->consoleOutput = $this->getMock('Symfony\Component\Console\Output\OutputInterface');
+
+		/** @var \OCP\IConfig $config */
+		$this->command = new GetConfig($config);
+	}
+
+
+	public function getData() {
+		return [
+			// String output as json
+			['name', 'newvalue', true, null, false, 'json', 0, json_encode('newvalue')],
+			// String output as plain text
+			['name', 'newvalue', true, null, false, 'plain', 0, 'newvalue'],
+			// String falling back to default output as json
+			['name', null, false, 'newvalue', true, 'json', 0, json_encode('newvalue')],
+			// String falling back without default: error
+			['name', null, false, null, false, 'json', 1, null],
+
+			// Int "0" output as json/plain
+			['name', 0, true, null, false, 'json', 0, json_encode(0)],
+			['name', 0, true, null, false, 'plain', 0, '0'],
+			// Int "1" output as json/plain
+			['name', 1, true, null, false, 'json', 0, json_encode(1)],
+			['name', 1, true, null, false, 'plain', 0, '1'],
+
+			// Bool "true" output as json/plain
+			['name', true, true, null, false, 'json', 0, json_encode(true)],
+			['name', true, true, null, false, 'plain', 0, 'true'],
+			// Bool "false" output as json/plain
+			['name', false, true, null, false, 'json', 0, json_encode(false)],
+			['name', false, true, null, false, 'plain', 0, 'false'],
+
+			// Null output as json/plain
+			['name', null, true, null, false, 'json', 0, json_encode(null)],
+			['name', null, true, null, false, 'plain', 0, 'null'],
+
+			// Array output as json/plain
+			['name', ['a', 'b'], true, null, false, 'json', 0, json_encode(['a', 'b'])],
+			['name', ['a', 'b'], true, null, false, 'plain', 0, "a\nb"],
+			// Key array output as json/plain
+			['name', [0 => 'a', 1 => 'b'], true, null, false, 'json', 0, json_encode(['a', 'b'])],
+			['name', [0 => 'a', 1 => 'b'], true, null, false, 'plain', 0, "a\nb"],
+			// Associative array output as json/plain
+			['name', ['a' => 1, 'b' => 2], true, null, false, 'json', 0, json_encode(['a' => 1, 'b' => 2])],
+			['name', ['a' => 1, 'b' => 2], true, null, false, 'plain', 0, "a: 1\nb: 2"],
+
+		];
+	}
+
+	/**
+	 * @dataProvider getData
+	 *
+	 * @param string $configName
+	 * @param mixed $value
+	 * @param bool $configExists
+	 * @param mixed $defaultValue
+	 * @param bool $hasDefault
+	 * @param string $outputFormat
+	 * @param int $expectedReturn
+	 * @param string $expectedMessage
+	 */
+	public function testGet($configName, $value, $configExists, $defaultValue, $hasDefault, $outputFormat, $expectedReturn, $expectedMessage) {
+		$this->config->expects($this->atLeastOnce())
+			->method('getAppKeys')
+			->with('app-name')
+			->willReturn($configExists ? [$configName] : []);
+
+		if (!$expectedReturn) {
+			if ($configExists) {
+				$this->config->expects($this->once())
+					->method('getAppValue')
+					->with('app-name', $configName)
+					->willReturn($value);
+			}
+		}
+
+		$this->consoleInput->expects($this->exactly(2))
+			->method('getArgument')
+			->willReturnMap([
+				['app', 'app-name'],
+				['name', $configName],
+			]);
+		$this->consoleInput->expects($this->any())
+			->method('getOption')
+			->willReturnMap([
+				['default-value', $defaultValue],
+				['output', $outputFormat],
+			]);
+		$this->consoleInput->expects($this->any())
+			->method('hasParameterOption')
+			->willReturnMap([
+				['--output', true],
+				['--default-value', $hasDefault],
+			]);
+
+		if ($expectedMessage !== null) {
+			global $output;
+
+			$output = '';
+			$this->consoleOutput->expects($this->any())
+				->method('writeln')
+				->willReturnCallback(function($value) {
+					global $output;
+					$output .= $value . "\n";
+					return $output;
+				});
+		}
+
+		$this->assertSame($expectedReturn, $this->invokePrivate($this->command, 'execute', [$this->consoleInput, $this->consoleOutput]));
+
+		if ($expectedMessage !== null) {
+			global $output;
+			// Remove the trailing newline
+			$this->assertSame($expectedMessage, substr($output, 0, -1));
+		}
+	}
+}
diff --git a/tests/core/command/config/app/setconfigtest.php b/tests/core/command/config/app/setconfigtest.php
new file mode 100644
index 0000000000000000000000000000000000000000..14d7b0cb7b5ca30caa96ba08cbf9dc65c181abc2
--- /dev/null
+++ b/tests/core/command/config/app/setconfigtest.php
@@ -0,0 +1,118 @@
+<?php
+/**
+ * @author Joas Schilling <nickvergessen@owncloud.com>
+ *
+ * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @license AGPL-3.0
+ *
+ * This code is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License, version 3,
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License, version 3,
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>
+ *
+ */
+
+namespace Tests\Core\Command\Config\App;
+
+
+use OC\Core\Command\Config\App\SetConfig;
+use Test\TestCase;
+
+class SetConfigTest extends TestCase {
+	/** @var \PHPUnit_Framework_MockObject_MockObject */
+	protected $config;
+
+	/** @var \PHPUnit_Framework_MockObject_MockObject */
+	protected $consoleInput;
+	/** @var \PHPUnit_Framework_MockObject_MockObject */
+	protected $consoleOutput;
+
+	/** @var \Symfony\Component\Console\Command\Command */
+	protected $command;
+
+	protected function setUp() {
+		parent::setUp();
+
+		$config = $this->config = $this->getMockBuilder('OCP\IConfig')
+			->disableOriginalConstructor()
+			->getMock();
+		$this->consoleInput = $this->getMock('Symfony\Component\Console\Input\InputInterface');
+		$this->consoleOutput = $this->getMock('Symfony\Component\Console\Output\OutputInterface');
+
+		/** @var \OCP\IConfig $config */
+		$this->command = new SetConfig($config);
+	}
+
+
+	public function setData() {
+		return [
+			[
+				'name',
+				'newvalue',
+				true,
+				true,
+				true,
+				'info',
+			],
+			[
+				'name',
+				'newvalue',
+				false,
+				true,
+				false,
+				'comment',
+			],
+		];
+	}
+
+	/**
+	 * @dataProvider setData
+	 *
+	 * @param string $configName
+	 * @param mixed $newValue
+	 * @param bool $configExists
+	 * @param bool $updateOnly
+	 * @param bool $updated
+	 * @param string $expectedMessage
+	 */
+	public function testSet($configName, $newValue, $configExists, $updateOnly, $updated, $expectedMessage) {
+		$this->config->expects($this->once())
+			->method('getAppKeys')
+			->with('app-name')
+			->willReturn($configExists ? [$configName] : []);
+
+		if ($updated) {
+			$this->config->expects($this->once())
+				->method('setAppValue')
+				->with('app-name', $configName, $newValue);
+		}
+
+		$this->consoleInput->expects($this->exactly(2))
+			->method('getArgument')
+			->willReturnMap([
+				['app', 'app-name'],
+				['name', $configName],
+			]);
+		$this->consoleInput->expects($this->any())
+			->method('getOption')
+			->with('value')
+			->willReturn($newValue);
+		$this->consoleInput->expects($this->any())
+			->method('hasParameterOption')
+			->with('--update-only')
+			->willReturn($updateOnly);
+
+		$this->consoleOutput->expects($this->any())
+			->method('writeln')
+			->with($this->stringContains($expectedMessage));
+
+		$this->invokePrivate($this->command, 'execute', [$this->consoleInput, $this->consoleOutput]);
+	}
+}
diff --git a/tests/core/command/config/importtest.php b/tests/core/command/config/importtest.php
new file mode 100644
index 0000000000000000000000000000000000000000..f14880f8bf433ce9ef199fb42bc061caa144749a
--- /dev/null
+++ b/tests/core/command/config/importtest.php
@@ -0,0 +1,185 @@
+<?php
+/**
+ * @author Joas Schilling <nickvergessen@owncloud.com>
+ *
+ * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @license AGPL-3.0
+ *
+ * This code is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License, version 3,
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License, version 3,
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>
+ *
+ */
+
+namespace Tests\Core\Command\Config;
+
+
+use OC\Core\Command\Config\Import;
+use Test\TestCase;
+
+class ImportTest extends TestCase {
+	/** @var \PHPUnit_Framework_MockObject_MockObject */
+	protected $config;
+
+	/** @var \PHPUnit_Framework_MockObject_MockObject */
+	protected $consoleInput;
+	/** @var \PHPUnit_Framework_MockObject_MockObject */
+	protected $consoleOutput;
+
+	/** @var \Symfony\Component\Console\Command\Command */
+	protected $command;
+
+	protected function setUp() {
+		parent::setUp();
+
+		$config = $this->config = $this->getMockBuilder('OCP\IConfig')
+			->disableOriginalConstructor()
+			->getMock();
+		$this->consoleInput = $this->getMock('Symfony\Component\Console\Input\InputInterface');
+		$this->consoleOutput = $this->getMock('Symfony\Component\Console\Output\OutputInterface');
+
+		/** @var \OCP\IConfig $config */
+		$this->command = new Import($config);
+	}
+
+	public function validateAppsArrayData() {
+		return [
+			[0],
+			[1],
+			[null],
+			['new \Exception()'],
+			[json_encode([])],
+		];
+	}
+
+	/**
+	 * @dataProvider validateAppsArrayData
+	 *
+	 * @param mixed $configValue
+	 */
+	public function testValidateAppsArray($configValue) {
+		$this->invokePrivate($this->command, 'validateAppsArray', [['app' => ['name' => $configValue]]]);
+		$this->assertTrue(true, 'Asserting that no exception is thrown');
+	}
+
+	public function validateAppsArrayThrowsData() {
+		return [
+			[false],
+			[true],
+			[[]],
+			[new \Exception()],
+		];
+	}
+
+	/**
+	 * @dataProvider validateAppsArrayThrowsData
+	 *
+	 * @param mixed $configValue
+	 */
+	public function testValidateAppsArrayThrows($configValue) {
+		try {
+			$this->invokePrivate($this->command, 'validateAppsArray', [['app' => ['name' => $configValue]]]);
+			$this->fail('Did not throw expected UnexpectedValueException');
+		} catch (\UnexpectedValueException $e) {
+			$this->assertStringStartsWith('Invalid app config value for "app":"name".', $e->getMessage());
+		}
+	}
+
+	public function checkTypeRecursivelyData() {
+		return [
+			[0],
+			[1],
+			[null],
+			['new \Exception()'],
+			[json_encode([])],
+			[false],
+			[true],
+			[[]],
+			[['string']],
+			[['test' => 'string']],
+			[['test' => ['sub' => 'string']]],
+		];
+	}
+
+	/**
+	 * @dataProvider checkTypeRecursivelyData
+	 *
+	 * @param mixed $configValue
+	 */
+	public function testCheckTypeRecursively($configValue) {
+		$this->invokePrivate($this->command, 'checkTypeRecursively', [$configValue, 'name']);
+		$this->assertTrue(true, 'Asserting that no exception is thrown');
+	}
+
+	public function checkTypeRecursivelyThrowsData() {
+		return [
+			[new \Exception()],
+			[[new \Exception()]],
+			[['test' => new \Exception()]],
+			[['test' => ['sub' => new \Exception()]]],
+		];
+	}
+
+	/**
+	 * @dataProvider checkTypeRecursivelyThrowsData
+	 *
+	 * @param mixed $configValue
+	 */
+	public function testCheckTypeRecursivelyThrows($configValue) {
+		try {
+			$this->invokePrivate($this->command, 'checkTypeRecursively', [$configValue, 'name']);
+			$this->fail('Did not throw expected UnexpectedValueException');
+		} catch (\UnexpectedValueException $e) {
+			$this->assertStringStartsWith('Invalid system config value for "name"', $e->getMessage());
+		}
+	}
+
+	public function validateArrayData() {
+		return [
+			[['system' => []]],
+			[['apps' => []]],
+			[['system' => [], 'apps' => []]],
+		];
+	}
+
+	/**
+	 * @dataProvider validateArrayData
+	 *
+	 * @param array $configArray
+	 */
+	public function testValidateArray($configArray) {
+		$this->invokePrivate($this->command, 'validateArray', [$configArray]);
+		$this->assertTrue(true, 'Asserting that no exception is thrown');
+	}
+
+	public function validateArrayThrowsData() {
+		return [
+			[[], 'At least one key of the following is expected:'],
+			[[0 => []], 'Found invalid entries in root'],
+			[['string' => []], 'Found invalid entries in root'],
+		];
+	}
+
+	/**
+	 * @dataProvider validateArrayThrowsData
+	 *
+	 * @param mixed $configArray
+	 * @param string $expectedException
+	 */
+	public function testValidateArrayThrows($configArray, $expectedException) {
+		try {
+			$this->invokePrivate($this->command, 'validateArray', [$configArray]);
+			$this->fail('Did not throw expected UnexpectedValueException');
+		} catch (\UnexpectedValueException $e) {
+			$this->assertStringStartsWith($expectedException, $e->getMessage());
+		}
+	}
+}
diff --git a/tests/core/command/config/listconfigstest.php b/tests/core/command/config/listconfigstest.php
new file mode 100644
index 0000000000000000000000000000000000000000..c9913d83f7fc5e87d154b138627f50b3ef6bc768
--- /dev/null
+++ b/tests/core/command/config/listconfigstest.php
@@ -0,0 +1,300 @@
+<?php
+/**
+ * @author Joas Schilling <nickvergessen@owncloud.com>
+ *
+ * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @license AGPL-3.0
+ *
+ * This code is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License, version 3,
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License, version 3,
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>
+ *
+ */
+
+namespace Tests\Core\Command\Config;
+
+
+use OC\Core\Command\Config\ListConfigs;
+use Test\TestCase;
+
+class ListConfigsTest extends TestCase {
+	/** @var \PHPUnit_Framework_MockObject_MockObject */
+	protected $appConfig;
+	/** @var \PHPUnit_Framework_MockObject_MockObject */
+	protected $systemConfig;
+
+	/** @var \PHPUnit_Framework_MockObject_MockObject */
+	protected $consoleInput;
+	/** @var \PHPUnit_Framework_MockObject_MockObject */
+	protected $consoleOutput;
+
+	/** @var \Symfony\Component\Console\Command\Command */
+	protected $command;
+
+	protected function setUp() {
+		parent::setUp();
+
+		$systemConfig = $this->systemConfig = $this->getMockBuilder('OC\SystemConfig')
+			->disableOriginalConstructor()
+			->getMock();
+		$appConfig = $this->appConfig = $this->getMockBuilder('OCP\IAppConfig')
+			->disableOriginalConstructor()
+			->getMock();
+		$this->consoleInput = $this->getMock('Symfony\Component\Console\Input\InputInterface');
+		$this->consoleOutput = $this->getMock('Symfony\Component\Console\Output\OutputInterface');
+
+		/** @var \OC\SystemConfig $systemConfig */
+		/** @var \OCP\IAppConfig $appConfig */
+		$this->command = new ListConfigs($systemConfig, $appConfig);
+	}
+
+	public function listData() {
+		return [
+			[
+				'all',
+				// config.php
+				[
+					'secret',
+					'overwrite.cli.url',
+				],
+				[
+					['secret', 'N;', 'my secret'],
+					['overwrite.cli.url', 'N;', 'http://localhost'],
+				],
+				// app config
+				[
+					['files', false, [
+						'enabled' => 'yes',
+					]],
+					['core', false, [
+						'global_cache_gc_lastrun' => '1430388388',
+					]],
+				],
+				false,
+				json_encode([
+					'system' => [
+						'overwrite.cli.url' => 'http://localhost',
+					],
+					'apps' => [
+						'core' => [
+							'global_cache_gc_lastrun' => '1430388388',
+						],
+						'files' => [
+							'enabled' => 'yes',
+						],
+					],
+				]),
+			],
+			[
+				'all',
+				// config.php
+				[
+					'secret',
+					'overwrite.cli.url',
+				],
+				[
+					['secret', 'N;', 'my secret'],
+					['overwrite.cli.url', 'N;', 'http://localhost'],
+				],
+				// app config
+				[
+					['files', false, [
+						'enabled' => 'yes',
+					]],
+					['core', false, [
+						'global_cache_gc_lastrun' => '1430388388',
+					]],
+				],
+				true,
+				json_encode([
+					'system' => [
+						'secret' => 'my secret',
+						'overwrite.cli.url' => 'http://localhost',
+					],
+					'apps' => [
+						'core' => [
+							'global_cache_gc_lastrun' => '1430388388',
+						],
+						'files' => [
+							'enabled' => 'yes',
+						],
+					],
+				]),
+			],
+			[
+				'system',
+				// config.php
+				[
+					'secret',
+					'overwrite.cli.url',
+				],
+				[
+					['secret', 'N;', 'my secret'],
+					['overwrite.cli.url', 'N;', 'http://localhost'],
+				],
+				// app config
+				[
+					['files', false, [
+						'enabled' => 'yes',
+					]],
+					['core', false, [
+						'global_cache_gc_lastrun' => '1430388388',
+					]],
+				],
+				false,
+				json_encode([
+					'system' => [
+						'overwrite.cli.url' => 'http://localhost',
+					],
+				]),
+			],
+			[
+				'system',
+				// config.php
+				[
+					'secret',
+					'overwrite.cli.url',
+				],
+				[
+					['secret', 'N;', 'my secret'],
+					['overwrite.cli.url', 'N;', 'http://localhost'],
+				],
+				// app config
+				[
+					['files', false, [
+						'enabled' => 'yes',
+					]],
+					['core', false, [
+						'global_cache_gc_lastrun' => '1430388388',
+					]],
+				],
+				true,
+				json_encode([
+					'system' => [
+						'secret' => 'my secret',
+						'overwrite.cli.url' => 'http://localhost',
+					],
+				]),
+			],
+			[
+				'files',
+				// config.php
+				[
+					'secret',
+					'overwrite.cli.url',
+				],
+				[
+					['secret', 'N;', 'my secret'],
+					['overwrite.cli.url', 'N;', 'http://localhost'],
+				],
+				// app config
+				[
+					['files', false, [
+						'enabled' => 'yes',
+					]],
+					['core', false, [
+						'global_cache_gc_lastrun' => '1430388388',
+					]],
+				],
+				false,
+				json_encode([
+					'apps' => [
+						'files' => [
+							'enabled' => 'yes',
+						],
+					],
+				]),
+			],
+			[
+				'files',
+				// config.php
+				[
+					'secret',
+					'overwrite.cli.url',
+				],
+				[
+					['secret', 'N;', 'my secret'],
+					['overwrite.cli.url', 'N;', 'http://localhost'],
+				],
+				// app config
+				[
+					['files', false, [
+						'enabled' => 'yes',
+					]],
+					['core', false, [
+						'global_cache_gc_lastrun' => '1430388388',
+					]],
+				],
+				true,
+				json_encode([
+					'apps' => [
+						'files' => [
+							'enabled' => 'yes',
+						],
+					],
+				]),
+			],
+		];
+	}
+
+	/**
+	 * @dataProvider listData
+	 *
+	 * @param string $app
+	 * @param array $systemConfigs
+	 * @param array $systemConfigMap
+	 * @param array $appConfig
+	 * @param bool $private
+	 * @param string $expected
+	 */
+	public function testList($app, $systemConfigs, $systemConfigMap, $appConfig, $private, $expected) {
+		$this->systemConfig->expects($this->any())
+			->method('getKeys')
+			->willReturn($systemConfigs);
+		$this->systemConfig->expects($this->any())
+			->method('getValue')
+			->willReturnMap($systemConfigMap);
+
+		$this->appConfig->expects($this->any())
+			->method('getApps')
+			->willReturn(['core', 'files']);
+		$this->appConfig->expects($this->any())
+			->method('getValues')
+			->willReturnMap($appConfig);
+
+		$this->consoleInput->expects($this->once())
+			->method('getArgument')
+			->with('app')
+			->willReturn($app);
+
+		$this->consoleInput->expects($this->any())
+			->method('getOption')
+			->willReturnMap([
+				['output', 'json'],
+				['private', $private],
+			]);
+
+		global $output;
+
+		$output = '';
+		$this->consoleOutput->expects($this->any())
+			->method('writeln')
+			->willReturnCallback(function($value) {
+				global $output;
+				$output .= $value . "\n";
+				return $output;
+			});
+
+		$this->invokePrivate($this->command, 'execute', [$this->consoleInput, $this->consoleOutput]);
+
+		$this->assertEquals($expected, trim($output, "\n"));
+	}
+}
diff --git a/tests/core/command/config/system/deleteconfigtest.php b/tests/core/command/config/system/deleteconfigtest.php
new file mode 100644
index 0000000000000000000000000000000000000000..aa1f93274c7ff32eebdb4a06e83b043f4d1f635d
--- /dev/null
+++ b/tests/core/command/config/system/deleteconfigtest.php
@@ -0,0 +1,120 @@
+<?php
+/**
+ * @author Joas Schilling <nickvergessen@owncloud.com>
+ *
+ * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @license AGPL-3.0
+ *
+ * This code is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License, version 3,
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License, version 3,
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>
+ *
+ */
+
+namespace Tests\Core\Command\Config\System;
+
+
+use OC\Core\Command\Config\System\DeleteConfig;
+use Test\TestCase;
+
+class DeleteConfigTest extends TestCase {
+	/** @var \PHPUnit_Framework_MockObject_MockObject */
+	protected $systemConfig;
+
+	/** @var \PHPUnit_Framework_MockObject_MockObject */
+	protected $consoleInput;
+	/** @var \PHPUnit_Framework_MockObject_MockObject */
+	protected $consoleOutput;
+
+	/** @var \Symfony\Component\Console\Command\Command */
+	protected $command;
+
+	protected function setUp() {
+		parent::setUp();
+
+		$systemConfig = $this->systemConfig = $this->getMockBuilder('OC\SystemConfig')
+			->disableOriginalConstructor()
+			->getMock();
+		$this->consoleInput = $this->getMock('Symfony\Component\Console\Input\InputInterface');
+		$this->consoleOutput = $this->getMock('Symfony\Component\Console\Output\OutputInterface');
+
+		/** @var \OC\SystemConfig $systemConfig */
+		$this->command = new DeleteConfig($systemConfig);
+	}
+
+
+	public function deleteData() {
+		return [
+			[
+				'name',
+				true,
+				true,
+				0,
+				'info',
+			],
+			[
+				'name',
+				true,
+				false,
+				0,
+				'info',
+			],
+			[
+				'name',
+				false,
+				false,
+				0,
+				'info',
+			],
+			[
+				'name',
+				false,
+				true,
+				1,
+				'error',
+			],
+		];
+	}
+
+	/**
+	 * @dataProvider deleteData
+	 *
+	 * @param string $configName
+	 * @param bool $configExists
+	 * @param bool $checkIfExists
+	 * @param int $expectedReturn
+	 * @param string $expectedMessage
+	 */
+	public function testDelete($configName, $configExists, $checkIfExists, $expectedReturn, $expectedMessage) {
+		$this->systemConfig->expects(($checkIfExists) ? $this->once() : $this->never())
+			->method('getKeys')
+			->willReturn($configExists ? [$configName] : []);
+
+		$this->systemConfig->expects(($expectedReturn === 0) ? $this->once() : $this->never())
+			->method('deleteValue')
+			->with($configName);
+
+		$this->consoleInput->expects($this->once())
+			->method('getArgument')
+			->with('name')
+			->willReturn($configName);
+		$this->consoleInput->expects($this->any())
+			->method('hasParameterOption')
+			->with('--error-if-not-exists')
+			->willReturn($checkIfExists);
+
+		$this->consoleOutput->expects($this->any())
+			->method('writeln')
+			->with($this->stringContains($expectedMessage));
+
+		$this->assertSame($expectedReturn, $this->invokePrivate($this->command, 'execute', [$this->consoleInput, $this->consoleOutput]));
+	}
+}
diff --git a/tests/core/command/config/system/getconfigtest.php b/tests/core/command/config/system/getconfigtest.php
new file mode 100644
index 0000000000000000000000000000000000000000..54dcdd434abc189b2d3085e49ee192d48a6f232a
--- /dev/null
+++ b/tests/core/command/config/system/getconfigtest.php
@@ -0,0 +1,160 @@
+<?php
+/**
+ * @author Joas Schilling <nickvergessen@owncloud.com>
+ *
+ * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @license AGPL-3.0
+ *
+ * This code is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License, version 3,
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License, version 3,
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>
+ *
+ */
+
+namespace Tests\Core\Command\Config\System;
+
+
+use OC\Core\Command\Config\System\GetConfig;
+use Test\TestCase;
+
+class GetConfigTest extends TestCase {
+	/** @var \PHPUnit_Framework_MockObject_MockObject */
+	protected $systemConfig;
+
+	/** @var \PHPUnit_Framework_MockObject_MockObject */
+	protected $consoleInput;
+	/** @var \PHPUnit_Framework_MockObject_MockObject */
+	protected $consoleOutput;
+
+	/** @var \Symfony\Component\Console\Command\Command */
+	protected $command;
+
+	protected function setUp() {
+		parent::setUp();
+
+		$systemConfig = $this->systemConfig = $this->getMockBuilder('OC\SystemConfig')
+			->disableOriginalConstructor()
+			->getMock();
+		$this->consoleInput = $this->getMock('Symfony\Component\Console\Input\InputInterface');
+		$this->consoleOutput = $this->getMock('Symfony\Component\Console\Output\OutputInterface');
+
+		/** @var \OC\SystemConfig $systemConfig */
+		$this->command = new GetConfig($systemConfig);
+	}
+
+
+	public function getData() {
+		return [
+			// String output as json
+			['name', 'newvalue', true, null, false, 'json', 0, json_encode('newvalue')],
+			// String output as plain text
+			['name', 'newvalue', true, null, false, 'plain', 0, 'newvalue'],
+			// String falling back to default output as json
+			['name', null, false, 'newvalue', true, 'json', 0, json_encode('newvalue')],
+			// String falling back without default: error
+			['name', null, false, null, false, 'json', 1, null],
+
+			// Int "0" output as json/plain
+			['name', 0, true, null, false, 'json', 0, json_encode(0)],
+			['name', 0, true, null, false, 'plain', 0, '0'],
+			// Int "1" output as json/plain
+			['name', 1, true, null, false, 'json', 0, json_encode(1)],
+			['name', 1, true, null, false, 'plain', 0, '1'],
+
+			// Bool "true" output as json/plain
+			['name', true, true, null, false, 'json', 0, json_encode(true)],
+			['name', true, true, null, false, 'plain', 0, 'true'],
+			// Bool "false" output as json/plain
+			['name', false, true, null, false, 'json', 0, json_encode(false)],
+			['name', false, true, null, false, 'plain', 0, 'false'],
+
+			// Null output as json/plain
+			['name', null, true, null, false, 'json', 0, json_encode(null)],
+			['name', null, true, null, false, 'plain', 0, 'null'],
+
+			// Array output as json/plain
+			['name', ['a', 'b'], true, null, false, 'json', 0, json_encode(['a', 'b'])],
+			['name', ['a', 'b'], true, null, false, 'plain', 0, "a\nb"],
+			// Key array output as json/plain
+			['name', [0 => 'a', 1 => 'b'], true, null, false, 'json', 0, json_encode(['a', 'b'])],
+			['name', [0 => 'a', 1 => 'b'], true, null, false, 'plain', 0, "a\nb"],
+			// Associative array output as json/plain
+			['name', ['a' => 1, 'b' => 2], true, null, false, 'json', 0, json_encode(['a' => 1, 'b' => 2])],
+			['name', ['a' => 1, 'b' => 2], true, null, false, 'plain', 0, "a: 1\nb: 2"],
+
+		];
+	}
+
+	/**
+	 * @dataProvider getData
+	 *
+	 * @param string $configName
+	 * @param mixed $value
+	 * @param bool $configExists
+	 * @param mixed $defaultValue
+	 * @param bool $hasDefault
+	 * @param string $outputFormat
+	 * @param int $expectedReturn
+	 * @param string $expectedMessage
+	 */
+	public function testGet($configName, $value, $configExists, $defaultValue, $hasDefault, $outputFormat, $expectedReturn, $expectedMessage) {
+		$this->systemConfig->expects($this->atLeastOnce())
+			->method('getKeys')
+			->willReturn($configExists ? [$configName] : []);
+
+		if (!$expectedReturn) {
+			if ($configExists) {
+				$this->systemConfig->expects($this->once())
+					->method('getValue')
+					->with($configName)
+					->willReturn($value);
+			}
+		}
+
+		$this->consoleInput->expects($this->once())
+			->method('getArgument')
+			->with('name')
+			->willReturn($configName);
+		$this->consoleInput->expects($this->any())
+			->method('getOption')
+			->willReturnMap([
+				['default-value', $defaultValue],
+				['output', $outputFormat],
+			]);
+		$this->consoleInput->expects($this->any())
+			->method('hasParameterOption')
+			->willReturnMap([
+				['--output', true],
+				['--default-value', $hasDefault],
+			]);
+
+		if ($expectedMessage !== null) {
+			global $output;
+
+			$output = '';
+			$this->consoleOutput->expects($this->any())
+				->method('writeln')
+				->willReturnCallback(function($value) {
+					global $output;
+					$output .= $value . "\n";
+					return $output;
+				});
+		}
+
+		$this->assertSame($expectedReturn, $this->invokePrivate($this->command, 'execute', [$this->consoleInput, $this->consoleOutput]));
+
+		if ($expectedMessage !== null) {
+			global $output;
+			// Remove the trailing newline
+			$this->assertSame($expectedMessage, substr($output, 0, -1));
+		}
+	}
+}
diff --git a/tests/core/command/config/system/setconfigtest.php b/tests/core/command/config/system/setconfigtest.php
new file mode 100644
index 0000000000000000000000000000000000000000..bbabee9b18f0afb0befa9faf3d19817430b0a572
--- /dev/null
+++ b/tests/core/command/config/system/setconfigtest.php
@@ -0,0 +1,115 @@
+<?php
+/**
+ * @author Joas Schilling <nickvergessen@owncloud.com>
+ *
+ * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @license AGPL-3.0
+ *
+ * This code is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License, version 3,
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License, version 3,
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>
+ *
+ */
+
+namespace Tests\Core\Command\Config\System;
+
+
+use OC\Core\Command\Config\System\SetConfig;
+use Test\TestCase;
+
+class SetConfigTest extends TestCase {
+	/** @var \PHPUnit_Framework_MockObject_MockObject */
+	protected $systemConfig;
+
+	/** @var \PHPUnit_Framework_MockObject_MockObject */
+	protected $consoleInput;
+	/** @var \PHPUnit_Framework_MockObject_MockObject */
+	protected $consoleOutput;
+
+	/** @var \Symfony\Component\Console\Command\Command */
+	protected $command;
+
+	protected function setUp() {
+		parent::setUp();
+
+		$systemConfig = $this->systemConfig = $this->getMockBuilder('OC\SystemConfig')
+			->disableOriginalConstructor()
+			->getMock();
+		$this->consoleInput = $this->getMock('Symfony\Component\Console\Input\InputInterface');
+		$this->consoleOutput = $this->getMock('Symfony\Component\Console\Output\OutputInterface');
+
+		/** @var \OC\SystemConfig $systemConfig */
+		$this->command = new SetConfig($systemConfig);
+	}
+
+
+	public function setData() {
+		return [
+			[
+				'name',
+				'newvalue',
+				true,
+				true,
+				true,
+				'info',
+			],
+			[
+				'name',
+				'newvalue',
+				false,
+				true,
+				false,
+				'comment',
+			],
+		];
+	}
+
+	/**
+	 * @dataProvider setData
+	 *
+	 * @param string $configName
+	 * @param mixed $newValue
+	 * @param bool $configExists
+	 * @param bool $updateOnly
+	 * @param bool $updated
+	 * @param string $expectedMessage
+	 */
+	public function testSet($configName, $newValue, $configExists, $updateOnly, $updated, $expectedMessage) {
+		$this->systemConfig->expects($this->once())
+			->method('getKeys')
+			->willReturn($configExists ? [$configName] : []);
+
+		if ($updated) {
+			$this->systemConfig->expects($this->once())
+				->method('setValue')
+				->with($configName, $newValue);
+		}
+
+		$this->consoleInput->expects($this->once())
+			->method('getArgument')
+			->with('name')
+			->willReturn($configName);
+		$this->consoleInput->expects($this->any())
+			->method('getOption')
+			->with('value')
+			->willReturn($newValue);
+		$this->consoleInput->expects($this->any())
+			->method('hasParameterOption')
+			->with('--update-only')
+			->willReturn($updateOnly);
+
+		$this->consoleOutput->expects($this->any())
+			->method('writeln')
+			->with($this->stringContains($expectedMessage));
+
+		$this->invokePrivate($this->command, 'execute', [$this->consoleInput, $this->consoleOutput]);
+	}
+}