Skip to content

Commit 1eba58b

Browse files
committedMar 14, 2022
feat: add tests for cluster
1 parent 06782e6 commit 1eba58b

File tree

6 files changed

+163
-13
lines changed

6 files changed

+163
-13
lines changed
 

‎.github/workflows/main.yml

+8-12
Original file line numberDiff line numberDiff line change
@@ -17,26 +17,22 @@ on:
1717

1818
# A workflow run is made up of one or more jobs that can run sequentially or in parallel
1919
jobs:
20-
# This workflow contains a single job called "build"
21-
build:
22-
# The type of runner that the job will run on
20+
test:
2321
runs-on: ubuntu-latest
24-
25-
# See https://docs.github.com/en/actions/reference/workflow-syntax-for-github-actions#using-environment-variables-in-a-matrix
2622
strategy:
2723
fail-fast: false
2824
matrix:
2925
include:
30-
# Need a new enough git version to install the npm husky module.
3126
- NODE_VERSION: 12-bullseye
3227
- NODE_VERSION: 14-bullseye
3328
- NODE_VERSION: 16-bullseye
34-
35-
# Steps represent a sequence of tasks that will be executed as part of the job
3629
steps:
37-
# Checks-out your repository under $GITHUB_WORKSPACE, so your job can access it
3830
- uses: actions/checkout@v2
39-
40-
# Runs a single command using the runners shell
41-
- name: Build and test in docker
31+
- name: Build and test
4232
run: bash test/docker/main.sh ${{ matrix.NODE_VERSION }}
33+
test-cluster:
34+
runs-on: ubuntu-latest
35+
steps:
36+
- uses: actions/checkout@v2
37+
- name: Build and test cluster
38+
run: bash test-cluster/docker/main.sh

‎lib/cluster/index.ts

+3-1
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@ import {
3636
weightSrvRecords,
3737
} from "./util";
3838
import Deque = require("denque");
39+
import { addTransactionSupport, Transaction } from "../transaction";
3940

4041
const debug = Debug("cluster");
4142

@@ -1042,6 +1043,7 @@ class Cluster extends Commander {
10421043
interface Cluster extends EventEmitter {}
10431044
applyMixin(Cluster, EventEmitter);
10441045

1045-
require("../transaction").addTransactionSupport(Cluster.prototype);
1046+
addTransactionSupport(Cluster.prototype);
1047+
interface Cluster extends Transaction {}
10461048

10471049
export default Cluster;

‎package.json

+1
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
"scripts": {
1111
"test:tsd": "npm run build && tsd",
1212
"test:js": "TS_NODE_TRANSPILE_ONLY=true TS_NODE_LOG_ERROR=true NODE_ENV=test mocha \"test/helpers/*.ts\" \"test/**/*.ts\"",
13+
"test:js:cluster": "TS_NODE_TRANSPILE_ONLY=true TS_NODE_LOG_ERROR=true NODE_ENV=test mocha \"test-cluster/**/*.ts\"",
1314
"test:docs": "(npm run docs && git diff-index --quiet HEAD docs) || (echo 'Run `npm run docs` and commit the updated docs' && exit 1)",
1415
"test": "npm run test:js && npm run test:tsd",
1516
"lint": "eslint --ext .js,.ts ./lib",

‎test-cluster/basic.ts

+128
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,128 @@
1+
import { expect } from "chai";
2+
import Redis, { Cluster } from "../lib";
3+
4+
const masters = [30000, 30001, 30002];
5+
const replicas = [30003, 30004, 30005];
6+
7+
describe("cluster", () => {
8+
afterEach(async () => {
9+
for (const port of masters) {
10+
const redis = new Redis(port);
11+
await redis.flushall();
12+
await redis.script("FLUSH");
13+
}
14+
// Wait for replication
15+
await new Promise((resolve) => setTimeout(resolve, 500));
16+
});
17+
18+
it("discovers nodes from master", async () => {
19+
const cluster = new Cluster([{ host: "127.0.0.1", port: masters[0] }]);
20+
await cluster.set("foo", "bar");
21+
expect(await cluster.get("foo")).to.eql("bar");
22+
});
23+
24+
it("discovers nodes from replica", async () => {
25+
const cluster = new Cluster([{ host: "127.0.0.1", port: replicas[0] }]);
26+
await cluster.set("foo", "bar");
27+
expect(await cluster.get("foo")).to.eql("bar");
28+
});
29+
30+
describe("#nodes()", () => {
31+
it("returns master nodes", async () => {
32+
const cluster = new Cluster([{ host: "127.0.0.1", port: masters[0] }]);
33+
await cluster.info();
34+
const nodes = cluster.nodes("master");
35+
expect(nodes.map((node) => node.options.port).sort()).to.eql(masters);
36+
});
37+
38+
it("returns replica nodes", async () => {
39+
const cluster = new Cluster([{ host: "127.0.0.1", port: masters[0] }]);
40+
await cluster.info();
41+
const nodes = cluster.nodes("slave");
42+
expect(nodes.map((node) => node.options.port).sort()).to.eql(replicas);
43+
});
44+
45+
it("returns all nodes", async () => {
46+
const cluster = new Cluster([{ host: "127.0.0.1", port: masters[0] }]);
47+
await cluster.info();
48+
const nodes = cluster.nodes();
49+
expect(nodes.map((node) => node.options.port).sort()).to.eql(
50+
masters.concat(replicas)
51+
);
52+
});
53+
});
54+
55+
describe("scaleReads", () => {
56+
it("ensures non-readonly commands still working", async () => {
57+
const cluster = new Cluster([{ host: "127.0.0.1", port: masters[0] }], {
58+
scaleReads: "slave",
59+
});
60+
await cluster.set("foo", "bar");
61+
expect(await cluster.get("foo")).to.eql("bar");
62+
});
63+
});
64+
65+
describe("pipeline", () => {
66+
it("ensures script ordering when not loaded", async () => {
67+
const cluster = new Cluster([{ host: "127.0.0.1", port: masters[0] }]);
68+
cluster.defineCommand("myget", {
69+
numberOfKeys: 1,
70+
lua: "return redis.call('GET', KEYS[1])",
71+
});
72+
73+
expect(
74+
await cluster
75+
.pipeline()
76+
// @ts-expect-error
77+
.myget("foo")
78+
.set("foo", "setAfterMyGET")
79+
.myget("foo")
80+
.exec()
81+
).to.eql([
82+
[null, null],
83+
[null, "OK"],
84+
[null, "setAfterMyGET"],
85+
]);
86+
});
87+
88+
it("falls back to eval when the cache is flushed", async () => {
89+
const cluster = new Cluster([{ host: "127.0.0.1", port: masters[0] }]);
90+
cluster.defineCommand("myget", {
91+
numberOfKeys: 1,
92+
lua: "return redis.call('GET', KEYS[1])",
93+
});
94+
95+
// @ts-expect-error
96+
await cluster.myget("foo");
97+
98+
for (const node of cluster.nodes("master")) {
99+
await node.script("FLUSH");
100+
}
101+
102+
expect(
103+
await cluster
104+
.pipeline()
105+
// @ts-expect-error
106+
.myget("foo")
107+
.set("foo", "setAfterMyGET")
108+
.myget("foo")
109+
.exec()
110+
).to.eql([
111+
[null, "setAfterMyGET"],
112+
[null, "OK"],
113+
[null, "setAfterMyGET"],
114+
]);
115+
});
116+
});
117+
118+
describe("auto pipelining", () => {
119+
it("works", async () => {
120+
const cluster = new Cluster([{ host: "127.0.0.1", port: masters[0] }], {
121+
enableAutoPipelining: true,
122+
});
123+
124+
cluster.set("foo", "auto pipelining");
125+
expect(await cluster.get("foo")).to.eql("auto pipelining");
126+
});
127+
});
128+
});

‎test-cluster/docker/Dockerfile

+19
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
FROM grokzen/redis-cluster
2+
3+
RUN apt-get --allow-releaseinfo-change update
4+
5+
RUN apt-get update -y && apt-get install -y redis-server && apt-get install -y curl
6+
RUN touch /etc/apt/apt.conf.d/99verify-peer.conf \
7+
&& echo >>/etc/apt/apt.conf.d/99verify-peer.conf "Acquire { https::Verify-Peer false }"
8+
RUN echo insecure >> $HOME/.curlrc
9+
10+
RUN curl --insecure -fsSL https://deb.nodesource.com/setup_14.x | bash -
11+
RUN apt-get install -y nodejs
12+
RUN apt-get clean
13+
RUN mkdir /code
14+
WORKDIR /code
15+
ADD package.json package-lock.json ./
16+
# Install npm dependencies without converting the lockfile version in npm 7,
17+
# and remove temporary files to save space when developing locally.
18+
RUN npm install --no-save && npm cache clean --force
19+

‎test-cluster/docker/main.sh

+4
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
docker run -e "INITIAL_PORT=30000" -e "IP=0.0.0.0" -p 30000-30005:30000-30005 grokzen/redis-cluster:latest &
2+
npm install
3+
sleep 15
4+
npm run test:js:cluster | npm run test:js:cluster

0 commit comments

Comments
 (0)
Please sign in to comment.