150 lines
5.0 KiB
TypeScript
150 lines
5.0 KiB
TypeScript
import {
|
|
getPublicKey,
|
|
randomPrivateKey,
|
|
} from "@suaveplan/crypto-curve/ed25519";
|
|
import { Drive, type DriveStorage } from "@suaveplan/drive";
|
|
import { MemoryStorage } from "@suaveplan/storage/memory";
|
|
import { describe, expect, it } from "@suaveplan/testing/runner";
|
|
import { CHUNKS_CODES, ChunksError } from "./error-codes.js";
|
|
import { chunksPlugin } from "./plugin.js";
|
|
|
|
function makeFailingStorage(failOn: (key: string) => boolean): DriveStorage {
|
|
const inner = new MemoryStorage();
|
|
return Object.assign(inner, {
|
|
id: "default",
|
|
set(key: string, value: Uint8Array): Promise<void> {
|
|
if (failOn(key)) {
|
|
throw new Error(`disk full for ${key}`);
|
|
}
|
|
return MemoryStorage.prototype.set.call(inner, key, value);
|
|
},
|
|
}) as unknown as DriveStorage;
|
|
}
|
|
|
|
function makeFailingStorageNonError(
|
|
failOn: (key: string) => boolean
|
|
): DriveStorage {
|
|
const inner = new MemoryStorage();
|
|
return Object.assign(inner, {
|
|
id: "default",
|
|
set(key: string, value: Uint8Array): Promise<void> {
|
|
if (failOn(key)) {
|
|
const literal: unknown = "literal-throwable";
|
|
throw literal;
|
|
}
|
|
return MemoryStorage.prototype.set.call(inner, key, value);
|
|
},
|
|
}) as unknown as DriveStorage;
|
|
}
|
|
|
|
describe("CHUNKS-INGEST-FAILED — non-ChunksError storage failures wrap as INGEST_FAILED", () => {
|
|
it("wraps a manifest-write Error into ChunksError(INGEST_FAILED)", {
|
|
timeout: 5000,
|
|
}, async () => {
|
|
const privKey = randomPrivateKey();
|
|
const pubKey = getPublicKey(privKey);
|
|
const storage = makeFailingStorage((k) => k.startsWith("manifest:"));
|
|
const drive = new Drive(storage);
|
|
await drive.initialize();
|
|
|
|
const chunks = await drive.usePlugin(
|
|
chunksPlugin({
|
|
serverPrivKey: privKey,
|
|
serverPubKey: pubKey,
|
|
chunkSize: 1024,
|
|
})
|
|
);
|
|
|
|
await drive.write("test.txt", new TextEncoder().encode("hello"));
|
|
|
|
try {
|
|
await chunks.ingest("test.txt");
|
|
throw new Error("expected ingest to throw");
|
|
} catch (e) {
|
|
expect(e).toBeInstanceOf(ChunksError);
|
|
expect((e as ChunksError).code).toBe(CHUNKS_CODES.INGEST_FAILED);
|
|
expect((e as ChunksError).message).toContain("disk full");
|
|
}
|
|
|
|
await drive.dispose();
|
|
});
|
|
|
|
it("passes through a ChunksError thrown inside the ingest path without re-wrapping", {
|
|
timeout: 5000,
|
|
}, async () => {
|
|
const privKey = randomPrivateKey();
|
|
const pubKey = getPublicKey(privKey);
|
|
const inner = new MemoryStorage();
|
|
const chunksErrorStorage = Object.assign(inner, {
|
|
id: "default",
|
|
set(key: string, value: Uint8Array): Promise<void> {
|
|
if (key.startsWith("manifest:")) {
|
|
throw new ChunksError(
|
|
CHUNKS_CODES.SIG_INVALID,
|
|
"synthetic: bypass wrapping"
|
|
);
|
|
}
|
|
return MemoryStorage.prototype.set.call(inner, key, value);
|
|
},
|
|
}) as unknown as DriveStorage;
|
|
const drive = new Drive(chunksErrorStorage);
|
|
await drive.initialize();
|
|
|
|
const chunks = await drive.usePlugin(
|
|
chunksPlugin({
|
|
serverPrivKey: privKey,
|
|
serverPubKey: pubKey,
|
|
chunkSize: 1024,
|
|
})
|
|
);
|
|
|
|
await drive.write("test.txt", new TextEncoder().encode("hello"));
|
|
|
|
try {
|
|
await chunks.ingest("test.txt");
|
|
throw new Error("expected ingest to throw");
|
|
} catch (e) {
|
|
expect(e).toBeInstanceOf(ChunksError);
|
|
expect((e as ChunksError).code).toBe(CHUNKS_CODES.SIG_INVALID);
|
|
expect((e as ChunksError).message).toContain(
|
|
"synthetic: bypass wrapping"
|
|
);
|
|
}
|
|
|
|
await drive.dispose();
|
|
});
|
|
|
|
it("wraps a non-Error throwable into ChunksError(INGEST_FAILED)", {
|
|
timeout: 5000,
|
|
}, async () => {
|
|
const privKey = randomPrivateKey();
|
|
const pubKey = getPublicKey(privKey);
|
|
const storage = makeFailingStorageNonError((k) =>
|
|
k.startsWith("manifest:")
|
|
);
|
|
const drive = new Drive(storage);
|
|
await drive.initialize();
|
|
|
|
const chunks = await drive.usePlugin(
|
|
chunksPlugin({
|
|
serverPrivKey: privKey,
|
|
serverPubKey: pubKey,
|
|
chunkSize: 1024,
|
|
})
|
|
);
|
|
|
|
await drive.write("test.txt", new TextEncoder().encode("hello"));
|
|
|
|
try {
|
|
await chunks.ingest("test.txt");
|
|
throw new Error("expected ingest to throw");
|
|
} catch (e) {
|
|
expect(e).toBeInstanceOf(ChunksError);
|
|
expect((e as ChunksError).code).toBe(CHUNKS_CODES.INGEST_FAILED);
|
|
expect((e as ChunksError).message).toContain("literal-throwable");
|
|
}
|
|
|
|
await drive.dispose();
|
|
});
|
|
});
|