mirror of
https://github.com/EGroupware/egroupware.git
synced 2024-11-07 08:34:42 +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
|
||||
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:
|
||||
# - mysql -e 'create database egroupware'
|
||||
@ -32,9 +34,8 @@ before_script:
|
||||
- mr --trust-all --stats up
|
||||
|
||||
script:
|
||||
#- find . -name "*.php" | xargs -n1 php -l
|
||||
./doc/php_syntax_check.sh
|
||||
#- ./vendor/bin/sabre-cs-fixer fix . --dry-run --diff
|
||||
./doc/test-cli.php
|
||||
|
||||
cache:
|
||||
directories:
|
||||
|
@ -18,13 +18,13 @@ use EGroupware\Api;
|
||||
|
||||
/**
|
||||
* 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
|
||||
* or the database password.
|
||||
*
|
||||
* 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').
|
||||
*
|
||||
* 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 &$pw_enc on return encryption used
|
||||
* @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
|
||||
*/
|
||||
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))
|
||||
{
|
||||
@ -431,7 +432,6 @@ class Credentials
|
||||
}
|
||||
}
|
||||
// using a pbkdf2 password derivation with a (stored) salt
|
||||
$salt = null;
|
||||
$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));
|
||||
|
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_INCLUDE_ROOT', EGW_SERVER_ROOT);
|
||||
define('EGW_API_INC', __DIR__);
|
||||
error_reporting(E_ALL & ~E_NOTICE & ~E_STRICT);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -33,5 +33,8 @@
|
||||
"bower-asset/jquery-ui":"=1.11.2",
|
||||
"npm-asset/as-jqplot" : "1.0.*",
|
||||
"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`),
|
||||
'editor' => trim(`which vi`),
|
||||
'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',
|
||||
'packager' => 'build@stylite.de',
|
||||
'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