1
0
mirror of https://github.com/e107inc/e107.git synced 2025-08-07 15:16:30 +02:00

Started a basic interface to manipulate files in acceptance tests

- MOD: Renamed lib/deployers/cpanel_deployer.php to
       lib/deployers/cPanelDeployer.php
- MOD: Moved responsibility of reconfiguring Codeception modules to the
       deployers.
- NEW: Abstract class Deployer to standardize the interface to Deployers
- NEW: Acceptance tests now support unlinkE107ConfigFromTestEnvironment
- MOD: Removed null checks for the Deployer in the Base Module
- MOD: Improved public method naming in the Base Module
- MOD: DeployerFactory always returns a Deployer implementation now.
- MOD: InstallCest always clears out the e107_config.php file before
       each test.
This commit is contained in:
Nick Liu
2018-08-14 16:03:30 -05:00
parent 58cd6f1c05
commit b5b59392eb
7 changed files with 291 additions and 217 deletions

View File

@@ -0,0 +1,29 @@
<?php
abstract class Deployer
{
abstract public function start();
abstract public function stop();
protected $components = array();
/**
* @param array $components
*/
public function setComponents($components)
{
$this->components = $components;
}
/**
* Methods not implemented
*
* @param $method_name
* @param $arguments
* @return null
*/
public function __call($method_name, $arguments)
{
return null;
}
}

View File

@@ -0,0 +1,17 @@
<?php
class DummyDeployer extends Deployer
{
public function start()
{
// Noop
return null;
}
public function stop()
{
// Noop
return null;
}
}

View File

@@ -1,59 +1,28 @@
<?php
include_once(__DIR__ . "/../cpaneluapi/cpaneluapi.class.php");
include_once(__DIR__ . "/Deployer.php");
class cPanelDeployer
class cPanelDeployer extends Deployer
{
protected $credentials;
protected $cPanel;
protected $run_id;
protected $db_id;
protected $homedir;
protected $docroot;
protected $domain;
private $skip_mysql_remote_hosts = false;
const TEST_PREFIX = 'test_';
const TARGET_RELPATH = 'public_html/';
const DEFAULT_COMPONENTS = ['db', 'fs'];
protected $credentials;
protected $cPanel;
protected $run_id;
protected $db_id;
protected $homedir;
protected $docroot;
protected $domain;
private $skip_mysql_remote_hosts = false;
function __construct($credentials)
{
$this->credentials = $credentials;
}
public function getUrl()
{
return "http://".$this->domain."/".$this->run_id."/";
}
public function getDsn()
{
$hostname = $this->credentials['hostname'];
$db_id = $this->db_id;
return "mysql:host=${hostname};dbname=${db_id}";
}
public function getDbName()
{
return $this->db_id;
}
public function getDbUsername()
{
return $this->db_id;
}
public function getDbPassword()
{
return $this->run_id;
}
public function start($components = self::DEFAULT_COMPONENTS)
public function start()
{
self::println();
self::println("=== cPanel Deployer Bring Up ===");
@@ -68,7 +37,7 @@ class cPanelDeployer
$this->prepare();
foreach ($components as $component)
foreach ($this->components as $component)
{
$method = "prepare_${component}";
if (!method_exists($this, $method))
@@ -77,7 +46,7 @@ class cPanelDeployer
return false;
}
}
foreach ($components as $component)
foreach ($this->components as $component)
{
$method = "prepare_${component}";
$this->$method();
@@ -86,23 +55,14 @@ class cPanelDeployer
return true;
}
public function stop()
private static function println($text = '')
{
self::println("=== cPanel Deployer Tear Down ===");
$cPanel = $this->cPanel;
$acceptance_tests = self::get_active_acceptance_tests($cPanel, $this->homedir);
self::println("Removing this test (".$this->run_id.") from registered tests list…");
self::prune_acceptance_tests($acceptance_tests, $this->run_id);
self::write_acceptance_tests($cPanel, $this->homedir, $acceptance_tests);
codecept_debug($text);
$valid_acceptance_test_ids = self::get_acceptance_test_ids($acceptance_tests);
self::println("Current unexpired tests: [".implode(", ", $valid_acceptance_test_ids)."]");
self::prune_inactive_acceptance_test_resources($cPanel, $valid_acceptance_test_ids);
//echo("${text}\n");
if (!$this->skip_mysql_remote_hosts)
{
self::clean_mysql_remote_hosts($cPanel);
}
//$prefix = debug_backtrace()[1]['function'];
//echo("[\033[1m${prefix}\033[0m] ${text}\n");
}
private function prepare()
@@ -150,6 +110,184 @@ class cPanelDeployer
self::prune_inactive_acceptance_test_resources($cPanel, $valid_acceptance_test_ids);
}
private static function get_active_acceptance_tests($cPanel, $homedir)
{
self::println("Retrieving existing registered tests from cPanel account…");
$acceptance_tests = [];
$acceptance_tests_apiresponse = $cPanel->uapi->Fileman->get_file_content(['dir' => $homedir, 'file' => 'acceptance_tests.status.txt']);
if (!is_null($acceptance_tests_apiresponse->{'data'}))
{
$acceptance_tests_raw = $acceptance_tests_apiresponse->{'data'}->{'content'};
$acceptance_tests = (array) json_decode($acceptance_tests_raw, true);
self::prune_acceptance_tests($acceptance_tests);
}
return $acceptance_tests;
}
private static function prune_acceptance_tests(array &$list, $id_to_remove = null)
{
foreach ($list as $key => $item)
{
$time = $item['time'];
if ($item['id'] === $id_to_remove || $time <= strtotime("now - 10 seconds"))
{
unset($list[$key]);
}
}
$list = array_values($list);
return $list;
}
private static function write_acceptance_tests($cPanel, $homedir, $acceptance_tests)
{
$acceptance_tests_json = json_encode($acceptance_tests, JSON_PRETTY_PRINT);
self::println("Saving registered tests list to cPanel account…");
$cPanel->uapi->Fileman->save_file_content(['dir' => $homedir, 'file' => 'acceptance_tests.status.txt', 'content' => $acceptance_tests_json]);
}
private static function get_acceptance_test_ids(array $list)
{
$ids = [];
foreach ($list as $item)
{
$ids[] = $item['id'];
}
return $ids;
}
private static function prune_inactive_acceptance_test_resources($cPanel, $valid_acceptance_test_ids)
{
self::println("Pruning expired tests…");
$listdbs = $cPanel->api2->MysqlFE->listdbs()->{'cpanelresult'}->{'data'};
self::prune_mysql_databases($listdbs, $valid_acceptance_test_ids, $cPanel);
$listdbusers = $cPanel->api2->MysqlFE->listusers()->{'cpanelresult'}->{'data'};
self::prune_mysql_users($listdbusers, $valid_acceptance_test_ids, $cPanel);
$target_files_apiresponse = $cPanel->uapi->Fileman->list_files(['dir' => self::TARGET_RELPATH]);
$target_files = $target_files_apiresponse->{'data'};
foreach ($target_files as $target_file)
{
$questionable_filename = $target_file->{'file'};
if (substr($questionable_filename, 0, strlen(self::TEST_PREFIX)) === self::TEST_PREFIX &&
!in_array($questionable_filename, $valid_acceptance_test_ids))
{
self::println("Deleting expired test folder \"".self::TARGET_RELPATH.$questionable_filename."\"");
$cPanel->api2->Fileman->fileop(['op' => 'unlink', 'sourcefiles' => self::TARGET_RELPATH.$questionable_filename]);
}
}
}
private static function prune_mysql_databases($dbs, $ids, $cPanel)
{
$prefix = $cPanel->user."_".self::TEST_PREFIX;
foreach ($dbs as $db)
{
$db = (array) $db;
if (substr($db['db'], 0, strlen($prefix)) !== $prefix)
continue;
$questionable_db = substr($db['db'], strlen($prefix));
if (!in_array($questionable_db, $ids))
{
self::println("Deleting expired MySQL database \"".$db['db']."\"");
$cPanel->uapi->Mysql->delete_database(['name' => $db['db']]);
}
}
}
private static function prune_mysql_users($users, $ids, $cPanel)
{
$prefix = $cPanel->user."_".self::TEST_PREFIX;
foreach ($users as $user)
{
$user = (array) $user;
if (substr($user['user'], 0, strlen($prefix)) !== $prefix)
continue;
$questionable_user = substr($user['user'], strlen($prefix));
if (!in_array($questionable_user, $ids))
{
self::println("Deleting expired MySQL user \"".$user['user']."\"");
$cPanel->uapi->Mysql->delete_user(['name' => $user['user']]);
}
}
}
public function stop()
{
self::println("=== cPanel Deployer Tear Down ===");
$cPanel = $this->cPanel;
$acceptance_tests = self::get_active_acceptance_tests($cPanel, $this->homedir);
self::println("Removing this test (".$this->run_id.") from registered tests list…");
self::prune_acceptance_tests($acceptance_tests, $this->run_id);
self::write_acceptance_tests($cPanel, $this->homedir, $acceptance_tests);
$valid_acceptance_test_ids = self::get_acceptance_test_ids($acceptance_tests);
self::println("Current unexpired tests: [".implode(", ", $valid_acceptance_test_ids)."]");
self::prune_inactive_acceptance_test_resources($cPanel, $valid_acceptance_test_ids);
if (!$this->skip_mysql_remote_hosts)
{
self::clean_mysql_remote_hosts($cPanel);
}
}
private static function clean_mysql_remote_hosts($cPanel)
{
$remote_hosts = $cPanel->api2->MysqlFE->gethosts()->{'cpanelresult'}->{'data'};
if (in_array('%', $remote_hosts, true))
{
self::println("Removing cPanel MySQL remote host '%'…");
$cPanel->uapi->Mysql->delete_host(['host' => '%']);
}
}
public function reconfigure_db($module)
{
$db = $module->getDbModule();
$Db_config = $db->_getConfig();
$Db_config['dsn'] = $this->getDsn();
$Db_config['user'] = $this->getDbUsername();
$Db_config['password'] = $this->getDbPassword();
$db->_reconfigure($Db_config);
// Next line is used to make connection available to any code after this point
//$this->getModule('\Helper\DelayedDb')->_delayedInitialize();
}
private function getDsn()
{
$hostname = $this->credentials['hostname'];
$db_id = $this->getDbName();
return "mysql:host=${hostname};dbname=${db_id}";
}
private function getDbName()
{
return $this->db_id;
}
private function getDbUsername()
{
return $this->db_id;
}
private function getDbPassword()
{
return $this->run_id;
}
public function reconfigure_fs($module)
{
$url = $this->getUrl();
$browser = $module->getBrowserModule();
$browser->_reconfigure(array('url' => $url));
}
private function getUrl()
{
return "http://".$this->domain."/".$this->run_id."/";
}
private function prepare_db()
{
$cPanel = $this->cPanel;
@@ -208,129 +346,6 @@ class cPanelDeployer
]);
}
private static function println($text = '')
{
codecept_debug($text);
//echo("${text}\n");
//$prefix = debug_backtrace()[1]['function'];
//echo("[\033[1m${prefix}\033[0m] ${text}\n");
}
private static function prune_inactive_acceptance_test_resources($cPanel, $valid_acceptance_test_ids)
{
self::println("Pruning expired tests…");
$listdbs = $cPanel->api2->MysqlFE->listdbs()->{'cpanelresult'}->{'data'};
self::prune_mysql_databases($listdbs, $valid_acceptance_test_ids, $cPanel);
$listdbusers = $cPanel->api2->MysqlFE->listusers()->{'cpanelresult'}->{'data'};
self::prune_mysql_users($listdbusers, $valid_acceptance_test_ids, $cPanel);
$target_files_apiresponse = $cPanel->uapi->Fileman->list_files(['dir' => self::TARGET_RELPATH]);
$target_files = $target_files_apiresponse->{'data'};
foreach ($target_files as $target_file)
{
$questionable_filename = $target_file->{'file'};
if (substr($questionable_filename, 0, strlen(self::TEST_PREFIX)) === self::TEST_PREFIX &&
!in_array($questionable_filename, $valid_acceptance_test_ids))
{
self::println("Deleting expired test folder \"".self::TARGET_RELPATH.$questionable_filename."\"");
$cPanel->api2->Fileman->fileop(['op' => 'unlink', 'sourcefiles' => self::TARGET_RELPATH.$questionable_filename]);
}
}
}
private static function get_active_acceptance_tests($cPanel, $homedir)
{
self::println("Retrieving existing registered tests from cPanel account…");
$acceptance_tests = [];
$acceptance_tests_apiresponse = $cPanel->uapi->Fileman->get_file_content(['dir' => $homedir, 'file' => 'acceptance_tests.status.txt']);
if (!is_null($acceptance_tests_apiresponse->{'data'}))
{
$acceptance_tests_raw = $acceptance_tests_apiresponse->{'data'}->{'content'};
$acceptance_tests = (array) json_decode($acceptance_tests_raw, true);
self::prune_acceptance_tests($acceptance_tests);
}
return $acceptance_tests;
}
private static function prune_acceptance_tests(array &$list, $id_to_remove = null)
{
foreach ($list as $key => $item)
{
$time = $item['time'];
if ($item['id'] === $id_to_remove || $time <= strtotime("now - 10 seconds"))
{
unset($list[$key]);
}
}
$list = array_values($list);
return $list;
}
private static function get_acceptance_test_ids(array $list)
{
$ids = [];
foreach ($list as $item)
{
$ids[] = $item['id'];
}
return $ids;
}
private static function write_acceptance_tests($cPanel, $homedir, $acceptance_tests)
{
$acceptance_tests_json = json_encode($acceptance_tests, JSON_PRETTY_PRINT);
self::println("Saving registered tests list to cPanel account…");
$cPanel->uapi->Fileman->save_file_content(['dir' => $homedir, 'file' => 'acceptance_tests.status.txt', 'content' => $acceptance_tests_json]);
}
private static function prune_mysql_databases($dbs, $ids, $cPanel)
{
$prefix = $cPanel->user."_".self::TEST_PREFIX;
foreach ($dbs as $db)
{
$db = (array) $db;
if (substr($db['db'], 0, strlen($prefix)) !== $prefix)
continue;
$questionable_db = substr($db['db'], strlen($prefix));
if (!in_array($questionable_db, $ids))
{
self::println("Deleting expired MySQL database \"".$db['db']."\"");
$cPanel->uapi->Mysql->delete_database(['name' => $db['db']]);
}
}
}
private static function prune_mysql_users($users, $ids, $cPanel)
{
$prefix = $cPanel->user."_".self::TEST_PREFIX;
foreach ($users as $user)
{
$user = (array) $user;
if (substr($user['user'], 0, strlen($prefix)) !== $prefix)
continue;
$questionable_user = substr($user['user'], strlen($prefix));
if (!in_array($questionable_user, $ids))
{
self::println("Deleting expired MySQL user \"".$user['user']."\"");
$cPanel->uapi->Mysql->delete_user(['name' => $user['user']]);
}
}
}
private static function clean_mysql_remote_hosts($cPanel)
{
$remote_hosts = $cPanel->api2->MysqlFE->gethosts()->{'cpanelresult'}->{'data'};
if (in_array('%', $remote_hosts, true))
{
self::println("Removed cPanel MySQL remote host '%'");
$response = $cPanel->uapi->Mysql->delete_host(['host' => '%']);
}
}
private static function archive_app($path, $prefix = '')
{
$tmp_file = tmpfile();
@@ -358,4 +373,11 @@ class cPanelDeployer
return $tmp_file;
}
public function unlinkAppFile($relative_path)
{
self::println("Deleting file \"$relative_path\" from deployed test location…");
$this->cPanel->api2->Fileman->fileop(['op' => 'unlink',
'sourcefiles' => self::TARGET_RELPATH.$this->run_id."/".$relative_path]);
}
}

View File

@@ -13,4 +13,16 @@ class Acceptance extends E107Base
// Noop
// Acceptance tests will install the app themselves
}
public function unlinkE107ConfigFromTestEnvironment()
{
// cPanel Environment
$this->deployer->unlinkAppFile("e107_config.php");
// Local Environment
if (file_exists(APP_PATH."/e107_config.php"))
{
unlink(APP_PATH."/e107_config.php");
}
}
}

View File

@@ -11,19 +11,24 @@ abstract class Base extends \Codeception\Module
protected $db;
public function getHelperDb()
public function getDbModule()
{
return $this->db ?: $this->db = $this->getModule('\Helper\DelayedDb');
}
public function getBrowserModule()
{
return $this->getModule('PhpBrowser');
}
public function _beforeSuite($settings = array())
{
$this->deployer = $this->getModule('\Helper\DeployerFactory')->create();
if (is_object($this->deployer))
{
$this->deployer->start($this->deployer_components);
$this->deployer->setComponents($this->deployer_components);
$this->deployer->start();
$this->_callbackDeployerStarted();
}
foreach ($this->getModules() as $module)
{
if (get_class($module) !== get_class($this))
@@ -33,7 +38,6 @@ abstract class Base extends \Codeception\Module
public function _afterSuite()
{
if (is_object($this->deployer))
$this->deployer->stop();
}
@@ -41,32 +45,16 @@ abstract class Base extends \Codeception\Module
{
foreach ($this->deployer_components as $component)
{
$method = "_reconfigure_${component}";
$this->$method();
$method = "reconfigure_${component}";
if (method_exists($this->deployer, $method))
{
$this->deployer->$method($this);
}
}
}
public function _before(\Codeception\TestCase $test = null)
{
if (is_object($this->deployer)) $this->_callbackDeployerStarted();
}
protected function _reconfigure_fs()
{
$url = $this->deployer->getUrl();
$browser = $this->getModule('PhpBrowser');
$browser->_reconfigure(array('url' => $url));
}
protected function _reconfigure_db()
{
$db = $this->getHelperDb();
$Db_config = $db->_getConfig();
$Db_config['dsn'] = $this->deployer->getDsn();
$Db_config['user'] = $this->deployer->getDbUsername();
$Db_config['password'] = $this->deployer->getDbPassword();
$db->_reconfigure($Db_config);
// Next line is used to make connection available to any code after this point
//$this->getModule('\Helper\DelayedDb')->_delayedInitialize();
$this->_callbackDeployerStarted();
}
}

View File

@@ -1,20 +1,32 @@
<?php
namespace Helper;
include_once(__DIR__ . "/../../../lib/deployers/cpanel_deployer.php");
$deployers_path = __DIR__ . "/../../../lib/deployers";
include_once("{$deployers_path}/Deployer.php");
foreach (glob("{$deployers_path}/*.php") as $path)
{
include_once($path);
}
// here you can define custom actions
// all public methods declared in helper class will be available in $I
class DeployerFactory extends \Codeception\Module
{
/**
* @return \Deployer
*/
public function create()
{
return $this->createFromSecrets($this->config['secrets']);
}
/**
* @param $secrets
* @return \Deployer
*/
public function createFromSecrets($secrets)
{
$deployer = null;
$deployer = new \DummyDeployer();
if ($secrets['cpanel']['enabled'] === '1')
{
$deployer = new \cPanelDeployer($secrets['cpanel']);

View File

@@ -5,6 +5,7 @@ class InstallCest
{
public function _before(AcceptanceTester $I)
{
$I->unlinkE107ConfigFromTestEnvironment();
}
public function _after(AcceptanceTester $I)
@@ -43,15 +44,10 @@ class InstallCest
}
private function installe107(AcceptanceTester $I, $parms=array())
private function installe107(AcceptanceTester $I, $params = array())
{
// Step 1
if(file_exists(APP_PATH."/e107_config.php")) // because we do mutliple installation scenarios.
{
unlink(APP_PATH."/e107_config.php");
}
$I->amOnPage('/install.php');
$I->selectOption("language", 'English');
$I->click('start');
@@ -60,7 +56,7 @@ class InstallCest
$I->see("MySQL Server Details", 'h3');
$db = $I->getHelperDb();
$db = $I->getDbModule();
$I->fillField('server', $db->_getDbHostname());
$I->fillField('name', $db->_getDbUsername());
@@ -110,9 +106,9 @@ class InstallCest
$I->see("Website Preferences", 'h3');
$I->fillField('sitename', 'Test Site');
if(!empty($parms['sitetheme']))
if(!empty($params['sitetheme']))
{
$I->selectOption('sitetheme', $parms['sitetheme']);
$I->selectOption('sitetheme', $params['sitetheme']);
}
$I->click('submit');
@@ -130,14 +126,13 @@ class InstallCest
$I->amOnPage('/index.php');
if(!empty($parms['sitetheme']))
if(!empty($params['sitetheme']))
{
$I->seeInSource('e107_themes/'.$parms['sitetheme']);
$I->seeInSource('e107_themes/'.$params['sitetheme']);
}
}
private function loginToAdmin(AcceptanceTester $I)
{
$I->amOnPage('/e107_admin/admin.php');
@@ -156,7 +151,6 @@ class InstallCest
$I->wantTo("Check there are no updates required after install");
$I->dontSee("Update", 'button span');
}
}