0
0
Fork 0
mirror of https://github.com/nextcloud/server.git synced 2025-02-22 07:59:13 +00:00
nextcloud_server/tests/lib/AllConfigTest.php
Joas Schilling bc750a1d09 fix(config): Throw PreconditionException always when it didn't match
Previously even when the precondition did not match, the call "passed"
when the after value was the expected one. This however can lead to
race conditions, duplicate code excutions and other things.

Signed-off-by: Joas Schilling <coding@schilljs.com>
2024-09-13 11:41:01 +00:00

511 lines
17 KiB
PHP

<?php
/**
* Copyright (c) 2014 Morris Jobke <hey@morrisjobke.de>
* This file is licensed under the Affero General Public License version 3 or
* later.
* See the COPYING-README file.
*/
namespace Test;
/**
* Class AllConfigTest
*
* @group DB
*
* @package Test
*/
use OC\SystemConfig;
use OCP\IDBConnection;
class AllConfigTest extends \Test\TestCase {
/** @var \OCP\IDBConnection */
protected $connection;
protected function getConfig($systemConfig = null, $connection = null) {
if ($this->connection === null) {
$this->connection = \OC::$server->getDatabaseConnection();
}
if ($connection === null) {
$connection = $this->connection;
}
if ($systemConfig === null) {
$systemConfig = $this->getMockBuilder('\OC\SystemConfig')
->disableOriginalConstructor()
->getMock();
}
return new \OC\AllConfig($systemConfig, $connection);
}
public function testDeleteUserValue() {
$config = $this->getConfig();
// preparation - add something to the database
$this->connection->executeUpdate(
'INSERT INTO `*PREFIX*preferences` (`userid`, `appid`, ' .
'`configkey`, `configvalue`) VALUES (?, ?, ?, ?)',
['userDelete', 'appDelete', 'keyDelete', 'valueDelete']
);
$config->deleteUserValue('userDelete', 'appDelete', 'keyDelete');
$result = $this->connection->executeQuery(
'SELECT COUNT(*) AS `count` FROM `*PREFIX*preferences` WHERE `userid` = ?',
['userDelete']
)->fetch();
$actualCount = $result['count'];
$this->assertEquals(0, $actualCount, 'There was one value in the database and after the tests there should be no entry left.');
}
public function testSetUserValue() {
$selectAllSQL = 'SELECT `userid`, `appid`, `configkey`, `configvalue` FROM `*PREFIX*preferences` WHERE `userid` = ?';
$config = $this->getConfig();
$config->setUserValue('userSet', 'appSet', 'keySet', 'valueSet');
$result = $this->connection->executeQuery($selectAllSQL, ['userSet'])->fetchAll();
$this->assertEquals(1, count($result));
$this->assertEquals([
'userid' => 'userSet',
'appid' => 'appSet',
'configkey' => 'keySet',
'configvalue' => 'valueSet'
], $result[0]);
// test if the method overwrites existing database entries
$config->setUserValue('userSet', 'appSet', 'keySet', 'valueSet2');
$result = $this->connection->executeQuery($selectAllSQL, ['userSet'])->fetchAll();
$this->assertEquals(1, count($result));
$this->assertEquals([
'userid' => 'userSet',
'appid' => 'appSet',
'configkey' => 'keySet',
'configvalue' => 'valueSet2'
], $result[0]);
// cleanup - it therefore relies on the successful execution of the previous test
$config->deleteUserValue('userSet', 'appSet', 'keySet');
}
public function testSetUserValueWithPreCondition() {
$config = $this->getConfig();
$selectAllSQL = 'SELECT `userid`, `appid`, `configkey`, `configvalue` FROM `*PREFIX*preferences` WHERE `userid` = ?';
$config->setUserValue('userPreCond', 'appPreCond', 'keyPreCond', 'valuePreCond');
$result = $this->connection->executeQuery($selectAllSQL, ['userPreCond'])->fetchAll();
$this->assertEquals(1, count($result));
$this->assertEquals([
'userid' => 'userPreCond',
'appid' => 'appPreCond',
'configkey' => 'keyPreCond',
'configvalue' => 'valuePreCond'
], $result[0]);
// test if the method overwrites existing database entries with valid precond
$config->setUserValue('userPreCond', 'appPreCond', 'keyPreCond', 'valuePreCond2', 'valuePreCond');
$result = $this->connection->executeQuery($selectAllSQL, ['userPreCond'])->fetchAll();
$this->assertEquals(1, count($result));
$this->assertEquals([
'userid' => 'userPreCond',
'appid' => 'appPreCond',
'configkey' => 'keyPreCond',
'configvalue' => 'valuePreCond2'
], $result[0]);
// cleanup
$config->deleteUserValue('userPreCond', 'appPreCond', 'keyPreCond');
}
public function dataSetUserValueUnexpectedValue() {
return [
[true],
[false],
[null],
[new \stdClass()],
];
}
/**
* @dataProvider dataSetUserValueUnexpectedValue
* @param mixed $value
*/
public function testSetUserValueUnexpectedValue($value) {
$this->expectException(\UnexpectedValueException::class);
$config = $this->getConfig();
$config->setUserValue('userSetBool', 'appSetBool', 'keySetBool', $value);
}
public function testSetUserValueWithPreConditionFailure() {
$this->expectException(\OCP\PreConditionNotMetException::class);
$config = $this->getConfig();
$selectAllSQL = 'SELECT `userid`, `appid`, `configkey`, `configvalue` FROM `*PREFIX*preferences` WHERE `userid` = ?';
$config->setUserValue('userPreCond1', 'appPreCond', 'keyPreCond', 'valuePreCond');
$result = $this->connection->executeQuery($selectAllSQL, ['userPreCond1'])->fetchAll();
$this->assertEquals(1, count($result));
$this->assertEquals([
'userid' => 'userPreCond1',
'appid' => 'appPreCond',
'configkey' => 'keyPreCond',
'configvalue' => 'valuePreCond'
], $result[0]);
// test if the method overwrites existing database entries with valid precond
$config->setUserValue('userPreCond1', 'appPreCond', 'keyPreCond', 'valuePreCond2', 'valuePreCond3');
$result = $this->connection->executeQuery($selectAllSQL, ['userPreCond1'])->fetchAll();
$this->assertEquals(1, count($result));
$this->assertEquals([
'userid' => 'userPreCond1',
'appid' => 'appPreCond',
'configkey' => 'keyPreCond',
'configvalue' => 'valuePreCond'
], $result[0]);
// cleanup
$config->deleteUserValue('userPreCond1', 'appPreCond', 'keyPreCond');
}
public function testSetUserValueWithPreConditionFailureWhenResultStillMatches(): void {
$this->expectException(\OCP\PreConditionNotMetException::class);
$config = $this->getConfig();
$selectAllSQL = 'SELECT `userid`, `appid`, `configkey`, `configvalue` FROM `*PREFIX*preferences` WHERE `userid` = ?';
$config->setUserValue('userPreCond1', 'appPreCond', 'keyPreCond', 'valuePreCond');
$result = $this->connection->executeQuery($selectAllSQL, ['userPreCond1'])->fetchAll();
$this->assertCount(1, $result);
$this->assertEquals([
'userid' => 'userPreCond1',
'appid' => 'appPreCond',
'configkey' => 'keyPreCond',
'configvalue' => 'valuePreCond'
], $result[0]);
// test if the method throws with invalid precondition when the value is the same
$config->setUserValue('userPreCond1', 'appPreCond', 'keyPreCond', 'valuePreCond', 'valuePreCond3');
$result = $this->connection->executeQuery($selectAllSQL, ['userPreCond1'])->fetchAll();
$this->assertCount(1, $result);
$this->assertEquals([
'userid' => 'userPreCond1',
'appid' => 'appPreCond',
'configkey' => 'keyPreCond',
'configvalue' => 'valuePreCond'
], $result[0]);
// cleanup
$config->deleteUserValue('userPreCond1', 'appPreCond', 'keyPreCond');
}
public function testSetUserValueUnchanged() {
// TODO - FIXME until the dependency injection is handled properly (in AllConfig)
$this->markTestSkipped('Skipped because this is just testable if database connection can be injected');
$resultMock = $this->getMockBuilder('\Doctrine\DBAL\Driver\Statement')
->disableOriginalConstructor()->getMock();
$resultMock->expects($this->once())
->method('fetchColumn')
->willReturn('valueSetUnchanged');
$connectionMock = $this->createMock(IDBConnection::class);
$connectionMock->expects($this->once())
->method('executeQuery')
->with($this->equalTo('SELECT `configvalue` FROM `*PREFIX*preferences` '.
'WHERE `userid` = ? AND `appid` = ? AND `configkey` = ?'),
$this->equalTo(['userSetUnchanged', 'appSetUnchanged', 'keySetUnchanged']))
->willReturn($resultMock);
$connectionMock->expects($this->never())
->method('executeUpdate');
$config = $this->getConfig(null, $connectionMock);
$config->setUserValue('userSetUnchanged', 'appSetUnchanged', 'keySetUnchanged', 'valueSetUnchanged');
}
public function testGetUserValue() {
$config = $this->getConfig();
// setup - it therefore relies on the successful execution of the previous test
$config->setUserValue('userGet', 'appGet', 'keyGet', 'valueGet');
$value = $config->getUserValue('userGet', 'appGet', 'keyGet');
$this->assertEquals('valueGet', $value);
$result = $this->connection->executeQuery(
'SELECT `userid`, `appid`, `configkey`, `configvalue` FROM `*PREFIX*preferences` WHERE `userid` = ?',
['userGet']
)->fetchAll();
$this->assertEquals(1, count($result));
$this->assertEquals([
'userid' => 'userGet',
'appid' => 'appGet',
'configkey' => 'keyGet',
'configvalue' => 'valueGet'
], $result[0]);
// drop data from database - but the config option should be cached in the config object
$this->connection->executeUpdate('DELETE FROM `*PREFIX*preferences` WHERE `userid` = ?', ['userGet']);
// testing the caching mechanism
$value = $config->getUserValue('userGet', 'appGet', 'keyGet');
$this->assertEquals('valueGet', $value);
$result = $this->connection->executeQuery(
'SELECT `userid`, `appid`, `configkey`, `configvalue` FROM `*PREFIX*preferences` WHERE `userid` = ?',
['userGet']
)->fetchAll();
$this->assertEquals(0, count($result));
}
public function testGetUserKeys() {
$config = $this->getConfig();
// preparation - add something to the database
$data = [
['userFetch', 'appFetch1', 'keyFetch1', 'value1'],
['userFetch', 'appFetch1', 'keyFetch2', 'value2'],
['userFetch', 'appFetch2', 'keyFetch3', 'value3'],
['userFetch', 'appFetch1', 'keyFetch4', 'value4'],
['userFetch', 'appFetch4', 'keyFetch1', 'value5'],
['userFetch', 'appFetch5', 'keyFetch1', 'value6'],
['userFetch2', 'appFetch', 'keyFetch1', 'value7']
];
foreach ($data as $entry) {
$this->connection->executeUpdate(
'INSERT INTO `*PREFIX*preferences` (`userid`, `appid`, ' .
'`configkey`, `configvalue`) VALUES (?, ?, ?, ?)',
$entry
);
}
$value = $config->getUserKeys('userFetch', 'appFetch1');
$this->assertEquals(['keyFetch1', 'keyFetch2', 'keyFetch4'], $value);
$value = $config->getUserKeys('userFetch2', 'appFetch');
$this->assertEquals(['keyFetch1'], $value);
// cleanup
$this->connection->executeUpdate('DELETE FROM `*PREFIX*preferences`');
}
public function testGetUserKeysAllInts() {
$config = $this->getConfig();
// preparation - add something to the database
$data = [
['userFetch', 'appFetch1', '123', 'value'],
['userFetch', 'appFetch1', '456', 'value'],
];
foreach ($data as $entry) {
$this->connection->executeUpdate(
'INSERT INTO `*PREFIX*preferences` (`userid`, `appid`, ' .
'`configkey`, `configvalue`) VALUES (?, ?, ?, ?)',
$entry
);
}
$value = $config->getUserKeys('userFetch', 'appFetch1');
$this->assertEquals(['123', '456'], $value);
$this->assertIsString($value[0]);
$this->assertIsString($value[1]);
// cleanup
$this->connection->executeUpdate('DELETE FROM `*PREFIX*preferences`');
}
public function testGetUserValueDefault() {
$config = $this->getConfig();
$this->assertEquals('', $config->getUserValue('userGetUnset', 'appGetUnset', 'keyGetUnset'));
$this->assertEquals(null, $config->getUserValue('userGetUnset', 'appGetUnset', 'keyGetUnset', null));
$this->assertEquals('foobar', $config->getUserValue('userGetUnset', 'appGetUnset', 'keyGetUnset', 'foobar'));
}
public function testGetUserValueForUsers() {
$config = $this->getConfig();
// preparation - add something to the database
$data = [
['userFetch1', 'appFetch2', 'keyFetch1', 'value1'],
['userFetch2', 'appFetch2', 'keyFetch1', 'value2'],
['userFetch3', 'appFetch2', 'keyFetch1', 3],
['userFetch4', 'appFetch2', 'keyFetch1', 'value4'],
['userFetch5', 'appFetch2', 'keyFetch1', 'value5'],
['userFetch6', 'appFetch2', 'keyFetch1', 'value6'],
['userFetch7', 'appFetch2', 'keyFetch1', 'value7']
];
foreach ($data as $entry) {
$this->connection->executeUpdate(
'INSERT INTO `*PREFIX*preferences` (`userid`, `appid`, ' .
'`configkey`, `configvalue`) VALUES (?, ?, ?, ?)',
$entry
);
}
$value = $config->getUserValueForUsers('appFetch2', 'keyFetch1',
['userFetch1', 'userFetch2', 'userFetch3', 'userFetch5']);
$this->assertEquals([
'userFetch1' => 'value1',
'userFetch2' => 'value2',
'userFetch3' => 3,
'userFetch5' => 'value5'
], $value);
$value = $config->getUserValueForUsers('appFetch2', 'keyFetch1',
['userFetch1', 'userFetch4', 'userFetch9']);
$this->assertEquals([
'userFetch1' => 'value1',
'userFetch4' => 'value4'
], $value, 'userFetch9 is an non-existent user and should not be shown.');
// cleanup
$this->connection->executeUpdate('DELETE FROM `*PREFIX*preferences`');
}
public function testDeleteAllUserValues() {
$config = $this->getConfig();
// preparation - add something to the database
$data = [
['userFetch3', 'appFetch1', 'keyFetch1', 'value1'],
['userFetch3', 'appFetch1', 'keyFetch2', 'value2'],
['userFetch3', 'appFetch2', 'keyFetch3', 'value3'],
['userFetch3', 'appFetch1', 'keyFetch4', 'value4'],
['userFetch3', 'appFetch4', 'keyFetch1', 'value5'],
['userFetch3', 'appFetch5', 'keyFetch1', 'value6'],
['userFetch4', 'appFetch2', 'keyFetch1', 'value7']
];
foreach ($data as $entry) {
$this->connection->executeUpdate(
'INSERT INTO `*PREFIX*preferences` (`userid`, `appid`, ' .
'`configkey`, `configvalue`) VALUES (?, ?, ?, ?)',
$entry
);
}
$config->deleteAllUserValues('userFetch3');
$result = $this->connection->executeQuery(
'SELECT COUNT(*) AS `count` FROM `*PREFIX*preferences`'
)->fetch();
$actualCount = $result['count'];
$this->assertEquals(1, $actualCount, 'After removing `userFetch3` there should be exactly 1 entry left.');
// cleanup
$this->connection->executeUpdate('DELETE FROM `*PREFIX*preferences`');
}
public function testDeleteAppFromAllUsers() {
$config = $this->getConfig();
// preparation - add something to the database
$data = [
['userFetch5', 'appFetch1', 'keyFetch1', 'value1'],
['userFetch5', 'appFetch1', 'keyFetch2', 'value2'],
['userFetch5', 'appFetch2', 'keyFetch3', 'value3'],
['userFetch5', 'appFetch1', 'keyFetch4', 'value4'],
['userFetch5', 'appFetch4', 'keyFetch1', 'value5'],
['userFetch5', 'appFetch5', 'keyFetch1', 'value6'],
['userFetch6', 'appFetch2', 'keyFetch1', 'value7']
];
foreach ($data as $entry) {
$this->connection->executeUpdate(
'INSERT INTO `*PREFIX*preferences` (`userid`, `appid`, ' .
'`configkey`, `configvalue`) VALUES (?, ?, ?, ?)',
$entry
);
}
$config->deleteAppFromAllUsers('appFetch1');
$result = $this->connection->executeQuery(
'SELECT COUNT(*) AS `count` FROM `*PREFIX*preferences`'
)->fetch();
$actualCount = $result['count'];
$this->assertEquals(4, $actualCount, 'After removing `appFetch1` there should be exactly 4 entries left.');
$config->deleteAppFromAllUsers('appFetch2');
$result = $this->connection->executeQuery(
'SELECT COUNT(*) AS `count` FROM `*PREFIX*preferences`'
)->fetch();
$actualCount = $result['count'];
$this->assertEquals(2, $actualCount, 'After removing `appFetch2` there should be exactly 2 entries left.');
// cleanup
$this->connection->executeUpdate('DELETE FROM `*PREFIX*preferences`');
}
public function testGetUsersForUserValue() {
// mock the check for the database to run the correct SQL statements for each database type
$systemConfig = $this->getMockBuilder('\OC\SystemConfig')
->disableOriginalConstructor()
->getMock();
$config = $this->getConfig($systemConfig);
// preparation - add something to the database
$data = [
['user1', 'appFetch9', 'keyFetch9', 'value9'],
['user2', 'appFetch9', 'keyFetch9', 'value9'],
['user3', 'appFetch9', 'keyFetch9', 'value8'],
['user4', 'appFetch9', 'keyFetch8', 'value9'],
['user5', 'appFetch8', 'keyFetch9', 'value9'],
['user6', 'appFetch9', 'keyFetch9', 'value9'],
];
foreach ($data as $entry) {
$this->connection->executeUpdate(
'INSERT INTO `*PREFIX*preferences` (`userid`, `appid`, ' .
'`configkey`, `configvalue`) VALUES (?, ?, ?, ?)',
$entry
);
}
$value = $config->getUsersForUserValue('appFetch9', 'keyFetch9', 'value9');
$this->assertEquals(['user1', 'user2', 'user6'], $value);
// cleanup
$this->connection->executeUpdate('DELETE FROM `*PREFIX*preferences`');
}
public function testGetUsersForUserValueCaseInsensitive() {
// mock the check for the database to run the correct SQL statements for each database type
$systemConfig = $this->createMock(SystemConfig::class);
$config = $this->getConfig($systemConfig);
$config->setUserValue('user1', 'myApp', 'myKey', 'test123');
$config->setUserValue('user2', 'myApp', 'myKey', 'TEST123');
$config->setUserValue('user3', 'myApp', 'myKey', 'test12345');
$users = $config->getUsersForUserValueCaseInsensitive('myApp', 'myKey', 'test123');
$this->assertSame(2, count($users));
$this->assertSame(['user1', 'user2'], $users);
}
}