feat: 기능 추가 과정중
This commit is contained in:
@@ -0,0 +1,204 @@
|
||||
import { describe, expect, it, vi } from "vitest";
|
||||
|
||||
import { createStorageDurabilityAdapter } from "../../src/adapters/browser-file-storage/storage-manager-adapter.ts";
|
||||
|
||||
describe("storage manager adapter", () => {
|
||||
it("classifies rough origin pressure without treating it as a reservation", async () => {
|
||||
const adapter = createStorageDurabilityAdapter({
|
||||
estimate: async () => ({ usage: 75, quota: 100 }),
|
||||
persisted: async () => false,
|
||||
persist: async () => false,
|
||||
});
|
||||
|
||||
expect(await adapter.inspect()).toEqual({
|
||||
ok: true,
|
||||
value: {
|
||||
usageBytes: 75,
|
||||
quotaBytes: 100,
|
||||
persisted: false,
|
||||
pressure: "PRESSURE",
|
||||
},
|
||||
});
|
||||
});
|
||||
|
||||
it("snapshots pressure thresholds when the adapter is composed", async () => {
|
||||
const policy = {
|
||||
pressureRatio: 0.7,
|
||||
criticalRatio: 0.85,
|
||||
};
|
||||
const adapter = createStorageDurabilityAdapter(
|
||||
{
|
||||
estimate: async () => ({ usage: 50, quota: 100 }),
|
||||
},
|
||||
policy,
|
||||
);
|
||||
|
||||
policy.pressureRatio = 0.1;
|
||||
policy.criticalRatio = 0.2;
|
||||
|
||||
await expect(adapter.inspect()).resolves.toMatchObject({
|
||||
ok: true,
|
||||
value: { pressure: "NORMAL" },
|
||||
});
|
||||
});
|
||||
|
||||
it("captures StorageManager methods when the adapter is composed", async () => {
|
||||
const manager = {
|
||||
estimate: async () => ({ usage: 10, quota: 100 }),
|
||||
persisted: async () => false,
|
||||
};
|
||||
const adapter = createStorageDurabilityAdapter(manager);
|
||||
|
||||
manager.estimate = async () => ({ usage: 100, quota: 100 });
|
||||
manager.persisted = async () => true;
|
||||
|
||||
await expect(adapter.inspect()).resolves.toEqual({
|
||||
ok: true,
|
||||
value: {
|
||||
usageBytes: 10,
|
||||
quotaBytes: 100,
|
||||
persisted: false,
|
||||
pressure: "NORMAL",
|
||||
},
|
||||
});
|
||||
});
|
||||
|
||||
it("settles an aborted inspection while native reads remain pending", async () => {
|
||||
const never = new Promise<never>(() => undefined);
|
||||
const estimate = vi.fn(() => never);
|
||||
const persisted = vi.fn(() => never);
|
||||
const adapter = createStorageDurabilityAdapter({
|
||||
estimate,
|
||||
persisted,
|
||||
});
|
||||
const controller = new AbortController();
|
||||
|
||||
const inspection = adapter.inspect(controller.signal);
|
||||
controller.abort();
|
||||
|
||||
await expect(inspection).resolves.toMatchObject({
|
||||
ok: false,
|
||||
error: { code: "ABORTED", operation: "STORAGE_ESTIMATE" },
|
||||
});
|
||||
expect(estimate).toHaveBeenCalledOnce();
|
||||
expect(persisted).toHaveBeenCalledOnce();
|
||||
});
|
||||
|
||||
it("consumes a late native rejection when abort wins during invocation", async () => {
|
||||
const controller = new AbortController();
|
||||
let rejectEstimate: ((reason: unknown) => void) | undefined;
|
||||
const estimateResult = new Promise<StorageEstimate>(
|
||||
(_resolve, reject) => {
|
||||
rejectEstimate = reject;
|
||||
},
|
||||
);
|
||||
const unhandled: unknown[] = [];
|
||||
const onUnhandled = (reason: unknown): void => {
|
||||
unhandled.push(reason);
|
||||
};
|
||||
process.on("unhandledRejection", onUnhandled);
|
||||
|
||||
try {
|
||||
const adapter = createStorageDurabilityAdapter({
|
||||
estimate: () => {
|
||||
controller.abort();
|
||||
return estimateResult;
|
||||
},
|
||||
});
|
||||
|
||||
await expect(adapter.inspect(controller.signal)).resolves.toMatchObject({
|
||||
ok: false,
|
||||
error: { code: "ABORTED", operation: "STORAGE_ESTIMATE" },
|
||||
});
|
||||
rejectEstimate?.(new Error("late estimate rejection"));
|
||||
await new Promise<void>((resolve) => {
|
||||
setTimeout(resolve, 0);
|
||||
});
|
||||
expect(unhandled).toEqual([]);
|
||||
} finally {
|
||||
process.off("unhandledRejection", onUnhandled);
|
||||
}
|
||||
});
|
||||
|
||||
it("requests persistence only through the explicit user-initiated port", async () => {
|
||||
const persist = vi.fn(async () => true);
|
||||
const adapter = createStorageDurabilityAdapter({
|
||||
estimate: async () => ({}),
|
||||
persist,
|
||||
}, undefined, { isActive: true });
|
||||
|
||||
expect(
|
||||
await adapter.requestPersistence({
|
||||
reason: "PROTECT_UNSYNCED_USER_DATA",
|
||||
userInitiated: true,
|
||||
}),
|
||||
).toEqual({ ok: true, value: "GRANTED" });
|
||||
expect(persist).toHaveBeenCalledOnce();
|
||||
});
|
||||
|
||||
it("requires real transient user activation before invoking persist", async () => {
|
||||
const persist = vi.fn(async () => true);
|
||||
const adapter = createStorageDurabilityAdapter(
|
||||
{ estimate: async () => ({}), persist },
|
||||
undefined,
|
||||
{ isActive: false },
|
||||
);
|
||||
|
||||
await expect(
|
||||
adapter.requestPersistence({
|
||||
reason: "PROTECT_UNSYNCED_USER_DATA",
|
||||
userInitiated: true,
|
||||
}),
|
||||
).resolves.toMatchObject({
|
||||
ok: false,
|
||||
error: { code: "PERMISSION_DENIED" },
|
||||
});
|
||||
expect(persist).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it("reports irreversible persist truth when abort wins after invocation", async () => {
|
||||
const controller = new AbortController();
|
||||
const adapter = createStorageDurabilityAdapter(
|
||||
{
|
||||
estimate: async () => ({}),
|
||||
persist: async () => {
|
||||
controller.abort();
|
||||
return true;
|
||||
},
|
||||
},
|
||||
undefined,
|
||||
{ isActive: true },
|
||||
);
|
||||
|
||||
await expect(
|
||||
adapter.requestPersistence({
|
||||
reason: "PROTECT_UNSYNCED_USER_DATA",
|
||||
userInitiated: true,
|
||||
signal: controller.signal,
|
||||
}),
|
||||
).resolves.toEqual({ ok: true, value: "GRANTED" });
|
||||
});
|
||||
|
||||
it("keeps unsupported persistence state distinct from false", async () => {
|
||||
const adapter = createStorageDurabilityAdapter({
|
||||
estimate: async () => ({ usage: 1, quota: 10 }),
|
||||
});
|
||||
|
||||
await expect(adapter.inspect()).resolves.toMatchObject({
|
||||
ok: true,
|
||||
value: { persisted: null },
|
||||
});
|
||||
});
|
||||
|
||||
it("returns unsupported rather than inventing durable memory storage", async () => {
|
||||
const adapter = createStorageDurabilityAdapter(undefined);
|
||||
|
||||
expect(await adapter.inspect()).toMatchObject({
|
||||
ok: false,
|
||||
error: {
|
||||
code: "UNSUPPORTED",
|
||||
recovery: "ONLINE_ONLY",
|
||||
},
|
||||
});
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user