diff --git a/updater/src/com/intellij/updater/NativeFileManager.java b/updater/src/com/intellij/updater/NativeFileManager.java index e3c298539da8..b60a430dd12f 100644 --- a/updater/src/com/intellij/updater/NativeFileManager.java +++ b/updater/src/com/intellij/updater/NativeFileManager.java @@ -23,7 +23,7 @@ import com.sun.jna.platform.win32.WinNT; import com.sun.jna.ptr.IntByReference; import com.sun.jna.ptr.LongByReference; import com.sun.jna.win32.StdCallLibrary; -import org.jetbrains.annotations.ApiStatus; +import org.jetbrains.annotations.VisibleForTesting; import java.io.File; import java.util.ArrayList; @@ -76,7 +76,7 @@ public final class NativeFileManager { } } - @ApiStatus.Internal + @VisibleForTesting public static List getProcessesUsing(File file, int initialBufferSize) { // If the DLL was not present (XP or other OS), do not try to find it again. if (!ourFailed) { diff --git a/updater/testSrc/com/intellij/updater/NativeFileManagerTest.java b/updater/testSrc/com/intellij/updater/NativeFileManagerTest.java index 9378e41cc484..73594a076b67 100644 --- a/updater/testSrc/com/intellij/updater/NativeFileManagerTest.java +++ b/updater/testSrc/com/intellij/updater/NativeFileManagerTest.java @@ -2,74 +2,65 @@ package com.intellij.updater; import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.io.TempDir; -import java.io.File; import java.io.IOException; import java.nio.charset.StandardCharsets; +import java.nio.file.Files; +import java.nio.file.Path; import java.util.Arrays; import java.util.Scanner; -import java.util.stream.Collectors; import static org.assertj.core.api.Assertions.assertThat; +import static org.junit.jupiter.api.Assumptions.assumeTrue; -public class NativeFileManagerTest { +class NativeFileManagerTest { + @TempDir Path tempDir; - @SuppressWarnings("SSBasedInspection") // suppress inspections about IntelliJ-only API - @Test public void singleProcessHoldsFile() throws IOException, InterruptedException { - if (!Utils.IS_WINDOWS) return; + @Test void singleProcessHoldsFile() throws IOException, InterruptedException { + assumeTrue(Utils.IS_WINDOWS); - var testFile = File.createTempFile("process-locked-test", ".tmp"); + var testFile = Files.writeString(tempDir.resolve("process-locked-test.tmp"), ""); + var process = startProcessHoldingFile(testFile); try { - var process = startProcessHoldingFile(testFile); - try { - var holders = NativeFileManager.getProcessesUsing(testFile).stream() - .map(p -> (long)p.pid).collect(Collectors.toList()); - assertThat(holders).containsExactly(process.pid()); - } finally { + var holders = NativeFileManager.getProcessesUsing(testFile.toFile()).stream().mapToLong(p -> (long)p.pid).toArray(); + assertThat(holders).containsExactly(process.pid()); + } + finally { + process.destroy(); + process.waitFor(); + } + + assertThat(NativeFileManager.getProcessesUsing(testFile.toFile())).isEmpty(); + } + + @Test void moreProcessesThanBufferSize() throws IOException, InterruptedException { + assumeTrue(Utils.IS_WINDOWS); + + var processCount = 5; + var bufferSize = processCount - 1; // check that we still receive all the processes even with smaller buffer size + + var testFile = Files.writeString(tempDir.resolve("process-locked-test.tmp"), ""); + var processes = new Process[processCount]; + for (int i = 0; i < processCount; i++) { + processes[i] = startProcessHoldingFile(testFile); + } + try { + var expectedPids = Arrays.stream(processes).mapToLong(Process::pid).toArray(); + var holders = NativeFileManager.getProcessesUsing(testFile.toFile(), bufferSize).stream().mapToLong(p -> (long)p.pid).toArray(); + assertThat(holders).hasSize(processCount).contains(expectedPids); + } + finally { + for (var process : processes) { process.destroy(); process.waitFor(); } - - assertThat(NativeFileManager.getProcessesUsing(testFile)).isEmpty(); - } finally { - var ignored = testFile.delete(); } + + assertThat(NativeFileManager.getProcessesUsing(testFile.toFile())).isEmpty(); } - @SuppressWarnings("SSBasedInspection") // suppress inspections about IntelliJ-only API - @Test public void moreProcessesThanBufferSize() throws IOException, InterruptedException { - if (!Utils.IS_WINDOWS) return; - - final int processCount = 5; - final int bufferSize = processCount - 1; // check that we still receive all the processes even with smaller buffer size - - var testFile = File.createTempFile("process-locked-test", ".tmp"); - try { - var processes = new Process[processCount]; - for (int i = 0; i < processCount; i++) { - processes[i] = startProcessHoldingFile(testFile); - } - try { - var expectedPids = Arrays.stream(processes).map(Process::pid).collect(Collectors.toList()); - - var holders = NativeFileManager.getProcessesUsing(testFile, bufferSize).stream() - .map(p -> (long)p.pid).collect(Collectors.toList()); - assertThat(holders).hasSize(processCount); - assertThat(holders).containsAll(expectedPids); - } finally { - for (var process : processes) { - process.destroy(); - process.waitFor(); - } - } - - assertThat(NativeFileManager.getProcessesUsing(testFile)).isEmpty(); - } finally { - var ignored = testFile.delete(); - } - } - - private static Process startProcessHoldingFile(File file) throws IOException { + private static Process startProcessHoldingFile(Path file) throws IOException { var command = String.format( "$handle = [IO.File]::Open('%s', [IO.FileMode]::Open, [IO.FileAccess]::ReadWrite, [IO.FileShare]::ReadWrite); Write-Output 'ok'; Start-Sleep 10", file);