From d1121899e8eb6efa1ad1a417dff8346e96d379a7 Mon Sep 17 00:00:00 2001 From: harrytwright Date: Tue, 9 Feb 2021 15:32:59 +0000 Subject: [PATCH 1/5] src: Fix '.addCommand' to work with custom mocks When using a redis plugin like ReJSON this wouldn't work as the mock was just built around the basic functionality of redis itself, so by adding an 'addMockCommand' and allowing the user to add their own functionality built around the basic redis code will help any tests TODO: - [ ] More testing - [ ] Clean up the code - [ ] Submit PR --- lib/client/redis-client.js | 81 +++++++++++ package.json | 4 +- test/client/redis-mock.addCommand.test.js | 160 ++++++++++++++++++++++ 3 files changed, 244 insertions(+), 1 deletion(-) create mode 100644 test/client/redis-mock.addCommand.test.js diff --git a/lib/client/redis-client.js b/lib/client/redis-client.js index a6952f0..eadef30 100644 --- a/lib/client/redis-client.js +++ b/lib/client/redis-client.js @@ -126,6 +126,9 @@ class RedisClient extends events.EventEmitter { this.subscriptions = {}; this.psubscriptions = {}; + // Custom commands + this.commands = {}; + process.nextTick(() => { this.connected = true; this.ready = true; @@ -181,6 +184,9 @@ class RedisClient extends events.EventEmitter { // TODO: Anything else we need to clear? + // Might be a cleaner way?? + this.commands = {}; + process.nextTick(() => { this.emit("end"); @@ -195,6 +201,81 @@ class RedisClient extends events.EventEmitter { } } +/** + * + * Custom commands + * + * Related to @yeahoffline/redis-mock/issue#163 + * + * Built almost identical to addCommand in the original + * but the command is handled by the function passed here + * + * May also add an addCommand method, so that any methods added here + * are not automatically added to the prototype unless called again + * like the issue mentions + * */ +RedisClient.prototype.addMockCommand = function (command, callback) { + // Could just return here?? + // or do we ignore this and + // just overwrite + if (this.commands[command]) { + throw new Error('command already exists'); + } + + const self = this; + this.commands[command] = function () { + // Probably don't need this but heigh-ho, snow white didn't need + // 7 dwarfs but she was better with them + const args = parseArguments(arguments); + const cb = args.pop(); + return callback(self, args, cb); + }; +}; + +/** + * I can see why this would help, the user can define the commands above in the test + * suite but have the commands 'added' in the main code somewhere + * */ +RedisClient.prototype.addCommand = function (command) { + // Some rare Redis commands use special characters in their command name + // Convert those to a underscore to prevent using invalid function names + const commandName = command.replace(/(?:^([0-9])|[^a-zA-Z0-9_$])/g, '_$1'); + + if (!this[command]) { + // Populate the prototype + this[command.toUpperCase()] = this[command] = this.commands[command]; + + // Alias special function names (e.g. JSON.SET becomes JSON_SET and json_set) + if (commandName !== command) { + this[commandName.toUpperCase()] = this[commandName] = this.commands[command]; + } + } + + if (!multi.Multi.prototype[command]) { + multi.Multi.prototype[command.toUpperCase()] = multi.Multi.prototype[command] = function (...args) { + this._command(command, args); + //Return this for chaining + return this; + }; + + // Alias special function names (e.g. JSON.SET becomes JSON_SET and json_set) + if (commandName !== command) { + multi.Multi.prototype[commandName.toUpperCase()] = multi.Multi.prototype[commandName] = multi.Multi.prototype[command]; + } + } + + // // saves writing extra lines + // // json.get, JSON.GET, json_get, JSON_GET + // [command, command.toUpperCase(), commandName, commandName.toUpperCase()].forEach((cmd) => { + // this[cmd] = this.commands[command]; + // multi.Multi.prototype[cmd] = function (...args) { + // this._command(cmd, args); + // //Return this for chaining + // return this; + // }; + // }); +}; + /** * Publish / subscribe / unsubscribe */ diff --git a/package.json b/package.json index 7a2a36b..1ac81e3 100644 --- a/package.json +++ b/package.json @@ -20,10 +20,12 @@ "test": "mocha --timeout 5000 --recursive", "test:valid": "VALID_TESTS=true npm run test -- --exit", "lint": "eslint ./lib ./test", + "lint:fix": "eslint ./lib ./test --fix", "preversion": "node ./bin/updateMockedCoverage.js" }, "files": [ - "lib" + "lib", + "plugins" ], "keywords": [ "redis", diff --git a/test/client/redis-mock.addCommand.test.js b/test/client/redis-mock.addCommand.test.js new file mode 100644 index 0000000..fd31948 --- /dev/null +++ b/test/client/redis-mock.addCommand.test.js @@ -0,0 +1,160 @@ +// TODO: Clean these up + +const should = require('should'); +const helpers = require('../helpers'); +const redismock = require("../../lib"); + +// Since this is purely for mocking plugins +if (process.env.VALID_TESTS) { + return; +} + +// Clean the db after each test +afterEach(function (done) { + var r = helpers.createClient(); + r.flushdb(function () { + r.end(true); + done(); + }); +}); + +describe('addMockCommand()', function () { + + it('should exist', function () { + var r = redismock.createClient(); + should.exist(r.addMockCommand); + }); + + it('should add method to `.commands` property', function () { + var r = redismock.createClient(); + + r.addMockCommand('json.set', (client, args, callback) => { + // Should never be called, maybe have an empty callback here?? + should.not.exist(client); + }); + + // Should only be added here when '.addCommand' is called + should.not.exist(r.json_set); + should(r.commands).have.key('json.set'); + }); + +}); + +// This is a valid command from NodeRedis +describe('addCommand()', function () { + + it('should exist', function () { + var r = redismock.createClient(); + should.exist(r.addCommand); + }); + + it('should add method to `.commands` property', function () { + var r = redismock.createClient(); + + // This is the flow + r.addMockCommand('json.set', (client, args, callback) => { + // Should never be called, maybe have an empty callback here?? + should.not.exist(client); + }); + + r.addCommand('json.set'); + + // Should only be added here when '.addCommand' is called + should.exist(r.json_set); + should(r.commands).have.key('json.set'); + }); + + describe('example commands', function () { + describe('client', function () { + let r; + + before(function () { + r = redismock.createClient(); + + // Better functionality but will work + r.addMockCommand('json.set', (client, args, callback) => { + client.set(args[0], JSON.stringify(args[2]), callback); + }); + + r.addMockCommand('json.get', (client, args, callback) => { + client.get(args[0], callback); + }); + + r.addCommand('json.set'); + r.addCommand('json.get'); + }); + + after(function (done) { + r.quit(done); + }); + + afterEach(function() { + r.flushall(); + }); + + it('should set value via working command', function (done) { + const value = { + hello: 'world' + }; + + r.json_set('foo', '.', value, function (err, result) { + result.should.eql('OK'); + + r.json_get('foo', function (err, result) { + JSON.parse(result).should.deepEqual(value); + done(); + }); + }); + }); + }); + + describe('multi', function () { + + let r; + + before(function () { + r = redismock.createClient(); + + // Better functionality but will work + r.addMockCommand('json.set', (client, args, callback) => { + client.set(args[0], JSON.stringify(args[2]), callback); + }); + + r.addMockCommand('json.get', (client, args, callback) => { + client.get(args[0], callback); + }); + + r.addCommand('json.set'); + r.addCommand('json.get'); + }); + + after(function (done) { + r.quit(done); + }); + + afterEach(function() { + r.flushall(); + }); + + it('should set the value with a ttl', function (done) { + const value = { + hello: 'world' + }; + + r.multi() + .json_set('key', 'path', JSON.stringify(value)) + .expire('key', 60) + .ttl('key') + .exec((err, results) => { + should(err).not.be.ok(); + should(results[0]).equal('OK'); + should(results[1]).equal(1); + (results[2]<= 60 ).should.be.true(); + + done(); + }); + }); + }); + }); + +}); From 003c9a5754cd97f053a95f5fb20b17485258aec6 Mon Sep 17 00:00:00 2001 From: harrytwright Date: Tue, 9 Feb 2021 17:14:50 +0000 Subject: [PATCH 2/5] src: Changed '.addCommand' to be more inline with NodeRedis When seeing if the concept would work I built the '.addCommand' inside the Client and not globally, which would cause issues with comparability, something I should have remembered since I spent a lot of time last year going through NodeRedis' source. This has now lead me on a rabbit hole dive with some ideas with slightly nicer functionality of adding commands, and how ArgumentParser could be leveraged to assert the args when they come in too, so a user can trust that we will test everything as best we can TODO: - [ ] More testing - [x] Clean up the code - [ ] Submit PR Signed-off-by: harrytwright --- lib/addCommand.js | 96 +++++++++++++ lib/client/redis-client.js | 86 +---------- lib/index.js | 7 +- package.json | 2 +- test/client/addCommand.test.js | 165 ++++++++++++++++++++++ test/client/redis-mock.addCommand.test.js | 160 --------------------- 6 files changed, 272 insertions(+), 244 deletions(-) create mode 100644 lib/addCommand.js create mode 100644 test/client/addCommand.test.js delete mode 100644 test/client/redis-mock.addCommand.test.js diff --git a/lib/addCommand.js b/lib/addCommand.js new file mode 100644 index 0000000..97ea8da --- /dev/null +++ b/lib/addCommand.js @@ -0,0 +1,96 @@ +/** + * + * Custom commands + * + * Related to @yeahoffline/redis-mock/issue#163 + * + * Built almost identical to addCommand in the original + * but the command held back from being added to the prototype + * unless it is called by addCommand + * */ + +const Client = require('./client/redis-client'); +const multi = require("./client/multi"); + +/** + * Hold all the commands here as they will only populate + * the prototype when called by 'addCommand' + * */ +const commands = {}; + +/** + * @typedef MockCommandCallback + * + * @property {RedisClient} client + * @property {Array} args + * @property {Function} callback + * */ + +/** + * + * Add global command to the clients either singular or + * passing a map object with the key as the name, and the + * callback as the value + * + * @param {string|Object} command + * @param {MockCommandCallback} [callback] + * */ +const addMockCommand = function (command, callback) { + if (typeof command === 'object') { + return Object.keys(command).forEach((cmd) => addMockCommand(cmd, command[cmd])); + } + + if (commands[command]) { + throw new Error(`Command [${command}] already registered`); + } + + commands[command] = callback; +}; + +const addCommand = function (command) { + // Some rare Redis commands use special characters in their command name + // Convert those to a underscore to prevent using invalid function names + const commandName = command.replace(/(?:^([0-9])|[^a-zA-Z0-9_$])/g, '_$1'); + + const callback = commands[command]; + + if (!callback) { + process.emitWarning(`Command [${command}] has not been registered with mock, returning`); + return; + } + + if (!Client.prototype[command]) { + Client.prototype[command.toUpperCase()] = Client.prototype[command] = function () { + // Should make a customer parser to handle this and not have to mess + // with preexisting exports?? + const args = Client.$_parser(arguments); + let cb; + if (typeof args[args.length - 1] === 'function') { + cb = args.pop(); + } + + return callback(this, args, cb); + }; + + // Alias special function names (e.g. JSON.SET becomes JSON_SET and json_set) + if (commandName !== command) { + Client.prototype[commandName.toUpperCase()] = Client.prototype[commandName] = Client.prototype[command]; + } + } + + if (!multi.Multi.prototype[command]) { + multi.Multi.prototype[command.toUpperCase()] = multi.Multi.prototype[command] = function (...args) { + this._command(command, args); + //Return this for chaining + return this; + }; + + // Alias special function names (e.g. JSON.SET becomes JSON_SET and json_set) + if (commandName !== command) { + multi.Multi.prototype[commandName.toUpperCase()] = multi.Multi.prototype[commandName] = multi.Multi.prototype[command]; + } + } +}; + +module.exports.addCommand = addCommand; +module.exports.addMockCommand = addMockCommand; diff --git a/lib/client/redis-client.js b/lib/client/redis-client.js index eadef30..2bc9298 100644 --- a/lib/client/redis-client.js +++ b/lib/client/redis-client.js @@ -126,9 +126,6 @@ class RedisClient extends events.EventEmitter { this.subscriptions = {}; this.psubscriptions = {}; - // Custom commands - this.commands = {}; - process.nextTick(() => { this.connected = true; this.ready = true; @@ -184,9 +181,6 @@ class RedisClient extends events.EventEmitter { // TODO: Anything else we need to clear? - // Might be a cleaner way?? - this.commands = {}; - process.nextTick(() => { this.emit("end"); @@ -201,81 +195,6 @@ class RedisClient extends events.EventEmitter { } } -/** - * - * Custom commands - * - * Related to @yeahoffline/redis-mock/issue#163 - * - * Built almost identical to addCommand in the original - * but the command is handled by the function passed here - * - * May also add an addCommand method, so that any methods added here - * are not automatically added to the prototype unless called again - * like the issue mentions - * */ -RedisClient.prototype.addMockCommand = function (command, callback) { - // Could just return here?? - // or do we ignore this and - // just overwrite - if (this.commands[command]) { - throw new Error('command already exists'); - } - - const self = this; - this.commands[command] = function () { - // Probably don't need this but heigh-ho, snow white didn't need - // 7 dwarfs but she was better with them - const args = parseArguments(arguments); - const cb = args.pop(); - return callback(self, args, cb); - }; -}; - -/** - * I can see why this would help, the user can define the commands above in the test - * suite but have the commands 'added' in the main code somewhere - * */ -RedisClient.prototype.addCommand = function (command) { - // Some rare Redis commands use special characters in their command name - // Convert those to a underscore to prevent using invalid function names - const commandName = command.replace(/(?:^([0-9])|[^a-zA-Z0-9_$])/g, '_$1'); - - if (!this[command]) { - // Populate the prototype - this[command.toUpperCase()] = this[command] = this.commands[command]; - - // Alias special function names (e.g. JSON.SET becomes JSON_SET and json_set) - if (commandName !== command) { - this[commandName.toUpperCase()] = this[commandName] = this.commands[command]; - } - } - - if (!multi.Multi.prototype[command]) { - multi.Multi.prototype[command.toUpperCase()] = multi.Multi.prototype[command] = function (...args) { - this._command(command, args); - //Return this for chaining - return this; - }; - - // Alias special function names (e.g. JSON.SET becomes JSON_SET and json_set) - if (commandName !== command) { - multi.Multi.prototype[commandName.toUpperCase()] = multi.Multi.prototype[commandName] = multi.Multi.prototype[command]; - } - } - - // // saves writing extra lines - // // json.get, JSON.GET, json_get, JSON_GET - // [command, command.toUpperCase(), commandName, commandName.toUpperCase()].forEach((cmd) => { - // this[cmd] = this.commands[command]; - // multi.Multi.prototype[cmd] = function (...args) { - // this._command(cmd, args); - // //Return this for chaining - // return this; - // }; - // }); -}; - /** * Publish / subscribe / unsubscribe */ @@ -805,3 +724,8 @@ types.getMethods(RedisClient).public() }); module.exports = RedisClient; + +/** + * @private + * */ +module.exports.$_parser = parseArguments; diff --git a/lib/index.js b/lib/index.js index 9f79fee..45692c0 100644 --- a/lib/index.js +++ b/lib/index.js @@ -1,9 +1,10 @@ 'use strict'; -const {Multi} = require("./client/multi"); +const { Multi } = require("./client/multi"); const RedisClient = require('./client/redis-client'); const errors = require('./errors'); const createClient = require('./client/createClient'); +const { addCommand, addMockCommand } = require('./addCommand'); module.exports = { AbortError: errors.AbortError, @@ -14,5 +15,7 @@ module.exports = { RedisClient, Multi, - createClient + createClient, + addCommand, + addMockCommand }; diff --git a/package.json b/package.json index 1ac81e3..9ed4721 100644 --- a/package.json +++ b/package.json @@ -17,7 +17,7 @@ "should": "13.2.3" }, "scripts": { - "test": "mocha --timeout 5000 --recursive", + "test": "mocha --timeout 5000 --recursive -g 'add*Command'", "test:valid": "VALID_TESTS=true npm run test -- --exit", "lint": "eslint ./lib ./test", "lint:fix": "eslint ./lib ./test --fix", diff --git a/test/client/addCommand.test.js b/test/client/addCommand.test.js new file mode 100644 index 0000000..c1975bf --- /dev/null +++ b/test/client/addCommand.test.js @@ -0,0 +1,165 @@ +// TODO: Clean these up + +const should = require('should'); +const helpers = require('../helpers'); +const redismock = require("../../lib"); + +// Since this is purely for mocking plugins +if (process.env.VALID_TESTS) { + return; +} + +/* eslint-disable-next-line */ +const noop = () => {}; + +// Clean the db after each test +afterEach(function (done) { + var r = helpers.createClient(); + r.flushdb(function () { + r.end(true); + done(); + }); +}); + +describe('addMockCommand()', function () { + + var Redis = redismock.RedisClient; + + it('should exist', function () { + should.exist(redismock.addMockCommand); + }); + + it('should not populate the prototype', function () { + redismock.addMockCommand('gh163.addMockCommand', noop); + should.not.exist(Redis.prototype.gh163_addMockCommand); + }); + +}); + +describe('addCommand()', function () { + + describe('adding command', function () { + + var Redis = redismock.RedisClient; + var Multi = redismock.Multi; + + it('should exist', function () { + should.exist(redismock.addCommand); + }); + + it('should populate the prototype', function () { + redismock.addMockCommand('gh163.addCommand', noop); + redismock.addCommand('gh163.addCommand'); + + should.exist(Redis.prototype.gh163_addCommand); + }); + + it('should convert special characters in functions names to lowercase', function () { + const command = 'gh163.addCommand.convert'; + + redismock.addMockCommand(command, noop); + redismock.addCommand(command); + + should.exist(Redis.prototype[command]); + should.exist(Redis.prototype[command.toUpperCase()]); + should.exist(Redis.prototype.gh163_addCommand_convert); + should.exist(Redis.prototype.GH163_ADDCOMMAND_CONVERT); + }); + + it('should add to multi', function () { + const command = 'gh163.addCommand.multi'; + + redismock.addMockCommand(command, noop); + redismock.addCommand(command); + + should.exist(Multi.prototype[command]); + }); + }); + + describe('using new command', function () { + + before(function () { + // Better functionality but will work + // + // The way the mock works just need a little workaround for multi + redismock.addMockCommand('json.set', (client, args, callback) => { + if (client instanceof redismock.Multi) { + client = client._client; + } + + client.set(args[0], JSON.stringify(args[2]), callback); + }); + + redismock.addMockCommand('json.get', (client, args, callback) => { + client.get(args[0], callback); + }); + + redismock.addCommand('json.set'); + redismock.addCommand('json.get'); + }); + + describe('client', function () { + + let r; + + beforeEach(function () { + r = redismock.createClient(); + }); + + afterEach(function(done) { + r.flushall(); + r.quit(done); + }); + + it('should set value via working command', function (done) { + const value = { + hello: 'world' + }; + + r.json_set('foo', '.', value, function (err, result) { + result.should.eql('OK'); + + r.json_get('foo', function (err, result) { + JSON.parse(result).should.deepEqual(value); + done(); + }); + }); + }); + }); + + describe('multi', function () { + + let r; + + beforeEach(function () { + r = redismock.createClient(); + }); + + afterEach(function(done) { + r.flushall(); + r.quit(done); + }); + + it('should set the value with a ttl', function (done) { + const value = { + hello: 'world' + }; + + const multi = r.multi(); + + multi.json_set('key', 'path', JSON.stringify(value)) + .expire('key', 60) + .ttl('key') + .exec((err, results) => { + should(err).not.be.ok(); + should(results[0]).equal('OK'); + should(results[1]).equal(1); + (results[2] <= 60).should.be.true(); + + done(); + }); + }); + }); + }); + +}); diff --git a/test/client/redis-mock.addCommand.test.js b/test/client/redis-mock.addCommand.test.js deleted file mode 100644 index fd31948..0000000 --- a/test/client/redis-mock.addCommand.test.js +++ /dev/null @@ -1,160 +0,0 @@ -// TODO: Clean these up - -const should = require('should'); -const helpers = require('../helpers'); -const redismock = require("../../lib"); - -// Since this is purely for mocking plugins -if (process.env.VALID_TESTS) { - return; -} - -// Clean the db after each test -afterEach(function (done) { - var r = helpers.createClient(); - r.flushdb(function () { - r.end(true); - done(); - }); -}); - -describe('addMockCommand()', function () { - - it('should exist', function () { - var r = redismock.createClient(); - should.exist(r.addMockCommand); - }); - - it('should add method to `.commands` property', function () { - var r = redismock.createClient(); - - r.addMockCommand('json.set', (client, args, callback) => { - // Should never be called, maybe have an empty callback here?? - should.not.exist(client); - }); - - // Should only be added here when '.addCommand' is called - should.not.exist(r.json_set); - should(r.commands).have.key('json.set'); - }); - -}); - -// This is a valid command from NodeRedis -describe('addCommand()', function () { - - it('should exist', function () { - var r = redismock.createClient(); - should.exist(r.addCommand); - }); - - it('should add method to `.commands` property', function () { - var r = redismock.createClient(); - - // This is the flow - r.addMockCommand('json.set', (client, args, callback) => { - // Should never be called, maybe have an empty callback here?? - should.not.exist(client); - }); - - r.addCommand('json.set'); - - // Should only be added here when '.addCommand' is called - should.exist(r.json_set); - should(r.commands).have.key('json.set'); - }); - - describe('example commands', function () { - describe('client', function () { - let r; - - before(function () { - r = redismock.createClient(); - - // Better functionality but will work - r.addMockCommand('json.set', (client, args, callback) => { - client.set(args[0], JSON.stringify(args[2]), callback); - }); - - r.addMockCommand('json.get', (client, args, callback) => { - client.get(args[0], callback); - }); - - r.addCommand('json.set'); - r.addCommand('json.get'); - }); - - after(function (done) { - r.quit(done); - }); - - afterEach(function() { - r.flushall(); - }); - - it('should set value via working command', function (done) { - const value = { - hello: 'world' - }; - - r.json_set('foo', '.', value, function (err, result) { - result.should.eql('OK'); - - r.json_get('foo', function (err, result) { - JSON.parse(result).should.deepEqual(value); - done(); - }); - }); - }); - }); - - describe('multi', function () { - - let r; - - before(function () { - r = redismock.createClient(); - - // Better functionality but will work - r.addMockCommand('json.set', (client, args, callback) => { - client.set(args[0], JSON.stringify(args[2]), callback); - }); - - r.addMockCommand('json.get', (client, args, callback) => { - client.get(args[0], callback); - }); - - r.addCommand('json.set'); - r.addCommand('json.get'); - }); - - after(function (done) { - r.quit(done); - }); - - afterEach(function() { - r.flushall(); - }); - - it('should set the value with a ttl', function (done) { - const value = { - hello: 'world' - }; - - r.multi() - .json_set('key', 'path', JSON.stringify(value)) - .expire('key', 60) - .ttl('key') - .exec((err, results) => { - should(err).not.be.ok(); - should(results[0]).equal('OK'); - should(results[1]).equal(1); - (results[2]<= 60 ).should.be.true(); - - done(); - }); - }); - }); - }); - -}); From 6e15f1d1cbe048fb93df5cc58bffe9bdfb0b16c5 Mon Sep 17 00:00:00 2001 From: harrytwright Date: Tue, 9 Feb 2021 17:22:17 +0000 Subject: [PATCH 3/5] test: Test all commands I'm a dick, the end Signed-off-by: harrytwright --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 9ed4721..1ac81e3 100644 --- a/package.json +++ b/package.json @@ -17,7 +17,7 @@ "should": "13.2.3" }, "scripts": { - "test": "mocha --timeout 5000 --recursive -g 'add*Command'", + "test": "mocha --timeout 5000 --recursive", "test:valid": "VALID_TESTS=true npm run test -- --exit", "lint": "eslint ./lib ./test", "lint:fix": "eslint ./lib ./test --fix", From 757ee71fdefa3e3f806eed1eb4c4923c15ea557a Mon Sep 17 00:00:00 2001 From: harrytwright Date: Tue, 9 Feb 2021 20:16:38 +0000 Subject: [PATCH 4/5] docs: Update README.md Signed-off-by: harrytwright --- README.md | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/README.md b/README.md index 43fc135..332fefc 100644 --- a/README.md +++ b/README.md @@ -171,6 +171,27 @@ $ npm test:valid You will need to have a running instance of `redis` on you machine and our tests use flushdb a lot so make sure you don't have anything important on it. +# Custom Commands + +Some commands might not come standard with redis-mock, i.e ReJSON and it's commands, but since they are valid commands +and would be helpful to test, you can create your own commands and run them + +> WIP: Would like to an extra package that holds the official plugin commands so you can +> add them to your project + +```javascript +var redis = require("redis-mock") + +redis.addMockCommand('json.set', (client, args, callback) => { + // your logic here... probably something like: client.set(args[0], JSON.stringify(args[1]), callback); +}) + +// In your app +redis.addCommand('json.set') + +var client redis.createClient() +client.json_set('key', { json: 'value' }, redis.print) // 0 'OK' +``` # Roadmap redis-mock is work in progress, feel free to report an issue From f46eb8388ad8afd723dfe9f13d08d5dd66974ace Mon Sep 17 00:00:00 2001 From: harrytwright Date: Fri, 1 Oct 2021 18:10:11 +0100 Subject: [PATCH 5/5] docs: Update README.md Bring the code back inline with the original Signed-off-by: harrytwright --- README.md | 22 ---------------------- package.json | 4 +--- 2 files changed, 1 insertion(+), 25 deletions(-) diff --git a/README.md b/README.md index 332fefc..fb3f684 100644 --- a/README.md +++ b/README.md @@ -171,28 +171,6 @@ $ npm test:valid You will need to have a running instance of `redis` on you machine and our tests use flushdb a lot so make sure you don't have anything important on it. -# Custom Commands - -Some commands might not come standard with redis-mock, i.e ReJSON and it's commands, but since they are valid commands -and would be helpful to test, you can create your own commands and run them - -> WIP: Would like to an extra package that holds the official plugin commands so you can -> add them to your project - -```javascript -var redis = require("redis-mock") - -redis.addMockCommand('json.set', (client, args, callback) => { - // your logic here... probably something like: client.set(args[0], JSON.stringify(args[1]), callback); -}) - -// In your app -redis.addCommand('json.set') - -var client redis.createClient() -client.json_set('key', { json: 'value' }, redis.print) // 0 'OK' -``` - # Roadmap redis-mock is work in progress, feel free to report an issue diff --git a/package.json b/package.json index 1ac81e3..7a2a36b 100644 --- a/package.json +++ b/package.json @@ -20,12 +20,10 @@ "test": "mocha --timeout 5000 --recursive", "test:valid": "VALID_TESTS=true npm run test -- --exit", "lint": "eslint ./lib ./test", - "lint:fix": "eslint ./lib ./test --fix", "preversion": "node ./bin/updateMockedCoverage.js" }, "files": [ - "lib", - "plugins" + "lib" ], "keywords": [ "redis",