From 8c1402c39cb168ca1d83012e9065c85c9f153338 Mon Sep 17 00:00:00 2001 From: Stefan Marr Date: Mon, 18 Dec 2017 22:29:38 +0100 Subject: [PATCH 1/2] Replace racy tests with tests based on simpler Actor2 example The PingPong program is racy, and too complex to be a good foundation for tests. Signed-off-by: Stefan Marr --- tools/kompos/tests/actor.ts | 396 +++++++++++--------------- tools/kompos/tests/actor2.ns | 161 +++++++++++ tools/kompos/tests/pingpong.ns | 2 +- tools/kompos/tests/som-integration.ts | 10 +- tools/kompos/tests/test-setup.ts | 2 + 5 files changed, 330 insertions(+), 241 deletions(-) create mode 100644 tools/kompos/tests/actor2.ns diff --git a/tools/kompos/tests/actor.ts b/tools/kompos/tests/actor.ts index ee9205d03..3a4430fdf 100644 --- a/tools/kompos/tests/actor.ts +++ b/tools/kompos/tests/actor.ts @@ -1,6 +1,6 @@ import { expect } from "chai"; import { createSectionBreakpointData, createLineBreakpointData } from "../src/messages"; -import { PING_PONG_URI, TestConnection, ACTOR_URI, TestController, ACTOR_FILE, PING_PONG_FILE } from "./test-setup"; +import { TestConnection, ACTOR_URI, TestController, ACTOR_FILE, ACTOR2_FILE, ACTOR2_URI } from "./test-setup"; import { BreakpointType as BT, SteppingType as ST } from "./somns-support"; import { Test, Stop, expectStops } from "./stepping"; @@ -26,20 +26,6 @@ describe("Actor Stepping", () => { activity: "MyActor" }; - const PingValidate: Stop = { - line: 33, - methodName: "Ping>>#validate:", - stackHeight: 1, - activity: "main" - }; - - const PingPing: Stop = { - line: 23, - methodName: "Ping>>#ping", - stackHeight: 2, - activity: "ping" - }; - const MTFooLine: Stop = { line: 11, methodName: "MyActor>>#foo", @@ -49,36 +35,76 @@ describe("Actor Stepping", () => { const steppingTests: Test[] = [ { - title: "stepping to message receiver", - test: PING_PONG_FILE, + title: "stepping to message receiver on same actor", + test: ACTOR2_FILE, + testArg: "stepToMessageReceiverOnSameActor", initialBreakpoints: [ - createSectionBreakpointData(PING_PONG_URI, 26, 19, 3, BT.MSG_SENDER, true)], + createSectionBreakpointData(ACTOR2_URI, 14, 12, 3, BT.MSG_SENDER, true)], initialStop: { - line: 26, - methodName: "Ping>>#ping", - stackHeight: 2, - activity: "ping" + line: 14, + methodName: "ActA>>#doSelfSend", + stackHeight: 1, + activity: "actA" }, steps: [ { type: ST.STEP_TO_MESSAGE_RECEIVER, - activity: "ping", + activity: "actA", stops: [{ - line: 27, - methodName: "Ping>>#ping", - stackHeight: 2, - activity: "ping" + // we do the step, which is remote and local, so, we stop locally first + line: 15, + methodName: "ActA>>#doSelfSend", + stackHeight: 1, + activity: "actA" }] }, { type: ST.RESUME, - activity: "ping", + activity: "actA", + stops: [{ + // after resuming, we arrive at the actual step target + line: 19, + methodName: "ActA>>#doSelfSend2", + stackHeight: 1, + activity: "actA" + }] + } + ] + }, + { + title: "stepping to message receiver on other actor", + test: ACTOR2_FILE, + testArg: "stepToMessageReceiverOnOtherActor", + initialBreakpoints: [ + createSectionBreakpointData(ACTOR2_URI, 33, 12, 3, BT.MSG_SENDER, true)], + initialStop: { + line: 33, + methodName: "ActB>>#doSendToA", + stackHeight: 1, + activity: "actB" + }, + steps: [ + { + type: ST.STEP_TO_MESSAGE_RECEIVER, + activity: "actB", stops: [{ - line: 33, - methodName: "Ping>>#validate:", + // we do the step, which is remote and local, so, we stop locally first + line: 34, + methodName: "ActB>>#doSendToA", + stackHeight: 1, + activity: "actB" + }, + { + // and then, in parallel, we stop in the remote actor + line: 25, + methodName: "ActA>>#finish", stackHeight: 1, - activity: "ping" + activity: "actA" }] + }, + { + type: ST.RESUME, + activity: "actA" } ] }, @@ -130,36 +156,30 @@ describe("Actor Stepping", () => { }, { title: "returning from turn to promise resolution for self-send", - test: PING_PONG_FILE, - initialBreakpoints: [ - createSectionBreakpointData(PING_PONG_URI, 33, 19, 3, BT.MSG_SENDER, true) - ], - initialStop: PingValidate, + test: ACTOR2_FILE, + testArg: "returnFromTurnToPromiseResolutionForSelfSend", + initialBreakpoints: [createLineBreakpointData(ACTOR2_URI, 49, true)], + initialStop: { + line: 49, + methodName: "ActC>>#msg", + stackHeight: 1, + activity: "ActC" + }, steps: [ { type: ST.RETURN_FROM_TURN_TO_PROMISE_RESOLUTION, - activity: "main", - stops: [PingValidate] - }, - { - type: ST.RESUME, - activity: "main", + activity: "ActC", stops: [{ - line: 27, - methodName: "Ping>>#λping@27@31:", + line: 44, + methodName: "ActC>>#λdoSelfSend@43@23:", stackHeight: 1, - activity: "main" + activity: "ActC" }] }, { type: ST.RESUME, - activity: "main", - stops: [PingValidate] - }, - { - type: ST.RESUME, - activity: "main" - }, + activity: "ActC" + } ] }, { @@ -207,276 +227,182 @@ describe("Actor Stepping", () => { ] }, { - title: "stepping to next turn", - test: PING_PONG_FILE, + title: "stepping to promise resolver on self send", + test: ACTOR2_FILE, + testArg: "stepToMessageReceiverOnSameActor", initialBreakpoints: [ - createSectionBreakpointData(PING_PONG_URI, 23, 14, 3, BT.MSG_SENDER, true) - ], - initialStop: PingPing, + createSectionBreakpointData(ACTOR2_URI, 14, 12, 3, BT.MSG_SENDER, true)], + initialStop: { + line: 14, + methodName: "ActA>>#doSelfSend", + stackHeight: 1, + activity: "ActA" + }, steps: [ { - type: ST.STEP_TO_NEXT_TURN, - activity: "ping", - stops: [{ - line: 56, - methodName: "Ping>>#pong:", + type: ST.STEP_TO_PROMISE_RESOLVER, + activity: "ActA", + stops: [{ // first we step locally, the stop for promise resolver is only in a later turn + line: 15, + methodName: "ActA>>#doSelfSend", stackHeight: 1, - activity: "ping" + activity: "ActA" }] }, { type: ST.RESUME, - activity: "ping", + activity: "ActA", stops: [{ - line: 23, - methodName: "Ping>>#ping", + line: 19, + methodName: "ActA>>#doSelfSend2", stackHeight: 1, - activity: "ping" + activity: "ActA" }] } ] }, - { - title: "stepping to promise resolution", - test: PING_PONG_FILE, - initialBreakpoints: [ - createSectionBreakpointData(PING_PONG_URI, 33, 19, 3, BT.MSG_SENDER, true)], - initialStop: PingValidate, - steps: [ - { - type: ST.STEP_TO_PROMISE_RESOLUTION, - activity: "main", - stops: [{ - line: 34, - methodName: "Ping>>#validate:", - stackHeight: 1, - activity: "main" - }] - }, - { - type: ST.RESUME, - activity: "main", - stops: [PingValidate] - } - ] - }, - { - title: "stepping to promise resolver", - test: PING_PONG_FILE, - initialBreakpoints: [ - createSectionBreakpointData(PING_PONG_URI, 26, 19, 3, BT.MSG_SENDER, true)], - initialStop: { - line: 26, - methodName: "Ping>>#ping", - stackHeight: 2, - activity: "main" - }, - steps: [ - { - type: ST.STEP_TO_PROMISE_RESOLVER, - activity: "main", - stops: [{ - line: 27, - methodName: "Ping>>#ping", - stackHeight: 2, - activity: "main" - }] - }, - { - type: ST.RESUME, - activity: "main", - stops: [PingValidate] - } - ] - }, { title: "stepping to promise resolution for explicit promise", - test: PING_PONG_FILE, - initialBreakpoints: [createLineBreakpointData(PING_PONG_URI, 92, true)], + test: ACTOR2_FILE, + testArg: "stepToResolutionExplicitPromise", + initialBreakpoints: [createLineBreakpointData(ACTOR2_URI, 53, true)], initialStop: { - line: 92, - methodName: "PingPong>>#benchmark", - stackHeight: 6, - activity: "main" + line: 53, + methodName: "ActC>>#makePromise", + stackHeight: 1, + activity: "ActC" }, steps: [ { type: ST.STEP_OVER, - activity: "main", + activity: "ActC", stops: [{ - line: 92, - methodName: "PingPong>>#benchmark", - stackHeight: 6, - activity: "main" + line: 54, + methodName: "ActC>>#makePromise", + stackHeight: 1, + activity: "ActC" }] }, { type: ST.STEP_TO_PROMISE_RESOLUTION, - activity: "main", + activity: "ActC", stops: [{ - line: 93, - methodName: "PingPong>>#benchmark", - stackHeight: 6, - activity: "main" + line: 54, + methodName: "ActC>>#makePromise", + stackHeight: 1, + activity: "ActC" }] }, { type: ST.RESUME, - activity: "main", + activity: "ActC", stops: [{ - line: 98, - methodName: "PingPong>>#λbenchmark@97@44:", + line: 56, + methodName: "ActC>>#λmakePromise@55@32:", stackHeight: 1, - activity: "main" + activity: "ActC" }] } ] }, { title: "stepping to promise resolution for whenResolved", - test: PING_PONG_FILE, - initialBreakpoints: [createLineBreakpointData(PING_PONG_URI, 27, true)], + test: ACTOR2_FILE, + testArg: "stepToResolutionOfWhenResolved", + initialBreakpoints: [createLineBreakpointData(ACTOR2_URI, 66, true)], initialStop: { - line: 27, - methodName: "Ping>>#ping", - activity: "ping", - stackHeight: 2 + line: 66, + methodName: "ActC>>#whenResolved", + activity: "ActC", + stackHeight: 1 }, steps: [ - { - type: ST.STEP_OVER, - activity: "ping", - stops: [{ - line: 27, - methodName: "Ping>>#ping", - activity: "ping", - stackHeight: 2 - }] - }, { type: ST.STEP_TO_PROMISE_RESOLUTION, - activity: "ping", + activity: "ActC", stops: [{ - line: 28, - methodName: "Ping>>#ping", - activity: "ping", - stackHeight: 2 + line: 66, + methodName: "ActC>>#whenResolved", + activity: "ActC", + stackHeight: 1 }] }, { type: ST.RESUME, - activity: "ping", + activity: "ActC", stops: [{ - line: 27, - methodName: "Ping>>#ping", + line: 70, + methodName: "ActC>>#λwhenResolved@69@24:", stackHeight: 1, - activity: "ping" + activity: "ActC" }] } ] }, { title: "stepping to promise resolution for whenResolvedOnError", - test: PING_PONG_FILE, - initialBreakpoints: [createLineBreakpointData(PING_PONG_URI, 34, true)], + test: ACTOR2_FILE, + testArg: "stepToResolutionOfWhenResolvedError", + initialBreakpoints: [createLineBreakpointData(ACTOR2_URI, 79, true)], initialStop: { - line: 34, - methodName: "Ping>>#validate:", - stackHeight: 1, - activity: "ping" + line: 79, + methodName: "ActC>>#whenResolvedError", + activity: "ActC", + stackHeight: 1 }, steps: [ - { - type: ST.STEP_OVER, - activity: "ping", - stops: [{ - line: 34, - methodName: "Ping>>#validate:", - stackHeight: 1, - activity: "ping" - }] - }, { type: ST.STEP_TO_PROMISE_RESOLUTION, - activity: "ping", + activity: "ActC", stops: [{ - line: 35, - methodName: "Ping>>#validate:", - stackHeight: 1, - activity: "ping" + line: 79, + methodName: "ActC>>#whenResolvedError", + activity: "ActC", + stackHeight: 1 }] }, { type: ST.RESUME, - activity: "ping", + activity: "ActC", stops: [{ - line: 34, - methodName: "Ping>>#validate:", + line: 83, + methodName: "ActC>>#λwhenResolvedError@82@24:", stackHeight: 1, - activity: "ping" - }] - }, - { - type: ST.RESUME, - activity: "ping", - stops: [{ - line: 34, - methodName: "Ping>>#validate:", - stackHeight: 1, - activity: "ping" + activity: "ActC" }] } ] }, { title: "stepping to promise resolution for onError", - test: PING_PONG_FILE, - initialBreakpoints: [createLineBreakpointData(PING_PONG_URI, 78, true)], + test: ACTOR2_FILE, + testArg: "stepToResolutionOnError", + initialBreakpoints: [createLineBreakpointData(ACTOR2_URI, 96, true)], initialStop: { - line: 78, - methodName: "Pong>>#stop", - stackHeight: 1, - activity: "pong" + line: 96, + methodName: "ActC>>#onError", + activity: "ActC", + stackHeight: 1 }, steps: [ - { - type: ST.STEP_OVER, - activity: "pong", - stops: [{ - methodName: "Pong>>#stop", - line: 78, - stackHeight: 1, - activity: "pong" - }] - }, { type: ST.STEP_TO_PROMISE_RESOLUTION, - activity: "pong", + activity: "ActC", stops: [{ - methodName: "Pong>>#stop", - line: 79, - stackHeight: 1, - activity: "pong" - }] - }, - { - type: ST.RESUME, - activity: "pong", - stops: [{ - methodName: "Pong>>#λstop@78@27:", - line: 78, - stackHeight: 1, - activity: "pong" + line: 96, + methodName: "ActC>>#onError", + activity: "ActC", + stackHeight: 1 }] }, { type: ST.RESUME, - activity: "pong", + activity: "ActC", stops: [{ - line: 71, - methodName: "Thing>>#println", + line: 100, + methodName: "ActC>>#λonError@99@24:", stackHeight: 1, - activity: "pong" + activity: "ActC" }] } ] diff --git a/tools/kompos/tests/actor2.ns b/tools/kompos/tests/actor2.ns new file mode 100644 index 000000000..968a114ea --- /dev/null +++ b/tools/kompos/tests/actor2.ns @@ -0,0 +1,161 @@ +(* A second little actor system in addition to Actor. + *) +class Actor2 usingPlatform: platform = Value ( +| private actors = platform actors. + private system = platform system. + private Exception = platform kernel Exception. +|)( + + private class ActA new: resolver = ( + | private resolver = resolver. | + )( + public doSelfSend = ( + 'ActA.doSelfSend' println. + self <-: doSelfSend2. + ^ self + ) + + public doSelfSend2 = ( + 'ActA.doSelfSend2' println. + self <-: finish. + ^ self + ) + + public finish = ( + resolver resolve: #done + ) + ) + + private class ActB new: actA = ( + | private actA = actA. | + )( + public doSendToA = ( + actA <-: finish. + ^ self + ) + ) + + private class ActC new: resolver = ( + | private resolver = resolver. | + )( + public doSelfSend = ( + self <-: msg + whenResolved: [:r | + 'doSelfSend whenResolved: ' print. + r println. + resolver resolve: #done. ] + ) + + public msg = ( ^ 42 ) + + public makePromise = ( + | pp | + 'ActC.makePromise' println. + pp:: actors createPromisePair. + pp promise whenResolved: [:r | + 'makePromise whenResolved' println. resolver resolve: #done. ]. + + 'makePromise after whenResolved' println. + + pp resolve: #done. + ) + + public whenResolved = ( + | p p2 | + p:: self <-: msg. + p2:: p whenResolved: [:r | + 'whenResolved whenResolved' println ]. + + p2 whenResolved: [:r | + 'whenResolved whenResolved2' println. + resolver resolve: #done. ]. + + 'whenResolved after whenResolved' println. + ) + + public whenResolvedError = ( + | p p2 | + p:: self <-: msg. + p2:: p whenResolved: [:r | + 'whenResolved whenResolved' println ] onError: [:e| ('-Error: ' + e) println ]. + + p2 whenResolved: [:r | + 'whenResolved whenResolved2' println. + resolver resolve: #done. ]. + + 'whenResolved after whenResolved' println. + ) + + public error = ( + Exception signal. + ) + + public onError = ( + | p p2 | + p:: self <-: error. + p2:: p onError: [:e | + ('-Error: ' + e) println ]. + + p2 whenResolved: [:r | + 'onError whenResolved' println. + resolver resolve: #done. ]. + + 'onError after whenResolved' println. + ) + ) + + public stepToMessageReceiverOnSameActor: completionPP = ( + | a = (actors createActorFromValue: ActA) <-: new: completionPP resolver. | + a <-: doSelfSend. + ) + + public stepToMessageReceiverOnOtherActor: completionPP = ( + | a = (actors createActorFromValue: ActA) <-: new: completionPP resolver. + b = (actors createActorFromValue: ActB) <-: new: a. | + b <-: doSendToA. + ) + + public returnFromTurnToPromiseResolutionForSelfSend: completionPP = ( + | c = (actors createActorFromValue: ActC) <-: new: completionPP resolver. | + c <-: doSelfSend. + ) + + public stepToResolutionExplicitPromise: completionPP = ( + | c = (actors createActorFromValue: ActC) <-: new: completionPP resolver. | + c <-: makePromise. + ) + + public stepToResolutionOfWhenResolved: completionPP = ( + | c = (actors createActorFromValue: ActC) <-: new: completionPP resolver. | + c <-: whenResolved. + ) + + public stepToResolutionOfWhenResolvedError: completionPP = ( + | c = (actors createActorFromValue: ActC) <-: new: completionPP resolver. | + c <-: whenResolvedError. + ) + + public stepToResolutionOnError: completionPP = ( + | c = (actors createActorFromValue: ActC) <-: new: completionPP resolver. | + c <-: onError. + ) + + public main: args = ( + | completionPP a test | + 'Actor breakpoint tests' println. + + completionPP:: actors createPromisePair. + test:: args at: 2. + ('Run test: ' + test) println. + + test = 'stepToMessageReceiverOnSameActor' ifTrue: [ stepToMessageReceiverOnSameActor: completionPP ]. + test = 'stepToMessageReceiverOnOtherActor' ifTrue: [ stepToMessageReceiverOnOtherActor: completionPP ]. + test = 'returnFromTurnToPromiseResolutionForSelfSend' ifTrue: [ returnFromTurnToPromiseResolutionForSelfSend: completionPP ]. + test = 'stepToResolutionExplicitPromise' ifTrue: [ stepToResolutionExplicitPromise: completionPP ]. + test = 'stepToResolutionOfWhenResolved' ifTrue: [ stepToResolutionOfWhenResolved: completionPP ]. + test = 'stepToResolutionOfWhenResolvedError' ifTrue: [ stepToResolutionOfWhenResolvedError: completionPP ]. + test = 'stepToResolutionOnError' ifTrue: [ stepToResolutionOnError: completionPP ]. + + ^ completionPP promise + ) +) diff --git a/tools/kompos/tests/pingpong.ns b/tools/kompos/tests/pingpong.ns index e114774ae..c951cc613 100644 --- a/tools/kompos/tests/pingpong.ns +++ b/tools/kompos/tests/pingpong.ns @@ -1,4 +1,4 @@ -class PingPongApp usingPlatform: platform = Value ( +class PingPong usingPlatform: platform = Value ( | private actors = platform actors. private system = platform system. private Exception = platform kernel Exception. diff --git a/tools/kompos/tests/som-integration.ts b/tools/kompos/tests/som-integration.ts index 8bb5a770e..0a7e5cc54 100644 --- a/tools/kompos/tests/som-integration.ts +++ b/tools/kompos/tests/som-integration.ts @@ -28,8 +28,8 @@ describe("Stack trace output", () => { \tBlock>>#on:do: Kernel.ns::\n\ \tvmMirror>>#exceptionDo:catch:onException: ExceptionDoOnPrimFactory::\n\ \tPlatform>>#λstart@@ Platform.ns::\n\ -\tPingPongApp>>#main: pingpong.ns::\n\ -\tPingPongApp>>#testDNU pingpong.ns::\n\ +\tPingPong>>#main: pingpong.ns::\n\ +\tPingPong>>#testDNU pingpong.ns::\n\ ERROR: MessageNotUnderstood(Integer>>#foobar)\n"); }); @@ -40,8 +40,8 @@ ERROR: MessageNotUnderstood(Integer>>#foobar)\n"); \tBlock>>#on:do: Kernel.ns::\n\ \tvmMirror>>#exceptionDo:catch:onException: ExceptionDoOnPrimFactory::\n\ \tPlatform>>#λstart@@ Platform.ns::\n\ -\tPingPongApp>>#main: pingpong.ns::\n\ -\tPingPongApp>>#testPrintStackTrace pingpong.ns::\n"); +\tPingPong>>#main: pingpong.ns::\n\ +\tPingPong>>#testPrintStackTrace pingpong.ns::\n"); }); }); @@ -64,7 +64,7 @@ describe("Language Debugger Integration", function() { it("should halt on expected source section", () => { return ctrl.stackPs[0].then(msg => { - expectStack(msg.stackFrames, 6, "PingPongApp>>#testHalt", 106); + expectStack(msg.stackFrames, 6, "PingPong>>#testHalt", 106); }); }); }); diff --git a/tools/kompos/tests/test-setup.ts b/tools/kompos/tests/test-setup.ts index 60d7e7002..23a68d5b3 100644 --- a/tools/kompos/tests/test-setup.ts +++ b/tools/kompos/tests/test-setup.ts @@ -19,7 +19,9 @@ export const SOM = SOM_BASEPATH + "som"; export const PING_PONG_FILE = resolve("tests/pingpong.ns"); export const PING_PONG_URI = "file:" + PING_PONG_FILE; export const ACTOR_FILE = resolve("tests/actor.ns") +export const ACTOR2_FILE = resolve("tests/actor2.ns") export const ACTOR_URI = "file:" + ACTOR_FILE; +export const ACTOR2_URI = "file:" + ACTOR2_FILE; const PRINT_SOM_OUTPUT = false; const PRINT_CMD_LINE = false; From fb4e3f5ee9ef0b29d31469191d6a25ddbf892ebd Mon Sep 17 00:00:00 2001 From: Stefan Marr Date: Tue, 19 Dec 2017 09:55:22 +0100 Subject: [PATCH 2/2] Replace ad hoc approach for STM tests with stepping DSL Signed-off-by: Stefan Marr --- tools/kompos/tests/stm.ts | 216 ++++++++++++++++++++++---------------- 1 file changed, 124 insertions(+), 92 deletions(-) diff --git a/tools/kompos/tests/stm.ts b/tools/kompos/tests/stm.ts index eb3efdbcc..4c7946c31 100644 --- a/tools/kompos/tests/stm.ts +++ b/tools/kompos/tests/stm.ts @@ -1,111 +1,143 @@ import { expect } from "chai"; import { resolve } from "path"; -import { BreakpointType, SteppingType } from "./somns-support"; -import { TestConnection, HandleStoppedAndGetStackTrace, expectStack } from "./test-setup"; -import { createSectionBreakpointData, StackTraceResponse } from "../src/messages"; +import { BreakpointType as BT, SteppingType as ST } from "./somns-support"; +import { TestConnection, TestController } from "./test-setup"; +import { createSectionBreakpointData, createLineBreakpointData } from "../src/messages"; +import { Test, expectStops } from "./stepping"; const STM_FILE = resolve("tests/stm.ns"); const STM_URI = "file:" + STM_FILE; describe("Setting STM Breakpoints", () => { let conn: TestConnection; - let ctrl: HandleStoppedAndGetStackTrace; const closeConnectionAfterSuite = (done) => { conn.fullyConnected.then(_ => { conn.close(done); }); conn.fullyConnected.catch(reason => done(reason)); }; - before("Start SOMns and Connect", () => { - const beforeBp = createSectionBreakpointData(STM_URI, 11, 8, 74, - BreakpointType.ATOMIC_BEFORE, true); - const commitBp = createSectionBreakpointData(STM_URI, 11, 8, 74, - BreakpointType.ATOMIC_BEFORE_COMMIT, true); - conn = new TestConnection(null, null, STM_FILE); - ctrl = new HandleStoppedAndGetStackTrace( - [beforeBp, commitBp], conn, conn.fullyConnected, 6); - }); - - after(closeConnectionAfterSuite); - - const thread1 = [ - { s: 6, n: "STM>>#doCount:", l: 11 }, - // line 13 is ok, because the bp uses source section of whole block - { s: 7, n: "STM>>#λdoCount@11@16", l: 13 }, - { s: 6, n: "STM>>#doCount:", l: 17 }, + const steppingTests: Test[] = [ + { + title: "stepping to message receiver on same actor", + test: STM_FILE, + initialBreakpoints: [ + createLineBreakpointData(STM_URI, 39, true), + createSectionBreakpointData(STM_URI, 11, 8, 74, BT.ATOMIC_BEFORE, true), + createSectionBreakpointData(STM_URI, 11, 8, 74, BT.ATOMIC_BEFORE_COMMIT, true)], + initialStop: { + line: 39, + methodName: "STM>>#main:", + stackHeight: 5, + activity: "main" + }, + steps: [ + { + type: ST.RESUME, + activity: "main", + stops: [{ + line: 11, + methodName: "STM>>#doCount:", + stackHeight: 6, + activity: "main" + }, + { + line: 11, + methodName: "STM>>#doCount:", + stackHeight: 2, + activity: "thread2" + }] + }, + { + type: ST.RESUME, + activity: "main", + stops: [{ + line: 13, + methodName: "STM>>#λdoCount@11@16", + stackHeight: 7, + activity: "main" + }] + }, + { + type: ST.RESUME, + activity: "thread2", + stops: [{ + line: 13, + methodName: "STM>>#λdoCount@11@16", + stackHeight: 3, + activity: "thread2" + }] + }, + { + type: ST.STEP_OVER, + activity: "main", + stops: [{ + line: 17, + methodName: "STM>>#doCount:", + stackHeight: 6, + activity: "main" + }] + }, + { + type: ST.RESUME, + activity: "thread2", + stops: [{ + line: 13, + methodName: "STM>>#λdoCount@11@16", + stackHeight: 3, + activity: "thread2" + }] + } + ] + } ]; - const thread2 = [ - { s: 2, n: "STM>>#doCount:", l: 11 }, - { s: 3, n: "STM>>#λdoCount@11@16", l: 13 }, - { s: 3, n: "STM>>#λdoCount@11@16", l: 13 }, - ]; - - let actId = 0; - it("should break on #atomic, 1st time, and resume", () => { - return ctrl.stackPs[0].then(msg => { - actId = msg.activityId; - conn.sendDebuggerAction(SteppingType.RESUME, ctrl.stoppedActivities[msg.requestId]); - - const exp = (msg.activityId === 0 ? thread1 : thread2)[0]; - return expectStack(msg.stackFrames, exp.s, exp.n, exp.l); - }); - }); - - it("should break on #atomic, 2nd time, and resume", () => { - return ctrl.stackPs[1].then(msg => { - expect(msg.activityId).not.equal(actId); - conn.sendDebuggerAction(SteppingType.RESUME, ctrl.stoppedActivities[msg.requestId]); - - const exp = (msg.activityId === 0 ? thread1 : thread2)[0]; - return expectStack(msg.stackFrames, exp.s, exp.n, exp.l); - }); - }); - - let postponedAct = null; - - it("should stop before commit, two times, and single step", () => { - const handler = function(msg: StackTraceResponse) { - if (msg.activityId === 0) { - conn.sendDebuggerAction(SteppingType.STEP_INTO, ctrl.stoppedActivities[msg.requestId]); - } else { - postponedAct = ctrl.stoppedActivities[msg.requestId]; - } - - const exp = (msg.activityId === 0 ? thread1 : thread2)[1]; - return expectStack(msg.stackFrames, exp.s, exp.n, exp.l); - }; - - const p1 = ctrl.stackPs[2].then(msg => { - return handler(msg); - }); - const p2 = ctrl.stackPs[3].then(msg => { - return handler(msg); - }); - return Promise.all([p1, p2]); - }); - - it("1st thread should stop before next operation, 2nd thread should retry transaction", () => { - const handle = function(msg: StackTraceResponse) { - if (msg.activityId === 0) { - console.assert(postponedAct !== null); - conn.sendDebuggerAction(SteppingType.STEP_INTO, postponedAct); - - const exp = thread1[2]; - return expectStack(msg.stackFrames, exp.s, exp.n, exp.l); - } else { - const exp = thread2[2]; - return expectStack(msg.stackFrames, exp.s, exp.n, exp.l); - } - }; - - const p1 = ctrl.stackPs[4].then(msg => { - return handle(msg); - }); - const p2 = ctrl.stackPs[5].then(msg => { - return handle(msg); + for (const suite of steppingTests) { + if (suite.skip) { + describe.skip(suite.title, () => { + if (!suite.steps) { return; } + suite.steps.forEach(step => { + const desc = step.desc ? step.desc : `do ${step.type} on ${step.activity}.`; + it.skip(desc, () => { }); + }); + }); + continue; + } + + describe(suite.title, () => { + let ctrl: TestController; + + before("Start SOMns and Connect", () => { + const arg = suite.testArg ? [suite.testArg] : null; + conn = new TestConnection(arg, false, suite.test); + ctrl = new TestController(suite, conn, conn.fullyConnected); + }); + + after(closeConnectionAfterSuite); + + it("should stop initially at breakpoint", () => { + return ctrl.stopsDoneForStep.then(stops => { + expect(stops).has.lengthOf(1); + expect(stops[0]).to.deep.equal(suite.initialStop); + }); + }); + + + describe("should", () => { + if (!suite.steps) { return; } + + suite.steps.forEach(step => { + const expectedStops = step.stops ? step.stops.length : 0; + const desc = step.desc ? step.desc : `do ${step.type} on ${step.activity} and stop ${expectedStops} times.`; + it(desc, () => { + const stopPs = ctrl.doNextStep(step.type, step.activity, step.stops); + + return stopPs.then(allStops => { + expectStops(allStops, step.stops); + }); + }); + }); + }); }); - return Promise.all([p1, p2]); - }); + } });