File.exists () иногда неправильно в Windows 10 с Java 8.191 - PullRequest
0 голосов
/ 25 января 2019

У меня есть несколько модульных тестов, которые содержат код, подобный следующему:

File file = new File("src/main/java/com/pany/Foo.java");
assertTrue("Missing file: " + file.getAbsolutePath(), file.exists());

Этот тест неожиданно завершается с ошибкой при запуске его с Maven Surefire и -DforkCount=0-DforkCount=1 он работает.

То, что я пробовал до сих пор:

  • Файл существует.Проводник Windows, командная строка (копирование и вставка), текстовые редакторы, Cygwin могут все найти и показать содержимое.Вот почему я думаю, что это не проблема с правами доступа.
  • Он не изменяется модульными тестами или чем-то еще.Git не показывает изменений за последние два месяца.
  • Я проверил файловую систему, она чистая.
  • Я пробовал другие версии Java 8, а именно 8u171 и 8u181.Та же проблема.
  • Я запустил Maven из Cygwin и командной строки.Тот же результат.
  • Перезагрузка :-) Нет эффекта: - (

Подробнее:

  • Когда я вижу эту проблему, я начинаю видеть«В других проектах разорванная виртуальная машина завершилась без должного прощания. Сбой виртуальной машины или вызванный System.exit?». Поэтому я попытался forkCount=0, что часто помогает в этом случае выяснить причину сбоя разветвленной виртуальной машины.
  • Это началось недавно, может быть, в октябре 2018 года, в обновлении Windows 10. До этого сборки работали безупречно в течение трех лет. Я думаю, моя машина была переведена на Windows 10 в конце 2017 года.
  • I 'Я использую Maven 3.6 и не могу легко попробовать старую версию из-за важной ошибки, которая была исправлена ​​с ней. Я видел сбой VM выше и с Maven 3.5.2.
  • Это всегда одни и те же файлыкоторый терпит неудачу (поэтому он стабилен).

ulimit (от Cygwin) говорит:

$ ulimit -a
core file size          (blocks, -c) unlimited
data seg size           (kbytes, -d) unlimited
file size               (blocks, -f) unlimited
open files                      (-n) 256
pipe size            (512 bytes, -p) 8
stack size              (kbytes, -s) 2032
cpu time               (seconds, -t) unlimited
max user processes              (-u) 256
virtual memory          (kbytes, -v) unlimited

Мне интересно, применяется ли ограничение «открытые файлы» 256 толькок процессам Cygwin или это то, что Cygwin прочиталс Windows.

Дайте мне знать, если вам нужно что-нибудь еще.У меня заканчиваются идеи, что я могу попробовать.

Обновление 1

Бернхард попросил меня напечатать абсолютные имена.Мой ответ состоял в том, что я уже использовал абсолютные имена, но я ошибался.Фактический код был:

File file = new File("src/main/java/com/pany/Foo.java");
if (!file.exists()) {
    log.debug("Missing file {}", file.getAbsolutePath());
    ... fail ...
}

... do something with file...

Теперь я изменил это на:

File file = new File("src/main/java/com/pany/Foo.java").getAbsoluteFile();
if (!file.exists()) {
    log.debug("Missing file {}", file);
}

, и это решило проблему.Я просто не могу понять , почему .

Когда Maven создает разветвленную виртуальную машину для запуска тестов с Surefire, он может изменить текущий каталог.Поэтому в этом случае имеет смысл, чтобы тесты работали при разветвлении, но не работали при работе на той же виртуальной машине (поскольку виртуальная машина была создана в корневой папке многомодульной сборки).Но почему перед вызовом exists() устанавливается абсолютный путь?

Ответы [ 3 ]

0 голосов
/ 28 января 2019

Аарон, мы разрабатываем Surefire. Мы можем помочь вам, если вы укажете путь для этого:

assertTrue("Missing file: " + file.getAbsolutePath(), file.exists());

Просьба опубликовать фактический путь, ожидаемый путь и basedir , где находится ваше POM. Теория здесь не поможет. Мы тестируем весь спектр JDK 7-12, но у нас нет комбинации Cygwin + Windows, которую следует учитывать. Настройка кода user.dir в упомянутом вами Surefire существует десятилетие.

0 голосов
/ 03 февраля 2019

Итак, я проверил, распечатав свойства системы, с помощью нескольких простых тестов .

Во время тестов с помощью maven-surefire-plugin user.dir будет изменен на кореньсоответствующий модуль в многокомпонентной сборке.

Но, как я уже говорил, доступно системное свойство basedir, которое можно использовать для правильной обработки местоположения для тестов, которым необходим доступ к ним через File... basedir указывает на местоположение pom.xml соответствующего модуля.

Но, к сожалению, свойство basedir имеет значение , а не , установленное IDEA IntelliJ во время тестового прогона.

Но это можно решить с помощью такой установки:

 private String basedir;

 @Before
 public void before() {
    this.basedir = System.getProperty("basedir", System.getProperty("user.dir", "Need to think about the default value"));
 }

 @Test
 public void testX() {
   File file = new File(this.basedir, "src/main/java/com/pany/Foo.java");
   assertTrue("Missing file: " + file.getAbsolutePath(), file.exists());
 }

Это будет работать в Maven Surefire с -DforkCount=0, а также -DforkCount=1 и в IDE (проверено только в IDEA IntelliJ).).

И да, это проблема в плагине Maven Surefire при изменении user.dir.

Мы можем убедить IDE в поддержке свойства basedir?

0 голосов
/ 25 января 2019

Некоторый фон.У каждого процесса есть понятие «текущий каталог».При запуске из командной строки это каталог, в котором была выполнена команда.При запуске из пользовательского интерфейса обычно это папка, в которой находится программа (файл .exe).

В командной строке или BASH вы можете изменить эту папку с помощью cd для процесса, который запускаеткомандная строка.

Когда Maven создает многомодульный проект, он должен изменить это для каждого модуля (чтобы относительный путь src/main/java/ всегда указывал на правильное место).К сожалению, в Java нигде нет метода «установить текущий каталог».Вы можете указать только один при создании нового процесса и изменить системное свойство user.dir.

. Поэтому new File("a").exists() и new File("a").getAbsoluteFile().exists() работают по-разному.

Последний будет использовать new File(System.getProperty("user.dir"), "a") для определения пути, а первый будет использовать функцию Windows API _wgetdcwd ( docs ), которая, в свою очередь, использует поле процесса Windows для получения текущего каталога - в нашем случае это всегдапапка, в которой изначально был запущен Maven, потому что Java не обновляет поле в процессе, когда кто-то изменяет user.dir, а Maven может изменять это свойство только для «имитации» смены папок.

WinNTFileSystem_md.c вызывает fileToNTPath().Это определено в io_util_md.c и вызывает pathToNTPath().Для относительных путей он будет вызывать currentDirLength(), который вызывает currentDir(), который вызывает _wgetdcwd().

См. Также:

и вот место, где плагин Surefire изменяет свойство user.dir: https://github.com/apache/maven-surefire/blob/56d41b4c903b6c134c5e1a2891f9f08be7e5039f/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/AbstractSurefireMojo.java#L1060

Когда он не разветвляется, он копируется в свойства системы текущей виртуальной машины: https://github.com/apache/maven-surefire/blob/56d41b4c903b6c134c5e1a2891f9f08be7e5039f/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/AbstractSurefireMojo.java#L1133

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...