summaryrefslogtreecommitdiffstatshomepage
path: root/core/lib/Drupal/Core/Test/TestSetupTrait.php
blob: e68c9dba532b14b942d6f0b8a34b54d0830bff65 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
<?php

namespace Drupal\Core\Test;

use Drupal\Core\Database\Database;

/**
 * Provides a trait for shared test setup functionality.
 */
trait TestSetupTrait {

  /**
   * An array of config object names that are excluded from schema checking.
   *
   * @var string[]
   */
  protected static $configSchemaCheckerExclusions = [
    // Following are used to test lack of or partial schema. Where partial
    // schema is provided, that is explicitly tested in specific tests.
    'config_schema_test.no_schema',
    'config_schema_test.some_schema',
    'config_schema_test.schema_data_types',
    'config_schema_test.no_schema_data_types',
    // Used to test application of schema to filtering of configuration.
    'config_test.dynamic.system',
  ];

  /**
   * The dependency injection container used in the test.
   *
   * @var \Symfony\Component\DependencyInjection\ContainerInterface
   */
  protected $container;

  /**
   * The site directory of this test run.
   *
   * @var string
   */
  protected $siteDirectory = NULL;

  /**
   * The public file directory for the test environment.
   *
   * @var string
   *
   * @see \Drupal\Tests\BrowserTestBase::prepareEnvironment()
   */
  protected $publicFilesDirectory;

  /**
   * The site directory of the original parent site.
   *
   * @var string
   */
  protected $originalSite;

  /**
   * The private file directory for the test environment.
   *
   * @var string
   *
   * @see \Drupal\Tests\BrowserTestBase::prepareEnvironment()
   */
  protected $privateFilesDirectory;

  /**
   * Set to TRUE to strict check all configuration saved.
   *
   * @var bool
   *
   * @see \Drupal\Core\Config\Testing\ConfigSchemaChecker
   */
  protected $strictConfigSchema = TRUE;

  /**
   * The DrupalKernel instance used in the test.
   *
   * @var \Drupal\Core\DrupalKernel
   */
  protected $kernel;

  /**
   * The database prefix of this test run.
   *
   * @var string
   */
  protected $databasePrefix;

  /**
   * The app root.
   *
   * @var string
   */
  protected $root;

  /**
   * The temporary file directory for the test environment.
   *
   * This value has to match the temporary directory created in
   * install_base_system() for test installs.
   *
   * @var string
   *
   * @see \Drupal\Tests\BrowserTestBase::prepareEnvironment()
   * @see install_base_system()
   */
  protected $tempFilesDirectory;

  /**
   * The test run ID.
   *
   * @var string
   */
  protected $testId;

  /**
   * Generates a database prefix for running tests.
   *
   * The database prefix is used by prepareEnvironment() to setup a public files
   * directory for the test to be run, which also contains the PHP error log,
   * which is written to in case of a fatal error. Since that directory is based
   * on the database prefix, all tests (even unit tests) need to have one, in
   * order to access and read the error log.
   *
   * The generated database table prefix is used for the Drupal installation
   * being performed for the test. It is also used as user agent HTTP header it
   * is also used in the user agent HTTP header value by BrowserTestBase, which
   * is sent to the Drupal installation of the test. During early Drupal all
   * bootstrap, the user agent HTTP header is parsed, and if it matches,
   * database queries use the database table prefix that has been generated
   * here.
   *
   * @see \Drupal\Tests\BrowserTestBase::prepareEnvironment()
   * @see drupal_valid_test_ua()
   */
  protected function prepareDatabasePrefix() {
    $test_db = new TestDatabase();
    $this->siteDirectory = $test_db->getTestSitePath();
    $this->databasePrefix = $test_db->getDatabasePrefix();
  }

  /**
   * Changes the database connection to the prefixed one.
   */
  protected function changeDatabasePrefix() {
    if (empty($this->databasePrefix)) {
      $this->prepareDatabasePrefix();
    }

    // If the test is run with argument dburl then use it.
    $db_url = getenv('SIMPLETEST_DB');
    if (!empty($db_url)) {
      // Ensure no existing database gets in the way. If a default database
      // exists already it must be removed.
      Database::removeConnection('default');
      $database = Database::convertDbUrlToConnectionInfo($db_url, $this->root ?? DRUPAL_ROOT, TRUE);
      Database::addConnectionInfo('default', 'default', $database);
    }

    // Clone the current connection and replace the current prefix.
    $connection_info = Database::getConnectionInfo('default');
    if (is_null($connection_info)) {
      throw new \InvalidArgumentException('There is no database connection so no tests can be run. You must provide a SIMPLETEST_DB environment variable to run PHPUnit based functional tests outside of run-tests.sh.');
    }
    else {
      Database::renameConnection('default', 'simpletest_original_default');
      foreach ($connection_info as $target => $value) {
        // Replace the full table prefix definition to ensure that no table
        // prefixes of the test runner leak into the test.
        $connection_info[$target]['prefix'] = $value['prefix'] . $this->databasePrefix;
      }
      Database::removeConnection('default');
      Database::addConnectionInfo('default', 'default', $connection_info['default']);
    }
  }

  /**
   * Gets the config schema exclusions for this test.
   *
   * @return string[]
   *   An array of config object names that are excluded from schema checking.
   */
  protected function getConfigSchemaExclusions() {
    $class = static::class;
    $exceptions = [];
    while ($class) {
      if (property_exists($class, 'configSchemaCheckerExclusions')) {
        $exceptions[] = $class::$configSchemaCheckerExclusions;
      }
      $class = get_parent_class($class);
    }
    // Filter out any duplicates.
    return array_unique(array_merge(...$exceptions));
  }

}