mirror of https://github.com/OpenVidu/openvidu.git
openvidu-test-e2e: do not use a shared cache between test runs for server SDK apps
parent
cf1512c108
commit
7b8b072005
|
|
@ -16,6 +16,7 @@ import java.nio.file.Paths;
|
|||
import java.time.Duration;
|
||||
import java.security.KeyManagementException;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.HashMap;
|
||||
import java.util.Iterator;
|
||||
|
|
@ -43,6 +44,9 @@ import org.testcontainers.containers.wait.strategy.Wait;
|
|||
import org.testcontainers.containers.wait.strategy.WaitStrategy;
|
||||
import org.testcontainers.utility.DockerImageName;
|
||||
|
||||
import com.github.dockerjava.api.model.Mount;
|
||||
import com.github.dockerjava.api.model.MountType;
|
||||
|
||||
import io.livekit.server.AccessToken;
|
||||
import io.livekit.server.CanPublish;
|
||||
import io.livekit.server.IngressServiceClient;
|
||||
|
|
@ -470,6 +474,34 @@ public class OpenViduTestE2e {
|
|||
startServerSdkPublisher(sdk, roomName, codec, 1);
|
||||
}
|
||||
|
||||
// Dependency cache volumes of the server SDK publishers, one per SDK, created
|
||||
// on first use and alive only for this JVM.
|
||||
private static final Map<String, String> SDK_CACHE_VOLUMES = new ConcurrentHashMap<>();
|
||||
|
||||
/**
|
||||
* Name of the dependency cache volume of the given SDK for this JVM, creating
|
||||
* it on first use. The volume carries the Testcontainers session labels, so
|
||||
* Ryuk removes it when the JVM ends, the same way it removes the containers;
|
||||
* a shutdown hook removes it too for the runs that disable Ryuk.
|
||||
*/
|
||||
private static String sdkCacheVolume(String sdk) {
|
||||
return SDK_CACHE_VOLUMES.computeIfAbsent(sdk, s -> {
|
||||
String name = "openvidu-e2e-sdk-cache-" + s + "-" + DockerClientFactory.SESSION_ID;
|
||||
Map<String, String> labels = new HashMap<>(DockerClientFactory.DEFAULT_LABELS);
|
||||
labels.put(DockerClientFactory.TESTCONTAINERS_SESSION_ID_LABEL, DockerClientFactory.SESSION_ID);
|
||||
DockerClientFactory.instance().client().createVolumeCmd().withName(name).withLabels(labels).exec();
|
||||
Runtime.getRuntime().addShutdownHook(new Thread(() -> {
|
||||
try {
|
||||
DockerClientFactory.instance().client().removeVolumeCmd(name).exec();
|
||||
} catch (Exception e) {
|
||||
// Already removed by Ryuk, or still used by a container Ryuk is
|
||||
// about to remove together with the volume
|
||||
}
|
||||
}));
|
||||
return name;
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Starts a LiveKit server RTC SDK participant (a minimal program at
|
||||
* src/test/resources/<sdk>-publisher) in a plain runtime container
|
||||
|
|
@ -478,8 +510,11 @@ public class OpenViduTestE2e {
|
|||
* simulcast for VP8/H264 and without SVC (scalabilityMode L1T1) for VP9/AV1.
|
||||
*
|
||||
* The container mounts the program read-only at /app, copies it to /work and
|
||||
* runs it there, with a per-SDK dependency cache mounted at /cache so
|
||||
* repeated runs skip downloads. Returns once the program logs
|
||||
* runs it there. /cache is a Docker volume that exists only for the current
|
||||
* test JVM (see {@link #sdkCacheVolume}): nothing of a previous run or of
|
||||
* another job on the same machine reaches the program, while the publishers
|
||||
* of one SDK still share their downloads (and the rust build, which takes up
|
||||
* to 30 minutes from cold) within the run. Returns once the program logs
|
||||
* TRACK_PUBLISHED. The container is stopped automatically on test dispose.
|
||||
*/
|
||||
public void startServerSdkPublisher(String sdk, String roomName, String codec, int layers) throws Exception {
|
||||
|
|
@ -542,14 +577,21 @@ public class OpenViduTestE2e {
|
|||
env.put("VIDEO_LAYERS", String.valueOf(layers));
|
||||
|
||||
String programDir = Paths.get("src/test/resources/" + sdk + "-publisher").toAbsolutePath().toString();
|
||||
Path cacheDir = Paths.get(System.getProperty("java.io.tmpdir"), "openvidu-e2e-sdk-cache", sdk);
|
||||
Files.createDirectories(cacheDir);
|
||||
String cacheVolume = sdkCacheVolume(sdk);
|
||||
|
||||
GenericContainer<?> publisherContainer = new GenericContainer<>(DockerImageName.parse(image))
|
||||
.withCreateContainerCmdModifier(
|
||||
cmd -> cmd.withName(sdk + "-publisher-" + (int) (Math.random() * 100000)))
|
||||
.withNetworkMode("host").withFileSystemBind(programDir, "/app", BindMode.READ_ONLY)
|
||||
.withFileSystemBind(cacheDir.toString(), "/cache").withEnv(env)
|
||||
// Not withFileSystemBind: it resolves its first argument as a host path
|
||||
.withCreateContainerCmdModifier(cmd -> {
|
||||
List<Mount> mounts = new ArrayList<>();
|
||||
if (cmd.getHostConfig().getMounts() != null) {
|
||||
mounts.addAll(cmd.getHostConfig().getMounts());
|
||||
}
|
||||
mounts.add(new Mount().withType(MountType.VOLUME).withSource(cacheVolume).withTarget("/cache"));
|
||||
cmd.getHostConfig().withMounts(mounts);
|
||||
})
|
||||
.withNetworkMode("host").withFileSystemBind(programDir, "/app", BindMode.READ_ONLY).withEnv(env)
|
||||
.withCommand("sh", "-c", "mkdir -p /work && cp -r /app/. /work && cd /work && " + runCommand)
|
||||
.withLogConsumer(
|
||||
frame -> log.info("[{}-publisher] {}", sdk, frame.getUtf8String().stripTrailing()))
|
||||
|
|
|
|||
|
|
@ -12,9 +12,14 @@ Minimal LiveKit server RTC SDK publisher programs used by
|
|||
| `dotnet-publisher/` | `Livekit.Rtc.Dotnet` | synthetic frames (FFI) |
|
||||
|
||||
Each program is launched by `OpenViduTestE2e#startServerSdkPublisher` inside a
|
||||
plain runtime container of its language (see that method for the images, run
|
||||
commands and per-SDK dependency caches). The directory is mounted read-only at
|
||||
`/app`, copied to `/work` and run there. The program must print the exact line
|
||||
plain runtime container of its language (see that method for the images and run
|
||||
commands). The directory is mounted read-only at `/app`, copied to `/work` and
|
||||
run there. The dependency cache at `/cache` is a Docker volume that lives only
|
||||
for the test JVM that created it (one per SDK, removed with the containers when
|
||||
the JVM ends), so a run never sees the downloads, builds or caches of a previous
|
||||
run or of another job on the same machine; within a run the publishers of an SDK
|
||||
share it, which keeps the Rust publisher's libwebrtc build to one per run. The
|
||||
program must print the exact line
|
||||
`TRACK_PUBLISHED` once the track is published: the Java test waits for it before
|
||||
asserting, and stops the container when the test ends, so the programs never
|
||||
exit on their own.
|
||||
|
|
|
|||
Loading…
Reference in New Issue