Flush queued IDE writes and restart validation after host revision changes
This commit is contained in:
+90
@@ -6,6 +6,96 @@ import java.nio.file.*;
|
||||
import java.util.*;
|
||||
|
||||
public final class IntellijDocumentsTest extends BasePlatformTestCase {
|
||||
/** Keeps real VFS writes queued until its per-file flush executes them. */
|
||||
public void testSaveWaitsForQueuedVfsWrites() throws Exception {
|
||||
var fs = com.intellij.openapi.vfs.LocalFileSystem.getInstance();
|
||||
var executorField = fs.getClass().getDeclaredField("ioTasksExecutor");
|
||||
executorField.setAccessible(true);
|
||||
var executor = executorField.get(fs);
|
||||
var workerField = executor.getClass().getDeclaredField("pendingTasksExecutor");
|
||||
workerField.setAccessible(true);
|
||||
var originalWorker = workerField.get(executor);
|
||||
com.intellij.openapi.vfs.newvfs.ManagingFS.getInstance().flushPendingUpdates();
|
||||
var queuedTasks = new java.util.concurrent.atomic.AtomicInteger();
|
||||
var queued =
|
||||
new java.util.concurrent.AbstractExecutorService() {
|
||||
public void execute(Runnable task) {
|
||||
queuedTasks.incrementAndGet();
|
||||
}
|
||||
|
||||
public void shutdown() {}
|
||||
|
||||
public java.util.List<Runnable> shutdownNow() {
|
||||
return java.util.List.of();
|
||||
}
|
||||
|
||||
public boolean isShutdown() {
|
||||
return false;
|
||||
}
|
||||
|
||||
public boolean isTerminated() {
|
||||
return false;
|
||||
}
|
||||
|
||||
public boolean awaitTermination(long time, java.util.concurrent.TimeUnit unit) {
|
||||
return false;
|
||||
}
|
||||
};
|
||||
Path file = Files.createTempFile("designer-queued-save-", ".fxml");
|
||||
Files.writeString(file, "before");
|
||||
com.intellij.openapi.vfs.newvfs.impl.VfsRootAccess.allowRootAccess(
|
||||
getTestRootDisposable(), file.toRealPath().toString());
|
||||
try (var docs = new IntellijDocuments(getProject());
|
||||
var d = docs.open(file.toUri()).toCompletableFuture().get()) {
|
||||
workerField.set(executor, queued);
|
||||
var changed =
|
||||
d.apply(new EditBatch(0, "edit", List.of(new EditBatch.Replacement(0, 6, "after"))))
|
||||
.toCompletableFuture()
|
||||
.get();
|
||||
var saved = d.save(changed.revision()).toCompletableFuture().get();
|
||||
assertFalse(saved.dirty());
|
||||
assertEquals(
|
||||
"A completed save must be visible to NIO readers", "after", Files.readString(file));
|
||||
assertEquals("after", d.snapshot().toCompletableFuture().get().text());
|
||||
assertTrue("The test must exercise asynchronous VFS writes", queuedTasks.get() > 0);
|
||||
var nativeEdit =
|
||||
d.apply(
|
||||
new EditBatch(
|
||||
saved.revision(),
|
||||
"native save",
|
||||
List.of(new EditBatch.Replacement(0, 5, "native"))))
|
||||
.toCompletableFuture()
|
||||
.get();
|
||||
var virtual = com.intellij.openapi.vfs.LocalFileSystem.getInstance().findFileByNioFile(file);
|
||||
var manager = com.intellij.openapi.fileEditor.FileDocumentManager.getInstance();
|
||||
manager.saveDocument(manager.getDocument(virtual));
|
||||
assertEquals("Native autosave is queued", "after", Files.readString(file));
|
||||
// Simulate editing in IntelliJ's text editor: no adapter apply/refresh in between.
|
||||
com.intellij.openapi.command.WriteCommandAction.runWriteCommandAction(
|
||||
getProject(), () -> manager.getDocument(virtual).setText("followup"));
|
||||
// A second designer host can open after native editing has already begun.
|
||||
// Its initial disk baseline must include the queued native save as well.
|
||||
try (var late = new IntellijDocuments(getProject());
|
||||
var opened = late.open(file.toUri()).toCompletableFuture().get()) {
|
||||
var current = opened.snapshot().toCompletableFuture().get();
|
||||
opened.save(current.revision()).toCompletableFuture().get();
|
||||
assertEquals("followup", Files.readString(file));
|
||||
}
|
||||
var followup = d.snapshot().toCompletableFuture().get();
|
||||
assertTrue(followup.revision() > nativeEdit.revision());
|
||||
d.save(followup.revision()).toCompletableFuture().get();
|
||||
assertEquals("followup", Files.readString(file));
|
||||
assertEquals("followup", d.snapshot().toCompletableFuture().get().text());
|
||||
} finally {
|
||||
try {
|
||||
com.intellij.openapi.vfs.newvfs.ManagingFS.getInstance().flushPendingUpdates();
|
||||
} finally {
|
||||
workerField.set(executor, originalWorker);
|
||||
Files.deleteIfExists(file);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void testNativeDocumentTransactionUndoAndIndependentHandles() throws Exception {
|
||||
Path file = Files.createTempFile("designer-document-", ".fxml");
|
||||
Files.writeString(file, "abcdef");
|
||||
|
||||
Reference in New Issue
Block a user