Mercurial > hg > cmmr2012-drupal-site
comparison core/tests/Drupal/TestSite/Commands/TestSiteInstallCommand.php @ 4:a9cd425dd02b
Update, including to Drupal core 8.6.10
author | Chris Cannam |
---|---|
date | Thu, 28 Feb 2019 13:11:55 +0000 |
parents | |
children |
comparison
equal
deleted
inserted
replaced
3:307d7a7fd348 | 4:a9cd425dd02b |
---|---|
1 <?php | |
2 | |
3 namespace Drupal\TestSite\Commands; | |
4 | |
5 use Drupal\Core\Database\Database; | |
6 use Drupal\Core\Test\FunctionalTestSetupTrait; | |
7 use Drupal\Core\Test\TestDatabase; | |
8 use Drupal\Core\Test\TestSetupTrait; | |
9 use Drupal\TestSite\TestSetupInterface; | |
10 use Drupal\Tests\RandomGeneratorTrait; | |
11 use Symfony\Component\Console\Command\Command; | |
12 use Symfony\Component\Console\Input\InputInterface; | |
13 use Symfony\Component\Console\Input\InputOption; | |
14 use Symfony\Component\Console\Output\OutputInterface; | |
15 use Symfony\Component\Console\Style\SymfonyStyle; | |
16 | |
17 /** | |
18 * Command to create a test Drupal site. | |
19 * | |
20 * @internal | |
21 */ | |
22 class TestSiteInstallCommand extends Command { | |
23 | |
24 use FunctionalTestSetupTrait { | |
25 installParameters as protected installParametersTrait; | |
26 } | |
27 use RandomGeneratorTrait; | |
28 use TestSetupTrait { | |
29 changeDatabasePrefix as protected changeDatabasePrefixTrait; | |
30 } | |
31 | |
32 /** | |
33 * The install profile to use. | |
34 * | |
35 * @var string | |
36 */ | |
37 protected $profile = 'testing'; | |
38 | |
39 /** | |
40 * Time limit in seconds for the test. | |
41 * | |
42 * Used by \Drupal\Core\Test\FunctionalTestSetupTrait::prepareEnvironment(). | |
43 * | |
44 * @var int | |
45 */ | |
46 protected $timeLimit = 500; | |
47 | |
48 /** | |
49 * The database prefix of this test run. | |
50 * | |
51 * @var string | |
52 */ | |
53 protected $databasePrefix; | |
54 | |
55 /** | |
56 * The language to install the site in. | |
57 * | |
58 * @var string | |
59 */ | |
60 protected $langcode = 'en'; | |
61 | |
62 /** | |
63 * {@inheritdoc} | |
64 */ | |
65 protected function configure() { | |
66 $this->setName('install') | |
67 ->setDescription('Creates a test Drupal site') | |
68 ->setHelp('The details to connect to the test site created will be displayed upon success. It will contain the database prefix and the user agent.') | |
69 ->addOption('setup-file', NULL, InputOption::VALUE_OPTIONAL, 'The path to a PHP file containing a class to setup configuration used by the test, for example, core/tests/Drupal/TestSite/TestSiteInstallTestScript.php.') | |
70 ->addOption('db-url', NULL, InputOption::VALUE_OPTIONAL, 'URL for database. Defaults to the environment variable SIMPLETEST_DB.', getenv('SIMPLETEST_DB')) | |
71 ->addOption('base-url', NULL, InputOption::VALUE_OPTIONAL, 'Base URL for site under test. Defaults to the environment variable SIMPLETEST_BASE_URL.', getenv('SIMPLETEST_BASE_URL')) | |
72 ->addOption('install-profile', NULL, InputOption::VALUE_OPTIONAL, 'Install profile to install the site in. Defaults to testing.', 'testing') | |
73 ->addOption('langcode', NULL, InputOption::VALUE_OPTIONAL, 'The language to install the site in. Defaults to en.', 'en') | |
74 ->addOption('json', NULL, InputOption::VALUE_NONE, 'Output test site connection details in JSON.') | |
75 ->addUsage('--setup-file core/tests/Drupal/TestSite/TestSiteInstallTestScript.php --json') | |
76 ->addUsage('--install-profile demo_umami --langcode fr') | |
77 ->addUsage('--base-url "http://example.com" --db-url "mysql://username:password@localhost/databasename#table_prefix"'); | |
78 } | |
79 | |
80 /** | |
81 * {@inheritdoc} | |
82 */ | |
83 protected function execute(InputInterface $input, OutputInterface $output) { | |
84 // Determines and validates the setup class prior to installing a database | |
85 // to avoid creating unnecessary sites. | |
86 $root = dirname(dirname(dirname(dirname(dirname(__DIR__))))); | |
87 chdir($root); | |
88 $class_name = $this->getSetupClass($input->getOption('setup-file')); | |
89 // Ensure we can install a site in the sites/simpletest directory. | |
90 $this->ensureDirectory($root); | |
91 | |
92 $db_url = $input->getOption('db-url'); | |
93 $base_url = $input->getOption('base-url'); | |
94 putenv("SIMPLETEST_DB=$db_url"); | |
95 putenv("SIMPLETEST_BASE_URL=$base_url"); | |
96 | |
97 // Manage site fixture. | |
98 $this->setup($input->getOption('install-profile'), $class_name, $input->getOption('langcode')); | |
99 | |
100 $user_agent = drupal_generate_test_ua($this->databasePrefix); | |
101 if ($input->getOption('json')) { | |
102 $output->writeln(json_encode([ | |
103 'db_prefix' => $this->databasePrefix, | |
104 'user_agent' => $user_agent, | |
105 'site_path' => $this->siteDirectory, | |
106 ])); | |
107 } | |
108 else { | |
109 $output->writeln('<info>Successfully installed a test site</info>'); | |
110 $io = new SymfonyStyle($input, $output); | |
111 $io->table([], [ | |
112 ['Database prefix', $this->databasePrefix], | |
113 ['User agent', $user_agent], | |
114 ['Site path', $this->siteDirectory], | |
115 ]); | |
116 } | |
117 } | |
118 | |
119 /** | |
120 * Gets the setup class. | |
121 * | |
122 * @param string|null $file | |
123 * The file to get the setup class from. | |
124 * | |
125 * @return string|null | |
126 * The setup class contained in the provided $file. | |
127 * | |
128 * @throws \InvalidArgumentException | |
129 * Thrown if the file does not exist, does not contain a class or the class | |
130 * does not implement \Drupal\TestSite\TestSetupInterface. | |
131 */ | |
132 protected function getSetupClass($file) { | |
133 if ($file === NULL) { | |
134 return; | |
135 } | |
136 if (!file_exists($file)) { | |
137 throw new \InvalidArgumentException("The file $file does not exist."); | |
138 } | |
139 | |
140 $classes = get_declared_classes(); | |
141 include_once $file; | |
142 $new_classes = array_values(array_diff(get_declared_classes(), $classes)); | |
143 if (empty($new_classes)) { | |
144 throw new \InvalidArgumentException("The file $file does not contain a class."); | |
145 } | |
146 $class = array_pop($new_classes); | |
147 | |
148 if (!is_subclass_of($class, TestSetupInterface::class)) { | |
149 throw new \InvalidArgumentException("The class $class contained in $file needs to implement \Drupal\TestSite\TestSetupInterface"); | |
150 } | |
151 return $class; | |
152 } | |
153 | |
154 /** | |
155 * Ensures that the sites/simpletest directory exists and is writable. | |
156 * | |
157 * @param string $root | |
158 * The Drupal root. | |
159 */ | |
160 protected function ensureDirectory($root) { | |
161 if (!is_writable($root . '/sites/simpletest')) { | |
162 if (!@mkdir($root . '/sites/simpletest')) { | |
163 throw new \RuntimeException($root . '/sites/simpletest must exist and be writable to install a test site'); | |
164 } | |
165 } | |
166 } | |
167 | |
168 /** | |
169 * Creates a test drupal installation. | |
170 * | |
171 * @param string $profile | |
172 * (optional) The installation profile to use. | |
173 * @param string $setup_class | |
174 * (optional) Setup class. A PHP class to setup configuration used by the | |
175 * test. | |
176 * @param string $langcode | |
177 * (optional) The language to install the site in. | |
178 */ | |
179 public function setup($profile = 'testing', $setup_class = NULL, $langcode = 'en') { | |
180 $this->profile = $profile; | |
181 $this->langcode = $langcode; | |
182 $this->setupBaseUrl(); | |
183 $this->prepareEnvironment(); | |
184 $this->installDrupal(); | |
185 | |
186 if ($setup_class) { | |
187 $this->executeSetupClass($setup_class); | |
188 } | |
189 } | |
190 | |
191 /** | |
192 * Installs Drupal into the test site. | |
193 */ | |
194 protected function installDrupal() { | |
195 $this->initUserSession(); | |
196 $this->prepareSettings(); | |
197 $this->doInstall(); | |
198 $this->initSettings(); | |
199 $container = $this->initKernel(\Drupal::request()); | |
200 $this->initConfig($container); | |
201 $this->installModulesFromClassProperty($container); | |
202 $this->rebuildAll(); | |
203 } | |
204 | |
205 /** | |
206 * Uses the setup file to configure Drupal. | |
207 * | |
208 * @param string $class | |
209 * The fully qualified class name, which should set up Drupal for tests. For | |
210 * example this class could create content types and fields or install | |
211 * modules. The class needs to implement TestSetupInterface. | |
212 * | |
213 * @see \Drupal\TestSite\TestSetupInterface | |
214 */ | |
215 protected function executeSetupClass($class) { | |
216 /** @var \Drupal\TestSite\TestSetupInterface $instance */ | |
217 $instance = new $class(); | |
218 $instance->setup(); | |
219 } | |
220 | |
221 /** | |
222 * {@inheritdoc} | |
223 */ | |
224 protected function installParameters() { | |
225 $parameters = $this->installParametersTrait(); | |
226 $parameters['parameters']['langcode'] = $this->langcode; | |
227 return $parameters; | |
228 } | |
229 | |
230 /** | |
231 * {@inheritdoc} | |
232 */ | |
233 protected function changeDatabasePrefix() { | |
234 // Ensure that we use the database from SIMPLETEST_DB environment variable. | |
235 Database::removeConnection('default'); | |
236 $this->changeDatabasePrefixTrait(); | |
237 } | |
238 | |
239 /** | |
240 * {@inheritdoc} | |
241 */ | |
242 protected function prepareDatabasePrefix() { | |
243 // Override this method so that we can force a lock to be created. | |
244 $test_db = new TestDatabase(NULL, TRUE); | |
245 $this->siteDirectory = $test_db->getTestSitePath(); | |
246 $this->databasePrefix = $test_db->getDatabasePrefix(); | |
247 } | |
248 | |
249 } |