Path: blob/master/src/packages/backend/conat/test/sync/dko.test.ts
1451 views
/*1Testing basic ops with dko = distributed key:object store with SPARSE updates.23DEVELOPMENT:45pnpm test ./dko.test.ts67*/89import { dko as createDko } from "@cocalc/backend/conat/sync";10import {11before,12after,13connect,14client,15} from "@cocalc/backend/conat/test/setup";16import { wait } from "@cocalc/backend/conat/test/util";1718beforeAll(before);1920describe("create a public dko and do a basic operation", () => {21let kv;22const name = `test-${Math.random()}`;2324it("creates the dko", async () => {25kv = await createDko({ name });26expect(kv.getAll()).toEqual({});27});2829it("tries to add a non-object and fails", () => {30expect(() => {31kv.a = 10;32}).toThrow("must be objects");33});3435it("adds a key to the dko", () => {36kv.a = { a: 5, b: 7 };37expect(kv.a).toEqual({ a: 5, b: 7 });38});3940it("waits for the dko to be saved, then closing and recreates the kv and verifies that the key is there.", async () => {41await kv.save();42kv.close();43kv = await createDko({ name });44expect(kv.a).toEqual({ a: 5, b: 7 });45});4647it("verifies sparseness of underlying storage", () => {48expect(Object.keys(kv.getAll()).length).toBe(1);49// 3 = object structure (1) + values (2)50expect(Object.keys(kv.dkv.getAll()).length).toBe(3);51});5253it("clears and closes the kv", async () => {54kv.clear();55await kv.close();56expect(kv.getAll).toThrow("closed");57});58});5960describe("create dko and check more complicated keys", () => {61let kv;62const name = `test-${Math.random()}`;6364it("creates the dko", async () => {65kv = await createDko({ name });66expect(kv.getAll()).toEqual({});67const key = "a!@#$%^&*|()lkasdjfxxxxxxxxxx";68kv.set(key, { [key]: "bar" });69expect(kv.get(key)).toEqual({ [key]: "bar" });70});7172it("clears and closes the kv", async () => {73kv.clear();74await kv.close();75});76});7778describe("test a large value that requires chunking", () => {79let kv;80const name = `test-${Math.random()}`;8182let maxPayload = 0;8384it("sanity check on the max payload", async () => {85const client = connect();86await wait({ until: () => client.info != null });87maxPayload = client.info?.max_payload ?? 0;88expect(maxPayload).toBeGreaterThan(500000);89});9091it("creates the dko", async () => {92kv = await createDko({ name });93expect(kv.getAll()).toEqual({});9495const big = { foo: "b".repeat(maxPayload * 1.3) };96kv.set("big", big);97expect(kv.get("big")).toEqual(big);98});99100it("clears and closes the kv", async () => {101kv.clear();102await kv.close();103});104});105106describe("test keys that start with a bracket, weird keys, valid JSON, etc", () => {107let kv, kv2;108let client2;109const BAD_KEYS = [110"[foo]",111"[P] [W}\\ test]",112"normal",113JSON.stringify(["foo", "bar"]),114];115it("creates a dko", async () => {116client2 = connect();117const name = "[!nuts$##&^$$#!\\blah]";118kv = await client.sync.dko({ name });119kv2 = await client2.sync.dko({ name });120for (const key of BAD_KEYS) {121kv.set(key, { cocalc: "conat" });122expect(kv.has(key)).toBe(true);123expect(kv.get(key)).toEqual({ cocalc: "conat" });124await kv.save();125await wait({ until: () => kv2.has(key) });126expect(kv2.get(key)).toEqual({ cocalc: "conat" });127}128kv.close();129kv2.close();130});131});132133describe("illustrate that https://github.com/sagemathinc/cocalc/issues/8386 is not truly fixed", () => {134it("creates a dko", async () => {135const kv = await client.sync.dko({ name: "issue-8386" });136const key = JSON.stringify(["key", "field"]);137kv.set(key, { foo: "bar" });138expect(kv.fromPath(key)).toEqual({ key: "key", field: "field" });139expect(kv.get(key)).toEqual({ foo: "bar" });140141// here's the bug -- basically if you have a key that is a valid JSON array of142// length two (and only then), you get an extra spurious key. This might never143// be a problem in practice though, since the key you want is also there.144expect(kv.getAll()).toEqual({145key: { field: ["foo"] },146'["key","field"]': { foo: "bar" },147});148});149});150151afterAll(after);152153154