denoland / deno

A modern runtime for JavaScript and TypeScript.
https://deno.com
MIT License
94.66k stars 5.25k forks source link

Memory-backed KV data disappears mid test #22548

Open laurie71 opened 7 months ago

laurie71 commented 7 months ago

Version: Deno x.x.x Memory backed KV data disappearing under test

I'm trying to figure out why my tests are failing, and it turns out that data stored in KV is disappearing mid test. The tests are run with DENO\_KV\_PATH=:memory: deno test -A ${file} --unstable-kv --inspect-brk, so the KV store is in-memory.

The test calls a `createUser()` function to store a test user, followed by a `createVote()` function, which retrieves the stored user. I've verified that the user was stored correctly, but on attempting to retrieve it, there are no users in the store.

Relevant snippets of the code and output below. As you can see, the createUser() call stores the user which can then be retrieved by key and via list(); in the subsequent call to createVote() the user is no longer there; in fact there are no users at all, event though there were three stored moments ago.

So where is the data going? I did also verify that, in createVote(), the call to kv.getMany() did successfully retrieve the item, also created by the same test, so the KV store hasn't gotten completely wiped.

Any insights would be appreciated!

db_test.ts:

Deno.test("[db] getAreVotedByUser()", async () => {
  const item = randomItem();
  const user = randomUser();
  const vote = {
    itemId: item.id,
    userLogin: user.login,
    createdAt: new Date(),
  };

  ...

  await createItem(item);
  await createUser(user);
  await createVote(vote);

  ...
});

db-users.ts:

export async function createUser(user: User) {
  const usersKey = ["users", user.login];
  const usersBySessionKey = ["users_by_session", user.sessionId];

  const atomicOp = kv.atomic()
    .check({ key: usersKey, versionstamp: null })
    .check({ key: usersBySessionKey, versionstamp: null })
    .set(usersKey, user)
    .set(usersBySessionKey, user);

  const res = await atomicOp.commit();
  if (!res.ok) throw new Error("Failed to create user");

  const created = await kv.get(usersKey);
  console.log("New user:", user);
  console.log("Created user:", created);
  console.log("All known users:");
  const allusers = kv.list({ prefix: ["users"] });
  for await (const entry of allusers) {
    console.log(entry.value);
  }
  console.log("done");
}

db-items.ts:

export async function createVote(vote: Vote) {
  const itemKey = ["items", vote.itemId];
  const userKey = ["users", vote.userLogin];
  const [itemRes, userRes] = await kv.getMany<[Item, User]>([itemKey, userKey]);

  console.log("=====");
  console.log((await kv.get(userKey)).value);
  console.log("=====");
  console.log("All known users:");
  const allusers = kv.list({ prefix: ["users"] });
  for await (const entry of allusers) {
    console.log(entry.value);
  }
  console.log("=====");

  const item = itemRes.value;
  const user = userRes.value;
  if (item === null) throw new Deno.errors.NotFound("Item not found");
  if (user === null) throw new Deno.errors.NotFound("User not found");

  ...
}

Output:

New user: {
  login: "3d37054b-8e08-46c3-beb0-14793e682355",
  sessionId: "0d399be6-2486-4208-b00f-f98030b946a5",
  isSubscribed: false,
  stripeCustomerId: "644fd255-e1f5-46d8-a7b1-2e1e75f78202"
}
Created user: {
  key: [ "users", "3d37054b-8e08-46c3-beb0-14793e682355" ],
  value: {
    login: "3d37054b-8e08-46c3-beb0-14793e682355",
    sessionId: "0d399be6-2486-4208-b00f-f98030b946a5",
    isSubscribed: false,
    stripeCustomerId: "644fd255-e1f5-46d8-a7b1-2e1e75f78202"
  },
  versionstamp: "00000000000000040000"
}
All known users:
lucacasonato commented 3 months ago

It seems that the reproduction is missing the done output - do you see a value after All known users:?