Skip to content

Commit 6e402ee

Browse files
committed
Adjust
1 parent 6e51548 commit 6e402ee

1 file changed

Lines changed: 36 additions & 15 deletions

File tree

httpcore5/src/test/java/org/apache/hc/core5/pool/ConnPoolContractFuzzer.java

Lines changed: 36 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -40,8 +40,6 @@
4040
import java.util.concurrent.CancellationException;
4141
import java.util.concurrent.ExecutionException;
4242
import java.util.concurrent.Future;
43-
import java.util.concurrent.TimeUnit;
44-
import java.util.concurrent.TimeoutException;
4543

4644
import org.apache.hc.core5.io.CloseMode;
4745
import org.apache.hc.core5.util.TimeValue;
@@ -50,6 +48,7 @@
5048
final class ConnPoolContractFuzzer {
5149

5250
private static final Timeout REQUEST_TIMEOUT = Timeout.ofSeconds(30);
51+
private static final Timeout NO_WAIT = Timeout.ofMilliseconds(0);
5352
private static final TimeValue IDLE_TIME = TimeValue.ofMilliseconds(1);
5453

5554
private ConnPoolContractFuzzer() {
@@ -113,9 +112,10 @@ static void run(
113112
case 1:
114113
case 2: {
115114
final String route = routes.get(rnd.nextInt(routes.size()));
116-
final Object state = (rnd.nextInt(4) == 0) ? null : rnd.nextInt(3);
115+
final Object state = (rnd.nextInt(4) == 0) ? null : Integer.valueOf(rnd.nextInt(3));
117116
trace.add(step + ": lease(" + route + ", state=" + state + ")");
118-
final Future<PoolEntry<String, PoolTestSupport.DummyConn>> f = pool.lease(route, state, REQUEST_TIMEOUT, null);
117+
final Future<PoolEntry<String, PoolTestSupport.DummyConn>> f =
118+
pool.lease(route, state, REQUEST_TIMEOUT, null);
119119
pending.add(new PendingLease(state, f));
120120
break;
121121
}
@@ -199,6 +199,9 @@ static void run(
199199
}
200200
}
201201

202+
// Drain again so invariants observe the same state we model.
203+
drainDoneFutures(pending, leased, leasedSet);
204+
202205
assertCoreInvariants(pool);
203206

204207
if (poolType != PoolTestSupport.PoolType.LAX) {
@@ -212,6 +215,7 @@ static void run(
212215

213216
} catch (final AssertionError ex) {
214217
fail("Pool=" + poolType + " seed=" + seed
218+
+ "\nAssertion: " + ex.getMessage()
215219
+ "\nRepro: -Dhc.pool.fuzz.seed=" + seed
216220
+ "\nTrace(last 80):\n" + tail(trace, 80), ex);
217221
} finally {
@@ -250,33 +254,49 @@ private static void drainDoneFutures(
250254
}
251255
}
252256

257+
/**
258+
* Fast, deterministic activity trigger. No waiting.
259+
*/
253260
private static void nudge(
254261
final ManagedConnPool<String, PoolTestSupport.DummyConn> pool,
255262
final List<String> routes) {
256263

264+
if (pool instanceof StrictConnPool) {
265+
((StrictConnPool<?, ?>) pool).validatePendingRequests();
266+
return;
267+
}
268+
if (pool instanceof LaxConnPool) {
269+
((LaxConnPool<?, ?>) pool).validatePendingRequests();
270+
return;
271+
}
272+
273+
// OFFLOCK: avoid waiting and avoid enqueuing if saturated.
257274
for (final String route : routes) {
258-
final Future<PoolEntry<String, PoolTestSupport.DummyConn>> f =
259-
pool.lease(route, null, Timeout.ofMilliseconds(200), null);
275+
final PoolStats rs = pool.getStats(route);
276+
final int max = pool.getMaxPerRoute(route);
277+
if (max > 0 && rs.getLeased() + rs.getAvailable() >= max) {
278+
continue;
279+
}
280+
281+
final Future<PoolEntry<String, PoolTestSupport.DummyConn>> f = pool.lease(route, null, NO_WAIT, null);
282+
if (!f.isDone()) {
283+
f.cancel(true);
284+
continue;
285+
}
260286
try {
261-
final PoolEntry<String, PoolTestSupport.DummyConn> entry = f.get(200, TimeUnit.MILLISECONDS);
287+
final PoolEntry<String, PoolTestSupport.DummyConn> entry = f.get();
262288
if (entry != null) {
263289
if (!entry.hasConnection()) {
264290
entry.assignConnection(new PoolTestSupport.DummyConn());
265291
}
266292
pool.release(entry, true);
267293
}
268-
} catch (final TimeoutException ex) {
269-
f.cancel(true);
270294
} catch (final Exception ignore) {
271295
// ignore
272296
}
273297
}
274298
}
275299

276-
/**
277-
* Adjustment: cleanup must not drop futures that completed concurrently, otherwise we
278-
* can leave a successfully leased entry unreleased and report a false “leak”.
279-
*/
280300
private static void cleanupAndAssertQuiescent(
281301
final PoolTestSupport.PoolType poolType,
282302
final ManagedConnPool<String, PoolTestSupport.DummyConn> pool,
@@ -298,7 +318,6 @@ private static void cleanupAndAssertQuiescent(
298318
pool.release(e, true);
299319
}
300320

301-
// Drain any done futures we didn’t observe via drainDoneFutures (race window).
302321
for (final Iterator<PendingLease> it = pending.iterator(); it.hasNext(); ) {
303322
final PendingLease p = it.next();
304323
if (!p.future.isDone()) {
@@ -320,7 +339,6 @@ private static void cleanupAndAssertQuiescent(
320339
}
321340
}
322341

323-
// Encourage flushing of cancelled waiters without using impl-specific APIs.
324342
nudge(pool, routes);
325343
pool.closeExpired();
326344
pool.closeIdle(IDLE_TIME);
@@ -344,12 +362,15 @@ private static void cleanupAndAssertQuiescent(
344362
}
345363

346364
private static void assertCoreInvariants(final ManagedConnPool<String, PoolTestSupport.DummyConn> pool) {
365+
assertTrue(pool.getMaxTotal() >= 0, "maxTotal negative");
366+
347367
final PoolStats total = pool.getTotalStats();
348368
assertTrue(total.getLeased() >= 0, "total.leased");
349369
assertTrue(total.getPending() >= 0, "total.pending");
350370
assertTrue(total.getAvailable() >= 0, "total.available");
351371

352372
for (final String route : pool.getRoutes()) {
373+
assertTrue(pool.getMaxPerRoute(route) >= 0, "maxPerRoute negative");
353374
final PoolStats rs = pool.getStats(route);
354375
assertTrue(rs.getLeased() >= 0, "route.leased");
355376
assertTrue(rs.getPending() >= 0, "route.pending");

0 commit comments

Comments
 (0)