task-164: 清理失败不阻断契约(单文件失败其余继续、失败路径可见、不上抛、下轮重试、引用跳过不计失败)+ 8 条测试

This commit is contained in:
2026-09-02 07:35:57 +08:00
parent 7a43ed6c43
commit 34f614ea32
2 changed files with 183 additions and 0 deletions
@@ -0,0 +1,122 @@
package com.nanri.aiimage.modules.file.service;
import com.nanri.aiimage.modules.file.service.BatchFileCleaner.BatchCleanResult;
import org.junit.jupiter.api.Test;
import java.io.File;
import java.util.List;
import java.util.concurrent.atomic.AtomicInteger;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.jupiter.api.Assertions.assertTrue;
/**
* task-164:清理失败不阻断契约(plan 09)。
* 单文件失败不影响其他;错误可见(failedPaths);不上抛;下轮可重试;
* 引用判定失败保守跳过不计数为失败。
*/
class BatchFileCleanerTest {
private final BatchFileCleaner cleaner = new BatchFileCleaner();
private final File a = new File("target/tmp/a.tmp");
private final File b = new File("target/tmp/b.tmp");
private final File c = new File("target/tmp/c.tmp");
@Test
void oneFailureOthersSucceed() {
BatchCleanResult result = cleaner.cleanBatch(
List.of(a, b, c),
file -> !file.getName().equals("b.tmp"),
name -> false);
assertEquals(2, result.cleanedCount(), "b 失败其余成功");
assertEquals(1, result.failedCount());
assertTrue(result.hasFailures());
}
@Test
void failureIsVisible() {
BatchCleanResult result = cleaner.cleanBatch(
List.of(a, b),
file -> !file.getName().equals("b.tmp"),
name -> false);
assertEquals(1, result.failedPaths().size());
assertTrue(result.failedPaths().getFirst().contains("b.tmp"), "失败路径可见");
}
@Test
void noThrowUpOnFailure() {
BatchCleanResult result = cleaner.cleanBatch(
List.of(a, b),
file -> {
if (file.getName().equals("b.tmp")) {
throw new RuntimeException("delete blew up");
}
return true;
},
name -> false);
assertEquals(1, result.cleanedCount());
assertEquals(1, result.failedCount(), "抛异常按失败计数不上抛");
}
@Test
void retryNextRoundSucceeds() {
AtomicInteger attempts = new AtomicInteger();
BatchCleanResult first = cleaner.cleanBatch(
List.of(b),
file -> attempts.incrementAndGet() == 1 ? false : true,
name -> false);
BatchCleanResult second = cleaner.cleanBatch(
List.of(b),
file -> attempts.incrementAndGet() > 1,
name -> false);
assertEquals(0, first.cleanedCount());
assertEquals(1, second.cleanedCount(), "下轮重试成功");
}
@Test
void partialResultReported() {
BatchCleanResult result = cleaner.cleanBatch(
List.of(a, c),
file -> true,
name -> false);
assertEquals(2, result.cleanedCount());
assertEquals(0, result.failedCount());
assertFalse(result.hasFailures());
}
@Test
void failureDoesNotBlockRemaining() {
BatchCleanResult result = cleaner.cleanBatch(
List.of(a, b, c),
file -> !file.getName().equals("b.tmp"),
name -> false);
assertEquals(2, result.cleanedCount(), "b 失败后 c 仍被清理(无级联)");
}
@Test
void referencedFilesSkippedNotCountedAsFailure() {
BatchCleanResult result = cleaner.cleanBatch(
List.of(a, b),
file -> true,
name -> name.equals("a.tmp"));
assertEquals(1, result.cleanedCount(), "被引用文件跳过,不算失败");
assertEquals(0, result.failedCount());
}
@Test
void nullInputsAreSafe() {
BatchCleanResult empty = cleaner.cleanBatch(null, file -> true, name -> false);
assertEquals(0, empty.cleanedCount());
assertEquals(0, empty.failedCount());
assertTrue(empty.failedPaths().isEmpty());
}
}