This is an automated email from the ASF dual-hosted git repository.

jamesbognar pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/juneau.git


The following commit(s) were added to refs/heads/master by this push:
     new 9ba5512204 Fix heap-dump test OOM by not buffering a full JVM dump 
through MockRestClient
9ba5512204 is described below

commit 9ba55122046f02a4b59220fd803d3b859b66d9e2
Author: James Bognar <[email protected]>
AuthorDate: Thu Jun 18 14:10:25 2026 -0400

    Fix heap-dump test OOM by not buffering a full JVM dump through 
MockRestClient
---
 .../juneau/rest/server/management/Dumps_Test.java  | 52 ++++++++++++++++++----
 .../juneau/rest/server/management/DumpsMixin.java  | 19 +++++++-
 .../rest/server/management/DumpsResource.java      | 19 +++++++-
 3 files changed, 80 insertions(+), 10 deletions(-)

diff --git 
a/juneau-integration-tests/src/test/java/org/apache/juneau/rest/server/management/Dumps_Test.java
 
b/juneau-integration-tests/src/test/java/org/apache/juneau/rest/server/management/Dumps_Test.java
index feb2d64765..0a49655924 100644
--- 
a/juneau-integration-tests/src/test/java/org/apache/juneau/rest/server/management/Dumps_Test.java
+++ 
b/juneau-integration-tests/src/test/java/org/apache/juneau/rest/server/management/Dumps_Test.java
@@ -112,10 +112,33 @@ class Dumps_Test extends TestBase {
                
c.get("/threaddump").run().assertStatus(200).assertContent().asString().isNotEmpty();
        }
 
-       @Test void c02_heapDumpEnabled() throws Exception {
-               var c = MockRestClient.buildLax(B.class);
-               var bytes = 
c.get("/heapdump").run().assertStatus(200).getContent().asBytes();
-               assertTrue(bytes.length > 0, "Heap dump body should be 
non-empty");
+       // The enabled-path heap-dump handler body (resolve stream -> set 
headers -> stream it back) is covered with a
+       // FAKE DumpsManager that returns a tiny in-memory stream instead of a 
real JVM heap dump.  We must NOT drive a
+       // REAL enabled /heapdump through MockRestClient: MockServletResponse 
buffers the whole response in memory, so a
+       // full JVM heap dump would OOM the constrained CI fork.  (Real 
dumpHeap content is covered by worker test a03.)
+
+       /** A DumpsManager that enables heap dumps and returns a tiny fixed 
stream — no real (huge) JVM dump. */
+       public static class FakeHeapDumpManager extends DumpsManager {
+               @Override public DumpsSettings resolveSettings(RestContext 
context) {
+                       return DumpsSettings.create().enableHeapDump().build();
+               }
+               @Override public InputStream heapDumpStream(boolean live) {
+                       return new ByteArrayInputStream("JAVA PROFILE 
1.0.2\0".getBytes());
+               }
+       }
+
+       @Rest(mixins={DumpsMixin.class})
+       public static class HF extends BasicRestServlet {
+               private static final long serialVersionUID = 1L;
+               @Bean public DumpsManager dumpsManager() { return new 
FakeHeapDumpManager(); }
+       }
+
+       @Test void c03_heapDumpEnabled_handlerBody_fakeManager() throws 
Exception {
+               var c = MockRestClient.buildLax(HF.class);
+               var body = c.get("/heapdump").run().assertStatus(200)
+                       
.assertHeader("Content-Type").is("application/octet-stream")
+                       .getContent().asString();
+               assertTrue(body.startsWith("JAVA PROFILE"), "Fake heap-dump 
stream should be returned verbatim");
        }
 
        // 
=================================================================================
@@ -141,10 +164,23 @@ class Dumps_Test extends TestBase {
                
c.get("/dumps/threaddump").run().assertStatus(200).assertContent().asString().isNotEmpty();
        }
 
-       @Test void d02_resourceHeapDumpEnabled() throws Exception {
-               var c = MockRestClient.buildLax(D.class);
-               var bytes = 
c.get("/dumps/heapdump").run().assertStatus(200).getContent().asBytes();
-               assertTrue(bytes.length > 0, "Heap dump body should be 
non-empty");
+       // Resource-flavor enabled heap-dump handler body via the fake manager 
(no real JVM dump — see the mixin note).
+       @Rest(path="/dumps")
+       public static class FakeHeapChild extends DumpsResource {
+               @Bean public DumpsManager dumpsManager() { return new 
FakeHeapDumpManager(); }
+       }
+
+       @Rest(children={FakeHeapChild.class})
+       public static class DF extends BasicRestServlet {
+               private static final long serialVersionUID = 1L;
+       }
+
+       @Test void d02_resourceHeapDumpEnabled_handlerBody_fakeManager() throws 
Exception {
+               var c = MockRestClient.buildLax(DF.class);
+               var body = c.get("/dumps/heapdump").run().assertStatus(200)
+                       
.assertHeader("Content-Type").is("application/octet-stream")
+                       .getContent().asString();
+               assertTrue(body.startsWith("JAVA PROFILE"), "Fake heap-dump 
stream should be returned verbatim");
        }
 
        // A child with no DumpsSettings bean -> deny-by-default on both ops.
diff --git 
a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/server/management/DumpsMixin.java
 
b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/server/management/DumpsMixin.java
index 5446627339..4353f45a08 100644
--- 
a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/server/management/DumpsMixin.java
+++ 
b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/server/management/DumpsMixin.java
@@ -45,7 +45,22 @@ import org.apache.juneau.rest.server.servlet.*;
 @Rest
 public class DumpsMixin extends RestMixin {
 
-       private final DumpsManager manager = new DumpsManager();
+       private final DumpsManager defaultManager = new DumpsManager();
+
+       /**
+        * Returns the {@link DumpsManager} worker, resolved from the host bean 
store when a consumer registers one,
+        * else a built-in default.  Resolving through the bean store lets 
consumers (and tests) supply an alternate
+        * worker without subclassing.
+        *
+        * @param req The HTTP request (its context's bean store is searched).
+        * @return The resolved manager; never <jk>null</jk>.
+        */
+       @SuppressWarnings({
+               "resource" // The bean store is owned by the RestContext; this 
only borrows a bean and must not close it.
+       })
+       protected DumpsManager manager(RestRequest req) {
+               return 
req.getContext().getBeanStore().getBean(DumpsManager.class).orElse(defaultManager);
+       }
 
        /**
         * [GET /threaddump] - Full thread dump from the {@link 
java.lang.management.ThreadMXBean ThreadMXBean}.
@@ -63,6 +78,7 @@ public class DumpsMixin extends RestMixin {
                description="Renders a full thread dump from the JVM 
ThreadMXBean.  Disabled by default; opt in via DumpsSettings."
        )
        public String getThreadDump(RestRequest req) {
+               var manager = manager(req);
                if (! 
manager.resolveSettings(req.getContext()).isThreadDumpEnabled())
                        throw new Forbidden("The /threaddump endpoint is 
disabled.  Register a DumpsSettings bean with threadDump enabled to use it.");
                return manager.threadDump();
@@ -91,6 +107,7 @@ public class DumpsMixin extends RestMixin {
                "resource" // The returned stream is handed off to the 
framework's InputStreamProcessor, which pipes then closes it (and the backing 
temp file self-deletes on close).
        })
        public InputStream getHeapDump(RestRequest req, RestResponse res) 
throws IOException {
+               var manager = manager(req);
                if (! 
manager.resolveSettings(req.getContext()).isHeapDumpEnabled())
                        throw new Forbidden("The /heapdump endpoint is 
disabled.  Register a DumpsSettings bean with heapDump enabled to use it.");
                var stream = manager.heapDumpStream(true);
diff --git 
a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/server/management/DumpsResource.java
 
b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/server/management/DumpsResource.java
index c9b26c6aa5..0da9039996 100644
--- 
a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/server/management/DumpsResource.java
+++ 
b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/server/management/DumpsResource.java
@@ -46,7 +46,22 @@ import org.apache.juneau.rest.server.servlet.*;
 @Rest(path="/dumps")
 public class DumpsResource extends BasicRestResource {
 
-       private final DumpsManager manager = new DumpsManager();
+       private final DumpsManager defaultManager = new DumpsManager();
+
+       /**
+        * Returns the {@link DumpsManager} worker, resolved from the bean 
store when a consumer registers one, else a
+        * built-in default.  Resolving through the bean store lets consumers 
(and tests) supply an alternate worker
+        * without subclassing.
+        *
+        * @param req The HTTP request (its context's bean store is searched).
+        * @return The resolved manager; never <jk>null</jk>.
+        */
+       @SuppressWarnings({
+               "resource" // The bean store is owned by the RestContext; this 
only borrows a bean and must not close it.
+       })
+       protected DumpsManager manager(RestRequest req) {
+               return 
req.getContext().getBeanStore().getBean(DumpsManager.class).orElse(defaultManager);
+       }
 
        /**
         * [GET /threaddump] - Full thread dump from the {@link 
java.lang.management.ThreadMXBean ThreadMXBean}.
@@ -61,6 +76,7 @@ public class DumpsResource extends BasicRestResource {
                description="Renders a full thread dump from the JVM 
ThreadMXBean.  Disabled by default; opt in via DumpsSettings."
        )
        public String getThreadDump(RestRequest req) {
+               var manager = manager(req);
                if (! 
manager.resolveSettings(req.getContext()).isThreadDumpEnabled())
                        throw new Forbidden("The /threaddump endpoint is 
disabled.  Register a DumpsSettings bean with threadDump enabled to use it.");
                return manager.threadDump();
@@ -85,6 +101,7 @@ public class DumpsResource extends BasicRestResource {
                "resource" // The returned stream is handed off to the 
framework's InputStreamProcessor, which pipes then closes it (and the backing 
temp file self-deletes on close).
        })
        public InputStream getHeapDump(RestRequest req, RestResponse res) 
throws IOException {
+               var manager = manager(req);
                if (! 
manager.resolveSettings(req.getContext()).isHeapDumpEnabled())
                        throw new Forbidden("The /heapdump endpoint is 
disabled.  Register a DumpsSettings bean with heapDump enabled to use it.");
                var stream = manager.heapDumpStream(true);

Reply via email to