From 300df6f7d168084d30bd1e7511ba8c5b7ea5f16b Mon Sep 17 00:00:00 2001 From: Caideyipi <87789683+Caideyipi@users.noreply.github.com> Date: Thu, 18 Jun 2026 16:13:52 +0800 Subject: [PATCH] Fix test clean directory deletion (#17860) (cherry picked from commit ddc65546ad65e167214a01f10142ecbae3d5950d) --- .../plugin/PipeDataNodePluginAgentTest.java | 9 +- .../repair/AbstractRepairDataTest.java | 11 +-- .../db/utils/ConfigurationFileUtilsTest.java | 9 +- .../iotdb/db/utils/EnvironmentUtils.java | 88 +++++++++++++++---- .../iotdb/db/utils/EnvironmentUtilsTest.java | 52 +++++++++++ .../iotdb/commons/utils/FileUtilsTest.java | 8 +- 6 files changed, 138 insertions(+), 39 deletions(-) create mode 100644 iotdb-core/datanode/src/test/java/org/apache/iotdb/db/utils/EnvironmentUtilsTest.java diff --git a/iotdb-core/datanode/src/test/java/org/apache/iotdb/db/pipe/agent/plugin/PipeDataNodePluginAgentTest.java b/iotdb-core/datanode/src/test/java/org/apache/iotdb/db/pipe/agent/plugin/PipeDataNodePluginAgentTest.java index ce898fab64a56..034eaa7b8e5bd 100644 --- a/iotdb-core/datanode/src/test/java/org/apache/iotdb/db/pipe/agent/plugin/PipeDataNodePluginAgentTest.java +++ b/iotdb-core/datanode/src/test/java/org/apache/iotdb/db/pipe/agent/plugin/PipeDataNodePluginAgentTest.java @@ -29,6 +29,7 @@ import org.apache.iotdb.db.pipe.sink.protocol.thrift.async.IoTDBDataRegionAsyncSink; import org.apache.iotdb.db.pipe.sink.protocol.thrift.sync.IoTDBDataRegionSyncSink; import org.apache.iotdb.db.pipe.source.dataregion.IoTDBDataRegionSource; +import org.apache.iotdb.db.utils.EnvironmentUtils; import org.apache.iotdb.pipe.api.customizer.parameter.PipeParameters; import org.junit.After; @@ -72,10 +73,10 @@ public void after() { String pluginPath = PipePluginExecutableManager.getInstance() .getPluginsDirPath(PIPE_PLUGIN_META.getPluginName()); - Files.deleteIfExists(Paths.get(pluginPath)); - Files.deleteIfExists(Paths.get(PipePluginExecutableManager.getInstance().getInstallDir())); - Files.deleteIfExists(Paths.get(TMP_TEMP_LIB_ROOT_DIR)); - Files.deleteIfExists(Paths.get(TMP_LIB_ROOT_DIR)); + EnvironmentUtils.cleanDir(pluginPath); + EnvironmentUtils.cleanDir(PipePluginExecutableManager.getInstance().getInstallDir()); + EnvironmentUtils.cleanDir(TMP_TEMP_LIB_ROOT_DIR); + EnvironmentUtils.cleanDir(TMP_LIB_ROOT_DIR); } catch (IOException e) { Assert.fail(); } diff --git a/iotdb-core/datanode/src/test/java/org/apache/iotdb/db/storageengine/dataregion/compaction/repair/AbstractRepairDataTest.java b/iotdb-core/datanode/src/test/java/org/apache/iotdb/db/storageengine/dataregion/compaction/repair/AbstractRepairDataTest.java index 673e7f88106b4..70e4859786b74 100644 --- a/iotdb-core/datanode/src/test/java/org/apache/iotdb/db/storageengine/dataregion/compaction/repair/AbstractRepairDataTest.java +++ b/iotdb-core/datanode/src/test/java/org/apache/iotdb/db/storageengine/dataregion/compaction/repair/AbstractRepairDataTest.java @@ -22,6 +22,7 @@ import org.apache.iotdb.commons.exception.MetadataException; import org.apache.iotdb.db.exception.StorageEngineException; import org.apache.iotdb.db.storageengine.dataregion.compaction.AbstractCompactionTest; +import org.apache.iotdb.db.utils.EnvironmentUtils; import org.apache.iotdb.db.utils.constant.TestConstant; import org.apache.tsfile.exception.write.WriteProcessException; @@ -54,14 +55,6 @@ public File getEmptyRepairDataLogDir() throws IOException { } private void deleteRepairDataLogDir() throws IOException { - if (repairDataLogDir.exists()) { - if (repairDataLogDir.isDirectory()) { - File[] files = repairDataLogDir.listFiles(); - for (File file : files == null ? new File[] {} : files) { - Files.deleteIfExists(file.toPath()); - } - } - Files.deleteIfExists(repairDataLogDir.toPath()); - } + EnvironmentUtils.cleanDir(repairDataLogDir.getPath()); } } diff --git a/iotdb-core/datanode/src/test/java/org/apache/iotdb/db/utils/ConfigurationFileUtilsTest.java b/iotdb-core/datanode/src/test/java/org/apache/iotdb/db/utils/ConfigurationFileUtilsTest.java index 89ef66db38565..39f078b440d90 100644 --- a/iotdb-core/datanode/src/test/java/org/apache/iotdb/db/utils/ConfigurationFileUtilsTest.java +++ b/iotdb-core/datanode/src/test/java/org/apache/iotdb/db/utils/ConfigurationFileUtilsTest.java @@ -30,7 +30,6 @@ import java.io.FileReader; import java.io.IOException; import java.nio.file.Files; -import java.util.Objects; import java.util.Properties; public class ConfigurationFileUtilsTest { @@ -40,13 +39,7 @@ public class ConfigurationFileUtilsTest { @After public void tearDown() throws IOException { - if (!dir.exists()) { - return; - } - for (File file : Objects.requireNonNull(dir.listFiles())) { - Files.delete(file.toPath()); - } - Files.delete(dir.toPath()); + EnvironmentUtils.cleanDir(dir.getPath()); } @Test diff --git a/iotdb-core/datanode/src/test/java/org/apache/iotdb/db/utils/EnvironmentUtils.java b/iotdb-core/datanode/src/test/java/org/apache/iotdb/db/utils/EnvironmentUtils.java index 1291540be05b5..aaac69f757a6c 100644 --- a/iotdb-core/datanode/src/test/java/org/apache/iotdb/db/utils/EnvironmentUtils.java +++ b/iotdb-core/datanode/src/test/java/org/apache/iotdb/db/utils/EnvironmentUtils.java @@ -51,7 +51,6 @@ import org.apache.iotdb.rpc.TSocketWrapper; import org.apache.iotdb.udf.api.exception.UDFManagementException; -import org.apache.commons.io.FileUtils; import org.apache.thrift.TConfiguration; import org.apache.thrift.transport.TTransport; import org.apache.thrift.transport.TTransportException; @@ -68,6 +67,12 @@ import java.io.IOException; import java.net.InetSocketAddress; import java.net.Socket; +import java.nio.file.FileVisitResult; +import java.nio.file.Files; +import java.nio.file.NoSuchFileException; +import java.nio.file.Path; +import java.nio.file.SimpleFileVisitor; +import java.nio.file.attribute.BasicFileAttributes; import java.util.concurrent.TimeUnit; import static org.junit.Assert.fail; @@ -80,6 +85,8 @@ public class EnvironmentUtils { private static final IoTDBConfig config = IoTDBDescriptor.getInstance().getConfig(); private static final CommonConfig commonConfig = CommonDescriptor.getInstance().getConfig(); private static final TierManager tierManager = TierManager.getInstance(); + private static final int DELETE_RETRY_TIMES = 5; + private static final long DELETE_RETRY_INTERVAL_MS = 100; public static long TEST_QUERY_JOB_ID = 1; public static QueryContext TEST_QUERY_CONTEXT = new QueryContext(TEST_QUERY_JOB_ID); @@ -253,7 +260,69 @@ public static void cleanAllDir() throws IOException { } public static void cleanDir(String dir) throws IOException { - FSFactoryProducer.getFSFactory().deleteDirectory(dir); + Path path = FSFactoryProducer.getFSFactory().getFile(dir).toPath(); + if (!Files.exists(path)) { + return; + } + + IOException lastException = null; + for (int i = 0; i < DELETE_RETRY_TIMES; i++) { + try { + deleteRecursively(path); + return; + } catch (NoSuchFileException e) { + return; + } catch (IOException e) { + lastException = e; + if (i + 1 == DELETE_RETRY_TIMES) { + break; + } + try { + TimeUnit.MILLISECONDS.sleep(DELETE_RETRY_INTERVAL_MS); + } catch (InterruptedException interruptedException) { + Thread.currentThread().interrupt(); + IOException ioException = + new IOException("Interrupted while deleting " + dir, interruptedException); + ioException.addSuppressed(e); + throw ioException; + } + } + } + throw lastException; + } + + private static void deleteRecursively(Path path) throws IOException { + if (!Files.exists(path)) { + return; + } + + Files.walkFileTree( + path, + new SimpleFileVisitor() { + @Override + public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) + throws IOException { + Files.deleteIfExists(file); + return FileVisitResult.CONTINUE; + } + + @Override + public FileVisitResult visitFileFailed(Path file, IOException exc) throws IOException { + if (exc instanceof NoSuchFileException) { + return FileVisitResult.CONTINUE; + } + throw exc; + } + + @Override + public FileVisitResult postVisitDirectory(Path dir, IOException exc) throws IOException { + if (exc != null) { + throw exc; + } + Files.deleteIfExists(dir); + return FileVisitResult.CONTINUE; + } + }); } /** disable memory control
this function should be called before all code in the setup */ @@ -317,19 +386,6 @@ private static void createDir(String dir) { } public static void recursiveDeleteFolder(String path) throws IOException { - File file = new File(path); - if (file.isDirectory()) { - File[] files = file.listFiles(); - if (files == null || files.length == 0) { - FileUtils.deleteDirectory(file); - } else { - for (File f : files) { - recursiveDeleteFolder(f.getAbsolutePath()); - } - FileUtils.deleteDirectory(file); - } - } else { - FileUtils.delete(file); - } + cleanDir(path); } } diff --git a/iotdb-core/datanode/src/test/java/org/apache/iotdb/db/utils/EnvironmentUtilsTest.java b/iotdb-core/datanode/src/test/java/org/apache/iotdb/db/utils/EnvironmentUtilsTest.java new file mode 100644 index 0000000000000..36783d78deceb --- /dev/null +++ b/iotdb-core/datanode/src/test/java/org/apache/iotdb/db/utils/EnvironmentUtilsTest.java @@ -0,0 +1,52 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package org.apache.iotdb.db.utils; + +import org.apache.iotdb.db.utils.constant.TestConstant; + +import org.junit.After; +import org.junit.Assert; +import org.junit.Test; + +import java.io.File; +import java.io.IOException; +import java.nio.file.Files; +import java.util.Collections; + +public class EnvironmentUtilsTest { + + private final File testDir = new File(TestConstant.BASE_OUTPUT_PATH, "EnvironmentUtilsTest"); + + @After + public void tearDown() throws IOException { + EnvironmentUtils.cleanDir(testDir.getPath()); + } + + @Test + public void testCleanDirDeletesNestedDirectory() throws IOException { + File nestedDir = new File(testDir, "ext" + File.separator + "udf" + File.separator + "tmp"); + Assert.assertTrue(nestedDir.isDirectory() || nestedDir.mkdirs()); + Files.write(new File(nestedDir, "plugin.txt").toPath(), Collections.singletonList("plugin")); + + EnvironmentUtils.cleanDir(testDir.getPath()); + + Assert.assertFalse(testDir.exists()); + } +} diff --git a/iotdb-core/node-commons/src/test/java/org/apache/iotdb/commons/utils/FileUtilsTest.java b/iotdb-core/node-commons/src/test/java/org/apache/iotdb/commons/utils/FileUtilsTest.java index f4b1ed962bc8e..c7e52558ff0d9 100644 --- a/iotdb-core/node-commons/src/test/java/org/apache/iotdb/commons/utils/FileUtilsTest.java +++ b/iotdb-core/node-commons/src/test/java/org/apache/iotdb/commons/utils/FileUtilsTest.java @@ -47,8 +47,12 @@ public void setUp() throws Exception { @After public void tearDown() throws Exception { - tmpDir.delete(); - targetDir.delete(); + if (tmpDir != null) { + FileUtils.deleteFileOrDirectory(tmpDir, true); + } + if (targetDir != null) { + FileUtils.deleteFileOrDirectory(targetDir, true); + } } @Test