Fix PHP exceptions and incompatibilities

Increased speed of integration tests

Make tests run with syncs as well

Signed-off-by: Christian Wolf <github@christianwolf.email>
This commit is contained in:
Christian Wolf 2022-08-03 20:50:48 +02:00
Родитель ca7ac92952
Коммит bab7b811d7
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: 9FC3120E932F73F1
28 изменённых файлов: 213 добавлений и 90 удалений

Просмотреть файл

@ -1,42 +1,137 @@
#! /bin/bash -e
BACKUP="$1"
SUBFIXTURE="$1"
echo "Restoring backup with name $BACKUP"
echo "Restoring sub-fixture $SUBFIXTURE"
echo "Cloning data files"
rsync --archive --delete --delete-delay "/dumps/$BACKUP/data/" /nextcloud/data/
SF_DIR="/dumps/current/$SUBFIXTURE"
echo "Restoring DB"
case "$INPUT_DB" in
mysql)
mysql -u root -p"$MYSQL_ROOT_PASSWORD" -h mysql < "/dumps/$BACKUP/sql/dump.sql"
;;
pgsql)
echo 'Dropping old data'
PGPASSWORD="$POSTGRES_PASSWORD" \
psql -d "$POSTGRES_DB" -h postgres -U "$POSTGRES_USER" -v 'ON_ERROR_STOP=1' <<- EOF || exit 1
DROP SCHEMA public CASCADE;
CREATE SCHEMA public;
GRANT ALL ON SCHEMA public TO $POSTGRES_USER;
GRANT ALL ON SCHEMA public TO public;
EOF
is_file_dump () {
test -f "$SF_DIR/sql/dump.sql"
}
restore_mysql_dump () {
echo "Dropping old data from the database"
mysql -u root -p"$MYSQL_ROOT_PASSWORD" -h mysql <<- EOF | tail -n +2 > /tmp/mysql_tables
SHOW TABLES;
EOF
cat /tmp/mysql_tables | sed 's@.*@DROP TABE \0;@' | mysql -u root -p"$MYSQL_ROOT_PASSWORD" -h mysql
echo "Restoring MySQL from single file dump"
mysql -u root -p"$MYSQL_ROOT_PASSWORD" -h mysql < "$SF_DIR/sql/dump.sql"
}
restore_postgres_dump () {
echo "Restoring PostgreSQL from single file dump"
echo 'Dropping old data'
PGPASSWORD="$POSTGRES_PASSWORD" \
psql -d "$POSTGRES_DB" -h postgres -U "$POSTGRES_USER" -v 'ON_ERROR_STOP=1' <<- EOF || exit 1
DROP SCHEMA public CASCADE;
CREATE SCHEMA public;
GRANT ALL ON SCHEMA public TO $POSTGRES_USER;
ALTER DEFAULT PRIVILEGES IN SCHEMA public GRANT ALL ON TABLES TO PUBLIC;
EOF
# PGPASSWORD="$POSTGRES_PASSWORD" \
# psql -d "$POSTGRES_DB" -h postgres -U "$POSTGRES_USER" <<- EOF
# \l
# \d
# SELECT * FROM oc_preferences WHERE appid='cookbook';
# EOF
echo 'Inserting dump data'
PGPASSWORD="$POSTGRES_PASSWORD" \
psql -d "$POSTGRES_DB" -h postgres -U "$POSTGRES_USER" -f "/dumps/$BACKUP/sql/dump.sql" -v 'ON_ERROR_STOP=1' || exit 1
echo 'Inserting dump data'
PGPASSWORD="$POSTGRES_PASSWORD" \
psql -d "$POSTGRES_DB" -h postgres -U "$POSTGRES_USER" -f "$SF_DIR/sql/dump.sql" -v 'ON_ERROR_STOP=1' || exit 1
# PGPASSWORD="$POSTGRES_PASSWORD" \
# psql -d "$POSTGRES_DB" -h postgres -U "$POSTGRES_USER" <<- EOF
# SELECT * FROM oc_preferences WHERE appid='cookbook';
# EOF
}
get_container_name() {
echo "cookbook_unittesting_${1}_1"
}
kill_container() {
local container_name="`get_container_name "$1"`"
echo "Killing container $container_name"
docker --log-level error kill "$container_name"
}
start_container() {
local container_name="`get_container_name "$1"`"
echo "Starting container $container_name"
docker --log-level error start "$container_name"
}
restore_db_synced_data() {
local db_path="/db/${1}"
echo "Restoring synced DB data from $SF_DIR/sql to $db_path"
sudo rsync -a --delete --delete-delay "$SF_DIR/sql/" "$db_path"
}
test_mysql_is_running() {
state=$(docker inspect --format '{{.State.Health.Status}}' "$(get_container_name mysql)")
test "$state" = "healthy"
}
test_postgres_is_running() {
PGPASSWORD="$POSTGRES_PASSWORD" \
psql -d "$POSTGRES_DB" -h postgres -U "$POSTGRES_USER" -v 'ON_ERROR_STOP=1' <<- EOF
\q
EOF
}
wait_for_container() {
container_test="$1"
i=0
while ! "$container_test"
do
sleep 0.1
let i=$i+100
if [ $i -gt 20000 ]; then
exit 1
fi
done
}
restore_mysql_sync () {
echo "Restoring MySQL from synced dump"
kill_container mysql
restore_db_synced_data mysql
start_container mysql
wait_for_container test_mysql_is_running
}
restore_postgres_sync () {
echo "Restoring PostgreSQL from synced dump"
kill_container postgres
restore_db_synced_data postgres
start_container postgres
wait_for_container test_postgres_is_running
}
# exec >> /output/reset.log 2>&1
echo "Cloning data files"
rsync --archive --delete --delete-delay "$SF_DIR/data/" /nextcloud/data/
echo "Restoring DB"
case "$INPUT_DB" in
mysql)
if is_file_dump ; then
restore_mysql_dump
else
restore_mysql_sync
fi
;;
pgsql)
if is_file_dump; then
restore_postgres_dump
else
restore_postgres_sync
fi
;;
sqlite)
echo "Doing nothing as it was already restored during data restoration."

Просмотреть файл

@ -3,7 +3,7 @@
namespace OCA\Cookbook\Exception;
class CouldNotGuessEncodingException extends \Exception {
public function __construct($message = null, $code = null, $previous = null) {
public function __construct($message = '', $code = 0, $previous = null) {
parent::__construct($message, $code, $previous);
}
}

Просмотреть файл

@ -3,7 +3,7 @@
namespace OCA\Cookbook\Exception;
class HtmlParsingException extends \Exception {
public function __construct($message = null, $code = null, $previous = null) {
public function __construct($message = '', $code = 0, $previous = null) {
parent::__construct($message, $code, $previous);
}
}

Просмотреть файл

@ -3,7 +3,7 @@
namespace OCA\Cookbook\Exception;
class ImportException extends \Exception {
public function __construct($message = null, $code = null, $previous = null) {
public function __construct($message = '', $code = 0, $previous = null) {
parent::__construct($message, $code, $previous);
}
}

Просмотреть файл

@ -3,7 +3,7 @@
namespace OCA\Cookbook\Exception;
class InvalidDurationException extends \Exception {
public function __construct($message = null, $code = null, $previous = null) {
public function __construct($message = '', $code = 0, $previous = null) {
parent::__construct($message, $code, $previous);
}
}

Просмотреть файл

@ -3,7 +3,7 @@
namespace OCA\Cookbook\Exception;
class InvalidJSONFileException extends \Exception {
public function __construct($message = null, $code = null, $previous = null) {
public function __construct($message = '', $code = 0, $previous = null) {
parent::__construct($message, $code, $previous);
}
}

Просмотреть файл

@ -3,7 +3,7 @@
namespace OCA\Cookbook\Exception;
class InvalidRecipeException extends \Exception {
public function __construct($message = null, $code = null, $previous = null) {
public function __construct($message = '', $code = 0, $previous = null) {
parent::__construct($message, $code, $previous);
}
}

Просмотреть файл

@ -3,7 +3,7 @@
namespace OCA\Cookbook\Exception;
class InvalidThumbnailTypeException extends \Exception {
public function __construct($message = null, $code = null, $previous = null) {
public function __construct($message = '', $code = 0, $previous = null) {
parent::__construct($message, $code, $previous);
}
}

Просмотреть файл

@ -3,7 +3,7 @@
namespace OCA\Cookbook\Exception;
class NoDownloadWasCarriedOutException extends \Exception {
public function __construct($message = null, $code = null, $previous = null) {
public function __construct($message = '', $code = 0, $previous = null) {
parent::__construct($message, $code, $previous);
}
}

Просмотреть файл

@ -3,7 +3,7 @@
namespace OCA\Cookbook\Exception;
class NoRecipeImageFoundException extends \Exception {
public function __construct($message = null, $code = null, $previous = null) {
public function __construct($message = '', $code = 0, $previous = null) {
parent::__construct($message, $code, $previous);
}
}

Просмотреть файл

@ -3,7 +3,7 @@
namespace OCA\Cookbook\Exception;
class NoRecipeNameGivenException extends \Exception {
public function __construct($message = null, $code = null, $previous = null) {
public function __construct($message = '', $code = 0, $previous = null) {
parent::__construct($message, $code, $previous);
}
}

Просмотреть файл

@ -3,7 +3,7 @@
namespace OCA\Cookbook\Exception;
class RecipeExistsException extends \Exception {
public function __construct($message = null, $code = null, $previous = null) {
public function __construct($message = '', $code = 0, $previous = null) {
parent::__construct($message, $code, $previous);
}
}

Просмотреть файл

@ -3,7 +3,7 @@
namespace OCA\Cookbook\Exception;
class RecipeImageExistsException extends \Exception {
public function __construct($message = null, $code = null, $previous = null) {
public function __construct($message = '', $code = 0, $previous = null) {
parent::__construct($message, $code, $previous);
}
}

Просмотреть файл

@ -3,7 +3,7 @@
namespace OCA\Cookbook\Exception;
class UserFolderNotValidException extends \Exception {
public function __construct($message = null, $code = null, $previous = null) {
public function __construct($message = '', $code = 0, $previous = null) {
parent::__construct($message, $code, $previous);
}
}

Просмотреть файл

@ -3,7 +3,7 @@
namespace OCA\Cookbook\Exception;
class UserFolderNotWritableException extends \Exception {
public function __construct($message = null, $code = null, $previous = null) {
public function __construct($message = '', $code = 0, $previous = null) {
parent::__construct($message, $code, $previous);
}
}

Просмотреть файл

@ -3,7 +3,7 @@
namespace OCA\Cookbook\Exception;
class UserNotLoggedInException extends \Exception {
public function __construct($message = null, $code = null, $previous = null) {
public function __construct($message = '', $code = 0, $previous = null) {
parent::__construct($message, $code, $previous);
}
}

Просмотреть файл

@ -3,7 +3,7 @@
namespace OCA\Cookbook\Helper\HTMLParser;
class AttributeNotFoundException extends \Exception {
public function __construct($message = null, $code = null, $previous = null) {
public function __construct($message = '', $code = 0, $previous = null) {
parent::__construct($message, $code, $previous);
}
}

Просмотреть файл

@ -117,7 +117,7 @@ class UserFolderHelper {
} catch (NotPermittedException $ex1) {
throw new UserFolderNotValidException(
$this->l->t('The user folder cannot be created due to missing permissions.'),
null,
0,
$ex1
);
}

Просмотреть файл

@ -315,7 +315,7 @@ class DbCacheService {
}
}
if (strlen(trim($category)) == 0) {
if (strlen(trim($category)) === 0) {
return null;
}
return $category;

Просмотреть файл

@ -123,7 +123,7 @@ class HtmlDownloadService {
try {
$this->downloadHelper->downloadFile($url, $opt);
} catch (NoDownloadWasCarriedOutException $ex) {
throw new ImportException($this->l->t('Exception while downloading recipe from %s.', [$url]), null, $ex);
throw new ImportException($this->l->t('Exception while downloading recipe from %s.', [$url]), 0, $ex);
}
$status = $this->downloadHelper->getStatus();

Просмотреть файл

@ -1,7 +1,7 @@
<?xml version="1.0"?>
<phpunit
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
bootstrap="tests/bootstrap.php"
bootstrap="tests/bootstrap_migration.php"
colors="true"
backupGlobals="false"
backupStaticAttributes="false"

Просмотреть файл

@ -1,5 +1,11 @@
<?php
namespace OCA\Cookbook\Helper;
function curl_exec($ch) {
return \OCA\Cookbook\tests\Integration\Helper\DownloadHelper\DownloadHelperTest::mock_curl_exec($ch);
}
namespace OCA\Cookbook\tests\Integration\Helper\DownloadHelper;
use OCA\Cookbook\Exception\NoDownloadWasCarriedOutException;
@ -26,6 +32,8 @@ class DownloadHelperTest extends TestCase {
if (file_exists('/www/.htaccess')) {
unlink('/www/.htaccess');
}
self::$useCurlMock = false;
}
protected function tearDown(): void {
@ -85,16 +93,20 @@ class DownloadHelperTest extends TestCase {
$this->assertEquals(404, $this->dut->getStatus());
}
/**
* @medium
*/
public function testFailedDownload() {
$this->expectException(NoDownloadWasCarriedOutException::class);
$opt = [
CURLOPT_TIMEOUT => 1,
CURLOPT_CONNECTTIMEOUT => 1,
];
$this->dut->downloadFile('http://www2/test.txt', $opt);
// Using mock here as the timeout causes the test to be really slow
self::$useCurlMock = true;
$this->dut->downloadFile('http://www2/test.txt');
}
private static $useCurlMock = false;
public static function mock_curl_exec($ch) {
if (self::$useCurlMock) {
throw new NoDownloadWasCarriedOutException();
} else {
return curl_exec($ch);
}
}
public function testNoContentType() {

Просмотреть файл

@ -15,15 +15,15 @@ class AppTest extends TestCase {
private $container;
public function setUp(): void {
resetEnvironmentToBackup();
parent::setUp();
$app = new App('cookbook');
$this->container = $app->getContainer();
}
public function testAppInstalled() {
/** @var IAppManager $appManager */
$appManager = $this->container->query(IAppManager::class);
$appManager->enableApp('cookbook');
$this->assertTrue($appManager->isInstalled('cookbook'));
}
}

Просмотреть файл

@ -45,8 +45,6 @@ abstract class AbstractMigrationTestCase extends TestCase {
public function setUp(): void {
parent::setUp();
resetEnvironmentToBackup('plain');
$this->hideMigrations();
$this->enableApp();
$this->restoreMigrations();

Просмотреть файл

@ -288,10 +288,15 @@ class RecipeControllerTest extends TestCase {
$_GET['size'] = $size;
}
/** @var File|Stub */
$file = $this->createStub(File::class);
$id = 123;
$this->recipeService->method('getRecipeImageFileByFolderId')->with($id, $size)->willReturn($file);
// Make teh tests stable against PHP deprecation warnings
$file->method('getMTime')->willReturn(100);
$file->method('getName')->willReturn('image.jpg');
/**
* @var FileDisplayResponse $ret
*/

Просмотреть файл

@ -1,40 +1,8 @@
<?php
require_once __DIR__ . '/bootstrap_helper.php';
require_once __DIR__ . '/../../../tests/bootstrap.php';
// Fix for "Autoload path not allowed: .../cookbook/tests/testcase.php"
\OC_App::loadApp('cookbook');
function resetEnvironmentToBackup(string $name = 'default', bool $forceprint = false) {
$output = [];
$ret = -1;
exec("./.github/actions/run-tests/reset-from-container.sh $name 2>&1", $output, $ret);
if ($ret !== 0 || $forceprint) {
echo "\nStandard output:\n";
print_r($output);
echo "Return value: $ret\n";
if ($ret !== 0) {
throw new Exception("Could not reset environment");
}
}
}
function runOCCCommand(array $args, bool $forceprint = false) {
$output = [];
$ret = -1;
$params = join(' ', array_map(function ($x) {
return escapeshellarg($x);
}, $args));
$cmd = "./.github/actions/run-tests/run-occ.sh $params 2>&1";
exec($cmd, $output, $ret);
if ($ret !== 0 || $forceprint) {
echo "\nStandard output:\n";
print_r($output);
echo "Return value: $ret\n";
if ($ret !== 0) {
throw new Exception("Could not run OCC command");
}
}
}

35
tests/bootstrap_helper.php Executable file
Просмотреть файл

@ -0,0 +1,35 @@
<?php
function resetEnvironmentToBackup(string $name = 'main', bool $forceprint = false) {
$output = [];
$ret = -1;
exec("./.github/actions/run-tests/reset-from-container.sh $name 2>&1", $output, $ret);
if ($ret !== 0 || $forceprint) {
echo "\nStandard output:\n";
print_r($output);
echo "Return value: $ret\n";
if ($ret !== 0) {
throw new Exception("Could not reset environment");
}
}
}
function runOCCCommand(array $args, bool $forceprint = false) {
$output = [];
$ret = -1;
$params = join(' ', array_map(function ($x) {
return escapeshellarg($x);
}, $args));
$cmd = "./.github/actions/run-tests/run-occ.sh $params 2>&1";
exec($cmd, $output, $ret);
if ($ret !== 0 || $forceprint) {
echo "\nStandard output:\n";
print_r($output);
echo "Return value: $ret\n";
if ($ret !== 0) {
throw new Exception("Could not run OCC command");
}
}
}

10
tests/bootstrap_migration.php Executable file
Просмотреть файл

@ -0,0 +1,10 @@
<?php
require_once __DIR__ . '/bootstrap_helper.php';
resetEnvironmentToBackup('plain', false);
require_once __DIR__ . '/../../../tests/bootstrap.php';
// Fix for "Autoload path not allowed: .../cookbook/tests/testcase.php"
\OC_App::loadApp('cookbook');