@withjoy/limiter 0.1.2 → 0.1.4-test
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +4 -0
- package/limitd-redis/LICENSE +21 -0
- package/limitd-redis/README.md +183 -0
- package/limitd-redis/docker-compose.yml +11 -0
- package/limitd-redis/index.js +2 -0
- package/limitd-redis/lib/cb.js +45 -0
- package/limitd-redis/lib/client.js +135 -0
- package/limitd-redis/lib/db.js +501 -0
- package/limitd-redis/lib/db_ping.js +106 -0
- package/limitd-redis/lib/put.lua +31 -0
- package/limitd-redis/lib/take.lua +48 -0
- package/limitd-redis/lib/utils.js +116 -0
- package/limitd-redis/lib/validation.js +64 -0
- package/limitd-redis/node_modules/lru-cache/LICENSE +15 -0
- package/limitd-redis/node_modules/lru-cache/README.md +158 -0
- package/limitd-redis/node_modules/lru-cache/index.js +468 -0
- package/limitd-redis/node_modules/lru-cache/package.json +74 -0
- package/limitd-redis/node_modules/ms/index.js +162 -0
- package/limitd-redis/node_modules/ms/license.md +21 -0
- package/limitd-redis/node_modules/ms/package.json +73 -0
- package/limitd-redis/node_modules/ms/readme.md +59 -0
- package/limitd-redis/node_modules/yallist/LICENSE +15 -0
- package/limitd-redis/node_modules/yallist/README.md +204 -0
- package/limitd-redis/node_modules/yallist/iterator.js +7 -0
- package/limitd-redis/node_modules/yallist/package.json +65 -0
- package/limitd-redis/node_modules/yallist/yallist.js +370 -0
- package/limitd-redis/opslevel.yml +6 -0
- package/limitd-redis/package-lock.json +3484 -0
- package/limitd-redis/package.json +31 -0
- package/limitd-redis/test/cb.tests.js +124 -0
- package/limitd-redis/test/client.tests.js +194 -0
- package/limitd-redis/test/db.tests.js +1318 -0
- package/limitd-redis/test/validation.tests.js +124 -0
- package/limiter.js +83 -19
- package/package.json +3 -2
- package/tests/limiter.test.js +27 -27
- package/tests/performTestWithTestPerMinute.js +1 -1
- package/tests/sanityCheck.js +33 -29
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
const assert = require('chai').assert;
|
|
2
|
+
|
|
3
|
+
const { validateParams } = require('../lib/validation');
|
|
4
|
+
|
|
5
|
+
describe('validation', () => {
|
|
6
|
+
describe('validateParameters', () => {
|
|
7
|
+
|
|
8
|
+
const buckets = {
|
|
9
|
+
user: {
|
|
10
|
+
size: 10
|
|
11
|
+
}
|
|
12
|
+
};
|
|
13
|
+
|
|
14
|
+
describe('when providing invalid parameters', () => {
|
|
15
|
+
const invalidParameterSets = [
|
|
16
|
+
{
|
|
17
|
+
result: {
|
|
18
|
+
message: 'params are required',
|
|
19
|
+
code: 101
|
|
20
|
+
}
|
|
21
|
+
}, {
|
|
22
|
+
params: {},
|
|
23
|
+
result: {
|
|
24
|
+
message: 'type is required',
|
|
25
|
+
code: 102
|
|
26
|
+
}
|
|
27
|
+
}, {
|
|
28
|
+
params: {
|
|
29
|
+
type: 'ip'
|
|
30
|
+
},
|
|
31
|
+
result: {
|
|
32
|
+
message: 'undefined bucket type ip',
|
|
33
|
+
code: 103
|
|
34
|
+
}
|
|
35
|
+
}, {
|
|
36
|
+
params: {
|
|
37
|
+
type: 'user'
|
|
38
|
+
},
|
|
39
|
+
result: {
|
|
40
|
+
message: 'key is required',
|
|
41
|
+
code: 104
|
|
42
|
+
}
|
|
43
|
+
}, {
|
|
44
|
+
params: {
|
|
45
|
+
type: 'user',
|
|
46
|
+
key: 'tenant|username',
|
|
47
|
+
configOverride: 5
|
|
48
|
+
},
|
|
49
|
+
result: {
|
|
50
|
+
message: 'configuration overrides must be an object',
|
|
51
|
+
code: 105
|
|
52
|
+
}
|
|
53
|
+
}, {
|
|
54
|
+
params: {
|
|
55
|
+
type: 'user',
|
|
56
|
+
key: 'tenant|username',
|
|
57
|
+
configOverride: {}
|
|
58
|
+
},
|
|
59
|
+
result: {
|
|
60
|
+
message: 'configuration overrides must provide either a size or interval',
|
|
61
|
+
code: 106
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
];
|
|
65
|
+
|
|
66
|
+
invalidParameterSets.forEach(testcase => {
|
|
67
|
+
it(`Should return a validation error, code ${testcase.result.code}`, () => {
|
|
68
|
+
const result = validateParams(testcase.params, buckets);
|
|
69
|
+
assert.strictEqual(result.name, 'LimitdRedisValidationError');
|
|
70
|
+
assert.strictEqual(result.message, testcase.result.message);
|
|
71
|
+
assert.deepEqual(result.extra, { code: testcase.result.code });
|
|
72
|
+
assert.exists(result.stack);
|
|
73
|
+
});
|
|
74
|
+
});
|
|
75
|
+
});
|
|
76
|
+
|
|
77
|
+
describe('when providing valid parameters', () => {
|
|
78
|
+
const validParameterSerts = [
|
|
79
|
+
{
|
|
80
|
+
params: {
|
|
81
|
+
type: 'user',
|
|
82
|
+
key: 'tenant|username',
|
|
83
|
+
},
|
|
84
|
+
name: 'type and key params'
|
|
85
|
+
}, {
|
|
86
|
+
params: {
|
|
87
|
+
type: 'user',
|
|
88
|
+
key: 'tenant|username',
|
|
89
|
+
configOverride: {
|
|
90
|
+
size: 77
|
|
91
|
+
}
|
|
92
|
+
},
|
|
93
|
+
name: 'configOverride with size'
|
|
94
|
+
}, {
|
|
95
|
+
params: {
|
|
96
|
+
type: 'user',
|
|
97
|
+
key: 'tenant|username',
|
|
98
|
+
configOverride: {
|
|
99
|
+
per_hour: 300
|
|
100
|
+
}
|
|
101
|
+
},
|
|
102
|
+
name: 'configOverride with interval'
|
|
103
|
+
}, {
|
|
104
|
+
params: {
|
|
105
|
+
type: 'user',
|
|
106
|
+
key: 'tenant|username',
|
|
107
|
+
configOverride: {
|
|
108
|
+
size: 30,
|
|
109
|
+
per_hour: 300
|
|
110
|
+
}
|
|
111
|
+
},
|
|
112
|
+
name: 'configOverride with size and interval'
|
|
113
|
+
},
|
|
114
|
+
];
|
|
115
|
+
|
|
116
|
+
validParameterSerts.forEach(testcase => {
|
|
117
|
+
it(`Should not cause a validation error for ${testcase.name}`, () => {
|
|
118
|
+
const result = validateParams(testcase.params, buckets);
|
|
119
|
+
assert.isUndefined(result);
|
|
120
|
+
});
|
|
121
|
+
});
|
|
122
|
+
});
|
|
123
|
+
});
|
|
124
|
+
});
|
package/limiter.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
|
|
3
3
|
var LimitdRedis = require("limitd-redis"); // name to redis matter
|
|
4
|
+
var z = require('zod');
|
|
4
5
|
|
|
5
6
|
const defaultBuckets = {
|
|
6
7
|
emailsByEventId: { size: 3000 },
|
|
@@ -37,13 +38,63 @@ class Operation {
|
|
|
37
38
|
// global singleton
|
|
38
39
|
let connection = null;
|
|
39
40
|
|
|
41
|
+
const LIMITER_CIRCUIT_BREAKER_DEFAULTS = {
|
|
42
|
+
timeout: "0.50s",
|
|
43
|
+
maxFailures: 50,
|
|
44
|
+
cooldown: "1s",
|
|
45
|
+
maxCooldown: "3s",
|
|
46
|
+
name: "limitr",
|
|
47
|
+
};
|
|
48
|
+
|
|
49
|
+
const LIMITER_RETRY_DEFAULTS = {
|
|
50
|
+
retries: 3,
|
|
51
|
+
minTimeout: 10,
|
|
52
|
+
maxTimeout: 30,
|
|
53
|
+
};
|
|
54
|
+
|
|
55
|
+
/**
|
|
56
|
+
* Circuit Breaker configuration for limiter. derived from limitd-redis package
|
|
57
|
+
* https://github.com/auth0/limitd-redis/blob/03ba193fe436c5b887ff410d4f2623512ee5c9e2/lib/client.js#L11C1-L12C1
|
|
58
|
+
*/
|
|
59
|
+
const limiterCircuitBreakerConfig = z
|
|
60
|
+
.object({
|
|
61
|
+
timeout: z.coerce
|
|
62
|
+
.string()
|
|
63
|
+
.default(LIMITER_CIRCUIT_BREAKER_DEFAULTS.timeout),
|
|
64
|
+
maxFailures: z.coerce
|
|
65
|
+
.number()
|
|
66
|
+
.default(LIMITER_CIRCUIT_BREAKER_DEFAULTS.maxFailures),
|
|
67
|
+
cooldown: z.coerce
|
|
68
|
+
.string()
|
|
69
|
+
.default(LIMITER_CIRCUIT_BREAKER_DEFAULTS.cooldown),
|
|
70
|
+
maxCooldown: z.coerce
|
|
71
|
+
.string()
|
|
72
|
+
.default(LIMITER_CIRCUIT_BREAKER_DEFAULTS.maxCooldown),
|
|
73
|
+
name: z.coerce.string().default(LIMITER_CIRCUIT_BREAKER_DEFAULTS.name),
|
|
74
|
+
})
|
|
75
|
+
.strict()
|
|
76
|
+
.default(LIMITER_CIRCUIT_BREAKER_DEFAULTS);
|
|
77
|
+
|
|
78
|
+
/**
|
|
79
|
+
* Limiter Retry configuration for limiter. derived from limitd-redis package
|
|
80
|
+
* https://github.com/auth0/limitd-redis/blob/03ba193fe436c5b887ff410d4f2623512ee5c9e2/lib/client.js#L22
|
|
81
|
+
*/
|
|
82
|
+
const limiterRetryConfig = z
|
|
83
|
+
.object({
|
|
84
|
+
retries: z.coerce.number().default(LIMITER_RETRY_DEFAULTS.retries),
|
|
85
|
+
minTimeout: z.coerce.number().default(LIMITER_RETRY_DEFAULTS.minTimeout),
|
|
86
|
+
maxTimeout: z.coerce.number().default(LIMITER_RETRY_DEFAULTS.maxTimeout),
|
|
87
|
+
})
|
|
88
|
+
.strict()
|
|
89
|
+
.default(LIMITER_RETRY_DEFAULTS);
|
|
90
|
+
|
|
40
91
|
class Limiter {
|
|
41
92
|
// static defaultBuckets;
|
|
42
93
|
// static pickDefaultBuckets(keys) { ... };
|
|
43
94
|
|
|
44
95
|
constructor(config) {
|
|
45
96
|
this._config = config;
|
|
46
|
-
this.
|
|
97
|
+
this._limitdRedisConnectionPromise = this.connect();
|
|
47
98
|
}
|
|
48
99
|
|
|
49
100
|
/*
|
|
@@ -52,29 +103,40 @@ class Limiter {
|
|
|
52
103
|
stub it to prevent a real connect from happening under Test Suite Conditions
|
|
53
104
|
*/
|
|
54
105
|
connect() {
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
connection
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
106
|
+
return new Promise((resolve, reject) => {
|
|
107
|
+
let buckets = this._config.buckets || {};
|
|
108
|
+
buckets = {
|
|
109
|
+
...defaultBuckets,
|
|
110
|
+
...buckets,
|
|
111
|
+
};
|
|
112
|
+
const keyPrefix = this._config.keyPrefix || defaultRedisKeyPrefix;
|
|
113
|
+
if (!connection) {
|
|
114
|
+
connection = new LimitdRedis({
|
|
115
|
+
uri: this._config.limitdUrl,
|
|
116
|
+
buckets,
|
|
117
|
+
keyPrefix,
|
|
118
|
+
circuitbreaker: this._config.circuitbreaker,
|
|
119
|
+
commandTimeout: this._config.commandTimeout,
|
|
120
|
+
retry: this._config.retry,
|
|
121
|
+
});
|
|
122
|
+
connection.db.on('ready', () => {
|
|
123
|
+
return resolve(connection);
|
|
124
|
+
});
|
|
125
|
+
} else {
|
|
126
|
+
return resolve(connection);
|
|
127
|
+
}
|
|
128
|
+
});
|
|
69
129
|
}
|
|
70
130
|
|
|
71
|
-
getLimiterProcessor(console) {
|
|
131
|
+
async getLimiterProcessor(console) {
|
|
132
|
+
await this._limitdRedisConnectionPromise;
|
|
72
133
|
return new LimiterProcessor(console);
|
|
73
134
|
}
|
|
74
135
|
|
|
75
136
|
close() {
|
|
76
|
-
return new Promise((resolve, reject) => {
|
|
77
|
-
|
|
137
|
+
return new Promise(async (resolve, reject) => {
|
|
138
|
+
const connectionPromise = await this._limitdRedisConnectionPromise;
|
|
139
|
+
connectionPromise.close((err, resp) => {
|
|
78
140
|
if (err) {
|
|
79
141
|
this._console.error(err);
|
|
80
142
|
return reject(err);
|
|
@@ -87,7 +149,7 @@ class Limiter {
|
|
|
87
149
|
}
|
|
88
150
|
|
|
89
151
|
class LimiterProcessor {
|
|
90
|
-
|
|
152
|
+
|
|
91
153
|
constructor(console) {
|
|
92
154
|
this._console = console;
|
|
93
155
|
this._operationList = [];
|
|
@@ -191,5 +253,7 @@ Limiter.pickDefaultBuckets = function pickDefaultBuckets(keyArray) {
|
|
|
191
253
|
}
|
|
192
254
|
return buckets;
|
|
193
255
|
};
|
|
256
|
+
Limiter.limiterCircuitBreakerConfig = limiterCircuitBreakerConfig;
|
|
257
|
+
Limiter.limiterRetryConfig = limiterRetryConfig;
|
|
194
258
|
|
|
195
259
|
module.exports = Limiter;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@withjoy/limiter",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.4-test",
|
|
4
4
|
"description": "Api Rate limiter",
|
|
5
5
|
"main": "limiter.js",
|
|
6
6
|
"scripts": {
|
|
@@ -10,7 +10,8 @@
|
|
|
10
10
|
"author": "services@withjoy.com",
|
|
11
11
|
"license": "MIT",
|
|
12
12
|
"dependencies": {
|
|
13
|
-
"limitd-redis": "
|
|
13
|
+
"limitd-redis": "file:./limitd-redis",
|
|
14
|
+
"zod": "^3.22.4"
|
|
14
15
|
},
|
|
15
16
|
"devDependencies": {
|
|
16
17
|
"jest": "^24.9.0"
|
package/tests/limiter.test.js
CHANGED
|
@@ -16,13 +16,13 @@ const TEST_BUCKETS = {
|
|
|
16
16
|
The limitd service is essentially a token bank
|
|
17
17
|
that we can withdraw from (take) or deposit to (put)
|
|
18
18
|
*/
|
|
19
|
-
const limiterWithMockService = (succeeds = true, conforms = true) => {
|
|
19
|
+
const limiterWithMockService = async (succeeds = true, conforms = true) => {
|
|
20
20
|
let token_pile = 0;
|
|
21
21
|
const limiter = new Limiter({
|
|
22
22
|
limitdUrl: "localhost:6379",
|
|
23
23
|
buckets: TEST_BUCKETS,
|
|
24
24
|
});
|
|
25
|
-
const limiterProcessor = limiter.getLimiterProcessor(console);
|
|
25
|
+
const limiterProcessor = await limiter.getLimiterProcessor(console);
|
|
26
26
|
limiterProcessor._limitdRedis = new (class MockLimitd {
|
|
27
27
|
constructor(should_succeed, should_conform) {
|
|
28
28
|
this.should_succeed = should_succeed;
|
|
@@ -61,7 +61,7 @@ test("perfrom limitd-redis testing with test bucket", async (done) => {
|
|
|
61
61
|
test: { size: 3, per_second: 2 },
|
|
62
62
|
},
|
|
63
63
|
})
|
|
64
|
-
const limiterProcessor = limiter.getLimiterProcessor(console);
|
|
64
|
+
const limiterProcessor = await limiter.getLimiterProcessor(console);
|
|
65
65
|
// take 2 # Conformant - Remaining: 1
|
|
66
66
|
const result1 = await limiterProcessor.transfer("test", "test-key", 2);
|
|
67
67
|
expect(result1).toMatchObject({
|
|
@@ -93,8 +93,8 @@ test("perfrom limitd-redis testing with test bucket", async (done) => {
|
|
|
93
93
|
done();
|
|
94
94
|
});
|
|
95
95
|
|
|
96
|
-
test("Resolves to null if we aren't doing a real transfer", (done) => {
|
|
97
|
-
let limiterProcessor = limiterWithMockService();
|
|
96
|
+
test("Resolves to null if we aren't doing a real transfer", async (done) => {
|
|
97
|
+
let limiterProcessor = await limiterWithMockService();
|
|
98
98
|
limiterProcessor.transfer("a", "b", 0, null).then((result) => {
|
|
99
99
|
expect(result).toBe(null);
|
|
100
100
|
expect(limiterProcessor._limitdRedis._num_tokens()).toBe(0);
|
|
@@ -102,8 +102,8 @@ test("Resolves to null if we aren't doing a real transfer", (done) => {
|
|
|
102
102
|
});
|
|
103
103
|
});
|
|
104
104
|
|
|
105
|
-
test("Adds tokens if provided a negative token amount", (done) => {
|
|
106
|
-
let limiterProcessor = limiterWithMockService();
|
|
105
|
+
test("Adds tokens if provided a negative token amount", async (done) => {
|
|
106
|
+
let limiterProcessor = await limiterWithMockService();
|
|
107
107
|
limiterProcessor.transfer("a", "b", -5).then((result) => {
|
|
108
108
|
expect(result).toMatchObject({});
|
|
109
109
|
expect(limiterProcessor._limitdRedis._num_tokens()).toBe(5);
|
|
@@ -111,8 +111,8 @@ test("Adds tokens if provided a negative token amount", (done) => {
|
|
|
111
111
|
});
|
|
112
112
|
});
|
|
113
113
|
|
|
114
|
-
test("Removes tokens if provided a positive token amount", (done) => {
|
|
115
|
-
let limiterProcessor = limiterWithMockService();
|
|
114
|
+
test("Removes tokens if provided a positive token amount", async (done) => {
|
|
115
|
+
let limiterProcessor = await limiterWithMockService();
|
|
116
116
|
limiterProcessor.transfer("a", "b", 5).then((result) => {
|
|
117
117
|
expect(result).toMatchObject({ conformant: true });
|
|
118
118
|
expect(limiterProcessor._limitdRedis._num_tokens()).toBe(-5);
|
|
@@ -120,8 +120,8 @@ test("Removes tokens if provided a positive token amount", (done) => {
|
|
|
120
120
|
});
|
|
121
121
|
});
|
|
122
122
|
|
|
123
|
-
test("Reverts all taken tokens when revert is called", (done) => {
|
|
124
|
-
let limiterProcessor = limiterWithMockService();
|
|
123
|
+
test("Reverts all taken tokens when revert is called", async (done) => {
|
|
124
|
+
let limiterProcessor = await limiterWithMockService();
|
|
125
125
|
limiterProcessor
|
|
126
126
|
.transfer("a", "b", 5)
|
|
127
127
|
.then((result) => {
|
|
@@ -135,8 +135,8 @@ test("Reverts all taken tokens when revert is called", (done) => {
|
|
|
135
135
|
});
|
|
136
136
|
});
|
|
137
137
|
|
|
138
|
-
test("Reverts all given tokens when revert is called", (done) => {
|
|
139
|
-
let limiterProcessor = limiterWithMockService();
|
|
138
|
+
test("Reverts all given tokens when revert is called", async (done) => {
|
|
139
|
+
let limiterProcessor = await limiterWithMockService();
|
|
140
140
|
limiterProcessor
|
|
141
141
|
.transfer("a", "b", -5)
|
|
142
142
|
.then((result) => {
|
|
@@ -150,8 +150,8 @@ test("Reverts all given tokens when revert is called", (done) => {
|
|
|
150
150
|
});
|
|
151
151
|
});
|
|
152
152
|
|
|
153
|
-
test("Reverts a series of actions when revert is called", (done) => {
|
|
154
|
-
let limiterProcessor = limiterWithMockService();
|
|
153
|
+
test("Reverts a series of actions when revert is called", async (done) => {
|
|
154
|
+
let limiterProcessor = await limiterWithMockService();
|
|
155
155
|
limiterProcessor
|
|
156
156
|
.transfer("a", "b", -5)
|
|
157
157
|
.then((result) => {
|
|
@@ -170,8 +170,8 @@ test("Reverts a series of actions when revert is called", (done) => {
|
|
|
170
170
|
});
|
|
171
171
|
});
|
|
172
172
|
|
|
173
|
-
test("Properly executes a transferAll()", (done) => {
|
|
174
|
-
let limiterProcessor = limiterWithMockService();
|
|
173
|
+
test("Properly executes a transferAll()", async (done) => {
|
|
174
|
+
let limiterProcessor = await limiterWithMockService();
|
|
175
175
|
limiterProcessor
|
|
176
176
|
.transferAll([
|
|
177
177
|
["a", "b", -5],
|
|
@@ -188,26 +188,26 @@ test("Properly executes a transferAll()", (done) => {
|
|
|
188
188
|
});
|
|
189
189
|
});
|
|
190
190
|
|
|
191
|
-
test("Errors from the underlying service are propagated (put)", () => {
|
|
192
|
-
let limiterProcessor = limiterWithMockService((succeeds = false));
|
|
191
|
+
test("Errors from the underlying service are propagated (put)", async () => {
|
|
192
|
+
let limiterProcessor = await limiterWithMockService((succeeds = false));
|
|
193
193
|
let endsInFailure = limiterProcessor.transfer("a", "b", -5);
|
|
194
194
|
return expect(endsInFailure).rejects.toThrow(PUT_FAILED);
|
|
195
195
|
});
|
|
196
196
|
|
|
197
|
-
test("Errors from the underlying service are propagated (take)", () => {
|
|
198
|
-
let limiterProcessor = limiterWithMockService((succeeds = false));
|
|
197
|
+
test("Errors from the underlying service are propagated (take)", async () => {
|
|
198
|
+
let limiterProcessor = await limiterWithMockService((succeeds = false));
|
|
199
199
|
let endsInFailure = limiterProcessor.transfer("a", "b", 5);
|
|
200
200
|
return expect(endsInFailure).rejects.toThrow(TAKE_FAILED);
|
|
201
201
|
});
|
|
202
202
|
|
|
203
|
-
test("Non-conforming response results in an error", () => {
|
|
204
|
-
let limiterProcessor = limiterWithMockService((succeeds = true), (conforms = false));
|
|
203
|
+
test("Non-conforming response results in an error", async () => {
|
|
204
|
+
let limiterProcessor = await limiterWithMockService((succeeds = true), (conforms = false));
|
|
205
205
|
let endsInFailure = limiterProcessor.transfer("a", "b", 5);
|
|
206
206
|
return expect(endsInFailure).rejects.toThrow("Non Conformant");
|
|
207
207
|
});
|
|
208
208
|
|
|
209
|
-
test("An operation that fails is not logged", (done) => {
|
|
210
|
-
let limiterProcessor = limiterWithMockService();
|
|
209
|
+
test("An operation that fails is not logged", async (done) => {
|
|
210
|
+
let limiterProcessor = await limiterWithMockService();
|
|
211
211
|
limiterProcessor
|
|
212
212
|
.transfer("emailRate", "b", -5)
|
|
213
213
|
.then((result) => {
|
|
@@ -229,8 +229,8 @@ test("An operation that fails is not logged", (done) => {
|
|
|
229
229
|
});
|
|
230
230
|
});
|
|
231
231
|
|
|
232
|
-
test("Properly handles spamming revert() calls", (done) => {
|
|
233
|
-
let limiterProcessor = limiterWithMockService();
|
|
232
|
+
test("Properly handles spamming revert() calls", async (done) => {
|
|
233
|
+
let limiterProcessor = await limiterWithMockService();
|
|
234
234
|
limiterProcessor
|
|
235
235
|
.transfer("a", "b", -5)
|
|
236
236
|
.then((result) => {
|
|
@@ -6,7 +6,7 @@ async function performTestWithTestPerMinute() {
|
|
|
6
6
|
limitdUrl: "localhost:6379",
|
|
7
7
|
console: console,
|
|
8
8
|
});
|
|
9
|
-
const limiterProcessor = limiter.getLimiterProcessor(console);
|
|
9
|
+
const limiterProcessor = await limiter.getLimiterProcessor(console);
|
|
10
10
|
// take 2 # Conformant - Remaining: 1
|
|
11
11
|
const result1 = await limiterProcessor.transfer("testPerMinute", "key", 2);
|
|
12
12
|
console.log("First Turn Take Result", result1);
|
package/tests/sanityCheck.js
CHANGED
|
@@ -2,32 +2,36 @@
|
|
|
2
2
|
|
|
3
3
|
var Limiter = require("../limiter");
|
|
4
4
|
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
}
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
]
|
|
32
|
-
|
|
33
|
-
|
|
5
|
+
async function sanityCheck(){
|
|
6
|
+
const buckets = {
|
|
7
|
+
emails: { size: 10 },
|
|
8
|
+
emailRate: { size: 10, per_hour: 10 },
|
|
9
|
+
};
|
|
10
|
+
|
|
11
|
+
var limiter = new Limiter({
|
|
12
|
+
limitdUrl: "localhost:6379",
|
|
13
|
+
buckets,
|
|
14
|
+
});
|
|
15
|
+
|
|
16
|
+
const limiterProcessor = await limiter.getLimiterProcessor(console);
|
|
17
|
+
|
|
18
|
+
var callback = function (err) {
|
|
19
|
+
if (err) {
|
|
20
|
+
console.log(err);
|
|
21
|
+
process.exit(1);
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
process.exit(0);
|
|
25
|
+
};
|
|
26
|
+
|
|
27
|
+
var withdrawls = [
|
|
28
|
+
["emails", process.argv[2], -parseInt(process.argv[3])],
|
|
29
|
+
["emailRate", process.argv[2], -parseInt(process.argv[3])],
|
|
30
|
+
["emails", process.argv[2], parseInt(process.argv[3])],
|
|
31
|
+
["emailRate", process.argv[2], parseInt(process.argv[3])],
|
|
32
|
+
];
|
|
33
|
+
|
|
34
|
+
limiterProcessor.transferAll(withdrawls).then(() => callback(), callback);
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
sanityCheck();
|