openvidu-test-e2e: add connectionQualityLostPublisherSubscriberNotLostTest

When a publisher's network dies, only that publisher should be reported
LOST. With the mediasoup engine every subscriber of its tracks was
reported LOST too, because the subscriber's quality is the minimum over
the tracks it publishes and subscribes to. Since livekit-client 2.22 a
participant that has been LOST for 10 s while publishing does a full
reconnect, so a healthy participant publishing in the same room would
reconnect because of someone else's outage.

No existing test covered this. connectionQualityLostPublisherTest only
checks the quality of the publisher whose network is cut. The ramp-up
test does check the subscriber's own quality, but by the time it blacks
out the publisher, mediasoup's frozen producer score is already
degraded, which hides the bug.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
pull/911/head
pabloFuente 2026-09-23 17:47:42 +02:00
parent d716ee15ec
commit ae08286d60
1 changed files with 41 additions and 0 deletions

View File

@ -1187,6 +1187,47 @@ public class OpenViduTestAppE2eTest extends AbstractOpenViduTestappE2eTest {
gracefullyLeaveParticipants(punchbagUser, 1); gracefullyLeaveParticipants(punchbagUser, 1);
} }
@Test
@DisplayName("ConnectionQuality LOST publisher does not make its subscriber LOST")
void connectionQualityLostPublisherSubscriberNotLostTest() throws Exception {
log.info("ConnectionQuality LOST publisher does not make its subscriber LOST");
// PunchbagUser publishes audio and video, RegularUser only subscribes to them
Pair<OpenViduTestappUser, OpenViduTestappUser> users = connectionQualityTest(true, false, null, null);
OpenViduTestappUser punchbagUser = users.getLeft();
OpenViduTestappUser regularUser = users.getRight();
// Cut the publisher's media uplink at once while its quality is EXCELLENT,
// keeping its signaling up: a sudden network outage on the publisher's side
NetworkConditioner.blackoutOutbound(getNetemContainerName(punchbagUser), "7900-7999", 120);
try {
waitUntilConnectionQuality(regularUser, 0, "PunchbagUser", q -> q.contains("lost"), 45,
"Expected the publisher's connection quality to reach LOST");
// Leave a couple more server quality ticks (every 5 s) to be reported
Thread.sleep(10000);
// RegularUser's own network is not impaired, so the publisher's outage must
// not be reported as LOST for RegularUser itself. Its instance lists its own
// ParticipantEvents ("lost") and the RoomEvents of every participant
// ("<identity> (lost)"), PunchbagUser's included: only RegularUser's count
List<String> qualities = new ArrayList<>();
for (WebElement el : getConnectionQualityEventContents(regularUser, 0, "RegularUser")) {
String text = el.getAttribute("textContent");
if (text != null) {
qualities.add(text.toLowerCase().trim());
}
}
Assertions.assertFalse(qualities.stream().anyMatch(q -> q.equals("lost") || q.equals("regularuser (lost)")),
"RegularUser only subscribes to the LOST publisher and its own network is not impaired, "
+ "so its own connection quality must never be LOST. Observed: " + qualities);
} finally {
NetworkConditioner.clear();
}
gracefullyLeaveParticipants(punchbagUser, 1);
}
@Test @Test
@DisplayName("ConnectionQuality POOR subscriber test") @DisplayName("ConnectionQuality POOR subscriber test")
void connectionQualityPoorSubscriberTest() throws Exception { void connectionQualityPoorSubscriberTest() throws Exception {