690d9afade3a6d8ffcaab5fd2ca9b381f0ebfd30
[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 {
20     public function testDispatchUsingAlias()
21     {
22         $unishAliases = [
23             'remote' => [
24                 'host' => 'server.isp.com',
25                 'user' => 'www-admin',
26                 'root' => '/path/to/drupal',
27                 'uri' => 'http://example.com',
28                 'paths' => [
29                     'drush-script' => '/usr/local/bin/drush',
30                 ],
31             ],
32         ];
33         // n.b. writeUnishConfig will overwrite the alias files create by setupDrupal
34         $this->writeUnishConfig($unishAliases);
35         $this->drush('status', [], ['simulate' => null], '@unish.remote');
36         $output = $this->getOutput();
37
38         // Clean up -- our other tests do not want extra configuration
39         unlink(self::getSandbox() . '/etc/drush/drush.yml');
40
41         $output = preg_replace('#  *#', ' ', $output);
42         $output = preg_replace('# -t #', ' ', $output); // volkswagon away the -t, it's not relevant to what we're testing here
43         $output = preg_replace('#' . self::getSandbox() . '#', '__SANDBOX__', $output);
44         $this->assertContains("Simulating backend invoke: ssh -o PasswordAuthentication=no www-admin@server.isp.com '/usr/local/bin/drush --alias-path=__SANDBOX__/etc/drush/sites --root=/path/to/drupal --uri=http://example.com --no-interaction status", $output);
45     }
46
47     /**
48      * Covers the following origin responsibilities.
49      *   - A remote host is recognized in site specification.
50      *   - Generates expected ssh command.
51      *
52      * General handling of site aliases will be in sitealiasTest.php.
53      */
54     public function testOrigin()
55     {
56         $site_specification = 'user@server/path/to/drupal#sitename';
57         $exec = sprintf('%s %s version --simulate --ssh-options=%s 2>%s', self::getDrush(), self::escapeshellarg($site_specification), self::escapeshellarg('-i mysite_dsa'), self::escapeshellarg($this->bitBucket()));
58         $this->execute($exec);
59         $bash = $this->escapeshellarg('drush --root=/path/to/drupal --uri=sitename version 2>&1');
60         $expected = "Simulating backend invoke: ssh -i mysite_dsa user@server $bash 2>&1";
61         $output = $this->getOutput();
62         // We do not care if Drush inserts a -t or not in the string. Depends on whether there is a tty.
63         $output = preg_replace('# -t #', ' ', $output);
64         // Remove double spaces from output to help protect test from false negatives if spacing changes subtlely
65         $output = preg_replace('#  *#', ' ', $output);
66         $this->assertContains($expected, $output, 'Expected ssh command was built');
67     }
68
69     public function testNonExistentCommand()
70     {
71         $this->markTestSkipped('Cannot run remote commands that do not exist locally');
72         // Assure that arguments and options are passed along to a command thats not recognized locally.
73         $this->drush('non-existent-command', ['foo'], ['bar' => 'baz', 'simulate' => null], $site_specification);
74         $output = $this->getOutput();
75         $this->assertContains('foo', $output);
76         $this->assertContains('--bar=baz', $output);
77     }
78
79     /**
80      * Covers the following target responsibilities.
81      *   - Interpret stdin as options as per REST API.
82      *   - Successfully execute specified command.
83      *   - JSON object has expected contents (including errors).
84      *   - JSON object is wrapped in expected delimiters.
85      */
86     public function testTarget()
87     {
88         // Backend invoke always runs in non-strict mode now.
89         $stdin = json_encode([]);
90         $exec = sprintf('%s version --not-exist --backend', self::getDrush());
91         $this->execute($exec, self::EXIT_SUCCESS, null, null, $stdin);
92         $exec = sprintf('%s version --backend', self::getDrush());
93         $this->execute($exec, self::EXIT_SUCCESS, null, null, $stdin);
94         $parsed = $this->parseBackendOutput($this->getOutput());
95         $this->assertTrue((bool) $parsed, 'Successfully parsed backend output');
96         $this->assertArrayHasKey('log', $parsed);
97         $this->assertArrayHasKey('output', $parsed);
98         $this->assertArrayHasKey('object', $parsed);
99         $this->assertEquals(self::EXIT_SUCCESS, $parsed['error_status']);
100         // This assertion shows that `version` was called and that stdin options were respected.
101         $this->assertEquals('drush-version', key($parsed['object']));
102         // @todo --backend not currently populating 'output' for Annotated commands.
103         // $this->assertStringStartsWith(' Drush Version ', $parsed['output']);
104         $this->assertEquals('Bootstrap to none', $parsed['log'][0]['message']);
105     }
106
107     public function testBackendErrorStatus()
108     {
109         // Check error propogation by requesting an invalid command (missing Drupal site).
110         $this->drush('core-cron', [], ['backend' => null], null, null, self::EXIT_ERROR);
111         $parsed = $this->parseBackendOutput($this->getOutput());
112         $this->assertEquals(1, $parsed['error_status']);
113     }
114
115     /**
116      * Covers the following target responsibilities.
117      *   - Insures that the 'Drush version' line from drush status appears in the output.
118      *   - Insures that the backend output start marker appears in the output (this is a backend command).
119      *   - Insures that the drush output appears before the backend output start marker (output is displayed in 'real time' as it is produced).
120      */
121     public function testRealtimeOutput()
122     {
123         $exec = sprintf('%s core-status --backend --format=yaml 2>&1', self::getDrush());
124         $this->execute($exec);
125
126         $output = $this->getOutput();
127         $drush_version_offset = strpos($output, "drush-version");
128         $backend_output_offset = strpos($output, "DRUSH_BACKEND_OUTPUT_START>>>");
129
130         $this->assertTrue($drush_version_offset !== false, "'Drush version' string appears in output.");
131         $this->assertTrue($backend_output_offset !== false, "Drush backend output marker appears in output.");
132         $this->assertTrue($drush_version_offset < $backend_output_offset, "Drush version string appears in output before the backend output marker.");
133     }
134
135     /**
136      * Covers the following target responsibilities.
137      *   - Insures that function result is returned in --backend mode
138      */
139     public function testBackendFunctionResult()
140     {
141         $php = "return 'bar'";
142         $this->drush('php-eval', [$php], ['backend' => null]);
143         $parsed = $this->parseBackendOutput($this->getOutput());
144         // assert that $parsed has 'bar'
145         $this->assertEquals("'bar'", var_export($parsed['object'], true));
146     }
147
148     /**
149      * Covers the following target responsibilities.
150      *   - Insures that backend_set_result is returned in --backend mode
151      *   - Insures that the result code for the function does not overwrite
152      *     the explicitly-set value
153      */
154     public function testBackendSetResult()
155     {
156         $php = "drush_backend_set_result('foo'); return 'bar'";
157         $this->drush('php-eval', [$php], ['backend' => null]);
158         $parsed = $this->parseBackendOutput($this->getOutput());
159         // assert that $parsed has 'foo' and not 'bar'
160         $this->assertEquals("'foo'", var_export($parsed['object'], true));
161     }
162
163     /**
164      * Covers the following target responsibilities.
165      *   - Insures that the backend option 'invoke-multiple' will cause multiple commands to be executed.
166      *   - Insures that the right number of commands run.
167      *   - Insures that the 'concurrent'-format result array is returned.
168      *   - Insures that correct results are returned from each command.
169      */
170     public function testBackendInvokeMultiple()
171     {
172         $this->markTestIncomplete('Depends on concurrency');
173         $options = [
174         'backend' => null,
175         'include' => dirname(__FILE__), // Find unit.drush.inc commandfile.
176         ];
177         $php = "\$values = drush_invoke_process('@none', 'unit-return-options', array('value'), array('x' => 'y'), array('invoke-multiple' => '3')); return \$values;";
178         $this->drush('php-eval', [$php], $options);
179         $parsed = $this->parseBackendOutput($this->getOutput());
180         // assert that $parsed has a 'concurrent'-format output result
181         $this->assertEquals('concurrent', implode(',', array_keys($parsed['object'])));
182         // assert that the concurrent output has indexes 0, 1 and 2 (in any order)
183         $concurrent_indexes = array_keys($parsed['object']['concurrent']);
184         sort($concurrent_indexes);
185         $this->assertEquals('0,1,2', implode(',', $concurrent_indexes));
186         foreach ($parsed['object']['concurrent'] as $index => $values) {
187             // assert that each result contains 'x' => 'y' and nothing else
188             $this->assertEquals("array (
189   'x' => 'y',
190 )", var_export($values['object'], true));
191         }
192     }
193     /**
194      * Covers the following target responsibilities.
195      *   - Insures that arrays are stripped when using --backend mode's method GET
196      *   - Insures that arrays can be returned as the function result of
197      *     backend invoke.
198      */
199     public function testBackendMethodGet()
200     {
201         $options = [
202         'backend' => null,
203         'include' => dirname(__FILE__), // Find unit.drush.inc commandfile.
204         ];
205         $php = "\$values = drush_invoke_process('@none', 'unit-return-options', array('value'), array('x' => 'y', 'data' => array('a' => 1, 'b' => 2)), array('method' => 'GET')); return array_key_exists('object', \$values) ? \$values['object'] : 'no result';";
206         $this->drush('php-eval', [$php], $options);
207         $parsed = $this->parseBackendOutput($this->getOutput());
208         // assert that $parsed has value of 'x'
209         $this->assertContains("'x' => 'y'", var_export($parsed['object'], true));
210     }
211
212     /**
213      * Covers the following target responsibilities.
214      *   - Insures that complex arrays can be passed through when using --backend mode's method POST
215      *   - Insures that arrays can be returned as the function result of
216      *     backend invoke.
217      */
218     public function testBackendMethodPost()
219     {
220         $options = [
221         'backend' => null,
222         'include' => dirname(__FILE__), // Find unit.drush.inc commandfile.
223         ];
224         $php = "\$values = drush_invoke_process('@none', 'unit-return-options', array('value'), array('x' => 'y', 'data' => array('a' => 1, 'b' => 2)), array('method' => 'POST')); return array_key_exists('object', \$values) ? \$values['object'] : 'no result';";
225         $this->drush('php-eval', [$php], $options);
226         $parsed = $this->parseBackendOutput($this->getOutput());
227         // assert that $parsed has 'x' and 'data'
228         $this->assertEquals('y', $parsed['object']['x']);
229         $this->assertEquals([
230         'a' => 1,
231         'b' => 2,
232         ], $parsed['object']['data']);
233     }
234 }