Magento 2 Documentation  2.3
Documentation for Magento 2 CMS v2.3 (December 2018)
ParallelGroupSorter.php
Go to the documentation of this file.
1 <?php
7 
10 
12 {
18  private $suiteConfig = [];
19 
23  public function __construct()
24  {
25  // empty constructor
26  }
27 
37  public function getTestsGroupedBySize($suiteConfiguration, $testNameToSize, $time)
38  {
39  // we must have the lines argument in order to create the test groups
40  if ($time == 0) {
41  throw new TestFrameworkException(
42  "Please provide the argument '--time' to the robo command in order to".
43  " generate grouped tests manifests for a parallel execution"
44  );
45  }
46 
47  $testGroups = [];
48  $splitSuiteNamesToTests = $this->createGroupsWithinSuites($suiteConfiguration, $time);
49  $splitSuiteNamesToSize = $this->getSuiteToSize($splitSuiteNamesToTests);
50  arsort($testNameToSize);
51  arsort($splitSuiteNamesToSize);
52 
53  $testNameToSizeForUse = $testNameToSize;
54  $nodeNumber = 1;
55 
56  foreach ($splitSuiteNamesToSize as $testName => $testSize) {
57  $testGroups[$nodeNumber] = [$testName => $testSize];
58  $nodeNumber++;
59  }
60 
61  foreach ($testNameToSize as $testName => $testSize) {
62  if (!array_key_exists($testName, $testNameToSizeForUse)) {
63  // skip tests which have already been added to a group
64  continue;
65  }
66 
67  $testGroup = $this->createTestGroup($time, $testName, $testSize, $testNameToSizeForUse);
68  $testGroups[$nodeNumber] = $testGroup;
69 
70  // unset the test which have been used.
71  $testNameToSizeForUse = array_diff_key($testNameToSizeForUse, $testGroup);
72  $nodeNumber++;
73  }
74 
75  return $testGroups;
76  }
77 
83  public function getResultingSuiteConfig()
84  {
85  if (empty($this->suiteConfig)) {
86  return null;
87  }
88 
89  return $this->suiteConfig;
90  }
91 
103  private function createTestGroup($timeMaximum, $testName, $testSize, $testNameToSizeForUse)
104  {
105  $group[$testName] = $testSize;
106 
107  if ($testSize < $timeMaximum) {
108  while (array_sum($group) < $timeMaximum && !empty($testNameToSizeForUse)) {
109  $groupSize = array_sum($group);
110  $lineGoal = $timeMaximum - $groupSize;
111 
112  $testNameForUse = $this->getClosestLineCount($testNameToSizeForUse, $lineGoal);
113  if ($testNameToSizeForUse[$testNameForUse] < $lineGoal) {
114  $testSizeForUse = $testNameToSizeForUse[$testNameForUse];
115  $group[$testNameForUse] = $testSizeForUse;
116  }
117 
118  unset($testNameToSizeForUse[$testNameForUse]);
119  }
120  }
121 
122  return $group;
123  }
124 
133  private function getClosestLineCount($testGroup, $desiredValue)
134  {
135  $winner = key($testGroup);
136  $closestThreshold = $desiredValue;
137  foreach ($testGroup as $testName => $testValue) {
138  // find the difference between the desired value and test candidate for the group
139  $testThreshold = $desiredValue - $testValue;
140 
141  // if we see that the gap between the desired value is non-negative and lower than the current closest make
142  // the test the winner.
143  if ($closestThreshold > $testThreshold && $testThreshold > 0) {
144  $closestThreshold = $testThreshold;
145  $winner = $testName;
146  }
147  }
148 
149  return $winner;
150  }
151 
160  private function createGroupsWithinSuites($suiteConfiguration, $lineLimit)
161  {
162  $suiteNameToTestSize = $this->getSuiteNameToTestSize($suiteConfiguration);
163  $suiteNameToSize = $this->getSuiteToSize($suiteNameToTestSize);
164 
165  // divide the suites up within the array
166  $suitesForResize = array_filter($suiteNameToSize, function ($val) use ($lineLimit) {
167  return $val > $lineLimit;
168  });
169 
170  // remove the suites for resize from the original list
171  $remainingSuites = array_diff_key($suiteNameToTestSize, $suitesForResize);
172 
173  foreach ($remainingSuites as $remainingSuite => $tests) {
174  $this->addSuiteToConfig($remainingSuite, null, $tests);
175  }
176 
177  $resultingGroups = [];
178  foreach ($suitesForResize as $suiteName => $suiteSize) {
179  $resultingGroups = array_merge(
180  $resultingGroups,
181  $this->splitTestSuite($suiteName, $suiteNameToTestSize[$suiteName], $lineLimit)
182  );
183  }
184 
185  // merge the resulting divisions with the appropriately sized suites
186  return array_merge($remainingSuites, $resultingGroups);
187  }
188 
195  private function getSuiteNameToTestSize($suiteConfiguration)
196  {
197  $suiteNameToTestSize = [];
198  foreach ($suiteConfiguration as $suite => $test) {
199  foreach ($test as $testName) {
200  $suiteNameToTestSize[$suite][$testName] = TestObjectHandler::getInstance()
201  ->getObject($testName)
202  ->getEstimatedDuration();
203  }
204  }
205 
206  return $suiteNameToTestSize;
207  }
208 
217  private function getSuiteToSize($suiteNamesToTests)
218  {
219  $suiteNamesToSize = [];
220  foreach ($suiteNamesToTests as $name => $tests) {
221  $size = array_sum($tests);
222  $suiteNamesToSize[$name] = $size;
223  }
224 
225  return $suiteNamesToSize;
226  }
227 
242  private function splitTestSuite($suiteName, $tests, $maxTime)
243  {
244  arsort($tests);
245  $splitSuites = [];
246  $availableTests = $tests;
247  $splitCount = 0;
248 
249  foreach ($tests as $test => $size) {
250  if (!array_key_exists($test, $availableTests)) {
251  continue;
252  }
253 
254  $group = $this->createTestGroup($maxTime, $test, $size, $availableTests);
255  $splitSuites["{$suiteName}_${splitCount}"] = $group;
256  $this->addSuiteToConfig($suiteName, "{$suiteName}_${splitCount}", $group);
257 
258  $availableTests = array_diff_key($availableTests, $group);
259  $splitCount++;
260  }
261 
262  return $splitSuites;
263  }
264 
275  private function addSuiteToConfig($originalSuiteName, $newSuiteName, $tests)
276  {
277  if ($newSuiteName == null) {
278  $this->suiteConfig[$originalSuiteName] = array_keys($tests);
279  return;
280  }
281 
282  $this->suiteConfig[$originalSuiteName][$newSuiteName] = array_keys($tests);
283  }
284 }
$group
Definition: sections.phtml:16
getTestsGroupedBySize($suiteConfiguration, $testNameToSize, $time)
if(!isset($_GET['name'])) $name
Definition: log.php:14