fix(storage): await recursive blob deletions and propagate failures
This commit is contained in:
@@ -571,7 +571,7 @@ export const deleteBlobCase = async (containerName, blobName) => {
|
||||
prefix: folderPrefix
|
||||
})) {
|
||||
console.log(" ------ :", blob.name);
|
||||
containerClient.deleteBlob(blob.name);
|
||||
await containerClient.deleteBlob(blob.name);
|
||||
}
|
||||
|
||||
//containerClient.deleteBlob(blobName);
|
||||
@@ -605,7 +605,7 @@ export const deleteBlobRep = async (containerName, blobName) => {
|
||||
console.log("=======:", await blockBlobClient.exists());
|
||||
|
||||
(await blockBlobClient.exists()) &&
|
||||
containerClient.deleteBlob(blob.name);
|
||||
(await containerClient.deleteBlob(blob.name));
|
||||
|
||||
//containerClient.deleteIfExists();
|
||||
//containerClient.deleteBlob(blob.name);
|
||||
|
||||
@@ -33,7 +33,10 @@ const loadAzureStorageHelperModule = (injected = {}) => {
|
||||
return context.module.exports;
|
||||
};
|
||||
|
||||
const loadRecursiveDeletionHelpers = ({ blobNames = [] } = {}) => {
|
||||
const loadRecursiveDeletionHelpers = ({
|
||||
blobNames = [],
|
||||
deleteBlob = () => Promise.resolve()
|
||||
} = {}) => {
|
||||
const filePath = path.join(rootDir, "actions", "azurestorage.js");
|
||||
const source = fs.readFileSync(filePath, "utf8");
|
||||
const start = source.indexOf("const isSafeDeletionPathSegment =");
|
||||
@@ -56,7 +59,7 @@ const loadRecursiveDeletionHelpers = ({ blobNames = [] } = {}) => {
|
||||
},
|
||||
deleteBlob(name) {
|
||||
deletedBlobNames.push(name);
|
||||
return Promise.resolve();
|
||||
return deleteBlob(name);
|
||||
},
|
||||
getBlockBlobClient() {
|
||||
return { exists: async () => true };
|
||||
@@ -95,6 +98,22 @@ const loadRecursiveDeletionHelpers = ({ blobNames = [] } = {}) => {
|
||||
const tests = [];
|
||||
const test = (name, fn) => tests.push({ name, fn });
|
||||
|
||||
const createDeferred = () => {
|
||||
let resolve;
|
||||
let reject;
|
||||
const promise = new Promise((resolvePromise, rejectPromise) => {
|
||||
resolve = resolvePromise;
|
||||
reject = rejectPromise;
|
||||
});
|
||||
|
||||
return { promise, resolve, reject };
|
||||
};
|
||||
|
||||
const flushMicrotasks = async () => {
|
||||
await Promise.resolve();
|
||||
await Promise.resolve();
|
||||
};
|
||||
|
||||
test("azurestorage helper builds download path with default encoding", () => {
|
||||
const mod = loadAzureStorageHelperModule();
|
||||
|
||||
@@ -219,6 +238,102 @@ test("recursive deletion helpers reject empty and unsafe resource paths before l
|
||||
}
|
||||
});
|
||||
|
||||
for (const deletionCase of [
|
||||
{
|
||||
helperName: "deleteBlobCase",
|
||||
resourcePath: "TMP-ABC",
|
||||
blobName: "TMP-ABC/files/evidence.pdf"
|
||||
},
|
||||
{
|
||||
helperName: "deleteBlobRep",
|
||||
resourcePath: "CASE-1/REP-1",
|
||||
blobName: "CASE-1/REP-1/files/evidence.pdf"
|
||||
}
|
||||
]) {
|
||||
test(`${deletionCase.helperName} remains pending until Azure deletion completes`, async () => {
|
||||
const deletion = createDeferred();
|
||||
const deletionStarted = createDeferred();
|
||||
const loaded = loadRecursiveDeletionHelpers({
|
||||
blobNames: [deletionCase.blobName],
|
||||
deleteBlob: () => {
|
||||
deletionStarted.resolve();
|
||||
return deletion.promise;
|
||||
}
|
||||
});
|
||||
let settled = false;
|
||||
|
||||
const helperPromise = loaded[
|
||||
deletionCase.helperName
|
||||
]("container-1", deletionCase.resourcePath).then((result) => {
|
||||
settled = true;
|
||||
return result;
|
||||
});
|
||||
|
||||
await deletionStarted.promise;
|
||||
await flushMicrotasks();
|
||||
assert.strictEqual(settled, false);
|
||||
|
||||
deletion.resolve();
|
||||
assert.deepStrictEqual(
|
||||
JSON.parse(JSON.stringify(await helperPromise)),
|
||||
{ deleted: deletionCase.resourcePath }
|
||||
);
|
||||
});
|
||||
|
||||
test(`${deletionCase.helperName} propagates Azure deletion rejection`, async () => {
|
||||
const deletionError = new Error("controlled Azure deletion failure");
|
||||
const rejectedDeletion = Promise.reject(deletionError);
|
||||
rejectedDeletion.catch(() => {});
|
||||
const loaded = loadRecursiveDeletionHelpers({
|
||||
blobNames: [deletionCase.blobName],
|
||||
deleteBlob: () => rejectedDeletion
|
||||
});
|
||||
|
||||
await assert.rejects(
|
||||
() =>
|
||||
loaded[deletionCase.helperName](
|
||||
"container-1",
|
||||
deletionCase.resourcePath
|
||||
),
|
||||
/controlled Azure deletion failure/
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
test("recursive deletion does not complete until all selected blob deletions complete", async () => {
|
||||
const firstDeletion = createDeferred();
|
||||
const secondDeletion = createDeferred();
|
||||
const deletionPromises = new Map([
|
||||
["TMP-ABC/files/first.pdf", firstDeletion.promise],
|
||||
["TMP-ABC/files/second.pdf", secondDeletion.promise]
|
||||
]);
|
||||
const loaded = loadRecursiveDeletionHelpers({
|
||||
blobNames: [...deletionPromises.keys()],
|
||||
deleteBlob: (name) => deletionPromises.get(name)
|
||||
});
|
||||
let settled = false;
|
||||
|
||||
const helperPromise = loaded
|
||||
.deleteBlobCase("container-1", "TMP-ABC")
|
||||
.then((result) => {
|
||||
settled = true;
|
||||
return result;
|
||||
});
|
||||
|
||||
await flushMicrotasks();
|
||||
assert.strictEqual(settled, false);
|
||||
|
||||
firstDeletion.resolve();
|
||||
await flushMicrotasks();
|
||||
assert.strictEqual(settled, false);
|
||||
|
||||
secondDeletion.resolve();
|
||||
assert.deepStrictEqual(
|
||||
JSON.parse(JSON.stringify(await helperPromise)),
|
||||
{ deleted: "TMP-ABC" }
|
||||
);
|
||||
});
|
||||
|
||||
const run = async () => {
|
||||
let passed = 0;
|
||||
for (const currentTest of tests) {
|
||||
|
||||
Reference in New Issue
Block a user