mirror of
https://github.com/EGroupware/egroupware.git
synced 2024-12-26 00:29:38 +01:00
adding a first unit test to EGroupware, plus a test runner running all test-classes in either:
$app/src/.*/test/$classTest.php or $app/test/class.$classTest.inc.php adding test runner doc/test-cli.php to Travis
This commit is contained in:
parent
0f70db5bcf
commit
5c33bd9bef
@ -22,6 +22,8 @@ matrix:
|
|||||||
|
|
||||||
sudo: required
|
sudo: required
|
||||||
dist: trusty
|
dist: trusty
|
||||||
|
# this myy fix hhvm builds according to https://docs.travis-ci.com/user/languages/php#HHVM-versions-on-Trusty
|
||||||
|
group: edge
|
||||||
|
|
||||||
before_script:
|
before_script:
|
||||||
# - mysql -e 'create database egroupware'
|
# - mysql -e 'create database egroupware'
|
||||||
@ -32,9 +34,8 @@ before_script:
|
|||||||
- mr --trust-all --stats up
|
- mr --trust-all --stats up
|
||||||
|
|
||||||
script:
|
script:
|
||||||
#- find . -name "*.php" | xargs -n1 php -l
|
|
||||||
./doc/php_syntax_check.sh
|
./doc/php_syntax_check.sh
|
||||||
#- ./vendor/bin/sabre-cs-fixer fix . --dry-run --diff
|
./doc/test-cli.php
|
||||||
|
|
||||||
cache:
|
cache:
|
||||||
directories:
|
directories:
|
||||||
|
@ -18,13 +18,13 @@ use EGroupware\Api;
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Mail account credentials are stored in egw_ea_credentials for given
|
* Mail account credentials are stored in egw_ea_credentials for given
|
||||||
* acocunt-id, users and types (imap, smtp and optional admin connection).
|
* account_id, users and types (imap, smtp and optional admin connection).
|
||||||
*
|
*
|
||||||
* Passwords in credentials are encrypted with either user password from session
|
* Passwords in credentials are encrypted with either user password from session
|
||||||
* or the database password.
|
* or the database password.
|
||||||
*
|
*
|
||||||
* If OpenSSL extension is available it is used to store credentials with AES-128-CBC,
|
* If OpenSSL extension is available it is used to store credentials with AES-128-CBC,
|
||||||
* with key generated via hash_pbkdf2 sha256 hash and 12 byte binary salt (=16 char base64).
|
* with key generated via hash_pbkdf2 sha256 hash and 16 byte binary salt (=24 char base64).
|
||||||
* OpenSSL can be also used to read old MCrypt credentials (OpenSSL 'des-ede3').
|
* OpenSSL can be also used to read old MCrypt credentials (OpenSSL 'des-ede3').
|
||||||
*
|
*
|
||||||
* If only MCrypt is available (or EGroupware versions 14.x) credentials are are stored
|
* If only MCrypt is available (or EGroupware versions 14.x) credentials are are stored
|
||||||
@ -412,9 +412,10 @@ class Credentials
|
|||||||
* @param int $account_id user-account password is for
|
* @param int $account_id user-account password is for
|
||||||
* @param int &$pw_enc on return encryption used
|
* @param int &$pw_enc on return encryption used
|
||||||
* @param string $key =null key/password to use, default password according to account_id
|
* @param string $key =null key/password to use, default password according to account_id
|
||||||
|
* @param string $salt =null (binary) salt to use, default generate new random salt
|
||||||
* @return string encrypted password
|
* @return string encrypted password
|
||||||
*/
|
*/
|
||||||
protected static function encrypt_openssl_aes($password, $account_id, &$pw_enc, $key=null)
|
protected static function encrypt_openssl_aes($password, $account_id, &$pw_enc, $key=null, $salt=null)
|
||||||
{
|
{
|
||||||
if (empty($key))
|
if (empty($key))
|
||||||
{
|
{
|
||||||
@ -431,7 +432,6 @@ class Credentials
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
// using a pbkdf2 password derivation with a (stored) salt
|
// using a pbkdf2 password derivation with a (stored) salt
|
||||||
$salt = null;
|
|
||||||
$aes_key = self::aes_key($key, $salt);
|
$aes_key = self::aes_key($key, $salt);
|
||||||
|
|
||||||
return base64_encode($salt).base64_encode(openssl_encrypt($password, self::AES_METHOD, $aes_key, OPENSSL_RAW_DATA, $salt));
|
return base64_encode($salt).base64_encode(openssl_encrypt($password, self::AES_METHOD, $aes_key, OPENSSL_RAW_DATA, $salt));
|
||||||
|
105
api/src/Mail/test/CredentialsTest.php
Normal file
105
api/src/Mail/test/CredentialsTest.php
Normal file
@ -0,0 +1,105 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* EGroupware Api: Mail account credentials tests
|
||||||
|
*
|
||||||
|
* @link http://www.stylite.de
|
||||||
|
* @package api
|
||||||
|
* @subpackage mail
|
||||||
|
* @author Ralf Becker <rb-AT-stylite.de>
|
||||||
|
* @copyright (c) 2016 by Ralf Becker <rb-AT-stylite.de>
|
||||||
|
* @author Stylite AG <info@stylite.de>
|
||||||
|
* @license http://opensource.org/licenses/gpl-license.php GPL - GNU General Public License
|
||||||
|
* @version $Id$
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace EGroupware\Api\Mail;
|
||||||
|
|
||||||
|
require_once realpath(__DIR__.'/../../loader/common.php'); // autoloader & check_load_extension
|
||||||
|
|
||||||
|
use EGroupware\Api;
|
||||||
|
use PHPUnit\Framework\TestCase;
|
||||||
|
use ReflectionClass;
|
||||||
|
use EGroupware\Api\Mail\Credentials;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Mail account credentials tests
|
||||||
|
*
|
||||||
|
* Only testing en&decryption of mail passwords so far.
|
||||||
|
* Further tests would need database.
|
||||||
|
*/
|
||||||
|
class CredentialsTest extends TestCase
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Test new 16.1 AES password encryption with OpenSSL
|
||||||
|
*/
|
||||||
|
public function testAes()
|
||||||
|
{
|
||||||
|
$mail_password = 'RälfÜber12345678sdddfd';
|
||||||
|
$account_id = $GLOBALS['egw_info']['user']['account_id'] = 1;
|
||||||
|
Api\Cache::setSession('phpgwapi', 'password', base64_encode('HMqUHxzMBjjvXppV'));
|
||||||
|
|
||||||
|
// test encryption with fixed salt
|
||||||
|
$pw_encrypted = 'IaaBeu6LiIa+iFBnHYroXA==4lp30Z4B20OdUYnFrxM3lo4b+bsf5wQITdyM1eMP6PM=';
|
||||||
|
$pw_enc = null;
|
||||||
|
$this->assertEquals($pw_encrypted, self::callProtectedMethod('encrypt_openssl_aes', __NAMESPACE__.'\\Credentials',
|
||||||
|
array($mail_password, $account_id, &$pw_enc, null, base64_decode(substr($pw_encrypted, 0, Credentials::SALT_LEN64)))),
|
||||||
|
'AES encrypt with fixed salt');
|
||||||
|
|
||||||
|
// test encryption&descryption with random salt
|
||||||
|
$pw_encrypted_rs = self::callProtectedMethod('encrypt', __NAMESPACE__.'\\Credentials',
|
||||||
|
array($mail_password, $account_id, &$pw_enc));
|
||||||
|
$row = array(
|
||||||
|
'account_id' => $account_id,
|
||||||
|
'cred_password' => $pw_encrypted_rs,
|
||||||
|
'cred_pw_enc' => $pw_enc,
|
||||||
|
);
|
||||||
|
$this->assertEquals($mail_password, self::callProtectedMethod('decrypt', __NAMESPACE__.'\\Credentials',
|
||||||
|
array($row)), 'AES decrypt with random salt');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Test old 14.x tripledes password encryption with mcrypt (if available) and openssl
|
||||||
|
*/
|
||||||
|
public function testTripledes()
|
||||||
|
{
|
||||||
|
$mail_password = 'RälfÜber12345678sdddfd';
|
||||||
|
$account_id = $GLOBALS['egw_info']['user']['account_id'] = 1;
|
||||||
|
Api\Cache::setSession('phpgwapi', 'password', base64_encode('HMqUHxzMBjjvXppV'));
|
||||||
|
$pw_encrypted = 'Y7QwLIqS6MP61hS8/e4i0wCdtpQP6kZ2';
|
||||||
|
|
||||||
|
// if mycrypt is available check encrypting too
|
||||||
|
if (check_load_extension('mcrypt'))
|
||||||
|
{
|
||||||
|
$pw_enc = null;
|
||||||
|
$this->assertEquals($pw_encrypted, self::callProtectedMethod('encrypt_mcrypt_3des', __NAMESPACE__.'\\Credentials',
|
||||||
|
array($mail_password, $account_id, &$pw_enc)), 'tripledes encryption with mcrypt');
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
$pw_enc = Credentials::USER;
|
||||||
|
}
|
||||||
|
// otherwise only check decrypting with openssl
|
||||||
|
$row = array(
|
||||||
|
'account_id' => $account_id,
|
||||||
|
'cred_password' => $pw_encrypted,
|
||||||
|
'cred_pw_enc' => $pw_enc,
|
||||||
|
);
|
||||||
|
$this->assertEquals($mail_password, self::callProtectedMethod('decrypt', __NAMESPACE__.'\\Credentials',
|
||||||
|
array($row)), 'tripledes decryption with openssl');
|
||||||
|
|
||||||
|
if (check_load_extension('mcrypt'))
|
||||||
|
{
|
||||||
|
$this->assertEquals($mail_password, self::callProtectedMethod('decrypt_mcrypt_3des', __NAMESPACE__.'\\Credentials',
|
||||||
|
array($row)), 'tripledes decryption with mcrypt');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected static function callProtectedMethod($name, $classname, $params)
|
||||||
|
{
|
||||||
|
$class = new ReflectionClass($classname);
|
||||||
|
$method = $class->getMethod($name);
|
||||||
|
$method->setAccessible(true);
|
||||||
|
$obj = new $classname();
|
||||||
|
return $method->invokeArgs($obj, $params);
|
||||||
|
}
|
||||||
|
}
|
@ -20,6 +20,7 @@ if (!defined('EGW_SERVER_ROOT'))
|
|||||||
define('EGW_SERVER_ROOT', dirname(dirname(__DIR__)));
|
define('EGW_SERVER_ROOT', dirname(dirname(__DIR__)));
|
||||||
define('EGW_INCLUDE_ROOT', EGW_SERVER_ROOT);
|
define('EGW_INCLUDE_ROOT', EGW_SERVER_ROOT);
|
||||||
define('EGW_API_INC', __DIR__);
|
define('EGW_API_INC', __DIR__);
|
||||||
|
error_reporting(E_ALL & ~E_NOTICE & ~E_STRICT);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -33,5 +33,8 @@
|
|||||||
"bower-asset/jquery-ui":"=1.11.2",
|
"bower-asset/jquery-ui":"=1.11.2",
|
||||||
"npm-asset/as-jqplot" : "1.0.*",
|
"npm-asset/as-jqplot" : "1.0.*",
|
||||||
"npm-asset/gridster":"0.5.*"
|
"npm-asset/gridster":"0.5.*"
|
||||||
|
},
|
||||||
|
"require-dev": {
|
||||||
|
"phpunit/phpunit": "5.4.*"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
1303
composer.lock
generated
1303
composer.lock
generated
File diff suppressed because it is too large
Load Diff
@ -55,7 +55,7 @@ $config = array(
|
|||||||
'gpg' => trim(`which gpg`),
|
'gpg' => trim(`which gpg`),
|
||||||
'editor' => trim(`which vi`),
|
'editor' => trim(`which vi`),
|
||||||
'rsync' => trim(`which rsync`).' --progress -e ssh --exclude "*-stylite-*" --exclude "*-esyncpro-*"',
|
'rsync' => trim(`which rsync`).' --progress -e ssh --exclude "*-stylite-*" --exclude "*-esyncpro-*"',
|
||||||
'composer' => ($composer=trim(`which composer.phar`)) ? $composer.' install --ignore-platform-reqs' : '',
|
'composer' => ($composer=trim(`which composer.phar`)) ? $composer.' install --ignore-platform-reqs --no-dev' : '',
|
||||||
'after-checkout' => 'rm -rf */source */templates/*/source',
|
'after-checkout' => 'rm -rf */source */templates/*/source',
|
||||||
'packager' => 'build@stylite.de',
|
'packager' => 'build@stylite.de',
|
||||||
'obs' => '/home/stylite/obs/stylite-epl-trunk',
|
'obs' => '/home/stylite/obs/stylite-epl-trunk',
|
||||||
|
71
doc/test-cli.php
Executable file
71
doc/test-cli.php
Executable file
@ -0,0 +1,71 @@
|
|||||||
|
#!/usr/bin/env php
|
||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* EGroupware Test Runner
|
||||||
|
*
|
||||||
|
* @author Ralf Becker <RalfBecker@outdoor-training.de>
|
||||||
|
* @license http://opensource.org/licenses/gpl-license.php GPL - GNU General Public License
|
||||||
|
*/
|
||||||
|
|
||||||
|
if (php_sapi_name() !== 'cli') // security precaution: forbit calling as web-page
|
||||||
|
{
|
||||||
|
die('<h1>test-cli.php must NOT be called as web-page --> exiting !!!</h1>');
|
||||||
|
}
|
||||||
|
|
||||||
|
require_once './api/src/loader/common.php';
|
||||||
|
|
||||||
|
$_SERVER['argv'][] = '--verbose';
|
||||||
|
$_SERVER['argv'][] = 'EgroupwareTestRunner';
|
||||||
|
$_SERVER['argv'][] = __FILE__;
|
||||||
|
PHPUnit_TextUI_Command::main();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Run all AllTests.php files
|
||||||
|
*/
|
||||||
|
class EgroupwareTestRunner
|
||||||
|
{
|
||||||
|
public static function suite()
|
||||||
|
{
|
||||||
|
$suite = new PHPUnit_Framework_TestSuite('EGroupware Test Runner');
|
||||||
|
|
||||||
|
$basedir = dirname(__DIR__);
|
||||||
|
|
||||||
|
// Find all /test/*Test.php files/classes
|
||||||
|
foreach (new RecursiveIteratorIterator(new RecursiveDirectoryIterator($basedir)) as $file)
|
||||||
|
{
|
||||||
|
if ($file->isFile() && preg_match('|/test/[^/]+Test\.php$|', $path=$file->getPathname()))
|
||||||
|
{
|
||||||
|
// Include the test suite, as it is NOT autoloadable in test directory!
|
||||||
|
require_once($path);
|
||||||
|
|
||||||
|
|
||||||
|
$matches = null;
|
||||||
|
// tests of namespaced classes in $app/src/.*/test/$classTest.php
|
||||||
|
if (preg_match('|/([^/]+)/src/((.*)/)?test/[^/]+Test\.php$|', $path, $matches))
|
||||||
|
{
|
||||||
|
$class = 'EGroupware\\'.ucfirst($matches[1]);
|
||||||
|
if (!empty($matches[2]))
|
||||||
|
{
|
||||||
|
foreach(explode('/', $matches[3]) as $name)
|
||||||
|
{
|
||||||
|
$class .= '\\'.ucfirst($name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
$class .= '\\'.$file->getBasename('.php');
|
||||||
|
}
|
||||||
|
// non-namespaced class in $app/test/class.$classTest.inc.php
|
||||||
|
elseif (preg_match('|/test/class\.([^./]+)\.inc\.php$|', $path, $matches))
|
||||||
|
{
|
||||||
|
$class = $matches[1];
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
echo "$path: $class\n";
|
||||||
|
$suite->addTestSuite($class);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return $suite;
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user