This is an automated email from the ASF dual-hosted git repository.
sunlan pushed a commit to branch GROOVY-9381_3
in repository https://gitbox.apache.org/repos/asf/groovy.git
The following commit(s) were added to refs/heads/GROOVY-9381_3 by this push:
new 24983b0a8e Tweak tests
24983b0a8e is described below
commit 24983b0a8eedf84be9ada1f6d18f90d9d58ddd5e
Author: Daniel Sun <[email protected]>
AuthorDate: Sat Mar 21 13:06:57 2026 +0900
Tweak tests
---
.../runtime/async/AsyncConcurrencyTest.groovy | 5 +-
.../codehaus/groovy/transform/AsyncApiTest.groovy | 68 ++++++------
.../groovy/transform/AsyncAwaitSyntaxTest.groovy | 32 ++----
.../groovy/transform/AsyncBestPracticesTest.groovy | 22 ++--
.../groovy/transform/AsyncClosureLambdaTest.groovy | 12 ++-
.../groovy/transform/AsyncDeferFlowTest.groovy | 18 ++--
.../transform/AsyncExceptionHandlingTest.groovy | 115 +++++++++++++--------
.../groovy/transform/AsyncTransformTest.groovy | 67 +++---------
.../groovy/transform/AsyncVirtualThreadTest.groovy | 61 +++++++----
9 files changed, 210 insertions(+), 190 deletions(-)
diff --git
a/src/test/groovy/org/apache/groovy/runtime/async/AsyncConcurrencyTest.groovy
b/src/test/groovy/org/apache/groovy/runtime/async/AsyncConcurrencyTest.groovy
index 7e74e0bf82..abc1e6c501 100644
---
a/src/test/groovy/org/apache/groovy/runtime/async/AsyncConcurrencyTest.groovy
+++
b/src/test/groovy/org/apache/groovy/runtime/async/AsyncConcurrencyTest.groovy
@@ -23,6 +23,7 @@ import org.junit.jupiter.api.Test
import org.junit.jupiter.api.Timeout
import org.junit.jupiter.api.DisplayName
+import java.io.IOException
import java.util.concurrent.CountDownLatch
import java.util.concurrent.CyclicBarrier
import java.util.concurrent.TimeUnit
@@ -503,13 +504,13 @@ class AsyncConcurrencyTest {
void testMoveNextPropagatesExceptionViaSneakyThrow() {
def gen = new AsyncStreamGenerator<Integer>()
Thread.start {
- gen.error(new java.io.IOException("disk fail"))
+ gen.error(new IOException("disk fail"))
}
try {
gen.moveNext().get()
assert false : "Expected IOException"
- } catch (java.io.IOException e) {
+ } catch (IOException e) {
assert e.message == "disk fail"
}
}
diff --git a/src/test/groovy/org/codehaus/groovy/transform/AsyncApiTest.groovy
b/src/test/groovy/org/codehaus/groovy/transform/AsyncApiTest.groovy
index e942c5e23b..d9d4fc62df 100644
--- a/src/test/groovy/org/codehaus/groovy/transform/AsyncApiTest.groovy
+++ b/src/test/groovy/org/codehaus/groovy/transform/AsyncApiTest.groovy
@@ -18,6 +18,7 @@
*/
package org.codehaus.groovy.transform
+import groovy.concurrent.AsyncScope
import groovy.concurrent.AsyncStream
import groovy.concurrent.AwaitResult
import groovy.concurrent.Awaitable
@@ -29,17 +30,24 @@ import org.apache.groovy.runtime.async.GroovyPromise
import org.junit.jupiter.api.AfterEach
import org.junit.jupiter.api.Test
+import java.lang.reflect.InvocationTargetException
import java.util.concurrent.Callable
import java.util.concurrent.CancellationException
import java.util.concurrent.CompletableFuture
import java.util.concurrent.CompletionException
import java.util.concurrent.CompletionStage
+import java.util.concurrent.ConcurrentLinkedQueue
import java.util.concurrent.CountDownLatch
+import java.util.concurrent.CyclicBarrier
import java.util.concurrent.ExecutionException
+import java.util.concurrent.Executor
+import java.util.concurrent.Executors
import java.util.concurrent.Flow
+import java.util.concurrent.Future
import java.util.concurrent.FutureTask
import java.util.concurrent.SubmissionPublisher
import java.util.concurrent.TimeUnit
+import java.util.concurrent.TimeoutException
import java.util.concurrent.atomic.AtomicBoolean
import java.util.concurrent.atomic.AtomicInteger
import java.util.concurrent.atomic.AtomicReference
@@ -150,7 +158,7 @@ class AsyncApiTest {
void testAwaitPlainFutureSuccess() {
def ft = new FutureTask<String>({ 'hello' } as Callable<String>)
ft.run()
- assert AsyncSupport.await((java.util.concurrent.Future<String>) ft) ==
'hello'
+ assert AsyncSupport.await((Future<String>) ft) == 'hello'
}
@Test
@@ -158,7 +166,7 @@ class AsyncApiTest {
def ft = new FutureTask<String>({ throw new
IOException('future-error') } as Callable<String>)
ft.run()
try {
- AsyncSupport.await((java.util.concurrent.Future<String>) ft)
+ AsyncSupport.await((Future<String>) ft)
assert false
} catch (IOException e) {
assert e.message == 'future-error'
@@ -170,7 +178,7 @@ class AsyncApiTest {
def ft = new FutureTask<String>({ 'never' } as Callable<String>)
ft.cancel(true)
try {
- AsyncSupport.await((java.util.concurrent.Future<String>) ft)
+ AsyncSupport.await((Future<String>) ft)
assert false
} catch (CancellationException ignored) {}
}
@@ -185,7 +193,7 @@ class AsyncApiTest {
// Don't run it — it will block on get(), and we set interrupt
Thread.currentThread().interrupt()
try {
- AsyncSupport.await((java.util.concurrent.Future<String>) ft)
+ AsyncSupport.await((Future<String>) ft)
assert false
} catch (CancellationException e) {
assert e.message.contains('Interrupted')
@@ -199,7 +207,7 @@ class AsyncApiTest {
void testAwaitFutureWithCompletableFuture() {
// Pass CF as Future to hit line 245: instanceof CompletableFuture
shortcut
def cf = CompletableFuture.completedFuture('via-cf')
- assert AsyncSupport.await((java.util.concurrent.Future<String>) cf) ==
'via-cf'
+ assert AsyncSupport.await((Future<String>) cf) == 'via-cf'
}
@Test
@@ -297,7 +305,7 @@ class AsyncApiTest {
def ft = new FutureTask<String>({ throw new
ArithmeticException('div-zero') } as Callable<String>)
ft.run()
try {
- AsyncSupport.await((java.util.concurrent.Future<String>) ft)
+ AsyncSupport.await((Future<String>) ft)
assert false
} catch (ArithmeticException e) {
assert e.message == 'div-zero'
@@ -1042,7 +1050,7 @@ class AsyncApiTest {
void testCloseInterruptsBlockedProducerThread() {
def gen = new AsyncStreamGenerator<Integer>()
def producerExit = new CompletableFuture<String>()
- def producerBlocked = new java.util.concurrent.CountDownLatch(1)
+ def producerBlocked = new CountDownLatch(1)
def producerThread = Thread.start {
gen.attachProducer(Thread.currentThread())
@@ -1094,7 +1102,7 @@ class AsyncApiTest {
void testCloseInterruptsBlockedConsumerThread() {
def gen = new AsyncStreamGenerator<Integer>()
def consumerResult = new CompletableFuture<Boolean>()
- def consumerBlocked = new java.util.concurrent.CountDownLatch(1)
+ def consumerBlocked = new CountDownLatch(1)
// Start a consumer thread that will block in moveNext()
// because no producer will ever yield anything
@@ -1367,7 +1375,7 @@ class AsyncApiTest {
def toAwaitable = builtInClass.getDeclaredMethod('toAwaitable', Object)
toAwaitable.accessible = true
- def ex = shouldFail(java.lang.reflect.InvocationTargetException) {
+ def ex = shouldFail(InvocationTargetException) {
toAwaitable.invoke(adapter, new Object())
}
assert ex.cause instanceof IllegalArgumentException
@@ -1384,7 +1392,7 @@ class AsyncApiTest {
def toAsyncStream = builtInClass.getDeclaredMethod('toAsyncStream',
Object)
toAsyncStream.accessible = true
- def ex = shouldFail(java.lang.reflect.InvocationTargetException) {
+ def ex = shouldFail(InvocationTargetException) {
toAsyncStream.invoke(adapter, 123)
}
assert ex.cause instanceof IllegalArgumentException
@@ -2040,13 +2048,13 @@ class AsyncApiTest {
assert false
} catch (Exception e) {
// IOException wrapped in ExecutionException, then unwrapped
- assert e instanceof IOException || e instanceof
java.util.concurrent.ExecutionException
+ assert e instanceof IOException || e instanceof ExecutionException
}
}
@Test
void testFutureAdapterInterruptedFutureMapsToCancellation() {
- def interruptedFuture = new java.util.concurrent.Future<String>() {
+ def interruptedFuture = new Future<String>() {
boolean cancel(boolean mayInterruptIfRunning) { false }
boolean isCancelled() { false }
boolean isDone() { true }
@@ -2062,7 +2070,7 @@ class AsyncApiTest {
@Test
void testFutureAdapterCancellationExceptionIsPropagated() {
- def cancelledFuture = new java.util.concurrent.Future<String>() {
+ def cancelledFuture = new Future<String>() {
boolean cancel(boolean mayInterruptIfRunning) { false }
boolean isCancelled() { true }
boolean isDone() { true }
@@ -2078,7 +2086,7 @@ class AsyncApiTest {
@Test
void testFutureAdapterUnexpectedExceptionIsPropagated() {
- def brokenFuture = new java.util.concurrent.Future<String>() {
+ def brokenFuture = new Future<String>() {
boolean cancel(boolean mayInterruptIfRunning) { false }
boolean isCancelled() { false }
boolean isDone() { true }
@@ -2113,7 +2121,7 @@ class AsyncApiTest {
void testGetSetExecutor() {
def original = AsyncSupport.getExecutor()
assert original != null
- def custom = { Runnable r -> r.run() } as java.util.concurrent.Executor
+ def custom = { Runnable r -> r.run() } as Executor
AsyncSupport.setExecutor(custom)
assert AsyncSupport.getExecutor().is(custom)
AsyncSupport.setExecutor(null) // reset
@@ -2402,7 +2410,7 @@ class AsyncApiTest {
def ex = shouldFail(ExecutionException) {
withTimeout.get()
}
- assert ex.cause instanceof java.util.concurrent.TimeoutException
+ assert ex.cause instanceof TimeoutException
}
@Test
@@ -2413,7 +2421,7 @@ class AsyncApiTest {
def ex = shouldFail(ExecutionException) {
withTimeout.get()
}
- assert ex.cause instanceof java.util.concurrent.TimeoutException
+ assert ex.cause instanceof TimeoutException
}
@Test
@@ -2469,7 +2477,7 @@ class AsyncApiTest {
void testGroovyPromiseGetWithTimeoutExpired() {
def cf = new CompletableFuture<>()
def promise = GroovyPromise.of(cf)
- shouldFail(java.util.concurrent.TimeoutException) {
+ shouldFail(TimeoutException) {
promise.get(50, TimeUnit.MILLISECONDS)
}
}
@@ -2690,7 +2698,7 @@ class AsyncApiTest {
def ex = shouldFail(ExecutionException) {
aw.get()
}
- assert ex.cause instanceof java.util.concurrent.TimeoutException
+ assert ex.cause instanceof TimeoutException
}
@Test
@@ -2716,7 +2724,7 @@ class AsyncApiTest {
def original = Awaitable.getExecutor()
assert original != null
try {
- def custom =
java.util.concurrent.Executors.newSingleThreadExecutor()
+ def custom = Executors.newSingleThreadExecutor()
Awaitable.setExecutor(custom)
assert Awaitable.getExecutor().is(custom)
custom.shutdown()
@@ -3169,7 +3177,7 @@ class AsyncApiTest {
void testAbstractAsyncStreamGeneratorBeforeTakeRejectsSecondConsumer() {
// AsyncStreamGenerator.beforeTake() enforces single-consumer semantics
def gen = new AsyncStreamGenerator<Integer>()
- def latch = new java.util.concurrent.CountDownLatch(1)
+ def latch = new CountDownLatch(1)
def error = new CompletableFuture<Throwable>()
CompletableFuture.runAsync {
@@ -3344,8 +3352,8 @@ class AsyncApiTest {
void testAdapterCacheConcurrentAccess() {
// Hammer the cache from multiple threads to verify thread safety
int threadCount = 32
- def barrier = new java.util.concurrent.CyclicBarrier(threadCount)
- def errors = new
java.util.concurrent.ConcurrentLinkedQueue<Throwable>()
+ def barrier = new CyclicBarrier(threadCount)
+ def errors = new ConcurrentLinkedQueue<Throwable>()
def threads = (1..threadCount).collect { idx ->
Thread.start {
try {
@@ -3442,7 +3450,7 @@ class AsyncApiTest {
@Test
void testAsyncScopeBasicUsage() {
- def result = groovy.concurrent.AsyncScope.withScope { scope ->
+ def result = AsyncScope.withScope { scope ->
def a = scope.async { 10 }
def b = scope.async { 20 }
return a.get() + b.get()
@@ -3456,7 +3464,7 @@ class AsyncApiTest {
def error = null
try {
- groovy.concurrent.AsyncScope.withScope { scope ->
+ AsyncScope.withScope { scope ->
// Slow task
scope.async {
try {
@@ -3484,7 +3492,7 @@ class AsyncApiTest {
@Test
void testAsyncScopeAggregatesSuppressedExceptions() {
try {
- groovy.concurrent.AsyncScope.withScope { scope ->
+ AsyncScope.withScope { scope ->
scope.async { throw new IllegalArgumentException("err1") }
scope.async { throw new IllegalStateException("err2") }
Thread.sleep(200) // Let both fail
@@ -3502,7 +3510,7 @@ class AsyncApiTest {
@Test
void testAsyncScopeRejectsAfterClose() {
- def scope = new groovy.concurrent.AsyncScope()
+ def scope = new AsyncScope()
scope.close()
shouldFail(IllegalStateException) {
scope.async { 42 }
@@ -3511,7 +3519,7 @@ class AsyncApiTest {
@Test
void testAsyncScopeChildCount() {
- groovy.concurrent.AsyncScope.withScope { scope ->
+ AsyncScope.withScope { scope ->
assert scope.childCount == 0
scope.async { 1 }
scope.async { 2 }
@@ -3524,7 +3532,7 @@ class AsyncApiTest {
@Test
void testAsyncScopeHighConcurrency() {
int taskCount = 10_000
- def result = groovy.concurrent.AsyncScope.withScope { scope ->
+ def result = AsyncScope.withScope { scope ->
def tasks = (1..taskCount).collect { n ->
scope.async { n }
}
@@ -3539,7 +3547,7 @@ class AsyncApiTest {
@Test
void testAsyncScopeCloseIsIdempotent() {
- def scope = new groovy.concurrent.AsyncScope()
+ def scope = new AsyncScope()
def task = scope.async { 42 }
assert task.get() == 42
scope.close()
diff --git
a/src/test/groovy/org/codehaus/groovy/transform/AsyncAwaitSyntaxTest.groovy
b/src/test/groovy/org/codehaus/groovy/transform/AsyncAwaitSyntaxTest.groovy
index 7ccdbeaa3d..2ace82da16 100644
--- a/src/test/groovy/org/codehaus/groovy/transform/AsyncAwaitSyntaxTest.groovy
+++ b/src/test/groovy/org/codehaus/groovy/transform/AsyncAwaitSyntaxTest.groovy
@@ -1421,6 +1421,7 @@ class AsyncAwaitSyntaxTest {
void testAsyncWithCustomExecutor() {
assertScript '''
import java.util.concurrent.Executors
+ import groovy.concurrent.Awaitable
class Svc {
static executor = Executors.newFixedThreadPool(2)
@@ -1429,12 +1430,12 @@ class AsyncAwaitSyntaxTest {
}
}
- groovy.concurrent.Awaitable.setExecutor(Svc.executor)
+ Awaitable.setExecutor(Svc.executor)
try {
def name = new Svc().threadInfo().get()
assert name.contains("pool")
} finally {
- groovy.concurrent.Awaitable.setExecutor(null)
+ Awaitable.setExecutor(null)
Svc.executor.shutdown()
}
'''
@@ -1643,29 +1644,6 @@ class AsyncAwaitSyntaxTest {
// 6. Error cases — syntax and semantic rejections
// =====================================================================
- @Test
- void testAsyncOnAbstractMethodFails() {
- def err = shouldFail CompilationFailedException, '''
- abstract class Svc {
- @groovy.transform.Async
- abstract def compute()
- }
- '''
- assert err.message.contains('cannot be applied to abstract method')
- }
-
- @Test
- void testAsyncOnAwaitableReturnTypeFails() {
- def err = shouldFail CompilationFailedException, '''
- import groovy.concurrent.Awaitable
- class Svc {
- @groovy.transform.Async
- Awaitable<String> compute() { Awaitable.of("x") }
- }
- '''
- assert err.message.contains('already returns an async type')
- }
-
@Test
void testForAwaitWithTraditionalForSyntaxFails() {
def err = shouldFail CompilationFailedException, '''
@@ -2471,9 +2449,11 @@ class AsyncAwaitSyntaxTest {
@Test
void testYieldReturnOutsideAsyncMethodFails() {
assertScript '''
+ import org.apache.groovy.runtime.async.AsyncSupport
+
// yield return outside async method should fail at runtime
try {
-
org.apache.groovy.runtime.async.AsyncSupport.yieldReturn("oops")
+ AsyncSupport.yieldReturn("oops")
assert false : "expected exception"
} catch (IllegalStateException e) {
assert e.message.contains("yield return")
diff --git
a/src/test/groovy/org/codehaus/groovy/transform/AsyncBestPracticesTest.groovy
b/src/test/groovy/org/codehaus/groovy/transform/AsyncBestPracticesTest.groovy
index 471981300c..51d6d0e758 100644
---
a/src/test/groovy/org/codehaus/groovy/transform/AsyncBestPracticesTest.groovy
+++
b/src/test/groovy/org/codehaus/groovy/transform/AsyncBestPracticesTest.groovy
@@ -675,6 +675,7 @@ class AsyncBestPracticesTest {
assertScript '''
import groovy.concurrent.Awaitable
import groovy.concurrent.Awaitable
+ import java.util.concurrent.TimeoutException
async slowOperation() {
await Awaitable.delay(5000)
@@ -685,7 +686,7 @@ class AsyncBestPracticesTest {
def timeout = Awaitable.delay(timeoutMs)
def winner = await(Awaitable.any(task, timeout))
if (winner == null) {
- throw new java.util.concurrent.TimeoutException("operation
timed out")
+ throw new TimeoutException("operation timed out")
}
return winner
}
@@ -694,7 +695,7 @@ class AsyncBestPracticesTest {
try {
await(withTimeout(task, 50))
assert false : "should have timed out"
- } catch (java.util.concurrent.TimeoutException e) {
+ } catch (TimeoutException e) {
assert e.message == "operation timed out"
} finally {
task.cancel()
@@ -734,6 +735,7 @@ class AsyncBestPracticesTest {
import groovy.concurrent.Awaitable
import java.util.concurrent.atomic.AtomicInteger
import java.util.concurrent.CountDownLatch
+ import java.util.concurrent.TimeUnit
def pingCount = new AtomicInteger(0)
def latch = new CountDownLatch(3)
@@ -757,7 +759,7 @@ class AsyncBestPracticesTest {
}
}, 0, 20)
- latch.await(5, java.util.concurrent.TimeUnit.SECONDS)
+ latch.await(5, TimeUnit.SECONDS)
timer.cancel()
assert pingCount.get() >= 3
'''
@@ -768,6 +770,7 @@ class AsyncBestPracticesTest {
assertScript '''
import groovy.concurrent.Awaitable
import java.util.concurrent.CountDownLatch
+ import java.util.concurrent.TimeUnit
def results = Collections.synchronizedList([])
def latch = new CountDownLatch(3)
@@ -785,7 +788,7 @@ class AsyncBestPracticesTest {
task()
}
- latch.await(5, java.util.concurrent.TimeUnit.SECONDS)
+ latch.await(5, TimeUnit.SECONDS)
assert results.size() == 3
assert results.sort() == ["item-0", "item-1", "item-2"]
'''
@@ -850,6 +853,7 @@ class AsyncBestPracticesTest {
import java.util.concurrent.ConcurrentHashMap
import java.util.concurrent.atomic.AtomicInteger
import java.util.concurrent.CountDownLatch
+ import java.util.concurrent.TimeUnit
class DataCache {
final AtomicInteger fetchCount = new AtomicInteger(0)
@@ -883,7 +887,7 @@ class AsyncBestPracticesTest {
task()
}
- latch.await(5, java.util.concurrent.TimeUnit.SECONDS)
+ latch.await(5, TimeUnit.SECONDS)
assert results.size() == 10
assert results.every { it == "Data-1" }
// computeIfAbsent ensures at most 1 fetch for the same key
@@ -984,6 +988,7 @@ class AsyncBestPracticesTest {
import groovy.concurrent.Awaitable
import java.util.concurrent.LinkedBlockingQueue
import java.util.concurrent.CountDownLatch
+ import java.util.concurrent.TimeUnit
class QueueProcessor {
private final LinkedBlockingQueue<String> queue = new
LinkedBlockingQueue<>()
@@ -994,7 +999,7 @@ class AsyncBestPracticesTest {
// GOOD: dedicated daemon thread for long-running work
def t = new Thread({
while (running) {
- def item = queue.poll(100,
java.util.concurrent.TimeUnit.MILLISECONDS)
+ def item = queue.poll(100, TimeUnit.MILLISECONDS)
if (item != null) processed.add(item.toUpperCase())
}
})
@@ -1036,6 +1041,7 @@ class AsyncBestPracticesTest {
import groovy.concurrent.Awaitable
import java.util.concurrent.CountDownLatch
import java.util.concurrent.atomic.AtomicBoolean
+ import java.util.concurrent.TimeUnit
def completed = new AtomicBoolean(false)
def latch = new CountDownLatch(1)
@@ -1053,7 +1059,7 @@ class AsyncBestPracticesTest {
// GOOD: capture the Awaitable for tracking
def awaitable = task()
- latch.await(5, java.util.concurrent.TimeUnit.SECONDS)
+ latch.await(5, TimeUnit.SECONDS)
assert completed.get()
assert await(awaitable) == "done"
'''
@@ -1361,7 +1367,7 @@ class AsyncBestPracticesTest {
}
}
- async withRetry(int maxRetries,
Closure<groovy.concurrent.Awaitable> op) {
+ async withRetry(int maxRetries, Closure<Awaitable> op) {
for (int i = 0; i <= maxRetries; i++) {
try {
return await op()
diff --git
a/src/test/groovy/org/codehaus/groovy/transform/AsyncClosureLambdaTest.groovy
b/src/test/groovy/org/codehaus/groovy/transform/AsyncClosureLambdaTest.groovy
index 5d671f0199..5075e2270f 100644
---
a/src/test/groovy/org/codehaus/groovy/transform/AsyncClosureLambdaTest.groovy
+++
b/src/test/groovy/org/codehaus/groovy/transform/AsyncClosureLambdaTest.groovy
@@ -388,12 +388,14 @@ final class AsyncClosureLambdaTest {
@Test
void testAsyncClosureExceptionTransparency() {
assertScript '''
+ import java.io.IOException
+
async caller() {
- def task = async { throw new java.io.IOException("async
closure error") }
+ def task = async { throw new IOException("async closure
error") }
try {
await task()
assert false
- } catch (java.io.IOException e) {
+ } catch (IOException e) {
return e.message
}
}
@@ -442,10 +444,12 @@ final class AsyncClosureLambdaTest {
@Test
void testAsyncClosureGeneratorExceptionPropagation() {
assertScript '''
+ import java.io.IOException
+
async caller() {
def gen = async {
yield return 1
- throw new java.io.IOException("generator error")
+ throw new IOException("generator error")
}
def items = []
try {
@@ -453,7 +457,7 @@ final class AsyncClosureLambdaTest {
items << item
}
assert false
- } catch (java.io.IOException e) {
+ } catch (IOException e) {
return "${items}:${e.message}"
}
}
diff --git
a/src/test/groovy/org/codehaus/groovy/transform/AsyncDeferFlowTest.groovy
b/src/test/groovy/org/codehaus/groovy/transform/AsyncDeferFlowTest.groovy
index 38c876fc86..a875c13c30 100644
--- a/src/test/groovy/org/codehaus/groovy/transform/AsyncDeferFlowTest.groovy
+++ b/src/test/groovy/org/codehaus/groovy/transform/AsyncDeferFlowTest.groovy
@@ -276,8 +276,10 @@ class AsyncDeferFlowTest {
@Test
void testForAwaitFlowPublisher() {
assertScript '''
+ import java.util.concurrent.SubmissionPublisher
+
class FlowTest {
- async
consumePublisher(java.util.concurrent.SubmissionPublisher<Integer> pub) {
+ async consumePublisher(SubmissionPublisher<Integer> pub) {
def results = []
for await (item in pub) {
results << item
@@ -286,7 +288,7 @@ class AsyncDeferFlowTest {
}
}
- def publisher = new
java.util.concurrent.SubmissionPublisher<Integer>()
+ def publisher = new SubmissionPublisher<Integer>()
def future = new FlowTest().consumePublisher(publisher)
// Wait until the for-await loop has subscribed to the publisher
def deadline = System.nanoTime() + 5_000_000_000L
@@ -302,8 +304,10 @@ class AsyncDeferFlowTest {
@Test
void testForAwaitFlowPublisherWithError() {
assertScript '''
+ import java.util.concurrent.SubmissionPublisher
+
class FlowTest {
- async
consumeWithError(java.util.concurrent.SubmissionPublisher<Integer> pub) {
+ async consumeWithError(SubmissionPublisher<Integer> pub) {
def results = []
for await (item in pub) {
results << item
@@ -312,7 +316,7 @@ class AsyncDeferFlowTest {
}
}
- def publisher = new
java.util.concurrent.SubmissionPublisher<Integer>()
+ def publisher = new SubmissionPublisher<Integer>()
def future = new FlowTest().consumeWithError(publisher)
// Wait until the for-await loop has subscribed
def deadline = System.nanoTime() + 5_000_000_000L
@@ -358,10 +362,12 @@ class AsyncDeferFlowTest {
@Test
void testDeferCombinedWithForAwaitFlow() {
assertScript '''
+ import java.util.concurrent.SubmissionPublisher
+
class CombinedTest {
static log = []
- async
processStream(java.util.concurrent.SubmissionPublisher<Integer> pub) {
+ async processStream(SubmissionPublisher<Integer> pub) {
defer { log << 'stream-cleanup' }
def sum = 0
for await (item in pub) {
@@ -372,7 +378,7 @@ class AsyncDeferFlowTest {
}
}
- def publisher = new
java.util.concurrent.SubmissionPublisher<Integer>()
+ def publisher = new SubmissionPublisher<Integer>()
def future = new CombinedTest().processStream(publisher)
// Wait until the for-await loop has subscribed
def deadline = System.nanoTime() + 5_000_000_000L
diff --git
a/src/test/groovy/org/codehaus/groovy/transform/AsyncExceptionHandlingTest.groovy
b/src/test/groovy/org/codehaus/groovy/transform/AsyncExceptionHandlingTest.groovy
index 1c1a8e86db..175fc22808 100644
---
a/src/test/groovy/org/codehaus/groovy/transform/AsyncExceptionHandlingTest.groovy
+++
b/src/test/groovy/org/codehaus/groovy/transform/AsyncExceptionHandlingTest.groovy
@@ -48,15 +48,17 @@ final class AsyncExceptionHandlingTest {
void testAwaitIOExceptionTransparency() {
assertScript '''
+ import java.io.IOException
+
async fetchData() {
- throw new java.io.IOException("disk failure")
+ throw new IOException("disk failure")
}
async caller() {
try {
await fetchData()
assert false : "should not reach"
- } catch (java.io.IOException e) {
+ } catch (IOException e) {
return e.message
}
}
@@ -69,15 +71,17 @@ final class AsyncExceptionHandlingTest {
void testAwaitSQLExceptionTransparency() {
assertScript '''
+ import java.sql.SQLException
+
async queryDb() {
- throw new java.sql.SQLException("connection refused", "08001")
+ throw new SQLException("connection refused", "08001")
}
async caller() {
try {
await queryDb()
assert false : "should not reach"
- } catch (java.sql.SQLException e) {
+ } catch (SQLException e) {
return e.SQLState
}
}
@@ -166,17 +170,19 @@ final class AsyncExceptionHandlingTest {
assertScript '''
import java.util.concurrent.CompletableFuture
import java.util.concurrent.CompletionException
+ import java.io.FileNotFoundException
+ import java.util.concurrent.ExecutionException
// Simulate deeply nested wrapping
async caller() {
- def original = new java.io.FileNotFoundException("config.yml")
- def wrapped = new CompletionException(new
java.util.concurrent.ExecutionException(original))
+ def original = new FileNotFoundException("config.yml")
+ def wrapped = new CompletionException(new
ExecutionException(original))
def future = new CompletableFuture()
future.completeExceptionally(wrapped)
try {
await future
assert false
- } catch (java.io.FileNotFoundException e) {
+ } catch (FileNotFoundException e) {
return e.message
}
}
@@ -280,16 +286,17 @@ final class AsyncExceptionHandlingTest {
void testAwaitAllWithFailureThrowsOriginal() {
assertScript '''
import groovy.concurrent.Awaitable
+ import java.io.IOException
async success() { return 1 }
- async failure() { throw new java.io.IOException("network error") }
+ async failure() { throw new IOException("network error") }
async caller() {
try {
await(Awaitable.all(success(), failure()))
assert false
- } catch (java.io.IOException e) {
+ } catch (IOException e) {
return e.message
}
}
@@ -321,12 +328,13 @@ final class AsyncExceptionHandlingTest {
void testAwaitAnyWithFailure() {
assertScript '''
import groovy.concurrent.Awaitable
+ import java.io.IOException
async caller() {
try {
- await(Awaitable.any(Awaitable.failed(new
java.io.IOException("fail"))))
+ await(Awaitable.any(Awaitable.failed(new
IOException("fail"))))
assert false
- } catch (java.io.IOException e) {
+ } catch (IOException e) {
return e.message
}
}
@@ -361,10 +369,11 @@ final class AsyncExceptionHandlingTest {
void testAwaitAllSettledMixedResults() {
assertScript '''
import groovy.concurrent.Awaitable
+ import java.io.IOException
async caller() {
def a = Awaitable.of(1)
- def b = Awaitable.failed(new java.io.IOException("err"))
+ def b = Awaitable.failed(new IOException("err"))
def c = Awaitable.of(3)
return await(Awaitable.allSettled(a, b, c))
}
@@ -376,7 +385,7 @@ final class AsyncExceptionHandlingTest {
assert results[0].value == 1
assert results[1].isFailure()
- assert results[1].error instanceof java.io.IOException
+ assert results[1].error instanceof IOException
assert results[1].error.message == "err"
assert results[2].isSuccess()
@@ -405,11 +414,12 @@ final class AsyncExceptionHandlingTest {
void testAwaitAllSettledAllFailure() {
assertScript '''
import groovy.concurrent.Awaitable
+ import java.io.IOException
async caller() {
return await(Awaitable.allSettled(
Awaitable.failed(new RuntimeException("e1")),
- Awaitable.failed(new java.io.IOException("e2")),
+ Awaitable.failed(new IOException("e2")),
Awaitable.failed(new IllegalStateException("e3"))
))
}
@@ -417,7 +427,7 @@ final class AsyncExceptionHandlingTest {
def results = await(caller())
assert results.every { it.isFailure() }
assert results[0].error instanceof RuntimeException
- assert results[1].error instanceof java.io.IOException
+ assert results[1].error instanceof IOException
assert results[2].error instanceof IllegalStateException
'''
}
@@ -489,10 +499,12 @@ final class AsyncExceptionHandlingTest {
void testGeneratorCheckedExceptionPropagation() {
assertScript '''
+ import java.io.IOException
+
async failingGenerator() {
yield return 1
yield return 2
- throw new java.io.IOException("generator IO error")
+ throw new IOException("generator IO error")
}
async caller() {
@@ -502,7 +514,7 @@ final class AsyncExceptionHandlingTest {
collected << item
}
assert false : "should not complete normally"
- } catch (java.io.IOException e) {
+ } catch (IOException e) {
return "${collected}:${e.message}"
}
}
@@ -544,8 +556,10 @@ final class AsyncExceptionHandlingTest {
void testTryCatchFinallyInAsync() {
assertScript '''
+ import java.io.IOException
+
async riskyOp() {
- throw new java.io.IOException("test")
+ throw new IOException("test")
}
async caller() {
@@ -554,7 +568,7 @@ final class AsyncExceptionHandlingTest {
log << "try"
await riskyOp()
log << "after-await"
- } catch (java.io.IOException e) {
+ } catch (IOException e) {
log << "catch:${e.message}"
} finally {
log << "finally"
@@ -570,8 +584,9 @@ final class AsyncExceptionHandlingTest {
void testMultipleCatchBlocks() {
assertScript '''
import groovy.concurrent.Awaitable
+ import java.io.IOException
- async throwIO() { throw new java.io.IOException("io") }
+ async throwIO() { throw new IOException("io") }
async throwArg() { throw new IllegalArgumentException("arg") }
@@ -583,7 +598,7 @@ final class AsyncExceptionHandlingTest {
await throwArg()
}
return "none"
- } catch (java.io.IOException e) {
+ } catch (IOException e) {
return "io:${e.message}"
} catch (IllegalArgumentException e) {
return "arg:${e.message}"
@@ -599,7 +614,9 @@ final class AsyncExceptionHandlingTest {
void testNestedTryCatch() {
assertScript '''
- async fail1() { throw new java.io.IOException("first") }
+ import java.io.IOException
+
+ async fail1() { throw new IOException("first") }
async fail2() { throw new IllegalStateException("second") }
@@ -608,7 +625,7 @@ final class AsyncExceptionHandlingTest {
try {
try {
await fail1()
- } catch (java.io.IOException e) {
+ } catch (IOException e) {
results << "inner:${e.message}"
}
await fail2()
@@ -650,8 +667,10 @@ final class AsyncExceptionHandlingTest {
void testExceptionChainingThreeDeep() {
assertScript '''
+ import java.io.IOException
+
async level3() {
- throw new java.io.IOException("root cause")
+ throw new IOException("root cause")
}
async level2() {
@@ -666,7 +685,7 @@ final class AsyncExceptionHandlingTest {
try {
await level1()
assert false
- } catch (java.io.IOException e) {
+ } catch (IOException e) {
return e.message
}
}
@@ -679,14 +698,16 @@ final class AsyncExceptionHandlingTest {
void testExceptionTransformAcrossMultipleAwaits() {
assertScript '''
+ import java.io.IOException
+
async step1() {
- throw new java.io.IOException("step1 failed")
+ throw new IOException("step1 failed")
}
async step2() {
try {
await step1()
- } catch (java.io.IOException e) {
+ } catch (IOException e) {
throw new IllegalStateException("step2 wraps: " +
e.message, e)
}
}
@@ -696,7 +717,7 @@ final class AsyncExceptionHandlingTest {
await step2()
assert false
} catch (IllegalStateException e) {
- assert e.cause instanceof java.io.IOException
+ assert e.cause instanceof IOException
return e.message
}
}
@@ -713,14 +734,15 @@ final class AsyncExceptionHandlingTest {
void testExceptionallyRecovery() {
assertScript '''
import groovy.concurrent.Awaitable
+ import java.io.IOException
async failing() {
- throw new java.io.IOException("network error")
+ throw new IOException("network error")
}
async caller() {
def task = failing().exceptionally { err ->
- assert err instanceof java.io.IOException
+ assert err instanceof IOException
return "recovered: ${err.message}"
}
return await task
@@ -736,14 +758,16 @@ final class AsyncExceptionHandlingTest {
import groovy.concurrent.Awaitable
import java.util.concurrent.CompletableFuture
import java.util.concurrent.CompletionException
+ import java.io.IOException
+ import org.apache.groovy.runtime.async.GroovyPromise
async caller() {
// Create a future that wraps a checked exception
def cf = new CompletableFuture()
cf.completeExceptionally(
- new CompletionException(new java.io.IOException("wrapped"))
+ new CompletionException(new IOException("wrapped"))
)
- def task = new
org.apache.groovy.runtime.async.GroovyPromise(cf)
+ def task = new GroovyPromise(cf)
def recovered = task.exceptionally { err ->
// Should receive the IOException, not CompletionException
return err.class.simpleName + ":" + err.message
@@ -787,14 +811,16 @@ final class AsyncExceptionHandlingTest {
void testDirectAsyncClosureExceptionHandling() {
assertScript '''
+ import java.io.IOException
+
async caller() {
def task = async {
- throw new java.io.IOException("from closure")
+ throw new IOException("from closure")
}
try {
await task()
assert false
- } catch (java.io.IOException e) {
+ } catch (IOException e) {
return e.message
}
}
@@ -919,9 +945,10 @@ final class AsyncExceptionHandlingTest {
void testRecoverAndContinue() {
assertScript '''
import groovy.concurrent.Awaitable
+ import java.io.IOException
async fetchWithRetry() {
- def attempt1 = Awaitable.failed(new
java.io.IOException("timeout"))
+ def attempt1 = Awaitable.failed(new IOException("timeout"))
def result1 = attempt1.exceptionally { err -> "fallback" }
return await result1
}
@@ -940,8 +967,9 @@ final class AsyncExceptionHandlingTest {
import org.apache.groovy.runtime.async.AsyncSupport
import java.util.concurrent.CompletionException
import java.util.concurrent.ExecutionException
+ import java.io.IOException
- def original = new java.io.IOException("root")
+ def original = new IOException("root")
def l1 = new ExecutionException(original)
def l2 = new CompletionException(l1)
def l3 = new CompletionException(l2)
@@ -1035,13 +1063,15 @@ final class AsyncExceptionHandlingTest {
void testSequentialAwaitsWithDifferentExceptions() {
assertScript '''
import groovy.concurrent.Awaitable
+ import java.io.IOException
+ import java.sql.SQLException
async caller() {
def log = []
try {
- await Awaitable.failed(new java.io.IOException("io"))
- } catch (java.io.IOException e) {
+ await Awaitable.failed(new IOException("io"))
+ } catch (IOException e) {
log << "io:${e.message}"
}
@@ -1052,8 +1082,8 @@ final class AsyncExceptionHandlingTest {
}
try {
- await Awaitable.failed(new java.sql.SQLException("sql"))
- } catch (java.sql.SQLException e) {
+ await Awaitable.failed(new SQLException("sql"))
+ } catch (SQLException e) {
log << "sql:${e.message}"
}
@@ -1072,12 +1102,13 @@ final class AsyncExceptionHandlingTest {
void testAwaitOnFailedAwaitable() {
assertScript '''
import groovy.concurrent.Awaitable
+ import java.io.IOException
async caller() {
try {
- await Awaitable.failed(new
java.io.IOException("pre-failed"))
+ await Awaitable.failed(new IOException("pre-failed"))
assert false
- } catch (java.io.IOException e) {
+ } catch (IOException e) {
return e.message
}
}
diff --git
a/src/test/groovy/org/codehaus/groovy/transform/AsyncTransformTest.groovy
b/src/test/groovy/org/codehaus/groovy/transform/AsyncTransformTest.groovy
index a077e4c067..908cad7006 100644
--- a/src/test/groovy/org/codehaus/groovy/transform/AsyncTransformTest.groovy
+++ b/src/test/groovy/org/codehaus/groovy/transform/AsyncTransformTest.groovy
@@ -486,6 +486,7 @@ class AsyncTransformTest {
assertScript '''
import groovy.transform.Async
import java.util.concurrent.CountDownLatch
+ import java.util.concurrent.TimeUnit
import java.util.concurrent.atomic.AtomicInteger
class Service {
@@ -496,7 +497,7 @@ class AsyncTransformTest {
def concurrentTask(CountDownLatch startLatch) {
int current = concurrentCount.incrementAndGet()
maxConcurrent.updateAndGet { max -> Math.max(max, current)
}
- startLatch.await(5, java.util.concurrent.TimeUnit.SECONDS)
+ startLatch.await(5, TimeUnit.SECONDS)
concurrentCount.decrementAndGet()
return current
}
@@ -507,7 +508,7 @@ class AsyncTransformTest {
def futures = (1..10).collect { service.concurrentTask(latch) }
Thread.sleep(500)
latch.countDown()
- futures.each { it.get(5, java.util.concurrent.TimeUnit.SECONDS) }
+ futures.each { it.get(5, TimeUnit.SECONDS) }
assert service.maxConcurrent.get() > 1
'''
}
@@ -516,6 +517,7 @@ class AsyncTransformTest {
void testHighConcurrencyStressTest() {
assertScript '''
import groovy.transform.Async
+ import java.util.concurrent.TimeUnit
import java.util.concurrent.atomic.AtomicInteger
class Service {
@@ -531,7 +533,7 @@ class AsyncTransformTest {
def service = new Service()
int taskCount = 1000
def futures = (1..taskCount).collect { service.increment() }
- futures.each { it.get(10, java.util.concurrent.TimeUnit.SECONDS) }
+ futures.each { it.get(10, TimeUnit.SECONDS) }
assert service.counter.get() == taskCount
'''
}
@@ -573,9 +575,11 @@ class AsyncTransformTest {
@Test
void testAwaitableAsyncClosure() {
assertScript '''
+ import groovy.concurrent.Awaitable
+
def asyncClosure = async { 42 }
def future = asyncClosure()
- assert future instanceof groovy.concurrent.Awaitable
+ assert future instanceof Awaitable
assert future.get() == 42
'''
}
@@ -653,12 +657,14 @@ class AsyncTransformTest {
@Test
void testAwaitableAwaitFutureInterface() {
assertScript '''
+ import java.util.concurrent.Callable
import java.util.concurrent.Executors
+ import java.util.concurrent.Future
async def doWork() {
def pool = Executors.newSingleThreadExecutor()
try {
- java.util.concurrent.Future<String> future = pool.submit({
"from-executor" } as java.util.concurrent.Callable)
+ Future<String> future = pool.submit({ "from-executor" } as
Callable)
def result = await future
assert result == "from-executor"
result
@@ -715,7 +721,7 @@ class AsyncTransformTest {
class Service {
@Async
Awaitable<String> fetchData() {
- return groovy.concurrent.Awaitable.of("hello")
+ return Awaitable.of("hello")
}
}
'''
@@ -1123,6 +1129,7 @@ class AsyncTransformTest {
import groovy.concurrent.Awaitable
import org.apache.groovy.runtime.async.GroovyPromise
import java.util.concurrent.CompletableFuture
+ import java.util.concurrent.ExecutionException
// Test Awaitable.of()
def a = Awaitable.of("hello")
@@ -1134,7 +1141,7 @@ class AsyncTransformTest {
try {
f.get()
assert false
- } catch (java.util.concurrent.ExecutionException e) {
+ } catch (ExecutionException e) {
assert e.cause.message == "oops"
}
'''
@@ -1180,18 +1187,6 @@ class AsyncTransformTest {
'''
}
- @Test
- void testAwaitableToCompletableFuture() {
- assertScript '''
- import org.apache.groovy.runtime.async.GroovyPromise
- import java.util.concurrent.CompletableFuture
-
- def p =
GroovyPromise.of(CompletableFuture.completedFuture("interop"))
- CompletableFuture<String> cf = p.toCompletableFuture()
- assert cf.get() == "interop"
- '''
- }
-
// ==== AwaitableAdapterRegistry tests ====
@Test
@@ -1294,27 +1289,6 @@ class AsyncTransformTest {
'''
}
- @Test
- void testForAwaitWithBreak() {
- assertScript '''
- import groovy.concurrent.Awaitable
-
- class Processor {
- async findFirst() {
- for await (item in [10, 20, 30, 40]) {
- if (item > 20) {
- return item
- }
- }
- return -1
- }
- }
-
- def p = new Processor()
- assert p.findFirst().get() == 30
- '''
- }
-
@Test
void testForAwaitWithAsyncKeyword() {
assertScript '''
@@ -1644,16 +1618,6 @@ class AsyncTransformTest {
'''
}
- @Test
- void testAsyncStreamEmpty() {
- assertScript '''
- import groovy.concurrent.*
-
- def stream = AsyncStream.empty()
- assert await(stream.moveNext()) == false
- '''
- }
-
@Test
void testAwaitNullReturnsNull() {
assertScript '''
@@ -1692,8 +1656,9 @@ class AsyncTransformTest {
assertScript '''
import groovy.concurrent.Awaitable
import groovy.concurrent.AsyncStream
+ import org.apache.groovy.runtime.async.AsyncSupport
- AsyncStream stream =
org.apache.groovy.runtime.async.AsyncSupport.toAsyncStream(null)
+ AsyncStream stream = AsyncSupport.toAsyncStream(null)
assert await(stream.moveNext()) == false
'''
}
diff --git
a/src/test/groovy/org/codehaus/groovy/transform/AsyncVirtualThreadTest.groovy
b/src/test/groovy/org/codehaus/groovy/transform/AsyncVirtualThreadTest.groovy
index eb4fc5dab0..87f158631d 100644
---
a/src/test/groovy/org/codehaus/groovy/transform/AsyncVirtualThreadTest.groovy
+++
b/src/test/groovy/org/codehaus/groovy/transform/AsyncVirtualThreadTest.groovy
@@ -237,9 +237,11 @@ final class AsyncVirtualThreadTest {
@Test
void testCheckedExceptionConsistencyAcrossAsyncMethods() {
assertScript '''
+ import java.io.IOException
+
class ExcService {
async failWithChecked() {
- throw new java.io.IOException("async method error")
+ throw new IOException("async method error")
}
}
@@ -247,7 +249,7 @@ final class AsyncVirtualThreadTest {
try {
await(svc.failWithChecked())
assert false : "Should have thrown"
- } catch (java.io.IOException e) {
+ } catch (IOException e) {
assert e.message == "async method error"
}
'''
@@ -256,12 +258,14 @@ final class AsyncVirtualThreadTest {
@Test
void testCheckedExceptionConsistencyAcrossClosures() {
assertScript '''
- def asyncIOError = async { throw new java.io.IOException("closure
error") }
+ import java.io.IOException
+
+ def asyncIOError = async { throw new IOException("closure error") }
def awaitable = asyncIOError()
try {
await(awaitable)
assert false : "Should have thrown"
- } catch (java.io.IOException e) {
+ } catch (IOException e) {
assert e.message == "closure error"
}
'''
@@ -270,11 +274,13 @@ final class AsyncVirtualThreadTest {
@Test
void testCheckedExceptionConsistencyAcrossLambdas() {
assertScript '''
- def asyncFn = async { x -> throw new java.io.IOException("lambda
error: ${x}") }
+ import java.io.IOException
+
+ def asyncFn = async { x -> throw new IOException("lambda error:
${x}") }
try {
await(asyncFn("test"))
assert false : "Should have thrown"
- } catch (java.io.IOException e) {
+ } catch (IOException e) {
assert e.message == "lambda error: test"
}
'''
@@ -369,25 +375,27 @@ final class AsyncVirtualThreadTest {
@Test
void testYieldReturnExceptionConsistencyAllForms() {
assertScript '''
+ import java.io.IOException
+
// async method generator with error
class FailGen {
async failing() {
yield return 1
- throw new java.io.IOException("gen method error")
+ throw new IOException("gen method error")
}
}
// async closure generator with error
def asyncFailGen = async {
yield return 10
- throw new java.io.IOException("gen closure error")
+ throw new IOException("gen closure error")
}
def closureFailGen = asyncFailGen()
// async lambda generator with error
def lambdaFailGen = async { x ->
yield return x
- throw new java.io.IOException("gen lambda error")
+ throw new IOException("gen lambda error")
}
// All should propagate IOException through for-await
@@ -396,7 +404,7 @@ final class AsyncVirtualThreadTest {
try {
for await (item in gen) { items << item }
assert false : "Should have thrown"
- } catch (java.io.IOException e) {
+ } catch (IOException e) {
assert e.message.contains("gen")
assert items.size() == 1
}
@@ -411,6 +419,7 @@ final class AsyncVirtualThreadTest {
assertScript '''
import groovy.concurrent.Awaitable
import java.util.concurrent.Executors
+ import org.apache.groovy.runtime.async.AsyncSupport
def pool = Executors.newSingleThreadExecutor({ r ->
def t = new Thread(r)
@@ -418,7 +427,7 @@ final class AsyncVirtualThreadTest {
t
})
- def awaitable =
org.apache.groovy.runtime.async.AsyncSupport.executeAsync({ ->
+ def awaitable = AsyncSupport.executeAsync({ ->
Thread.currentThread().getName()
}, pool)
def result = await(awaitable)
@@ -433,11 +442,12 @@ final class AsyncVirtualThreadTest {
import groovy.concurrent.Awaitable
import java.util.concurrent.Executors
import java.util.concurrent.atomic.AtomicBoolean
+ import org.apache.groovy.runtime.async.AsyncSupport
def pool = Executors.newSingleThreadExecutor()
def executed = new AtomicBoolean(false)
- def awaitable =
org.apache.groovy.runtime.async.AsyncSupport.executeAsyncVoid({ ->
+ def awaitable = AsyncSupport.executeAsyncVoid({ ->
executed.set(true)
}, pool)
def _v1 = await(awaitable)
@@ -636,11 +646,12 @@ final class AsyncVirtualThreadTest {
@Test
void testAwaitWithFuture() {
assertScript '''
+ import java.util.concurrent.Callable
import java.util.concurrent.Executors
import java.util.concurrent.Future
def pool = Executors.newSingleThreadExecutor()
- Future future = pool.submit({ "from future" } as
java.util.concurrent.Callable)
+ Future future = pool.submit({ "from future" } as Callable)
def result = await(future)
assert result == "from future"
pool.shutdown()
@@ -722,22 +733,26 @@ final class AsyncVirtualThreadTest {
@Test
void testDeepUnwrapNestedExceptions() {
assertScript '''
+ import java.io.IOException
+ import java.lang.reflect.InvocationTargetException
+ import java.lang.reflect.UndeclaredThrowableException
+ import java.util.concurrent.CompletableFuture
import java.util.concurrent.CompletionException
import java.util.concurrent.ExecutionException
// Create deeply nested exception chain
- def original = new java.io.IOException("deep")
+ def original = new IOException("deep")
def wrapped = new CompletionException(new ExecutionException(
- new java.lang.reflect.UndeclaredThrowableException(
- new
java.lang.reflect.InvocationTargetException(original))))
+ new UndeclaredThrowableException(
+ new InvocationTargetException(original))))
- def cf = new java.util.concurrent.CompletableFuture()
+ def cf = new CompletableFuture()
cf.completeExceptionally(wrapped)
try {
await(cf)
assert false
- } catch (java.io.IOException e) {
+ } catch (IOException e) {
assert e.message == "deep"
}
'''
@@ -812,6 +827,7 @@ final class AsyncVirtualThreadTest {
import groovy.concurrent.Awaitable
import groovy.concurrent.AwaitableAdapter
import groovy.concurrent.AwaitableAdapterRegistry
+ import org.apache.groovy.runtime.async.AsyncSupport
// Register an adapter for List that provides an AsyncStream
AwaitableAdapterRegistry.register(new AwaitableAdapter() {
@@ -836,7 +852,7 @@ final class AsyncVirtualThreadTest {
})
def results = []
- def stream =
org.apache.groovy.runtime.async.AsyncSupport.toAsyncStream([10, 20, 30])
+ def stream = AsyncSupport.toAsyncStream([10, 20, 30])
for await (item in stream) {
results << item
}
@@ -849,11 +865,12 @@ final class AsyncVirtualThreadTest {
assertScript '''
import groovy.concurrent.Awaitable
import java.util.concurrent.CompletableFuture
+ import java.util.concurrent.CompletionStage
// Test Object overload dispatch for each type
Object a = Awaitable.of("awaitable")
Object b = CompletableFuture.completedFuture("cf")
- Object c = CompletableFuture.completedFuture("stage") as
java.util.concurrent.CompletionStage
+ Object c = CompletableFuture.completedFuture("stage") as
CompletionStage
assert await(a) == "awaitable"
assert await(b) == "cf"
@@ -1071,9 +1088,11 @@ final class AsyncVirtualThreadTest {
@Test
void testYieldReturnOutsideAsyncContextFails() {
assertScript '''
+ import org.apache.groovy.runtime.async.AsyncSupport
+
// yield return outside async context should fail at runtime
try {
-
org.apache.groovy.runtime.async.AsyncSupport.yieldReturn("oops")
+ AsyncSupport.yieldReturn("oops")
assert false : "expected exception"
} catch (IllegalStateException e) {
assert e.message.contains("yield return")