1515import org .jsoup .Jsoup ;
1616import org .jsoup .nodes .Document ;
1717import org .jsoup .select .Elements ;
18+ import com .fasterxml .jackson .databind .ObjectMapper ;
19+ import com .fasterxml .jackson .dataformat .yaml .YAMLFactory ;
20+ import com .fasterxml .jackson .core .type .TypeReference ;
21+ import java .io .InputStream ;
22+ import java .util .List ;
23+ import java .util .Map ;
1824import org .junit .jupiter .api .AfterAll ;
1925import org .junit .jupiter .api .BeforeAll ;
2026import org .junit .jupiter .api .BeforeEach ;
@@ -178,14 +184,93 @@ private void validateMultiTestCaseHtmlReport(Path htmlReport) throws IOException
178184 assertTrue (comparisonRows .size () >= 3 ,
179185 "Comparison table should have at least 3 rows (one per test case), found: " + comparisonRows .size ());
180186
181- // Log all test case results for visibility
182- for (var row : comparisonRows ) {
183- Elements cells = row .select ("td" );
184- if (cells .size () >= 6 ) {
185- String label = cells .get (1 ).text ();
186- String sessions = cells .get (4 ).text ();
187- String participants = cells .get (5 ).text ();
188- log .info ("Test case '{}': sessions={}, participants={}" , label , sessions , participants );
187+ // Parse the YAML test config to know expected participants for each test case
188+ ObjectMapper mapper = new ObjectMapper (new YAMLFactory ());
189+ try (InputStream is = getClass ().getClassLoader ()
190+ .getResourceAsStream ("integration/config/multi-test-config.yaml" )) {
191+ Map <String , Object > cfg = mapper .readValue (is , new TypeReference <Map <String , Object >>() {
192+ });
193+ List <Map <String , Object >> testcases = (List <Map <String , Object >>) cfg .get ("testcases" );
194+
195+ // Global capacity: distribution.usersPerWorker (if present)
196+ int usersPerWorkerFromCfg = 0 ;
197+ Object distributionObj = cfg .get ("distribution" );
198+ if (distributionObj instanceof Map ) {
199+ Object upw = ((Map <?, ?>) distributionObj ).get ("usersPerWorker" );
200+ if (upw instanceof Number ) {
201+ usersPerWorkerFromCfg = ((Number ) upw ).intValue ();
202+ } else if (upw != null ) {
203+ usersPerWorkerFromCfg = Integer .parseInt (upw .toString ());
204+ }
205+ }
206+
207+ // For each overview row, assert the participants column matches the expected
208+ // total
209+ int idx = 0 ;
210+ // Explicit expected totals for the 3 test cases in this config
211+ int [] explicitExpected = new int [] { 25 , 215 , 303 };
212+ for (var row : comparisonRows ) {
213+ Elements cells = row .select ("td" );
214+ if (cells .size () >= 7 && idx < testcases .size ()) {
215+ String label = cells .get (1 ).text ();
216+ String sessionsCell = cells .get (4 ).text ();
217+ String participantsCell = cells .get (5 ).text ();
218+ String workersCell = cells .get (6 ).text ();
219+ // Stop reason is the last column in the overview table
220+ String stopReasonCell = cells .size () >= 9 ? cells .get (8 ).text () : "" ;
221+ log .info ("Test case '{}': sessions={}, participants={}, workers={}, stopReason={}" , label ,
222+ sessionsCell , participantsCell , workersCell , stopReasonCell );
223+
224+ // Expected participants per session is declared in config under 'participants'
225+ Map <String , Object > tc = testcases .get (idx );
226+ List <String > participantsList = (List <String >) tc .get ("participants" );
227+ // We only support single-entry participants in the test config for this
228+ // assertion
229+ String participantsSpec = participantsList .get (0 );
230+
231+ // Compute expected per-session participants: sum parts if "a:b" or single
232+ // integer
233+ int expectedPerSession = 0 ;
234+ if (participantsSpec .contains (":" )) {
235+ String [] parts = participantsSpec .split (":" );
236+ for (String p : parts ) {
237+ expectedPerSession += Integer .parseInt (p .trim ());
238+ }
239+ } else {
240+ expectedPerSession = Integer .parseInt (participantsSpec .trim ());
241+ }
242+
243+ String [] sessionsParts = sessionsCell .split ("/" );
244+ int sessionsCreated = Integer .parseInt (sessionsParts [0 ].trim ());
245+ int expectedTotalParticipants = expectedPerSession * sessionsCreated ;
246+
247+ // Apply capacity cap if distribution.usersPerWorker is configured
248+ int workersUsed = Integer .parseInt (workersCell .trim ());
249+ if (usersPerWorkerFromCfg > 0 && workersUsed > 0 ) {
250+ expectedTotalParticipants = Math .min (expectedTotalParticipants ,
251+ usersPerWorkerFromCfg * workersUsed );
252+ }
253+
254+ try {
255+ int actualTotal = Integer .parseInt (participantsCell .trim ());
256+ assertEquals (expectedTotalParticipants , actualTotal ,
257+ "Total participants for test case does not match expected for: " + label );
258+
259+ // Additional explicit checks requested:
260+ if (idx < explicitExpected .length ) {
261+ assertEquals (explicitExpected [idx ], actualTotal ,
262+ "Explicit total participants expected for test case does not match: " + label );
263+ }
264+
265+ // Assert stop reason is exactly "Test finished"
266+ assertEquals ("Test finished" , stopReasonCell ,
267+ "Stop reason should be 'Test finished' for test case: " + label );
268+ } catch (NumberFormatException nfe ) {
269+ fail ("Participants cell is not a number for test case: " + label + " value: "
270+ + participantsCell );
271+ }
272+ idx ++;
273+ }
189274 }
190275 }
191276
@@ -198,4 +283,4 @@ private void validateMultiTestCaseHtmlReport(Path htmlReport) throws IOException
198283 }
199284 assertTrue (hasOverviewActive , "Overview tab should be active by default" );
200285 }
201- }
286+ }
0 commit comments