|
|
# Copyright (C) 2010-2024 RhodeCode GmbH
|
|
|
#
|
|
|
# This program is free software: you can redistribute it and/or modify
|
|
|
# it under the terms of the GNU Affero General Public License, version 3
|
|
|
# (only), 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 General Public License for more details.
|
|
|
#
|
|
|
# You should have received a copy of the GNU Affero General Public License
|
|
|
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
|
#
|
|
|
# This program is dual-licensed. If you wish to learn more about the
|
|
|
# RhodeCode Enterprise Edition, including its added features, Support services,
|
|
|
# and proprietary license terms, please see https://rhodecode.com/licenses/
|
|
|
import pytest
|
|
|
|
|
|
from rhodecode.apps import file_store
|
|
|
from rhodecode.apps.file_store import config_keys
|
|
|
from rhodecode.apps.file_store.backends.filesystem_legacy import LegacyFileSystemBackend
|
|
|
from rhodecode.apps.file_store.backends.filesystem import FileSystemBackend
|
|
|
from rhodecode.apps.file_store.backends.objectstore import ObjectStoreBackend
|
|
|
from rhodecode.apps.file_store.exceptions import FileNotAllowedException, FileOverSizeException
|
|
|
|
|
|
from rhodecode.apps.file_store import utils as store_utils
|
|
|
from rhodecode.apps.file_store.tests import random_binary_file, file_store_instance
|
|
|
|
|
|
|
|
|
class TestFileStoreBackends:
|
|
|
|
|
|
@pytest.mark.parametrize('backend_type, expected_instance', [
|
|
|
(config_keys.backend_legacy_filesystem, LegacyFileSystemBackend),
|
|
|
(config_keys.backend_filesystem, FileSystemBackend),
|
|
|
(config_keys.backend_objectstore, ObjectStoreBackend),
|
|
|
])
|
|
|
def test_get_backend(self, backend_type, expected_instance, ini_settings):
|
|
|
config = ini_settings
|
|
|
config[config_keys.backend_type] = backend_type
|
|
|
f_store = store_utils.get_filestore_backend(config=config, always_init=True)
|
|
|
assert isinstance(f_store, expected_instance)
|
|
|
|
|
|
@pytest.mark.parametrize('backend_type, expected_instance', [
|
|
|
(config_keys.backend_legacy_filesystem, LegacyFileSystemBackend),
|
|
|
(config_keys.backend_filesystem, FileSystemBackend),
|
|
|
(config_keys.backend_objectstore, ObjectStoreBackend),
|
|
|
])
|
|
|
def test_store_and_read(self, backend_type, expected_instance, ini_settings, random_binary_file):
|
|
|
filename, temp_file = random_binary_file
|
|
|
config = ini_settings
|
|
|
config[config_keys.backend_type] = backend_type
|
|
|
f_store = store_utils.get_filestore_backend(config=config, always_init=True)
|
|
|
metadata = {
|
|
|
'user_uploaded': {
|
|
|
'username': 'user1',
|
|
|
'user_id': 10,
|
|
|
'ip': '10.20.30.40'
|
|
|
}
|
|
|
}
|
|
|
store_fid, metadata = f_store.store(filename, temp_file, extra_metadata=metadata)
|
|
|
assert store_fid
|
|
|
assert metadata
|
|
|
|
|
|
# read-after write
|
|
|
reader, metadata2 = f_store.fetch(store_fid)
|
|
|
assert reader
|
|
|
assert metadata2['filename'] == filename
|
|
|
|
|
|
@pytest.mark.parametrize('backend_type, expected_instance', [
|
|
|
(config_keys.backend_legacy_filesystem, LegacyFileSystemBackend),
|
|
|
(config_keys.backend_filesystem, FileSystemBackend),
|
|
|
(config_keys.backend_objectstore, ObjectStoreBackend),
|
|
|
])
|
|
|
def test_store_file_not_allowed(self, backend_type, expected_instance, ini_settings, random_binary_file):
|
|
|
filename, temp_file = random_binary_file
|
|
|
config = ini_settings
|
|
|
config[config_keys.backend_type] = backend_type
|
|
|
f_store = store_utils.get_filestore_backend(config=config, always_init=True)
|
|
|
with pytest.raises(FileNotAllowedException):
|
|
|
f_store.store('notallowed.exe', temp_file, extensions=['.txt'])
|
|
|
|
|
|
@pytest.mark.parametrize('backend_type, expected_instance', [
|
|
|
(config_keys.backend_legacy_filesystem, LegacyFileSystemBackend),
|
|
|
(config_keys.backend_filesystem, FileSystemBackend),
|
|
|
(config_keys.backend_objectstore, ObjectStoreBackend),
|
|
|
])
|
|
|
def test_store_file_over_size(self, backend_type, expected_instance, ini_settings, random_binary_file):
|
|
|
filename, temp_file = random_binary_file
|
|
|
config = ini_settings
|
|
|
config[config_keys.backend_type] = backend_type
|
|
|
f_store = store_utils.get_filestore_backend(config=config, always_init=True)
|
|
|
with pytest.raises(FileOverSizeException):
|
|
|
f_store.store('toobig.exe', temp_file, extensions=['.exe'], max_filesize=124)
|
|
|
|
|
|
@pytest.mark.parametrize('backend_type, expected_instance, extra_conf', [
|
|
|
(config_keys.backend_legacy_filesystem, LegacyFileSystemBackend, {}),
|
|
|
(config_keys.backend_filesystem, FileSystemBackend, {config_keys.filesystem_storage_path: '/tmp/test-fs-store'}),
|
|
|
(config_keys.backend_objectstore, ObjectStoreBackend, {config_keys.objectstore_bucket: 'test-bucket'}),
|
|
|
])
|
|
|
def test_store_stats_and_keys(self, backend_type, expected_instance, extra_conf, ini_settings, random_binary_file):
|
|
|
config = ini_settings
|
|
|
config[config_keys.backend_type] = backend_type
|
|
|
config.update(extra_conf)
|
|
|
|
|
|
f_store = store_utils.get_filestore_backend(config=config, always_init=True)
|
|
|
|
|
|
# purge storage before running
|
|
|
for shard, k in f_store.iter_artifacts():
|
|
|
f_store.delete(k)
|
|
|
|
|
|
for i in range(10):
|
|
|
filename, temp_file = random_binary_file
|
|
|
|
|
|
metadata = {
|
|
|
'user_uploaded': {
|
|
|
'username': 'user1',
|
|
|
'user_id': 10,
|
|
|
'ip': '10.20.30.40'
|
|
|
}
|
|
|
}
|
|
|
store_fid, metadata = f_store.store(filename, temp_file, extra_metadata=metadata)
|
|
|
assert store_fid
|
|
|
assert metadata
|
|
|
|
|
|
cnt, size, meta = f_store.get_statistics()
|
|
|
assert cnt == 10
|
|
|
assert 10 == len(list(f_store.iter_keys()))
|
|
|
|