backendTest.php

  1. 8.0.x tests/backendTest.php
  2. 6.x tests/backendTest.php
  3. 7.x tests/backendTest.php
  4. 4.x tests/backendTest.php
  5. 5.x tests/backendTest.php
  6. master tests/backendTest.php

Namespace

Unish

Classes

Namesort descending Description
backendCase We choose to test the backend system in two parts.

File

tests/backendTest.php
View source
  1. <?php
  2. namespace Unish;
  3. /**
  4. * We choose to test the backend system in two parts.
  5. * - Origin. These tests assure that we are generate a proper ssh command
  6. * when a backend invoke is needed.
  7. * - Target. These tests assure that drush generates a delimited JSON array
  8. * when called with --backend option.
  9. *
  10. * Advantages of this approach:
  11. * - No network calls and thus more robust.
  12. * - No network calls and thus faster.
  13. *
  14. * @group base
  15. */
  16. class backendCase extends CommandUnishTestCase {
  17. // Test to insure that calling drush_invoke_process() with 'dispatch-using-alias'
  18. // will build a command string that uses the alias instead of --root and --uri.
  19. function testDispatchUsingAlias() {
  20. $this->markTestIncomplete('Started failing due to https://github.com/drush-ops/drush/pull/555');
  21. $aliasPath = UNISH_SANDBOX . '/aliases';
  22. mkdir($aliasPath);
  23. $aliasFile = $aliasPath . '/foo.aliases.drushrc.php';
  24. $aliasContents = <<<EOD
  25. <?php
  26. // Written by Unish. This file is safe to delete.
  27. \$aliases['dev'] = array('root' => '/fake/path/to/root', 'uri' => 'default');
  28. EOD;
  29. file_put_contents($aliasFile, $aliasContents);
  30. $options = array(
  31. 'alias-path' => $aliasPath,
  32. 'include' => dirname(__FILE__), // Find unit.drush.inc commandfile.
  33. 'script-path' => dirname(__FILE__) . '/resources', // Find unit.drush.inc commandfile.
  34. 'backend' => TRUE,
  35. );
  36. $this->drush('php-script', array('testDispatchUsingAlias_script'), $options);
  37. $parsed = $this->parse_backend_output($this->getOutput());
  38. // $parsed['with'] and $parsed['without'] now contain an array
  39. // each with the original arguments passed in with and without
  40. // 'dispatch-using-alias', respectively.
  41. $argDifference = array_diff($parsed['object']['with'], $parsed['object']['without']);
  42. $this->assertEquals(array_diff(array_values($argDifference), array('@foo.dev')), array());
  43. $argDifference = array_diff($parsed['object']['without'], $parsed['object']['with']);
  44. $this->assertEquals(array_diff(array_values($argDifference), array('--root=/fake/path/to/root', '--uri=default')), array());
  45. }
  46. /**
  47. * Covers the following origin responsibilities.
  48. * - A remote host is recognized in site specification.
  49. * - Generates expected ssh command.
  50. *
  51. * General handling of site aliases will be in sitealiasTest.php.
  52. */
  53. function testOrigin() {
  54. $exec = sprintf('%s %s version arg1 arg2 --simulate --ssh-options=%s 2>/dev/null | grep ssh', UNISH_DRUSH, self::escapeshellarg('user@server/path/to/drupal#sitename'), self::escapeshellarg('-i mysite_dsa'));
  55. $this->execute($exec);
  56. $bash = $this->escapeshellarg('drush --uri=sitename --root=/path/to/drupal version arg1 arg2 2>&1');
  57. $expected = "Simulating backend invoke: ssh -i mysite_dsa user@server $bash 2>&1";
  58. $output = $this->getOutput();
  59. $this->assertEquals($expected, $output, 'Expected ssh command was built');
  60. }
  61. /**
  62. * Covers the following target responsibilities.
  63. * - Interpret stdin as options as per REST API.
  64. * - Successfully execute specified command.
  65. * - JSON object has expected contents (including errors).
  66. * - JSON object is wrapped in expected delimiters.
  67. */
  68. function testTarget() {
  69. $stdin = json_encode(array('filter'=>'sql'));
  70. $exec = sprintf('echo %s | %s version --backend 2>/dev/null', self::escapeshellarg($stdin), UNISH_DRUSH);
  71. $this->execute($exec);
  72. $parsed = $this->parse_backend_output($this->getOutput());
  73. $this->assertTrue((bool) $parsed, 'Successfully parsed backend output');
  74. $this->assertArrayHasKey('log', $parsed);
  75. $this->assertArrayHasKey('output', $parsed);
  76. $this->assertArrayHasKey('object', $parsed);
  77. $this->assertEquals(self::EXIT_SUCCESS, $parsed['error_status']);
  78. // This assertion shows that `version` was called and that stdin options were respected.
  79. $this->assertStringStartsWith(' Drush Version ', $parsed['output']);
  80. $this->assertEquals('Starting Drush preflight.', $parsed['log'][1]['message']);
  81. // Check error propogation by requesting an invalid command (missing Drupal site).
  82. $this->drush('core-cron', array(), array('backend' => NULL), NULL, NULL, self::EXIT_ERROR);
  83. $parsed = $this->parse_backend_output($this->getOutput());
  84. $this->assertEquals(1, $parsed['error_status']);
  85. $this->assertArrayHasKey('DRUSH_COMMAND_INSUFFICIENT_BOOTSTRAP', $parsed['error_log']);
  86. }
  87. /**
  88. * Covers the following target responsibilities.
  89. * - Insures that the 'Drush version' line from drush status appears in the output.
  90. * - Insures that the backend output start marker appears in the output (this is a backend command).
  91. * - Insures that the drush output appears before the backend output start marker (output is displayed in 'real time' as it is produced).
  92. */
  93. function testRealtimeOutput() {
  94. $exec = sprintf('%s core-status --backend --nocolor 2>&1', UNISH_DRUSH);
  95. $this->execute($exec);
  96. $output = $this->getOutput();
  97. $drush_version_offset = strpos($output, "Drush version");
  98. $backend_output_offset = strpos($output, "DRUSH_BACKEND_OUTPUT_START>>>");
  99. $this->assertTrue($drush_version_offset !== FALSE, "'Drush version' string appears in output.");
  100. $this->assertTrue($backend_output_offset !== FALSE, "Drush backend output marker appears in output.");
  101. $this->assertTrue($drush_version_offset < $backend_output_offset, "Drush version string appears in output before the backend output marker.");
  102. }
  103. /**
  104. * Covers the following target responsibilities.
  105. * - Insures that function result is returned in --backend mode
  106. */
  107. function testBackendFunctionResult() {
  108. $php = "return 'bar'";
  109. $this->drush('php-eval', array($php), array('backend' => NULL));
  110. $parsed = $this->parse_backend_output($this->getOutput());
  111. // assert that $parsed has 'bar'
  112. $this->assertEquals("'bar'", var_export($parsed['object'], TRUE));
  113. }
  114. /**
  115. * Covers the following target responsibilities.
  116. * - Insures that backend_set_result is returned in --backend mode
  117. * - Insures that the result code for the function does not overwrite
  118. * the explicitly-set value
  119. */
  120. function testBackendSetResult() {
  121. $php = "drush_backend_set_result('foo'); return 'bar'";
  122. $this->drush('php-eval', array($php), array('backend' => NULL));
  123. $parsed = $this->parse_backend_output($this->getOutput());
  124. // assert that $parsed has 'foo' and not 'bar'
  125. $this->assertEquals("'foo'", var_export($parsed['object'], TRUE));
  126. }
  127. /**
  128. * Covers the following target responsibilities.
  129. * - Insures that the backend option 'invoke-multiple' will cause multiple commands to be executed.
  130. * - Insures that the right number of commands run.
  131. * - Insures that the 'concurrent'-format result array is returned.
  132. * - Insures that correct results are returned from each command.
  133. */
  134. function testBackendInvokeMultiple() {
  135. $options = array(
  136. 'backend' => NULL,
  137. 'include' => dirname(__FILE__), // Find unit.drush.inc commandfile.
  138. );
  139. $php = "\$values = drush_invoke_process('@none', 'unit-return-options', array('value'), array('x' => 'y', 'strict' => 0), array('invoke-multiple' => '3')); return \$values;";
  140. $this->drush('php-eval', array($php), $options);
  141. $parsed = $this->parse_backend_output($this->getOutput());
  142. // assert that $parsed has a 'concurrent'-format output result
  143. $this->assertEquals('concurrent', implode(',', array_keys($parsed['object'])));
  144. // assert that the concurrent output has indexes 0, 1 and 2 (in any order)
  145. $concurrent_indexes = array_keys($parsed['object']['concurrent']);
  146. sort($concurrent_indexes);
  147. $this->assertEquals('0,1,2', implode(',', $concurrent_indexes));
  148. foreach ($parsed['object']['concurrent'] as $index => $values) {
  149. // assert that each result contains 'x' => 'y' and nothing else
  150. $this->assertEquals("array (
  151. 'x' => 'y',
  152. )", var_export($values['object'], TRUE));
  153. }
  154. }
  155. /**
  156. * Covers the following target responsibilities.
  157. * - Insures that arrays are stripped when using --backend mode's method GET
  158. * - Insures that arrays can be returned as the function result of
  159. * backend invoke.
  160. */
  161. function testBackendMethodGet() {
  162. $options = array(
  163. 'backend' => NULL,
  164. 'include' => dirname(__FILE__), // Find unit.drush.inc commandfile.
  165. );
  166. $php = "\$values = drush_invoke_process('@none', 'unit-return-options', array('value'), array('x' => 'y', 'strict' => 0, 'data' => array('a' => 1, 'b' => 2)), array('method' => 'GET')); return array_key_exists('object', \$values) ? \$values['object'] : 'no result';";
  167. $this->drush('php-eval', array($php), $options);
  168. $parsed = $this->parse_backend_output($this->getOutput());
  169. // assert that $parsed has 'x' but not 'data'
  170. $this->assertEquals("array (
  171. 'x' => 'y',
  172. )", var_export($parsed['object'], TRUE));
  173. }
  174. /**
  175. * Covers the following target responsibilities.
  176. * - Insures that complex arrays can be passed through when using --backend mode's method POST
  177. * - Insures that arrays can be returned as the function result of
  178. * backend invoke.
  179. */
  180. function testBackendMethodPost() {
  181. $options = array(
  182. 'backend' => NULL,
  183. 'include' => dirname(__FILE__), // Find unit.drush.inc commandfile.
  184. );
  185. $php = "\$values = drush_invoke_process('@none', 'unit-return-options', array('value'), array('x' => 'y', 'strict' => 0, 'data' => array('a' => 1, 'b' => 2)), array('method' => 'POST')); return array_key_exists('object', \$values) ? \$values['object'] : 'no result';";
  186. $this->drush('php-eval', array($php), $options);
  187. $parsed = $this->parse_backend_output($this->getOutput());
  188. // assert that $parsed has 'x' and 'data'
  189. $this->assertEquals(array (
  190. 'x' => 'y',
  191. 'data' =>
  192. array (
  193. 'a' => 1,
  194. 'b' => 2,
  195. ),
  196. ), $parsed['object']);
  197. }
  198. /**
  199. * Covers the following target responsibilities.
  200. * - Insures that backend invoke can properly re-assemble packets
  201. * that are split across process-read-size boundaries.
  202. *
  203. * This test works by repeating testBackendMethodGet(), while setting
  204. * '#process-read-size' to a very small value, insuring that packets
  205. * will be split.
  206. */
  207. function testBackendReassembleSplitPackets() {
  208. $options = array(
  209. 'backend' => NULL,
  210. 'include' => dirname(__FILE__), // Find unit.drush.inc commandfile.
  211. );
  212. $min = 1;
  213. $max = 4;
  214. $read_sizes_to_test = array(4096);
  215. if (in_array('--debug', $_SERVER['argv'])) {
  216. $read_sizes_to_test[] = 128;
  217. $read_sizes_to_test[] = 16;
  218. $max = 16;
  219. }
  220. foreach ($read_sizes_to_test as $read_size) {
  221. $log_message="";
  222. for ($i = $min; $i <= $max; $i++) {
  223. $log_message .= "X";
  224. $php = "\$values = drush_invoke_process('@none', 'unit-return-options', array('value'), array('log-message' => '$log_message', 'x' => 'y$read_size', 'strict' => 0, 'data' => array('a' => 1, 'b' => 2)), array('method' => 'GET', '#process-read-size' => $read_size)); return array_key_exists('object', \$values) ? \$values['object'] : 'no result';";
  225. $this->drush('php-eval', array($php), $options);
  226. $parsed = $this->parse_backend_output($this->getOutput());
  227. // assert that $parsed has 'x' but not 'data'
  228. $all_warnings=array();
  229. foreach ($parsed['log'] as $log) {
  230. if ($log['type'] == 'warning') {
  231. $all_warnings[] = $log['message'];
  232. }
  233. }
  234. $this->assertEquals("$log_message,done", implode(',', $all_warnings), 'Log reconstruction with read_size ' . $read_size);
  235. $this->assertEquals("array (
  236. 'x' => 'y$read_size',
  237. )", var_export($parsed['object'], TRUE));
  238. }
  239. }
  240. }
  241. }