gnodet-bot commented on code in PR #2153:
URL: https://github.com/apache/maven-resolver/pull/2153#discussion_r4071726157
##########
maven-resolver-util/src/test/java/org/eclipse/aether/util/graph/transformer/ConflictResolverTest.java:
##########
@@ -879,6 +879,88 @@ private static DependencyNode makeDependencyNode(
return node;
}
+ /**
+ * Regression test for exponential Path creation (OOM) in dense dependency
graphs.
+ * <p>
+ * Constructs a 3-level graph where hub nodes (which have their own shared
children)
+ * are each reachable via M distinct parent paths:
+ * <pre>
+ * root → p0, p1, … p(M-1) (M parent modules)
+ * each pi → hub0, hub1, … hub(N-1) (N shared hub nodes, with
children)
+ * each hub → sub0, sub1, … sub(K-1) (K shared sub-hub leaf nodes)
+ * </pre>
+ * Without the {@code expandedNodes} guard in {@link
PathConflictResolver#gatherCRNodes},
+ * each hub node would be pushed onto the expansion stack M times (once
per parent),
+ * causing its K sub-hubs to be expanded M times each — M×N×K stack
entries instead of N+K.
+ * With M=N=K=20 that is 20×20×20=8,000 redundant expansions for sub-hubs
alone, and
+ * grows polynomially with more levels. The guard prevents this by
skipping re-expansion
+ * of a node already expanded at the same or shallower depth.
+ */
+ @ParameterizedTest
+ @MethodSource("conflictResolverSource")
+ void denseGraphDoesNotOom(ConflictResolver conflictResolver) throws
RepositoryException {
Review Comment:
⚠️ **Test parameters too small to detect OOM regression**
The 3-level topology is now correct — hubs have children, so the
`expandedNodes` guard is actually exercised. But with `M=N=K=20`, the
pathological case without the guard produces at most `M×N = 400` hub-expansion
stack entries and `M×N×K = 8,000` sub-hub entries. That's trivially fast and
uses negligible memory. If someone removes the `expandedNodes` guard tomorrow,
this test still passes — it only validates correctness (all nodes survive), not
the memory bound.
To make this a genuine regression guard, either bump the parameters so the
un-fixed path is slow/OOM on CI heap, or assert on a proxy for expansion count
(e.g. a counter injected into `gatherCRNodes`, or a `@Timeout` that would
expire on the pathological case). A practical approach:
```suggestion
int M = 50; // parent modules
int N = 50; // hub modules (shared, each with children)
int K = 50; // sub-hub leaf modules (shared across hubs)
```
With `M=N=K=50`, without the fix: `50×50 = 2,500` hub expansions and
`50×50×50 = 125,000` sub-hub stack entries — still not an OOM, but slow enough
that adding a `@Timeout(value = 5, unit = TimeUnit.SECONDS)` would fail
reliably. Alternatively, use a counter that asserts the fix's O(N+K) expansion
bound:
```java
// Assert expansion is bounded — without the fix this would be M*N*K
assertTrue(expandedNodes.size() <= N + K, "expandedNodes grew beyond
O(N+K)");
```
(The `expandedNodes` field is `private` so this requires either
package-private test access or a subclass hook — but the intent is clear.)
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: [email protected]
For queries about this service, please contact Infrastructure at:
[email protected]