X-Git-Url: http://www.aleph1.co.uk/gitweb/?p=yaffs-website;a=blobdiff_plain;f=vendor%2Fdrush%2Fdrush%2Ftests%2FUnishTestCase.php;fp=vendor%2Fdrush%2Fdrush%2Ftests%2FUnishTestCase.php;h=9a30848598182bc06f987520d07732c06f1dabca;hp=0000000000000000000000000000000000000000;hb=af6d1fb995500ae68849458ee10d66abbdcfb252;hpb=680c79a86e3ed402f263faeac92e89fb6d9edcc0 diff --git a/vendor/drush/drush/tests/UnishTestCase.php b/vendor/drush/drush/tests/UnishTestCase.php new file mode 100644 index 000000000..9a3084859 --- /dev/null +++ b/vendor/drush/drush/tests/UnishTestCase.php @@ -0,0 +1,661 @@ +>>%s<< $site) { + $aliases[$key] = '@sut.' . $key; + } + return $aliases; + } + + public static function getUri($site = 'dev') + { + return self::$sites[$site]['uri']; + } + + /** + * @return string + */ + public static function getDrush() + { + return self::$drush; + } + + /** + * @return string + */ + public static function getTmp() + { + return self::$tmp; + } + + /** + * @return string + */ + public static function getSandbox() + { + return self::$sandbox; + } + + /** + * @return string + */ + public static function getSut() + { + return Path::join(self::getTmp(), 'drush-sut'); + } + + /** + * - Remove sandbox directory. + * - Empty /modules, /profiles, /themes in SUT. + */ + public static function cleanDirs() + { + if (empty(getenv('UNISH_DIRTY'))) { + $sandbox = self::getSandbox(); + if (file_exists($sandbox)) { + self::recursiveDelete($sandbox); + } + foreach (['modules', 'themes', 'profiles', 'drush'] as $dir) { + $target = Path::join(self::getSut(), 'web', $dir, 'contrib'); + if (file_exists($target)) { + self::recursiveDeleteDirContents($target); + } + } + foreach (['sites/dev', 'sites/stage', 'sites/prod'] as $dir) { + $target = Path::join(self::getSut(), 'web', $dir); + if (file_exists($target)) { + self::recursiveDelete($target); + } + } + } + } + + /** + * @return string + */ + public static function getDbUrl() + { + return self::$db_url; + } + + /** + * @return string + */ + public static function getUserGroup() + { + return self::$usergroup; + } + + /** + * @return string + */ + public static function getBackendOutputDelimiter() + { + return self::$backendOutputDelimiter; + } + + public function __construct($name = null, array $data = [], $dataName = '') + { + parent::__construct($name, $data, $dataName); + + // Default drupal major version to run tests over. + // @todo Remove this. + if (!defined('UNISH_DRUPAL_MAJOR_VERSION')) { + define('UNISH_DRUPAL_MAJOR_VERSION', '8'); + } + + // We read from env then globals then default to mysql. + self::$db_url = getenv('UNISH_DB_URL') ?: (isset($GLOBALS['UNISH_DB_URL']) ? $GLOBALS['UNISH_DB_URL'] : 'mysql://root:@127.0.0.1'); + + require_once __DIR__ . '/unish.inc'; + list($unish_tmp, $unish_sandbox, $unish_drush_dir) = \unishGetPaths(); + $unish_cache = Path::join($unish_sandbox, 'cache'); + + self::$drush = $unish_drush_dir . '/drush'; + self::$tmp = $unish_tmp; + self::$sandbox = $unish_sandbox; + self::$usergroup = isset($GLOBALS['UNISH_USERGROUP']) ? $GLOBALS['UNISH_USERGROUP'] : null; + + self::setEnv(['CACHE_PREFIX' => $unish_cache]); + $home = $unish_sandbox . '/home'; + self::setEnv(['HOME' => $home]); + self::setEnv(['HOMEDRIVE' => $home]); + $composer_home = $unish_cache . '/.composer'; + self::setEnv(['COMPOSER_HOME' => $composer_home]); + self::setEnv(['ETC_PREFIX' => $unish_sandbox]); + self::setEnv(['SHARE_PREFIX' => $unish_sandbox]); + self::setEnv(['TEMP' => Path::join($unish_sandbox, 'tmp')]); + self::setEnv(['DRUSH_AUTOLOAD_PHP' => PHPUNIT_COMPOSER_INSTALL]); + } + + /** + * We used to assure that each class starts with an empty sandbox directory and + * a clean environment except for the SUT. History: http://drupal.org/node/1103568. + */ + public static function setUpBeforeClass() + { + self::cleanDirs(); + + // Create all the dirs. + $sandbox = self::getSandbox(); + $dirs = [getenv('HOME') . '/.drush', $sandbox . '/etc/drush', $sandbox . '/share/drush/commands', "$sandbox/cache", getenv('TEMP')]; + foreach ($dirs as $dir) { + self::mkdir($dir); + } + + if (strtoupper(substr(PHP_OS, 0, 3)) === 'WIN') { + // Hack to make git use unix line endings on windows + exec("git config --file $sandbox\\home\\.gitconfig core.autocrlf false", $output, $return); + } + parent::setUpBeforeClass(); + } + + /** + * Runs after all tests in a class are run. + */ + public static function tearDownAfterClass() + { + self::cleanDirs(); + + self::$sites = []; + parent::tearDownAfterClass(); + } + + /** + * Print a log message to the console. + * + * @param string $message + * @param string $type + * Supported types are: + * - notice + * - verbose + * - debug + */ + public function log($message, $type = 'notice') + { + $line = "\nLog: $message\n"; + switch ($this->logLevel()) { + case 'verbose': + if (in_array($type, ['notice', 'verbose'])) { + fwrite(STDERR, $line); + } + break; + case 'debug': + fwrite(STDERR, $line); + break; + default: + if ($type == 'notice') { + fwrite(STDERR, $line); + } + break; + } + } + + public function logLevel() + { + // -d is reserved by `phpunit` + if (in_array('--debug', $_SERVER['argv'])) { + return 'debug'; + } elseif (in_array('--verbose', $_SERVER['argv']) || in_array('-v', $_SERVER['argv'])) { + return 'verbose'; + } + } + + public static function isWindows() + { + return strtoupper(substr(PHP_OS, 0, 3)) == "WIN"; + } + + public static function getTarExecutable() + { + return self::isWindows() ? "bsdtar.exe" : "tar"; + } + + /** + * Print out a tick mark. + * + * Useful for longer running tests to indicate they're working. + */ + public function tick() + { + static $chars = ['/', '-', '\\', '|']; + static $counter = 0; + // ANSI support is flaky on Win32, so don't try to do ticks there. + if (!$this->isWindows()) { + print $chars[($counter++ % 4)] . "\033[1D"; + } + } + + /** + * Borrowed from Drush. + * Checks operating system and returns + * supported bit bucket folder. + */ + public function bitBucket() + { + if (!$this->isWindows()) { + return '/dev/null'; + } else { + return 'nul'; + } + } + + public static function escapeshellarg($arg) + { + // Short-circuit escaping for simple params (keep stuff readable) + if (preg_match('|^[a-zA-Z0-9.:/_-]*$|', $arg)) { + return $arg; + } elseif (self::isWindows()) { + return self::_escapeshellargWindows($arg); + } else { + return escapeshellarg($arg); + } + } + + public static function _escapeshellargWindows($arg) + { + // Double up existing backslashes + $arg = preg_replace('/\\\/', '\\\\\\\\', $arg); + + // Double up double quotes + $arg = preg_replace('/"/', '""', $arg); + + // Double up percents. + $arg = preg_replace('/%/', '%%', $arg); + + // Add surrounding quotes. + $arg = '"' . $arg . '"'; + + return $arg; + } + + /** + * Helper function to generate a random string of arbitrary length. + * + * Copied from drush_generate_password(), which is otherwise not available here. + * + * @param $length + * Number of characters the generated string should contain. + * @return + * The generated string. + */ + public function randomString($length = 10) + { + // This variable contains the list of allowable characters for the + // password. Note that the number 0 and the letter 'O' have been + // removed to avoid confusion between the two. The same is true + // of 'I', 1, and 'l'. + $allowable_characters = 'abcdefghijkmnopqrstuvwxyzABCDEFGHJKLMNPQRSTUVWXYZ23456789'; + + // Zero-based count of characters in the allowable list: + $len = strlen($allowable_characters) - 1; + + // Declare the password as a blank string. + $pass = ''; + + // Loop the number of times specified by $length. + for ($i = 0; $i < $length; $i++) { + // Each iteration, pick a random character from the + // allowable string and append it to the password: + $pass .= $allowable_characters[mt_rand(0, $len)]; + } + + return $pass; + } + + public static function mkdir($path) + { + if (!is_dir($path)) { + if (self::mkdir(dirname($path))) { + if (@mkdir($path)) { + return true; + } + } + return false; + } + return true; + } + + public static function recursiveCopy($src, $dst) + { + $dir = opendir($src); + self::mkdir($dst); + while (false !== ( $file = readdir($dir))) { + if (( $file != '.' ) && ( $file != '..' )) { + if (is_dir($src . '/' . $file)) { + self::recursiveCopy($src . '/' . $file, $dst . '/' . $file); + } else { + copy($src . '/' . $file, $dst . '/' . $file); + } + } + } + closedir($dir); + } + + + /** + * Deletes the specified file or directory and everything inside it. + * + * Usually respects read-only files and folders. To do a forced delete use + * drush_delete_tmp_dir() or set the parameter $forced. + * + * To avoid permission denied error on Windows, make sure your CWD is not + * inside the directory being deleted. + * + * This is essentially a copy of drush_delete_dir(). + * + * @todo This sort of duplication isn't very DRY. This is bound to get out of + * sync with drush_delete_dir(), as in fact it already has before. + * + * @param string $dir + * The file or directory to delete. + * @param bool $force + * Whether or not to try everything possible to delete the directory, even if + * it's read-only. Defaults to FALSE. + * @param bool $follow_symlinks + * Whether or not to delete symlinked files. Defaults to FALSE--simply + * unlinking symbolic links. + * + * @return bool + * FALSE on failure, TRUE if everything was deleted. + * + * @see drush_delete_dir() + */ + public static function recursiveDelete($dir, $force = true, $follow_symlinks = false) + { + // Do not delete symlinked files, only unlink symbolic links + if (is_link($dir) && !$follow_symlinks) { + return unlink($dir); + } + // Allow to delete symlinks even if the target doesn't exist. + if (!is_link($dir) && !file_exists($dir)) { + return true; + } + if (!is_dir($dir)) { + if ($force) { + // Force deletion of items with readonly flag. + @chmod($dir, 0777); + } + return unlink($dir); + } + if (self::recursiveDeleteDirContents($dir, $force) === false) { + return false; + } + if ($force) { + // Force deletion of items with readonly flag. + @chmod($dir, 0777); + } + return rmdir($dir); + } + + /** + * Deletes the contents of a directory. + * + * This is essentially a copy of drush_delete_dir_contents(). + * + * @param string $dir + * The directory to delete. + * @param bool $force + * Whether or not to try everything possible to delete the contents, even if + * they're read-only. Defaults to FALSE. + * + * @return bool + * FALSE on failure, TRUE if everything was deleted. + * + * @see drush_delete_dir_contents() + */ + public static function recursiveDeleteDirContents($dir, $force = false) + { + $scandir = @scandir($dir); + if (!is_array($scandir)) { + return false; + } + + foreach ($scandir as $item) { + if ($item == '.' || $item == '..') { + continue; + } + if ($force) { + @chmod($dir, 0777); + } + if (!self::recursiveDelete($dir . '/' . $item, $force)) { + return false; + } + } + return true; + } + + public function webroot() + { + return Path::join(self::getSut(), 'web'); + } + + public function directoryCache($subdir = '') + { + return getenv('CACHE_PREFIX') . '/' . $subdir; + } + + /** + * @param $env + * @return string + */ + public function dbUrl($env) + { + return substr(self::getDbUrl(), 0, 6) == 'sqlite' ? "sqlite://sites/$env/files/unish.sqlite" : self::getDbUrl() . '/unish_' . $env; + } + + public function dbDriver($db_url = null) + { + return parse_url($db_url ?: self::getDbUrl(), PHP_URL_SCHEME); + } + + /** + * Create some fixture sites that only have a 'settings.php' file + * with a database record. + * + * @param array $sites key=site_subder value=array of extra alias data + * @param string $aliasGroup Write aliases into a file named group.alias.yml + */ + public function setUpSettings(array $sites, $aliasGroup = 'fixture') + { + foreach ($sites as $subdir => $extra) { + $this->createSettings($subdir); + } + // Create basic site alias data with root and uri + $siteAliasData = $this->createAliasFileData(array_keys($sites), $aliasGroup); + // Add in caller-provided site alias data + $siteAliasData = array_merge_recursive($siteAliasData, $sites); + $this->writeSiteAliases($siteAliasData, $aliasGroup); + } + + public function createSettings($subdir) + { + $settingsContents = << 'unish_$subdir', + 'username' => 'root', + 'password' => '', + 'prefix' => '', + 'host' => '127.0.0.1', + 'port' => '', + 'namespace' => 'Drupal\\Core\\Database\\Driver\\mysql', + 'driver' => 'mysql', +); +\$settings['install_profile'] = 'testing'; +EOT; + + $root = $this->webroot(); + $settingsPath = "$root/sites/$subdir/settings.php"; + self::mkdir(dirname($settingsPath)); + file_put_contents($settingsPath, $settingsContents); + } + /** + * Assemble (and optionally install) one or more Drupal sites using a single codebase. + * + * It is no longer supported to pass alternative versions of Drupal or an alternative install_profile. + */ + public function setUpDrupal($num_sites = 1, $install = false) + { + $sites_subdirs_all = ['dev', 'stage', 'prod', 'retired', 'elderly', 'dead', 'dust']; + $sites_subdirs = array_slice($sites_subdirs_all, 0, $num_sites); + $root = $this->webroot(); + + // Install (if needed). + foreach ($sites_subdirs as $subdir) { + $this->installDrupal($subdir, $install); + } + + // Write an empty sites.php. Needed for multi-site on D8+. + if (!file_exists($root . '/sites/sites.php')) { + copy($root . '/sites/example.sites.php', $root . '/sites/sites.php'); + } + + $siteData = $this->createAliasFile($sites_subdirs, 'unish'); + self::$sites = []; + foreach ($siteData as $key => $data) { + self::$sites[$key] = $data; + } + return self::$sites; + } + + public function createAliasFileData($sites_subdirs, $aliasGroup = 'unish') + { + $root = $this->webroot(); + // Stash details about each site. + $sites = []; + foreach ($sites_subdirs as $subdir) { + $sites[$subdir] = [ + 'root' => $root, + 'uri' => $subdir, + 'dbUrl' => $this->dbUrl($subdir), + ]; + } + return $sites; + } + + public function createAliasFile($sites_subdirs, $aliasGroup = 'unish') + { + // Make an alias group for the sites. + $sites = $this->createAliasFileData($sites_subdirs, $aliasGroup); + $this->writeSiteAliases($sites, $aliasGroup); + + return $sites; + } + + /** + * Install a Drupal site. + * + * It is no longer supported to pass alternative versions of Drupal or an alternative install_profile. + */ + public function installDrupal($env = 'dev', $install = false) + { + $root = $this->webroot(); + $uri = $env; + $site = "$root/sites/$uri"; + + // If specified, install Drupal as a multi-site. + if ($install) { + $options = [ + 'root' => $root, + 'db-url' => $this->dbUrl($env), + 'sites-subdir' => $uri, + 'yes' => null, + 'quiet' => null, + ]; + $this->drush('site-install', ['testing', 'install_configure_form.enable_update_status_emails=NULL'], $options); + // Give us our write perms back. + chmod($site, 0777); + } else { + $this->mkdir($site); + touch("$site/settings.php"); + } + } + + /** + * Write an alias group file and a config file which points to same dir. + * + * @param $sites + */ + public function writeSiteAliases($sites, $aliasGroup = 'unish') + { + $this->writeUnishConfig($sites, [], $aliasGroup); + } + + public function writeUnishConfig($unishAliases, $config = [], $aliasGroup = 'unish') + { + $etc = self::getSandbox() . '/etc/drush'; + $aliases_dir = Path::join($etc, 'sites'); + @mkdir($aliases_dir); + file_put_contents(Path::join($aliases_dir, $aliasGroup . '.site.yml'), Yaml::dump($unishAliases, PHP_INT_MAX, 2)); + $config['drush']['paths']['alias-path'][] = $aliases_dir; + file_put_contents(Path::join($etc, 'drush.yml'), Yaml::dump($config, PHP_INT_MAX, 2)); + } + + /** + * The sitewide directory for Drupal extensions. + */ + public function drupalSitewideDirectory() + { + return '/sites/all'; + } + + /** + * Set environment variables that should be passed to child processes. + * + * @param array $vars + * The variables to set. + * + * We will change implementation to take advantage of https://github.com/symfony/symfony/pull/19053/files once we drop Symfony 2 compat. + */ + public static function setEnv(array $vars) + { + foreach ($vars as $k => $v) { + putenv($k . '=' . $v); + // Value must be a string. See \Symfony\Component\Process\Process::getDefaultEnv. + $_SERVER[$k]= (string) $v; + } + } +}