Spaces:
Running
Running
File size: 6,716 Bytes
96bdf6c e4e0afe 96bdf6c e4e0afe 96bdf6c e4e0afe 96bdf6c e4e0afe 96bdf6c | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 | import { POST } from './route';
import { getWebuiImageRetentionStore, resetWebuiImageRetentionStoresForTests } from '@/lib/webui-image-retention-store';
import { NextRequest } from 'next/server';
import assert from 'node:assert/strict';
import { access, mkdtemp, mkdir, rm, writeFile } from 'node:fs/promises';
import os from 'node:os';
import path from 'node:path';
import { afterEach, beforeEach, describe, it } from 'node:test';
const validFilename = '1781567999000-aaaaaaaaaaaaaaaa-0.png';
const missingFilename = '1781567999001-bbbbbbbbbbbbbbbb-1.webp';
let originalEnv: NodeJS.ProcessEnv;
let originalCwd = '';
let tempDir = '';
beforeEach(async () => {
originalEnv = { ...process.env };
originalCwd = process.cwd();
tempDir = await mkdtemp(path.join(os.tmpdir(), 'image-delete-route-'));
process.chdir(tempDir);
delete process.env.APP_PASSWORD;
resetWebuiImageRetentionStoresForTests();
});
afterEach(async () => {
resetWebuiImageRetentionStoresForTests();
process.chdir(originalCwd);
await rm(tempDir, { recursive: true, force: true });
restoreProcessEnv(originalEnv);
});
describe('POST /api/image-delete', { concurrency: false }, () => {
it('removes automatic-cleanup protection after deleting an image successfully', async () => {
const filepath = await writeOutputFile(validFilename);
const store = await getWebuiImageRetentionStore();
await store.preserve([validFilename]);
const response = await POST(jsonRequest({ filenames: [validFilename] }));
const body = (await response.json()) as {
results: Array<{ filename: string; success: boolean; error?: string }>;
};
assert.equal(response.status, 200);
assert.deepEqual(body.results, [{ filename: validFilename, success: true }]);
await assert.rejects(() => access(filepath));
assert.deepEqual(await store.listPermanentFilenames(), []);
});
it('reports a missing file as absent and releases stale automatic-cleanup protection', async () => {
const store = await getWebuiImageRetentionStore();
await store.preserve([missingFilename]);
const response = await POST(jsonRequest({ filenames: [missingFilename] }));
const body = (await response.json()) as {
results: Array<{
filename: string;
success: boolean;
fileDeleted?: boolean;
fileAbsent?: boolean;
markerRemoved?: boolean;
error?: string;
}>;
};
assert.equal(response.status, 207);
assert.deepEqual(body.results, [
{
filename: missingFilename,
success: false,
fileAbsent: true,
markerRemoved: true,
error: '文件不存在。'
}
]);
assert.deepEqual(await store.listPermanentFilenames(), []);
});
it('reports a retention-state cleanup failure after deleting the file', async () => {
const filepath = await writeOutputFile(validFilename);
const store = await getWebuiImageRetentionStore();
await store.preserve([validFilename]);
const originalRemove = store.remove.bind(store);
store.remove = async () => {
throw new Error('expected retention state failure');
};
try {
const response = await POST(jsonRequest({ filenames: [validFilename] }));
const body = (await response.json()) as {
results: Array<{
filename: string;
success: boolean;
fileDeleted?: boolean;
fileAbsent?: boolean;
markerRemoved?: boolean;
error?: string;
}>;
};
assert.equal(response.status, 207);
assert.deepEqual(body.results, [
{
filename: validFilename,
success: false,
fileDeleted: true,
markerRemoved: false,
error: '图片已删除,但自动清理保护未能清理。'
}
]);
await assert.rejects(() => access(filepath));
assert.deepEqual(await store.listPermanentFilenames(), [validFilename]);
} finally {
store.remove = originalRemove;
}
});
it('does not report a stale marker as released when its cleanup fails for an absent file', async () => {
const store = await getWebuiImageRetentionStore();
await store.preserve([missingFilename]);
const originalRemove = store.remove.bind(store);
store.remove = async () => {
throw new Error('expected retention state failure');
};
try {
const response = await POST(jsonRequest({ filenames: [missingFilename] }));
const body = (await response.json()) as {
results: Array<{
filename: string;
success: boolean;
fileDeleted?: boolean;
fileAbsent?: boolean;
markerRemoved?: boolean;
error?: string;
}>;
};
assert.equal(response.status, 207);
assert.deepEqual(body.results, [
{
filename: missingFilename,
success: false,
fileAbsent: true,
markerRemoved: false,
error: '图片已不存在,但自动清理保护未能清理。'
}
]);
assert.deepEqual(await store.listPermanentFilenames(), [missingFilename]);
} finally {
store.remove = originalRemove;
}
});
});
function jsonRequest(body: unknown): NextRequest {
return new NextRequest('http://localhost/api/image-delete', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(body)
});
}
async function writeOutputFile(filename: string): Promise<string> {
const outputDir = path.join(tempDir, 'generated-images');
await mkdir(outputDir, { recursive: true });
const filepath = path.join(outputDir, filename);
await writeFile(filepath, 'image');
return filepath;
}
function restoreProcessEnv(snapshot: NodeJS.ProcessEnv): void {
for (const key of Object.keys(process.env)) {
if (!(key in snapshot)) delete process.env[key];
}
for (const [key, value] of Object.entries(snapshot)) {
process.env[key] = value;
}
}
|