Skip to content

Commit 816169b

Browse files
committed
test: add tests for metadata validation
1 parent 16ec028 commit 816169b

File tree

3 files changed

+69
-10
lines changed

3 files changed

+69
-10
lines changed

packages/miniflare/src/workers/kv/namespace.worker.ts

Lines changed: 16 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ import {
2222
validatePutOptions,
2323
} from "./validator.worker";
2424

25+
const MAX_BULK_GET_KEYS = 100;
2526
interface KVParams {
2627
key: string;
2728
}
@@ -81,17 +82,22 @@ async function processKeyValue(
8182
withMetadata: boolean = false
8283
) {
8384
const decoder = new TextDecoder();
84-
let r = "";
85+
let decodedValue = "";
8586
if (obj?.value) {
8687
for await (const chunk of obj?.value) {
87-
r += decoder.decode(chunk, { stream: true });
88+
decodedValue += decoder.decode(chunk, { stream: true });
8889
}
89-
r += decoder.decode();
90+
decodedValue += decoder.decode();
9091
}
9192

9293
let val = null;
9394
try {
94-
val = obj?.value == null ? null : type === "json" ? JSON.parse(r) : r;
95+
val =
96+
obj?.value == null
97+
? null
98+
: type === "json"
99+
? JSON.parse(decodedValue)
100+
: decodedValue;
95101
} catch (err: any) {
96102
throw new HttpError(
97103
400,
@@ -104,7 +110,7 @@ async function processKeyValue(
104110
if (withMetadata) {
105111
return {
106112
value: val,
107-
metadata: obj?.metadata ? JSON.stringify(obj?.metadata) : null,
113+
metadata: obj?.metadata ?? null,
108114
};
109115
}
110116
return val;
@@ -121,20 +127,20 @@ export class KVNamespaceObject extends MiniflareDurableObject {
121127
@POST("/bulk/get")
122128
get: RouteHandler<KVParams> = async (req, params, url) => {
123129
if (req.method === "POST" && req.body != null) {
124-
let r = "";
130+
let decodedBody = "";
125131
const decoder = new TextDecoder();
126132
for await (const chunk of req.body) {
127-
r += decoder.decode(chunk, { stream: true });
133+
decodedBody += decoder.decode(chunk, { stream: true });
128134
}
129-
r += decoder.decode();
130-
const parsedBody = JSON.parse(r);
135+
decodedBody += decoder.decode();
136+
const parsedBody = JSON.parse(decodedBody);
131137
const keys: string[] = parsedBody.keys;
132138
const type = parsedBody?.type;
133139
if (type && type !== "text" && type !== "json") {
134140
return new Response("", { status: 400 });
135141
}
136142
const obj: { [key: string]: any } = {};
137-
if (keys.length > 100) {
143+
if (keys.length > MAX_BULK_GET_KEYS) {
138144
return new Response("", { status: 400 });
139145
}
140146
for (const key of keys) {

packages/miniflare/test/plugins/kv/index.spec.ts

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -172,6 +172,57 @@ test("bulk get: request json type", async (t) => {
172172
}
173173
});
174174

175+
test("bulk get: check metadata", async (t) => {
176+
const { kv } = t.context;
177+
await kv.put("key1", "value1", {
178+
expiration: TIME_FUTURE,
179+
metadata: { testing: true },
180+
});
181+
182+
await kv.put("key2", "value2");
183+
const result: any = await kv.getWithMetadata(["key1", "key2"]);
184+
const expectedResult: any = new Map([
185+
["key1", { value: "value1", metadata: { testing: true } }],
186+
["key2", { value: "value2", metadata: null }],
187+
]);
188+
t.deepEqual(result, expectedResult);
189+
});
190+
191+
test("bulk get: check metadata with int", async (t) => {
192+
const { kv } = t.context;
193+
await kv.put("key1", "value1", {
194+
expiration: TIME_FUTURE,
195+
metadata: 123,
196+
});
197+
198+
const result: any = await kv.getWithMetadata(["key1"]);
199+
const expectedResult: any = new Map([
200+
["key1", { value: "value1", metadata: 123 }],
201+
]);
202+
t.deepEqual(result, expectedResult);
203+
});
204+
205+
test("bulk get: check metadata as string", async (t) => {
206+
const { kv } = t.context;
207+
await kv.put("key1", "value1", {
208+
expiration: TIME_FUTURE,
209+
metadata: "example",
210+
});
211+
const result: any = await kv.getWithMetadata(["key1"]);
212+
const expectedResult: any = new Map([
213+
["key1", { value: "value1", metadata: "example" }],
214+
]);
215+
t.deepEqual(result, expectedResult);
216+
});
217+
218+
test("bulk get: get with metadata for 404", async (t) => {
219+
const { kv } = t.context;
220+
221+
const result: any = await kv.getWithMetadata(["key1"]);
222+
const expectedResult: any = new Map([["key1", null]]);
223+
t.deepEqual(result, expectedResult);
224+
});
225+
175226
test("get: returns null for non-existent keys", async (t) => {
176227
const { kv } = t.context;
177228
t.is(await kv.get("key"), null);

packages/miniflare/test/test-shared/miniflare.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,8 @@ export function namespace<T>(ns: string, binding: T): Namespaced<T> {
4444
);
4545
if (result instanceof Promise) {
4646
return result.then((res) => {
47+
// KV.get([a,b,c]) would be prefixed with ns, so we strip this prefix from response.
48+
// Map keys => [ns-a, ns-b, ns-c] -> [a,b,c]
4749
if (res instanceof Map) {
4850
const newResult = new Map<string, unknown>();
4951
for (const [key, value] of res) {

0 commit comments

Comments
 (0)