Add Drone CI
authorPhilipp Holzer <admin+github@philipp.info>
Mon, 16 Sep 2019 12:47:49 +0000 (14:47 +0200)
committerPhilipp Holzer <admin+github@philipp.info>
Mon, 30 Sep 2019 12:03:12 +0000 (14:03 +0200)
- Add drone test environment
- Add drone config
- apt phpunit
- Fix api.php
- Fix item.php
- Fix DBStructure
- Check if caching is possible during tests

20 files changed:
.drone.yml [new file with mode: 0644]
.travis.yml
autotest.sh [new file with mode: 0755]
bin/wait-for-connection [new file with mode: 0755]
include/api.php
mod/api.php
mod/item.php
phpunit.xml [deleted file]
src/Core/Cache/MemcacheCache.php
src/Core/Cache/RedisCache.php
src/Database/DBStructure.php
src/Database/Database.php
tests/Util/Database/StaticDatabase.php
tests/phpunit.xml [new file with mode: 0644]
tests/src/Core/Cache/MemcacheCacheTest.php
tests/src/Core/Cache/MemcachedCacheTest.php
tests/src/Core/Cache/RedisCacheTest.php
tests/src/Core/Lock/MemcacheCacheLockTest.php
tests/src/Core/Lock/MemcachedCacheLockTest.php
tests/src/Core/Lock/RedisCacheLockTest.php

diff --git a/.drone.yml b/.drone.yml
new file mode 100644 (file)
index 0000000..0d826cf
--- /dev/null
@@ -0,0 +1,34 @@
+kind: pipeline
+name: mysql-php7.1
+
+steps:
+- name: mysql-php7.1
+  image: friendicaci/php7.1:php7.1
+  commands:
+    - NOCOVERAGE=true ./autotest.sh
+  environment:
+    MYSQL_USERNAME: friendica
+    MYSQL_PASSWORD: friendica
+    MYSQL_DATABASE: friendica
+    MYSQL_HOST: mysql
+
+services:
+- name: mysql
+  image: mysql:8.0
+  command: [ "--default-authentication-plugin=mysql_native_password" ]
+  environment:
+    MYSQL_ROOT_PASSWORD: friendica
+    MYSQL_USER: friendica
+    MYSQL_PASSWORD: friendica
+    MYSQL_DATABASE: friendica
+  tmpfs:
+    - /var/lib/mysql
+
+#trigger:
+#  branch:
+#    - master
+#    - develop
+#    - "*-rc"
+#  event:
+#    - pull_request
+#    - push
index e2aa84f..493ba65 100644 (file)
@@ -26,4 +26,6 @@ before_script:
  - phpenv config-add .travis/redis.ini
  - phpenv config-add .travis/memcached.ini
 
+script: vendor/bin/phpunit --configuration tests/phpunit.xml --coverage-clover clover.xml
+
 after_success: bash <(curl -s https://codecov.io/bash)
diff --git a/autotest.sh b/autotest.sh
new file mode 100755 (executable)
index 0000000..796572d
--- /dev/null
@@ -0,0 +1,161 @@
+#!/usr/bin/env bash
+
+DATABASENAME=${MYSQL_DATABASE:-test}
+DATABASEUSER=${MYSQL_USERNAME:-friendica}
+DATABASEHOST=${MYSQL_HOST:-localhost}
+BASEDIR=$PWD
+
+export MYSQL_DATABASE="$DATABASENAME"
+export MYSQL_USERNAME="$DATABASEUSER"
+export MYSQL_PASSWORD="friendica"
+
+if [ -z "$PHP_EXE" ]; then
+  PHP_EXE=php
+fi
+PHP=$(which "$PHP_EXE")
+# Use the Friendica internal composer
+COMPOSER="$BASEDIR/bin/composer.phar"
+
+set -e
+
+_XDEBUG_CONFIG=$XDEBUG_CONFIG
+unset XDEBUG_CONFIG
+
+if [ -x "$PHP" ]; then
+  echo "Using PHP executable $PHP"
+else
+  echo "Could not find PHP executable $PHP_EXE" >&2
+  exit 3
+fi
+
+echo "Installing depdendencies"
+$PHP "$COMPOSER" install
+
+PHPUNIT="$BASEDIR/vendor/bin/phpunit"
+
+if [ -x "$PHPUNIT" ]; then
+  echo "Using PHPUnit executable $PHPUNIT"
+else
+  echo "Could not find PHPUnit executable after composer $PHPUNIT" >&2
+  exit 3
+fi
+
+if ! [ \( -w config -a ! -f config/local.config.php \) -o \( -f config/local.config.php -a -w config/local.config.php \) ]; then
+       echo "Please enable write permissions on config and config/config.php" >&2
+       exit 1
+fi
+
+# Back up existing (dev) config if one exists and backup not already there
+if [ -f config/local.config.php ] && [ ! -f config/local.config-autotest-backup.php ]; then
+  mv config/local.config.php config/local.config-autotest-backup.php
+fi
+
+function cleanup_config {
+
+    if [ -n "$DOCKER_CONTAINER_ID" ]; then
+      echo "Kill the docker $DOCKER_CONTAINER_ID"
+      docker stop "$DOCKER_CONTAINER_ID"
+      docker rm -f "$DOCKER_CONTAINER_ID"
+    fi
+
+    cd "$BASEDIR"
+
+    # Restore existing config
+    if [ -f config/local.config-autotest-backup.php ]; then
+      mv config/local.config-autotest-backup.php config/local.config.php
+    fi
+}
+
+# restore config on exit
+trap cleanup_config EXIT
+
+function execute_tests {
+    echo "Setup environment for MariaDB testing ..."
+    # back to root folder
+    cd "$BASEDIR"
+
+    # backup current config
+    if [ -f config/local.config.php ]; then
+      mv config/local.config.php config/local.config-autotest-backup.php
+    fi
+
+    if [ -n "$USEDOCKER" ]; then
+      echo "Fire up the mysql docker"
+      DOCKER_CONTAINER_ID=$(docker run \
+              -e MYSQL_ROOT_PASSWORD=friendica \
+              -e MYSQL_USER="$DATABASEUSER" \
+              -e MYSQL_PASSWORD=friendica \
+              -e MYSQL_DATABASE="$DATABASENAME" \
+              -d mysql)
+      DATABASEHOST=$(docker inspect --format="{{.NetworkSettings.IPAddress}}" "$DOCKER_CONTAINER_ID")
+    else
+      if [ -z "$DRONE" ]; then  # no need to drop the DB when we are on CI
+        if [ "mysql" != "$(mysql --version | grep -o mysql)" ]; then
+          echo "Your mysql binary is not provided by mysql"
+          echo "To use the docker container set the USEDOCKER environment variable"
+          exit 3
+        fi
+        mysql -u "$DATABASEUSER" -pfriendica -e "DROP DATABASE IF EXISTS $DATABASENAME"
+        mysql -u "$DATABASEUSER" -pfriendica -e "CREATE DATABASE $DATABASENAME DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci"
+      else
+        DATABASEHOST=mysql
+      fi
+    fi
+
+    echo "Waiting for MySQL $DATABASEHOST initialization..."
+    if ! bin/wait-for-connection $DATABASEHOST 3306 300; then
+      echo "[ERROR] Waited 300 seconds, no response" >&2
+      exit 1
+    fi
+
+    if [ -n "$USEDOCKER" ]; then
+      echo "Initialize database..."
+      docker exec $DOCKER_CONTAINER_ID mysql -u root -pfriendica -e 'CREATE DATABASE IF NOT EXISTS $DATABASENAME;'
+    fi
+
+    export MYSQL_HOST="$DATABASEHOST"
+
+    #call installer
+    echo "Installing Friendica..."
+    "$PHP" ./bin/console.php autoinstall --dbuser="$DATABASEUSER" --dbpass=friendica --dbdata="$DATABASENAME" --dbhost="$DATABASEHOST" --url=https://friendica.local --admin=admin@friendica.local
+
+    #test execution
+    echo "Testing..."
+    rm -fr "coverage-html"
+    mkdir "coverage-html"
+    if [[ "$_XDEBUG_CONFIG" ]]; then
+      export XDEBUG_CONFIG=$_XDEBUG_CONFIG
+    fi
+
+    COVER=''
+    if [ -z "$NOCOVERAGE" ]; then
+      COVER="--coverage-clover autotest-clover.xml --coverage-html coverage-html"
+    else
+      echo "No coverage"
+    fi
+
+    INPUT="$BASEDIR/tests"
+    if [ -n "$1" ]; then
+      INPUT="$INPUT/$1"
+    fi
+
+    echo "${PHPUNIT[@]}" --configuration tests/phpunit.xml $COVER --log-junit "autotest-results.xml" "$INPUT" "$2"
+    "${PHPUNIT[@]}" --configuration tests/phpunit.xml $COVER --log-junit "autotest-results.xml" "$INPUT" "$2"
+    RESULT=$?
+
+    if [ -n "$DOCKER_CONTAINER_ID" ]; then
+      echo "Kill the docker $DOCKER_CONTAINER_ID"
+      docker stop $DOCKER_CONTAINER_ID
+      docker rm -f $DOCKER_CONTAINER_ID
+      unset $DOCKER_CONTAINER_ID
+    fi
+}
+
+#
+# Start the test execution
+#
+if [ -n "$1" ] && [ ! -f "tests/$FILENAME" ] && [ "${FILENAME:0:2}" != "--" ]; then
+  execute_tests "$FILENAME" "$2"
+else
+  execute_tests
+fi
diff --git a/bin/wait-for-connection b/bin/wait-for-connection
new file mode 100755 (executable)
index 0000000..67990f9
--- /dev/null
@@ -0,0 +1,40 @@
+#!/usr/bin/php
+
+<?php
+$timeout = 60;
+switch ($argc) {
+       case 4:
+               $timeout = (float)$argv[3];
+       case 3:
+               $host = $argv[1];
+               $port = (int)$argv[2];
+               break;
+       default:
+               fwrite(STDERR, 'Usage: '.$argv[0].' host port [timeout]'."\n");
+               exit(2);
+}
+if ($timeout < 0) {
+       fwrite(STDERR, 'Timeout must be greater than zero'."\n");
+       exit(2);
+}
+if ($port < 1) {
+       fwrite(STDERR, 'Port must be an integer greater than zero'."\n");
+       exit(2);
+}
+$socketTimeout = (float)ini_get('default_socket_timeout');
+if ($socketTimeout > $timeout) {
+       $socketTimeout = $timeout;
+}
+$stopTime = time() + $timeout;
+do {
+       $sock = @fsockopen($host, $port, $errno, $errstr, $socketTimeout);
+       if ($sock !== false) {
+               fclose($sock);
+               fwrite(STDOUT, "\n");
+               exit(0);
+       }
+       sleep(1);
+       fwrite(STDOUT, '.');
+} while (time() < $stopTime);
+fwrite(STDOUT, "\n");
+exit(1);
\ No newline at end of file
index bdab20b..8b93850 100644 (file)
@@ -48,9 +48,9 @@ use Friendica\Util\Proxy as ProxyUtils;
 use Friendica\Util\Strings;
 use Friendica\Util\XML;
 
-require_once 'mod/share.php';
-require_once 'mod/item.php';
-require_once 'mod/wall_upload.php';
+require_once __DIR__ . '/../mod/share.php';
+require_once __DIR__ . '/../mod/item.php';
+require_once __DIR__ . '/../mod/wall_upload.php';
 
 define('API_METHOD_ANY', '*');
 define('API_METHOD_GET', 'GET');
index 4a1db1b..9a802b5 100644 (file)
@@ -2,6 +2,7 @@
 /**
  * @file mod/api.php
  */
+
 use Friendica\App;
 use Friendica\Core\Config;
 use Friendica\Core\L10n;
@@ -9,7 +10,7 @@ use Friendica\Core\Renderer;
 use Friendica\Database\DBA;
 use Friendica\Module\Login;
 
-require_once 'include/api.php';
+require_once __DIR__ . '/../include/api.php';
 
 function oauth_get_client(OAuthRequest $request)
 {
index 8bc394b..2ebf5a2 100644 (file)
@@ -42,7 +42,7 @@ use Friendica\Util\Security;
 use Friendica\Util\Strings;
 use Friendica\Worker\Delivery;
 
-require_once 'include/items.php';
+require_once __DIR__ . '/../include/items.php';
 
 function item_post(App $a) {
        if (!local_user() && !remote_user()) {
diff --git a/phpunit.xml b/phpunit.xml
deleted file mode 100644 (file)
index a46f7be..0000000
+++ /dev/null
@@ -1,31 +0,0 @@
-<?xml version="1.0"?>
-<phpunit
-       bootstrap="tests/bootstrap.php"
-       verbose="true">
-    <testsuites>
-        <testsuite>
-            <directory>tests/</directory>
-        </testsuite>
-    </testsuites>
-       <!-- Filters for Code Coverage -->
-       <filter>
-               <whitelist>
-                       <directory suffix=".php">.</directory>
-                       <exclude>
-                               <directory suffix=".php">config/</directory>
-                               <directory suffix=".php">doc/</directory>
-                               <directory suffix=".php">images/</directory>
-                               <directory suffix=".php">library/</directory>
-                               <directory suffix=".php">spec/</directory>
-                               <directory suffix=".php">tests/</directory>
-                               <directory suffix=".php">view/</directory>
-                       </exclude>
-               </whitelist>
-       </filter>
-       <logging>
-               <log type="coverage-clover" target="clover.xml" />
-       </logging>
-       <listeners>
-               <listener class="JohnKary\PHPUnit\Listener\SpeedTrapListener" />
-       </listeners>
-</phpunit>
index 7171669..53a6523 100644 (file)
@@ -37,7 +37,7 @@ class MemcacheCache extends Cache implements IMemoryCache
                $memcache_host = $config->get('system', 'memcache_host');
                $memcache_port = $config->get('system', 'memcache_port');
 
-               if (!$this->memcache->connect($memcache_host, $memcache_port)) {
+               if (!@$this->memcache->connect($memcache_host, $memcache_port)) {
                        throw new Exception('Expected Memcache server at ' . $memcache_host . ':' . $memcache_port . ' isn\'t available');
                }
        }
index b2638c4..3558a38 100644 (file)
@@ -37,9 +37,9 @@ class RedisCache extends Cache implements IMemoryCache
                $redis_pw   = $config->get('system', 'redis_password');
                $redis_db   = $config->get('system', 'redis_db', 0);
 
-               if (isset($redis_port) && !$this->redis->connect($redis_host, $redis_port)) {
+               if (isset($redis_port) && !@$this->redis->connect($redis_host, $redis_port)) {
                        throw new Exception('Expected Redis server at ' . $redis_host . ':' . $redis_port . ' isn\'t available');
-               } elseif (!$this->redis->connect($redis_host)) {
+               } elseif (!@$this->redis->connect($redis_host)) {
                        throw new Exception('Expected Redis server at ' . $redis_host . ' isn\'t available');
                }
 
index cf707f2..72b903e 100644 (file)
@@ -12,7 +12,7 @@ use Friendica\Core\L10n;
 use Friendica\Core\Logger;
 use Friendica\Util\DateTimeFormat;
 
-require_once 'include/dba.php';
+require_once __DIR__ . '/../../include/dba.php';
 
 /**
  * @brief This class contain functions for the database management
index 813d4e9..6b4b621 100644 (file)
@@ -67,7 +67,7 @@ class Database
        {
                // Use environment variables for mysql if they are set beforehand
                if (!empty($server['MYSQL_HOST'])
-                   && !empty($server['MYSQL_USERNAME'] || !empty($server['MYSQL_USER']))
+                   && (!empty($server['MYSQL_USERNAME'] || !empty($server['MYSQL_USER'])))
                    && $server['MYSQL_PASSWORD'] !== false
                    && !empty($server['MYSQL_DATABASE']))
                {
index e4ea112..128ecc8 100644 (file)
@@ -80,7 +80,7 @@ class StaticDatabase extends Database
        {
                // Use environment variables for mysql if they are set beforehand
                if (!empty($server['MYSQL_HOST'])
-                   && !empty($server['MYSQL_USERNAME'] || !empty($server['MYSQL_USER']))
+                   && (!empty($server['MYSQL_USERNAME'] || !empty($server['MYSQL_USER'])))
                    && $server['MYSQL_PASSWORD'] !== false
                    && !empty($server['MYSQL_DATABASE']))
                {
diff --git a/tests/phpunit.xml b/tests/phpunit.xml
new file mode 100644 (file)
index 0000000..73b643e
--- /dev/null
@@ -0,0 +1,29 @@
+<?xml version="1.0" encoding="utf-8" ?>
+<phpunit
+       bootstrap="bootstrap.php"
+       verbose="true">
+       <testsuite name='friendica'>
+               <directory suffix='.php'>functional/</directory>
+               <directory suffix='.php'>include/</directory>
+               <directory suffix='.php'>src/</directory>
+               <directory suffix='.php'>./</directory>
+       </testsuite>
+       <!-- Filters for Code Coverage -->
+       <filter>
+               <whitelist>
+                       <directory suffix=".php">..</directory>
+                       <exclude>
+                               <directory suffix=".php">config/</directory>
+                               <directory suffix=".php">doc/</directory>
+                               <directory suffix=".php">images/</directory>
+                               <directory suffix=".php">library/</directory>
+                               <directory suffix=".php">spec/</directory>
+                               <directory suffix=".php">tests/</directory>
+                               <directory suffix=".php">view/</directory>
+                       </exclude>
+               </whitelist>
+       </filter>
+       <listeners>
+               <listener class="JohnKary\PHPUnit\Listener\SpeedTrapListener" />
+       </listeners>
+</phpunit>
index ccc3723..8abf169 100644 (file)
@@ -14,16 +14,22 @@ class MemcacheCacheTest extends MemoryCacheTest
        {
                $configMock = \Mockery::mock(Configuration::class);
 
+               $host = $_SERVER['MEMCACHE_HOST'] ?? 'localhost';
+
                $configMock
                        ->shouldReceive('get')
                        ->with('system', 'memcache_host')
-                       ->andReturn('localhost');
+                       ->andReturn($host);
                $configMock
                        ->shouldReceive('get')
                        ->with('system', 'memcache_port')
                        ->andReturn(11211);
 
-               $this->cache = new MemcacheCache('localhost', $configMock);
+               try {
+                       $this->cache = new MemcacheCache($host, $configMock);
+               } catch (\Exception $e) {
+                       $this->markTestSkipped('Memcache is not available');
+               }
                return $this->cache;
        }
 
index d887250..c8c65c9 100644 (file)
@@ -16,14 +16,20 @@ class MemcachedCacheTest extends MemoryCacheTest
        {
                $configMock = \Mockery::mock(Configuration::class);
 
+               $host = $_SERVER['MEMCACHED_HOST'] ?? 'localhost';
+
                $configMock
                        ->shouldReceive('get')
                        ->with('system', 'memcached_hosts')
-                       ->andReturn([0 => 'localhost, 11211']);
+                       ->andReturn([0 => $host . ', 11211']);
 
                $logger = new NullLogger();
 
-               $this->cache = new MemcachedCache('localhost', $configMock, $logger);
+               try {
+                       $this->cache = new MemcachedCache($host, $configMock, $logger);
+               } catch (\Exception $exception) {
+                       $this->markTestSkipped('Memcached is not available');
+               }
                return $this->cache;
        }
 
index df35325..cddefe3 100644 (file)
@@ -15,10 +15,12 @@ class RedisCacheTest extends MemoryCacheTest
        {
                $configMock = \Mockery::mock(Configuration::class);
 
+               $host = $_SERVER['REDIS_HOST'] ?? 'localhost';
+
                $configMock
                        ->shouldReceive('get')
                        ->with('system', 'redis_host')
-                       ->andReturn('localhost');
+                       ->andReturn($host);
                $configMock
                        ->shouldReceive('get')
                        ->with('system', 'redis_port')
@@ -33,7 +35,11 @@ class RedisCacheTest extends MemoryCacheTest
                        ->with('system', 'redis_password')
                        ->andReturn(null);
 
-               $this->cache = new RedisCache('localhost', $configMock);
+               try {
+                       $this->cache = new RedisCache($host, $configMock);
+               } catch (\Exception $e) {
+                       $this->markTestSkipped('Redis is not available.');
+               }
                return $this->cache;
        }
 
index f550ac5..4e7dd30 100644 (file)
@@ -16,15 +16,26 @@ class MemcacheCacheLockTest extends LockTest
        {
                $configMock = \Mockery::mock(Configuration::class);
 
+               $host = $_SERVER['MEMCACHE_HOST'] ?? 'localhost';
+
                $configMock
                        ->shouldReceive('get')
                        ->with('system', 'memcache_host')
-                       ->andReturn('localhost');
+                       ->andReturn($host);
                $configMock
                        ->shouldReceive('get')
                        ->with('system', 'memcache_port')
                        ->andReturn(11211);
 
-               return new CacheLock(new MemcacheCache('localhost', $configMock));
+               $lock = null;
+
+               try {
+                       $cache = new MemcacheCache($host, $configMock);
+                       $lock = new CacheLock($cache);
+               } catch (\Exception $e) {
+                       $this->markTestSkipped('Memcache is not available');
+               }
+
+               return $lock;
        }
 }
index 8b59f91..2249b88 100644 (file)
@@ -17,13 +17,24 @@ class MemcachedCacheLockTest extends LockTest
        {
                $configMock = \Mockery::mock(Configuration::class);
 
+               $host = $_SERVER['MEMCACHED_HOST'] ?? 'localhost';
+
                $configMock
                        ->shouldReceive('get')
                        ->with('system', 'memcached_hosts')
-                       ->andReturn([0 => 'localhost, 11211']);
+                       ->andReturn([0 => $host . ', 11211']);
 
                $logger = new NullLogger();
 
-               return new CacheLock(new MemcachedCache('localhost', $configMock, $logger));
+               $lock = null;
+
+               try {
+                       $cache = new MemcachedCache($host, $configMock, $logger);
+                       $lock = new CacheLock($cache);
+               } catch (\Exception $e) {
+                       $this->markTestSkipped('Memcached is not available');
+               }
+
+               return $lock;
        }
 }
index 0ebc021..5cecd8f 100644 (file)
@@ -16,10 +16,12 @@ class RedisCacheLockTest extends LockTest
        {
                $configMock = \Mockery::mock(Configuration::class);
 
+               $host = $_SERVER['REDIS_HOST'] ?? 'localhost';
+
                $configMock
                        ->shouldReceive('get')
                        ->with('system', 'redis_host')
-                       ->andReturn('localhost');
+                       ->andReturn($host);
                $configMock
                        ->shouldReceive('get')
                        ->with('system', 'redis_port')
@@ -34,6 +36,15 @@ class RedisCacheLockTest extends LockTest
                        ->with('system', 'redis_password')
                        ->andReturn(null);
 
-               return new CacheLock(new RedisCache('localhost', $configMock));
+               $lock = null;
+
+               try {
+                       $cache = new RedisCache($host, $configMock);
+                       $lock = new CacheLock($cache);
+               } catch (\Exception $e) {
+                       $this->markTestSkipped('Redis is not available');
+               }
+
+               return $lock;
        }
 }