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