mirror of
https://github.com/openjdk/jdk.git
synced 2026-01-28 12:09:14 +00:00
8370966: Create regression test for the hierarchical memory limit fix in JDK-8370572
Reviewed-by: shade, syan
This commit is contained in:
parent
76a1109d6f
commit
291003208c
@ -77,7 +77,7 @@ public class TestJFRWithJMX {
|
||||
throw new SkippedException("Docker is not supported on this host");
|
||||
}
|
||||
|
||||
if (isPodman() & !Platform.isRoot()) {
|
||||
if (DockerTestUtils.isPodman() & !Platform.isRoot()) {
|
||||
throw new SkippedException("test cannot be run under rootless podman configuration");
|
||||
}
|
||||
|
||||
@ -222,10 +222,4 @@ public class TestJFRWithJMX {
|
||||
}
|
||||
}
|
||||
|
||||
static boolean isPodman() {
|
||||
String[] parts = Container.ENGINE_COMMAND
|
||||
.toLowerCase()
|
||||
.split(File.pathSeparator);
|
||||
return "podman".equals(parts[parts.length - 1]);
|
||||
}
|
||||
}
|
||||
|
||||
@ -57,7 +57,7 @@ public class TestJcmd {
|
||||
private static final String IMAGE_NAME = Common.imageName("jcmd");
|
||||
private static final int TIME_TO_RUN_CONTAINER_PROCESS = (int) (10 * Utils.TIMEOUT_FACTOR); // seconds
|
||||
private static final String CONTAINER_NAME = "test-container";
|
||||
private static final boolean IS_PODMAN = Container.ENGINE_COMMAND.contains("podman");
|
||||
private static final boolean IS_PODMAN = DockerTestUtils.isPodman();
|
||||
private static final String ROOT_UID = "0";
|
||||
|
||||
|
||||
|
||||
@ -0,0 +1,117 @@
|
||||
/*
|
||||
* Copyright (C) 2025, IBM Corporation. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
import jdk.test.lib.Container;
|
||||
import jdk.test.lib.containers.docker.Common;
|
||||
import jdk.test.lib.containers.docker.DockerTestUtils;
|
||||
import jdk.test.lib.containers.docker.ContainerRuntimeVersionTestUtils;
|
||||
import jdk.test.lib.containers.docker.DockerRunOptions;
|
||||
import jdk.test.lib.process.OutputAnalyzer;
|
||||
import jdk.internal.platform.Metrics;
|
||||
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.Files;
|
||||
import java.util.ArrayList;
|
||||
|
||||
import jtreg.SkippedException;
|
||||
|
||||
/*
|
||||
* @test
|
||||
* @bug 8370966
|
||||
* @requires os.family == "linux"
|
||||
* @requires !vm.asan
|
||||
* @modules java.base/jdk.internal.platform
|
||||
* @library /test/lib
|
||||
* @run main TestMemoryInvisibleParent
|
||||
*/
|
||||
public class TestMemoryInvisibleParent {
|
||||
private static final String UNLIMITED = "-1";
|
||||
private static final String imageName = Common.imageName("invisible-parent");
|
||||
|
||||
public static void main(String[] args) throws Exception {
|
||||
Metrics metrics = Metrics.systemMetrics();
|
||||
if (metrics == null) {
|
||||
System.out.println("Cgroup not configured.");
|
||||
return;
|
||||
}
|
||||
if (!DockerTestUtils.canTestDocker()) {
|
||||
System.out.println("Unable to run docker tests.");
|
||||
return;
|
||||
}
|
||||
|
||||
ContainerRuntimeVersionTestUtils.checkContainerVersionSupported();
|
||||
|
||||
if (DockerTestUtils.isRootless()) {
|
||||
throw new SkippedException("Test skipped in rootless mode");
|
||||
}
|
||||
DockerTestUtils.buildJdkContainerImage(imageName);
|
||||
|
||||
if ("cgroupv1".equals(metrics.getProvider())) {
|
||||
try {
|
||||
testMemoryLimitHiddenParent("104857600", "104857600");
|
||||
testMemoryLimitHiddenParent("209715200", "209715200");
|
||||
} finally {
|
||||
DockerTestUtils.removeDockerImage(imageName);
|
||||
}
|
||||
} else {
|
||||
throw new SkippedException("cgroup v1 - only test! This is " + metrics.getProvider());
|
||||
}
|
||||
}
|
||||
|
||||
private static void testMemoryLimitHiddenParent(String valueToSet, String expectedValue)
|
||||
throws Exception {
|
||||
|
||||
Common.logNewTestCase("Cgroup V1 hidden parent memory limit: " + valueToSet);
|
||||
|
||||
try {
|
||||
String cgroupParent = setParentWithLimit(valueToSet);
|
||||
DockerRunOptions opts = new DockerRunOptions(imageName, "/jdk/bin/java", "-version", "-Xlog:os+container=trace");
|
||||
opts.appendTestJavaOptions = false;
|
||||
if (DockerTestUtils.isPodman()) {
|
||||
// Podman needs to run this test with engine option --cgroup-manager=cgroupfs
|
||||
opts.addEngineOpts("--cgroup-manager", "cgroupfs");
|
||||
}
|
||||
opts.addDockerOpts("--cgroup-parent=/" + cgroupParent);
|
||||
Common.run(opts)
|
||||
.shouldContain("Hierarchical Memory Limit is: " + expectedValue);
|
||||
} finally {
|
||||
// Reset the parent memory limit to unlimited (-1)
|
||||
setParentWithLimit(UNLIMITED);
|
||||
}
|
||||
}
|
||||
|
||||
private static String setParentWithLimit(String memLimit) throws Exception {
|
||||
String cgroupParent = "hidden-parent-" + TestMemoryInvisibleParent.class.getSimpleName() + Runtime.version().feature();
|
||||
Path sysFsMemory = Path.of("/", "sys", "fs", "cgroup", "memory");
|
||||
Path cgroupParentPath = sysFsMemory.resolve(cgroupParent);
|
||||
ProcessBuilder pb = new ProcessBuilder("mkdir", "-p", cgroupParentPath.toString());
|
||||
OutputAnalyzer out = new OutputAnalyzer(pb.start())
|
||||
.shouldHaveExitValue(0);
|
||||
Path memoryLimitsFile = cgroupParentPath.resolve("memory.limit_in_bytes");
|
||||
Files.writeString(memoryLimitsFile, memLimit);
|
||||
System.out.println("Cgroup parent is: /" + cgroupParentPath.getFileName() +
|
||||
" at " + sysFsMemory.toString());
|
||||
return cgroupParent;
|
||||
}
|
||||
|
||||
}
|
||||
@ -46,19 +46,6 @@ import jtreg.SkippedException;
|
||||
public class TestMemoryWithSubgroups {
|
||||
private static final String imageName = Common.imageName("subgroup");
|
||||
|
||||
static String getEngineInfo(String format) throws Exception {
|
||||
return DockerTestUtils.execute(Container.ENGINE_COMMAND, "info", "-f", format)
|
||||
.getStdout();
|
||||
}
|
||||
|
||||
static boolean isRootless() throws Exception {
|
||||
// Docker and Podman have different INFO structures.
|
||||
// The node path for Podman is .Host.Security.Rootless, that also holds for
|
||||
// Podman emulating Docker CLI. The node path for Docker is .SecurityOptions.
|
||||
return (getEngineInfo("{{.Host.Security.Rootless}}").contains("true") ||
|
||||
getEngineInfo("{{.SecurityOptions}}").contains("name=rootless"));
|
||||
}
|
||||
|
||||
public static void main(String[] args) throws Exception {
|
||||
Metrics metrics = Metrics.systemMetrics();
|
||||
if (metrics == null) {
|
||||
@ -72,7 +59,7 @@ public class TestMemoryWithSubgroups {
|
||||
|
||||
ContainerRuntimeVersionTestUtils.checkContainerVersionSupported();
|
||||
|
||||
if (isRootless()) {
|
||||
if (DockerTestUtils.isRootless()) {
|
||||
throw new SkippedException("Test skipped in rootless mode");
|
||||
}
|
||||
Common.prepareWhiteBox();
|
||||
|
||||
@ -47,7 +47,7 @@ import jdk.test.lib.Utils;
|
||||
|
||||
public class TestPids {
|
||||
private static final String imageName = Common.imageName("pids");
|
||||
private static final boolean IS_PODMAN = Container.ENGINE_COMMAND.contains("podman");
|
||||
private static final boolean IS_PODMAN = DockerTestUtils.isPodman();
|
||||
private static final int UNLIMITED_PIDS_PODMAN = 0;
|
||||
private static final int UNLIMITED_PIDS_DOCKER = -1;
|
||||
|
||||
|
||||
@ -52,19 +52,6 @@ public class TestDockerMemoryMetricsSubgroup {
|
||||
DockerfileConfig.getBaseImageName() + ":" +
|
||||
DockerfileConfig.getBaseImageVersion();
|
||||
|
||||
static String getEngineInfo(String format) throws Exception {
|
||||
return DockerTestUtils.execute(Container.ENGINE_COMMAND, "info", "-f", format)
|
||||
.getStdout();
|
||||
}
|
||||
|
||||
static boolean isRootless() throws Exception {
|
||||
// Docker and Podman have different INFO structures.
|
||||
// The node path for Podman is .Host.Security.Rootless, that also holds for
|
||||
// Podman emulating Docker CLI. The node path for Docker is .SecurityOptions.
|
||||
return (getEngineInfo("{{.Host.Security.Rootless}}").contains("true") ||
|
||||
getEngineInfo("{{.SecurityOptions}}").contains("name=rootless"));
|
||||
}
|
||||
|
||||
public static void main(String[] args) throws Exception {
|
||||
Metrics metrics = Metrics.systemMetrics();
|
||||
if (metrics == null) {
|
||||
@ -78,7 +65,7 @@ public class TestDockerMemoryMetricsSubgroup {
|
||||
|
||||
ContainerRuntimeVersionTestUtils.checkContainerVersionSupported();
|
||||
|
||||
if (isRootless()) {
|
||||
if (DockerTestUtils.isRootless()) {
|
||||
throw new SkippedException("Test skipped in rootless mode");
|
||||
}
|
||||
|
||||
|
||||
@ -31,6 +31,7 @@ import java.util.Collections;
|
||||
// in test environment.
|
||||
public class DockerRunOptions {
|
||||
public String imageNameAndTag;
|
||||
public ArrayList<String> engineOpts = new ArrayList<>();
|
||||
public ArrayList<String> dockerOpts = new ArrayList<>();
|
||||
public String command; // normally a full path to java
|
||||
public ArrayList<String> javaOpts = new ArrayList<>();
|
||||
@ -70,6 +71,11 @@ public class DockerRunOptions {
|
||||
return this;
|
||||
}
|
||||
|
||||
public final DockerRunOptions addEngineOpts(String... opts) {
|
||||
Collections.addAll(engineOpts, opts);
|
||||
return this;
|
||||
}
|
||||
|
||||
public final DockerRunOptions addJavaOpts(String... opts) {
|
||||
Collections.addAll(javaOpts, opts);
|
||||
return this;
|
||||
|
||||
@ -83,6 +83,14 @@ public class DockerTestUtils {
|
||||
return isDockerEngineAvailable;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the actual engine command is podman.
|
||||
*
|
||||
* @return {@code true} if engine is podman. {@code false} otherwise.
|
||||
*/
|
||||
public static boolean isPodman() {
|
||||
return Container.ENGINE_COMMAND.contains("podman");
|
||||
}
|
||||
|
||||
/**
|
||||
* Convenience method, will check if docker engine is available and usable;
|
||||
@ -121,6 +129,26 @@ public class DockerTestUtils {
|
||||
return true;
|
||||
}
|
||||
|
||||
private static String getEngineInfo(String format) throws Exception {
|
||||
return execute(Container.ENGINE_COMMAND, "info", "-f", format).getStdout();
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine if the engine is running in root-less mode.
|
||||
*
|
||||
* @return {@code true} when running root-less (podman or docker). {@code false}
|
||||
* otherwise.
|
||||
*
|
||||
* @throws Exception
|
||||
*/
|
||||
public static boolean isRootless() throws Exception {
|
||||
// Docker and Podman have different INFO structures.
|
||||
// The node path for Podman is .Host.Security.Rootless, that also holds for
|
||||
// Podman emulating Docker CLI. The node path for Docker is .SecurityOptions.
|
||||
return (getEngineInfo("{{.Host.Security.Rootless}}").contains("true") ||
|
||||
getEngineInfo("{{.SecurityOptions}}").contains("name=rootless"));
|
||||
}
|
||||
|
||||
/**
|
||||
* Build a container image that contains JDK under test.
|
||||
* The jdk will be placed under the "/jdk/" folder inside the image/container file system.
|
||||
@ -202,6 +230,9 @@ public class DockerTestUtils {
|
||||
*/
|
||||
public static List<String> buildJavaCommand(DockerRunOptions opts) throws Exception {
|
||||
List<String> cmd = buildContainerCommand();
|
||||
if (!opts.engineOpts.isEmpty()) {
|
||||
cmd.addAll(opts.engineOpts);
|
||||
}
|
||||
cmd.add("run");
|
||||
if (opts.tty)
|
||||
cmd.add("--tty=true");
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user