Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions phpBB/composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,11 @@
"vimeo/psalm": "^6.13.1",
"psalm/plugin-symfony": "^v5.1.0"
},
"autoload-dev": {
"psr-4": {
"phpbb\\tests\\functional\\storage\\": "../tests/functional/storage/"
}
},
"extra": {
"branch-alias": {
"dev-master": "4.0.x-dev"
Expand Down
14 changes: 14 additions & 0 deletions phpBB/config/test/container/services.yml
Original file line number Diff line number Diff line change
@@ -1,2 +1,16 @@
imports:
- { resource: ../../default/container/services.yml }

services:
storage.adapter.db:
class: phpbb\tests\functional\storage\db_adapter
shared: false
arguments:
- '@config_text'
tags:
- { name: storage.adapter }

storage.provider.db:
class: phpbb\tests\functional\storage\db_provider
tags:
- { name: storage.provider }
124 changes: 86 additions & 38 deletions tests/functional/acp_storage_settings_test.php
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
*/
class phpbb_functional_acp_storage_settings_test extends phpbb_functional_test_case
{
public function test_storage_settings()
public function test_storage_settings_no_changes()
{
$this->add_lang(['common', 'acp/storage']);
$this->login();
Expand All @@ -30,12 +30,24 @@ public function test_storage_settings()
$crawler = self::submit($form);
$this->assertContainsLang('INFORMATION', $crawler->filter('div[class="errorbox"] > h3')->text());
$this->assertContainsLang('STORAGE_NO_CHANGES', $crawler->filter('div[class="errorbox"] > p')->text());
}

public function test_local_storage_settings()
{
global $phpbb_root_path;

$this->add_lang(['common', 'acp/storage']);
$this->login();
$this->admin_login();

// Test empty storage paths - invalid
$crawler = self::request('GET', 'adm/index.php?i=acp_storage&mode=settings&sid=' . $this->sid);
$form = $crawler->selectButton($this->lang('SUBMIT'))->form([
'attachment[provider]' => \phpbb\storage\provider\local::class,
'attachment[path]' => '',
'avatar[provider]' => \phpbb\storage\provider\local::class,
'avatar[path]' => '',
'backup[provider]' => \phpbb\storage\provider\local::class,
'backup[path]' => '',
]);
$crawler = self::submit($form);
Expand All @@ -48,46 +60,82 @@ public function test_storage_settings()
// Unix tests only
if (!defined('PHP_WINDOWS_VERSION_MAJOR'))
{
$crawler = self::request('GET', 'adm/index.php?i=acp_storage&mode=settings&sid=' . $this->sid);
$form = $crawler->selectButton($this->lang('SUBMIT'))->form();
$values = $form->getValues();
$filesystem = new \phpbb\filesystem\filesystem;
$paths = [];

$attachments_storage_path = $values['attachment[path]'];
$avatar_upload_path = $values['avatar[path]'];
$backup_storage_path = $values['backup[path]'];
// Set local storage for this test
$this->set_storage_provider(\phpbb\storage\provider\local::class);

$filesystem = new \phpbb\filesystem\filesystem;
try
{
$crawler = self::request('GET', 'adm/index.php?i=acp_storage&mode=settings&sid=' . $this->sid);
$form = $crawler->selectButton($this->lang('SUBMIT'))->form();
$values = $form->getValues();

$paths = [
'attachment' => $values['attachment[path]'],
'avatar' => $values['avatar[path]'],
'backup' => $values['backup[path]'],
];

// Make the directory not writable
global $phpbb_root_path;
$filesystem->chmod($phpbb_root_path . $attachments_storage_path, 444);
$filesystem->chmod($phpbb_root_path . $avatar_upload_path, 444);
$filesystem->chmod($phpbb_root_path . $backup_storage_path, 444);
$this->assertFalse($filesystem->is_writable($phpbb_root_path . $avatar_upload_path));

// Visit ACP Storage settings again - warning should be displayed
$crawler = self::request('GET', 'adm/index.php?i=acp_storage&mode=settings&sid=' . $this->sid);
$this->assertContainsLang('WARNING', $crawler->filter('div[class="errorbox"] > h3')->text());
$this->assertStringContainsString($this->lang('STORAGE_PATH_NOT_EXISTS', $this->lang('STORAGE_ATTACHMENT_TITLE')), $crawler->filter('div[class="errorbox"]')->text());
$this->assertStringContainsString($this->lang('STORAGE_PATH_NOT_EXISTS', $this->lang('STORAGE_AVATAR_TITLE')), $crawler->filter('div[class="errorbox"]')->text());
$this->assertStringContainsString($this->lang('STORAGE_PATH_NOT_EXISTS', $this->lang('STORAGE_BACKUP_TITLE')), $crawler->filter('div[class="errorbox"]')->text());

// Restore default state
$filesystem->chmod($phpbb_root_path . $attachments_storage_path, 777);
$filesystem->chmod($phpbb_root_path . $avatar_upload_path, 777);
$filesystem->chmod($phpbb_root_path . $backup_storage_path, 777);
$this->assertTrue($filesystem->is_writable($phpbb_root_path . $attachments_storage_path));
$this->assertTrue($filesystem->is_writable($phpbb_root_path . $avatar_upload_path));
$this->assertTrue($filesystem->is_writable($phpbb_root_path . $backup_storage_path));

$crawler = self::request('GET', 'adm/index.php?i=acp_storage&mode=settings&sid=' . $this->sid);
$this->assertStringNotContainsString($this->lang('STORAGE_PATH_NOT_SET', $this->lang('STORAGE_ATTACHMENT_TITLE')), $this->get_content());
$this->assertStringNotContainsString($this->lang('STORAGE_PATH_NOT_SET', $this->lang('STORAGE_AVATAR_TITLE')), $this->get_content());
$this->assertStringNotContainsString($this->lang('STORAGE_PATH_NOT_SET', $this->lang('STORAGE_BACKUP_TITLE')), $this->get_content());

$this->assertStringNotContainsString($this->lang('STORAGE_PATH_NOT_EXISTS', $this->lang('STORAGE_ATTACHMENT_TITLE')), $this->get_content());
$this->assertStringNotContainsString($this->lang('STORAGE_PATH_NOT_EXISTS', $this->lang('STORAGE_AVATAR_TITLE')), $this->get_content());
$this->assertStringNotContainsString($this->lang('STORAGE_PATH_NOT_EXISTS', $this->lang('STORAGE_BACKUP_TITLE')), $this->get_content());
// Make the directories not writable
foreach ($paths as $path)
{
$filesystem->chmod($phpbb_root_path . $path, 444);
$this->assertFalse($filesystem->is_writable($phpbb_root_path . $path));
}

// Visit ACP Storage settings again - warning should be displayed
$crawler = self::request('GET', 'adm/index.php?i=acp_storage&mode=settings&sid=' . $this->sid);
$this->assertContainsLang('WARNING', $crawler->filter('div[class="errorbox"] > h3')->text());
$errorbox_text = $crawler->filter('div[class="errorbox"]')->text();
foreach (array_keys($paths) as $storage_name)
{
$storage_title = $this->lang('STORAGE_' . strtoupper($storage_name) . '_TITLE');
$this->assertStringContainsString($this->lang('STORAGE_PATH_NOT_EXISTS', $storage_title), $errorbox_text);
}

// Restore default state
foreach ($paths as $path)
{
$filesystem->chmod($phpbb_root_path . $path, 777);
$this->assertTrue($filesystem->is_writable($phpbb_root_path . $path));
}

$crawler = self::request('GET', 'adm/index.php?i=acp_storage&mode=settings&sid=' . $this->sid);
$content = $this->get_content();
foreach (array_keys($paths) as $storage_name)
{
$storage_title = $this->lang('STORAGE_' . strtoupper($storage_name) . '_TITLE');
$this->assertStringNotContainsString($this->lang('STORAGE_PATH_NOT_SET', $storage_title), $content);
$this->assertStringNotContainsString($this->lang('STORAGE_PATH_NOT_EXISTS', $storage_title), $content);
}
}
finally
{
foreach ($paths as $path)
{
$filesystem->chmod($phpbb_root_path . $path, 777);
}

// Restore db storage after test is finished
$this->set_storage_provider(\phpbb\tests\functional\storage\db_provider::class);
}
}
}

private function set_storage_provider(string $provider): void
{
$config_names = [];
foreach (['attachment', 'avatar', 'backup'] as $storage_name)
{
$config_names[] = 'storage\\' . $storage_name . '\\provider';
}

$sql = 'UPDATE ' . CONFIG_TABLE . "
SET config_value = '" . $this->db->sql_escape($provider) . "'
WHERE " . $this->db->sql_in_set('config_name', $config_names);
$this->db->sql_query($sql);
$this->purge_cache();
}
}
115 changes: 115 additions & 0 deletions tests/functional/storage/db_adapter.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,115 @@
<?php
/**
*
* This file is part of the phpBB Forum Software package.
*
* @copyright (c) phpBB Limited <https://www.phpbb.com>
* @license GNU General Public License, version 2 (GPL-2.0)
*
* For full copyright and license information, please see
* the docs/CREDITS.txt file.
*
*/

namespace phpbb\tests\functional\storage;

use phpbb\config\db_text;
use phpbb\storage\adapter\adapter_interface;
use phpbb\storage\exception\storage_exception;

/**
* Database storage adapter for functional tests.
*
* File contents are kept in the test database so they remain available across
* the separate HTTP requests and PHP processes used by functional tests.
*/
class db_adapter implements adapter_interface
{
/** @var db_text */
protected $config_text;

/** @var string */
protected $storage_name;

/**
* @param db_text $config_text
*/
public function __construct(db_text $config_text)
{
$this->config_text = $config_text;
}

/**
* {@inheritdoc}
*/
public function configure(array $options): void
{
$this->storage_name = $options['storage'];
}

/**
* {@inheritdoc}
*/
public function read(string $path)
{
$content = $this->config_text->get($this->get_key($path));
$content = $content !== null ? base64_decode($content, true) : false;

if ($content === false || ($stream = fopen('php://memory', 'w+b')) === false)
{
throw new storage_exception('STORAGE_CANNOT_OPEN_FILE', $path);
}

if (fwrite($stream, $content) === false)
{
fclose($stream);
throw new storage_exception('STORAGE_CANNOT_OPEN_FILE', $path);
}
Comment on lines +63 to +67

rewind($stream);

return $stream;
}

/**
* {@inheritdoc}
*/
public function write(string $path, $resource): int
{
if (($content = stream_get_contents($resource)) === false)
{
throw new storage_exception('STORAGE_CANNOT_COPY_RESOURCE');
}

$this->config_text->set($this->get_key($path), base64_encode($content));

return strlen($content);
}

/**
* {@inheritdoc}
*/
public function delete(string $path): void
{
$this->config_text->delete($this->get_key($path));
}

/**
* {@inheritdoc}
*/
public function free_space(): float
{
return (float) PHP_INT_MAX;
}

/**
* Return the database key for a stored file.
*
* @param string $path
* @return string
*/
protected function get_key(string $path): string
{
return 'storage.db.' . hash('sha256', $this->storage_name . "\0" . $path);
}
}
62 changes: 62 additions & 0 deletions tests/functional/storage/db_provider.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
<?php
/**
*
* This file is part of the phpBB Forum Software package.
*
* @copyright (c) phpBB Limited <https://www.phpbb.com>
* @license GNU General Public License, version 2 (GPL-2.0)
*
* For full copyright and license information, please see
* the docs/CREDITS.txt file.
*
*/

namespace phpbb\tests\functional\storage;

use phpbb\storage\provider\provider_interface;

/**
* Database storage provider for functional tests.
*/
class db_provider implements provider_interface
{
/**
* {@inheritdoc}
*/
public function get_name(): string
{
return 'db';
}

/**
* {@inheritdoc}
*/
public function get_title(): string
{
return 'Database';
}

/**
* {@inheritdoc}
*/
public function get_adapter_class(): string
{
return db_adapter::class;
}

/**
* {@inheritdoc}
*/
public function get_options(): array
{
return [];
}

/**
* {@inheritdoc}
*/
public function is_available(): bool
{
return true;
}
}
Loading
Loading