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