ApiDataFixture.php 5.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168
  1. <?php
  2. /**
  3. * Implementation of the magentoApiDataFixture DocBlock annotation.
  4. *
  5. * The difference of magentoApiDataFixture from magentoDataFixture is
  6. * that no transactions should be used for API data fixtures.
  7. * Otherwise fixture data will not be accessible to Web API functional tests.
  8. *
  9. * Copyright © Magento, Inc. All rights reserved.
  10. * See COPYING.txt for license details.
  11. */
  12. namespace Magento\TestFramework\Annotation;
  13. class ApiDataFixture
  14. {
  15. /**
  16. * @var string
  17. */
  18. protected $_fixtureBaseDir;
  19. /**
  20. * Fixtures that have been applied
  21. *
  22. * @var array
  23. */
  24. private $_appliedFixtures = [];
  25. /**
  26. * Constructor
  27. *
  28. * @param string $fixtureBaseDir
  29. * @throws \Magento\Framework\Exception\LocalizedException
  30. */
  31. public function __construct($fixtureBaseDir)
  32. {
  33. if (!is_dir($fixtureBaseDir)) {
  34. throw new \Magento\Framework\Exception\LocalizedException(
  35. __("Fixture base directory '%1' does not exist.", $fixtureBaseDir)
  36. );
  37. }
  38. $this->_fixtureBaseDir = realpath($fixtureBaseDir);
  39. }
  40. /**
  41. * Handler for 'startTest' event
  42. *
  43. * @param \PHPUnit\Framework\TestCase $test
  44. */
  45. public function startTest(\PHPUnit\Framework\TestCase $test)
  46. {
  47. \Magento\TestFramework\Helper\Bootstrap::getInstance()->reinitialize();
  48. /** Apply method level fixtures if thy are available, apply class level fixtures otherwise */
  49. $this->_applyFixtures($this->_getFixtures('method', $test) ?: $this->_getFixtures('class', $test));
  50. }
  51. /**
  52. * Handler for 'endTest' event
  53. */
  54. public function endTest()
  55. {
  56. $this->_revertFixtures();
  57. /** @var $objectManager \Magento\TestFramework\ObjectManager */
  58. $objectManager = \Magento\TestFramework\Helper\Bootstrap::getObjectManager();
  59. $objectManager->get(\Magento\Customer\Model\Metadata\AttributeMetadataCache::class)->clean();
  60. }
  61. /**
  62. * Retrieve fixtures from annotation
  63. *
  64. * @param string $scope 'class' or 'method'
  65. * @param \PHPUnit\Framework\TestCase $test
  66. * @return array
  67. * @throws \Magento\Framework\Exception\LocalizedException
  68. */
  69. protected function _getFixtures($scope, \PHPUnit\Framework\TestCase $test)
  70. {
  71. $annotations = $test->getAnnotations();
  72. $result = [];
  73. if (!empty($annotations[$scope]['magentoApiDataFixture'])) {
  74. foreach ($annotations[$scope]['magentoApiDataFixture'] as $fixture) {
  75. if (strpos($fixture, '\\') !== false) {
  76. // usage of a single directory separator symbol streamlines search across the source code
  77. throw new \Magento\Framework\Exception\LocalizedException(
  78. __('Directory separator "\\" is prohibited in fixture declaration.')
  79. );
  80. }
  81. $fixtureMethod = [get_class($test), $fixture];
  82. if (is_callable($fixtureMethod)) {
  83. $result[] = $fixtureMethod;
  84. } else {
  85. $result[] = $this->_fixtureBaseDir . '/' . $fixture;
  86. }
  87. }
  88. }
  89. return $result;
  90. }
  91. /**
  92. * Execute single fixture script
  93. *
  94. * @param string|array $fixture
  95. * @throws \Throwable
  96. */
  97. protected function _applyOneFixture($fixture)
  98. {
  99. try {
  100. if (is_callable($fixture)) {
  101. call_user_func($fixture);
  102. } else {
  103. require $fixture;
  104. }
  105. } catch (\Exception $e) {
  106. throw new \Exception(
  107. sprintf(
  108. "Exception occurred when running the %s fixture: \n%s",
  109. (\is_array($fixture) || is_scalar($fixture) ? json_encode($fixture) : 'callback'),
  110. $e->getMessage()
  111. )
  112. );
  113. }
  114. $this->_appliedFixtures[] = $fixture;
  115. }
  116. /**
  117. * Execute fixture scripts if any
  118. *
  119. * @param array $fixtures
  120. * @throws \Magento\Framework\Exception\LocalizedException
  121. */
  122. protected function _applyFixtures(array $fixtures)
  123. {
  124. /* Execute fixture scripts */
  125. foreach ($fixtures as $oneFixture) {
  126. /* Skip already applied fixtures */
  127. if (!in_array($oneFixture, $this->_appliedFixtures, true)) {
  128. $this->_applyOneFixture($oneFixture);
  129. }
  130. }
  131. }
  132. /**
  133. * Revert changes done by fixtures
  134. */
  135. protected function _revertFixtures()
  136. {
  137. $appliedFixtures = array_reverse($this->_appliedFixtures);
  138. foreach ($appliedFixtures as $fixture) {
  139. if (is_callable($fixture)) {
  140. $fixture[1] .= 'Rollback';
  141. if (is_callable($fixture)) {
  142. $this->_applyOneFixture($fixture);
  143. }
  144. } else {
  145. $fileInfo = pathinfo($fixture);
  146. $extension = '';
  147. if (isset($fileInfo['extension'])) {
  148. $extension = '.' . $fileInfo['extension'];
  149. }
  150. $rollbackScript = $fileInfo['dirname'] . '/' . $fileInfo['filename'] . '_rollback' . $extension;
  151. if (file_exists($rollbackScript)) {
  152. $this->_applyOneFixture($rollbackScript);
  153. }
  154. }
  155. }
  156. $this->_appliedFixtures = [];
  157. }
  158. }