Skip to content

Commit 6af6a0b

Browse files
committed
feat: add msetex command and tests for it
1 parent 9c9a973 commit 6af6a0b

File tree

3 files changed

+539
-0
lines changed

3 files changed

+539
-0
lines changed
Lines changed: 393 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,393 @@
1+
import { strict as assert } from "node:assert";
2+
import testUtils, { GLOBAL } from "../test-utils";
3+
import MSETEX, { ExpirationMode, SetMode } from "./MSETEX";
4+
import { parseArgs } from "./generic-transformers";
5+
6+
describe("MSETEX", () => {
7+
describe("transformArguments", () => {
8+
it("single key-value pair as array", () => {
9+
assert.deepEqual(parseArgs(MSETEX, ["key1", "value1"]), [
10+
"MSETEX",
11+
"1",
12+
"key1",
13+
"value1",
14+
]);
15+
});
16+
17+
it("array of key value pairs", () => {
18+
assert.deepEqual(
19+
parseArgs(MSETEX, [
20+
"key1",
21+
"value1",
22+
"key2",
23+
"value2",
24+
"key3",
25+
"value3",
26+
]),
27+
["MSETEX", "3", "key1", "value1", "key2", "value2", "key3", "value3"]
28+
);
29+
});
30+
31+
it("array of tuples", () => {
32+
assert.deepEqual(
33+
parseArgs(MSETEX, [
34+
["key1", "value1"],
35+
["key2", "value2"],
36+
]),
37+
["MSETEX", "2", "key1", "value1", "key2", "value2"]
38+
);
39+
});
40+
41+
it("object of key value pairs", () => {
42+
assert.deepEqual(
43+
parseArgs(MSETEX, {
44+
key1: "value1",
45+
key2: "value2",
46+
}),
47+
["MSETEX", "2", "key1", "value1", "key2", "value2"]
48+
);
49+
});
50+
51+
it("with EX expiration", () => {
52+
assert.deepEqual(
53+
parseArgs(
54+
MSETEX,
55+
{
56+
key1: "value1",
57+
key2: "value2",
58+
},
59+
{
60+
expiration: {
61+
type: ExpirationMode.EX,
62+
value: 1,
63+
},
64+
}
65+
),
66+
["MSETEX", "2", "key1", "value1", "key2", "value2", "EX", "1"]
67+
);
68+
});
69+
70+
it("with NX set mode", () => {
71+
assert.deepEqual(
72+
parseArgs(
73+
MSETEX,
74+
[
75+
["key1", "value1"],
76+
["key2", "value2"],
77+
],
78+
{
79+
mode: SetMode.NX,
80+
}
81+
),
82+
["MSETEX", "2", "key1", "value1", "key2", "value2", "NX"]
83+
);
84+
});
85+
86+
it("with XX set mode and PX expiration", () => {
87+
assert.deepEqual(
88+
parseArgs(MSETEX, ["key1", "value1", "key2", "value2"], {
89+
mode: SetMode.XX,
90+
expiration: {
91+
type: ExpirationMode.PX,
92+
value: 1,
93+
},
94+
}),
95+
["MSETEX", "2", "key1", "value1", "key2", "value2", "XX", "PX", "1"]
96+
);
97+
});
98+
99+
it("with EXAT Date expiration", () => {
100+
assert.deepEqual(
101+
parseArgs(
102+
MSETEX,
103+
{
104+
key1: "value1",
105+
key2: "value2",
106+
},
107+
{
108+
expiration: {
109+
type: ExpirationMode.EXAT,
110+
value: new Date("2025-10-28T11:23:36.203Z"),
111+
},
112+
}
113+
),
114+
[
115+
"MSETEX",
116+
"2",
117+
"key1",
118+
"value1",
119+
"key2",
120+
"value2",
121+
"EXAT",
122+
"1761650616",
123+
]
124+
);
125+
});
126+
127+
it("with EXAT numeric expiration", () => {
128+
assert.deepEqual(
129+
parseArgs(
130+
MSETEX,
131+
[
132+
["key1", "value1"],
133+
["key2", "value2"],
134+
],
135+
{
136+
expiration: {
137+
type: ExpirationMode.EXAT,
138+
value: 1761650616,
139+
},
140+
}
141+
),
142+
[
143+
"MSETEX",
144+
"2",
145+
"key1",
146+
"value1",
147+
"key2",
148+
"value2",
149+
"EXAT",
150+
"1761650616",
151+
]
152+
);
153+
});
154+
155+
it("with PXAT Date expiration", () => {
156+
assert.deepEqual(
157+
parseArgs(MSETEX, ["key1", "value1", "key2", "value2"], {
158+
expiration: {
159+
type: ExpirationMode.PXAT,
160+
value: new Date("2025-10-28T11:23:36.203Z"),
161+
},
162+
}),
163+
[
164+
"MSETEX",
165+
"2",
166+
"key1",
167+
"value1",
168+
"key2",
169+
"value2",
170+
"PXAT",
171+
"1761650616203",
172+
]
173+
);
174+
});
175+
176+
it("with PXAT numeric expiration", () => {
177+
assert.deepEqual(
178+
parseArgs(
179+
MSETEX,
180+
{
181+
key1: "value1",
182+
key2: "value2",
183+
},
184+
{
185+
expiration: {
186+
type: ExpirationMode.PXAT,
187+
value: 1761650616203,
188+
},
189+
}
190+
),
191+
[
192+
"MSETEX",
193+
"2",
194+
"key1",
195+
"value1",
196+
"key2",
197+
"value2",
198+
"PXAT",
199+
"1761650616203",
200+
]
201+
);
202+
});
203+
204+
it("with KEEPTTL expiration", () => {
205+
assert.deepEqual(
206+
parseArgs(MSETEX, ["key1", "value1", "key2", "value2"], {
207+
expiration: {
208+
type: ExpirationMode.KEEPTTL,
209+
},
210+
}),
211+
["MSETEX", "2", "key1", "value1", "key2", "value2", "KEEPTTL"]
212+
);
213+
});
214+
215+
it("with empty expiration object", () => {
216+
assert.deepEqual(
217+
parseArgs(
218+
MSETEX,
219+
[
220+
["key1", "value1"],
221+
["key2", "value2"],
222+
],
223+
{
224+
expiration: {},
225+
}
226+
),
227+
["MSETEX", "2", "key1", "value1", "key2", "value2"]
228+
);
229+
});
230+
});
231+
232+
testUtils.testAll(
233+
"basic mSetEx",
234+
async (client) => {
235+
assert.equal(
236+
await client.mSetEx(["{key}1", "value1", "{key}2", "value2"]),
237+
1
238+
);
239+
},
240+
{
241+
client: { ...GLOBAL.SERVERS.OPEN, minimumDockerVersion: [8, 4] },
242+
cluster: { ...GLOBAL.CLUSTERS.OPEN, minimumDockerVersion: [8, 4] },
243+
}
244+
);
245+
246+
testUtils.testAll(
247+
"mSetEx with XX",
248+
async (client) => {
249+
const keyValuePairs = {
250+
"{key}1": "value1",
251+
"{key}2": "value2",
252+
};
253+
254+
const keysDoNotExist = await client.mSetEx(keyValuePairs, {
255+
mode: SetMode.XX,
256+
});
257+
258+
assert.equal(keysDoNotExist, 0);
259+
260+
await client.mSet(keyValuePairs);
261+
262+
const keysExist = await client.mSetEx(keyValuePairs, {
263+
mode: SetMode.XX,
264+
});
265+
266+
assert.equal(keysExist, 1);
267+
},
268+
{
269+
client: { ...GLOBAL.SERVERS.OPEN, minimumDockerVersion: [8, 4] },
270+
cluster: { ...GLOBAL.CLUSTERS.OPEN, minimumDockerVersion: [8, 4] },
271+
}
272+
);
273+
274+
testUtils.testAll(
275+
"mSetEx with NX",
276+
async (client) => {
277+
const keyValuePairs = [
278+
["{key}1", "value1"],
279+
["{key}2", "value2"],
280+
] as Array<[string, string]>;
281+
282+
const firstAttempt = await client.mSetEx(keyValuePairs, {
283+
mode: SetMode.NX,
284+
});
285+
286+
assert.equal(firstAttempt, 1);
287+
288+
const secondAttempt = await client.mSetEx(keyValuePairs, {
289+
mode: SetMode.NX,
290+
});
291+
292+
assert.equal(secondAttempt, 0);
293+
},
294+
{
295+
client: { ...GLOBAL.SERVERS.OPEN, minimumDockerVersion: [8, 4] },
296+
cluster: { ...GLOBAL.CLUSTERS.OPEN, minimumDockerVersion: [8, 4] },
297+
}
298+
);
299+
300+
testUtils.testAll(
301+
"mSetEx with PX expiration",
302+
async (client) => {
303+
assert.equal(
304+
await client.mSetEx(
305+
[
306+
["{key}1", "value1"],
307+
["{key}2", "value2"],
308+
],
309+
{
310+
expiration: {
311+
type: ExpirationMode.PX,
312+
value: 500,
313+
},
314+
}
315+
),
316+
1
317+
);
318+
},
319+
{
320+
client: { ...GLOBAL.SERVERS.OPEN, minimumDockerVersion: [8, 4] },
321+
cluster: { ...GLOBAL.CLUSTERS.OPEN, minimumDockerVersion: [8, 4] },
322+
}
323+
);
324+
325+
testUtils.testAll(
326+
"mSetEx with EXAT expiration",
327+
async (client) => {
328+
assert.equal(
329+
await client.mSetEx(
330+
[
331+
["{key}1", "value1"],
332+
["{key}2", "value2"],
333+
],
334+
{
335+
expiration: {
336+
type: ExpirationMode.EXAT,
337+
value: new Date(Date.now() + 10000),
338+
},
339+
}
340+
),
341+
1
342+
);
343+
},
344+
{
345+
client: { ...GLOBAL.SERVERS.OPEN, minimumDockerVersion: [8, 4] },
346+
cluster: { ...GLOBAL.CLUSTERS.OPEN, minimumDockerVersion: [8, 4] },
347+
}
348+
);
349+
350+
testUtils.testAll(
351+
"mSetEx with KEEPTTL expiration",
352+
async (client) => {
353+
assert.equal(
354+
await client.mSetEx(["{key}1", "value1", "{key}2", "value2"], {
355+
expiration: {
356+
type: ExpirationMode.KEEPTTL,
357+
},
358+
}),
359+
1
360+
);
361+
},
362+
{
363+
client: { ...GLOBAL.SERVERS.OPEN, minimumDockerVersion: [8, 4] },
364+
cluster: { ...GLOBAL.CLUSTERS.OPEN, minimumDockerVersion: [8, 4] },
365+
}
366+
);
367+
368+
testUtils.testAll(
369+
"mSetEx with all options",
370+
async (client) => {
371+
assert.equal(
372+
await client.mSetEx(
373+
{
374+
"{key}1": "value1",
375+
"{key}2": "value2",
376+
},
377+
{
378+
expiration: {
379+
type: ExpirationMode.PXAT,
380+
value: Date.now() + 10000,
381+
},
382+
mode: SetMode.NX,
383+
}
384+
),
385+
1
386+
);
387+
},
388+
{
389+
client: { ...GLOBAL.SERVERS.OPEN, minimumDockerVersion: [8, 4] },
390+
cluster: { ...GLOBAL.CLUSTERS.OPEN, minimumDockerVersion: [8, 4] },
391+
}
392+
);
393+
});

0 commit comments

Comments
 (0)