Added EvalSession way of controlling all coroutines started from a script
This commit is contained in:
1 parent
446c8d9a6e
commit
fc01016a74
13 files changed
+482
-94
No files matched your search
@@ -0,0 +1,160 @@
|
||||
/*
|
||||
* Copyright 2026 Sergey S. Chernov real.sergeych@gmail.com
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
*/
|
||||
|
||||
import kotlinx.coroutines.async
|
||||
import kotlinx.coroutines.launch
|
||||
import kotlinx.coroutines.test.advanceTimeBy
|
||||
import kotlinx.coroutines.test.runTest
|
||||
import net.sergeych.lyng.EvalSession
|
||||
import net.sergeych.lyng.Scope
|
||||
import net.sergeych.lyng.obj.ObjBool
|
||||
import net.sergeych.lyng.obj.ObjFlow
|
||||
import net.sergeych.lyng.obj.ObjInt
|
||||
import net.sergeych.lyng.obj.ObjList
|
||||
import kotlin.test.*
|
||||
|
||||
class EvalSessionTest {
|
||||
@Test
|
||||
fun sessionCreatesAndReusesScope() = runTest {
|
||||
val session = EvalSession()
|
||||
|
||||
assertEquals(null, session.scope)
|
||||
assertEquals(10L, (session.eval("var x = 10; x") as ObjInt).value)
|
||||
assertNotNull(session.scope)
|
||||
assertEquals(session.scope, session.getScope())
|
||||
assertEquals(15L, (session.eval("x += 5; x") as ObjInt).value)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun sessionCancelStopsLaunchedCoroutines() = runTest {
|
||||
val scope = Scope()
|
||||
val session = EvalSession(scope)
|
||||
|
||||
session.eval(
|
||||
"""
|
||||
var touched = false
|
||||
launch {
|
||||
delay(100)
|
||||
touched = true
|
||||
}
|
||||
"""
|
||||
.trimIndent()
|
||||
)
|
||||
|
||||
session.cancel()
|
||||
session.join()
|
||||
advanceTimeBy(150)
|
||||
|
||||
assertFalse((scope.eval("touched") as ObjBool).value)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun joinObservesWorkStartedByLaterEval() = runTest {
|
||||
val session = EvalSession(Scope())
|
||||
|
||||
session.eval("launch { delay(100) }")
|
||||
|
||||
var joined = false
|
||||
val waiter = launch {
|
||||
session.join()
|
||||
joined = true
|
||||
}
|
||||
|
||||
advanceTimeBy(50)
|
||||
assertFalse(joined)
|
||||
|
||||
session.eval("launch { delay(100) }")
|
||||
|
||||
advanceTimeBy(60)
|
||||
assertFalse(joined)
|
||||
|
||||
advanceTimeBy(50)
|
||||
waiter.join()
|
||||
assertTrue(joined)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun concurrentEvalCallsAreSerialized() = runTest {
|
||||
val session = EvalSession(Scope())
|
||||
|
||||
session.eval("var counter = 0")
|
||||
|
||||
val first = async {
|
||||
session.eval(
|
||||
"""
|
||||
delay(100)
|
||||
counter += 1
|
||||
counter
|
||||
"""
|
||||
.trimIndent()
|
||||
) as ObjInt
|
||||
}
|
||||
val second = async {
|
||||
session.eval(
|
||||
"""
|
||||
counter += 10
|
||||
counter
|
||||
"""
|
||||
.trimIndent()
|
||||
) as ObjInt
|
||||
}
|
||||
|
||||
advanceTimeBy(150)
|
||||
|
||||
assertEquals(1L, first.await().value)
|
||||
assertEquals(11L, second.await().value)
|
||||
assertEquals(11L, (session.eval("counter") as ObjInt).value)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun joinWaitsForActiveFlowProducer() = runTest {
|
||||
val scope = Scope()
|
||||
val session = EvalSession(scope)
|
||||
val flow = session.eval(
|
||||
"""
|
||||
flow {
|
||||
delay(100)
|
||||
emit(1)
|
||||
delay(100)
|
||||
emit(2)
|
||||
}
|
||||
"""
|
||||
.trimIndent()
|
||||
) as ObjFlow
|
||||
|
||||
var joined = false
|
||||
var collected: ObjList? = null
|
||||
|
||||
val collector = launch {
|
||||
collected = flow.callMethod(scope, "toList")
|
||||
}
|
||||
val waiter = launch {
|
||||
session.join()
|
||||
joined = true
|
||||
}
|
||||
|
||||
advanceTimeBy(150)
|
||||
assertFalse(joined)
|
||||
|
||||
advanceTimeBy(100)
|
||||
collector.join()
|
||||
waiter.join()
|
||||
|
||||
assertTrue(joined)
|
||||
assertEquals(listOf(1L, 2L), collected!!.list.map { (it as ObjInt).value })
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user