diff --git a/lib/deployers/Deployer.php b/lib/deployers/Deployer.php new file mode 100644 index 000000000..861ad3ba8 --- /dev/null +++ b/lib/deployers/Deployer.php @@ -0,0 +1,29 @@ +components = $components; + } + + /** + * Methods not implemented + * + * @param $method_name + * @param $arguments + * @return null + */ + public function __call($method_name, $arguments) + { + return null; + } +} \ No newline at end of file diff --git a/lib/deployers/DummyDeployer.php b/lib/deployers/DummyDeployer.php new file mode 100644 index 000000000..12fcdc74d --- /dev/null +++ b/lib/deployers/DummyDeployer.php @@ -0,0 +1,17 @@ +credentials = $credentials; - } - - public function getUrl() + function __construct($credentials) { - return "http://".$this->domain."/".$this->run_id."/"; + $this->credentials = $credentials; } - public function getDsn() + public function start() { - $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) - { self::println(); self::println("=== cPanel Deployer – Bring Up ==="); $creds = $this->credentials; if (!$creds['hostname'] || - !$creds['username'] || - !$creds['password']) + !$creds['username'] || + !$creds['password']) { self::println("Cannot deploy cPanel environment because credentials are missing. Falling back to manual mode…"); return false; @@ -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() @@ -110,7 +70,7 @@ class cPanelDeployer $username = &$this->credentials['username']; $password = &$this->credentials['password']; $hostname = &$this->credentials['hostname']; - + $this->run_id = $run_id = uniqid(self::TEST_PREFIX); self::println("Test run ID: ".$this->run_id); @@ -118,7 +78,7 @@ class cPanelDeployer $this->cPanel = $cPanel = new cpanelAPI($username, $password, $hostname); self::println("Connecting to cPanel at \"${hostname}\" with username \"${username}\"…"); - + $domains_data = $cPanel->uapi->DomainInfo->domains_data(); if (!$domains_data) { @@ -134,113 +94,22 @@ class cPanelDeployer self::println("Obtained domain name from cPanel: " . $this->domain); $acceptance_tests = self::get_active_acceptance_tests($cPanel, $homedir); - + self::println("Adding this test (".$this->run_id.") to registered tests list…"); $run_time = microtime(true); array_push($acceptance_tests, - ['id' => $run_id, - 'time' => $run_time - ]); - + ['id' => $run_id, + 'time' => $run_time + ]); + self::write_acceptance_tests($cPanel, $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); } - private function prepare_db() - { - $cPanel = $this->cPanel; - $username = &$this->credentials['username']; - $run_id = &$this->run_id; - $this->db_id = $db_id = "${username}_${run_id}"; - - self::println("Ensuring that MySQL users allow any remote access hosts (%)…"); - $remote_hosts = $cPanel->api2->MysqlFE->gethosts()->{'cpanelresult'}->{'data'}; - if (!in_array('%', $remote_hosts, true)) - { - $cPanel->uapi->Mysql->add_host(['host' => '%']); - register_shutdown_function(function() use ($cPanel) - { - self::clean_mysql_remote_hosts($cPanel); - }); - } - else - { - $this->skip_mysql_remote_hosts = true; - } - - self::println("Creating new MySQL database \"${db_id}\"…"); - $cPanel->uapi->Mysql->create_database(['name' => $db_id]); - - self::println("Creating new MySQL user \"${db_id}\" with password \"${run_id}\"…"); - $cPanel->uapi->Mysql->create_user(['name' => $db_id, 'password' => $run_id]); - self::println("Granting ALL PRIVILEGES to MySQL user \"${db_id}\"…"); - $cPanel->uapi->Mysql->set_privileges_on_database(['user' => $db_id, - 'database' => $db_id, - 'privileges' => 'ALL PRIVILEGES' - ]); - } - - private function prepare_fs() - { - $cPanel = $this->cPanel; - $app_archive = self::archive_app(APP_PATH, $this->run_id); - $app_archive_path = stream_get_meta_data($app_archive)['uri']; - $app_archive_name = basename($app_archive_path); - self::println("Sending archive to cPanel server…"); - $cPanel->uapi->post->Fileman - ->upload_files(['dir' => self::TARGET_RELPATH, - 'file-1' => new CURLFile($app_archive_path) - ]); - self::println("Extracting archive on cPanel server…"); - $cPanel->api2->Fileman - ->fileop(['op' => 'extract', - 'sourcefiles' => self::TARGET_RELPATH.$app_archive_name, - 'destfiles' => '.' - ]); - self::println("Deleting archive from cPanel server…"); - $cPanel->api2->Fileman - ->fileop(['op' => 'unlink', - 'sourcefiles' => self::TARGET_RELPATH.$app_archive_name - ]); - } - - 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…"); @@ -269,6 +138,14 @@ class cPanelDeployer 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 = []; @@ -279,12 +156,27 @@ class cPanelDeployer return $ids; } - private static function write_acceptance_tests($cPanel, $homedir, $acceptance_tests) + private static function prune_inactive_acceptance_test_resources($cPanel, $valid_acceptance_test_ids) { - $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]); + 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) @@ -321,16 +213,139 @@ class cPanelDeployer } } + 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("Removed cPanel MySQL remote host '%'"); - $response = $cPanel->uapi->Mysql->delete_host(['host' => '%']); + 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; + $username = &$this->credentials['username']; + $run_id = &$this->run_id; + $this->db_id = $db_id = "${username}_${run_id}"; + + self::println("Ensuring that MySQL users allow any remote access hosts (%)…"); + $remote_hosts = $cPanel->api2->MysqlFE->gethosts()->{'cpanelresult'}->{'data'}; + if (!in_array('%', $remote_hosts, true)) + { + $cPanel->uapi->Mysql->add_host(['host' => '%']); + register_shutdown_function(function() use ($cPanel) + { + self::clean_mysql_remote_hosts($cPanel); + }); + } + else + { + $this->skip_mysql_remote_hosts = true; + } + + self::println("Creating new MySQL database \"${db_id}\"…"); + $cPanel->uapi->Mysql->create_database(['name' => $db_id]); + + self::println("Creating new MySQL user \"${db_id}\" with password \"${run_id}\"…"); + $cPanel->uapi->Mysql->create_user(['name' => $db_id, 'password' => $run_id]); + self::println("Granting ALL PRIVILEGES to MySQL user \"${db_id}\"…"); + $cPanel->uapi->Mysql->set_privileges_on_database(['user' => $db_id, + 'database' => $db_id, + 'privileges' => 'ALL PRIVILEGES' + ]); + } + + private function prepare_fs() + { + $cPanel = $this->cPanel; + $app_archive = self::archive_app(APP_PATH, $this->run_id); + $app_archive_path = stream_get_meta_data($app_archive)['uri']; + $app_archive_name = basename($app_archive_path); + self::println("Sending archive to cPanel server…"); + $cPanel->uapi->post->Fileman + ->upload_files(['dir' => self::TARGET_RELPATH, + 'file-1' => new CURLFile($app_archive_path) + ]); + self::println("Extracting archive on cPanel server…"); + $cPanel->api2->Fileman + ->fileop(['op' => 'extract', + 'sourcefiles' => self::TARGET_RELPATH.$app_archive_name, + 'destfiles' => '.' + ]); + self::println("Deleting archive from cPanel server…"); + $cPanel->api2->Fileman + ->fileop(['op' => 'unlink', + 'sourcefiles' => self::TARGET_RELPATH.$app_archive_name + ]); + } + private static function archive_app($path, $prefix = '') { $tmp_file = tmpfile(); @@ -347,10 +362,10 @@ class cPanelDeployer if (substr($realpath, 0, strlen($path)) === $path) $relpath = substr($realpath, strlen($path)); if (substr($relpath, -3) === "/.." || - substr($relpath, -2) === "/." || - !file_exists($realpath) || - !is_file($realpath) || - empty($relpath)) continue; + substr($relpath, -2) === "/." || + !file_exists($realpath) || + !is_file($realpath) || + empty($relpath)) continue; $relpath = $prefix . $relpath; $archive->addFile($realpath, $relpath); } @@ -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]); + } } diff --git a/tests/_support/Helper/Acceptance.php b/tests/_support/Helper/Acceptance.php index 135323bb7..087998a35 100644 --- a/tests/_support/Helper/Acceptance.php +++ b/tests/_support/Helper/Acceptance.php @@ -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"); + } + } } diff --git a/tests/_support/Helper/Base.php b/tests/_support/Helper/Base.php index 2367c77b9..b3bd13d24 100644 --- a/tests/_support/Helper/Base.php +++ b/tests/_support/Helper/Base.php @@ -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->_callbackDeployerStarted(); - } + $this->deployer->setComponents($this->deployer_components); + + $this->deployer->start(); + $this->_callbackDeployerStarted(); + foreach ($this->getModules() as $module) { if (get_class($module) !== get_class($this)) @@ -33,40 +38,23 @@ abstract class Base extends \Codeception\Module public function _afterSuite() { - if (is_object($this->deployer)) - $this->deployer->stop(); + $this->deployer->stop(); } protected function _callbackDeployerStarted() { 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(); } } diff --git a/tests/_support/Helper/DeployerFactory.php b/tests/_support/Helper/DeployerFactory.php index 813d9e9fe..00da9a411 100644 --- a/tests/_support/Helper/DeployerFactory.php +++ b/tests/_support/Helper/DeployerFactory.php @@ -1,20 +1,32 @@ 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']); diff --git a/tests/acceptance/0000_InstallCest.php b/tests/acceptance/0000_InstallCest.php index a0913dc76..cef6c1151 100644 --- a/tests/acceptance/0000_InstallCest.php +++ b/tests/acceptance/0000_InstallCest.php @@ -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'); - } }