Magento 2 Documentation  2.3
Documentation for Magento 2 CMS v2.3 (December 2018)
SuiteGenerator.php
Go to the documentation of this file.
1 <?php
8 
19 use Symfony\Component\Yaml\Yaml;
20 
22 {
23  const YAML_CODECEPTION_DIST_FILENAME = 'codeception.dist.yml';
24  const YAML_CODECEPTION_CONFIG_FILENAME = 'codeception.yml';
25  const YAML_GROUPS_TAG = 'groups';
26  const YAML_EXTENSIONS_TAG = 'extensions';
27  const YAML_ENABLED_TAG = 'enabled';
29  "# Copyright © Magento, Inc. All rights reserved.\n# See COPYING.txt for license details.\n";
30 
36  private static $SUITE_GENERATOR_INSTANCE;
37 
43  private $groupClassGenerator;
44 
48  private function __construct()
49  {
50  $this->groupClassGenerator = new GroupClassGenerator();
51  }
52 
58  public static function getInstance()
59  {
60  if (!self::$SUITE_GENERATOR_INSTANCE) {
61  // clear any previous configurations before any generation occurs.
62  self::clearPreviousGroupPreconditions();
63  self::clearPreviousSessionConfigEntries();
64  self::$SUITE_GENERATOR_INSTANCE = new SuiteGenerator();
65  }
66 
67  return self::$SUITE_GENERATOR_INSTANCE;
68  }
69 
78  public function generateAllSuites($testManifest)
79  {
80  $suites = $testManifest->getSuiteConfig();
81 
82  foreach ($suites as $suiteName => $suiteContent) {
83  $firstElement = array_values($suiteContent)[0];
84 
85  // if the first element is a string we know that we simply have an array of tests
86  if (is_string($firstElement)) {
87  $this->generateSuiteFromTest($suiteName, $suiteContent);
88  }
89 
90  // if our first element is an array we know that we have split the suites
91  if (is_array($firstElement)) {
92  $this->generateSplitSuiteFromTest($suiteName, $suiteContent);
93  }
94  }
95  }
96 
105  public function generateSuite($suiteName)
106  {
108  $this->generateSuiteFromTest($suiteName, []);
109  }
110 
123  private function generateSuiteFromTest($suiteName, $tests = [], $originalSuiteName = null)
124  {
125  $relativePath = TestGenerator::GENERATED_DIR . DIRECTORY_SEPARATOR . $suiteName;
126  $fullPath = TESTS_MODULE_PATH . DIRECTORY_SEPARATOR . $relativePath . DIRECTORY_SEPARATOR;
127 
128  DirSetupUtil::createGroupDir($fullPath);
129 
130  $relevantTests = [];
131  if (!empty($tests)) {
132  $this->validateTestsReferencedInSuite($suiteName, $tests, $originalSuiteName);
133  foreach ($tests as $testName) {
134  $relevantTests[$testName] = TestObjectHandler::getInstance()->getObject($testName);
135  }
136  } else {
137  $relevantTests = SuiteObjectHandler::getInstance()->getObject($suiteName)->getTests();
138  }
139 
140  $this->generateRelevantGroupTests($suiteName, $relevantTests);
141  $groupNamespace = $this->generateGroupFile($suiteName, $relevantTests, $originalSuiteName);
142 
143  $this->appendEntriesToConfig($suiteName, $fullPath, $groupNamespace);
144  LoggingUtil::getInstance()->getLogger(SuiteGenerator::class)->info(
145  "suite generated",
146  ['suite' => $suiteName, 'relative_path' => $relativePath]
147  );
148  }
149 
161  private function validateTestsReferencedInSuite($suiteName, $testsReferenced, $originalSuiteName)
162  {
163  $suiteRef = $originalSuiteName ?? $suiteName;
164  $possibleTestRef = SuiteObjectHandler::getInstance()->getObject($suiteRef)->getTests();
165  $errorMsg = "Cannot reference tests whcih are not declared as part of suite.";
166 
167  $invalidTestRef = array_diff($testsReferenced, array_keys($possibleTestRef));
168 
169  if (!empty($invalidTestRef)) {
170  throw new TestReferenceException($errorMsg, ['suite' => $suiteRef, 'test' => $invalidTestRef]);
171  }
172  }
173 
183  private function generateSplitSuiteFromTest($suiteName, $suiteContent)
184  {
185  foreach ($suiteContent as $suiteSplitName => $tests) {
186  $this->generateSuiteFromTest($suiteSplitName, $tests, $suiteName);
187  }
188  }
189 
201  private function generateGroupFile($suiteName, $tests, $originalSuiteName)
202  {
203  // if there's an original suite name we know that this test came from a split group.
204  if ($originalSuiteName) {
205  // create the new suite object
207  $originalSuite = SuiteObjectHandler::getInstance()->getObject($originalSuiteName);
208  $suiteObject = new SuiteObject(
209  $suiteName,
210  $tests,
211  [],
212  $originalSuite->getHooks()
213  );
214  } else {
215  $suiteObject = SuiteObjectHandler::getInstance()->getObject($suiteName);
216  // we have to handle the case when there is a custom configuration for an existing suite.
217  if (count($suiteObject->getTests()) != count($tests)) {
218  return $this->generateGroupFile($suiteName, $tests, $suiteName);
219  }
220  }
221 
222  if (!$suiteObject->requiresGroupFile()) {
223  // if we do not require a group file we don't need a namespace
224  return null;
225  }
226 
227  // if the suite requires a group file, generate it and set the namespace
228  return $this->groupClassGenerator->generateGroupClass($suiteObject);
229  }
230 
241  private function appendEntriesToConfig($suiteName, $suitePath, $groupNamespace)
242  {
243  $relativeSuitePath = substr($suitePath, strlen(TESTS_BP));
244  $relativeSuitePath = ltrim($relativeSuitePath, DIRECTORY_SEPARATOR);
245 
246  $ymlArray = self::getYamlFileContents();
247  if (!array_key_exists(self::YAML_GROUPS_TAG, $ymlArray)) {
248  $ymlArray[self::YAML_GROUPS_TAG]= [];
249  }
250 
251  if ($groupNamespace) {
252  $ymlArray[self::YAML_EXTENSIONS_TAG][self::YAML_ENABLED_TAG][] = $groupNamespace;
253  }
254  $ymlArray[self::YAML_GROUPS_TAG][$suiteName] = [$relativeSuitePath];
255 
256  $ymlText = self::YAML_COPYRIGHT_TEXT . Yaml::dump($ymlArray, 10);
257  file_put_contents(self::getYamlConfigFilePath() . self::YAML_CODECEPTION_CONFIG_FILENAME, $ymlText);
258  }
259 
266  private static function clearPreviousSessionConfigEntries()
267  {
268  $ymlArray = self::getYamlFileContents();
269  $newYmlArray = $ymlArray;
270  // if the yaml entries haven't already been cleared
271  if (array_key_exists(self::YAML_EXTENSIONS_TAG, $ymlArray)) {
272  foreach ($ymlArray[self::YAML_EXTENSIONS_TAG][self::YAML_ENABLED_TAG] as $key => $entry) {
273  if (preg_match('/(Group\\\\.*)/', $entry)) {
274  unset($newYmlArray[self::YAML_EXTENSIONS_TAG][self::YAML_ENABLED_TAG][$key]);
275  }
276  }
277 
278  // needed for proper yml file generation based on indices
280  array_values($newYmlArray[self::YAML_EXTENSIONS_TAG][self::YAML_ENABLED_TAG]);
281  }
282 
283  if (array_key_exists(self::YAML_GROUPS_TAG, $newYmlArray)) {
284  unset($newYmlArray[self::YAML_GROUPS_TAG]);
285  }
286 
287  $ymlText = self::YAML_COPYRIGHT_TEXT . Yaml::dump($newYmlArray, 10);
288  file_put_contents(self::getYamlConfigFilePath() . self::YAML_CODECEPTION_CONFIG_FILENAME, $ymlText);
289  }
290 
301  private function generateRelevantGroupTests($path, $tests)
302  {
303  $testGenerator = TestGenerator::getInstance($path, $tests);
304  $testGenerator->createAllTestFiles(null, []);
305  }
306 
312  private static function clearPreviousGroupPreconditions()
313  {
314  $groupFilePath = GroupClassGenerator::getGroupDirPath();
315  array_map('unlink', glob("$groupFilePath*.php"));
316  }
317 
323  private static function getYamlFileContents()
324  {
325  $configYmlFile = self::getYamlConfigFilePath() . self::YAML_CODECEPTION_CONFIG_FILENAME;
326  $defaultConfigYmlFile = self::getYamlConfigFilePath() . self::YAML_CODECEPTION_DIST_FILENAME;
327 
328  $ymlContents = null;
329  if (file_exists($configYmlFile)) {
330  $ymlContents = file_get_contents($configYmlFile);
331  } else {
332  $ymlContents = file_get_contents($defaultConfigYmlFile);
333  }
334 
335  return Yaml::parse($ymlContents) ?? [];
336  }
337 
343  private static function getYamlConfigFilePath()
344  {
345  return TESTS_BP . DIRECTORY_SEPARATOR;
346  }
347 }
static getInstance($dir=null, $tests=[], $debug=false)
$relativePath
Definition: get.php:35