UnishTestCase.php

  1. 8.0.x tests/Unish/UnishTestCase.php
  2. 7.x tests/Unish/UnishTestCase.php
  3. master tests/Unish/UnishTestCase.php

Namespace

Unish

Classes

Namesort descending Description
UnishTestCase

File

tests/Unish/UnishTestCase.php
View source
  1. <?php
  2. namespace Unish;
  3. abstract class UnishTestCase extends \PHPUnit_Framework_TestCase {
  4. /**
  5. * A list of Drupal sites that have been recently installed.
  6. *
  7. * @var array
  8. */
  9. private static $sites = array();
  10. function __construct($name = NULL, array $data = array(), $dataName = '') {
  11. parent::__construct($name, $data, $dataName);
  12. }
  13. /**
  14. * Assure that each class starts with an empty sandbox directory and
  15. * a clean environment - http://drupal.org/node/1103568.
  16. */
  17. public static function setUpBeforeClass() {
  18. self::setUpFreshSandBox();
  19. }
  20. /**
  21. * Remove any pre-existing sandbox, then create a new one.
  22. */
  23. public static function setUpFreshSandBox() {
  24. $sandbox = UNISH_SANDBOX;
  25. if (file_exists($sandbox)) {
  26. unish_file_delete_recursive($sandbox);
  27. }
  28. $ret = mkdir($sandbox, 0777, TRUE);
  29. chdir(UNISH_SANDBOX);
  30. mkdir(getenv('HOME') . '/.drush', 0777, TRUE);
  31. mkdir($sandbox . '/etc/drush', 0777, TRUE);
  32. mkdir($sandbox . '/share/drush/commands', 0777, TRUE);
  33. if (strtoupper(substr(PHP_OS, 0, 3)) === 'WIN') {
  34. // Hack to make git use unix line endings on windows
  35. // We need it to make hashes of files pulled from git match ones hardcoded in tests
  36. if (!file_exists($sandbox . '\home')) {
  37. mkdir($sandbox . '\home');
  38. }
  39. exec("git config --file $sandbox\\home\\.gitconfig core.autocrlf false", $output, $return);
  40. }
  41. }
  42. /**
  43. * Runs after all tests in a class are run. Remove sandbox directory.
  44. */
  45. public static function tearDownAfterClass() {
  46. $dirty = getenv('UNISH_DIRTY');
  47. if (file_exists(UNISH_SANDBOX) && empty($dirty)) {
  48. unish_file_delete_recursive(UNISH_SANDBOX, TRUE);
  49. }
  50. self::$sites = array();
  51. }
  52. /**
  53. * Print a log message to the console.
  54. *
  55. * @param string $message
  56. * @param string $type
  57. * Supported types are:
  58. * - notice
  59. * - verbose
  60. * - debug
  61. */
  62. function log($message, $type = 'notice') {
  63. $line = "\nLog: $message\n";
  64. switch ($this->log_level()) {
  65. case 'verbose':
  66. if (in_array($type, array('notice', 'verbose'))) print $line;
  67. break;
  68. case 'debug':
  69. print $line;
  70. break;
  71. default:
  72. if ($type == 'notice') print $line;
  73. break;
  74. }
  75. }
  76. function log_level() {
  77. if (in_array('--debug', $_SERVER['argv'])) {
  78. return 'debug';
  79. }
  80. elseif (in_array('--verbose', $_SERVER['argv'])) {
  81. return 'verbose';
  82. }
  83. }
  84. public static function is_windows() {
  85. return (strtoupper(substr(PHP_OS, 0, 3)) == "WIN");
  86. }
  87. public static function get_tar_executable() {
  88. return self::is_windows() ? "bsdtar.exe" : "tar";
  89. }
  90. /**
  91. * Print out a tick mark.
  92. *
  93. * Useful for longer running tests to indicate they're working.
  94. */
  95. function tick() {
  96. static $chars = array('/', '-', '\\', '|');
  97. static $counter = 0;
  98. print $chars[($counter++ % 4)] . "\033[1D";
  99. }
  100. /**
  101. * Converts a Windows path (dir1\dir2\dir3) into a Unix path (dir1/dir2/dir3).
  102. * Also converts a cygwin "drive emulation" path (/cygdrive/c/dir1) into a
  103. * proper drive path, still with Unix slashes (c:/dir1).
  104. *
  105. * @copied from Drush's environment.inc
  106. */
  107. function convert_path($path) {
  108. $path = str_replace('\\','/', $path);
  109. $path = preg_replace('/^\/cygdrive\/([A-Za-z])(.*)$/', '\1:\2', $path);
  110. return $path;
  111. }
  112. /**
  113. * Borrowed from Drush.
  114. * Checks operating system and returns
  115. * supported bit bucket folder.
  116. */
  117. function bit_bucket() {
  118. if (!$this->is_windows()) {
  119. return '/dev/null';
  120. }
  121. else {
  122. return 'nul';
  123. }
  124. }
  125. public static function escapeshellarg($arg) {
  126. // Short-circuit escaping for simple params (keep stuff readable)
  127. if (preg_match('|^[a-zA-Z0-9.:/_-]*$|', $arg)) {
  128. return $arg;
  129. }
  130. elseif (self::is_windows()) {
  131. return self::_escapeshellarg_windows($arg);
  132. }
  133. else {
  134. return escapeshellarg($arg);
  135. }
  136. }
  137. public static function _escapeshellarg_windows($arg) {
  138. // Double up existing backslashes
  139. $arg = preg_replace('/\\\/', '\\\\\\\\', $arg);
  140. // Double up double quotes
  141. $arg = preg_replace('/"/', '""', $arg);
  142. // Double up percents.
  143. // $arg = preg_replace('/%/', '%%', $arg);
  144. // Add surrounding quotes.
  145. $arg = '"' . $arg . '"';
  146. return $arg;
  147. }
  148. /**
  149. * Helper function to generate a random string of arbitrary length.
  150. *
  151. * Copied from drush_generate_password(), which is otherwise not available here.
  152. *
  153. * @param $length
  154. * Number of characters the generated string should contain.
  155. * @return
  156. * The generated string.
  157. */
  158. public function randomString($length = 10) {
  159. // This variable contains the list of allowable characters for the
  160. // password. Note that the number 0 and the letter 'O' have been
  161. // removed to avoid confusion between the two. The same is true
  162. // of 'I', 1, and 'l'.
  163. $allowable_characters = 'abcdefghijkmnopqrstuvwxyzABCDEFGHJKLMNPQRSTUVWXYZ23456789';
  164. // Zero-based count of characters in the allowable list:
  165. $len = strlen($allowable_characters) - 1;
  166. // Declare the password as a blank string.
  167. $pass = '';
  168. // Loop the number of times specified by $length.
  169. for ($i = 0; $i < $length; $i++) {
  170. // Each iteration, pick a random character from the
  171. // allowable string and append it to the password:
  172. $pass .= $allowable_characters[mt_rand(0, $len)];
  173. }
  174. return $pass;
  175. }
  176. function webroot() {
  177. return UNISH_SANDBOX . '/web';
  178. }
  179. function getSites() {
  180. return self::$sites;
  181. }
  182. function directory_cache($subdir = '') {
  183. return getenv('CACHE_PREFIX') . '/' . $subdir;
  184. }
  185. /**
  186. * @param $env
  187. * @return string
  188. */
  189. function db_url($env) {
  190. return substr(UNISH_DB_URL, 0, 6) == 'sqlite' ? "sqlite://sites/$env/files/unish.sqlite" : UNISH_DB_URL . '/unish_' . $env;
  191. }
  192. function db_driver($db_url = UNISH_DB_URL) {
  193. return parse_url(UNISH_DB_URL, PHP_URL_SCHEME);
  194. }
  195. function setUpDrupal($num_sites = 1, $install = FALSE, $version_string = UNISH_DRUPAL_MAJOR_VERSION, $profile = NULL) {
  196. $sites_subdirs_all = array('dev', 'stage', 'prod', 'retired', 'elderly', 'dead', 'dust');
  197. $sites_subdirs = array_slice($sites_subdirs_all, 0, $num_sites);
  198. $root = $this->webroot();
  199. $major_version = substr($version_string, 0, 1);
  200. if (!isset($profile)) {
  201. $profile = $major_version >= 7 ? 'testing' : 'default';
  202. }
  203. $db_driver = $this->db_driver(UNISH_DB_URL);
  204. $cache_keys = array($num_sites, $install ? 'install' : 'noinstall', $version_string, $profile, $db_driver);
  205. $source = $this->directory_cache('environments') . '/' . implode('-', $cache_keys) . '.tar.gz';
  206. if (file_exists($source)) {
  207. $this->log('Cache HIT. Environment: ' . $source, 'verbose');
  208. $this->drush('archive-restore', array($source), array('destination' => $root, 'overwrite' => NULL));
  209. }
  210. else {
  211. $this->log('Cache MISS. Environment: ' . $source, 'verbose');
  212. // Build the site(s), install (if needed), then cache.
  213. foreach ($sites_subdirs as $subdir) {
  214. $this->fetchInstallDrupal($subdir, $install, $version_string, $profile);
  215. }
  216. // Write an empty sites.php if we are on D8+. Needed for multi-site.
  217. if ($major_version >= 8 && !file_exists($root . '/sites/sites.php')) {
  218. copy($root . '/sites/example.sites.php', $root . '/sites/sites.php');
  219. }
  220. $options = array(
  221. 'destination' => $source,
  222. 'root' => $root,
  223. 'uri' => reset($sites_subdirs),
  224. 'overwrite' => NULL,
  225. );
  226. if ($install) {
  227. $this->drush('archive-dump', array('@sites'), $options);
  228. }
  229. }
  230. // Stash details about each site.
  231. foreach ($sites_subdirs as $subdir) {
  232. self::$sites[$subdir] = array(
  233. 'root' => $root,
  234. 'uri' => $subdir,
  235. 'db_url' => $this->db_url($subdir),
  236. );
  237. // Make an alias for the site
  238. $this->writeSiteAlias($subdir, $root, $subdir);
  239. }
  240. return self::$sites;
  241. }
  242. function fetchInstallDrupal($env = 'dev', $install = FALSE, $version_string = UNISH_DRUPAL_MAJOR_VERSION, $profile = NULL, $separate_roots = FALSE) {
  243. $root = $this->webroot();
  244. $uri = $separate_roots ? "default" : "$env";
  245. $options = array();
  246. $site = "$root/sites/$uri";
  247. if (substr($version_string, 0, 1) == 6 && $this->db_driver(UNISH_DB_URL) == 'sqlite') {
  248. // Validate
  249. $this->markTestSkipped("Drupal 6 does not support SQLite.");
  250. }
  251. if ($version_string == 8) {
  252. // We want to track Drupal 8 very closely.
  253. $version_string = '8.1.x';
  254. $options['no-md5'] = NULL;
  255. }
  256. // Download Drupal if not already present.
  257. if (!file_exists($root)) {
  258. $options += array(
  259. 'destination' => dirname($root),
  260. 'drupal-project-rename' => basename($root),
  261. 'yes' => NULL,
  262. 'quiet' => NULL,
  263. 'cache' => NULL,
  264. );
  265. $this->drush('pm-download', array("drupal-$version_string"), $options);
  266. // @todo This path is not proper in D8.
  267. mkdir($root . '/sites/all/drush', 0777, TRUE);
  268. }
  269. // If specified, install Drupal as a multi-site.
  270. if ($install) {
  271. $options = array(
  272. 'root' => $root,
  273. 'db-url' => $this->db_url($env),
  274. 'sites-subdir' => $uri,
  275. 'yes' => NULL,
  276. 'quiet' => NULL,
  277. );
  278. $this->drush('site-install', array($profile), $options);
  279. // Give us our write perms back.
  280. chmod($site, 0777);
  281. }
  282. else {
  283. mkdir($site);
  284. touch("$site/settings.php");
  285. }
  286. }
  287. function writeSiteAlias($name, $root, $uri) {
  288. $alias_definition = array($name => array('root' => $root, 'uri' => $uri));
  289. file_put_contents(UNISH_SANDBOX . '/etc/drush/' . $name . '.alias.drushrc.php', $this->unish_file_aliases($alias_definition));
  290. }
  291. /**
  292. * Prepare the contents of an aliases file.
  293. */
  294. function unish_file_aliases($aliases) {
  295. foreach ($aliases as $name => $alias) {
  296. $records[] = sprintf('$aliases[\'%s\'] = %s;', $name, var_export($alias, TRUE));
  297. }
  298. $contents = "<?php\n\n" . implode("\n\n", $records);
  299. return $contents;
  300. }
  301. /**
  302. * @see drush_drupal_sitewide_directory()
  303. */
  304. function drupalSitewideDirectory($major_version = NULL) {
  305. if (!$major_version) {
  306. $major_version = UNISH_DRUPAL_MAJOR_VERSION;
  307. }
  308. return ($major_version < 8) ? '/sites/all' : '';
  309. }
  310. }