Browse Source

feat: move primary object store configuration to a single place

Signed-off-by: Robin Appelman <robin@icewind.nl>
pull/52816/head
Robin Appelman 3 years ago
parent
commit
7599162c7b
  1. 8
      build/psalm-baseline.xml
  2. 1
      lib/composer/composer/autoload_classmap.php
  3. 1
      lib/composer/composer/autoload_static.php
  4. 110
      lib/private/Files/Mount/ObjectHomeMountProvider.php
  5. 62
      lib/private/Files/Mount/RootMountProvider.php
  6. 140
      lib/private/Files/ObjectStore/PrimaryObjectStoreConfig.php
  7. 6
      lib/private/Server.php
  8. 242
      tests/lib/Files/Mount/ObjectHomeMountProviderTest.php
  9. 7
      tests/lib/Files/Mount/RootMountProviderTest.php
  10. 5
      tests/lib/TestCase.php

8
build/psalm-baseline.xml

@ -3885,14 +3885,6 @@
<code><![CDATA[wrap]]></code>
</UndefinedInterfaceMethod>
</file>
<file src="lib/private/Files/Mount/ObjectHomeMountProvider.php">
<InvalidNullableReturnType>
<code><![CDATA[\OCP\Files\Mount\IMountPoint]]></code>
</InvalidNullableReturnType>
<NullableReturnStatement>
<code><![CDATA[null]]></code>
</NullableReturnStatement>
</file>
<file src="lib/private/Files/Node/File.php">
<InvalidReturnStatement>
<code><![CDATA[$this->view->hash($type, $this->path, $raw)]]></code>

1
lib/composer/composer/autoload_classmap.php

@ -1644,6 +1644,7 @@ return array(
'OC\\Files\\ObjectStore\\Mapper' => $baseDir . '/lib/private/Files/ObjectStore/Mapper.php',
'OC\\Files\\ObjectStore\\ObjectStoreScanner' => $baseDir . '/lib/private/Files/ObjectStore/ObjectStoreScanner.php',
'OC\\Files\\ObjectStore\\ObjectStoreStorage' => $baseDir . '/lib/private/Files/ObjectStore/ObjectStoreStorage.php',
'OC\\Files\\ObjectStore\\PrimaryObjectStoreConfig' => $baseDir . '/lib/private/Files/ObjectStore/PrimaryObjectStoreConfig.php',
'OC\\Files\\ObjectStore\\S3' => $baseDir . '/lib/private/Files/ObjectStore/S3.php',
'OC\\Files\\ObjectStore\\S3ConfigTrait' => $baseDir . '/lib/private/Files/ObjectStore/S3ConfigTrait.php',
'OC\\Files\\ObjectStore\\S3ConnectionTrait' => $baseDir . '/lib/private/Files/ObjectStore/S3ConnectionTrait.php',

1
lib/composer/composer/autoload_static.php

@ -1685,6 +1685,7 @@ class ComposerStaticInit749170dad3f5e7f9ca158f5a9f04f6a2
'OC\\Files\\ObjectStore\\Mapper' => __DIR__ . '/../../..' . '/lib/private/Files/ObjectStore/Mapper.php',
'OC\\Files\\ObjectStore\\ObjectStoreScanner' => __DIR__ . '/../../..' . '/lib/private/Files/ObjectStore/ObjectStoreScanner.php',
'OC\\Files\\ObjectStore\\ObjectStoreStorage' => __DIR__ . '/../../..' . '/lib/private/Files/ObjectStore/ObjectStoreStorage.php',
'OC\\Files\\ObjectStore\\PrimaryObjectStoreConfig' => __DIR__ . '/../../..' . '/lib/private/Files/ObjectStore/PrimaryObjectStoreConfig.php',
'OC\\Files\\ObjectStore\\S3' => __DIR__ . '/../../..' . '/lib/private/Files/ObjectStore/S3.php',
'OC\\Files\\ObjectStore\\S3ConfigTrait' => __DIR__ . '/../../..' . '/lib/private/Files/ObjectStore/S3ConfigTrait.php',
'OC\\Files\\ObjectStore\\S3ConnectionTrait' => __DIR__ . '/../../..' . '/lib/private/Files/ObjectStore/S3ConnectionTrait.php',

110
lib/private/Files/Mount/ObjectHomeMountProvider.php

@ -7,117 +7,39 @@
*/
namespace OC\Files\Mount;
use OC\Files\ObjectStore\HomeObjectStoreStorage;
use OC\Files\ObjectStore\PrimaryObjectStoreConfig;
use OCP\Files\Config\IHomeMountProvider;
use OCP\Files\Mount\IMountPoint;
use OCP\Files\Storage\IStorageFactory;
use OCP\IConfig;
use OCP\IUser;
use Psr\Log\LoggerInterface;
/**
* Mount provider for object store home storages
*/
class ObjectHomeMountProvider implements IHomeMountProvider {
/**
* @var IConfig
*/
private $config;
/**
* ObjectStoreHomeMountProvider constructor.
*
* @param IConfig $config
*/
public function __construct(IConfig $config) {
$this->config = $config;
public function __construct(
private PrimaryObjectStoreConfig $objectStoreConfig,
) {
}
/**
* Get the cache mount for a user
* Get the home mount for a user
*
* @param IUser $user
* @param IStorageFactory $loader
* @return \OCP\Files\Mount\IMountPoint
* @return ?IMountPoint
*/
public function getHomeMountForUser(IUser $user, IStorageFactory $loader) {
$config = $this->getMultiBucketObjectStoreConfig($user);
if ($config === null) {
$config = $this->getSingleBucketObjectStoreConfig($user);
}
if ($config === null) {
public function getHomeMountForUser(IUser $user, IStorageFactory $loader): ?IMountPoint {
$objectStoreConfig = $this->objectStoreConfig->getObjectStoreConfigForUser($user);
if ($objectStoreConfig === null) {
return null;
}
$arguments = array_merge($objectStoreConfig['arguments'], [
'objectstore' => $this->objectStoreConfig->buildObjectStore($objectStoreConfig),
'user' => $user,
]);
return new HomeMountPoint($user, '\OC\Files\ObjectStore\HomeObjectStoreStorage', '/' . $user->getUID(), $config['arguments'], $loader, null, null, self::class);
}
/**
* @param IUser $user
* @return array|null
*/
private function getSingleBucketObjectStoreConfig(IUser $user) {
$config = $this->config->getSystemValue('objectstore');
if (!is_array($config)) {
return null;
}
// sanity checks
if (empty($config['class'])) {
\OC::$server->get(LoggerInterface::class)->error('No class given for objectstore', ['app' => 'files']);
}
if (!isset($config['arguments'])) {
$config['arguments'] = [];
}
// instantiate object store implementation
$config['arguments']['objectstore'] = new $config['class']($config['arguments']);
$config['arguments']['user'] = $user;
return $config;
}
/**
* @param IUser $user
* @return array|null
*/
private function getMultiBucketObjectStoreConfig(IUser $user) {
$config = $this->config->getSystemValue('objectstore_multibucket');
if (!is_array($config)) {
return null;
}
// sanity checks
if (empty($config['class'])) {
\OC::$server->get(LoggerInterface::class)->error('No class given for objectstore', ['app' => 'files']);
}
if (!isset($config['arguments'])) {
$config['arguments'] = [];
}
$bucket = $this->config->getUserValue($user->getUID(), 'homeobjectstore', 'bucket', null);
if ($bucket === null) {
/*
* Use any provided bucket argument as prefix
* and add the mapping from username => bucket
*/
if (!isset($config['arguments']['bucket'])) {
$config['arguments']['bucket'] = '';
}
$mapper = new \OC\Files\ObjectStore\Mapper($user, $this->config);
$numBuckets = $config['arguments']['num_buckets'] ?? 64;
$config['arguments']['bucket'] .= $mapper->getBucket($numBuckets);
$this->config->setUserValue($user->getUID(), 'homeobjectstore', 'bucket', $config['arguments']['bucket']);
} else {
$config['arguments']['bucket'] = $bucket;
}
// instantiate object store implementation
$config['arguments']['objectstore'] = new $config['class']($config['arguments']);
$config['arguments']['user'] = $user;
return $config;
return new HomeMountPoint($user, HomeObjectStoreStorage::class, '/' . $user->getUID(), $arguments, $loader, null, null, self::class);
}
}

62
lib/private/Files/Mount/RootMountProvider.php

@ -10,79 +10,41 @@ namespace OC\Files\Mount;
use OC;
use OC\Files\ObjectStore\ObjectStoreStorage;
use OC\Files\ObjectStore\PrimaryObjectStoreConfig;
use OC\Files\Storage\LocalRootStorage;
use OC_App;
use OCP\Files\Config\IRootMountProvider;
use OCP\Files\Storage\IStorageFactory;
use OCP\IConfig;
use Psr\Log\LoggerInterface;
class RootMountProvider implements IRootMountProvider {
private PrimaryObjectStoreConfig $objectStoreConfig;
private IConfig $config;
private LoggerInterface $logger;
public function __construct(IConfig $config, LoggerInterface $logger) {
public function __construct(PrimaryObjectStoreConfig $objectStoreConfig, IConfig $config) {
$this->objectStoreConfig = $objectStoreConfig;
$this->config = $config;
$this->logger = $logger;
}
public function getRootMounts(IStorageFactory $loader): array {
$objectStore = $this->config->getSystemValue('objectstore', null);
$objectStoreMultiBucket = $this->config->getSystemValue('objectstore_multibucket', null);
$objectStoreConfig = $this->objectStoreConfig->getObjectStoreConfigForRoot();
if ($objectStoreMultiBucket) {
return [$this->getMultiBucketStoreRootMount($loader, $objectStoreMultiBucket)];
} elseif ($objectStore) {
return [$this->getObjectStoreRootMount($loader, $objectStore)];
if ($objectStoreConfig) {
return [$this->getObjectStoreRootMount($loader, $objectStoreConfig)];
} else {
return [$this->getLocalRootMount($loader)];
}
}
private function validateObjectStoreConfig(array &$config) {
if (empty($config['class'])) {
$this->logger->error('No class given for objectstore', ['app' => 'files']);
}
if (!isset($config['arguments'])) {
$config['arguments'] = [];
}
// instantiate object store implementation
$name = $config['class'];
if (str_starts_with($name, 'OCA\\') && substr_count($name, '\\') >= 2) {
$segments = explode('\\', $name);
OC_App::loadApp(strtolower($segments[1]));
}
}
private function getLocalRootMount(IStorageFactory $loader): MountPoint {
$configDataDirectory = $this->config->getSystemValue('datadirectory', OC::$SERVERROOT . '/data');
return new MountPoint(LocalRootStorage::class, '/', ['datadir' => $configDataDirectory], $loader, null, null, self::class);
}
private function getObjectStoreRootMount(IStorageFactory $loader, array $config): MountPoint {
$this->validateObjectStoreConfig($config);
$config['arguments']['objectstore'] = new $config['class']($config['arguments']);
// mount with plain / root object store implementation
$config['class'] = ObjectStoreStorage::class;
return new MountPoint($config['class'], '/', $config['arguments'], $loader, null, null, self::class);
}
private function getMultiBucketStoreRootMount(IStorageFactory $loader, array $config): MountPoint {
$this->validateObjectStoreConfig($config);
if (!isset($config['arguments']['bucket'])) {
$config['arguments']['bucket'] = '';
}
// put the root FS always in first bucket for multibucket configuration
$config['arguments']['bucket'] .= '0';
$config['arguments']['objectstore'] = new $config['class']($config['arguments']);
// mount with plain / root object store implementation
$config['class'] = ObjectStoreStorage::class;
private function getObjectStoreRootMount(IStorageFactory $loader, array $objectStoreConfig): MountPoint {
$arguments = array_merge($objectStoreConfig['arguments'], [
'objectstore' => $this->objectStoreConfig->buildObjectStore($objectStoreConfig),
]);
return new MountPoint($config['class'], '/', $config['arguments'], $loader, null, null, self::class);
return new MountPoint(ObjectStoreStorage::class, '/', $arguments, $loader, null, null, self::class);
}
}

140
lib/private/Files/ObjectStore/PrimaryObjectStoreConfig.php

@ -0,0 +1,140 @@
<?php
declare(strict_types=1);
/**
* SPDX-FileCopyrightText: 2025 Nextcloud GmbH and Nextcloud contributors
* SPDX-License-Identifier: AGPL-3.0-only
*/
namespace OC\Files\ObjectStore;
use OCP\App\IAppManager;
use OCP\Files\ObjectStore\IObjectStore;
use OCP\IConfig;
use OCP\IUser;
/**
* @psalm-type ObjectStoreConfig array{class: class-string<IObjectStore>, arguments: array{multibucket: bool, ...}}
*/
class PrimaryObjectStoreConfig {
public function __construct(
private readonly IConfig $config,
private readonly IAppManager $appManager,
) {
}
/**
* @param ObjectStoreConfig $config
*/
public function buildObjectStore(array $config): IObjectStore {
return new $config['class']($config['arguments']);
}
/**
* @return ?ObjectStoreConfig
*/
public function getObjectStoreConfigForRoot(): ?array {
$config = $this->getObjectStoreConfig();
if ($config && $config['arguments']['multibucket']) {
if (!isset($config['arguments']['bucket'])) {
$config['arguments']['bucket'] = '';
}
// put the root FS always in first bucket for multibucket configuration
$config['arguments']['bucket'] .= '0';
}
return $config;
}
/**
* @return ?ObjectStoreConfig
*/
public function getObjectStoreConfigForUser(IUser $user): ?array {
$config = $this->getObjectStoreConfig();
if ($config && $config['arguments']['multibucket']) {
$config['arguments']['bucket'] = $this->getBucketForUser($user, $config);
}
return $config;
}
/**
* @return ?ObjectStoreConfig
*/
private function getObjectStoreConfig(): ?array {
$objectStore = $this->config->getSystemValue('objectstore', null);
$objectStoreMultiBucket = $this->config->getSystemValue('objectstore_multibucket', null);
// new-style multibucket config uses the same 'objectstore' key but sets `'multibucket' => true`, transparently upgrade older style config
if ($objectStoreMultiBucket) {
$objectStoreMultiBucket['arguments']['multibucket'] = true;
return $this->validateObjectStoreConfig($objectStoreMultiBucket);
} elseif ($objectStore) {
return $this->validateObjectStoreConfig($objectStore);
} else {
return null;
}
}
/**
* @return ObjectStoreConfig
*/
private function validateObjectStoreConfig(array $config) {
if (!isset($config['class'])) {
throw new \Exception('No class configured for object store');
}
if (!isset($config['arguments'])) {
$config['arguments'] = [];
}
$class = $config['class'];
$arguments = $config['arguments'];
if (!is_array($arguments)) {
throw new \Exception('Configured object store arguments are not an array');
}
if (!isset($arguments['multibucket'])) {
$arguments['multibucket'] = false;
}
if (!is_bool($arguments['multibucket'])) {
throw new \Exception('arguments.multibucket must be a boolean in object store configuration');
}
if (!is_string($class)) {
throw new \Exception('Configured class for object store is not a string');
}
if (str_starts_with($class, 'OCA\\') && substr_count($class, '\\') >= 2) {
[$appId] = explode('\\', $class);
$this->appManager->loadApp(strtolower($appId));
}
if (!is_a($class, IObjectStore::class, true)) {
throw new \Exception('Configured class for object store is not an object store');
}
return [
'class' => $class,
'arguments' => $arguments,
];
}
private function getBucketForUser(IUser $user, array $config): string {
$bucket = $this->config->getUserValue($user->getUID(), 'homeobjectstore', 'bucket', null);
if ($bucket === null) {
/*
* Use any provided bucket argument as prefix
* and add the mapping from username => bucket
*/
if (!isset($config['arguments']['bucket'])) {
$config['arguments']['bucket'] = '';
}
$mapper = new Mapper($user, $this->config);
$numBuckets = isset($config['arguments']['num_buckets']) ? $config['arguments']['num_buckets'] : 64;
$bucket = $config['arguments']['bucket'] . $mapper->getBucket($numBuckets);
$this->config->setUserValue($user->getUID(), 'homeobjectstore', 'bucket', $bucket);
}
return $bucket;
}
}

6
lib/private/Server.php

@ -55,6 +55,7 @@ use OC\Files\Mount\RootMountProvider;
use OC\Files\Node\HookConnector;
use OC\Files\Node\LazyRoot;
use OC\Files\Node\Root;
use OC\Files\ObjectStore\PrimaryObjectStoreConfig;
use OC\Files\SetupManager;
use OC\Files\Storage\StorageFactory;
use OC\Files\Template\TemplateManager;
@ -819,10 +820,11 @@ class Server extends ServerContainer implements IServerContainer {
$config = $c->get(\OCP\IConfig::class);
$logger = $c->get(LoggerInterface::class);
$objectStoreConfig = $c->get(PrimaryObjectStoreConfig::class);
$manager->registerProvider(new CacheMountProvider($config));
$manager->registerHomeProvider(new LocalHomeMountProvider());
$manager->registerHomeProvider(new ObjectHomeMountProvider($config));
$manager->registerRootProvider(new RootMountProvider($config, $c->get(LoggerInterface::class)));
$manager->registerHomeProvider(new ObjectHomeMountProvider($objectStoreConfig));
$manager->registerRootProvider(new RootMountProvider($objectStoreConfig, $config));
$manager->registerRootProvider(new ObjectStorePreviewCacheMountProvider($logger, $config));
return $manager;

242
tests/lib/Files/Mount/ObjectHomeMountProviderTest.php

@ -7,6 +7,9 @@
namespace Test\Files\Mount;
use OC\Files\Mount\ObjectHomeMountProvider;
use OC\Files\ObjectStore\PrimaryObjectStoreConfig;
use OCP\App\IAppManager;
use OCP\Files\ObjectStore\IObjectStore;
use OCP\Files\Storage\IStorageFactory;
use OCP\IConfig;
use OCP\IUser;
@ -31,51 +34,54 @@ class ObjectHomeMountProviderTest extends \Test\TestCase {
$this->user = $this->createMock(IUser::class);
$this->loader = $this->createMock(IStorageFactory::class);
$this->provider = new ObjectHomeMountProvider($this->config);
$objectStoreConfig = new PrimaryObjectStoreConfig($this->config, $this->createMock(IAppManager::class));
$this->provider = new ObjectHomeMountProvider($objectStoreConfig);
}
public function testSingleBucket(): void {
$this->config->expects($this->once())
->method('getSystemValue')
->with($this->equalTo('objectstore'), '')
->willReturn([
'class' => 'Test\Files\Mount\FakeObjectStore',
]);
$this->user->expects($this->never())->method($this->anything());
$this->loader->expects($this->never())->method($this->anything());
$this->config->method('getSystemValue')
->willReturnCallback(function ($key, $default) {
if ($key === 'objectstore') {
return [
'class' => 'Test\Files\Mount\FakeObjectStore',
'arguments' => [
'foo' => 'bar'
],
];
} else {
return $default;
}
});
$config = $this->invokePrivate($this->provider, 'getSingleBucketObjectStoreConfig', [$this->user, $this->loader]);
$mount = $this->provider->getHomeMountForUser($this->user, $this->loader);
$arguments = $this->invokePrivate($mount, 'arguments');
$this->assertArrayHasKey('class', $config);
$this->assertEquals($config['class'], 'Test\Files\Mount\FakeObjectStore');
$this->assertArrayHasKey('arguments', $config);
$this->assertArrayHasKey('user', $config['arguments']);
$this->assertSame($this->user, $config['arguments']['user']);
$this->assertArrayHasKey('objectstore', $config['arguments']);
$this->assertInstanceOf('Test\Files\Mount\FakeObjectStore', $config['arguments']['objectstore']);
$objectStore = $arguments['objectstore'];
$this->assertInstanceOf(FakeObjectStore::class, $objectStore);
$this->assertEquals(['foo' => 'bar', 'multibucket' => false], $objectStore->getArguments());
}
public function testMultiBucket(): void {
$this->config->expects($this->exactly(2))
->method('getSystemValue')
->with($this->equalTo('objectstore_multibucket'), '')
->willReturn([
'class' => 'Test\Files\Mount\FakeObjectStore',
]);
$this->config->method('getSystemValue')
->willReturnCallback(function ($key, $default) {
if ($key === 'objectstore_multibucket') {
return [
'class' => 'Test\Files\Mount\FakeObjectStore',
'arguments' => [
'foo' => 'bar'
],
];
} else {
return $default;
}
});
$this->user->method('getUID')
->willReturn('uid');
$this->loader->expects($this->never())->method($this->anything());
$this->config->expects($this->once())
->method('getUserValue')
->with(
$this->equalTo('uid'),
$this->equalTo('homeobjectstore'),
$this->equalTo('bucket'),
$this->equalTo(null)
)->willReturn(null);
$this->config->method('getUserValue')
->willReturn(null);
$this->config->expects($this->once())
->method('setUserValue')
@ -87,42 +93,37 @@ class ObjectHomeMountProviderTest extends \Test\TestCase {
$this->equalTo(null)
);
$config = $this->invokePrivate($this->provider, 'getMultiBucketObjectStoreConfig', [$this->user, $this->loader]);
$mount = $this->provider->getHomeMountForUser($this->user, $this->loader);
$arguments = $this->invokePrivate($mount, 'arguments');
$this->assertArrayHasKey('class', $config);
$this->assertEquals($config['class'], 'Test\Files\Mount\FakeObjectStore');
$this->assertArrayHasKey('arguments', $config);
$this->assertArrayHasKey('user', $config['arguments']);
$this->assertSame($this->user, $config['arguments']['user']);
$this->assertArrayHasKey('objectstore', $config['arguments']);
$this->assertInstanceOf('Test\Files\Mount\FakeObjectStore', $config['arguments']['objectstore']);
$this->assertArrayHasKey('bucket', $config['arguments']);
$this->assertEquals('49', $config['arguments']['bucket']);
$objectStore = $arguments['objectstore'];
$this->assertInstanceOf(FakeObjectStore::class, $objectStore);
$this->assertEquals(['foo' => 'bar', 'bucket' => 49, 'multibucket' => true], $objectStore->getArguments());
}
public function testMultiBucketWithPrefix(): void {
$this->config->expects($this->exactly(2))
->method('getSystemValue')
->with('objectstore_multibucket')
->willReturn([
'class' => 'Test\Files\Mount\FakeObjectStore',
'arguments' => [
'bucket' => 'myBucketPrefix',
],
]);
$this->config->method('getSystemValue')
->willReturnCallback(function ($key, $default) {
if ($key === 'objectstore_multibucket') {
return [
'class' => 'Test\Files\Mount\FakeObjectStore',
'arguments' => [
'foo' => 'bar',
'bucket' => 'myBucketPrefix',
],
];
} else {
return $default;
}
});
$this->user->method('getUID')
->willReturn('uid');
$this->loader->expects($this->never())->method($this->anything());
$this->config->expects($this->once())
$this->config
->method('getUserValue')
->with(
$this->equalTo('uid'),
$this->equalTo('homeobjectstore'),
$this->equalTo('bucket'),
$this->equalTo(null)
)->willReturn(null);
->willReturn(null);
$this->config->expects($this->once())
->method('setUserValue')
@ -134,66 +135,70 @@ class ObjectHomeMountProviderTest extends \Test\TestCase {
$this->equalTo(null)
);
$config = $this->invokePrivate($this->provider, 'getMultiBucketObjectStoreConfig', [$this->user, $this->loader]);
$mount = $this->provider->getHomeMountForUser($this->user, $this->loader);
$arguments = $this->invokePrivate($mount, 'arguments');
$this->assertArrayHasKey('class', $config);
$this->assertEquals($config['class'], 'Test\Files\Mount\FakeObjectStore');
$this->assertArrayHasKey('arguments', $config);
$this->assertArrayHasKey('user', $config['arguments']);
$this->assertSame($this->user, $config['arguments']['user']);
$this->assertArrayHasKey('objectstore', $config['arguments']);
$this->assertInstanceOf('Test\Files\Mount\FakeObjectStore', $config['arguments']['objectstore']);
$this->assertArrayHasKey('bucket', $config['arguments']);
$this->assertEquals('myBucketPrefix49', $config['arguments']['bucket']);
$objectStore = $arguments['objectstore'];
$this->assertInstanceOf(FakeObjectStore::class, $objectStore);
$this->assertEquals(['foo' => 'bar', 'bucket' => 'myBucketPrefix49', 'multibucket' => true], $objectStore->getArguments());
}
public function testMultiBucketBucketAlreadySet(): void {
$this->config->expects($this->once())
->method('getSystemValue')
->with('objectstore_multibucket')
->willReturn([
'class' => 'Test\Files\Mount\FakeObjectStore',
'arguments' => [
'bucket' => 'myBucketPrefix',
],
]);
$this->config->method('getSystemValue')
->willReturnCallback(function ($key, $default) {
if ($key === 'objectstore_multibucket') {
return [
'class' => 'Test\Files\Mount\FakeObjectStore',
'arguments' => [
'foo' => 'bar',
'bucket' => 'myBucketPrefix',
],
];
} else {
return $default;
}
});
$this->user->method('getUID')
->willReturn('uid');
$this->loader->expects($this->never())->method($this->anything());
$this->config->expects($this->once())
$this->config
->method('getUserValue')
->with(
$this->equalTo('uid'),
$this->equalTo('homeobjectstore'),
$this->equalTo('bucket'),
$this->equalTo(null)
)->willReturn('awesomeBucket1');
->willReturnCallback(function ($uid, $app, $key, $default) {
if ($uid === 'uid' && $app === 'homeobjectstore' && $key === 'bucket') {
return 'awesomeBucket1';
} else {
return $default;
}
});
$this->config->expects($this->never())
->method('setUserValue');
$config = $this->invokePrivate($this->provider, 'getMultiBucketObjectStoreConfig', [$this->user, $this->loader]);
$mount = $this->provider->getHomeMountForUser($this->user, $this->loader);
$arguments = $this->invokePrivate($mount, 'arguments');
$this->assertArrayHasKey('class', $config);
$this->assertEquals($config['class'], 'Test\Files\Mount\FakeObjectStore');
$this->assertArrayHasKey('arguments', $config);
$this->assertArrayHasKey('user', $config['arguments']);
$this->assertSame($this->user, $config['arguments']['user']);
$this->assertArrayHasKey('objectstore', $config['arguments']);
$this->assertInstanceOf('Test\Files\Mount\FakeObjectStore', $config['arguments']['objectstore']);
$this->assertArrayHasKey('bucket', $config['arguments']);
$this->assertEquals('awesomeBucket1', $config['arguments']['bucket']);
$objectStore = $arguments['objectstore'];
$this->assertInstanceOf(FakeObjectStore::class, $objectStore);
$this->assertEquals(['foo' => 'bar', 'bucket' => 'awesomeBucket1', 'multibucket' => true], $objectStore->getArguments());
}
public function testMultiBucketConfigFirst(): void {
$this->config->expects($this->exactly(2))
->method('getSystemValue')
->with('objectstore_multibucket')
->willReturn([
'class' => 'Test\Files\Mount\FakeObjectStore',
]);
$this->config->method('getSystemValue')
->willReturnCallback(function ($key, $default) {
if ($key === 'objectstore_multibucket') {
return [
'class' => 'Test\Files\Mount\FakeObjectStore',
'arguments' => [
'foo' => 'bar',
'bucket' => 'myBucketPrefix',
],
];
} else {
return $default;
}
});
$this->user->method('getUID')
->willReturn('uid');
@ -204,11 +209,15 @@ class ObjectHomeMountProviderTest extends \Test\TestCase {
}
public function testMultiBucketConfigFirstFallBackSingle(): void {
$this->config->expects($this->exactly(2))
$this->config
->method('getSystemValue')->willReturnMap([
['objectstore_multibucket', '', ''],
['objectstore', '', [
['objectstore_multibucket', null, null],
['objectstore', null, [
'class' => 'Test\Files\Mount\FakeObjectStore',
'arguments' => [
'foo' => 'bar',
'bucket' => 'myBucketPrefix',
],
]],
]);
@ -221,16 +230,17 @@ class ObjectHomeMountProviderTest extends \Test\TestCase {
}
public function testNoObjectStore(): void {
$this->config->expects($this->exactly(2))
->method('getSystemValue')
->willReturn('');
$this->config->method('getSystemValue')
->willReturnCallback(function ($key, $default) {
return $default;
});
$mount = $this->provider->getHomeMountForUser($this->user, $this->loader);
$this->assertNull($mount);
}
}
class FakeObjectStore {
class FakeObjectStore implements IObjectStore {
private $arguments;
public function __construct(array $arguments) {
@ -240,4 +250,22 @@ class FakeObjectStore {
public function getArguments() {
return $this->arguments;
}
public function getStorageId() {
}
public function readObject($urn) {
}
public function writeObject($urn, $stream, ?string $mimetype = null) {
}
public function deleteObject($urn) {
}
public function objectExists($urn) {
}
public function copyObject($from, $to) {
}
}

7
tests/lib/Files/Mount/RootMountProviderTest.php

@ -10,11 +10,12 @@ namespace Test\Files\Mount;
use OC\Files\Mount\RootMountProvider;
use OC\Files\ObjectStore\ObjectStoreStorage;
use OC\Files\ObjectStore\PrimaryObjectStoreConfig;
use OC\Files\ObjectStore\S3;
use OC\Files\Storage\LocalRootStorage;
use OC\Files\Storage\StorageFactory;
use OCP\App\IAppManager;
use OCP\IConfig;
use Psr\Log\LoggerInterface;
use Test\TestCase;
/**
@ -40,8 +41,8 @@ class RootMountProviderTest extends TestCase {
private function getProvider(array $systemConfig): RootMountProvider {
$config = $this->getConfig($systemConfig);
$provider = new RootMountProvider($config, $this->createMock(LoggerInterface::class));
return $provider;
$objectStoreConfig = new PrimaryObjectStoreConfig($config, $this->createMock(IAppManager::class));
return new RootMountProvider($objectStoreConfig, $config);
}
public function testLocal(): void {

5
tests/lib/TestCase.php

@ -15,6 +15,7 @@ use OC\Files\Filesystem;
use OC\Files\Mount\CacheMountProvider;
use OC\Files\Mount\LocalHomeMountProvider;
use OC\Files\Mount\RootMountProvider;
use OC\Files\ObjectStore\PrimaryObjectStoreConfig;
use OC\Files\SetupManager;
use OC\Template\Base;
use OCP\Command\IBus;
@ -25,7 +26,6 @@ use OCP\IDBConnection;
use OCP\IL10N;
use OCP\Lock\ILockingProvider;
use OCP\Security\ISecureRandom;
use Psr\Log\LoggerInterface;
if (version_compare(\PHPUnit\Runner\Version::id(), 10, '>=')) {
trait OnNotSuccessfulTestTrait {
@ -332,7 +332,8 @@ abstract class TestCase extends \PHPUnit\Framework\TestCase {
$config = \OC::$server->get(IConfig::class);
$mountProviderCollection->registerProvider(new CacheMountProvider($config));
$mountProviderCollection->registerHomeProvider(new LocalHomeMountProvider());
$mountProviderCollection->registerRootProvider(new RootMountProvider($config, \OC::$server->get(LoggerInterface::class)));
$objectStoreConfig = \OC::$server->get(PrimaryObjectStoreConfig::class);
$mountProviderCollection->registerRootProvider(new RootMountProvider($objectStoreConfig, $config));
$setupManager->setupRoot();

Loading…
Cancel
Save