Skip to content

Commit 96e23e3

Browse files
Copilotrubensworks
andauthored
Harden ScriptingData watcher tests against remaining CI timing flakes
Agent-Logs-Url: https://github.com/CyclopsMC/IntegratedScripting/sessions/6ffc475d-616b-4093-84ee-1077ec5095ec Co-authored-by: rubensworks <440384+rubensworks@users.noreply.github.com>
1 parent ccda308 commit 96e23e3

1 file changed

Lines changed: 36 additions & 28 deletions

File tree

src/test/java/org/cyclops/integratedscripting/core/network/ScriptingDataTest.java

Lines changed: 36 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -5,10 +5,8 @@
55
import org.junit.Test;
66

77
import java.io.IOException;
8-
import java.lang.reflect.Field;
98
import java.nio.file.Files;
109
import java.nio.file.Path;
11-
import java.util.Map;
1210

1311
import static org.hamcrest.CoreMatchers.equalTo;
1412
import static org.hamcrest.CoreMatchers.hasItem;
@@ -18,6 +16,7 @@
1816
public class ScriptingDataTest {
1917

2018
private static final int AWAIT_TIMEOUT_MS = 20000;
19+
private static final int ATTEMPT_TIMEOUT_MS = 750;
2120
private static final int POLLING_INTERVAL_MS = 25;
2221

2322
@Test
@@ -26,19 +25,15 @@ public void testExternalUpdatesOnRuntimeCreatedDiskFolderSynced() throws IOExcep
2625
ScriptingData scriptingData = new ScriptingData(rootPath);
2726
try {
2827
scriptingData.initialize();
29-
Path disksPath = rootPath.resolve("scripting-disks");
30-
awaitCondition(() -> isWatcherRegistered(scriptingData, disksPath));
31-
32-
Path diskPath = disksPath.resolve("123");
28+
Path diskPath = rootPath.resolve("scripting-disks").resolve("123");
3329
Files.createDirectories(diskPath);
3430
awaitCondition(() -> scriptingData.getDisks().contains(123));
35-
awaitCondition(() -> isWatcherRegistered(scriptingData, diskPath));
36-
37-
Files.writeString(diskPath.resolve("main.js"), "export const value = 1;");
38-
awaitCondition(() -> "export const value = 1;".equals(scriptingData.getScripts(123).get(Path.of("main.js"))));
3931

32+
Path scriptPath = Path.of("main.js");
33+
int observedValue = writeScriptValueUntilObserved(
34+
scriptingData, 123, diskPath.resolve(scriptPath), scriptPath, 1);
4035
assertThat(scriptingData.getDisks(), hasItem(123));
41-
assertThat(scriptingData.getScripts(123).get(Path.of("main.js")), equalTo("export const value = 1;"));
36+
assertThat(scriptingData.getScripts(123).get(scriptPath), equalTo(scriptValue(observedValue)));
4237
} finally {
4338
scriptingData.close();
4439
FileUtils.deleteDirectory(rootPath.toFile());
@@ -52,42 +47,55 @@ public void testExternalUpdatesOnRuntimeFirstUsedDiskSynced() throws IOException
5247
try {
5348
scriptingData.initialize();
5449
Path diskPath = rootPath.resolve("scripting-disks").resolve("456");
50+
Path scriptPath = Path.of("main.js");
5551

56-
scriptingData.setScript(456, Path.of("main.js"), "export const value = 1;", IScriptingData.ChangeLocation.MEMORY);
52+
scriptingData.setScript(456, scriptPath, scriptValue(1), IScriptingData.ChangeLocation.MEMORY);
5753
scriptingData.tick();
58-
assertTrue(Files.exists(diskPath.resolve("main.js")));
59-
awaitCondition(() -> isWatcherRegistered(scriptingData, diskPath));
54+
assertTrue(Files.exists(diskPath.resolve(scriptPath)));
6055

61-
Files.writeString(diskPath.resolve("main.js"), "export const value = 2;");
62-
awaitCondition(() -> "export const value = 2;".equals(scriptingData.getScripts(456).get(Path.of("main.js"))));
56+
int observedValue = writeScriptValueUntilObserved(
57+
scriptingData, 456, diskPath.resolve(scriptPath), scriptPath, 2);
6358

64-
assertThat(scriptingData.getScripts(456).get(Path.of("main.js")), equalTo("export const value = 2;"));
59+
assertThat(scriptingData.getScripts(456).get(scriptPath), equalTo(scriptValue(observedValue)));
6560
} finally {
6661
scriptingData.close();
6762
FileUtils.deleteDirectory(rootPath.toFile());
6863
}
6964
}
7065

7166
private static void awaitCondition(Condition condition) throws InterruptedException {
72-
long deadline = System.currentTimeMillis() + AWAIT_TIMEOUT_MS;
67+
assertTrue("Timed out waiting for condition", awaitCondition(condition, AWAIT_TIMEOUT_MS));
68+
}
69+
70+
private static boolean awaitCondition(Condition condition, int timeoutMs) throws InterruptedException {
71+
long deadline = System.currentTimeMillis() + timeoutMs;
7372
while (System.currentTimeMillis() < deadline) {
7473
if (condition.matches()) {
75-
return;
74+
return true;
7675
}
7776
Thread.sleep(POLLING_INTERVAL_MS);
7877
}
79-
assertTrue("Timed out waiting for condition", condition.matches());
78+
return condition.matches();
8079
}
8180

82-
private static boolean isWatcherRegistered(ScriptingData scriptingData, Path path) {
83-
try {
84-
Field field = ScriptingData.class.getDeclaredField("pathWatchers");
85-
field.setAccessible(true);
86-
Map<Path, ?> pathWatchers = (Map<Path, ?>) field.get(scriptingData);
87-
return pathWatchers.containsKey(path);
88-
} catch (IllegalAccessException | NoSuchFieldException e) {
89-
throw new RuntimeException(e);
81+
private static int writeScriptValueUntilObserved(ScriptingData scriptingData, int disk, Path scriptPathAbsolute,
82+
Path scriptPathRelative, int startValue) throws IOException, InterruptedException {
83+
int value = startValue;
84+
long deadline = System.currentTimeMillis() + AWAIT_TIMEOUT_MS;
85+
while (System.currentTimeMillis() < deadline) {
86+
String expectedScriptValue = scriptValue(value);
87+
Files.writeString(scriptPathAbsolute, expectedScriptValue);
88+
if (awaitCondition(() -> expectedScriptValue.equals(scriptingData.getScripts(disk).get(scriptPathRelative)),
89+
ATTEMPT_TIMEOUT_MS)) {
90+
return value;
91+
}
92+
value++;
9093
}
94+
throw new AssertionError("Timed out waiting for script update after repeated writes");
95+
}
96+
97+
private static String scriptValue(int value) {
98+
return "export const value = " + value + ";";
9199
}
92100

93101
@FunctionalInterface

0 commit comments

Comments
 (0)