openvidu-test-e2e: remove the bridged browsers' DNS dependency on the SFU host name for connectionQuality tests

master
pabloFuente 2026-09-17 13:42:37 +02:00
parent adfd19c8fa
commit ff7425c38e
3 changed files with 88 additions and 0 deletions

View File

@ -59,6 +59,10 @@ public class NetworkConditioner {
// blackoutOutbound().
private static String blackoutContainer;
// Both Pumba images are pinned to an immutable tag: pulling them once per JVM
// is enough. See pullImages().
private static final java.util.concurrent.atomic.AtomicBoolean imagesPulled = new java.util.concurrent.atomic.AtomicBoolean();
// Container Pumba is currently impairing. Tracked so that clear() can scrub its
// network namespace itself instead of trusting Pumba to have reverted.
private static String impairedContainer;
@ -80,7 +84,17 @@ public class NetworkConditioner {
UDP, TCP
}
/**
* Pulls the Pumba images, once per JVM. Both are pinned to an immutable tag, so
* re-pulling them before every connection-quality test only buys another chance
* of hitting a registry or DNS hiccup: seen in CI taking 171 s instead of the
* usual 3 s, in the middle of the network outage that then kept the bridged
* browser from connecting at all (run 35203642658).
*/
public static void pullImages() {
if (!imagesPulled.compareAndSet(false, true)) {
return;
}
log.info("Pulling Pumba images {} and {}", PUMBA_IMAGE, NETTOOLS_IMAGE);
commandLine.executeCommand("docker pull " + PUMBA_IMAGE, 180);
commandLine.executeCommand("docker pull " + NETTOOLS_IMAGE, 180);

View File

@ -4,10 +4,12 @@ import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.net.DatagramSocket;
import java.net.InetAddress;
import java.net.ServerSocket;
import java.net.URI;
import java.net.URISyntaxException;
import java.net.URL;
import java.net.UnknownHostException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
@ -142,6 +144,15 @@ public class OpenViduTestE2e {
protected Collection<Network> netemNetworks = ConcurrentHashMap.newKeySet();
private final AtomicInteger netemContainerCounter = new AtomicInteger();
// Host name pinned in /etc/hosts of the bridged ("chromeNetwork") browsers, and
// the address it resolved to. See pinHostForNetemBrowser.
private static String netemPinnedHostName;
private static String netemPinnedHostAddress;
// Resolved once per JVM, so that after the first success a later DNS outage
// cannot stop a bridged browser from being pinned.
private static final Map<String, String> resolvedHostAddresses = new ConcurrentHashMap<>();
protected static RoomServiceClient LK;
protected static IngressServiceClient LK_INGRESS;
@ -233,9 +244,67 @@ public class OpenViduTestE2e {
.withExtraHost("host.docker.internal", "host-gateway")
.withCreateContainerCmdModifier(cmd -> cmd.withName(containerName))
.waitingFor(waitBrowser);
if (netemPinnedHostName != null) {
log.info("Pinning {} to {} in the /etc/hosts of bridged browser {}", netemPinnedHostName,
netemPinnedHostAddress, containerName);
chrome.withExtraHost(netemPinnedHostName, netemPinnedHostAddress);
}
return chrome;
}
/**
* Pins the host of {@code url} to its current address in the /etc/hosts of
* every bridged ("chromeNetwork") browser created from now on, so that the
* browser never has to resolve it.
*
* Those browsers sit in their own Docker network and reach the SFU through the
* deployment's public wildcard name
* ({@code <ip-with-dashes>.openvidu-local.dev}, which the TLS certificate is
* issued for, so the name cannot simply be replaced by the address). Resolving
* it is a real DNS query, and it is the only thing in the connection-quality
* tests that depends on the runner having working external DNS at connect
* time: every other browser in the suite talks to localhost. When that DNS
* blinks, the browser never opens the signaling WebSocket and the test fails
* 50 s later waiting for "connected", with the connectivity dump reporting
* "bad address" for a name Docker's own resolver still had cached (CI run
* 35203642658, where a 3-minute outage also stretched a 3 s "docker pull" to
* 171 s).
*
* Best-effort: if the name cannot be resolved right now (and was not resolved
* earlier in this JVM), nothing is pinned and the browser resolves it itself,
* exactly as before.
*/
protected static void pinHostForNetemBrowser(String url) {
netemPinnedHostName = null;
netemPinnedHostAddress = null;
if (url == null || url.isBlank()) {
return;
}
String host;
try {
host = URI.create(url.trim()).getHost();
} catch (IllegalArgumentException e) {
log.warn("Not a URL, so nothing to pin for the bridged browsers: {}", url);
return;
}
if (host == null || host.isBlank()) {
return;
}
String address = resolvedHostAddresses.get(host);
if (address == null) {
try {
address = InetAddress.getByName(host).getHostAddress();
resolvedHostAddresses.put(host, address);
} catch (UnknownHostException e) {
log.warn("Could not resolve {} to pin it in the bridged browsers' /etc/hosts ({}). They will have to"
+ " resolve it through DNS themselves.", host, e.toString());
return;
}
}
netemPinnedHostName = host;
netemPinnedHostAddress = address;
}
protected String getNetemContainerName(BrowserUser browserUser) {
return this.netemContainerNames.get(browserUser);
}

View File

@ -946,6 +946,11 @@ public class OpenViduTestAppE2eTest extends AbstractOpenViduTestappE2eTest {
"Could not obtain the LiveKit wss:// URL from the 'ready-check' container log. Is openvidu-local-deployment running? ");
log.info("Using LiveKit URL: {}", secureLivekitUrlFromOpenViduLocalDeployment);
// Both browsers below are bridged into their own Docker network and reach the
// SFU through this public wildcard name: pin its address so that they never
// depend on the runner's DNS to open the signaling WebSocket
pinHostForNetemBrowser(secureLivekitUrlFromOpenViduLocalDeployment);
NetworkConditioner.pullImages();
// Connect to the openvidu-testapp through "host.docker.internal"