mirror of
https://github.com/logos-messaging/logos-delivery-js.git
synced 2026-03-13 21:23:38 +00:00
199 lines
6.3 KiB
TypeScript
199 lines
6.3 KiB
TypeScript
import { expect } from "chai";
|
|
|
|
import { MemLocalHistory } from "./mem_local_history.js";
|
|
import { ContentMessage } from "./message.js";
|
|
import { HistoryStorage, PersistentStorage } from "./persistent_storage.js";
|
|
|
|
const channelId = "channel-1";
|
|
|
|
describe("PersistentStorage", () => {
|
|
describe("Explicit storage", () => {
|
|
it("persists and restores messages", () => {
|
|
const storage = new MemoryStorage();
|
|
const persistentStorage = PersistentStorage.create(channelId, storage);
|
|
|
|
expect(persistentStorage).to.not.be.undefined;
|
|
|
|
const history1 = new MemLocalHistory({ storage: persistentStorage });
|
|
history1.push(createMessage("msg-1", 1));
|
|
history1.push(createMessage("msg-2", 2));
|
|
|
|
const history2 = new MemLocalHistory({ storage: persistentStorage });
|
|
|
|
expect(history2.length).to.equal(2);
|
|
expect(history2.slice(0).map((msg) => msg.messageId)).to.deep.equal([
|
|
"msg-1",
|
|
"msg-2"
|
|
]);
|
|
});
|
|
|
|
it("uses in-memory only when no storage is provided", () => {
|
|
const history = new MemLocalHistory({ maxSize: 100 });
|
|
history.push(createMessage("msg-3", 3));
|
|
|
|
expect(history.length).to.equal(1);
|
|
expect(history.slice(0)[0].messageId).to.equal("msg-3");
|
|
|
|
const history2 = new MemLocalHistory({ maxSize: 100 });
|
|
expect(history2.length).to.equal(0);
|
|
});
|
|
|
|
it("handles corrupt data in storage gracefully", () => {
|
|
const storage = new MemoryStorage();
|
|
// Corrupt data
|
|
storage.setItem("waku:sds:history:channel-1", "{ invalid json }");
|
|
|
|
const persistentStorage = PersistentStorage.create(channelId, storage);
|
|
const history = new MemLocalHistory({ storage: persistentStorage });
|
|
|
|
expect(history.length).to.equal(0);
|
|
|
|
// Corrupt data is not saved
|
|
expect(storage.getItem("waku:sds:history:channel-1")).to.equal(null);
|
|
});
|
|
|
|
it("isolates history by channel ID", () => {
|
|
const storage = new MemoryStorage();
|
|
|
|
const storage1 = PersistentStorage.create("channel-1", storage);
|
|
const storage2 = PersistentStorage.create("channel-2", storage);
|
|
|
|
const history1 = new MemLocalHistory({ storage: storage1 });
|
|
const history2 = new MemLocalHistory({ storage: storage2 });
|
|
|
|
history1.push(createMessage("msg-1", 1));
|
|
history2.push(createMessage("msg-2", 2));
|
|
|
|
expect(history1.length).to.equal(1);
|
|
expect(history1.slice(0)[0].messageId).to.equal("msg-1");
|
|
|
|
expect(history2.length).to.equal(1);
|
|
expect(history2.slice(0)[0].messageId).to.equal("msg-2");
|
|
|
|
expect(storage.getItem("waku:sds:history:channel-1")).to.not.be.null;
|
|
expect(storage.getItem("waku:sds:history:channel-2")).to.not.be.null;
|
|
});
|
|
|
|
it("saves messages after each push", () => {
|
|
const storage = new MemoryStorage();
|
|
const persistentStorage = PersistentStorage.create(channelId, storage);
|
|
const history = new MemLocalHistory({ storage: persistentStorage });
|
|
|
|
expect(storage.getItem("waku:sds:history:channel-1")).to.be.null;
|
|
|
|
history.push(createMessage("msg-1", 1));
|
|
|
|
expect(storage.getItem("waku:sds:history:channel-1")).to.not.be.null;
|
|
|
|
const saved = JSON.parse(storage.getItem("waku:sds:history:channel-1")!);
|
|
expect(saved).to.have.lengthOf(1);
|
|
expect(saved[0].messageId).to.equal("msg-1");
|
|
});
|
|
|
|
it("loads messages on initialization", () => {
|
|
const storage = new MemoryStorage();
|
|
const persistentStorage1 = PersistentStorage.create(channelId, storage);
|
|
const history1 = new MemLocalHistory({ storage: persistentStorage1 });
|
|
|
|
history1.push(createMessage("msg-1", 1));
|
|
history1.push(createMessage("msg-2", 2));
|
|
history1.push(createMessage("msg-3", 3));
|
|
|
|
const persistentStorage2 = PersistentStorage.create(channelId, storage);
|
|
const history2 = new MemLocalHistory({ storage: persistentStorage2 });
|
|
|
|
expect(history2.length).to.equal(3);
|
|
expect(history2.slice(0).map((m) => m.messageId)).to.deep.equal([
|
|
"msg-1",
|
|
"msg-2",
|
|
"msg-3"
|
|
]);
|
|
});
|
|
});
|
|
|
|
describe("Node.js only (no localStorage)", () => {
|
|
before(function () {
|
|
if (typeof localStorage !== "undefined") {
|
|
this.skip();
|
|
}
|
|
});
|
|
|
|
it("returns undefined when no storage is available", () => {
|
|
const persistentStorage = PersistentStorage.create(channelId, undefined);
|
|
|
|
expect(persistentStorage).to.equal(undefined);
|
|
});
|
|
});
|
|
|
|
describe("Browser only (localStorage)", () => {
|
|
before(function () {
|
|
if (typeof localStorage === "undefined") {
|
|
this.skip();
|
|
}
|
|
});
|
|
|
|
it("persists and restores messages with channelId", () => {
|
|
const testChannelId = `test-${Date.now()}`;
|
|
const history1 = new MemLocalHistory({ storage: testChannelId });
|
|
history1.push(createMessage("msg-1", 1));
|
|
history1.push(createMessage("msg-2", 2));
|
|
|
|
const history2 = new MemLocalHistory({ storage: testChannelId });
|
|
|
|
expect(history2.length).to.equal(2);
|
|
expect(history2.slice(0).map((msg) => msg.messageId)).to.deep.equal([
|
|
"msg-1",
|
|
"msg-2"
|
|
]);
|
|
|
|
localStorage.removeItem(`waku:sds:history:${testChannelId}`);
|
|
});
|
|
|
|
it("auto-uses localStorage when channelId is provided", () => {
|
|
const testChannelId = `auto-storage-${Date.now()}`;
|
|
|
|
const history = new MemLocalHistory({ storage: testChannelId });
|
|
history.push(createMessage("msg-auto-1", 1));
|
|
history.push(createMessage("msg-auto-2", 2));
|
|
|
|
const history2 = new MemLocalHistory({ storage: testChannelId });
|
|
expect(history2.length).to.equal(2);
|
|
expect(history2.slice(0).map((m) => m.messageId)).to.deep.equal([
|
|
"msg-auto-1",
|
|
"msg-auto-2"
|
|
]);
|
|
|
|
localStorage.removeItem(`waku:sds:history:${testChannelId}`);
|
|
});
|
|
});
|
|
});
|
|
|
|
const createMessage = (id: string, timestamp: number): ContentMessage => {
|
|
return new ContentMessage(
|
|
id,
|
|
channelId,
|
|
"sender",
|
|
[],
|
|
BigInt(timestamp),
|
|
undefined,
|
|
new Uint8Array([timestamp]),
|
|
undefined
|
|
);
|
|
};
|
|
|
|
class MemoryStorage implements HistoryStorage {
|
|
private readonly store = new Map<string, string>();
|
|
|
|
public getItem(key: string): string | null {
|
|
return this.store.get(key) ?? null;
|
|
}
|
|
|
|
public setItem(key: string, value: string): void {
|
|
this.store.set(key, value);
|
|
}
|
|
|
|
public removeItem(key: string): void {
|
|
this.store.delete(key);
|
|
}
|
|
}
|