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