SchemaFixture.php 5.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188
  1. <?php
  2. /**
  3. * Copyright © Magento, Inc. All rights reserved.
  4. * See COPYING.txt for license details.
  5. */
  6. /**
  7. * Implementation of the @magentoSchemaFixture DocBlock annotation.
  8. */
  9. namespace Magento\TestFramework\Annotation;
  10. /**
  11. * Represents following construction handling:
  12. *
  13. * @magentoSchemaFixture {link_to_file.php}
  14. */
  15. class SchemaFixture
  16. {
  17. /**
  18. * Fixtures base directory.
  19. *
  20. * @var string
  21. */
  22. protected $fixtureBaseDir;
  23. /**
  24. * Fixtures that have been applied.
  25. *
  26. * @var array
  27. */
  28. private $appliedFixtures = [];
  29. /**
  30. * Constructor.
  31. *
  32. * @param string $fixtureBaseDir
  33. * @throws \Magento\Framework\Exception\LocalizedException
  34. */
  35. public function __construct($fixtureBaseDir)
  36. {
  37. if (!is_dir($fixtureBaseDir)) {
  38. throw new \Magento\Framework\Exception\LocalizedException(
  39. new \Magento\Framework\Phrase("Fixture base directory '%1' does not exist.", [$fixtureBaseDir])
  40. );
  41. }
  42. $this->fixtureBaseDir = realpath($fixtureBaseDir);
  43. }
  44. /**
  45. * Apply magento data fixture on.
  46. *
  47. * @param \PHPUnit\Framework\TestCase $test
  48. * @return void
  49. */
  50. public function startTest(\PHPUnit\Framework\TestCase $test)
  51. {
  52. if ($this->_getFixtures($test)) {
  53. $this->_applyFixtures($this->_getFixtures($test));
  54. }
  55. }
  56. /**
  57. * Finish test execution.
  58. *
  59. * @param \PHPUnit\Framework\TestCase $test
  60. */
  61. public function endTest(\PHPUnit\Framework\TestCase $test)
  62. {
  63. if ($this->_getFixtures($test)) {
  64. $this->_revertFixtures();
  65. }
  66. }
  67. /**
  68. * Retrieve fixtures from annotation.
  69. *
  70. * @param \PHPUnit\Framework\TestCase $test
  71. * @param string $scope
  72. * @return array
  73. * @throws \Magento\Framework\Exception\LocalizedException
  74. */
  75. protected function _getFixtures(\PHPUnit\Framework\TestCase $test, $scope = null)
  76. {
  77. if ($scope === null) {
  78. $annotations = $this->getAnnotations($test);
  79. } else {
  80. $annotations = $test->getAnnotations()[$scope];
  81. }
  82. $result = [];
  83. if (!empty($annotations['magentoSchemaFixture'])) {
  84. foreach ($annotations['magentoSchemaFixture'] as $fixture) {
  85. if (strpos($fixture, '\\') !== false) {
  86. // usage of a single directory separator symbol streamlines search across the source code
  87. throw new \Magento\Framework\Exception\LocalizedException(
  88. new \Magento\Framework\Phrase('Directory separator "\\" is prohibited in fixture declaration.')
  89. );
  90. }
  91. $fixtureMethod = [get_class($test), $fixture];
  92. if (is_callable($fixtureMethod)) {
  93. $result[] = $fixtureMethod;
  94. } else {
  95. $result[] = $this->fixtureBaseDir . '/' . $fixture;
  96. }
  97. }
  98. }
  99. return $result;
  100. }
  101. /**
  102. * Get annotations for test.
  103. *
  104. * @param \PHPUnit\Framework\TestCase $test
  105. * @return array
  106. */
  107. private function getAnnotations(\PHPUnit\Framework\TestCase $test)
  108. {
  109. $annotations = $test->getAnnotations();
  110. return array_replace($annotations['class'], $annotations['method']);
  111. }
  112. /**
  113. * Execute single fixture script.
  114. *
  115. * @param string|array $fixture
  116. * @throws \Exception
  117. */
  118. protected function _applyOneFixture($fixture)
  119. {
  120. try {
  121. if (is_callable($fixture)) {
  122. call_user_func($fixture);
  123. } else {
  124. include $fixture;
  125. }
  126. } catch (\Exception $e) {
  127. throw new \Exception(
  128. sprintf("Error in fixture: %s.\n %s", json_encode($fixture), $e->getMessage()),
  129. 500,
  130. $e
  131. );
  132. }
  133. }
  134. /**
  135. * Execute fixture scripts if any.
  136. *
  137. * @param array $fixtures
  138. * @throws \Magento\Framework\Exception\LocalizedException
  139. */
  140. protected function _applyFixtures(array $fixtures)
  141. {
  142. /* Execute fixture scripts */
  143. foreach ($fixtures as $oneFixture) {
  144. /* Skip already applied fixtures */
  145. if (in_array($oneFixture, $this->appliedFixtures, true)) {
  146. continue;
  147. }
  148. $this->_applyOneFixture($oneFixture);
  149. $this->appliedFixtures[] = $oneFixture;
  150. }
  151. }
  152. /**
  153. * Revert changes done by fixtures.
  154. */
  155. protected function _revertFixtures()
  156. {
  157. foreach ($this->appliedFixtures as $fixture) {
  158. if (is_callable($fixture)) {
  159. $fixture[1] .= 'Rollback';
  160. if (is_callable($fixture)) {
  161. $this->_applyOneFixture($fixture);
  162. }
  163. } else {
  164. $fileInfo = pathinfo($fixture);
  165. $extension = '';
  166. if (isset($fileInfo['extension'])) {
  167. $extension = '.' . $fileInfo['extension'];
  168. }
  169. $rollbackScript = $fileInfo['dirname'] . '/' . $fileInfo['filename'] . '_rollback' . $extension;
  170. if (file_exists($rollbackScript)) {
  171. $this->_applyOneFixture($rollbackScript);
  172. }
  173. }
  174. }
  175. $this->appliedFixtures = [];
  176. }
  177. }