/vendor/magento/magento2-base/dev/tests/integration/framework/Magento/TestFramework/Workaround/Cleanup/StaticProperties.php

https://gitlab.com/yousafsyed/easternglamor · PHP · 203 lines · 135 code · 14 blank · 54 comment · 12 complexity · 342bd7f57786dd5a5f41ab7e3bd52cc7 MD5 · raw file

  1. <?php
  2. /**
  3. * Copyright © 2016 Magento. All rights reserved.
  4. * See COPYING.txt for license details.
  5. */
  6. /**
  7. * Workaround for decreasing memory consumption by cleaning up static properties
  8. */
  9. namespace Magento\TestFramework\Workaround\Cleanup;
  10. use Magento\Framework\Component\ComponentRegistrar;
  11. use Magento\Framework\App\Utility\Files;
  12. class StaticProperties
  13. {
  14. /**
  15. * Directories to clear static variables.
  16. *
  17. * Format: ['cleanableFolder' => ['pseudo-globs to match uncleanable subfolders']]
  18. *
  19. * @var array
  20. */
  21. protected static $_cleanableFolders = [
  22. '/dev/tests/integration/framework' => [],
  23. ];
  24. protected static $backupStaticVariables = [];
  25. /**
  26. * Classes to exclude from static variables cleaning
  27. *
  28. * @var array
  29. */
  30. protected static $_classesToSkip = [
  31. 'Mage',
  32. 'Magento\Framework\App\ObjectManager',
  33. 'Magento\TestFramework\Helper\Bootstrap',
  34. 'Magento\TestFramework\Event\Magento',
  35. 'Magento\TestFramework\Event\PhpUnit',
  36. 'Magento\TestFramework\Annotation\AppIsolation',
  37. 'Magento\TestFramework\Workaround\Cleanup\StaticProperties',
  38. 'Magento\Framework\Phrase',
  39. ];
  40. /**
  41. * Constructor
  42. */
  43. public function __construct()
  44. {
  45. $componentRegistrar = new ComponentRegistrar();
  46. /** @var \Magento\Framework\Filesystem $filesystem */
  47. foreach ($componentRegistrar->getPaths(ComponentRegistrar::MODULE) as $moduleDir) {
  48. $key = $moduleDir . '/';
  49. $value = $key . 'Test/Unit/';
  50. self::$_cleanableFolders[$key] = [$value];
  51. }
  52. foreach ($componentRegistrar->getPaths(ComponentRegistrar::LIBRARY) as $libraryDir) {
  53. $key = $libraryDir . '/';
  54. $valueRootFolder = $key . '/Test/Unit/';
  55. $valueSubFolder = $key . '/*/Test/Unit/';
  56. self::$_cleanableFolders[$key] = [$valueSubFolder, $valueRootFolder];
  57. }
  58. }
  59. /**
  60. * Check whether it is allowed to clean given class static variables
  61. *
  62. * @param \ReflectionClass $reflectionClass
  63. * @return bool
  64. */
  65. protected static function _isClassCleanable(\ReflectionClass $reflectionClass)
  66. {
  67. // do not process blacklisted classes from integration framework
  68. foreach (self::$_classesToSkip as $notCleanableClass) {
  69. if ($reflectionClass->getName() == $notCleanableClass || is_subclass_of(
  70. $reflectionClass->getName(),
  71. $notCleanableClass
  72. )
  73. ) {
  74. return false;
  75. }
  76. }
  77. return true;
  78. }
  79. /**
  80. * Check if class has to be backed up
  81. *
  82. * @param string $classFile
  83. * @return bool
  84. */
  85. protected static function _isClassInCleanableFolders($classFile)
  86. {
  87. $classFile = str_replace('\\', '/', $classFile);
  88. foreach (self::$_cleanableFolders as $include => $excludeSet) {
  89. if (stripos($classFile, $include) !== false) {
  90. foreach ($excludeSet as $exclude) {
  91. $excludeExp = '#' . str_replace('*', '[\w]+', $exclude) . '#';
  92. if (preg_match($excludeExp, $classFile)) {
  93. return false; // File is in an "include" directory, but also an "exclude" subdirectory of it
  94. }
  95. }
  96. return true; // File is in an "include" directory, and not in an "exclude" subdirectory of it
  97. }
  98. }
  99. return false; // File is not in an "include" directory
  100. }
  101. /**
  102. * Restore static variables (after running controller test case)
  103. * @TODO: refactor all code where objects are stored to static variables to use object manager instead
  104. */
  105. public static function restoreStaticVariables()
  106. {
  107. foreach (array_keys(self::$backupStaticVariables) as $class) {
  108. $reflectionClass = new \ReflectionClass($class);
  109. $staticProperties = $reflectionClass->getProperties(\ReflectionProperty::IS_STATIC);
  110. foreach ($staticProperties as $staticProperty) {
  111. $staticProperty->setAccessible(true);
  112. $staticProperty->setValue(self::$backupStaticVariables[$class][$staticProperty->getName()]);
  113. }
  114. }
  115. }
  116. /**
  117. * Backup static variables
  118. *
  119. */
  120. public static function backupStaticVariables()
  121. {
  122. $classFiles = Files::init()->getPhpFiles(
  123. Files::INCLUDE_APP_CODE
  124. | Files::INCLUDE_LIBS
  125. | Files::INCLUDE_TESTS
  126. );
  127. $namespacePattern = '/namespace [a-zA-Z0-9\\\\]+;/';
  128. $classPattern = '/\nclass [a-zA-Z0-9_]+/';
  129. foreach ($classFiles as $classFile) {
  130. if (self::_isClassInCleanableFolders($classFile)) {
  131. $file = @fopen($classFile, 'r');
  132. $code = fread($file, 4096);
  133. preg_match($namespacePattern, $code, $namespace);
  134. preg_match($classPattern, $code, $class);
  135. if (!isset($namespace[0]) || !isset($class[0])) {
  136. fclose($file);
  137. continue;
  138. }
  139. // trim namespace and class name
  140. $namespace = substr($namespace[0], 10, strlen($namespace[0]) - 11);
  141. $class = substr($class[0], 7, strlen($class[0]) - 7);
  142. $className = $namespace . '\\' . $class;
  143. try {
  144. $reflectionClass = new \ReflectionClass($className);
  145. } catch (\Exception $e) {
  146. fclose($file);
  147. continue;
  148. }
  149. if (self::_isClassCleanable($reflectionClass)) {
  150. $staticProperties = $reflectionClass->getProperties(\ReflectionProperty::IS_STATIC);
  151. foreach ($staticProperties as $staticProperty) {
  152. $staticProperty->setAccessible(true);
  153. $value = $staticProperty->getValue();
  154. self::$backupStaticVariables[$className][$staticProperty->getName()] = $value;
  155. }
  156. }
  157. fclose($file);
  158. }
  159. }
  160. }
  161. /**
  162. * Handler for 'startTestSuite' event
  163. *
  164. */
  165. public function startTestSuite()
  166. {
  167. if (empty(self::$backupStaticVariables)) {
  168. self::backupStaticVariables();
  169. }
  170. }
  171. /**
  172. * Handler for 'endTestSuite' event
  173. *
  174. * @param \PHPUnit_Framework_TestSuite $suite
  175. */
  176. public function endTestSuite(\PHPUnit_Framework_TestSuite $suite)
  177. {
  178. $clearStatics = false;
  179. foreach ($suite->tests() as $test) {
  180. if ($test instanceof \Magento\TestFramework\TestCase\AbstractController) {
  181. $clearStatics = true;
  182. break;
  183. }
  184. }
  185. if ($clearStatics) {
  186. self::restoreStaticVariables();
  187. }
  188. }
  189. }