Skip to content

Commit 74fd263

Browse files
authored
Merge pull request #20889 from njr-11/18669-test-getContextService-from-executor-definitions
test getContextService from executor definitions
2 parents f7cdc28 + 79d3ba2 commit 74fd263

File tree

2 files changed

+180
-2
lines changed

2 files changed

+180
-2
lines changed

dev/com.ibm.ws.concurrent_fat_jakarta/test-applications/ConcurrencyTestWeb/src/test/jakarta/concurrency/web/ConcurrencyTestServlet.java

Lines changed: 130 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1149,14 +1149,143 @@ public void testForcedCompletionOfCopies() throws Exception {
11491149
assertTrue(copy6.isCancelled());
11501150
}
11511151

1152+
/**
1153+
* Verify that it is possible to obtain the nested ContextService of a ManagedExecutorService
1154+
* that is configured as a ManagedExecutorDefinition, and that when withContextCapture is invoked on this ContextService,
1155+
* the resulting CompletableFuture is backed by the ManagedExecutorService, subject to its concurrency
1156+
* constraints (maxAsync=1) and runs tasks under the context propagation settings of its nested ContextService.
1157+
*/
1158+
@Test
1159+
public void testGetContextServiceFromManagedExecutorDefinition() throws Exception {
1160+
Executor bean = InitialContext.doLookup("java:global/ConcurrencyTestApp/ConcurrencyTestEJB/ExecutorBean!java.util.concurrent.Executor");
1161+
assertNotNull(bean);
1162+
bean.execute(() -> {
1163+
CountDownLatch blocker = new CountDownLatch(1);
1164+
CountDownLatch blocking = new CountDownLatch(1);
1165+
Callable<Boolean> blockerTask = () -> {
1166+
blocking.countDown();
1167+
return blocker.await(TIMEOUT_NS, TimeUnit.NANOSECONDS);
1168+
};
1169+
1170+
try {
1171+
ManagedExecutorService executor = InitialContext.doLookup("java:comp/concurrent/executor8");
1172+
ContextService contextSvc = executor.getContextService();
1173+
1174+
CompletableFuture<String> stage1 = new CompletableFuture<String>();
1175+
1176+
CompletableFuture<String> stage1copy = contextSvc.withContextCapture(stage1);
1177+
1178+
// block the managed executor's single maxAsync slot
1179+
Future<Boolean> blockerFuture1 = executor.submit(blockerTask);
1180+
assertTrue(blocking.await(TIMEOUT_NS, TimeUnit.NANOSECONDS));
1181+
1182+
CompletableFuture<Object> stage2 = stage1copy.thenApplyAsync(jndiName -> {
1183+
try {
1184+
return InitialContext.doLookup(jndiName);
1185+
} catch (NamingException x) {
1186+
throw new CompletionException(x);
1187+
}
1188+
});
1189+
1190+
stage1.complete("java:comp/concurrent/executor8");
1191+
1192+
// copied stage completes,
1193+
assertEquals("java:comp/concurrent/executor8", stage1copy.get(TIMEOUT_NS, TimeUnit.NANOSECONDS));
1194+
1195+
// but the async stage must be blocked from running on the executor,
1196+
try {
1197+
Object result = stage2.get(1, TimeUnit.SECONDS);
1198+
fail("Dependent stage of withContextCapture stage should be blocked from asynchronous execution " +
1199+
"due to both maxAsync slots of the executor being used up. Instead: " + result);
1200+
} catch (TimeoutException x) {
1201+
// expected
1202+
}
1203+
1204+
blocker.countDown();
1205+
1206+
Object result;
1207+
assertNotNull(result = stage2.get(TIMEOUT_NS, TimeUnit.NANOSECONDS));
1208+
assertTrue(result.toString(), result instanceof ManagedExecutorService);
1209+
1210+
assertEquals(true, blockerFuture1.get(TIMEOUT_NS, TimeUnit.NANOSECONDS));
1211+
} catch (ExecutionException | InterruptedException | NamingException | TimeoutException x) {
1212+
throw new EJBException(x);
1213+
} finally {
1214+
blocker.countDown();
1215+
}
1216+
});
1217+
}
1218+
1219+
/**
1220+
* Verify that it is possible to obtain the nested ContextService of a ManagedScheduledExecutorService
1221+
* that is configured as a ManagedScheduledExecutorDefinition, and that when withContextCapture is invoked on this ContextService,
1222+
* the resulting CompletableFuture is backed by the ManagedScheduledExecutorService, subject to its concurrency
1223+
* constraints (maxAsync=2) and runs tasks under the context propagation settings of its nested ContextService.
1224+
*/
1225+
@Test
1226+
public void testGetContextServiceFromManagedScheduledExecutorDefinition() throws Exception {
1227+
ManagedScheduledExecutorService executor = InitialContext.doLookup("java:comp/concurrent/executor6");
1228+
ContextService contextSvc = executor.getContextService();
1229+
1230+
CompletableFuture<String> stage1 = new CompletableFuture<String>();
1231+
1232+
CompletableFuture<String> stage1copy = contextSvc.withContextCapture(stage1);
1233+
1234+
CountDownLatch blocker = new CountDownLatch(1);
1235+
CountDownLatch blocking = new CountDownLatch(2);
1236+
Callable<Boolean> blockerTask = () -> {
1237+
blocking.countDown();
1238+
return blocker.await(TIMEOUT_NS, TimeUnit.NANOSECONDS);
1239+
};
1240+
try {
1241+
// block both of the managed executor's maxAsync slots
1242+
Future<Boolean> blockerFuture1 = executor.submit(blockerTask);
1243+
Future<Boolean> blockerFuture2 = executor.submit(blockerTask);
1244+
assertTrue(blocking.await(TIMEOUT_NS, TimeUnit.NANOSECONDS));
1245+
1246+
CompletableFuture<Object> stage2 = stage1copy.thenApplyAsync(jndiName -> {
1247+
try {
1248+
return InitialContext.doLookup(jndiName);
1249+
} catch (NamingException x) {
1250+
throw new CompletionException(x);
1251+
}
1252+
});
1253+
1254+
stage1.complete("java:comp/concurrent/executor6");
1255+
1256+
// copied stage completes,
1257+
assertEquals("java:comp/concurrent/executor6", stage1copy.get(TIMEOUT_NS, TimeUnit.NANOSECONDS));
1258+
1259+
// but the async stage must be blocked from running on the executor,
1260+
try {
1261+
Object result = stage2.get(1, TimeUnit.SECONDS);
1262+
fail("Dependent stage of withContextCapture stage should be blocked from asynchronous execution " +
1263+
"due to both maxAsync slots of the executor being used up. Instead: " + result);
1264+
} catch (TimeoutException x) {
1265+
// expected
1266+
}
1267+
1268+
blocker.countDown();
1269+
1270+
Object result;
1271+
assertNotNull(result = stage2.get(TIMEOUT_NS, TimeUnit.NANOSECONDS));
1272+
assertTrue(result.toString(), result instanceof ManagedScheduledExecutorService);
1273+
1274+
assertEquals(true, blockerFuture1.get(TIMEOUT_NS, TimeUnit.NANOSECONDS));
1275+
assertEquals(true, blockerFuture2.get(TIMEOUT_NS, TimeUnit.NANOSECONDS));
1276+
} finally {
1277+
blocker.countDown();
1278+
}
1279+
}
1280+
11521281
/**
11531282
* Verify that it is possible to obtain the nested ContextService of a ManagedExecutorService
11541283
* that is configured in server.xml, and that when withContextCapture is invoked on this ContextService,
11551284
* the resulting CompletableFuture is backed by the ManagedExecutorService, subject to its concurrency
11561285
* constraints, and runs tasks under the context propagation settings of its nested ContextService.
11571286
*/
11581287
@Test
1159-
public void testGetContextService1WithContextCapture() throws Exception {
1288+
public void testGetContextServiceFromServerXMLWithContextCapture() throws Exception {
11601289
ContextService contextSvc = executor1.getContextService();
11611290

11621291
CompletableFuture<String> stage1 = new CompletableFuture<String>();

dev/com.ibm.ws.concurrent_fat_zcontext/test-applications/SimZOSContextWeb/src/test/concurrent/sim/zos/context/web/SimZOSContextTestServlet.java

Lines changed: 50 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,6 @@
4747
@ContextServiceDefinition(name = "java:app/concurrent/ThreadNameContext",
4848
propagated = { "SyncToOSThread", SECURITY, APPLICATION })
4949

50-
//TODO move to web.xml and include properties?
5150
@ContextServiceDefinition(name = "java:module/concurrent/zosWLMContext",
5251
propagated = { "Classification" },
5352
cleared = { TRANSACTION, "SyncToOSThread", SECURITY },
@@ -244,4 +243,54 @@ public void testPropagateSimulatedZOSWLMContext() throws Exception {
244243
Enclave.clear();
245244
}
246245
}
246+
247+
/**
248+
* Configure vendor properties for PropagateOrNew and with different default transaction
249+
* classes for zosWLMContext and verify that the fake context type that we are using to simulate it
250+
* propagates or creates the new context on the thread.
251+
*/
252+
// TODO If the spec ever adds a way for vendor properties to be supplied to context types, this test could help provide coverage.
253+
// @Test
254+
public void testVendorPropertiesSimulatedZOSWLMContext() throws Exception {
255+
// Instead of testing the real z/OS WLM context behavior,
256+
// the fake context provider updates the state of a mock Enclave class.
257+
ContextService contextSvc = InitialContext.doLookup("java:comp/concurrent/zosWLMContextPropagateOrNew");
258+
259+
String originalName = Thread.currentThread().getName();
260+
try {
261+
Enclave.setTransactionClass("TX_CLASS_D");
262+
263+
Supplier<String> txClassSupplier = contextSvc.contextualSupplier(Enclave::getTransactionClass);
264+
265+
Enclave.setTransactionClass("TX_CLASS_E");
266+
267+
assertEquals("TX_CLASS_D", txClassSupplier.get());
268+
269+
assertEquals("TX_CLASS_E", Enclave.getTransactionClass());
270+
271+
// Propagate the absence of context:
272+
273+
Enclave.clear();
274+
275+
txClassSupplier = contextSvc.contextualSupplier(Enclave::getTransactionClass);
276+
277+
Enclave.setTransactionClass("TX_CLASS_F");
278+
279+
assertEquals("DEFAULT_TX", txClassSupplier.get());
280+
281+
assertEquals("TX_CLASS_F", Enclave.getTransactionClass());
282+
283+
// Long running task:
284+
285+
@SuppressWarnings("unchecked")
286+
Supplier<String> longRunningTxSupplier = contextSvc.createContextualProxy(Enclave::getTransactionClass,
287+
Collections.singletonMap(ManagedTask.LONGRUNNING_HINT, "true"),
288+
Supplier.class);
289+
assertEquals("DAEMON_TX", longRunningTxSupplier.get());
290+
291+
assertEquals("TX_CLASS_F", Enclave.getTransactionClass());
292+
} finally {
293+
Enclave.clear();
294+
}
295+
}
247296
}

0 commit comments

Comments
 (0)