55import org .junit .Test ;
66
77import java .io .IOException ;
8- import java .lang .reflect .Field ;
98import java .nio .file .Files ;
109import java .nio .file .Path ;
11- import java .util .Map ;
1210
1311import static org .hamcrest .CoreMatchers .equalTo ;
1412import static org .hamcrest .CoreMatchers .hasItem ;
1816public 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