@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.
Files changed (38) hide show
  1. package/README.md +4 -0
  2. package/limitd-redis/LICENSE +21 -0
  3. package/limitd-redis/README.md +183 -0
  4. package/limitd-redis/docker-compose.yml +11 -0
  5. package/limitd-redis/index.js +2 -0
  6. package/limitd-redis/lib/cb.js +45 -0
  7. package/limitd-redis/lib/client.js +135 -0
  8. package/limitd-redis/lib/db.js +501 -0
  9. package/limitd-redis/lib/db_ping.js +106 -0
  10. package/limitd-redis/lib/put.lua +31 -0
  11. package/limitd-redis/lib/take.lua +48 -0
  12. package/limitd-redis/lib/utils.js +116 -0
  13. package/limitd-redis/lib/validation.js +64 -0
  14. package/limitd-redis/node_modules/lru-cache/LICENSE +15 -0
  15. package/limitd-redis/node_modules/lru-cache/README.md +158 -0
  16. package/limitd-redis/node_modules/lru-cache/index.js +468 -0
  17. package/limitd-redis/node_modules/lru-cache/package.json +74 -0
  18. package/limitd-redis/node_modules/ms/index.js +162 -0
  19. package/limitd-redis/node_modules/ms/license.md +21 -0
  20. package/limitd-redis/node_modules/ms/package.json +73 -0
  21. package/limitd-redis/node_modules/ms/readme.md +59 -0
  22. package/limitd-redis/node_modules/yallist/LICENSE +15 -0
  23. package/limitd-redis/node_modules/yallist/README.md +204 -0
  24. package/limitd-redis/node_modules/yallist/iterator.js +7 -0
  25. package/limitd-redis/node_modules/yallist/package.json +65 -0
  26. package/limitd-redis/node_modules/yallist/yallist.js +370 -0
  27. package/limitd-redis/opslevel.yml +6 -0
  28. package/limitd-redis/package-lock.json +3484 -0
  29. package/limitd-redis/package.json +31 -0
  30. package/limitd-redis/test/cb.tests.js +124 -0
  31. package/limitd-redis/test/client.tests.js +194 -0
  32. package/limitd-redis/test/db.tests.js +1318 -0
  33. package/limitd-redis/test/validation.tests.js +124 -0
  34. package/limiter.js +83 -19
  35. package/package.json +3 -2
  36. package/tests/limiter.test.js +27 -27
  37. package/tests/performTestWithTestPerMinute.js +1 -1
  38. package/tests/sanityCheck.js +33 -29
@@ -0,0 +1,31 @@
1
+ {
2
+ "name": "limitd-redis",
3
+ "version": "7.8.1",
4
+ "description": "A database client for limits on top of redis",
5
+ "main": "index.js",
6
+ "repository": {
7
+ "type": "git",
8
+ "url": "http://github.com/auth0/limitd-redis.git"
9
+ },
10
+ "scripts": {
11
+ "test": "trap 'docker-compose down --remove-orphans -v' EXIT; docker-compose up -d && NODE_ENV=test nyc mocha --exit"
12
+ },
13
+ "author": "Auth0",
14
+ "license": "MIT",
15
+ "dependencies": {
16
+ "async": "^2.6.1",
17
+ "disyuntor": "^3.5.0",
18
+ "ioredis": "^4.28.5",
19
+ "lodash": "^4.17.15",
20
+ "lru-cache": "^4.1.5",
21
+ "ms": "^2.1.2",
22
+ "retry": "^0.12.0"
23
+ },
24
+ "devDependencies": {
25
+ "chai": "^4.1.2",
26
+ "eslint": "^6.1.0",
27
+ "mocha": "^5.2.0",
28
+ "nyc": "^14.1.1",
29
+ "toxiproxy-node-client": "^2.0.6"
30
+ }
31
+ }
@@ -0,0 +1,124 @@
1
+ var assert = require('assert'),
2
+ cb = require('../lib/cb');
3
+
4
+ function invokeAsync(callback) {
5
+ setTimeout(function() {
6
+ callback(null, 'foo');
7
+ }, 100);
8
+ }
9
+
10
+ function invokeAsyncError(callback) {
11
+ setTimeout(function() {
12
+ callback(new Error());
13
+ }, 100);
14
+ }
15
+
16
+ function invokeAsyncTwice(callback) {
17
+ setTimeout(function() {
18
+ callback(null, 'foo');
19
+ callback(null, 'foo');
20
+ }, 100);
21
+ }
22
+
23
+ describe('cb(callback)', function() {
24
+
25
+ it('should invoke the provided callback', function(done) {
26
+ invokeAsync(cb(function(err, res) {
27
+ assert.strictEqual(res, 'foo');
28
+ done();
29
+ }));
30
+ });
31
+
32
+ it('shouldn\'t mess with errors', function(done) {
33
+ invokeAsyncError(cb(function(err, res) {
34
+ assert(err);
35
+ done();
36
+ }));
37
+ });
38
+
39
+ it('should allow multiple executions', function(done) {
40
+ var count = 0;
41
+ invokeAsyncTwice(cb(function(err, res) {
42
+ count++;
43
+ if (count === 2) done();
44
+ }));
45
+ });
46
+
47
+ });
48
+
49
+ describe('cb(callback).timeout(ms)', function() {
50
+
51
+ it('should complete successfully within timeout period', function(done) {
52
+ invokeAsync(cb(function(err, res) {
53
+ assert.strictEqual(res, 'foo');
54
+ done();
55
+ }).timeout(200));
56
+ });
57
+
58
+ it('should complete with an error after timeout period', function(done) {
59
+ invokeAsync(cb(function(err, res) {
60
+ assert(err);
61
+ done();
62
+ }).timeout(50));
63
+ });
64
+
65
+ it('error resulting from a timeout should be instanceof cb.TimeoutError', function(done) {
66
+ invokeAsync(cb(function(err, res) {
67
+ assert(err instanceof cb.TimeoutError);
68
+ done();
69
+ }).timeout(50));
70
+ });
71
+ });
72
+
73
+ describe('cb(callback).error(errback)', function() {
74
+
75
+ it('should skip the err argument when invoking callback', function(done) {
76
+ invokeAsync(cb(function(res) {
77
+ assert.strictEqual(res, 'foo');
78
+ done();
79
+ }).error(assert.ifError));
80
+ });
81
+
82
+ it('should pass errors to provided errback', function(done) {
83
+ invokeAsyncError(cb(function(res) {
84
+ throw new Error('should not be invoked');
85
+ }).error(function(err) {
86
+ assert(err);
87
+ done();
88
+ }));
89
+ });
90
+
91
+ });
92
+
93
+ describe('cb(callback).error(errback).timeout(ms)', function() {
94
+
95
+ it('should skip the err argument when invoking callback', function(done) {
96
+ invokeAsync(cb(function(res) {
97
+ assert.strictEqual(res, 'foo');
98
+ done();
99
+ }).error(assert.ifError).timeout(200));
100
+ });
101
+
102
+ it('should pass timeout error to provided errback', function(done) {
103
+ invokeAsyncError(cb(function(res) {
104
+ throw new Error('should not be invoked');
105
+ }).error(function(err) {
106
+ assert(err);
107
+ done();
108
+ }).timeout(50));
109
+ });
110
+
111
+ });
112
+
113
+ describe('cb(callback).once()', function() {
114
+
115
+ it('should allow multiple executions', function(done) {
116
+ var count = 0;
117
+ invokeAsyncTwice(cb(function(err, res) {
118
+ count++;
119
+ assert.notEqual(count, 2);
120
+ setTimeout(done, 100);
121
+ }).once());
122
+ });
123
+
124
+ });
@@ -0,0 +1,194 @@
1
+ /* eslint-env node, mocha */
2
+ const _ = require('lodash');
3
+ const assert = require('chai').assert;
4
+ const LimitRedis = require('../lib/client');
5
+ const ValidationError = LimitRedis.ValidationError;
6
+
7
+ describe('LimitdRedis', () => {
8
+ let client;
9
+ beforeEach((done) => {
10
+ client = new LimitRedis({ uri: 'localhost', buckets: {}, prefix: 'tests:' });
11
+ client.on('error', done);
12
+ client.on('ready', done);
13
+ });
14
+
15
+ describe('#constructor', () => {
16
+ it('should call error if db fails', (done) => {
17
+ let called = false; // avoid uncaught
18
+ client = new LimitRedis({ uri: 'localhost:fail', buckets: {} });
19
+ client.on('error', () => {
20
+ if (!called) {
21
+ called = true;
22
+ return done();
23
+ }
24
+ });
25
+ });
26
+
27
+ it('should set up retry and circuitbreaker defaults', () => {
28
+ assert.equal(client.retryOpts.retries, 3);
29
+ assert.equal(client.retryOpts.minTimeout, 10);
30
+ assert.equal(client.retryOpts.maxTimeout, 30);
31
+ assert.equal(client.breakerOpts.timeout, '0.25s');
32
+ assert.equal(client.breakerOpts.maxFailures, 50);
33
+ assert.equal(client.breakerOpts.cooldown, '1s');
34
+ assert.equal(client.breakerOpts.maxCooldown, '3s');
35
+ assert.equal(client.breakerOpts.name, 'limitr');
36
+ assert.equal(client.commandTimeout, 75);
37
+ });
38
+
39
+ it('should accept circuitbreaker parameters', () => {
40
+ client = new LimitRedis({ uri: 'localhost', buckets: {}, circuitbreaker: { onTrip: () => {} } });
41
+ assert.ok(client.breakerOpts.onTrip);
42
+ });
43
+
44
+ it('should accept retry parameters', () => {
45
+ client = new LimitRedis({ uri: 'localhost', buckets: {}, retry: { retries: 5 } });
46
+ assert.equa;(client.retryOpts.retries, 5);
47
+ });
48
+ });
49
+
50
+ describe('#handler', () => {
51
+ it('should handle count & cb-less calls', (done) => {
52
+ client.db.take = (params, cb) => {
53
+ cb();
54
+ done();
55
+ };
56
+ client.handler('take', 'test', 'test', 1);
57
+ });
58
+ it('should handle count-less & cb-less calls', (done) => {
59
+ client.db.take = (params, cb) => {
60
+ cb();
61
+ done();
62
+ };
63
+ client.handler('take', 'test', 'test');
64
+ });
65
+ it('should handle count-less & cb calls', (done) => {
66
+ client.db.take = (params, cb) => {
67
+ cb();
68
+ };
69
+ client.handler('take', 'test', 'test', done);
70
+ });
71
+ it('should not retry or circuitbreak on ValidationError', (done) => {
72
+ client = new LimitRedis({ uri: 'localhost', buckets: {}, circuitbreaker: { maxFailures: 3, onTrip: () => {} } });
73
+ client.db.take = (params, cb) => {
74
+ return cb(new ValidationError('invalid config'));
75
+ };
76
+ client.handler('take', 'invalid', 'test', _.noop);
77
+ client.handler('take', 'invalid', 'test', _.noop);
78
+ client.handler('take', 'invalid', 'test', _.noop);
79
+ client.handler('take', 'invalid', 'test', _.noop);
80
+ client.handler('take', 'invalid', 'test', _.noop);
81
+ client.handler('take', 'invalid', 'test', _.noop);
82
+ client.handler('take', 'invalid', 'test', (err) => {
83
+ assert.notEqual(err.message, 'limitr: the circuit-breaker is open');
84
+ assert.equal(err.message, 'invalid config');
85
+ done();
86
+ });
87
+ });
88
+ it('should retry on redis errors', (done) => {
89
+ let calls = 0;
90
+ client.db.take = (params, cb) => {
91
+ if (calls === 0) {
92
+ calls++;
93
+ return cb(new Error());
94
+ }
95
+ return cb();
96
+ };
97
+ client.handler('take', 'test', 'test', done);
98
+ });
99
+ it('should retry on timeouts against redis', (done) => {
100
+ let calls = 0;
101
+ client.db.take = (params, cb) => {
102
+ if (calls === 0) {
103
+ calls++;
104
+ return;
105
+ }
106
+ assert.equal(calls, 1);
107
+ return cb();
108
+ };
109
+ client.handler('take', 'test', 'test', done);
110
+ });
111
+ it('should circuitbreak', (done) => {
112
+ client = new LimitRedis({ uri: 'localhost', buckets: {}, circuitbreaker: { maxFailures: 3, onTrip: () => {} } });
113
+ client.db.take = () => {};
114
+ client.handler('take', 'test', 'test', _.noop);
115
+ client.handler('take', 'test', 'test', _.noop);
116
+ client.handler('take', 'test', 'test', _.noop);
117
+ client.handler('take', 'test', 'test', _.noop);
118
+ client.handler('take', 'test', 'test', _.noop);
119
+ client.handler('take', 'test', 'test', () => {
120
+ client.handler('take', 'test', 'test', (err) => {
121
+ assert.equal(err.message, 'limitr: the circuit-breaker is open');
122
+ done();
123
+ });
124
+ });
125
+ });
126
+ });
127
+
128
+ describe('#take', () => {
129
+ it('should call #handle with take as the method', (done) => {
130
+ client.handler = (method, type, key, count, cb) => {
131
+ assert.equal(method, 'take');
132
+ cb();
133
+ };
134
+ client.take('test', 'test', 1, done);
135
+ });
136
+ });
137
+
138
+ describe('#wait', () => {
139
+ it('should call #handle with take as the method', (done) => {
140
+ client.handler = (method, type, key, count, cb) => {
141
+ assert.equal(method, 'wait');
142
+ cb();
143
+ };
144
+ client.wait('test', 'test', 1, done);
145
+ });
146
+ });
147
+
148
+ describe('#put', () => {
149
+ it('should call #handle with take as the method', (done) => {
150
+ client.handler = (method, type, key, count, cb) => {
151
+ assert.equal(method, 'put');
152
+ cb();
153
+ };
154
+ client.put('test', 'test', 1, done);
155
+ });
156
+ });
157
+
158
+ describe('#get', () => {
159
+ it('should call #handle with get as the method', (done) => {
160
+ client.handler = (method, type, key, cb) => {
161
+ assert.equal(method, 'get');
162
+ cb();
163
+ };
164
+ client.get('test', 'test', done);
165
+ });
166
+ });
167
+
168
+ describe('#reset', () => {
169
+ it('should call #put', (done) => {
170
+ client.put = (type, key, count, cb) => {
171
+ cb();
172
+ };
173
+ client.reset('test', 'test', 1, done);
174
+ });
175
+ });
176
+
177
+ describe('#resetAll', () => {
178
+ it('should call db.resetAll', (done) => {
179
+ client.db.resetAll = (cb) => cb();
180
+ client.resetAll(done);
181
+ });
182
+ });
183
+
184
+ describe('#close', () => {
185
+ it('should call db.close', (done) => {
186
+ client.db.close = (cb) => cb();
187
+ client.close((err) => {
188
+ assert.equal(client.db.listenerCount('error'), 0);
189
+ assert.equal(client.db.listenerCount('ready'), 0);
190
+ done(err);
191
+ });
192
+ });
193
+ });
194
+ });