From 31aa61bdda35d8c51e2415ca841d4ecd075fa50f Mon Sep 17 00:00:00 2001 From: leibale Date: Mon, 12 Jul 2021 18:08:54 -0400 Subject: [PATCH] run some tests only on supported redis versions, use coveralls parallel mode --- .github/workflows/tests.yml | 15 +- lib/client.spec.ts | 9 +- lib/commands/ACL_CAT.spec.ts | 3 + lib/commands/ACL_DELUSER.spec.ts | 4 +- lib/commands/ACL_GENPASS.spec.ts | 3 + lib/commands/ACL_GETUSER.spec.ts | 4 +- lib/commands/ACL_LIST.spec.ts | 3 + lib/commands/ACL_LOAD.spec.ts | 3 + lib/commands/ACL_LOG.spec.ts | 3 + lib/commands/ACL_LOG_RESET.spec.ts | 3 + lib/commands/ACL_SAVE.spec.ts | 3 + lib/commands/ACL_SETUSER.spec.ts | 3 + lib/commands/ACL_USERS.spec.ts | 3 + lib/commands/ACL_WHOAMI.spec.ts | 3 + lib/commands/BLMOVE.spec.ts | 4 +- lib/commands/COPY.spec.ts | 4 +- lib/commands/HRANDFIELD.spec.ts | 4 +- lib/commands/HRANDFIELD_COUNT.spec.ts | 4 +- .../HRANDFIELD_COUNT_WITHVALUES.spec.ts | 4 +- lib/commands/LMOVE.spec.ts | 4 +- lib/commands/LPOP_COUNT.spec.ts | 4 +- lib/commands/LPOS.spec.ts | 4 +- lib/commands/LPOS_COUNT.spec.ts | 4 +- lib/commands/RPOP_COUNT.spec.ts | 4 +- lib/commands/SET.spec.ts | 2 + lib/commands/SISMEMBER.spec.ts | 4 +- lib/commands/XAUTOCLAIM.spec.ts | 4 +- lib/commands/XAUTOCLAIM_JUSTID.spec.ts | 4 +- lib/commands/XGROUP_CREATECONSUMER.spec.ts | 4 +- lib/commands/XINFO_STREAM.ts | 58 ++- lib/commands/ZDIFF.spec.ts | 4 +- lib/commands/ZDIFFSTORE.spec.ts | 4 +- lib/commands/ZDIFF_WITHSCORES.spec.ts | 4 +- lib/commands/ZINTER.spec.ts | 4 +- lib/commands/ZINTER_WITHSCORES.spec.ts | 4 +- lib/commands/ZMSCORE.spec.ts | 4 +- lib/commands/ZRANDMEMBER.spec.ts | 4 +- lib/commands/ZRANDMEMBER_COUNT.spec.ts | 4 +- .../ZRANDMEMBER_COUNT_WITHSCORES.spec.ts | 4 +- lib/commands/ZRANGESTORE.spec.ts | 4 +- lib/commands/ZUNION.spec.ts | 4 +- lib/commands/ZUNION_WITHSCORES.spec.ts | 4 +- lib/test-utils.ts | 356 ++++++++++-------- 43 files changed, 383 insertions(+), 199 deletions(-) diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 9e04bc4ef6..5511b42f6d 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -7,13 +7,12 @@ on: jobs: tests: - name: Tests runs-on: ubuntu-latest strategy: fail-fast: false matrix: node-version: [12.x, 14.x, 16.x] - redis-version: [6.x, 5.x] + redis-version: [5.x, 6.x] steps: - uses: actions/checkout@v2.3.4 @@ -44,3 +43,15 @@ jobs: uses: coverallsapp/github-action@v1.1.2 with: github-token: ${{ secrets.GITHUB_TOKEN }} + flag-name: Node ${{ matrix.node-version }} Redis ${{ matrix.redis-version }} + parallel: true + + finish: + needs: tests + runs-on: ubuntu-latest + steps: + - name: Coveralls Finished + uses: coverallsapp/github-action@master + with: + github-token: ${{ secrets.github_token }} + parallel-finished: true diff --git a/lib/client.spec.ts b/lib/client.spec.ts index 21a93e4e28..cb17adf75c 100644 --- a/lib/client.spec.ts +++ b/lib/client.spec.ts @@ -1,6 +1,6 @@ import { strict as assert } from 'assert'; import { once } from 'events'; -import { itWithClient, TEST_REDIS_SERVERS, TestRedisServers, waitTillBeenCalled } from './test-utils'; +import { itWithClient, TEST_REDIS_SERVERS, TestRedisServers, waitTillBeenCalled, isRedisVersionGreaterThan } from './test-utils'; import RedisClient from './client'; import { AbortError } from './errors'; import { defineScript } from './lua-script'; @@ -26,7 +26,10 @@ describe('Client', () => { await assert.rejects( client.connect(), { - message: 'WRONGPASS invalid username-password pair or user is disabled.' + + message: isRedisVersionGreaterThan([6]) ? + 'WRONGPASS invalid username-password pair or user is disabled.' : + 'ERR invalid password' } ); @@ -114,7 +117,7 @@ describe('Client', () => { }); it('client.{command} should accept mix of strings and array of strings', done => { - (client as any).set(['a'], 'b', ['GET'], (err?: Error, reply?: string) => { + (client as any).set(['a'], 'b', ['XX'], (err?: Error, reply?: string) => { if (err) { return done(err); } diff --git a/lib/commands/ACL_CAT.spec.ts b/lib/commands/ACL_CAT.spec.ts index 118122bb1e..77ed1cb7a0 100644 --- a/lib/commands/ACL_CAT.spec.ts +++ b/lib/commands/ACL_CAT.spec.ts @@ -1,7 +1,10 @@ import { strict as assert } from 'assert'; +import { describeHandleMinimumRedisVersion } from '../test-utils'; import { transformArguments } from './ACL_CAT'; describe('ACL CAT', () => { + describeHandleMinimumRedisVersion([6]); + describe('transformArguments', () => { it('simple', () => { assert.deepEqual( diff --git a/lib/commands/ACL_DELUSER.spec.ts b/lib/commands/ACL_DELUSER.spec.ts index e23bc5e886..c64e8db196 100644 --- a/lib/commands/ACL_DELUSER.spec.ts +++ b/lib/commands/ACL_DELUSER.spec.ts @@ -1,8 +1,10 @@ import { strict as assert } from 'assert'; -import { itWithClient, TestRedisServers } from '../test-utils'; +import { describeHandleMinimumRedisVersion, itWithClient, TestRedisServers } from '../test-utils'; import { transformArguments } from './ACL_DELUSER'; describe('ACL DELUSER', () => { + describeHandleMinimumRedisVersion([6]); + describe('transformArguments', () => { it('string', () => { assert.deepEqual( diff --git a/lib/commands/ACL_GENPASS.spec.ts b/lib/commands/ACL_GENPASS.spec.ts index d07df4b4dd..a288a4f714 100644 --- a/lib/commands/ACL_GENPASS.spec.ts +++ b/lib/commands/ACL_GENPASS.spec.ts @@ -1,7 +1,10 @@ import { strict as assert } from 'assert'; +import { describeHandleMinimumRedisVersion } from '../test-utils'; import { transformArguments } from './ACL_GENPASS'; describe('ACL GENPASS', () => { + describeHandleMinimumRedisVersion([6]); + describe('transformArguments', () => { it('simple', () => { assert.deepEqual( diff --git a/lib/commands/ACL_GETUSER.spec.ts b/lib/commands/ACL_GETUSER.spec.ts index 4e7d5af955..c43cdc364a 100644 --- a/lib/commands/ACL_GETUSER.spec.ts +++ b/lib/commands/ACL_GETUSER.spec.ts @@ -1,8 +1,10 @@ import { strict as assert } from 'assert'; -import { itWithClient, TestRedisServers } from '../test-utils'; +import { describeHandleMinimumRedisVersion, itWithClient, TestRedisServers } from '../test-utils'; import { transformArguments } from './ACL_GETUSER'; describe('ACL GETUSER', () => { + describeHandleMinimumRedisVersion([6]); + it('transformArguments', () => { assert.deepEqual( transformArguments('username'), diff --git a/lib/commands/ACL_LIST.spec.ts b/lib/commands/ACL_LIST.spec.ts index 288bc0024d..ab6bae762f 100644 --- a/lib/commands/ACL_LIST.spec.ts +++ b/lib/commands/ACL_LIST.spec.ts @@ -1,7 +1,10 @@ import { strict as assert } from 'assert'; +import { describeHandleMinimumRedisVersion } from '../test-utils'; import { transformArguments } from './ACL_LIST'; describe('ACL LIST', () => { + describeHandleMinimumRedisVersion([6]); + it('transformArguments', () => { assert.deepEqual( transformArguments(), diff --git a/lib/commands/ACL_LOAD.spec.ts b/lib/commands/ACL_LOAD.spec.ts index 56e9b4ed63..d173d7f135 100644 --- a/lib/commands/ACL_LOAD.spec.ts +++ b/lib/commands/ACL_LOAD.spec.ts @@ -1,7 +1,10 @@ import { strict as assert } from 'assert'; +import { describeHandleMinimumRedisVersion } from '../test-utils'; import { transformArguments } from './ACL_SAVE'; describe('ACL SAVE', () => { + describeHandleMinimumRedisVersion([6]); + it('transformArguments', () => { assert.deepEqual( transformArguments(), diff --git a/lib/commands/ACL_LOG.spec.ts b/lib/commands/ACL_LOG.spec.ts index a814fac83c..3ae25fdf6b 100644 --- a/lib/commands/ACL_LOG.spec.ts +++ b/lib/commands/ACL_LOG.spec.ts @@ -1,7 +1,10 @@ import { strict as assert } from 'assert'; +import { describeHandleMinimumRedisVersion } from '../test-utils'; import { transformArguments } from './ACL_LOG'; describe('ACL LOG', () => { + describeHandleMinimumRedisVersion([6]); + describe('transformArguments', () => { it('simple', () => { assert.deepEqual( diff --git a/lib/commands/ACL_LOG_RESET.spec.ts b/lib/commands/ACL_LOG_RESET.spec.ts index 6809f24842..3f0e628d9f 100644 --- a/lib/commands/ACL_LOG_RESET.spec.ts +++ b/lib/commands/ACL_LOG_RESET.spec.ts @@ -1,7 +1,10 @@ import { strict as assert } from 'assert'; +import { describeHandleMinimumRedisVersion } from '../test-utils'; import { transformArguments } from './ACL_LOG_RESET'; describe('ACL LOG RESET', () => { + describeHandleMinimumRedisVersion([6]); + it('transformArguments', () => { assert.deepEqual( transformArguments(), diff --git a/lib/commands/ACL_SAVE.spec.ts b/lib/commands/ACL_SAVE.spec.ts index b22583a730..b34c7bb0e6 100644 --- a/lib/commands/ACL_SAVE.spec.ts +++ b/lib/commands/ACL_SAVE.spec.ts @@ -1,7 +1,10 @@ import { strict as assert } from 'assert'; +import { describeHandleMinimumRedisVersion } from '../test-utils'; import { transformArguments } from './ACL_LOAD'; describe('ACL LOAD', () => { + describeHandleMinimumRedisVersion([6]); + it('transformArguments', () => { assert.deepEqual( transformArguments(), diff --git a/lib/commands/ACL_SETUSER.spec.ts b/lib/commands/ACL_SETUSER.spec.ts index 82560669e2..f3badfcdca 100644 --- a/lib/commands/ACL_SETUSER.spec.ts +++ b/lib/commands/ACL_SETUSER.spec.ts @@ -1,7 +1,10 @@ import { strict as assert } from 'assert'; +import { describeHandleMinimumRedisVersion } from '../test-utils'; import { transformArguments } from './ACL_SETUSER'; describe('ACL SETUSER', () => { + describeHandleMinimumRedisVersion([6]); + describe('transformArguments', () => { it('string', () => { assert.deepEqual( diff --git a/lib/commands/ACL_USERS.spec.ts b/lib/commands/ACL_USERS.spec.ts index 26417181a8..14b76725fc 100644 --- a/lib/commands/ACL_USERS.spec.ts +++ b/lib/commands/ACL_USERS.spec.ts @@ -1,7 +1,10 @@ import { strict as assert } from 'assert'; +import { describeHandleMinimumRedisVersion } from '../test-utils'; import { transformArguments } from './ACL_USERS'; describe('ACL USERS', () => { + describeHandleMinimumRedisVersion([6]); + it('transformArguments', () => { assert.deepEqual( transformArguments(), diff --git a/lib/commands/ACL_WHOAMI.spec.ts b/lib/commands/ACL_WHOAMI.spec.ts index 03bd42d256..a933057ea9 100644 --- a/lib/commands/ACL_WHOAMI.spec.ts +++ b/lib/commands/ACL_WHOAMI.spec.ts @@ -1,7 +1,10 @@ import { strict as assert } from 'assert'; +import { describeHandleMinimumRedisVersion } from '../test-utils'; import { transformArguments } from './ACL_WHOAMI'; describe('ACL WHOAMI', () => { + describeHandleMinimumRedisVersion([6]); + it('transformArguments', () => { assert.deepEqual( transformArguments(), diff --git a/lib/commands/BLMOVE.spec.ts b/lib/commands/BLMOVE.spec.ts index 8ff289d3c3..517009dd37 100644 --- a/lib/commands/BLMOVE.spec.ts +++ b/lib/commands/BLMOVE.spec.ts @@ -1,10 +1,12 @@ import { strict as assert } from 'assert'; -import { TestRedisServers, itWithClient, itWithCluster, TestRedisClusters } from '../test-utils'; +import { TestRedisServers, itWithClient, itWithCluster, TestRedisClusters, describeHandleMinimumRedisVersion } from '../test-utils'; import { transformArguments } from './BLMOVE'; import RedisClient from '../client'; import RedisCluster from '../cluster'; describe('BLMOVE', () => { + describeHandleMinimumRedisVersion([6, 2]); + it('transformArguments', () => { assert.deepEqual( transformArguments('source', 'destination', 'LEFT', 'RIGHT', 0), diff --git a/lib/commands/COPY.spec.ts b/lib/commands/COPY.spec.ts index fe2930f6cc..fb35be863a 100644 --- a/lib/commands/COPY.spec.ts +++ b/lib/commands/COPY.spec.ts @@ -1,8 +1,10 @@ import { strict as assert } from 'assert'; -import { TestRedisServers, itWithClient } from '../test-utils'; +import { TestRedisServers, itWithClient, describeHandleMinimumRedisVersion } from '../test-utils'; import { transformArguments, transformReply } from './COPY'; describe('COPY', () => { + describeHandleMinimumRedisVersion([6, 2]); + describe('transformArguments', () => { it('simple', () => { assert.deepEqual( diff --git a/lib/commands/HRANDFIELD.spec.ts b/lib/commands/HRANDFIELD.spec.ts index 6203b507b1..70e2585cf9 100644 --- a/lib/commands/HRANDFIELD.spec.ts +++ b/lib/commands/HRANDFIELD.spec.ts @@ -1,8 +1,10 @@ import { strict as assert } from 'assert'; -import { TestRedisServers, itWithClient } from '../test-utils'; +import { TestRedisServers, itWithClient, describeHandleMinimumRedisVersion } from '../test-utils'; import { transformArguments } from './HRANDFIELD'; describe('HRANDFIELD', () => { + describeHandleMinimumRedisVersion([6, 2]); + it('transformArguments', () => { assert.deepEqual( transformArguments('key'), diff --git a/lib/commands/HRANDFIELD_COUNT.spec.ts b/lib/commands/HRANDFIELD_COUNT.spec.ts index a971143524..f1221c82de 100644 --- a/lib/commands/HRANDFIELD_COUNT.spec.ts +++ b/lib/commands/HRANDFIELD_COUNT.spec.ts @@ -1,8 +1,10 @@ import { strict as assert } from 'assert'; -import { TestRedisServers, itWithClient } from '../test-utils'; +import { TestRedisServers, itWithClient, describeHandleMinimumRedisVersion } from '../test-utils'; import { transformArguments } from './HRANDFIELD_COUNT'; describe('HRANDFIELD COUNT', () => { + describeHandleMinimumRedisVersion([6, 2]); + it('transformArguments', () => { assert.deepEqual( transformArguments('key', 1), diff --git a/lib/commands/HRANDFIELD_COUNT_WITHVALUES.spec.ts b/lib/commands/HRANDFIELD_COUNT_WITHVALUES.spec.ts index 47145dc30e..2e8db18a52 100644 --- a/lib/commands/HRANDFIELD_COUNT_WITHVALUES.spec.ts +++ b/lib/commands/HRANDFIELD_COUNT_WITHVALUES.spec.ts @@ -1,8 +1,10 @@ import { strict as assert } from 'assert'; -import { TestRedisServers, itWithClient } from '../test-utils'; +import { TestRedisServers, itWithClient, describeHandleMinimumRedisVersion } from '../test-utils'; import { transformArguments } from './HRANDFIELD_COUNT_WITHVALUES'; describe('HRANDFIELD COUNT WITHVALUES', () => { + describeHandleMinimumRedisVersion([6, 2]); + it('transformArguments', () => { assert.deepEqual( transformArguments('key', 1), diff --git a/lib/commands/LMOVE.spec.ts b/lib/commands/LMOVE.spec.ts index 94d7be2076..bcb897f76a 100644 --- a/lib/commands/LMOVE.spec.ts +++ b/lib/commands/LMOVE.spec.ts @@ -1,8 +1,10 @@ import { strict as assert } from 'assert'; -import { TestRedisServers, itWithClient, itWithCluster, TestRedisClusters } from '../test-utils'; +import { TestRedisServers, itWithClient, itWithCluster, TestRedisClusters, describeHandleMinimumRedisVersion } from '../test-utils'; import { transformArguments } from './LMOVE'; describe('LMOVE', () => { + describeHandleMinimumRedisVersion([6, 2]); + it('transformArguments', () => { assert.deepEqual( transformArguments('source', 'destination', 'LEFT', 'RIGHT'), diff --git a/lib/commands/LPOP_COUNT.spec.ts b/lib/commands/LPOP_COUNT.spec.ts index 6d28505ccc..89150dbf4d 100644 --- a/lib/commands/LPOP_COUNT.spec.ts +++ b/lib/commands/LPOP_COUNT.spec.ts @@ -1,8 +1,10 @@ import { strict as assert } from 'assert'; -import { TestRedisServers, itWithClient, itWithCluster, TestRedisClusters } from '../test-utils'; +import { TestRedisServers, itWithClient, itWithCluster, TestRedisClusters, describeHandleMinimumRedisVersion } from '../test-utils'; import { transformArguments } from './LPOP_COUNT'; describe('LPOP COUNT', () => { + describeHandleMinimumRedisVersion([6, 2]); + it('transformArguments', () => { assert.deepEqual( transformArguments('key', 1), diff --git a/lib/commands/LPOS.spec.ts b/lib/commands/LPOS.spec.ts index 0fae55fee1..1cf9e35209 100644 --- a/lib/commands/LPOS.spec.ts +++ b/lib/commands/LPOS.spec.ts @@ -1,8 +1,10 @@ import { strict as assert } from 'assert'; -import { TestRedisServers, itWithClient, itWithCluster, TestRedisClusters } from '../test-utils'; +import { TestRedisServers, itWithClient, TestRedisClusters, itWithCluster, describeHandleMinimumRedisVersion } from '../test-utils'; import { transformArguments } from './LPOS'; describe('LPOS', () => { + describeHandleMinimumRedisVersion([6, 0, 6]); + describe('transformArguments', () => { it('simple', () => { assert.deepEqual( diff --git a/lib/commands/LPOS_COUNT.spec.ts b/lib/commands/LPOS_COUNT.spec.ts index 0a5ade39e7..1d80bd45c3 100644 --- a/lib/commands/LPOS_COUNT.spec.ts +++ b/lib/commands/LPOS_COUNT.spec.ts @@ -1,8 +1,10 @@ import { strict as assert } from 'assert'; -import { TestRedisServers, itWithClient, itWithCluster, TestRedisClusters } from '../test-utils'; +import { TestRedisServers, itWithClient, itWithCluster, TestRedisClusters, describeHandleMinimumRedisVersion } from '../test-utils'; import { transformArguments } from './LPOS_COUNT'; describe('LPOS COUNT', () => { + describeHandleMinimumRedisVersion([6, 0, 6]); + describe('transformArguments', () => { it('simple', () => { assert.deepEqual( diff --git a/lib/commands/RPOP_COUNT.spec.ts b/lib/commands/RPOP_COUNT.spec.ts index 87d52b9f00..2624540f12 100644 --- a/lib/commands/RPOP_COUNT.spec.ts +++ b/lib/commands/RPOP_COUNT.spec.ts @@ -1,8 +1,10 @@ import { strict as assert } from 'assert'; -import { TestRedisServers, itWithClient, itWithCluster, TestRedisClusters } from '../test-utils'; +import { TestRedisServers, itWithClient, itWithCluster, TestRedisClusters, describeHandleMinimumRedisVersion } from '../test-utils'; import { transformArguments } from './RPOP_COUNT'; describe('RPOP COUNT', () => { + describeHandleMinimumRedisVersion([6, 2]); + it('transformArguments', () => { assert.deepEqual( transformArguments('key', 1), diff --git a/lib/commands/SET.spec.ts b/lib/commands/SET.spec.ts index 5ddb97989f..a587f6c312 100644 --- a/lib/commands/SET.spec.ts +++ b/lib/commands/SET.spec.ts @@ -114,6 +114,8 @@ describe('SET', () => { }), null ); + }, { + minimumRedisVersion: [6, 2] }); }); }); diff --git a/lib/commands/SISMEMBER.spec.ts b/lib/commands/SISMEMBER.spec.ts index 5ce894956f..fec4ebfc57 100644 --- a/lib/commands/SISMEMBER.spec.ts +++ b/lib/commands/SISMEMBER.spec.ts @@ -1,8 +1,10 @@ import { strict as assert } from 'assert'; -import { TestRedisServers, itWithClient } from '../test-utils'; +import { TestRedisServers, itWithClient, describeHandleMinimumRedisVersion } from '../test-utils'; import { transformArguments } from './SISMEMBER'; describe('SISMEMBER', () => { + describeHandleMinimumRedisVersion([6, 2]); + it('transformArguments', () => { assert.deepEqual( transformArguments('key', 'member'), diff --git a/lib/commands/XAUTOCLAIM.spec.ts b/lib/commands/XAUTOCLAIM.spec.ts index 7414d48c06..a0818d5c2c 100644 --- a/lib/commands/XAUTOCLAIM.spec.ts +++ b/lib/commands/XAUTOCLAIM.spec.ts @@ -1,8 +1,10 @@ import { strict as assert } from 'assert'; -import { TestRedisServers, itWithClient } from '../test-utils'; +import { TestRedisServers, itWithClient, describeHandleMinimumRedisVersion } from '../test-utils'; import { transformArguments } from './XAUTOCLAIM'; describe('XAUTOCLAIM', () => { + describeHandleMinimumRedisVersion([6, 2]); + describe('transformArguments', () => { it('simple', () => { assert.deepEqual( diff --git a/lib/commands/XAUTOCLAIM_JUSTID.spec.ts b/lib/commands/XAUTOCLAIM_JUSTID.spec.ts index af8f9c0751..d076f28751 100644 --- a/lib/commands/XAUTOCLAIM_JUSTID.spec.ts +++ b/lib/commands/XAUTOCLAIM_JUSTID.spec.ts @@ -1,8 +1,10 @@ import { strict as assert } from 'assert'; -import { TestRedisServers, itWithClient } from '../test-utils'; +import { TestRedisServers, itWithClient, describeHandleMinimumRedisVersion } from '../test-utils'; import { transformArguments } from './XAUTOCLAIM_JUSTID'; describe('XAUTOCLAIM JUSTID', () => { + describeHandleMinimumRedisVersion([6, 2]); + it('transformArguments', () => { assert.deepEqual( transformArguments('key', 'group', 'consumer', 1, '0-0'), diff --git a/lib/commands/XGROUP_CREATECONSUMER.spec.ts b/lib/commands/XGROUP_CREATECONSUMER.spec.ts index aaeb1794e0..5b06188e30 100644 --- a/lib/commands/XGROUP_CREATECONSUMER.spec.ts +++ b/lib/commands/XGROUP_CREATECONSUMER.spec.ts @@ -1,8 +1,10 @@ import { strict as assert } from 'assert'; -import { TestRedisServers, itWithClient } from '../test-utils'; +import { TestRedisServers, itWithClient, describeHandleMinimumRedisVersion } from '../test-utils'; import { transformArguments } from './XGROUP_CREATECONSUMER'; describe('XGROUP CREATECONSUMER', () => { + describeHandleMinimumRedisVersion([6, 2]); + it('transformArguments', () => { assert.deepEqual( transformArguments('key', 'group', 'consumer'), diff --git a/lib/commands/XINFO_STREAM.ts b/lib/commands/XINFO_STREAM.ts index 550b85989c..bdaebf2749 100644 --- a/lib/commands/XINFO_STREAM.ts +++ b/lib/commands/XINFO_STREAM.ts @@ -18,20 +18,46 @@ interface XInfoStreamReply { lastEntry: StreamMessageReply | null; }; -export function transformReply(reply: Array): XInfoStreamReply { - return { - length: reply[1], - radixTreeKeys: reply[3], - radixTreeNodes: reply[5], - lastGeneratedId: reply[7], - groups: reply[9], - firstEntry: reply[11] ? { - id: reply[11][0] ?? null, - message: transformReplyTuples(reply[11][1]) - } : null, - lastEntry: reply[13] ? { - id: reply[13][0], - message: transformReplyTuples(reply[13][1]) - } : null - }; +export function transformReply(rawReply: Array): XInfoStreamReply { + const parsedReply: Partial = {}; + + for (let i = 0; i < rawReply.length; i+= 2) { + switch (rawReply[i]) { + case 'length': + parsedReply.length = rawReply[i + 1]; + break; + + case 'radix-tree-keys': + parsedReply.radixTreeKeys = rawReply[i + 1]; + break; + + case 'radix-tree-nodes': + parsedReply.radixTreeNodes = rawReply[i + 1]; + break; + + case 'groups': + parsedReply.groups = rawReply[i + 1]; + break; + + case 'last-generated-id': + parsedReply.lastGeneratedId = rawReply[i + 1]; + break; + + case 'first-entry': + parsedReply.firstEntry = { + id: rawReply[i + 1][0], + message: transformReplyTuples(rawReply[i + 1][1]) + }; + break; + + case 'last-entry': + parsedReply.lastEntry = { + id: rawReply[i + 1][0], + message: transformReplyTuples(rawReply[i + 1][1]) + }; + break; + } + } + + return parsedReply as XInfoStreamReply; } diff --git a/lib/commands/ZDIFF.spec.ts b/lib/commands/ZDIFF.spec.ts index 14b0c780c4..f45b2af7ed 100644 --- a/lib/commands/ZDIFF.spec.ts +++ b/lib/commands/ZDIFF.spec.ts @@ -1,8 +1,10 @@ import { strict as assert } from 'assert'; -import { TestRedisServers, itWithClient } from '../test-utils'; +import { TestRedisServers, itWithClient, describeHandleMinimumRedisVersion } from '../test-utils'; import { transformArguments } from './ZDIFF'; describe('ZDIFF', () => { + describeHandleMinimumRedisVersion([6, 2]); + describe('transformArguments', () => { it('string', () => { assert.deepEqual( diff --git a/lib/commands/ZDIFFSTORE.spec.ts b/lib/commands/ZDIFFSTORE.spec.ts index f2a7a42b21..5fbeebaf50 100644 --- a/lib/commands/ZDIFFSTORE.spec.ts +++ b/lib/commands/ZDIFFSTORE.spec.ts @@ -1,8 +1,10 @@ import { strict as assert } from 'assert'; -import { TestRedisServers, itWithClient } from '../test-utils'; +import { TestRedisServers, itWithClient, describeHandleMinimumRedisVersion } from '../test-utils'; import { transformArguments } from './ZDIFFSTORE'; describe('ZDIFFSTORE', () => { + describeHandleMinimumRedisVersion([6, 2]); + describe('transformArguments', () => { it('string', () => { assert.deepEqual( diff --git a/lib/commands/ZDIFF_WITHSCORES.spec.ts b/lib/commands/ZDIFF_WITHSCORES.spec.ts index febb71e4d9..99c2310829 100644 --- a/lib/commands/ZDIFF_WITHSCORES.spec.ts +++ b/lib/commands/ZDIFF_WITHSCORES.spec.ts @@ -1,8 +1,10 @@ import { strict as assert } from 'assert'; -import { TestRedisServers, itWithClient } from '../test-utils'; +import { TestRedisServers, itWithClient, describeHandleMinimumRedisVersion } from '../test-utils'; import { transformArguments } from './ZDIFF_WITHSCORES'; describe('ZDIFF WITHSCORES', () => { + describeHandleMinimumRedisVersion([6, 2]); + describe('transformArguments', () => { it('string', () => { assert.deepEqual( diff --git a/lib/commands/ZINTER.spec.ts b/lib/commands/ZINTER.spec.ts index 82940cff4f..998c46fd3e 100644 --- a/lib/commands/ZINTER.spec.ts +++ b/lib/commands/ZINTER.spec.ts @@ -1,8 +1,10 @@ import { strict as assert } from 'assert'; -import { TestRedisServers, itWithClient } from '../test-utils'; +import { TestRedisServers, itWithClient, describeHandleMinimumRedisVersion } from '../test-utils'; import { transformArguments } from './ZINTER'; describe('ZINTER', () => { + describeHandleMinimumRedisVersion([6, 2]); + describe('transformArguments', () => { it('key (string)', () => { assert.deepEqual( diff --git a/lib/commands/ZINTER_WITHSCORES.spec.ts b/lib/commands/ZINTER_WITHSCORES.spec.ts index 1dbeda9fd3..f66787e3de 100644 --- a/lib/commands/ZINTER_WITHSCORES.spec.ts +++ b/lib/commands/ZINTER_WITHSCORES.spec.ts @@ -1,8 +1,10 @@ import { strict as assert } from 'assert'; -import { TestRedisServers, itWithClient } from '../test-utils'; +import { TestRedisServers, itWithClient, describeHandleMinimumRedisVersion } from '../test-utils'; import { transformArguments } from './ZINTER_WITHSCORES'; describe('ZINTER WITHSCORES', () => { + describeHandleMinimumRedisVersion([6, 2]); + describe('transformArguments', () => { it('key (string)', () => { assert.deepEqual( diff --git a/lib/commands/ZMSCORE.spec.ts b/lib/commands/ZMSCORE.spec.ts index 0419666f34..3cf3845392 100644 --- a/lib/commands/ZMSCORE.spec.ts +++ b/lib/commands/ZMSCORE.spec.ts @@ -1,8 +1,10 @@ import { strict as assert } from 'assert'; -import { TestRedisServers, itWithClient } from '../test-utils'; +import { TestRedisServers, itWithClient, describeHandleMinimumRedisVersion } from '../test-utils'; import { transformArguments } from './ZMSCORE'; describe('ZMSCORE', () => { + describeHandleMinimumRedisVersion([6, 2]); + describe('transformArguments', () => { it('string', () => { assert.deepEqual( diff --git a/lib/commands/ZRANDMEMBER.spec.ts b/lib/commands/ZRANDMEMBER.spec.ts index 406aa4d113..da31641a18 100644 --- a/lib/commands/ZRANDMEMBER.spec.ts +++ b/lib/commands/ZRANDMEMBER.spec.ts @@ -1,8 +1,10 @@ import { strict as assert } from 'assert'; -import { TestRedisServers, itWithClient } from '../test-utils'; +import { TestRedisServers, itWithClient, describeHandleMinimumRedisVersion } from '../test-utils'; import { transformArguments } from './ZRANDMEMBER'; describe('ZRANDMEMBER', () => { + describeHandleMinimumRedisVersion([6, 2]); + it('transformArguments', () => { assert.deepEqual( transformArguments('key'), diff --git a/lib/commands/ZRANDMEMBER_COUNT.spec.ts b/lib/commands/ZRANDMEMBER_COUNT.spec.ts index 96c68ffd85..759d1b19b7 100644 --- a/lib/commands/ZRANDMEMBER_COUNT.spec.ts +++ b/lib/commands/ZRANDMEMBER_COUNT.spec.ts @@ -1,8 +1,10 @@ import { strict as assert } from 'assert'; -import { TestRedisServers, itWithClient } from '../test-utils'; +import { TestRedisServers, itWithClient, describeHandleMinimumRedisVersion } from '../test-utils'; import { transformArguments } from './ZRANDMEMBER_COUNT'; describe('ZRANDMEMBER COUNT', () => { + describeHandleMinimumRedisVersion([6, 2]); + it('transformArguments', () => { assert.deepEqual( transformArguments('key', 1), diff --git a/lib/commands/ZRANDMEMBER_COUNT_WITHSCORES.spec.ts b/lib/commands/ZRANDMEMBER_COUNT_WITHSCORES.spec.ts index 9c41ab3e37..0135c3a75d 100644 --- a/lib/commands/ZRANDMEMBER_COUNT_WITHSCORES.spec.ts +++ b/lib/commands/ZRANDMEMBER_COUNT_WITHSCORES.spec.ts @@ -1,8 +1,10 @@ import { strict as assert } from 'assert'; -import { TestRedisServers, itWithClient } from '../test-utils'; +import { TestRedisServers, itWithClient, describeHandleMinimumRedisVersion } from '../test-utils'; import { transformArguments } from './ZRANDMEMBER_COUNT_WITHSCORES'; describe('ZRANDMEMBER COUNT WITHSCORES', () => { + describeHandleMinimumRedisVersion([6, 2]); + it('transformArguments', () => { assert.deepEqual( transformArguments('key', 1), diff --git a/lib/commands/ZRANGESTORE.spec.ts b/lib/commands/ZRANGESTORE.spec.ts index c767f174f8..fc40df7535 100644 --- a/lib/commands/ZRANGESTORE.spec.ts +++ b/lib/commands/ZRANGESTORE.spec.ts @@ -1,8 +1,10 @@ import { strict as assert } from 'assert'; -import { TestRedisServers, itWithClient } from '../test-utils'; +import { TestRedisServers, itWithClient, describeHandleMinimumRedisVersion } from '../test-utils'; import { transformArguments } from './ZRANGESTORE'; describe('ZRANGESTORE', () => { + describeHandleMinimumRedisVersion([6, 2]); + describe('transformArguments', () => { it('simple', () => { assert.deepEqual( diff --git a/lib/commands/ZUNION.spec.ts b/lib/commands/ZUNION.spec.ts index 728d81bbd8..12e9283393 100644 --- a/lib/commands/ZUNION.spec.ts +++ b/lib/commands/ZUNION.spec.ts @@ -1,8 +1,10 @@ import { strict as assert } from 'assert'; -import { TestRedisServers, itWithClient } from '../test-utils'; +import { TestRedisServers, itWithClient, describeHandleMinimumRedisVersion } from '../test-utils'; import { transformArguments } from './ZUNION'; describe('ZUNION', () => { + describeHandleMinimumRedisVersion([6, 2]); + describe('transformArguments', () => { it('key (string)', () => { assert.deepEqual( diff --git a/lib/commands/ZUNION_WITHSCORES.spec.ts b/lib/commands/ZUNION_WITHSCORES.spec.ts index b20bd85b49..d9c65ba5e4 100644 --- a/lib/commands/ZUNION_WITHSCORES.spec.ts +++ b/lib/commands/ZUNION_WITHSCORES.spec.ts @@ -1,8 +1,10 @@ import { strict as assert } from 'assert'; -import { TestRedisServers, itWithClient } from '../test-utils'; +import { TestRedisServers, itWithClient, describeHandleMinimumRedisVersion } from '../test-utils'; import { transformArguments } from './ZUNION_WITHSCORES'; describe('ZUNION WITHSCORES', () => { + describeHandleMinimumRedisVersion([6, 2]); + describe('transformArguments', () => { it('key (string)', () => { assert.deepEqual( diff --git a/lib/test-utils.ts b/lib/test-utils.ts index 0ad10ea0a5..6b1491208e 100644 --- a/lib/test-utils.ts +++ b/lib/test-utils.ts @@ -1,8 +1,8 @@ -import assert from 'assert/strict'; +import { strict as assert } from 'assert'; import RedisClient, { RedisClientType } from './client'; import { RedisModules } from './commands'; import { RedisLuaScripts } from './lua-script'; -import { spawn } from 'child_process'; +import { execSync, spawn } from 'child_process'; import { once } from 'events'; import { RedisSocketOptions } from './socket'; import which from 'which'; @@ -10,6 +10,29 @@ import { SinonSpy } from 'sinon'; import { setTimeout } from 'timers/promises'; import RedisCluster, { RedisClusterType } from './cluster'; import { unlink } from 'fs/promises'; +import { Context as MochaContext } from 'mocha'; + +type RedisVersion = [major: number, minor: number, patch: number]; + +type PartialRedisVersion = RedisVersion | [major: number, minor: number] | [major: number] | undefined; + +const REDIS_VERSION = execSync('redis-server -v') + .toString() + .split('.', 3) + .map(Number) as RedisVersion; + +export function isRedisVersionGreaterThan(minimumVersion: PartialRedisVersion): boolean { + if (minimumVersion === undefined) return true; + + const lastIndex = minimumVersion.length - 1; + for (let i = 0; i < lastIndex; i++) { + if (minimumVersion[i] > REDIS_VERSION[i]) { + return true; + } + } + + return minimumVersion[lastIndex] >= REDIS_VERSION[lastIndex]; +} export enum TestRedisServers { OPEN, @@ -24,102 +47,6 @@ export enum TestRedisClusters { export const TEST_REDIS_CLUSTERES: Record> = {}; -before(function () { - this.timeout(10000); - - return Promise.all([ - spawnOpenServer(), - spawnPasswordServer(), - spawnOpenCluster() - ]); -}); - -async function spawnOpenServer(): Promise { - TEST_REDIS_SERVERS[TestRedisServers.OPEN] = { - port: await spawnGlobalRedisServer() - }; -} - -async function spawnPasswordServer(): Promise { - TEST_REDIS_SERVERS[TestRedisServers.PASSWORD] = { - port: await spawnGlobalRedisServer(['--requirepass', 'password']), - username: 'default', - password: 'password' - }; -} - -async function spawnOpenCluster(): Promise { - TEST_REDIS_CLUSTERES[TestRedisClusters.OPEN] = (await spawnGlobalRedisCluster(TestRedisClusters.OPEN, 3)).map(port => ({ - port - })); -} - -export function itWithClient(type: TestRedisServers, title: string, fn: (client: RedisClientType) => Promise): void { - it(title, async () => { - const client = RedisClient.create({ - socket: TEST_REDIS_SERVERS[type] - }); - - await client.connect(); - - try { - await client.flushAll(); - await fn(client); - } finally { - await client.flushAll(); - await client.disconnect(); - } - }); -} - -export function itWithCluster(type: TestRedisClusters, title: string, fn: (cluster: RedisClusterType) => Promise): void { - it(title, async () => { - const cluster = RedisCluster.create({ - rootNodes: TEST_REDIS_CLUSTERES[type] - }); - - await cluster.connect(); - - try { - await clusterFlushAll(cluster); - await fn(cluster); - } finally { - await clusterFlushAll(cluster); - await cluster.disconnect(); - } - }); -} - -export function itWithDedicatedCluster(title: string, fn: (cluster: RedisClusterType) => Promise): void { - it(title, async function () { - this.timeout(10000); - - const spawnResults = await spawnRedisCluster(null, 3), - cluster = RedisCluster.create({ - rootNodes: [{ - port: spawnResults[0].port - }] - }); - - await cluster.connect(); - - try { - await fn(cluster); - } finally { - await cluster.disconnect(); - - for (const { cleanup } of spawnResults) { - await cleanup(); - } - } - }); -} - -async function clusterFlushAll(cluster: RedisCluster): Promise { - await Promise.all( - cluster.getMasters().map(({ client }) => client.flushAll()) - ); -} const REDIS_PATH = which.sync('redis-server'); @@ -173,57 +100,6 @@ async function spawnGlobalRedisServer(args?: Array): Promise { const SLOTS = 16384, CLUSTER_NODE_TIMEOUT = 2000; -export async function spawnRedisCluster(type: TestRedisClusters | null, numberOfNodes: number, args?: Array): Promise> { - const spawnPromises = [], - slotsPerNode = Math.floor(SLOTS / numberOfNodes); - for (let i = 0; i < numberOfNodes; i++) { - const fromSlot = i * slotsPerNode; - spawnPromises.push( - spawnRedisClusterNode( - type, - i, - fromSlot, - i === numberOfNodes - 1 ? SLOTS : fromSlot + slotsPerNode, - args - ) - ); - } - - const spawnResults = await Promise.all(spawnPromises), - meetPromises = []; - for (let i = 1; i < spawnResults.length; i++) { - meetPromises.push( - spawnResults[i].client.clusterMeet( - '127.0.0.1', - spawnResults[i - 1].port - ) - ); - } - - while ((await spawnResults[0].client.clusterInfo()).state !== 'ok') { - await setTimeout(CLUSTER_NODE_TIMEOUT); - } - - const disconnectPromises = []; - for (const result of spawnResults) { - disconnectPromises.push(result.client.disconnect()); - } - - await Promise.all(disconnectPromises); - - return spawnResults; -} - -export async function spawnGlobalRedisCluster(type: TestRedisClusters | null, numberOfNodes: number, args?: Array): Promise> { - const results = await spawnRedisCluster(type, numberOfNodes, args); - - after(() => Promise.all( - results.map(({ cleanup }) => cleanup()) - )); - - return results.map(({ port }) => port); -} - interface SpawnRedisClusterNodeResult extends SpawnRedisServerResult { client: RedisClientType } @@ -281,6 +157,186 @@ async function spawnRedisClusterNode( }; } +export async function spawnRedisCluster(type: TestRedisClusters | null, numberOfNodes: number, args?: Array): Promise> { + const spawnPromises = [], + slotsPerNode = Math.floor(SLOTS / numberOfNodes); + for (let i = 0; i < numberOfNodes; i++) { + const fromSlot = i * slotsPerNode; + spawnPromises.push( + spawnRedisClusterNode( + type, + i, + fromSlot, + i === numberOfNodes - 1 ? SLOTS : fromSlot + slotsPerNode, + args + ) + ); + } + + const spawnResults = await Promise.all(spawnPromises), + meetPromises = []; + for (let i = 1; i < spawnResults.length; i++) { + meetPromises.push( + spawnResults[i].client.clusterMeet( + '127.0.0.1', + spawnResults[i - 1].port + ) + ); + } + + while ((await spawnResults[0].client.clusterInfo()).state !== 'ok') { + await setTimeout(CLUSTER_NODE_TIMEOUT); + } + + const disconnectPromises = []; + for (const result of spawnResults) { + disconnectPromises.push(result.client.disconnect()); + } + + await Promise.all(disconnectPromises); + + return spawnResults; +} + +export async function spawnGlobalRedisCluster(type: TestRedisClusters | null, numberOfNodes: number, args?: Array): Promise> { + const results = await spawnRedisCluster(type, numberOfNodes, args); + + after(() => Promise.all( + results.map(({ cleanup }) => cleanup()) + )); + + return results.map(({ port }) => port); +} + +async function spawnOpenServer(): Promise { + TEST_REDIS_SERVERS[TestRedisServers.OPEN] = { + port: await spawnGlobalRedisServer() + }; +} + +async function spawnPasswordServer(): Promise { + TEST_REDIS_SERVERS[TestRedisServers.PASSWORD] = { + port: await spawnGlobalRedisServer(['--requirepass', 'password']), + password: 'password' + }; +} + +async function spawnOpenCluster(): Promise { + TEST_REDIS_CLUSTERES[TestRedisClusters.OPEN] = (await spawnGlobalRedisCluster(TestRedisClusters.OPEN, 3)).map(port => ({ + port + })); +} + +before(function () { + this.timeout(10000); + + return Promise.all([ + spawnOpenServer(), + spawnPasswordServer(), + spawnOpenCluster() + ]); +}); + +interface RedisTestOptions { + minimumRedisVersion?: PartialRedisVersion; +} + +export function handleMinimumRedisVersion(mochaContext: MochaContext, minimumRedisVersion: PartialRedisVersion): boolean { + if (isRedisVersionGreaterThan(minimumRedisVersion)) { + mochaContext.skip(); + return true; + } + + return false; +} + +export function describeHandleMinimumRedisVersion(minimumRedisVersion: PartialRedisVersion): void { + before(function () { + handleMinimumRedisVersion(this, minimumRedisVersion); + }); +} + +export function itWithClient( + type: TestRedisServers, + title: string, + fn: (client: RedisClientType) => Promise, + options?: RedisTestOptions +): void { + it(title, async function () { + handleMinimumRedisVersion(this, options?.minimumRedisVersion); + + const client = RedisClient.create({ + socket: TEST_REDIS_SERVERS[type] + }); + + await client.connect(); + + try { + await client.flushAll(); + await fn(client); + } finally { + await client.flushAll(); + await client.disconnect(); + } + }); +} + +export function itWithCluster( + type: TestRedisClusters, + title: string, + fn: (cluster: RedisClusterType) => Promise, + options?: RedisTestOptions +): void { + it(title, async function () { + handleMinimumRedisVersion(this, options?.minimumRedisVersion); + + const cluster = RedisCluster.create({ + rootNodes: TEST_REDIS_CLUSTERES[type] + }); + + await cluster.connect(); + + try { + await clusterFlushAll(cluster); + await fn(cluster); + } finally { + await clusterFlushAll(cluster); + await cluster.disconnect(); + } + }); +} + +export function itWithDedicatedCluster(title: string, fn: (cluster: RedisClusterType) => Promise): void { + it(title, async function () { + this.timeout(10000); + + const spawnResults = await spawnRedisCluster(null, 3), + cluster = RedisCluster.create({ + rootNodes: [{ + port: spawnResults[0].port + }] + }); + + await cluster.connect(); + + try { + await fn(cluster); + } finally { + await cluster.disconnect(); + + for (const { cleanup } of spawnResults) { + await cleanup(); + } + } + }); +} + +async function clusterFlushAll(cluster: RedisCluster): Promise { + await Promise.all( + cluster.getMasters().map(({ client }) => client.flushAll()) + ); +} + export async function waitTillBeenCalled(spy: SinonSpy): Promise { const start = process.hrtime.bigint(), calls = spy.callCount; @@ -292,4 +348,4 @@ export async function waitTillBeenCalled(spy: SinonSpy): Promise { await setTimeout(1); } while (spy.callCount === calls) -} +} \ No newline at end of file