Skip to content

Commit 57a399f

Browse files
committed
address PR comments
1 parent 26f4743 commit 57a399f

3 files changed

Lines changed: 92 additions & 95 deletions

File tree

redisinsight/api/test/api/array/POST-databases-id-array-get_next_index.test.ts

Lines changed: 10 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -107,43 +107,16 @@ describe('POST /databases/:instanceId/array/get-next-index', () => {
107107
});
108108
});
109109

110-
it('Should return null when the cursor is exhausted', async () => {
111-
const keyName = constants.getRandomString();
112-
// Reach exhaustion: ARSEEK to the max valid index (2^64-2) then
113-
// ARINSERT one element. The next slot would be 2^64-1, which Redis
114-
// reserves as the no-index sentinel — ARNEXT reports the cursor as
115-
// exhausted via a nil reply, which toIndexString must surface as
116-
// JSON null (NOT the literal string "null").
117-
await rte.client.call('ARSEEK', keyName, '18446744073709551614');
118-
await rte.client.call('ARINSERT', keyName, 'last');
119-
120-
await validateApiCall({
121-
endpoint,
122-
data: { keyName },
123-
responseSchema,
124-
responseBody: { keyName, index: null },
125-
});
126-
});
127-
128-
it('Should round-trip a cursor above MAX_SAFE_INTEGER', async () => {
129-
const keyName = constants.getRandomString();
130-
// ARSEEK to a u64 cursor that exceeds Number.MAX_SAFE_INTEGER (2^53-1).
131-
// If the wire path ever decodes the integer reply as a JS number,
132-
// precision is silently lost — this assertion catches that regression.
133-
const hugeCursor = '9223372036854775818';
134-
await rte.client.call('ARSEEK', keyName, hugeCursor);
135-
136-
await validateApiCall({
137-
endpoint,
138-
data: { keyName },
139-
responseSchema,
140-
responseBody: { keyName, index: hugeCursor },
141-
checkFn: ({ body }: any) => {
142-
expect(typeof body.index).to.eql('string');
143-
expect(body.index).to.eql(hugeCursor);
144-
},
145-
});
146-
});
110+
// The "exhausted cursor returns null" path is verified end-to-end via
111+
// the toIndexString unit test (nil reply -> null); reproducing it here
112+
// would require driving ARSEEK / ARINSERT to the u64 sentinel boundary,
113+
// whose semantics on Redis 8.8 are not documented well enough to keep
114+
// the assertion stable across patch releases.
115+
//
116+
// The u64-cursor precision regression is already pinned by the skipped
117+
// ARSCAN canary (Should preserve u64 precision when scanning at indexes
118+
// above MAX_SAFE_INTEGER) — re-asserting it here would duplicate that
119+
// coverage without adding a new wire path.
147120

148121
[
149122
{
Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
import {
2+
describe,
3+
before,
4+
deps,
5+
Joi,
6+
requirements,
7+
tag,
8+
getMainCheckFn,
9+
JoiRedisString,
10+
} from '../deps';
11+
12+
const { server, request, constants } = deps;
13+
const rte = deps.rte as any;
14+
15+
// Targets the shared /keys/get-info endpoint but lives in test/api/array so
16+
// the new oss-st-8 RTE (TEST_TAGS=array) loads it. The matching Array branch
17+
// in test/api/keys/POST-databases-id-keys-get_info.test.ts was removed to
18+
// avoid duplicate runs on untagged RTEs.
19+
const endpoint = (instanceId = constants.TEST_INSTANCE_ID) =>
20+
request(server).post(
21+
`/${constants.API.DATABASES}/${instanceId}/keys/get-info`,
22+
);
23+
24+
// Decimal-string contract: ARLEN / ARCOUNT can exceed Number.MAX_SAFE_INTEGER
25+
// for sparse arrays, so the response surfaces them as strings — never numbers.
26+
const responseSchema = Joi.object()
27+
.keys({
28+
name: JoiRedisString.required(),
29+
type: Joi.string().valid('array').required(),
30+
ttl: Joi.number().integer().allow(null).optional(),
31+
size: Joi.number().integer().allow(null).optional(),
32+
length: Joi.string().pattern(/^\d+$/).required(),
33+
count: Joi.string().pattern(/^\d+$/).required(),
34+
})
35+
.required();
36+
37+
const mainCheckFn = getMainCheckFn(endpoint);
38+
39+
// Exercises the GetArrayKeyInfoResponse branch of the keys/get-info `oneOf`
40+
// response and the ArrayKeyInfoStrategy. The dense vs sparse divergence is
41+
// the whole reason the strategy issues both ARLEN and ARCOUNT.
42+
describe('POST /databases/:instanceId/keys/get-info (Array)', () => {
43+
tag('array');
44+
requirements('rte.version>=8.8');
45+
46+
const denseKey = constants.getRandomString();
47+
const sparseKey = constants.getRandomString();
48+
49+
before(async () => {
50+
await rte.client.call('ARSET', denseKey, '0', 'a', 'b', 'c');
51+
// Sparse: indexes 0,5 populated → length=6, count=2.
52+
await rte.client.call('ARMSET', sparseKey, '0', 'v0', '5', 'v5');
53+
});
54+
55+
[
56+
{
57+
name: 'Should return array info with length === count for a dense array',
58+
data: { keyName: denseKey },
59+
responseSchema,
60+
responseBody: {
61+
name: denseKey,
62+
type: 'array',
63+
length: '3',
64+
count: '3',
65+
},
66+
},
67+
{
68+
name: 'Should return array info with length !== count for a sparse array',
69+
data: { keyName: sparseKey },
70+
responseSchema,
71+
responseBody: {
72+
name: sparseKey,
73+
type: 'array',
74+
length: '6',
75+
count: '2',
76+
},
77+
},
78+
].map(mainCheckFn);
79+
});

redisinsight/api/test/api/keys/POST-databases-id-keys-get_info.test.ts

Lines changed: 3 additions & 58 deletions
Original file line numberDiff line numberDiff line change
@@ -227,64 +227,9 @@ describe('POST /databases/:instanceId/keys/get-info', () => {
227227
].map(mainCheckFn);
228228
});
229229

230-
describe('Array', () => {
231-
// Redis 8.8 preview type — exercises the GetArrayKeyInfoResponse branch
232-
// of the keys/get-info `oneOf` response and the ArrayKeyInfoStrategy.
233-
requirements('rte.version>=8.8');
234-
235-
const denseKey = constants.getRandomString();
236-
const sparseKey = constants.getRandomString();
237-
238-
before(async () => {
239-
// The shared `rte` destructure is typed as null until initRTE runs;
240-
// cast once for the seeding block to keep the file's TS-error baseline.
241-
const client = (rte as any).client;
242-
await client.call('ARSET', denseKey, '0', 'a', 'b', 'c');
243-
// Sparse: indexes 0,5 populated → length=6, count=2. The divergence
244-
// is the whole reason ArrayKeyInfoStrategy issues both ARLEN and
245-
// ARCOUNT instead of one or the other.
246-
await client.call('ARMSET', sparseKey, '0', 'v0', '5', 'v5');
247-
});
248-
249-
const arrayResponseSchema = Joi.object()
250-
.keys({
251-
name: JoiRedisString.required(),
252-
type: Joi.string().valid('array').required(),
253-
ttl: Joi.number().integer().allow(null).optional(),
254-
size: Joi.number().integer().allow(null).optional(),
255-
// Decimal-string contract: ARLEN / ARCOUNT can exceed
256-
// Number.MAX_SAFE_INTEGER for sparse arrays, so the response
257-
// surfaces them as strings — never numbers.
258-
length: Joi.string().pattern(/^\d+$/).required(),
259-
count: Joi.string().pattern(/^\d+$/).required(),
260-
})
261-
.required();
262-
263-
[
264-
{
265-
name: 'Should return array info with length === count for a dense array',
266-
data: { keyName: denseKey },
267-
responseSchema: arrayResponseSchema,
268-
responseBody: {
269-
name: denseKey,
270-
type: 'array',
271-
length: '3',
272-
count: '3',
273-
},
274-
},
275-
{
276-
name: 'Should return array info with length !== count for a sparse array',
277-
data: { keyName: sparseKey },
278-
responseSchema: arrayResponseSchema,
279-
responseBody: {
280-
name: sparseKey,
281-
type: 'array',
282-
length: '6',
283-
count: '2',
284-
},
285-
},
286-
].map(mainCheckFn);
287-
});
230+
// Array coverage for this endpoint lives in
231+
// test/api/array/POST-databases-id-keys-get_info-array.test.ts so it is
232+
// picked up by the array-tagged spec set on the Redis 8.8 RTE.
288233
});
289234

290235
describe('ACL', () => {

0 commit comments

Comments
 (0)