tests: Integrate the DB in "unit" tests.

This commit is contained in:
Harald Eilertsen
2024-01-06 16:34:38 +00:00
committed by Mario
parent 6252340804
commit e3d30763da
10 changed files with 315 additions and 157 deletions

View File

@@ -1,10 +1,3 @@
# Select image from https://hub.docker.com/_/php/
#image: php:7.3
# Use a prepared Hubzilla image to optimise pipeline duration
# image: registry.gitlab.com/dawnbreak/hubzilla/core:php7.3
image: php:8.1
stages:
- test
- deploy
@@ -33,58 +26,64 @@ variables:
before_script:
# pecl and composer do not work with PHP production restrictions (from Hubzilla Docker image)
- if [ -f /usr/local/etc/php/conf.d/z_prod.ini ]; then mv /usr/local/etc/php/conf.d/z_prod.ini /usr/local/etc/php/conf.d/z_prod.ini.off; fi
# Install & enable Xdebug for code coverage reports
- pecl install xdebug
- apt-get update
- apt-get install zip unzip libjpeg-dev libpng-dev -yqq
- docker-php-ext-enable xdebug
- docker-php-ext-install gd
# Install composer
- curl -sS https://getcomposer.org/installer | php
# Install dev libraries from composer
- php ./composer.phar install --no-progress
# php.ini settings
- echo 'xdebug.mode=coverage' >> /usr/local/etc/php/php.ini
# hidden job definition with template for PHP
.job_template_php: &job_definition_php
stage: test
script:
- vendor/bin/phpunit --configuration tests/phpunit.xml --coverage-text
# Install & enable Xdebug for code coverage reports
- pecl install xdebug
- apt-get update
- apt-get install -yqq libjpeg-dev libpng-dev libpq-dev libzip-dev mariadb-client postgresql-client unzip zip
- docker-php-ext-enable xdebug
- docker-php-ext-install gd pdo_mysql pdo_pgsql zip
# Install composer
- curl -sS https://getcomposer.org/installer | php
# Install dev libraries from composer
- php ./composer.phar install --no-progress
# php.ini settings
- echo 'xdebug.mode=coverage' >> /usr/local/etc/php/php.ini
# hidden job definition with template for MySQL/MariaDB
#.job_template_mysql: &job_definition_mysql
# stage: test
# script:
# - echo "USE $MYSQL_DATABASE; $(cat ./install/schema_mysql.sql)" | mysql --user=root --password="$MYSQL_ROOT_PASSWORD" --host=mysql "$MYSQL_DATABASE"
# - echo "SHOW DATABASES;" | mysql --user=root --password="$MYSQL_ROOT_PASSWORD" --host=mysql "$MYSQL_DATABASE"
# - echo "USE $MYSQL_DATABASE; SHOW TABLES;" | mysql --user=root --password="$MYSQL_ROOT_PASSWORD" --host=mysql "$MYSQL_DATABASE"
# - vendor/bin/phpunit --configuration tests/phpunit.xml --coverage-text
.job_template_mysql: &job_definition_mysql
stage: test
variables:
HZ_TEST_DB_HOST: mysql
HZ_TEST_DB_TYPE: mysql
HZ_TEST_DB_USER: root
HZ_TEST_DB_PASS: $MYSQL_ROOT_PASSWORD
HZ_TEST_DB_DATABASE: $MYSQL_DATABASE
script:
- echo "USE $MYSQL_DATABASE; $(cat ./install/schema_mysql.sql)" | mysql --user=root --password="$MYSQL_ROOT_PASSWORD" --host=mysql "$MYSQL_DATABASE"
- echo "SHOW DATABASES;" | mysql --user=root --password="$MYSQL_ROOT_PASSWORD" --host=mysql "$MYSQL_DATABASE"
- echo "USE $MYSQL_DATABASE; SHOW TABLES;" | mysql --user=root --password="$MYSQL_ROOT_PASSWORD" --host=mysql "$MYSQL_DATABASE"
- touch dbfail.out
- vendor/bin/phpunit --configuration tests/phpunit.xml --verbose --stop-on-error --coverage-text --colors=never --log-junit tests/results/junit.xml
coverage: '/^\s*Lines:\s*\d+.\d+\%/'
# hidden job definition with template for PostgreSQL
#.job_template_postgres: &job_definition_postgres
# stage: test
# services:
# - postgres:latest
# script:
# - export PGPASSWORD=$POSTGRES_PASSWORD
# - psql --version
# - psql -h "postgres" -U "$POSTGRES_USER" -d "$POSTGRES_DB" -c "SELECT VERSION();"
# Import hubzilla's DB schema
# - psql -h "postgres" -U "$POSTGRES_USER" -v ON_ERROR_STOP=1 --quiet "$POSTGRES_DB" < ./install/schema_postgres.sql
# Show databases and relations/tables of hubzilla's database
#- psql -h "postgres" -U "$POSTGRES_USER" -l
#- psql -h "postgres" -U "$POSTGRES_USER" -d "$POSTGRES_DB" -c "\dt;"
# Run the actual tests
# - vendor/bin/phpunit --configuration tests/phpunit-pgsql.xml --testdox
.job_template_postgres: &job_definition_postgres
stage: test
variables:
HZ_TEST_DB_HOST: postgres
HZ_TEST_DB_TYPE: postgres
HZ_TEST_DB_USER: $POSTGRES_USER
HZ_TEST_DB_PASS: $POSTGRES_PASSWORD
HZ_TEST_DB_DATABASE: $POSTGRES_DB
script:
- export PGPASSWORD=$POSTGRES_PASSWORD
- psql --version
- psql -h "postgres" -U "$POSTGRES_USER" -d "$POSTGRES_DB" -c "SELECT VERSION();"
# Import hubzilla's DB schema
- psql -h "postgres" -U "$POSTGRES_USER" -v ON_ERROR_STOP=1 --quiet "$POSTGRES_DB" < ./install/schema_postgres.sql
# Show databases and relations/tables of hubzilla's database
#- psql -h "postgres" -U "$POSTGRES_USER" -l
#- psql -h "postgres" -U "$POSTGRES_USER" -d "$POSTGRES_DB" -c "\dt;"
# Run the actual tests
- touch dbfail.out
- vendor/bin/phpunit --configuration tests/phpunit.xml --verbose --stop-on-error --coverage-text --colors=never --log-junit tests/results/junit.xml
coverage: '/^\s*Lines:\s*\d+.\d+\%/'
# hidden job definition with artifacts config template
.artifacts_template:
artifacts: &artifacts_template
.artifacts_template: &artifacts_template
artifacts:
expire_in: 1 week
# Gitlab should show the results, but has problems parsing PHPUnit's junit file.
reports:
@@ -95,54 +94,22 @@ before_script:
- tests/results/
# PHP8.1
php8.1:
<<: *job_definition_php
# PHP8.0 with MySQL 5.7
#php8.0_mysql5.7:
# <<: *job_definition_mysql
# services:
# - mysql:5.7
php8.1_mysql5.7:
<<: *job_definition_mysql
<<: *artifacts_template
image: php:8.1
services:
- mysql:5.7
# PHP8.0 with MySQL 8 (latest)
#php8.0_mysql8:
# <<: *job_definition_mysql
# services:
# - name: mysql:8
# command: ["--default-authentication-plugin=mysql_native_password"]
# PHP8.0 with MariaDB 10.2
#php8.0_mariadb10.2:
# <<: *job_definition_mysql
# services:
# - name: mariadb:10.2
# alias: mysql
# PHP8.0 with MariaDB 10.3 (latest)
#php8.0_mariadb10.3:
# <<: *job_definition_mysql
# image: php:8.0
#image: registry.gitlab.com/dawnbreak/hubzilla/core:php7.3
# services:
# - name: mariadb:10.3
# alias: mysql
# PHP7.3 with PostgreSQL latest (11)
#php7.3_postgres11:
# <<: *job_definition_postgres
# artifacts: *artifacts_template
# PHP7.3 with PostgreSQL latest (11)
#php7.3_postgres11:
# <<: *job_definition_postgres
# image: registry.gitlab.com/dawnbreak/hubzilla/core:php7.3
# artifacts: *artifacts_template
# PHP8.1 with PostgreSQL 12
php8.1_postgres12:
<<: *job_definition_postgres
<<: *artifacts_template
image: php:8.1
services:
- postgres:12-alpine
# Generate Doxygen API Documentation and deploy it as GitLab pages

View File

@@ -27,9 +27,12 @@ class HTTPSig {
* @param string $alg hash algorithm (one of 'sha256','sha512')
* @return string The generated digest header string for $body
*/
static function generate_digest_header($body, $alg = 'sha256') {
if ($body === null) {
$body = '';
}
$digest = base64_encode(hash($alg, $body, true));
switch ($alg) {
case 'sha512':

63
tests/create_test_db_pgsql.sh Executable file
View File

@@ -0,0 +1,63 @@
#!/usr/bin/env bash
#
# Copyright (c) 2016 Hubzilla
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
# in the Software without restriction, including without limitation the rights
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in
# all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
# SOFTWARE.
#
# Exit if anything fails
set -e
#
# Initialize some defaults if they're not set by the environment
#
: ${DB_ROOT_USER:=postgres}
: ${DB_TEST_USER:=test_user}
: ${DB_TEST_DB:=hubzilla_test_db}
echo "Creating test db for PostgreSQL..."
if [[ "$POSTGRESQL_VERSION" == "10" ]]; then
echo "Using PostgreSQL in Docker container, need to use TCP"
export PROTO="-h localhost"
fi
# Print out some PostgreSQL information
psql --version
# Why does this hang further execution of the job?
psql $PROTO -U $DB_ROOT_USER -c "SELECT VERSION();"
# Create Hubzilla database
psql $PROTO -U $DB_ROOT_USER -v ON_ERROR_STOP=1 <<-EOSQL
DROP DATABASE IF EXISTS $DB_TEST_DB;
DROP USER IF EXISTS $DB_TEST_USER;
CREATE USER $DB_TEST_USER WITH PASSWORD 'hubzilla';
CREATE DATABASE $DB_TEST_DB WITH OWNER $DB_TEST_USER;
EOSQL
export PGPASSWORD=hubzilla
# Import table structure
echo "Importing schema..."
psql $PROTO -U $DB_TEST_USER -v ON_ERROR_STOP=1 $DB_TEST_DB < ./install/schema_postgres.sql
# Show databases and tables
psql $PROTO -U $DB_TEST_USER -l
psql $PROTO -U $DB_TEST_USER -d $DB_TEST_DB -c "\dt;"

View File

@@ -1,21 +1,20 @@
<?xml version="1.0" encoding="UTF-8"?>
<phpunit xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" bootstrap="../boot.php" colors="true" xsi:noNamespaceSchemaLocation="https://schema.phpunit.de/9.3/phpunit.xsd">
<coverage processUncoveredFiles="false" includeUncoveredFiles="false">
<include>
<directory suffix=".php">../Zotlabs/</directory>
<directory suffix=".php">../include/</directory>
</include>
</coverage>
<phpunit
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
bootstrap="../boot.php"
colors="true"
xsi:noNamespaceSchemaLocation="https://schema.phpunit.de/9.3/phpunit.xsd"
>
<php>
<var name="db_dsn" value="mysql:dbname=gitlab_ci_hubzilla;host=mysql"/>
<var name="db_username" value="root"/>
<var name="db_password" value="mysql"/>
<env name="hz_db_server" value="mysql"/>
<env name="hz_db_scheme" value="mysql"/>
<env name="hz_db_port" value=""/>
<env name="hz_db_user" value="root"/>
<env name="hz_db_pass" value="mysql"/>
<env name="hz_db_database" value="hello_world_test"/>
<includePath>..</includePath>
<env name="HZ_TEST_DB_HOST" value="db"/>
<env name="HZ_TEST_DB_TYPE" value="postgres"/>
<env name="HZ_TEST_DB_PORT" value=""/>
<env name="HZ_TEST_DB_USER" value="test_user"/>
<env name="HZ_TEST_DB_PASS" value="hubzilla"/>
<env name="HZ_TEST_DB_DATABASE" value="hubzilla_test_db"/>
<env name="HZ_TEST_DB_CHARSET" value="UTF8"/>
</php>
<testsuites>
<testsuite name="Hubzilla default Test Suite">
@@ -24,14 +23,14 @@
<testsuite name="API Test Suite">
<directory suffix="Test.php" prefix="API">./unit/</directory>
</testsuite>
<testsuite name="Ex-/Import Test Suite">
<!--<directory suffix="Test.php">./Unit/eximport/</directory>-->
</testsuite>
</testsuites>
<groups>
<exclude>
<group>postgresql</group>
</exclude>
</groups>
<!--cover reporting-->
<coverage
processUncoveredFiles="false"
cacheDirectory=".cache/phpunit"
>
<include>
<directory suffix=".php">../Zotlabs/</directory>
<directory suffix=".php">../include/</directory>
</include>
</coverage>
</phpunit>

View File

@@ -26,6 +26,7 @@ class MockApp {
*
* @param string $sql
*/
/*
function q($sql) {
$result=array(array('id'=>15,
'attag'=>'', 'network'=>'dfrn',
@@ -55,7 +56,7 @@ function q($sql) {
return $result;
}
}
*/
/**
* Replacement for dbesc.
* I don't want to test dbesc here, so
@@ -68,9 +69,11 @@ function q($sql) {
*
* @return input
*/
/*
function dbesc($str) {
return $str;
}
*/
/**
* TestCase for tag handling.

View File

@@ -63,11 +63,52 @@ class PermissionDescriptionTest extends UnitTestCase {
$this->assertNotNull($permDescSelf);
}
/**
* Test fetching permission descriptions for the current channel.
*/
public function testFromGlobalPermission() {
//$permDesc = PermissionDescription::fromGlobalPermission('view_profile');
// Initiate the global App with a channel_id
\App::$channel = array(
'channel_id' => 42,
);
$this->markTestIncomplete(
'The method fromGlobalPermission() is not yet testable ...'
// Make sure the requested permission is set for this channel.
\Zotlabs\Access\PermissionLimits::Set(
\App::$channel['channel_id'],
'view_profile',
PERMS_NETWORK
);
\Zotlabs\Access\PermissionLimits::Set(
\App::$channel['channel_id'],
'write_storage',
PERMS_SPECIFIC
);
// Set an invalid(?) permission
\Zotlabs\Access\PermissionLimits::Set(
\App::$channel['channel_id'],
'view_wiki',
1337
);
$permDesc = PermissionDescription::fromGlobalPermission('view_profile');
$this->assertEquals(
'Anybody in the Hubzilla network',
$permDesc->get_permission_description()
);
$permDesc = PermissionDescription::fromGlobalPermission('write_storage');
$this->assertEquals(
'Only connections I specifically allow',
$permDesc->get_permission_description()
);
// Permissions we don't know about will get the fallback description.
$permDesc = PermissionDescription::fromGlobalPermission('view_wiki');
$this->assertEquals(
'Visible to your default audience',
$permDesc->get_permission_description()
);
}

View File

@@ -23,12 +23,14 @@
namespace Zotlabs\Tests\Unit;
use PHPUnit\Framework\TestCase;
use Symfony\Component\Yaml\Yaml;
/*
* Make sure global constants and the global App object is available to the
* tests.
*/
require_once __DIR__ . '/../../boot.php';
require_once 'include/dba/dba_driver.php' ;
/**
* @brief Base class for our Unit Tests.
@@ -39,6 +41,95 @@ require_once __DIR__ . '/../../boot.php';
*
* @author Klaus Weidenbach
*/
abstract class UnitTestCase extends TestCase {
// when needed we can define functionality here which is used in UnitTests.
class UnitTestCase extends TestCase {
private bool $in_transaction = false;
protected array $fixtures = array();
public static function setUpBeforeClass() : void {
if ( !\DBA::$dba ) {
\DBA::dba_factory(
getenv('HZ_TEST_DB_HOST') ?: 'db',
// Use default port for db type if none specified
getenv('HZ_TEST_DB_PORT'),
getenv('HZ_TEST_DB_USER') ?: 'test_user',
getenv('HZ_TEST_DB_PASS') ?: 'hubzilla',
getenv('HZ_TEST_DB_DATABASE') ?: 'hubzilla_test_db',
Self::dbtype(getenv('HZ_TEST_DB_TYPE')),
getenv('HZ_TEST_DB_CHARSET') ?: 'UTF8',
false);
if ( !\DBA::$dba->connected ) {
$msg = "Unable to connect to db! ";
if(file_exists('dbfail.out')) {
$msg .= file_get_contents('dbfail.out');
}
throw new \Exception($msg);
}
\DBA::$dba->dbg(true);
}
}
protected function setUp() : void {
if ( \DBA::$dba->connected ) {
// Create a transaction, so that any actions taken by the
// tests does not change the actual contents of the database.
$this->in_transaction = \DBA::$dba->db->beginTransaction();
$this->loadFixtures();
}
}
protected function tearDown() : void {
if ( \DBA::$dba->connected && $this->in_transaction ) {
// Roll back the transaction, restoring the db to the
// state it was before the test was run.
if ( \DBA::$dba->db->rollBack() ) {
$this->in_transaction = false;
} else {
throw new \Exception(
"Transaction rollback failed! Error is: "
. \DBA::$dba->db->errorInfo());
}
}
}
private static function dbtype(string $type): int {
if (trim(strtolower($type)) === 'postgres') {
return DBTYPE_POSTGRES;
} else {
return DBTYPE_MYSQL;
}
}
private function loadFixtures() : void {
$files = glob(__DIR__ . '/includes/dba/_files/*.yml');
if ($files === false || empty($files)) {
error_log('[-] ' . __METHOD__ . ': No fixtures found! :(');
}
array_walk($files, fn($file) => $this->loadFixture($file));
}
private function loadFixture($file) : void {
$table_name = basename($file, '.yml');
$this->fixtures[$table_name] = Yaml::parseFile($file)[$table_name];
//echo "\n[*] Loaded fixture '{$table_name}':\n";
// . print_r($this->fixtures[$table_name], true)
// . PHP_EOL;
foreach ($this->fixtures[$table_name] as $entry) {
$query = 'INSERT INTO ' . dbesc($table_name) . '('
. implode(',', array_keys($entry))
. ') VALUES('
. implode(',', array_map(fn($val) => "'{$val}'", array_values($entry)))
. ')';
//print_r($query);
q($query);
}
}
}

View File

@@ -70,9 +70,6 @@ class HttpSigTest extends UnitTestCase {
);
}
/**
* @uses ::Crypto::unencapsulate
*/
function testDecrypt_sigheader() {
$header = 'Header: iv="value_iv" key="value_key" alg="value_alg" data="value_data"';
$result = [
@@ -85,9 +82,7 @@ class HttpSigTest extends UnitTestCase {
$this->assertSame($result, HTTPSig::decrypt_sigheader($header, 'site private key'));
}
/**
* @uses ::Crypto::unencapsulate
*/
function testDecrypt_sigheaderUseSitePrivateKey() {
// Create a stub for global function get_config() with expectation
$t = $this->getFunctionMock('Zotlabs\Web', 'get_config');

View File

@@ -0,0 +1,12 @@
<?php
/**
* Tests for account handling helper functions.
*/
class AccountTest extends Zotlabs\Tests\Unit\UnitTestCase {
public function test_get_account_by_id_returns_existing_account() {
$account = get_account_by_id(42);
$this->assertNotFalse($account);
$this->assertEquals($this->fixtures['account'][0]['account_email'], $account['account_email']);
}
}

View File

@@ -2,38 +2,22 @@
namespace Zotlabs\Tests\Unit\includes;
//use Zotlabs\Photo\PhotoGd;
use Zotlabs\Tests\Unit\UnitTestCase;
//use phpmock\phpunit\PHPMock;
/**
* @brief Unit Test cases for include/photo/photo_driver.php file.
*/
class PhotodriverTest extends UnitTestCase {
//use PHPMock;
public function testPhotofactoryReturnsNullForUnsupportedType() {
// php-mock can not mock global functions which is called by a global function.
// If the calling function is in a namespace it would work.
//$logger = $this->getFunctionMock(__NAMESPACE__, 'logger');
//$logger->expects($this->once());
//$ph = \photo_factory('', 'image/bmp');
//$this->assertNull($ph);
$this->markTestIncomplete('Need to mock logger(), otherwise not unit testable.');
$photo = \photo_factory('', 'image/bmp');
$this->assertNull($photo);
}
public function testPhotofactoryReturnsPhotogdIfConfigIgnore_imagickIsSet() {
// php-mock can not mock global functions which is called by a global function.
// If the calling function is in a namespace it would work.
//$gc = $this->getFunctionMock(__NAMESPACE__, 'get_config');
// simulate get_config('system', 'ignore_imagick') configured
//$gc->expects($this->once())->willReturn(1)
\Zotlabs\Lib\Config::Set('system', 'ignore_imagick', true);
//$ph = \photo_factory(file_get_contents('images/hz-16.png'), 'image/png');
//$this->assertInstanceOf(PhotoGd::class, $ph);
$this->markTestIncomplete('Need to mock get_config(), otherwise not unit testable.');
$photo = \photo_factory(file_get_contents('images/hz-16.png'), 'image/png');
$this->assertInstanceOf('Zotlabs\Photo\PhotoGd', $photo);
}
}
}