Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,9 @@ public void initialize() {
e.printStackTrace();
}

// Register watcher for all disk directories
this.registerAbsolutePathWatcher(disksPath);

// Collect all disk ids
List<Integer> diskIds = Lists.newArrayList();
try {
Expand Down Expand Up @@ -248,6 +251,7 @@ public void setScripts(int disk, Map<Path, String> scripts, ChangeLocation chang
}

// Register watchers for all directories
this.registerPathWatcher(disk, null);
for (Path path : scripts.keySet()) {
this.registerPathWatcher(disk, path.getParent());
}
Expand Down Expand Up @@ -299,9 +303,16 @@ public void setScript(int disk, Path scriptPathRelative, @Nullable String script
protected void registerPathWatcher(int diskId, @Nullable Path pathRelative) {
Path diskPath = getDiskPath(diskId);
Path pathAbsolute = pathRelative == null ? diskPath : diskPath.resolve(pathRelative);
this.registerAbsolutePathWatcher(pathAbsolute);
}

protected void registerAbsolutePathWatcher(Path pathAbsolute) {
if (!pathWatchers.containsKey(pathAbsolute)) {
try {
WatchKey watchKey = pathAbsolute.register(watchService, StandardWatchEventKinds.ENTRY_CREATE, StandardWatchEventKinds.ENTRY_MODIFY, StandardWatchEventKinds.ENTRY_DELETE);
WatchKey watchKey = pathAbsolute.register(watchService,
StandardWatchEventKinds.ENTRY_CREATE,
StandardWatchEventKinds.ENTRY_MODIFY,
StandardWatchEventKinds.ENTRY_DELETE);
pathWatchers.put(pathAbsolute, watchKey);
pathWatchersReverse.put(watchKey, pathAbsolute);
} catch (IOException e) {
Expand Down Expand Up @@ -366,6 +377,8 @@ protected void flushScript(int disk, Path scriptPathRelative) {
} else {
scriptPathAbsolute.getParent().toFile().mkdirs();
FileUtils.write(scriptPathAbsolute.toFile(), script, StandardCharsets.UTF_8);
this.registerPathWatcher(disk, null);
this.registerPathWatcher(disk, scriptPathRelative.getParent());
}
} catch (IOException e) {
e.printStackTrace();
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
package org.cyclops.integratedscripting.core.network;

import org.apache.commons.io.FileUtils;
import org.cyclops.integratedscripting.api.network.IScriptingData;
import org.junit.Test;

import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;

import static org.hamcrest.CoreMatchers.equalTo;
import static org.hamcrest.CoreMatchers.hasItem;
import static org.junit.Assert.assertThat;
import static org.junit.Assert.assertTrue;

public class ScriptingDataTest {

private static final int AWAIT_TIMEOUT_MS = 20000;
private static final int ATTEMPT_TIMEOUT_MS = 750;
private static final int POLLING_INTERVAL_MS = 25;

@Test
public void testExternalUpdatesOnRuntimeCreatedDiskFolderSynced() throws IOException, InterruptedException {
Path rootPath = Files.createTempDirectory("integratedscripting-test");
ScriptingData scriptingData = new ScriptingData(rootPath);
try {
scriptingData.initialize();
Path diskPath = rootPath.resolve("scripting-disks").resolve("123");
Files.createDirectories(diskPath);
awaitCondition(() -> scriptingData.getDisks().contains(123));

Path scriptPath = Path.of("main.js");
int observedValue = writeScriptValueUntilObserved(
scriptingData, 123, diskPath.resolve(scriptPath), scriptPath, 1);
assertThat(scriptingData.getDisks(), hasItem(123));
assertThat(scriptingData.getScripts(123).get(scriptPath), equalTo(scriptValue(observedValue)));
} finally {
scriptingData.close();
FileUtils.deleteDirectory(rootPath.toFile());
}
}

@Test
public void testExternalUpdatesOnRuntimeFirstUsedDiskSynced() throws IOException, InterruptedException {
Path rootPath = Files.createTempDirectory("integratedscripting-test");
ScriptingData scriptingData = new ScriptingData(rootPath);
try {
scriptingData.initialize();
Path diskPath = rootPath.resolve("scripting-disks").resolve("456");
Path scriptPath = Path.of("main.js");

scriptingData.setScript(456, scriptPath, scriptValue(1), IScriptingData.ChangeLocation.MEMORY);
scriptingData.tick();
assertTrue(Files.exists(diskPath.resolve(scriptPath)));

int observedValue = writeScriptValueUntilObserved(
scriptingData, 456, diskPath.resolve(scriptPath), scriptPath, 2);

assertThat(scriptingData.getScripts(456).get(scriptPath), equalTo(scriptValue(observedValue)));
} finally {
scriptingData.close();
FileUtils.deleteDirectory(rootPath.toFile());
}
}

private static void awaitCondition(Condition condition) throws InterruptedException {
assertTrue("Timed out waiting for condition", awaitCondition(condition, AWAIT_TIMEOUT_MS));
}

private static boolean awaitCondition(Condition condition, int timeoutMs) throws InterruptedException {
long deadline = System.currentTimeMillis() + timeoutMs;
while (System.currentTimeMillis() < deadline) {
if (condition.matches()) {
return true;
}
Thread.sleep(POLLING_INTERVAL_MS);
}
return condition.matches();
}

private static int writeScriptValueUntilObserved(ScriptingData scriptingData, int disk, Path scriptPathAbsolute,
Path scriptPathRelative, int startValue) throws IOException, InterruptedException {
int value = startValue;
long deadline = System.currentTimeMillis() + AWAIT_TIMEOUT_MS;
while (System.currentTimeMillis() < deadline) {
String expectedScriptValue = scriptValue(value);
Files.writeString(scriptPathAbsolute, expectedScriptValue);
if (awaitCondition(() -> expectedScriptValue.equals(scriptingData.getScripts(disk).get(scriptPathRelative)),
ATTEMPT_TIMEOUT_MS)) {
return value;
}
value++;
}
throw new AssertionError("Timed out waiting for script update after repeated writes");
}

private static String scriptValue(int value) {
return "export const value = " + value + ";";
}

@FunctionalInterface
private interface Condition {
boolean matches();
}
}
Loading