Add DISABLE_PARALLEL_EXECUTION runtime option (#1087)

Add runtime option for sequential command execution
This commit is contained in:
Dmitry Bushev 2020-08-19 08:00:21 +03:00 committed by GitHub
parent 74e56c0d48
commit 6da3b9252f
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 272 additions and 135 deletions

View File

@ -1,11 +1,11 @@
package org.enso.polyglot; package org.enso.polyglot;
import java.util.logging.Level;
import org.graalvm.options.OptionDescriptor; import org.graalvm.options.OptionDescriptor;
import org.graalvm.options.OptionDescriptors; import org.graalvm.options.OptionDescriptors;
import org.graalvm.options.OptionKey; import org.graalvm.options.OptionKey;
import java.util.Arrays; import java.util.Arrays;
import java.util.logging.Level;
/** Class representing runtime options supported by the Enso engine. */ /** Class representing runtime options supported by the Enso engine. */
public class RuntimeOptions { public class RuntimeOptions {
@ -29,13 +29,24 @@ public class RuntimeOptions {
private static final OptionDescriptor LOG_LEVEL_DESCRIPTOR = private static final OptionDescriptor LOG_LEVEL_DESCRIPTOR =
OptionDescriptor.newBuilder(LOG_LEVEL_KEY, LOG_LEVEL).build(); OptionDescriptor.newBuilder(LOG_LEVEL_KEY, LOG_LEVEL).build();
public static final String INTERPRETER_SEQUENTIAL_COMMAND_EXECUTION =
interpreterOptionName(".sequentialCommandExecution");
public static final OptionKey<Boolean> INTERPRETER_SEQUENTIAL_COMMAND_EXECUTION_KEY =
new OptionKey<>(false);
public static final OptionDescriptor INTERPRETER_SEQUENTIAL_COMMAND_EXECUTION_DESCRIPTOR =
OptionDescriptor.newBuilder(
INTERPRETER_SEQUENTIAL_COMMAND_EXECUTION_KEY,
INTERPRETER_SEQUENTIAL_COMMAND_EXECUTION)
.build();
public static final OptionDescriptors OPTION_DESCRIPTORS = public static final OptionDescriptors OPTION_DESCRIPTORS =
OptionDescriptors.create( OptionDescriptors.create(
Arrays.asList( Arrays.asList(
PACKAGES_PATH_DESCRIPTOR, PACKAGES_PATH_DESCRIPTOR,
STRICT_ERRORS_DESCRIPTOR, STRICT_ERRORS_DESCRIPTOR,
LOG_LEVEL_DESCRIPTOR, LOG_LEVEL_DESCRIPTOR,
DISABLE_INLINE_CACHES_DESCRIPTOR)); DISABLE_INLINE_CACHES_DESCRIPTOR,
INTERPRETER_SEQUENTIAL_COMMAND_EXECUTION_DESCRIPTOR));
/** /**
* Canonicalizes the option name by prefixing it with the language name. * Canonicalizes the option name by prefixing it with the language name.
@ -46,4 +57,14 @@ public class RuntimeOptions {
private static String optionName(String name) { private static String optionName(String name) {
return LanguageInfo.ID + "." + name; return LanguageInfo.ID + "." + name;
} }
/**
* Canonicalizes the option name by prefixing it with the 'interpreter' subname.
*
* @param name the simplified option name
* @return the canonicalized representation of the option.
*/
private static String interpreterOptionName(String name) {
return LanguageInfo.ID + ".interpreter." + name;
}
} }

View File

@ -132,6 +132,10 @@ object Runtime {
value = classOf[Api.ExecutionFailed], value = classOf[Api.ExecutionFailed],
name = "executionFailed" name = "executionFailed"
), ),
new JsonSubTypes.Type(
value = classOf[Api.ExecutionSuccessful],
name = "executionSuccessful"
),
new JsonSubTypes.Type( new JsonSubTypes.Type(
value = classOf[Api.VisualisationExpressionFailed], value = classOf[Api.VisualisationExpressionFailed],
name = "visualisationExpressionFailed" name = "visualisationExpressionFailed"
@ -534,6 +538,13 @@ object Runtime {
case class ExecutionFailed(contextId: ContextId, message: String) case class ExecutionFailed(contextId: ContextId, message: String)
extends ApiNotification extends ApiNotification
/**
* Signals that execution of a context was successful.
*
* @param contextId the context's id
*/
case class ExecutionSuccessful(contextId: ContextId) extends ApiNotification
/** /**
* Signals that an expression specified in a [[AttachVisualisation]] or * Signals that an expression specified in a [[AttachVisualisation]] or
* a [[ModifyVisualisation]] cannot be evaluated. * a [[ModifyVisualisation]] cannot be evaluated.

View File

@ -7,8 +7,9 @@ import org.enso.interpreter.instrument.InterpreterContext
import org.enso.interpreter.instrument.command.Command import org.enso.interpreter.instrument.command.Command
import org.enso.interpreter.instrument.execution.Completion.{Done, Interrupted} import org.enso.interpreter.instrument.execution.Completion.{Done, Interrupted}
import org.enso.interpreter.runtime.control.ThreadInterruptedException import org.enso.interpreter.runtime.control.ThreadInterruptedException
import org.enso.polyglot.RuntimeOptions
import scala.concurrent.{ExecutionContext, Future} import scala.concurrent.{ExecutionContext, ExecutionContextExecutor, Future}
import scala.util.control.NonFatal import scala.util.control.NonFatal
import scala.util.{Failure, Success} import scala.util.{Failure, Success}
@ -19,24 +20,40 @@ import scala.util.{Failure, Success}
* @param interpreterContext suppliers of services that provide interpreter * @param interpreterContext suppliers of services that provide interpreter
* specific functionality * specific functionality
*/ */
class CommandExecutionEngine( class CommandExecutionEngine(interpreterContext: InterpreterContext)
interpreterContext: InterpreterContext extends CommandProcessor {
) extends CommandProcessor {
private val context = interpreterContext.executionService.getContext private val isSequential =
interpreterContext.executionService.getContext.getEnvironment.getOptions
private val commandExecutor = Executors.newCachedThreadPool( .get(RuntimeOptions.INTERPRETER_SEQUENTIAL_COMMAND_EXECUTION_KEY)
new TruffleThreadFactory(context, "command-pool") .booleanValue()
)
implicit private val commandExecutionContext =
ExecutionContext.fromExecutor(commandExecutor)
private val locking = new ReentrantLocking private val locking = new ReentrantLocking
private val jobExecutionEngine = private val jobExecutionEngine =
new JobExecutionEngine(interpreterContext, locking) new JobExecutionEngine(interpreterContext, locking)
private val commandExecutor =
if (isSequential) {
interpreterContext.executionService.getLogger.fine(
"Executing commands sequentially"
)
jobExecutionEngine.jobExecutor
} else {
interpreterContext.executionService.getLogger.fine(
"Executing commands in a separate command pool"
)
Executors.newCachedThreadPool(
new TruffleThreadFactory(
interpreterContext.executionService.getContext,
"command-pool"
)
)
}
implicit private val commandExecutionContext: ExecutionContextExecutor =
ExecutionContext.fromExecutor(commandExecutor)
private val runtimeContext = private val runtimeContext =
RuntimeContext( RuntimeContext(
executionService = interpreterContext.executionService, executionService = interpreterContext.executionService,
@ -48,7 +65,7 @@ class CommandExecutionEngine(
locking = locking locking = locking
) )
/** @inheritdoc **/ /** @inheritdoc */
def invoke(cmd: Command): Future[Completion] = { def invoke(cmd: Command): Future[Completion] = {
val logger = runtimeContext.executionService.getLogger val logger = runtimeContext.executionService.getLogger
val doIt = () => val doIt = () =>
@ -80,7 +97,7 @@ class CommandExecutionEngine(
} }
/** @inheritdoc **/ /** @inheritdoc */
override def stop(): Unit = { override def stop(): Unit = {
jobExecutionEngine.stop() jobExecutionEngine.stop()
commandExecutor.shutdownNow() commandExecutor.shutdownNow()

View File

@ -36,7 +36,7 @@ class JobExecutionEngine(
.get(RuntimeServerInfo.JOB_PARALLELISM_KEY) .get(RuntimeServerInfo.JOB_PARALLELISM_KEY)
.intValue() .intValue()
private val jobExecutor = Executors.newFixedThreadPool( val jobExecutor = Executors.newFixedThreadPool(
jobParallelism, jobParallelism,
new TruffleThreadFactory(context, "job-pool") new TruffleThreadFactory(context, "job-pool")
) )
@ -52,7 +52,7 @@ class JobExecutionEngine(
locking = locking locking = locking
) )
/** @inheritdoc * */ /** @inheritdoc */
override def run[A](job: Job[A]): Future[A] = { override def run[A](job: Job[A]): Future[A] = {
val jobId = UUID.randomUUID() val jobId = UUID.randomUUID()
val promise = Promise[A]() val promise = Promise[A]()
@ -78,7 +78,7 @@ class JobExecutionEngine(
promise.future promise.future
} }
/** @inheritdoc * */ /** @inheritdoc */
override def abortAllJobs(): Unit = { override def abortAllJobs(): Unit = {
val allJobs = runningJobsRef.get() val allJobs = runningJobsRef.get()
val cancellableJobs = allJobs.filter(_.job.isCancellable) val cancellableJobs = allJobs.filter(_.job.isCancellable)
@ -89,7 +89,7 @@ class JobExecutionEngine(
.checkInterrupts() .checkInterrupts()
} }
/** @inheritdoc * */ /** @inheritdoc */
override def abortJobs(contextId: UUID): Unit = { override def abortJobs(contextId: UUID): Unit = {
val allJobs = runningJobsRef.get() val allJobs = runningJobsRef.get()
val contextJobs = allJobs.filter(_.job.contextIds.contains(contextId)) val contextJobs = allJobs.filter(_.job.contextIds.contains(contextId))
@ -102,7 +102,7 @@ class JobExecutionEngine(
.checkInterrupts() .checkInterrupts()
} }
/** @inheritdoc * */ /** @inheritdoc */
override def stop(): Unit = { override def stop(): Unit = {
val allJobs = runningJobsRef.get() val allJobs = runningJobsRef.get()
allJobs.foreach(_.future.cancel(true)) allJobs.foreach(_.future.cancel(true))

View File

@ -47,10 +47,12 @@ class ExecuteJob(
errorOrOk match { errorOrOk match {
case Left(e) => case Left(e) =>
ctx.endpoint.sendToClient( ctx.endpoint.sendToClient(
Api.Response(None, Api.ExecutionFailed(contextId, e)) Api.Response(Api.ExecutionFailed(contextId, e))
)
case Right(()) =>
ctx.endpoint.sendToClient(
Api.Response(Api.ExecutionSuccessful(contextId))
) )
case Right(()) => //nop
} }
} finally { } finally {
ctx.executionService.getContext.getThreadManager.leave() ctx.executionService.getContext.getThreadManager.leave()

View File

@ -44,6 +44,7 @@ class RuntimeServerTest
.allowAllAccess(true) .allowAllAccess(true)
.option(RuntimeOptions.PACKAGES_PATH, pkg.root.getAbsolutePath) .option(RuntimeOptions.PACKAGES_PATH, pkg.root.getAbsolutePath)
.option(RuntimeOptions.LOG_LEVEL, "WARNING") .option(RuntimeOptions.LOG_LEVEL, "WARNING")
.option(RuntimeOptions.INTERPRETER_SEQUENTIAL_COMMAND_EXECUTION, "true")
.option(RuntimeServerInfo.ENABLE_OPTION, "true") .option(RuntimeServerInfo.ENABLE_OPTION, "true")
.out(out) .out(out)
.serverTransport { (uri, peer) => .serverTransport { (uri, peer) =>
@ -80,6 +81,10 @@ class RuntimeServerTest
def send(msg: Api.Request): Unit = endPoint.sendBinary(Api.serialize(msg)) def send(msg: Api.Request): Unit = endPoint.sendBinary(Api.serialize(msg))
def receiveNone: Option[Api.Response] = {
Option(messageQueue.poll())
}
def receive: Option[Api.Response] = { def receive: Option[Api.Response] = {
Option(messageQueue.poll(3, TimeUnit.SECONDS)) Option(messageQueue.poll(3, TimeUnit.SECONDS))
} }
@ -94,6 +99,9 @@ class RuntimeServerTest
result.linesIterator.toList result.linesIterator.toList
} }
def executionSuccessful(contextId: UUID): Api.Response =
Api.Response(Api.ExecutionSuccessful(contextId))
object Main { object Main {
val metadata = new Metadata val metadata = new Metadata
@ -304,7 +312,8 @@ class RuntimeServerTest
Api.Response(requestId, Api.PushContextResponse(contextId)), Api.Response(requestId, Api.PushContextResponse(contextId)),
context.Main.Update.mainX(contextId), context.Main.Update.mainX(contextId),
context.Main.Update.mainY(contextId), context.Main.Update.mainY(contextId),
context.Main.Update.mainZ(contextId) context.Main.Update.mainZ(contextId),
context.executionSuccessful(contextId)
) )
// push foo call // push foo call
@ -315,7 +324,8 @@ class RuntimeServerTest
context.receive(4) should contain theSameElementsAs Seq( context.receive(4) should contain theSameElementsAs Seq(
Api.Response(requestId, Api.PushContextResponse(contextId)), Api.Response(requestId, Api.PushContextResponse(contextId)),
context.Main.Update.fooY(contextId), context.Main.Update.fooY(contextId),
context.Main.Update.fooZ(contextId) context.Main.Update.fooZ(contextId),
context.executionSuccessful(contextId)
) )
// push method pointer on top of the non-empty stack // push method pointer on top of the non-empty stack
@ -349,12 +359,13 @@ class RuntimeServerTest
) )
) )
) )
) ),
context.executionSuccessful(contextId)
) )
// pop main // pop main
context.send(Api.Request(requestId, Api.PopContextRequest(contextId))) context.send(Api.Request(requestId, Api.PopContextRequest(contextId)))
context.receive(2) should contain theSameElementsAs Seq( context.receive shouldEqual Some(
Api.Response(requestId, Api.PopContextResponse(contextId)) Api.Response(requestId, Api.PopContextResponse(contextId))
) )
@ -393,7 +404,7 @@ class RuntimeServerTest
context.send( context.send(
Api.Request(Api.OpenFileNotification(mainFile, contents, false)) Api.Request(Api.OpenFileNotification(mainFile, contents, false))
) )
context.receive shouldEqual None context.receiveNone shouldEqual None
// push main // push main
context.send( context.send(
@ -409,7 +420,7 @@ class RuntimeServerTest
) )
) )
) )
context.receive(4) should contain theSameElementsAs Seq( context.receive(5) should contain theSameElementsAs Seq(
Api.Response(requestId, Api.PushContextResponse(contextId)), Api.Response(requestId, Api.PushContextResponse(contextId)),
Api.Response( Api.Response(
Api.ExpressionValuesComputed( Api.ExpressionValuesComputed(
@ -461,7 +472,8 @@ class RuntimeServerTest
) )
) )
) )
) ),
context.executionSuccessful(contextId)
) )
} }
@ -493,7 +505,7 @@ class RuntimeServerTest
context.send( context.send(
Api.Request(Api.OpenFileNotification(mainFile, contents, false)) Api.Request(Api.OpenFileNotification(mainFile, contents, false))
) )
context.receive shouldEqual None context.receiveNone shouldEqual None
// push main // push main
context.send( context.send(
@ -561,12 +573,13 @@ class RuntimeServerTest
) )
) )
) )
) ),
context.executionSuccessful(contextId)
) )
context.consumeOut shouldEqual List("3") context.consumeOut shouldEqual List("3")
} }
it should "Run State getting the initial state" in { it should "run State getting the initial state" in {
val contextId = UUID.randomUUID() val contextId = UUID.randomUUID()
val requestId = UUID.randomUUID() val requestId = UUID.randomUUID()
val moduleName = "Test.Main" val moduleName = "Test.Main"
@ -593,7 +606,7 @@ class RuntimeServerTest
context.send( context.send(
Api.Request(Api.OpenFileNotification(mainFile, contents, false)) Api.Request(Api.OpenFileNotification(mainFile, contents, false))
) )
context.receive shouldEqual None context.receiveNone shouldEqual None
// push main // push main
context.send( context.send(
@ -609,7 +622,7 @@ class RuntimeServerTest
) )
) )
) )
context.receive(4) should contain theSameElementsAs Seq( context.receive(5) should contain theSameElementsAs Seq(
Api.Response(requestId, Api.PushContextResponse(contextId)), Api.Response(requestId, Api.PushContextResponse(contextId)),
Api.Response( Api.Response(
Api.ExpressionValuesComputed( Api.ExpressionValuesComputed(
@ -657,12 +670,13 @@ class RuntimeServerTest
) )
) )
) )
) ),
context.executionSuccessful(contextId)
) )
context.consumeOut shouldEqual List("42") context.consumeOut shouldEqual List("42")
} }
it should "Run State setting the state" in { it should "run State setting the state" in {
val contextId = UUID.randomUUID() val contextId = UUID.randomUUID()
val requestId = UUID.randomUUID() val requestId = UUID.randomUUID()
val moduleName = "Test.Main" val moduleName = "Test.Main"
@ -691,7 +705,7 @@ class RuntimeServerTest
context.send( context.send(
Api.Request(Api.OpenFileNotification(mainFile, contents, false)) Api.Request(Api.OpenFileNotification(mainFile, contents, false))
) )
context.receive shouldEqual None context.receiveNone shouldEqual None
// push main // push main
context.send( context.send(
@ -707,7 +721,7 @@ class RuntimeServerTest
) )
) )
) )
context.receive(4) should contain theSameElementsAs Seq( context.receive(5) should contain theSameElementsAs Seq(
Api.Response(requestId, Api.PushContextResponse(contextId)), Api.Response(requestId, Api.PushContextResponse(contextId)),
Api.Response( Api.Response(
Api.ExpressionValuesComputed( Api.ExpressionValuesComputed(
@ -755,7 +769,8 @@ class RuntimeServerTest
) )
) )
) )
) ),
context.executionSuccessful(contextId)
) )
context.consumeOut shouldEqual List("10") context.consumeOut shouldEqual List("10")
} }
@ -789,7 +804,7 @@ class RuntimeServerTest
context.send( context.send(
Api.Request(Api.OpenFileNotification(mainFile, contents, false)) Api.Request(Api.OpenFileNotification(mainFile, contents, false))
) )
context.receive shouldEqual None context.receiveNone shouldEqual None
// push main // push main
context.send( context.send(
@ -805,7 +820,7 @@ class RuntimeServerTest
) )
) )
) )
context.receive(4) should contain theSameElementsAs Seq( context.receive(5) should contain theSameElementsAs Seq(
Api.Response(requestId, Api.PushContextResponse(contextId)), Api.Response(requestId, Api.PushContextResponse(contextId)),
Api.Response( Api.Response(
Api.ExpressionValuesComputed( Api.ExpressionValuesComputed(
@ -857,7 +872,8 @@ class RuntimeServerTest
) )
) )
) )
) ),
context.executionSuccessful(contextId)
) )
} }
@ -886,7 +902,7 @@ class RuntimeServerTest
context.send( context.send(
Api.Request(Api.OpenFileNotification(mainFile, contents, false)) Api.Request(Api.OpenFileNotification(mainFile, contents, false))
) )
context.receive shouldEqual None context.receiveNone shouldEqual None
// push main // push main
context.send( context.send(
@ -991,7 +1007,8 @@ class RuntimeServerTest
) )
) )
) )
) ),
context.executionSuccessful(contextId)
) )
// push foo call // push foo call
@ -1002,7 +1019,8 @@ class RuntimeServerTest
context.receive(4) should contain theSameElementsAs Seq( context.receive(4) should contain theSameElementsAs Seq(
Api.Response(requestId, Api.PushContextResponse(contextId)), Api.Response(requestId, Api.PushContextResponse(contextId)),
context.Main.Update.fooY(contextId), context.Main.Update.fooY(contextId),
context.Main.Update.fooZ(contextId) context.Main.Update.fooZ(contextId),
context.executionSuccessful(contextId)
) )
// pop foo call // pop foo call
@ -1020,12 +1038,13 @@ class RuntimeServerTest
) )
) )
) )
) ),
context.executionSuccessful(contextId)
) )
// pop main // pop main
context.send(Api.Request(requestId, Api.PopContextRequest(contextId))) context.send(Api.Request(requestId, Api.PopContextRequest(contextId)))
context.receive(2) should contain theSameElementsAs Seq( context.receive(1) should contain theSameElementsAs Seq(
Api.Response(requestId, Api.PopContextResponse(contextId)) Api.Response(requestId, Api.PopContextResponse(contextId))
) )
} }
@ -1057,7 +1076,7 @@ class RuntimeServerTest
context.send( context.send(
Api.Request(Api.OpenFileNotification(mainFile, contents, false)) Api.Request(Api.OpenFileNotification(mainFile, contents, false))
) )
context.receive shouldEqual None context.receiveNone shouldEqual None
// push main // push main
context.send( context.send(
@ -1122,7 +1141,8 @@ class RuntimeServerTest
) )
) )
) )
) ),
context.executionSuccessful(contextId)
) )
context.consumeOut shouldEqual List("1337") context.consumeOut shouldEqual List("1337")
@ -1146,7 +1166,8 @@ class RuntimeServerTest
contextId, contextId,
Vector(Api.ExpressionValueUpdate(idResult, Some("Text"), None)) Vector(Api.ExpressionValueUpdate(idResult, Some("Text"), None))
) )
) ),
context.executionSuccessful(contextId)
) )
context.consumeOut shouldEqual List("Hi") context.consumeOut shouldEqual List("Hi")
} }
@ -1187,7 +1208,7 @@ class RuntimeServerTest
context.send( context.send(
Api.Request(Api.OpenFileNotification(mainFile, contents, false)) Api.Request(Api.OpenFileNotification(mainFile, contents, false))
) )
context.receive shouldEqual None context.receiveNone shouldEqual None
// push main // push main
context.send( context.send(
@ -1299,7 +1320,8 @@ class RuntimeServerTest
) )
) )
) )
) ),
context.executionSuccessful(contextId)
) )
context.consumeOut shouldEqual List("144") context.consumeOut shouldEqual List("144")
@ -1329,7 +1351,8 @@ class RuntimeServerTest
) )
) )
) )
) ),
context.executionSuccessful(contextId)
) )
context.consumeOut shouldEqual List("4") context.consumeOut shouldEqual List("4")
@ -1347,7 +1370,7 @@ class RuntimeServerTest
) )
) )
) )
context.receive shouldEqual None context.receive shouldEqual Some(context.executionSuccessful(contextId))
context.consumeOut shouldEqual List("5") context.consumeOut shouldEqual List("5")
// Edit s/1000.x 5/Main.pie/ // Edit s/1000.x 5/Main.pie/
@ -1376,7 +1399,8 @@ class RuntimeServerTest
) )
) )
) )
) ),
context.executionSuccessful(contextId)
) )
context.consumeOut shouldEqual List("3") context.consumeOut shouldEqual List("3")
@ -1406,7 +1430,8 @@ class RuntimeServerTest
) )
) )
) )
) ),
context.executionSuccessful(contextId)
) )
context.consumeOut shouldEqual List("7") context.consumeOut shouldEqual List("7")
@ -1436,7 +1461,8 @@ class RuntimeServerTest
) )
) )
) )
) ),
context.executionSuccessful(contextId)
) )
context.consumeOut shouldEqual List("hie!") context.consumeOut shouldEqual List("hie!")
@ -1460,7 +1486,8 @@ class RuntimeServerTest
contextId, contextId,
Vector(Api.ExpressionValueUpdate(idMainA, Some("Text"), None)) Vector(Api.ExpressionValueUpdate(idMainA, Some("Text"), None))
) )
) ),
context.executionSuccessful(contextId)
) )
context.consumeOut shouldEqual List("Hello!") context.consumeOut shouldEqual List("Hello!")
} }
@ -1500,7 +1527,7 @@ class RuntimeServerTest
context.send( context.send(
Api.Request(Api.OpenFileNotification(mainFile, contents, false)) Api.Request(Api.OpenFileNotification(mainFile, contents, false))
) )
context.receive shouldEqual None context.receiveNone shouldEqual None
// push main // push main
context.send( context.send(
@ -1635,7 +1662,8 @@ class RuntimeServerTest
) )
) )
) )
) ),
context.executionSuccessful(contextId)
) )
// push call1 // push call1
@ -1649,7 +1677,8 @@ class RuntimeServerTest
) )
) )
context.receive(2) should contain theSameElementsAs Seq( context.receive(2) should contain theSameElementsAs Seq(
Api.Response(requestId, Api.PushContextResponse(contextId)) Api.Response(requestId, Api.PushContextResponse(contextId)),
context.executionSuccessful(contextId)
) )
// pop call1 // pop call1
@ -1691,7 +1720,8 @@ class RuntimeServerTest
) )
) )
) )
) ),
context.executionSuccessful(contextId)
) )
// push call2 // push call2
@ -1705,7 +1735,8 @@ class RuntimeServerTest
) )
) )
context.receive(2) should contain theSameElementsAs Seq( context.receive(2) should contain theSameElementsAs Seq(
Api.Response(requestId, Api.PushContextResponse(contextId)) Api.Response(requestId, Api.PushContextResponse(contextId)),
context.executionSuccessful(contextId)
) )
// pop call2 // pop call2
@ -1747,7 +1778,8 @@ class RuntimeServerTest
) )
) )
) )
) ),
context.executionSuccessful(contextId)
) )
// push call3 // push call3
@ -1761,7 +1793,8 @@ class RuntimeServerTest
) )
) )
context.receive(2) should contain theSameElementsAs Seq( context.receive(2) should contain theSameElementsAs Seq(
Api.Response(requestId, Api.PushContextResponse(contextId)) Api.Response(requestId, Api.PushContextResponse(contextId)),
context.executionSuccessful(contextId)
) )
// pop call3 // pop call3
@ -1803,7 +1836,8 @@ class RuntimeServerTest
) )
) )
) )
) ),
context.executionSuccessful(contextId)
) )
} }
@ -1830,7 +1864,7 @@ class RuntimeServerTest
) )
) )
) )
context.receive shouldEqual None context.receiveNone shouldEqual None
context.consumeOut shouldEqual List() context.consumeOut shouldEqual List()
// Push new item on the stack to trigger the re-execution // Push new item on the stack to trigger the re-execution
@ -1867,7 +1901,8 @@ class RuntimeServerTest
) )
) )
) )
) ),
context.executionSuccessful(contextId)
) )
context.consumeOut shouldEqual List("I'm a file!") context.consumeOut shouldEqual List("I'm a file!")
@ -1885,7 +1920,7 @@ class RuntimeServerTest
) )
) )
) )
context.receive shouldEqual None context.receive shouldEqual Some(context.executionSuccessful(contextId))
context.consumeOut shouldEqual List("I'm a modified!") context.consumeOut shouldEqual List("I'm a modified!")
// Close the file // Close the file
@ -1919,7 +1954,7 @@ class RuntimeServerTest
) )
) )
) )
context.receive shouldEqual None context.receiveNone shouldEqual None
// Push new item on the stack to trigger the re-execution // Push new item on the stack to trigger the re-execution
context.send( context.send(
@ -1936,7 +1971,7 @@ class RuntimeServerTest
) )
) )
) )
context.receive(3) should contain theSameElementsAs Seq( context.receive(4) should contain theSameElementsAs Seq(
Api.Response(requestId, Api.PushContextResponse(contextId)), Api.Response(requestId, Api.PushContextResponse(contextId)),
Api.Response( Api.Response(
Api.ExpressionValuesComputed( Api.ExpressionValuesComputed(
@ -1963,7 +1998,8 @@ class RuntimeServerTest
) )
) )
) )
) ),
context.executionSuccessful(contextId)
) )
// Modify the file // Modify the file
@ -1980,10 +2016,10 @@ class RuntimeServerTest
) )
) )
) )
context.receive shouldEqual None context.receive shouldEqual Some(context.executionSuccessful(contextId))
} }
it should "send suggestion notifications when file executed" in { it should "send suggestion notifications when file is executed" in {
val contextId = UUID.randomUUID() val contextId = UUID.randomUUID()
val requestId = UUID.randomUUID() val requestId = UUID.randomUUID()
val idMain = context.Main.metadata.addItem(7, 47) val idMain = context.Main.metadata.addItem(7, 47)
@ -2013,7 +2049,7 @@ class RuntimeServerTest
) )
) )
) )
context.receive shouldEqual None context.receiveNone shouldEqual None
// push main // push main
val item1 = Api.StackItem.ExplicitCall( val item1 = Api.StackItem.ExplicitCall(
@ -2111,7 +2147,8 @@ class RuntimeServerTest
) )
) )
) )
) ),
context.executionSuccessful(contextId)
) )
// push foo call // push foo call
@ -2122,7 +2159,8 @@ class RuntimeServerTest
context.receive(4) should contain theSameElementsAs Seq( context.receive(4) should contain theSameElementsAs Seq(
Api.Response(requestId, Api.PushContextResponse(contextId)), Api.Response(requestId, Api.PushContextResponse(contextId)),
context.Main.Update.fooY(contextId), context.Main.Update.fooY(contextId),
context.Main.Update.fooZ(contextId) context.Main.Update.fooZ(contextId),
context.executionSuccessful(contextId)
) )
// pop foo call // pop foo call
@ -2140,12 +2178,13 @@ class RuntimeServerTest
) )
) )
) )
) ),
context.executionSuccessful(contextId)
) )
// pop main // pop main
context.send(Api.Request(requestId, Api.PopContextRequest(contextId))) context.send(Api.Request(requestId, Api.PopContextRequest(contextId)))
context.receive(2) should contain theSameElementsAs Seq( context.receive(1) should contain theSameElementsAs Seq(
Api.Response(requestId, Api.PopContextResponse(contextId)) Api.Response(requestId, Api.PopContextResponse(contextId))
) )
@ -2156,7 +2195,7 @@ class RuntimeServerTest
) )
} }
it should "send suggestion notifications when file modified" in { it should "send suggestion notifications when file is modified" in {
val fooFile = new File(context.pkg.sourceDir, "Foo.enso") val fooFile = new File(context.pkg.sourceDir, "Foo.enso")
val contextId = UUID.randomUUID() val contextId = UUID.randomUUID()
val requestId = UUID.randomUUID() val requestId = UUID.randomUUID()
@ -2179,7 +2218,7 @@ class RuntimeServerTest
) )
) )
) )
context.receive shouldEqual None context.receiveNone shouldEqual None
context.consumeOut shouldEqual List() context.consumeOut shouldEqual List()
// Push new item on the stack to trigger the re-execution // Push new item on the stack to trigger the re-execution
@ -2216,7 +2255,8 @@ class RuntimeServerTest
) )
) )
) )
) ),
context.executionSuccessful(contextId)
) )
context.consumeOut shouldEqual List("I'm a file!") context.consumeOut shouldEqual List("I'm a file!")
@ -2255,13 +2295,14 @@ class RuntimeServerTest
) )
) )
) )
) ),
context.executionSuccessful(contextId)
) )
context.consumeOut shouldEqual List("I'm a modified!") context.consumeOut shouldEqual List("I'm a modified!")
// Close the file // Close the file
context.send(Api.Request(Api.CloseFileNotification(fooFile))) context.send(Api.Request(Api.CloseFileNotification(fooFile)))
context.receive shouldEqual None context.receiveNone shouldEqual None
context.consumeOut shouldEqual List() context.consumeOut shouldEqual List()
} }
@ -2289,7 +2330,8 @@ class RuntimeServerTest
Api.Response(requestId, Api.PushContextResponse(contextId)), Api.Response(requestId, Api.PushContextResponse(contextId)),
context.Main.Update.mainX(contextId), context.Main.Update.mainX(contextId),
context.Main.Update.mainY(contextId), context.Main.Update.mainY(contextId),
context.Main.Update.mainZ(contextId) context.Main.Update.mainZ(contextId),
context.executionSuccessful(contextId)
) )
// recompute // recompute
@ -2297,7 +2339,8 @@ class RuntimeServerTest
Api.Request(requestId, Api.RecomputeContextRequest(contextId, None)) Api.Request(requestId, Api.RecomputeContextRequest(contextId, None))
) )
context.receive(2) should contain theSameElementsAs Seq( context.receive(2) should contain theSameElementsAs Seq(
Api.Response(requestId, Api.RecomputeContextResponse(contextId)) Api.Response(requestId, Api.RecomputeContextResponse(contextId)),
context.executionSuccessful(contextId)
) )
} }
@ -2325,7 +2368,8 @@ class RuntimeServerTest
Api.Response(requestId, Api.PushContextResponse(contextId)), Api.Response(requestId, Api.PushContextResponse(contextId)),
context.Main.Update.mainX(contextId), context.Main.Update.mainX(contextId),
context.Main.Update.mainY(contextId), context.Main.Update.mainY(contextId),
context.Main.Update.mainZ(contextId) context.Main.Update.mainZ(contextId),
context.executionSuccessful(contextId)
) )
// recompute // recompute
@ -2339,7 +2383,8 @@ class RuntimeServerTest
) )
) )
context.receive(2) should contain theSameElementsAs Seq( context.receive(2) should contain theSameElementsAs Seq(
Api.Response(requestId, Api.RecomputeContextResponse(contextId)) Api.Response(requestId, Api.RecomputeContextResponse(contextId)),
context.executionSuccessful(contextId)
) )
} }
@ -2367,7 +2412,8 @@ class RuntimeServerTest
Api.Response(requestId, Api.PushContextResponse(contextId)), Api.Response(requestId, Api.PushContextResponse(contextId)),
context.Main.Update.mainX(contextId), context.Main.Update.mainX(contextId),
context.Main.Update.mainY(contextId), context.Main.Update.mainY(contextId),
context.Main.Update.mainZ(contextId) context.Main.Update.mainZ(contextId),
context.executionSuccessful(contextId)
) )
// recompute // recompute
@ -2382,8 +2428,9 @@ class RuntimeServerTest
) )
) )
) )
context.receive(1) should contain theSameElementsAs Seq( context.receive(2) should contain theSameElementsAs Seq(
Api.Response(requestId, Api.RecomputeContextResponse(contextId)) Api.Response(requestId, Api.RecomputeContextResponse(contextId)),
context.executionSuccessful(contextId)
) )
} }
@ -2525,7 +2572,7 @@ class RuntimeServerTest
) )
) )
) )
context.receive(3) should contain theSameElementsAs Seq( context.receive(2) should contain theSameElementsAs Seq(
Api.Response(requestId, Api.PushContextResponse(contextId)), Api.Response(requestId, Api.PushContextResponse(contextId)),
Api.Response( Api.Response(
Api.ExecutionFailed(contextId, "Object 42 is not invokable.") Api.ExecutionFailed(contextId, "Object 42 is not invokable.")
@ -2566,7 +2613,7 @@ class RuntimeServerTest
) )
) )
) )
context.receive(3) should contain theSameElementsAs Seq( context.receive(2) should contain theSameElementsAs Seq(
Api.Response(requestId, Api.PushContextResponse(contextId)), Api.Response(requestId, Api.PushContextResponse(contextId)),
Api.Response(Api.ExecutionFailed(contextId, "Error in function main.")) Api.Response(Api.ExecutionFailed(contextId, "Error in function main."))
) )
@ -2605,7 +2652,7 @@ class RuntimeServerTest
) )
) )
) )
context.receive(3) should contain theSameElementsAs Seq( context.receive(2) should contain theSameElementsAs Seq(
Api.Response(requestId, Api.PushContextResponse(contextId)), Api.Response(requestId, Api.PushContextResponse(contextId)),
Api.Response( Api.Response(
Api.ExecutionFailed( Api.ExecutionFailed(
@ -2646,7 +2693,7 @@ class RuntimeServerTest
) )
) )
) )
context.receive(3) should contain theSameElementsAs Seq( context.receive(2) should contain theSameElementsAs Seq(
Api.Response(requestId, Api.PushContextResponse(contextId)), Api.Response(requestId, Api.PushContextResponse(contextId)),
Api.Response( Api.Response(
Api.ExecutionFailed( Api.ExecutionFailed(
@ -2680,18 +2727,18 @@ class RuntimeServerTest
context.receive(4) should contain theSameElementsAs Seq( context.receive(4) should contain theSameElementsAs Seq(
Api.Response(requestId, Api.PushContextResponse(contextId)), Api.Response(requestId, Api.PushContextResponse(contextId)),
context.Main2.Update.mainY(contextId), context.Main2.Update.mainY(contextId),
context.Main2.Update.mainZ(contextId) context.Main2.Update.mainZ(contextId),
context.executionSuccessful(contextId)
) )
context.consumeOut shouldEqual List("I'm expensive!", "I'm more expensive!") context.consumeOut shouldEqual List("I'm expensive!", "I'm more expensive!")
// recompute // recompute
context.send( context.send(
Api.Request(requestId, Api.RecomputeContextRequest(contextId, None)) Api.Request(requestId, Api.RecomputeContextRequest(contextId, None))
) )
context.receive(2) should contain theSameElementsAs Seq( context.receive(2) should contain theSameElementsAs Seq(
Api.Response(requestId, Api.RecomputeContextResponse(contextId)) Api.Response(requestId, Api.RecomputeContextResponse(contextId)),
context.executionSuccessful(contextId)
) )
context.consumeOut shouldEqual List() context.consumeOut shouldEqual List()
} }
@ -2730,14 +2777,15 @@ class RuntimeServerTest
context.send( context.send(
Api.Request(requestId, Api.PushContextRequest(contextId, item1)) Api.Request(requestId, Api.PushContextRequest(contextId, item1))
) )
context.receive(5) should contain theSameElementsAs Seq( context.receive(5) should contain theSameElementsAs Seq(
Api.Response(requestId, Api.PushContextResponse(contextId)), Api.Response(requestId, Api.PushContextResponse(contextId)),
context.Main.Update.mainX(contextId), context.Main.Update.mainX(contextId),
context.Main.Update.mainY(contextId), context.Main.Update.mainY(contextId),
context.Main.Update.mainZ(contextId) context.Main.Update.mainZ(contextId),
context.executionSuccessful(contextId)
) )
// attach visualisation
context.send( context.send(
Api.Request( Api.Request(
requestId, requestId,
@ -2753,8 +2801,9 @@ class RuntimeServerTest
) )
) )
val attachVisualisationResponses = context.receive(3) val attachVisualisationResponses = context.receive(3)
attachVisualisationResponses should contain( attachVisualisationResponses should contain allOf (
Api.Response(requestId, Api.VisualisationAttached()) Api.Response(requestId, Api.VisualisationAttached()),
context.executionSuccessful(contextId)
) )
val expectedExpressionId = context.Main.idMainX val expectedExpressionId = context.Main.idMainX
val Some(data) = attachVisualisationResponses.collectFirst { val Some(data) = attachVisualisationResponses.collectFirst {
@ -2777,8 +2826,9 @@ class RuntimeServerTest
context.send( context.send(
Api.Request(requestId, Api.RecomputeContextRequest(contextId, None)) Api.Request(requestId, Api.RecomputeContextRequest(contextId, None))
) )
context.receive(2) should contain theSameElementsAs Seq( context.receive(2) should contain allOf (
Api.Response(requestId, Api.RecomputeContextResponse(contextId)) Api.Response(requestId, Api.RecomputeContextResponse(contextId)),
context.executionSuccessful(contextId)
) )
// recompute invalidating x // recompute invalidating x
@ -2794,8 +2844,9 @@ class RuntimeServerTest
) )
) )
val recomputeResponses2 = context.receive(3) val recomputeResponses2 = context.receive(3)
recomputeResponses2 should contain( recomputeResponses2 should contain allOf (
Api.Response(requestId, Api.RecomputeContextResponse(contextId)) Api.Response(requestId, Api.RecomputeContextResponse(contextId)),
context.executionSuccessful(contextId)
) )
val Some(data2) = recomputeResponses2.collectFirst { val Some(data2) = recomputeResponses2.collectFirst {
case Api.Response( case Api.Response(
@ -2838,7 +2889,7 @@ class RuntimeServerTest
context.send( context.send(
Api.Request(Api.OpenFileNotification(mainFile, contents, false)) Api.Request(Api.OpenFileNotification(mainFile, contents, false))
) )
context.receive shouldEqual None context.receiveNone shouldEqual None
// create context // create context
context.send(Api.Request(requestId, Api.CreateContextRequest(contextId))) context.send(Api.Request(requestId, Api.CreateContextRequest(contextId)))
@ -2942,7 +2993,8 @@ class RuntimeServerTest
) )
) )
) )
) ),
context.executionSuccessful(contextId)
) )
// attach visualization // attach visualization
@ -2960,9 +3012,10 @@ class RuntimeServerTest
) )
) )
) )
val attachVisualisationResponses = context.receive(2) val attachVisualisationResponses = context.receive(3)
attachVisualisationResponses should contain( attachVisualisationResponses should contain allOf (
Api.Response(requestId, Api.VisualisationAttached()) Api.Response(requestId, Api.VisualisationAttached()),
context.executionSuccessful(contextId)
) )
val expectedExpressionId = context.Main.idMainX val expectedExpressionId = context.Main.idMainX
val Some(data) = attachVisualisationResponses.collectFirst { val Some(data) = attachVisualisationResponses.collectFirst {
@ -2996,7 +3049,9 @@ class RuntimeServerTest
) )
) )
val Some(data1) = context.receive(1).collectFirst { val editFileResponse = context.receive(2)
editFileResponse should contain(context.executionSuccessful(contextId))
val Some(data1) = editFileResponse.collectFirst {
case Api.Response( case Api.Response(
None, None,
Api.VisualisationUpdate( Api.VisualisationUpdate(
@ -3027,6 +3082,7 @@ class RuntimeServerTest
) )
) )
) )
context.receiveNone shouldEqual None
val contextId = UUID.randomUUID() val contextId = UUID.randomUUID()
val requestId = UUID.randomUUID() val requestId = UUID.randomUUID()
@ -3047,14 +3103,15 @@ class RuntimeServerTest
context.send( context.send(
Api.Request(requestId, Api.PushContextRequest(contextId, item1)) Api.Request(requestId, Api.PushContextRequest(contextId, item1))
) )
context.receive(5) should contain theSameElementsAs Seq( context.receive(5) should contain theSameElementsAs Seq(
Api.Response(requestId, Api.PushContextResponse(contextId)), Api.Response(requestId, Api.PushContextResponse(contextId)),
context.Main.Update.mainX(contextId), context.Main.Update.mainX(contextId),
context.Main.Update.mainY(contextId), context.Main.Update.mainY(contextId),
context.Main.Update.mainZ(contextId) context.Main.Update.mainZ(contextId),
context.executionSuccessful(contextId)
) )
// attach visualisation
context.send( context.send(
Api.Request( Api.Request(
requestId, requestId,
@ -3071,8 +3128,9 @@ class RuntimeServerTest
) )
val attachVisualisationResponses = context.receive(3) val attachVisualisationResponses = context.receive(3)
attachVisualisationResponses should contain( attachVisualisationResponses should contain allOf (
Api.Response(requestId, Api.VisualisationAttached()) Api.Response(requestId, Api.VisualisationAttached()),
context.executionSuccessful(contextId)
) )
val expectedExpressionId = context.Main.idMainX val expectedExpressionId = context.Main.idMainX
val Some(data) = attachVisualisationResponses.collectFirst { val Some(data) = attachVisualisationResponses.collectFirst {
@ -3091,6 +3149,7 @@ class RuntimeServerTest
} }
data.sameElements("6".getBytes) shouldBe true data.sameElements("6".getBytes) shouldBe true
// modify visualisation
context.send( context.send(
Api.Request( Api.Request(
requestId, requestId,
@ -3105,8 +3164,9 @@ class RuntimeServerTest
) )
) )
val modifyVisualisationResponses = context.receive(3) val modifyVisualisationResponses = context.receive(3)
modifyVisualisationResponses should contain( modifyVisualisationResponses should contain allOf (
Api.Response(requestId, Api.VisualisationModified()) Api.Response(requestId, Api.VisualisationModified()),
context.executionSuccessful(contextId)
) )
val Some(dataAfterModification) = val Some(dataAfterModification) =
modifyVisualisationResponses.collectFirst { modifyVisualisationResponses.collectFirst {
@ -3147,10 +3207,11 @@ class RuntimeServerTest
// create context // create context
context.send(Api.Request(requestId, Api.CreateContextRequest(contextId))) context.send(Api.Request(requestId, Api.CreateContextRequest(contextId)))
context.receive(2) should contain theSameElementsAs Seq( context.receive shouldEqual Some(
Api.Response(requestId, Api.CreateContextResponse(contextId)) Api.Response(requestId, Api.CreateContextResponse(contextId))
) )
// attach visualisation
context.send( context.send(
Api.Request( Api.Request(
requestId, requestId,
@ -3165,10 +3226,11 @@ class RuntimeServerTest
) )
) )
) )
context.receive(3) should contain theSameElementsAs Seq( context.receive(2) should contain theSameElementsAs Seq(
Api.Response(requestId, Api.VisualisationAttached()), Api.Response(requestId, Api.VisualisationAttached()),
Api.Response(Api.ExecutionFailed(contextId, "Stack is empty.")) Api.Response(Api.ExecutionFailed(contextId, "Stack is empty."))
) )
// push main // push main
val item1 = Api.StackItem.ExplicitCall( val item1 = Api.StackItem.ExplicitCall(
Api.MethodPointer("Test.Main", "Main", "main"), Api.MethodPointer("Test.Main", "Main", "main"),
@ -3178,14 +3240,33 @@ class RuntimeServerTest
context.send( context.send(
Api.Request(requestId, Api.PushContextRequest(contextId, item1)) Api.Request(requestId, Api.PushContextRequest(contextId, item1))
) )
val pushResponses = context.receive(6)
context.receive(6) should contain allOf ( pushResponses should contain allOf (
Api.Response(requestId, Api.PushContextResponse(contextId)), Api.Response(requestId, Api.PushContextResponse(contextId)),
context.Main.Update.mainX(contextId), context.Main.Update.mainX(contextId),
context.Main.Update.mainY(contextId), context.Main.Update.mainY(contextId),
context.Main.Update.mainZ(contextId), context.Main.Update.mainZ(contextId),
context.executionSuccessful(contextId)
) )
val expectedExpressionId = context.Main.idMainX
val Some(data) =
pushResponses.collectFirst {
case Api.Response(
None,
Api.VisualisationUpdate(
Api.VisualisationContext(
`visualisationId`,
`contextId`,
`expectedExpressionId`
),
data
)
) =>
data
}
util.Arrays.equals(data, "6".getBytes) shouldEqual true
// detach visualisation
context.send( context.send(
Api.Request( Api.Request(
requestId, requestId,
@ -3196,7 +3277,7 @@ class RuntimeServerTest
) )
) )
) )
context.receive shouldBe Some( context.receive shouldEqual Some(
Api.Response(requestId, Api.VisualisationDetached()) Api.Response(requestId, Api.VisualisationDetached())
) )
@ -3205,7 +3286,8 @@ class RuntimeServerTest
Api.Request(requestId, Api.RecomputeContextRequest(contextId, None)) Api.Request(requestId, Api.RecomputeContextRequest(contextId, None))
) )
context.receive(2) should contain theSameElementsAs Seq( context.receive(2) should contain theSameElementsAs Seq(
Api.Response(requestId, Api.RecomputeContextResponse(contextId)) Api.Response(requestId, Api.RecomputeContextResponse(contextId)),
context.executionSuccessful(contextId)
) )
// recompute invalidating x // recompute invalidating x
@ -3221,7 +3303,8 @@ class RuntimeServerTest
) )
) )
context.receive(2) should contain theSameElementsAs Seq( context.receive(2) should contain theSameElementsAs Seq(
Api.Response(requestId, Api.RecomputeContextResponse(contextId)) Api.Response(requestId, Api.RecomputeContextResponse(contextId)),
context.executionSuccessful(contextId)
) )
} }
@ -3254,13 +3337,14 @@ class RuntimeServerTest
Api.Response(requestId, Api.PushContextResponse(contextId)), Api.Response(requestId, Api.PushContextResponse(contextId)),
context.Main.Update.mainX(contextId), context.Main.Update.mainX(contextId),
context.Main.Update.mainY(contextId), context.Main.Update.mainY(contextId),
context.Main.Update.mainZ(contextId) context.Main.Update.mainZ(contextId),
context.executionSuccessful(contextId)
) )
// rename Test -> Foo // rename Test -> Foo
context.pkg.rename("Foo") context.pkg.rename("Foo")
context.send(Api.Request(requestId, Api.RenameProject("Test", "Foo"))) context.send(Api.Request(requestId, Api.RenameProject("Test", "Foo")))
context.receive(2) should contain theSameElementsAs Seq( context.receive(1) should contain theSameElementsAs Seq(
Api.Response(requestId, Api.ProjectRenamed("Foo")) Api.Response(requestId, Api.ProjectRenamed("Foo"))
) )
@ -3269,7 +3353,8 @@ class RuntimeServerTest
Api.Request(requestId, Api.RecomputeContextRequest(contextId, None)) Api.Request(requestId, Api.RecomputeContextRequest(contextId, None))
) )
context.receive(2) should contain theSameElementsAs Seq( context.receive(2) should contain theSameElementsAs Seq(
Api.Response(requestId, Api.RecomputeContextResponse(contextId)) Api.Response(requestId, Api.RecomputeContextResponse(contextId)),
context.executionSuccessful(contextId)
) )
// recompute invalidating all // recompute invalidating all
@ -3282,7 +3367,7 @@ class RuntimeServerTest
) )
) )
) )
context.receive(2) should contain theSameElementsAs Seq( context.receive(3) should contain theSameElementsAs Seq(
Api.Response(requestId, Api.RecomputeContextResponse(contextId)), Api.Response(requestId, Api.RecomputeContextResponse(contextId)),
Api.Response( Api.Response(
Api.ExpressionValuesComputed( Api.ExpressionValuesComputed(
@ -3295,7 +3380,8 @@ class RuntimeServerTest
) )
) )
) )
) ),
context.executionSuccessful(contextId)
) )
} }