@@ -37,7 +37,7 @@ public function __construct()
3737 public function getTestsGroupedBySize ($ suiteConfiguration , $ testNameToSize , $ time )
3838 {
3939 // we must have the lines argument in order to create the test groups
40- if ($ time === 0 ) {
40+ if ($ time == 0 ) {
4141 throw new FastFailException (
4242 "Please provide the argument '--time' to the robo command in order to " .
4343 " generate grouped tests manifests for a parallel execution "
@@ -86,27 +86,38 @@ public function getTestsGroupedBySize($suiteConfiguration, $testNameToSize, $tim
8686 */
8787 public function getTestsGroupedByFixedGroupCount ($ suiteConfiguration , $ testNameToSize , $ groupTotal )
8888 {
89- $ suiteNameToTestSize = $ this ->getSuiteNameToTestSize ($ suiteConfiguration );
90-
91- $ minRequiredGroupCount = count ($ suiteNameToTestSize );
92- if (!empty ($ testNameToSize )) {
93- $ minRequiredGroupCount += 1 ;
94- }
95- if ($ groupTotal < $ minRequiredGroupCount ) {
96- throw new FastFailException (
97- "Invalid parameter 'groupTotal': must be equal or greater than {$ minRequiredGroupCount }"
98- );
99- }
100-
10189 if (empty ($ suiteConfiguration )) {
10290 return $ this ->convertArrayIndexStartingAtOne ($ this ->splitTestsIntoGroups ($ testNameToSize , $ groupTotal ));
10391 }
10492
93+ $ suiteNameToTestSize = $ this ->getSuiteNameToTestSize ($ suiteConfiguration );
94+
10595 // Calculate suite group totals
10696 $ suiteNameToGroupCount = $ this ->getSuiteGroupCounts ($ suiteNameToTestSize , $ testNameToSize , $ groupTotal );
10797
108- // Calculate test group total
109- $ testGroupTotal = $ groupTotal - array_sum ($ suiteNameToGroupCount );
98+ $ suitesGroupTotal = array_sum ($ suiteNameToGroupCount );
99+
100+ // Calculate minimum required groups
101+ $ minSuiteGroupTotal = count ($ suiteNameToTestSize );
102+ $ minTestGroupTotal = empty ($ testNameToSize ) ? 0 : 1 ;
103+ $ minRequiredGroupTotal = $ minSuiteGroupTotal + $ minTestGroupTotal ;
104+
105+ if ($ groupTotal < $ minRequiredGroupTotal ) {
106+ throw new FastFailException (
107+ "Invalid parameter 'groupTotal': must be equal or greater than {$ minRequiredGroupTotal }"
108+ );
109+ } elseif ($ groupTotal < $ suitesGroupTotal + $ minTestGroupTotal ) {
110+ // Split in savvy mode when $groupTotal requested is very small
111+ $ testGroupTotal = $ minTestGroupTotal ;
112+ // Reduce suite group total
113+ $ suiteNameToGroupCount = $ this ->reduceSuiteGroupTotal (
114+ $ suiteNameToGroupCount ,
115+ $ groupTotal - $ minTestGroupTotal
116+ );
117+ } else {
118+ // Calculate test group total
119+ $ testGroupTotal = $ groupTotal - $ suitesGroupTotal ;
120+ }
110121
111122 // Split tests and suites
112123 $ testGroups = $ this ->splitTestsIntoGroups ($ testNameToSize , $ testGroupTotal );
@@ -140,19 +151,19 @@ private function getSuiteGroupCounts($suiteNameToTestSize, $testNameToSize, $gro
140151 $ maxSuiteTime = max ($ suiteNameToSize );
141152
142153 // Calculate 2 possible suite group times
143- $ ceilSuiteGroupNumber = ceil ($ maxSuiteTime / $ minGroupTime );
154+ $ ceilSuiteGroupNumber = ( int ) ceil ($ maxSuiteTime / $ minGroupTime );
144155 $ ceilSuiteGroupTime = max (ceil ($ maxSuiteTime / $ ceilSuiteGroupNumber ), $ minGroupTime );
145- $ floorSuiteGroupNumber = floor ($ maxSuiteTime / $ minGroupTime );
146- if ($ floorSuiteGroupNumber !== 0 ) {
156+ $ floorSuiteGroupNumber = ( int ) floor ($ maxSuiteTime / $ minGroupTime );
157+ if ($ floorSuiteGroupNumber != 0 ) {
147158 $ floorSuiteGroupTime = max (ceil ($ maxSuiteTime / $ floorSuiteGroupNumber ), $ minGroupTime );
148159 }
149160
150161 // Calculate test group time for ceiling
151162 $ ceilSuiteNameToGroupCount = $ this ->getSuiteGroupCountFromGroupTime ($ suiteNameToTestSize , $ ceilSuiteGroupTime );
152163 $ ceilSuiteGroupTotal = array_sum ($ ceilSuiteNameToGroupCount );
153- $ ceilTestGroupTotal = ( int ) $ groupTotal - ( int ) $ ceilSuiteGroupTotal ;
164+ $ ceilTestGroupTotal = $ groupTotal - $ ceilSuiteGroupTotal ;
154165
155- if ($ ceilTestGroupTotal === 0 ) {
166+ if ($ ceilTestGroupTotal == 0 ) {
156167 $ ceilTestGroupTime = 0 ;
157168 } else {
158169 $ ceilTestGroupTime = ceil (array_sum ($ testNameToSize ) / $ ceilTestGroupTotal );
@@ -161,15 +172,15 @@ private function getSuiteGroupCounts($suiteNameToTestSize, $testNameToSize, $gro
161172 // Set suite group total to ceiling
162173 $ suiteNameToGroupCount = $ ceilSuiteNameToGroupCount ;
163174
164- if (isset ($ floorSuiteGroupTime ) && $ ceilSuiteGroupTime !== $ floorSuiteGroupTime ) {
175+ if (isset ($ floorSuiteGroupTime ) && $ ceilSuiteGroupTime != $ floorSuiteGroupTime ) {
165176 // Calculate test group time for floor
166177 $ floorSuiteNameToGroupCount = $ this ->getSuiteGroupCountFromGroupTime (
167178 $ suiteNameToTestSize ,
168179 $ floorSuiteGroupTime
169180 );
170181 $ floorSuiteGroupTotal = array_sum ($ floorSuiteNameToGroupCount );
171182 $ floorTestGroupTotal = $ groupTotal - $ floorSuiteGroupTotal ;
172- if ($ floorTestGroupTotal === 0 ) {
183+ if ($ floorTestGroupTotal == 0 ) {
173184 $ floorTestGroupTime = 0 ;
174185 } else {
175186 $ floorTestGroupTime = ceil (array_sum ($ testNameToSize ) / $ floorTestGroupTotal );
@@ -187,6 +198,39 @@ private function getSuiteGroupCounts($suiteNameToTestSize, $testNameToSize, $gro
187198 return $ suiteNameToGroupCount ;
188199 }
189200
201+ /**
202+ * Reduce total suite groups to a given $total.
203+ * This method will reduce 1 from a suite that's greater than 1 repeatedly until sum of all groups reaches $total.
204+ *
205+ * @param array $suiteNameToGroupCount
206+ * @param integer $total
207+ * @return array
208+ * @throws FastFailException
209+ */
210+ private function reduceSuiteGroupTotal ($ suiteNameToGroupCount , $ total )
211+ {
212+ if (count ($ suiteNameToGroupCount ) > $ total ) {
213+ throw new FastFailException (
214+ "Invalid parameter 'total': must be equal or greater than {count( $ suiteNameToGroupCount)} "
215+ );
216+ }
217+
218+ $ done = false ;
219+ while (!$ done ) {
220+ foreach ($ suiteNameToGroupCount as $ suite => $ count ) {
221+ if (array_sum ($ suiteNameToGroupCount ) == $ total ) {
222+ $ done = true ;
223+ break ;
224+ }
225+ if ($ count > 1 ) {
226+ $ suiteNameToGroupCount [$ suite ] -= 1 ;
227+ }
228+ }
229+ }
230+
231+ return $ suiteNameToGroupCount ;
232+ }
233+
190234 /**
191235 * Return array contains suitename to number of groups to be split based on time.
192236 *
@@ -203,7 +247,7 @@ private function getSuiteGroupCountFromGroupTime($suiteNameToTestSize, $time)
203247 if ($ suiteTime <= $ time ) {
204248 $ suiteNameToGroupCount [$ suiteName ] = 1 ;
205249 } else {
206- $ suiteNameToGroupCount [$ suiteName ] = min (ceil ($ suiteTime /$ time ), $ maxCount );
250+ $ suiteNameToGroupCount [$ suiteName ] = min (( int ) ceil ($ suiteTime /$ time ), $ maxCount );
207251 }
208252 }
209253 return $ suiteNameToGroupCount ;
@@ -218,6 +262,10 @@ private function getSuiteGroupCountFromGroupTime($suiteNameToTestSize, $time)
218262 */
219263 private function splitTestsIntoGroups ($ tests , $ groupCnt )
220264 {
265+ if (empty ($ tests )) {
266+ return [];
267+ }
268+
221269 // Reverse sort the test array by size
222270 uasort ($ tests , function ($ a , $ b ) {
223271 return $ a >= $ b ? -1 : 1 ;
@@ -247,7 +295,7 @@ private function splitSuitesIntoGroups($suiteNameToTestSize, $suiteNameToGroupCo
247295 $ groups = [];
248296 foreach ($ suiteNameToTestSize as $ suiteName => $ suiteTests ) {
249297 $ suiteCnt = $ suiteNameToGroupCount [$ suiteName ];
250- if ($ suiteCnt === 1 ) {
298+ if ($ suiteCnt == 1 ) {
251299 $ groups [][$ suiteName ] = array_sum ($ suiteTests );
252300 $ this ->addSuiteToConfig ($ suiteName , null , $ suiteTests );
253301 } elseif ($ suiteCnt > 1 ) {
0 commit comments