Skip to content

Commit 054872f

Browse files
committed
churn(test): use redislabs/client-libs-test for testing
- `FT.SUGGET` [`WITHSCORES`] [`WITHPAYLOAD`] are now returning empty array `[]` instead of `null` in `8.0-M04-pre` - Update `FT.PROFILE` reply to include shards & coordinator profiles - Update default redis server version to `8.0-M04-pre` - `GEOPOS` command returns coordinates with 17 decimal places in Redis 8+ vs 14 decimal places in previous versions
1 parent 558ebb4 commit 054872f

23 files changed

+391
-119
lines changed

.github/workflows/tests.yml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,8 +21,8 @@ jobs:
2121
strategy:
2222
fail-fast: false
2323
matrix:
24-
node-version: ['18', '20', '22']
25-
redis-version: ['6.2.6-v17', '7.2.0-v13', '7.4.0-v1']
24+
node-version: [ '18', '20', '22' ]
25+
redis-version: [ 'rs-7.2.0-v13', 'rs-7.4.0-v1', '8.0-M04-pre' ]
2626
steps:
2727
- uses: actions/checkout@v4
2828
with:

packages/bloom/lib/test-utils.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,9 @@ import TestUtils from '@redis/test-utils';
22
import RedisBloomModules from '.';
33

44
export default new TestUtils({
5-
dockerImageName: 'redis/redis-stack',
5+
dockerImageName: 'redislabs/client-libs-test',
66
dockerImageVersionArgument: 'redisbloom-version',
7-
defaultDockerVersion: '7.4.0-v1'
7+
defaultDockerVersion: '8.0-M04-pre'
88
});
99

1010
export const GLOBAL = {

packages/client/lib/commands/GEOPOS.spec.ts

Lines changed: 133 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -32,21 +32,149 @@ describe('GEOPOS', () => {
3232

3333
testUtils.testAll('geoPos with member', async client => {
3434
const coordinates = {
35-
longitude: '-122.06429868936538696',
36-
latitude: '37.37749628831998194'
35+
longitude: '-122.06429868936539',
36+
latitude: '37.37749628831998'
3737
};
3838

3939
await client.geoAdd('key', {
4040
member: 'member',
4141
...coordinates
4242
});
4343

44-
assert.deepEqual(
45-
await client.geoPos('key', 'member'),
46-
[coordinates]
44+
const result = await client.geoPos('key', 'member');
45+
46+
/**
47+
* - Redis < 8: Returns coordinates with 14 decimal places (e.g., "-122.06429868936539")
48+
* - Redis 8+: Returns coordinates with 17 decimal places (e.g., "-122.06429868936538696")
49+
*
50+
*/
51+
const PRECISION = 13; // Number of decimal places to compare
52+
53+
assert.ok(result.length === 1, 'Expected one result');
54+
55+
assert.ok(
56+
compareWithPrecision(result[0].longitude, coordinates.longitude, PRECISION),
57+
`Longitude mismatch: ${result[0].longitude} vs ${coordinates.longitude}`
58+
);
59+
assert.ok(
60+
compareWithPrecision(result[0].latitude, coordinates.latitude, PRECISION),
61+
`Latitude mismatch: ${result[0].latitude} vs ${coordinates.latitude}`
4762
);
4863
}, {
4964
client: GLOBAL.SERVERS.OPEN,
5065
cluster: GLOBAL.CLUSTERS.OPEN
5166
});
5267
});
68+
69+
describe('compareWithPrecision', () => {
70+
it('should match exact same numbers', () => {
71+
assert.strictEqual(
72+
compareWithPrecision('123.456789', '123.456789', 6),
73+
true
74+
);
75+
});
76+
77+
it('should match when actual has more precision than needed', () => {
78+
assert.strictEqual(
79+
compareWithPrecision('123.456789123456', '123.456789', 6),
80+
true
81+
);
82+
});
83+
84+
it('should match when expected has more precision than needed', () => {
85+
assert.strictEqual(
86+
compareWithPrecision('123.456789', '123.456789123456', 6),
87+
true
88+
);
89+
});
90+
91+
it('should fail when decimals differ within precision', () => {
92+
assert.strictEqual(
93+
compareWithPrecision('123.456689', '123.456789', 6),
94+
false
95+
);
96+
});
97+
98+
it('should handle negative numbers', () => {
99+
assert.strictEqual(
100+
compareWithPrecision('-122.06429868936538', '-122.06429868936539', 13),
101+
true
102+
);
103+
});
104+
105+
it('should fail when integer parts differ', () => {
106+
assert.strictEqual(
107+
compareWithPrecision('124.456789', '123.456789', 6),
108+
false
109+
);
110+
});
111+
112+
it('should handle zero decimal places', () => {
113+
assert.strictEqual(
114+
compareWithPrecision('123.456789', '123.456789', 0),
115+
true
116+
);
117+
});
118+
119+
it('should handle numbers without decimal points', () => {
120+
assert.strictEqual(
121+
compareWithPrecision('123', '123', 6),
122+
true
123+
);
124+
});
125+
126+
it('should handle one number without decimal point', () => {
127+
assert.strictEqual(
128+
compareWithPrecision('123', '123.000', 3),
129+
false
130+
);
131+
});
132+
133+
it('should match Redis coordinates with different precision', () => {
134+
assert.strictEqual(
135+
compareWithPrecision(
136+
'-122.06429868936538696',
137+
'-122.06429868936539',
138+
13
139+
),
140+
true
141+
);
142+
});
143+
144+
it('should match Redis latitude with different precision', () => {
145+
assert.strictEqual(
146+
compareWithPrecision(
147+
'37.37749628831998194',
148+
'37.37749628831998',
149+
14
150+
),
151+
true
152+
);
153+
});
154+
});
155+
156+
// Helper function to compare with fixed decimal places
157+
const compareWithPrecision = (actual, expected, decimals) => {
158+
const actualDotIndex = actual.indexOf('.');
159+
const expectedDotIndex = expected.indexOf('.');
160+
161+
// If either number doesn't have a decimal point
162+
if (actualDotIndex === -1 || expectedDotIndex === -1) {
163+
// If both don't have decimal points, compare directly
164+
if (actualDotIndex === -1 && expectedDotIndex === -1) {
165+
return actual === expected;
166+
}
167+
// If only one has a decimal point, add .000... to the other
168+
const withoutDecimal = actualDotIndex === -1 ? actual : expected;
169+
const withDecimal = actualDotIndex === -1 ? expected : actual;
170+
return compareWithPrecision(withoutDecimal + '.0', withDecimal, decimals);
171+
}
172+
173+
const integerPart = actual.slice(0, actualDotIndex);
174+
const decimalPart = actual.slice(actualDotIndex + 1, actualDotIndex + 1 + decimals);
175+
176+
const expectedIntegerPart = expected.slice(0, expectedDotIndex);
177+
const expectedDecimalPart = expected.slice(expectedDotIndex + 1, expectedDotIndex + 1 + decimals);
178+
179+
return integerPart === expectedIntegerPart && decimalPart === expectedDecimalPart;
180+
};

packages/client/lib/test-utils.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,9 +6,9 @@ import { Command } from './RESP/types';
66
import { BasicCommandParser } from './client/parser';
77

88
const utils = new TestUtils({
9-
dockerImageName: 'redis/redis-stack',
9+
dockerImageName: 'redislabs/client-libs-test',
1010
dockerImageVersionArgument: 'redis-version',
11-
defaultDockerVersion: '7.4.0-v1'
11+
defaultDockerVersion: '8.0-M04-pre'
1212
});
1313

1414
export default utils;

packages/entraid/lib/test-utils.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,9 @@ import TestUtils from '@redis/test-utils';
44
import { EntraidCredentialsProvider } from './entraid-credentials-provider';
55

66
export const testUtils = new TestUtils({
7-
dockerImageName: 'redis/redis-stack',
7+
dockerImageName: 'redislabs/client-libs-test',
88
dockerImageVersionArgument: 'redis-version',
9-
defaultDockerVersion: '7.4.0-v1'
9+
defaultDockerVersion: '8.0-M04-pre'
1010
});
1111

1212
const DEBUG_MODE_ARGS = testUtils.isVersionGreaterThan([7]) ?

packages/graph/lib/test-utils.ts

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,11 @@
11
import TestUtils from '@redis/test-utils';
22
import RedisGraph from '.';
33

4+
45
export default new TestUtils({
5-
dockerImageName: 'redis/redis-stack',
6+
dockerImageName: 'redislabs/client-libs-test',
67
dockerImageVersionArgument: 'redisgraph-version',
7-
defaultDockerVersion: '7.4.0-v1'
8+
defaultDockerVersion: '8.0-M04-pre'
89
});
910

1011
export const GLOBAL = {

packages/json/lib/test-utils.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,9 @@ import TestUtils from '@redis/test-utils';
22
import RedisJSON from '.';
33

44
export default new TestUtils({
5-
dockerImageName: 'redis/redis-stack',
5+
dockerImageName: 'redislabs/client-libs-test',
66
dockerImageVersionArgument: 'redisgraph-version',
7-
defaultDockerVersion: '7.4.0-v1'
7+
defaultDockerVersion: '8.0-M04-pre'
88
});
99

1010
export const GLOBAL = {

packages/search/lib/commands/INFO.spec.ts

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,14 @@ describe('INFO', () => {
2424
index_name: 'index',
2525
index_options: [],
2626
index_definition: Object.create(null, {
27-
default_score: {
27+
28+
indexes_all: {
29+
value: 'false',
30+
configurable: true,
31+
enumerable: true
32+
},
33+
34+
default_score: {
2835
value: '1',
2936
configurable: true,
3037
enumerable: true

packages/search/lib/commands/PROFILE_AGGREGATE.spec.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -40,9 +40,9 @@ describe('PROFILE AGGREGATE', () => {
4040
]);
4141

4242
const res = await client.ft.profileAggregate('index', '*');
43-
assert.deepEqual('None', res.profile.warning);
44-
assert.ok(typeof res.profile.iteratorsProfile.counter === 'number');
45-
assert.ok(typeof res.profile.parsingTime === 'string');
43+
assert.deepEqual('None', res.shards[0].warning);
44+
assert.ok(typeof res.shards[0].iteratorsProfile.counter === 'number');
45+
assert.ok(typeof res.shards[0].parsingTime === 'string');
4646
assert.ok(res.results.total == 1);
4747
}, GLOBAL.SERVERS.OPEN);
4848
});
Lines changed: 31 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -1,37 +1,38 @@
11
import { CommandParser } from '@redis/client/dist/lib/client/parser';
2-
import { Command, ReplyUnion } from "@redis/client/dist/lib/RESP/types";
3-
import AGGREGATE, { AggregateRawReply, FtAggregateOptions, parseAggregateOptions } from "./AGGREGATE";
4-
import { ProfileOptions, ProfileRawReply, ProfileReply, transformProfile } from "./PROFILE_SEARCH";
2+
import { Command, ReplyUnion } from '@redis/client/dist/lib/RESP/types';
3+
import AGGREGATE, { AggregateRawReply, FtAggregateOptions, parseAggregateOptions } from './AGGREGATE';
4+
import { ProfileOptions, ProfileRawReply, ProfileReply, transformCoordinatorProfile, transformShardProfile } from './PROFILE_SEARCH';
55

66
export default {
77
NOT_KEYED_COMMAND: true,
8-
IS_READ_ONLY: true,
9-
parseCommand(
10-
parser: CommandParser,
11-
index: string,
12-
query: string,
13-
options?: ProfileOptions & FtAggregateOptions
14-
) {
15-
parser.push('FT.PROFILE', index, 'AGGREGATE');
16-
17-
if (options?.LIMITED) {
18-
parser.push('LIMITED');
19-
}
20-
21-
parser.push('QUERY', query);
8+
IS_READ_ONLY: true,
9+
parseCommand(
10+
parser: CommandParser,
11+
index: string,
12+
query: string,
13+
options?: ProfileOptions & FtAggregateOptions
14+
) {
15+
parser.push('FT.PROFILE', index, 'AGGREGATE');
2216

23-
parseAggregateOptions(parser, options)
24-
},
25-
transformReply: {
26-
2: (reply: ProfileAggeregateRawReply): ProfileReply => {
27-
return {
28-
results: AGGREGATE.transformReply[2](reply[0]),
29-
profile: transformProfile(reply[1])
30-
}
31-
},
32-
3: undefined as unknown as () => ReplyUnion
17+
if (options?.LIMITED) {
18+
parser.push('LIMITED');
19+
}
20+
21+
parser.push('QUERY', query);
22+
23+
parseAggregateOptions(parser, options)
24+
},
25+
transformReply: {
26+
2: (reply: ProfileAggeregateRawReply): ProfileReply => {
27+
return {
28+
results: AGGREGATE.transformReply[2](reply[0]),
29+
shards: transformShardProfile(reply[1]),
30+
coordinator: transformCoordinatorProfile(reply[1])
31+
}
3332
},
34-
unstableResp3: true
35-
} as const satisfies Command;
33+
3: undefined as unknown as () => ReplyUnion
34+
},
35+
unstableResp3: true
36+
} as const satisfies Command;
3637

37-
type ProfileAggeregateRawReply = ProfileRawReply<AggregateRawReply>;
38+
type ProfileAggeregateRawReply = ProfileRawReply<AggregateRawReply>;

0 commit comments

Comments
 (0)