484 lines
11 KiB
PHP
484 lines
11 KiB
PHP
<?php
|
|
|
|
|
|
|
|
echo "\n************************************************************************************";
|
|
echo "\nBegin gpEasy Tests\n\n";
|
|
|
|
|
|
defined('gpdebug') or define('gpdebug',true);
|
|
defined('is_running') or define('is_running',true);
|
|
defined('gp_unit_testing') or define('gp_unit_testing',true);
|
|
defined('gp_nonce_algo') or define('gp_nonce_algo','sha512');
|
|
error_reporting(E_ALL); // 32767
|
|
|
|
if (!class_exists('\PHPUnit_Framework_TestCase') && class_exists('\PHPUnit\Framework\TestCase'))
|
|
class_alias('\PHPUnit\Framework\TestCase', '\PHPUnit_Framework_TestCase');
|
|
|
|
|
|
|
|
class gptest_bootstrap extends \PHPUnit_Framework_TestCase{
|
|
|
|
protected static $process;
|
|
protected static $client_user; // guzzle client for making anonymous user requests
|
|
protected static $client_admin; // guzzle client for making admin user requests
|
|
protected static $client_current;
|
|
protected static $is_admin = false;
|
|
protected static $requests = 0;
|
|
protected static $proc_output = [];
|
|
protected static $phpinfo;
|
|
protected static $tracking = [];
|
|
|
|
|
|
const user_name = 'phpunit_username';
|
|
const user_pass = 'phpunit-test-password';
|
|
const user_email = 'test@typesettercms.com';
|
|
|
|
|
|
static function log($msg){
|
|
static $fp;
|
|
|
|
if( !$fp ){
|
|
$log = __DIR__ . '/phpunit.log';
|
|
$fp = fopen($log, 'a');
|
|
}
|
|
fwrite($fp, "\n".print_r($msg, TRUE));
|
|
}
|
|
|
|
public function setUp(){
|
|
self::UseAdmin();
|
|
}
|
|
|
|
/**
|
|
* Use php's built-in web server
|
|
* https://medium.com/@peter.lafferty/start-phps-built-in-web-server-from-phpunit-9571f38c5045
|
|
*
|
|
*/
|
|
public static function setUpBeforeClass(){
|
|
|
|
if( function_exists('showError') ){
|
|
return;
|
|
}
|
|
|
|
self::Console('Start server, set phpinfo...');
|
|
|
|
self::PrepInstall();
|
|
self::StartServer();
|
|
|
|
|
|
// create client for user requests
|
|
self::$client_user = new \GuzzleHttp\Client(['http_errors' => false,'cookies' => true]);
|
|
|
|
// create client for admin requests
|
|
self::$client_admin = new \GuzzleHttp\Client(['http_errors' => false,'cookies' => true]);
|
|
self::UseAdmin();
|
|
|
|
|
|
self::Install();
|
|
\gp\tool::GetLangFile();
|
|
|
|
self::LogIn();
|
|
|
|
$url = '/phpinfo.php';
|
|
$response = self::GuzzleRequest('GET',$url);
|
|
$body = $response->getBody();
|
|
self::$phpinfo = (string)$body;
|
|
|
|
}
|
|
|
|
|
|
public static function StartServer(){
|
|
global $dataDir;
|
|
|
|
|
|
$proc = ['php','-S','localhost:8081'];
|
|
|
|
// doc root
|
|
$proc[] = '-t';
|
|
$proc[] = $dataDir; // '.';
|
|
|
|
// error log
|
|
$proc[] = '-d';
|
|
$proc[] = 'error_log='.$dataDir . '/data/request-errors.log';
|
|
|
|
// xdebug configuration to collect code coverage
|
|
//$proc[] = '-c';
|
|
//$proc[] = __DIR__ . '/phpconfig.ini';
|
|
|
|
$proc[] = '-d';
|
|
$proc[] = 'auto_prepend_file='.__DIR__ . '/ServerPrepend.php';
|
|
|
|
// xdebug profiling
|
|
/*
|
|
$profile_dir = sys_get_temp_dir().'/test-profiler';
|
|
if( file_exists($profile_dir) ){
|
|
\gp\tool\Files::RmAll($profile_dir);
|
|
}
|
|
mkdir($profile_dir);
|
|
|
|
$proc[] = '-d';
|
|
$proc[] = 'xdebug.profiler_enable=1';
|
|
|
|
$proc[] = '-d';
|
|
$proc[] = 'xdebug.profiler_output_dir='.$profile_dir;
|
|
*/
|
|
|
|
|
|
|
|
self::$process = new \Symfony\Component\Process\Process($proc);
|
|
self::$process->start(function($type,$buffer){
|
|
self::$proc_output[] = ['type'=>$type,'buffer'=>(string)$buffer];
|
|
});
|
|
usleep(100000); //wait for server to get going
|
|
|
|
|
|
register_shutdown_function(function(){
|
|
self::Console('Stopping server process');
|
|
gptest_bootstrap::$process->stop();
|
|
|
|
usort(self::$tracking,function($a,$b){
|
|
if( $a['time'] == $b['time'] ){
|
|
return 0;
|
|
}
|
|
return ($a['time'] < $b['time']) ? 1 : -1;
|
|
});
|
|
|
|
self::Console('Slowest requests (the slowest will usually be because of scss compilation');
|
|
self::$tracking = array_slice(self::$tracking,0,5);
|
|
|
|
foreach(self::$tracking as $req){
|
|
self::Console(' - '.$req['url'].' in '.$req['class'].' took '.$req['time']);
|
|
}
|
|
|
|
});
|
|
}
|
|
|
|
|
|
/**
|
|
* Switch current guzzle client to $client_admin
|
|
*/
|
|
public static function UseAdmin(){
|
|
self::$client_current = self::$client_admin;
|
|
self::$is_admin = true;
|
|
}
|
|
|
|
/**
|
|
* Switch current guzzle client to $client_user
|
|
*/
|
|
public static function UseAnon(){
|
|
self::$client_current = self::$client_user;
|
|
self::$is_admin = false;
|
|
}
|
|
|
|
/**
|
|
* Print process output
|
|
*
|
|
*/
|
|
public static function ProcessOutput($type,$url){
|
|
|
|
echo "\n\n----------------------------------------------------------------";
|
|
self::Console('Begin Process Output: '.$type.' '.$url);
|
|
echo "\n";
|
|
|
|
if( !empty(self::$proc_output) ){
|
|
self::Console('Proc Output');
|
|
print_r(self::$proc_output);
|
|
}
|
|
echo "\nEnd Process Output\n----------------------------------------------------------------\n\n";
|
|
}
|
|
|
|
|
|
/**
|
|
* Send a GET request to the test server
|
|
*
|
|
*/
|
|
public static function GetRequest( $slug, $query='', $nonce_action=false ){
|
|
$url = \gp\tool::GetUrl( $slug, $query, false, $nonce_action);
|
|
return self::GuzzleRequest('GET',$url);
|
|
}
|
|
|
|
|
|
/**
|
|
* Send a POST request to the test server
|
|
*
|
|
*/
|
|
public static function PostRequest($slug, $params = []){
|
|
|
|
$url = \gp\tool::GetUrl($slug);
|
|
$options = ['form_params' => $params];
|
|
|
|
return self::GuzzleRequest('POST',$url,200,$options);
|
|
}
|
|
|
|
/**
|
|
* Send a request to the test server and check the response
|
|
*
|
|
*/
|
|
public static function GuzzleRequest($type,$url,$expected_resonse = 200, $options = []){
|
|
global $dataDir;
|
|
|
|
$start = microtime(true);
|
|
$response = null;
|
|
$debug_file = $dataDir . '/data/response-' . self::$requests . '-anon-' . $type . '-' . str_replace('/','_',$url);
|
|
if( self::$is_admin ){
|
|
$debug_file = $dataDir . '/data/response-' . self::$requests . '-admin-' . $type . '-' . str_replace('/','_',$url);
|
|
}
|
|
|
|
$tracking = [
|
|
'url' => $url,
|
|
'is_admin' => self::$is_admin,
|
|
'class' => get_called_class(),
|
|
];
|
|
|
|
|
|
try{
|
|
self::$proc_output = [];
|
|
$options['headers'] = ['X-REQ-ID' => self::$requests,'Connection'=>'close'];
|
|
$url = 'http://localhost:8081' . $url;
|
|
$response = self::$client_current->request($type, $url, $options);
|
|
$body = $response->getBody();
|
|
$status = $response->getStatusCode();
|
|
|
|
|
|
file_put_contents($debug_file, $body);
|
|
self::$requests++;
|
|
|
|
self::$process->getOutput(); # makes symfony/process populate our self::$proc_output
|
|
|
|
|
|
if( $expected_resonse !== $status ){
|
|
self::ProcessOutput($type,$url);
|
|
self::Console('PHPINFO()');
|
|
echo (string)self::$phpinfo;
|
|
}
|
|
self::assertEquals($expected_resonse, $status);
|
|
|
|
|
|
// make sure the response doesn't have <div id="gp_admin_html">
|
|
if( self::$is_admin === false ){
|
|
self::assertNotStrpos($body,'gp_admin_html');
|
|
}
|
|
|
|
self::ServerErrors($type,$url);
|
|
|
|
}catch( \Exception $e ){
|
|
self::ServerErrors($type,$url);
|
|
self::Fail('Exception fetching url '.$url.$e->getMessage());
|
|
}
|
|
|
|
$tracking['time'] = microtime(true) - $start;
|
|
self::$tracking[] = $tracking;
|
|
|
|
return $response;
|
|
}
|
|
|
|
|
|
/**
|
|
* Output Error log
|
|
*
|
|
*/
|
|
public static function ServerErrors($type,$url){
|
|
global $dataDir;
|
|
|
|
$error_log = $dataDir . '/data/request-errors.log';
|
|
if( !file_exists($error_log) ){
|
|
return;
|
|
}
|
|
|
|
$content = file_get_contents($error_log);
|
|
if( empty($content) ){
|
|
return;
|
|
}
|
|
|
|
echo "\n\n----------------------------------------------------------------";
|
|
self::Console('Error Log for '.$type.' '.$url);
|
|
echo "\n";
|
|
|
|
echo $content;
|
|
echo "\n\nEnd Error Log\n----------------------------------------------------------------\n\n";
|
|
|
|
$fp = fopen($error_log, "r+");
|
|
ftruncate($fp, 0);
|
|
fclose($fp);
|
|
|
|
self::assertEmpty($content,'php error log was not empty');
|
|
}
|
|
|
|
|
|
/**
|
|
* Log In
|
|
*
|
|
*/
|
|
public static function LogIn(){
|
|
|
|
// load login page to set cookies
|
|
$response = self::GetRequest('Admin');
|
|
|
|
$params = [];
|
|
$params['cmd'] = 'login';
|
|
$params['username'] = self::user_name;
|
|
$params['password'] = self::user_pass;
|
|
$params['login_nonce'] = \gp\tool\Nonce::Create('login_nonce',true,300);
|
|
$response = self::PostRequest('Admin',$params);
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
* Create an install folder in the temporary directory
|
|
*
|
|
*/
|
|
public static function PrepInstall(){
|
|
global $dataDir, $languages, $config;
|
|
|
|
|
|
|
|
// get a clean temporary install folder
|
|
$dataDir = sys_get_temp_dir().'/typesetter-test';
|
|
$old_dir = sys_get_temp_dir().'/typesetter-test-old';
|
|
if( file_exists($dataDir) ){
|
|
rename($dataDir,$old_dir);
|
|
}
|
|
mkdir($dataDir);
|
|
mkdir($dataDir.'/data');
|
|
|
|
|
|
|
|
|
|
// create symlinks of include, addons, and themes
|
|
$symlinks = ['include','addons','themes','gpconfig.php','index.php','vendor'];
|
|
foreach($symlinks as $name){
|
|
|
|
$path = $dataDir.'/'.$name;
|
|
$target = $_SERVER['PWD'].'/'.$name;
|
|
|
|
if( !file_exists($target) ){
|
|
self::Console('symlink target does not exist: '. $target);
|
|
continue;
|
|
}
|
|
|
|
if( file_exists($path) ){
|
|
unlink($path);
|
|
}
|
|
|
|
symlink( $target, $path);
|
|
}
|
|
|
|
|
|
// create a phpinfo.php file
|
|
$file = $dataDir.'/phpinfo.php';
|
|
$content = '<?php phpinfo();';
|
|
file_put_contents($file,$content);
|
|
|
|
|
|
|
|
include('include/common.php');
|
|
spl_autoload_register( array('\\gp\\tool','Autoload') );
|
|
require dirname(__DIR__) . '/vendor/autoload.php';
|
|
includeFile('tool/functions.php');
|
|
|
|
self::Console('datadir = '.$dataDir);
|
|
self::Console('gp_data_type = '.gp_data_type);
|
|
|
|
|
|
|
|
|
|
|
|
// delete old installation
|
|
\gp\tool\Files::RmAll($old_dir);
|
|
|
|
|
|
// reset coverage folder
|
|
$cov_dir = dirname(__DIR__).'/x_coverage';
|
|
if( file_exists($cov_dir) ){
|
|
self::Console('resetting coverage folder: '.$cov_dir);
|
|
\gp\tool\Files::RmAll($cov_dir);
|
|
}
|
|
mkdir($cov_dir);
|
|
}
|
|
|
|
|
|
/**
|
|
* Output a string to the console
|
|
*
|
|
*/
|
|
public static function Console($msg){
|
|
echo "\n";
|
|
echo "\e[0;32m";
|
|
echo $msg;
|
|
echo "\e[0m";
|
|
echo "\n";
|
|
}
|
|
|
|
/*
|
|
* Create an installation
|
|
*
|
|
*/
|
|
public static function Install(){
|
|
global $config;
|
|
|
|
|
|
//make sure it's not installed
|
|
$installed = \gp\tool::Installed();
|
|
self::AssertFalse($installed,'Cannot test installation (Already Installed)');
|
|
|
|
|
|
// test install checks
|
|
// one of the checks actually fails
|
|
$values = [1,1,-1,1,1,1];
|
|
$installer = new \gp\install\Installer();
|
|
foreach($values as $i => $val){
|
|
self::assertGreaterThanOrEqual( $val, $installer->statuses[$i]['can_install'], 'Unexpected status ('.$i.') '.pre($installer->statuses[$i]) );
|
|
}
|
|
|
|
|
|
|
|
// test rendering of the install template
|
|
$response = self::GetRequest('');
|
|
|
|
//ob_start();
|
|
//includeFile('install/install.php');
|
|
//$installer->Form_Entry();
|
|
//$content = ob_get_clean();
|
|
//self::assertNotEmpty($content);
|
|
|
|
|
|
|
|
//attempt to install
|
|
$params = [];
|
|
$params['site_title'] = 'unit tests';
|
|
$params['email'] = self::user_email;
|
|
$params['username'] = self::user_name;
|
|
$params['password'] = self::user_pass;
|
|
$params['password1'] = self::user_pass;
|
|
$params['cmd'] = 'Install';
|
|
$response = self::PostRequest('',$params);
|
|
|
|
|
|
|
|
//double check
|
|
$installed = \gp\tool::Installed();
|
|
self::AssertTrue($installed,'Not installed');
|
|
|
|
|
|
|
|
\gp\tool::GetConfig();
|
|
}
|
|
|
|
public static function assertStrpos( $haystack, $needle , $msg = 'String not found' ){
|
|
|
|
if( strpos($haystack, $needle) === false ){
|
|
self::fail($msg);
|
|
}
|
|
|
|
}
|
|
|
|
public static function assertNotStrpos( $haystack, $needle , $msg = 'String found' ){
|
|
|
|
if( strpos($haystack, $needle) !== false ){
|
|
self::fail($msg);
|
|
}
|
|
|
|
}
|
|
|
|
}
|