Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Multiple fixes for federated programs with TypeScript target #1752

Merged
merged 52 commits into from
Jun 3, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
52 commits
Select commit Hold shift + click to select a range
c8d7bb5
Exit with 1 if the RTI is not installed
byeonggiljun May 19, 2023
ba3a8bc
Move failed tests to the failing folder
byeonggiljun May 19, 2023
67def09
Make the CI installs the RTI while tests reactor-ts
byeonggiljun May 19, 2023
d9b5672
Update py-tests.yml
lhstrh May 19, 2023
b68cf19
Update serialization-tests.yml
lhstrh May 19, 2023
e6c7268
Update ts-tests.yml
lhstrh May 19, 2023
0e1285c
Update ci.yml
lhstrh May 19, 2023
4a36a87
Merge branch 'master' into fix-ts-federated-tests
lhstrh May 20, 2023
a31f8f8
See if PR in reactor-c-py addresses test failure
lhstrh May 20, 2023
48f9c39
Update ts-tests.yml
lhstrh May 20, 2023
0c0157b
Minor fix to TS test PingPongDistributed.lf
hokeun May 20, 2023
3b1ad06
Do not overwrite keepAlive of federateConfig with the app parameter (…
hokeun May 20, 2023
946ef5b
Set the default keepAlive of federation to true
byeonggiljun May 20, 2023
ddc6549
Minor fix to TS TestCount.lf
byeonggiljun May 20, 2023
7f8889c
Merge branch 'master' into fix-ts-federated-tests
byeonggiljun May 21, 2023
87b0be5
Update package.json
byeonggiljun May 21, 2023
959ab3c
Point to the branch 'fix-federation' of reactor-ts
byeonggiljun May 21, 2023
441ee02
Move failed test to the failing folder
byeonggiljun May 22, 2023
e529d7c
Merge branch 'master' into fix-ts-federated-tests
byeonggiljun May 22, 2023
dd823e2
Update reactor-c submodule
lhstrh May 22, 2023
ec1afec
Merge branch 'master' into fix-ts-federated-tests
byeonggiljun May 24, 2023
b7bd75b
Update submodule pointer
lhstrh May 24, 2023
eadc552
Merge master into fix-ts-federated-tests
lhstrh May 24, 2023
861636e
Merge branch 'master' into fix-ts-federated-tests
byeonggiljun May 28, 2023
ed2630e
Fix use of wrong API function name.
petervdonovan May 28, 2023
3a1be91
Possibly fix the federated tests on Unix.
petervdonovan May 28, 2023
4983ea9
Update package.json
lhstrh May 28, 2023
05922ff
Update ts-tests.yml
byeonggiljun May 28, 2023
e883169
Merge branch 'master' into fix-ts-federated-tests
byeonggiljun May 28, 2023
4c05b68
Update reactor-c.
petervdonovan May 29, 2023
5b8129b
Use a flag to indicate successful exit.
petervdonovan May 29, 2023
98e33df
Replace lf_request_stop with request_stop.
petervdonovan May 29, 2023
3f5e944
Fix get_start_time issue.
petervdonovan May 29, 2023
83cd35a
Patch over the files property merging.
petervdonovan May 29, 2023
2157755
Merge pull request #1794 from lf-lang/fix-federated-tests2
byeonggiljun May 30, 2023
16448e3
Merge brach 'master' into fix-ts-federated-tests
byeonggiljun May 30, 2023
193a830
Merge branch 'master' into fix-ts-federated-tests
lhstrh May 30, 2023
9ca4410
Compare elapsed logical tag
byeonggiljun May 31, 2023
08023f7
Merge branch 'master' into fix-ts-federated-tests
byeonggiljun May 31, 2023
3b6bfca
Merge branch 'master' into fix-ts-federated-tests
lhstrh May 31, 2023
1d0de2a
Check whether 5 violations are detected or not
byeonggiljun Jun 1, 2023
5fec4ca
Delete test output to avoid running out of memory.
petervdonovan Jun 1, 2023
adc2ea7
Avoid unnecessarily frequent timer triggering.
petervdonovan Jun 1, 2023
d31bc76
Merge branch 'master' into fix-ts-federated-tests
lhstrh Jun 1, 2023
b725fa8
Try again to pass all C tests.
petervdonovan Jun 1, 2023
3b3c517
Address errors in LFTest.java.
petervdonovan Jun 1, 2023
4b09250
Format Python tests.
petervdonovan Jun 1, 2023
8a442ee
Try again to address error in LFTest.java.
petervdonovan Jun 1, 2023
627f88a
Apply formatter.
petervdonovan Jun 1, 2023
13e5fd0
Merge branch 'master' into fix-ts-federated-tests
lhstrh Jun 2, 2023
8487bd7
Merge master into fix-ts-federated-tests
lhstrh Jun 2, 2023
5334d4a
Go back to using StringBuffers.
petervdonovan Jun 3, 2023
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .github/workflows/py-tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,9 @@ jobs:
fetch-depth: 0
- name: Prepare build environment
uses: ./.github/actions/prepare-build-env
- name: Install RTI
uses: ./.github/actions/install-rti
if: ${{ runner.os == 'macOS' || runner.os == 'Linux' }}
- name: Setup Python
uses: actions/setup-python@v4
with:
Expand Down
3 changes: 3 additions & 0 deletions .github/workflows/serialization-tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,9 @@ jobs:
fetch-depth: 0
- name: Prepare build environment
uses: ./.github/actions/prepare-build-env
- name: Install RTI
uses: ./.github/actions/install-rti
if: ${{ runner.os == 'macOS' || runner.os == 'Linux' }}
- name: Setup ROS2
uses: ./.github/actions/setup-ros2
- name: Install Protobuf Ubuntu
Expand Down
6 changes: 5 additions & 1 deletion .github/workflows/ts-tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ jobs:
uses: actions/checkout@v3
with:
fetch-depth: 0
submodules: true
- name: Prepare build environment
uses: ./.github/actions/prepare-build-env
- name: Setup Node.js environment
Expand All @@ -31,9 +32,12 @@ jobs:
run: |
brew install coreutils
if: ${{ runner.os == 'macOS' }}
- name: Install RTI
uses: ./.github/actions/install-rti
if: ${{ runner.os == 'macOS' || runner.os == 'Linux' }}
- name: Perform TypeScript tests
run: |
./gradlew targetTest -Ptarget=TypeScript -Druntime="git://github.com/lf-lang/reactor-ts.git#minor-reorg"
./gradlew targetTest -Ptarget=TypeScript -Druntime="git://github.com/lf-lang/reactor-ts.git#master"
- name: Collect code coverage
run: ./gradlew jacocoTestReport
- name: Report to CodeCov
Expand Down
28 changes: 22 additions & 6 deletions core/src/main/java/org/lflang/TargetProperty.java
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@
import java.util.Arrays;
import java.util.LinkedList;
import java.util.List;
import java.util.Objects;
import java.util.Optional;
import java.util.function.Predicate;
import java.util.stream.Collectors;
Expand Down Expand Up @@ -283,10 +284,6 @@ public enum TargetProperty {
(config, value, err) -> {
config.files = ASTUtils.elementToListOfStrings(value);
},
// FIXME: This merging of lists is potentially dangerous since
// the incoming list of files can belong to a .lf file that is
// located in a different location, and keeping just filename
// strings like this without absolute paths is incorrect.
(config, value, err) -> {
config.files.addAll(ASTUtils.elementToListOfStrings(value));
}),
Expand Down Expand Up @@ -1001,15 +998,34 @@ public static TargetDecl extractTargetDecl(Target target, TargetConfig config) {
*
* @param config The configuration object to update.
* @param properties AST node that holds all the target properties.
* @param relativePath The path from the main resource to the resource from which the new
* properties originate.
*/
public static void update(TargetConfig config, List<KeyValuePair> properties, ErrorReporter err) {
public static void update(
TargetConfig config, List<KeyValuePair> properties, Path relativePath, ErrorReporter err) {
properties.forEach(
property -> {
TargetProperty p = forName(property.getName());
if (p != null) {
// Mark the specified target property as set by the user
config.setByUser.add(p);
p.updater.parseIntoTargetConfig(config, property.getValue(), err);
var value = property.getValue();
if (property.getName().equals("files")) {
var array = LfFactory.eINSTANCE.createArray();
ASTUtils.elementToListOfStrings(property.getValue()).stream()
.map(relativePath::resolve) // assume all paths are relative
.map(Objects::toString)
.map(
s -> {
var element = LfFactory.eINSTANCE.createElement();
element.setLiteral(s);
return element;
})
.forEach(array.getElements()::add);
value = LfFactory.eINSTANCE.createElement();
value.setArray(array);
}
p.updater.parseIntoTargetConfig(config, value, err);
}
});
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -120,7 +120,7 @@ public String generatePreamble(
fast: false,
federateID: %d,
federationID: "Unidentified Federation",
keepAlive: false,
keepAlive: true,
minOutputDelay: %s,
networkMessageActions: [%s],
rtiHost: "%s",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

import static org.lflang.ast.ASTUtils.convertToEmptyListIfNull;

import java.nio.file.Path;
import org.eclipse.emf.ecore.resource.Resource;
import org.lflang.ErrorReporter;
import org.lflang.TargetConfig;
Expand Down Expand Up @@ -57,11 +58,20 @@ private void mergeImportedConfig(
if (targetProperties != null) {
// Merge properties
TargetProperty.update(
this, convertToEmptyListIfNull(targetProperties.getPairs()), errorReporter);
this,
convertToEmptyListIfNull(targetProperties.getPairs()),
getRelativePath(mainResource, federateResource),
errorReporter);
}
}
}

private Path getRelativePath(Resource source, Resource target) {
return Path.of(source.getURI().toFileString())
.getParent()
.relativize(Path.of(target.getURI().toFileString()).getParent());
}

/** Method for the removal of things that should not appear in the target config of a federate. */
private void clearPropertiesToIgnore() {
this.setByUser.remove(TargetProperty.CLOCK_SYNC);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -205,7 +205,8 @@ public void doGenerate(List<FederateInstance> federates, RtiConfig rtiConfig) {
"do",
" wait $pid",
"done",
"echo \"All done.\"")
"echo \"All done.\"",
"EXITED_SUCCESSFULLY=true")
+ "\n");

// Create bin directory for the script.
Expand Down Expand Up @@ -281,24 +282,19 @@ private String getSetupCode() {
"# Set a trap to kill all background jobs on error or control-C",
"# Use two distinct traps so we can see which signal causes this.",
"cleanup() {",
" printf \"Killing federate %s.\\n\" ${pids[*]}",
" # The || true clause means this is not an error if kill fails.",
" kill ${pids[@]} || true",
" printf \"#### Killing RTI %s.\\n\" ${RTI}",
" kill ${RTI} || true",
" exit 1",
"}",
"cleanup_err() {",
" echo \"#### Received ERR signal on line $1. Invoking cleanup().\"",
" cleanup",
"}",
"cleanup_sigint() {",
" echo \"#### Received SIGINT signal on line $1. Invoking cleanup().\"",
" cleanup",
" if [ \"$EXITED_SUCCESSFULLY\" = true ] ; then",
" exit 0",
" else",
" printf \"Killing federate %s.\\n\" ${pids[*]}",
" # The || true clause means this is not an error if kill fails.",
" kill ${pids[@]} || true",
" printf \"#### Killing RTI %s.\\n\" ${RTI}",
" kill ${RTI} || true",
" exit 1",
" fi",
"}",
"",
"trap 'cleanup_err $LINENO' ERR",
"trap 'cleanup_sigint $LINENO' SIGINT",
"trap 'cleanup; exit' EXIT",
"",
"# Create a random 48-byte text ID for this federation.",
"# The likelihood of two federations having the same ID is 1/16,777,216 (1/2^24).",
Expand Down Expand Up @@ -354,7 +350,7 @@ private String getLaunchCode(String rtiLaunchCode) {
" echo \"RTI could not be found.\"",
" echo \"The source code can be obtained from"
+ " https://github.com/lf-lang/reactor-c/tree/main/core/federated/RTI\"",
" exit",
" exit 1",
"fi ",
"# The RTI is started first to allow proper boot-up",
"# before federates will try to connect.",
Expand Down Expand Up @@ -388,7 +384,7 @@ private String getRemoteLaunchCode(
" then",
" echo \"RTI could not be found.\"",
" echo \"The source code can be found in org.lflang/src/lib/core/federated/RTI\"",
" exit",
" exit 1",
" fi",
" " + rtiLaunchString + " 2>&1 | tee -a " + logFileName + "' &",
"# Store the PID of the channel to RTI",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,6 @@ class TSConstructorGenerator(
| }
| federateConfig.federationID = __federationID;
| federateConfig.fast = __fast;
| federateConfig.keepAlive = __keepAlive;
| super(federateConfig, success, fail);
""".trimMargin()
} else {
Expand Down
4 changes: 4 additions & 0 deletions core/src/testFixtures/java/org/lflang/tests/LFTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -258,6 +258,10 @@ private Thread recordStream(StringBuffer builder, InputStream inputStream) {
char[] buf = new char[1024];
while ((len = reader.read(buf)) > 0) {
builder.append(buf, 0, len);
if (Runtime.getRuntime().freeMemory()
< Runtime.getRuntime().totalMemory() * 3 / 4) {
builder.delete(0, builder.length() / 2);
}
}
} catch (IOException e) {
throw new RuntimeIOException(e);
Expand Down
2 changes: 1 addition & 1 deletion core/src/testFixtures/java/org/lflang/tests/TestBase.java
Original file line number Diff line number Diff line change
Expand Up @@ -520,7 +520,7 @@ private void execute(LFTest test) throws TestError {
if (!p.waitFor(MAX_EXECUTION_TIME_SECONDS, TimeUnit.SECONDS)) {
stdout.interrupt();
stderr.interrupt();
p.destroyForcibly();
p.destroy();
throw new TestError(Result.TEST_TIMEOUT);
} else {
if (stdoutException.get() != null || stderrException.get() != null) {
Expand Down
4 changes: 2 additions & 2 deletions test/Python/src/docker/FilesPropertyContainerized.lf
Original file line number Diff line number Diff line change
Expand Up @@ -7,15 +7,15 @@ preamble {=
try:
import hello
except:
lf_request_stop()
request_stop()
=}

main reactor {
preamble {=
try:
import hello
except:
lf_request_stop()
request_stop()
=}
state passed = False
timer t(1 msec)
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/**
* Test for lf_request_stop() in federated execution with decentralized
* Test for request_stop() in federated execution with decentralized
* coordination.
*
* @author Soroush Bateni
Expand Down
2 changes: 1 addition & 1 deletion test/Python/src/federated/CycleDetection.lf
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ reactor UserInput {
self.sys.stderr.write("Did not receive the expected balance. Expected: 200. Got: {}.\n".format(balance.value))
self.sys.exit(1)
print("Balance: {}".format(balance.value))
lf_request_stop()
request_stop()
=}

reaction(shutdown) {= print("Test passed!") =}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,8 @@ reactor Print {
# STP(in, 30 msec);
state success = 0
state success_stp_violation = 0
# Force a timer to be invoke periodically
timer t(0, 10 usec)
# Force a timer to be invoked periodically
timer t(0, 1 msec)
# to ensure logical time will advance in the absence of incoming messages.
state c = 0

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,48 @@ target Python {
}

import Count from "../lib/Count.lf"
import ImportantActuator, Print from "DistributedCountDecentralizedLateDownstream.lf"
import Print from "DistributedCountDecentralizedLateDownstream.lf"

reactor ImportantActuator {
input inp
# Count messages that arrive without STP violation.
state success = 0
state success_stp_violation = 0
# Force a timer to be invoked periodically
timer t(0, 10 usec)
# to ensure logical time will advance in the absence of incoming messages.
state c = 0

reaction(inp) {=
current_tag = lf.tag()
print(f"ImportantActuator: At tag ({lf.tag().time}, {lf.tag().microstep}) received {inp.value}. "
f"Intended tag is ({inp.intended_tag.time - lf.time.start()}, {inp.intended_tag.microstep}).")
if lf.tag() == Tag((SEC(1) * self.c) + + lf.time.start(), 0):
self.success += 1 # Message was on-time
else:
self.sys.stderr.write("Normal reaction was invoked, but current tag doesn't match expected tag.")
self.sys.exit(1)
self.c += 1
=} STP(0) {=
current_tag = lf.tag()
print(f"ImportantActuator: At tag ({lf.time.logical_elapsed()}, {lf.tag().microstep}), message has violated the STP offset "
f"by ({lf.tag().time - inp.intended_tag.time}, {lf.tag().microstep - inp.intended_tag.microstep}).")
self.success_stp_violation += 1
self.c += 1
=}

reaction(t) {=
# Do nothing.
=}

reaction(shutdown) {=
if (self.success + self.success_stp_violation) != 5:
self.sys.stderr.write("Failed to detect STP violation in messages.")
self.sys.exit(1)
else:
print(f"Successfully detected STP violations ({self.success_stp_violation} violations, {self.success} on-time).")
=}
}

reactor Receiver {
input inp
Expand Down
2 changes: 1 addition & 1 deletion test/Python/src/federated/DistributedSendClass.lf
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ preamble {=
reactor A {
input o

reaction(o) {= lf_request_stop() =}
reaction(o) {= request_stop() =}
}

reactor B {
Expand Down
21 changes: 10 additions & 11 deletions test/Python/src/federated/DistributedStop.lf
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
/**
* Test for lf_request_stop() in federated execution with centralized
* coordination.
* Test for request_stop() in federated execution with centralized coordination.
*
* @author Soroush Bateni
*/
Expand All @@ -18,23 +17,23 @@ reactor Sender {
tag = lf.tag()
print("Sending 42 at ({}, {}).".format(
lf.time.logical_elapsed(),
lf.tag().microstep))
tag.microstep))
out.set(42)
if lf.tag().microstep == 0:
if tag.microstep == 0:
# Instead of having a separate reaction
# for 'act' like Stop.lf, we trigger the
# same reaction to test lf_request_stop() being
# same reaction to test request_stop() being
# called multiple times
act.schedule(0)
if tag.time == USEC(1):
# Call lf_request_stop() both at (1 usec, 0) and
if lf.time.logical_elapsed() == USEC(1):
# Call request_stop() both at (1 usec, 0) and
# (1 usec, 1)
print("Requesting stop at ({}, {}).".format(
lf.time.logical_elapsed(),
lf.tag().microstep))
lf_request_stop()
request_stop()

_1usec1 = Tag(time=USEC(1) + get_start_time(), microstep=1)
_1usec1 = Tag(time=USEC(1) + lf.time.start(), microstep=1)
if lf.tag_compare(lf.tag(), _1usec1) == 0:
# The reaction was invoked at (1 usec, 1) as expected
self.reaction_invoked_correctly = True
Expand Down Expand Up @@ -77,12 +76,12 @@ reactor Receiver(
print("Requesting stop at ({}, {}).".format(
lf.time.logical_elapsed(),
lf.tag().microstep))
lf_request_stop()
request_stop()
# The receiver should receive a message at tag
# (1 usec, 1) and trigger this reaction
self.reaction_invoked_correctly = True

_1usec1 = Tag(time=USEC(1) + get_start_time(), microstep=1)
_1usec1 = Tag(time=USEC(1) + lf.time.start(), microstep=1)
if lf.tag_compare(lf.tag(), _1usec1) > 0:
self.reaction_invoked_correctly = False
=}
Expand Down
2 changes: 1 addition & 1 deletion test/Python/src/federated/DistributedStopDecentralized.lf
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/**
* Test for lf_request_stop() in federated execution with decentralized
* Test for request_stop() in federated execution with decentralized
* coordination.
*
* @author Soroush Bateni
Expand Down
Loading