diff --git a/.codeclimate.yml b/.codeclimate.yml index 30106f6..d657c7a 100644 --- a/.codeclimate.yml +++ b/.codeclimate.yml @@ -1,9 +1,9 @@ engines: eslint: enabled: true - channel: "eslint-8" + channel: 'eslint-8' config: - config: ".eslintrc.yaml" + config: '.eslintrc.yaml' checks: method-complexity: @@ -11,5 +11,5 @@ checks: threshold: 10 ratings: - paths: - - "**.js" + paths: + - '**.js' diff --git a/.eslintrc.yaml b/.eslintrc.yaml index b10c53f..035a400 100644 --- a/.eslintrc.yaml +++ b/.eslintrc.yaml @@ -2,19 +2,6 @@ env: node: true es6: true mocha: true - es2020: true + es2022: true -plugins: [ haraka ] - -extends: [ eslint:recommended, plugin:haraka/recommended ] - -root: true - -globals: - OK: true - CONT: true - DENY: true - DENYSOFT: true - DENYDISCONNECT: true - DENYSOFTDISCONNECT: true - connection: true +extends: ['@haraka'] diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md index afafec5..bd8fb43 100644 --- a/.github/PULL_REQUEST_TEMPLATE.md +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -1,10 +1,12 @@ Fixes # Changes proposed in this pull request: -- -- + +- +- Checklist: + - [ ] docs updated - [ ] tests updated - [ ] Changes.md updated diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 94be697..a067f44 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -1,41 +1,22 @@ name: CI -on: [ push, pull_request ] +on: [push, pull_request] env: CI: true - node-version: 16 jobs: - lint: - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v3 - - uses: actions/setup-node@v3 - name: Node ${{ env.node-version }} - with: - node-version: ${{ env.node-version }} - - run: npm install - - run: npm run lint + uses: haraka/.github/.github/workflows/lint.yml@master + + # coverage: + # uses: haraka/.github/.github/workflows/coverage.yml@master + # secrets: inherit test: - runs-on: ${{ matrix.os }} - services: - redis: - image: redis - ports: - - 6379:6379 - strategy: - matrix: - os: [ ubuntu-latest ] - node-version: [ 14, 16, 18 ] - fail-fast: false - steps: - - uses: actions/checkout@v3 - - uses: actions/setup-node@v3 - name: Node ${{ matrix.node-version }} on ${{ matrix.os }} - with: - node-version: ${{ matrix.node-version }} - - run: npm install - - run: npm run test + needs: [lint] + uses: haraka/.github/.github/workflows/ubuntu.yml@master + + # windows: + # needs: [lint] + # uses: haraka/.github/.github/workflows/windows.yml@master diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml index 3627451..8314a66 100644 --- a/.github/workflows/codeql.yml +++ b/.github/workflows/codeql.yml @@ -2,10 +2,10 @@ name: CodeQL on: push: - branches: [ master ] + branches: [master] pull_request: # The branches below must be a subset of the branches above - branches: [ master ] + branches: [master] schedule: - cron: '18 7 * * 4' diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml index d489fbd..e81c15f 100644 --- a/.github/workflows/publish.yml +++ b/.github/workflows/publish.yml @@ -13,4 +13,4 @@ env: jobs: publish: uses: haraka/.github/.github/workflows/publish.yml@master - secrets: inherit \ No newline at end of file + secrets: inherit diff --git a/.npmignore b/.npmignore deleted file mode 100644 index 3e8e260..0000000 --- a/.npmignore +++ /dev/null @@ -1,58 +0,0 @@ -# Logs -logs -*.log -npm-debug.log* - -# Runtime data -pids -*.pid -*.seed - -# Directory for instrumented libs generated by jscoverage/JSCover -lib-cov - -# Coverage directory used by tools like istanbul -coverage - -# nyc test coverage -.nyc_output - -# Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files) -.grunt - -# node-waf configuration -.lock-wscript - -# Compiled binary addons (http://nodejs.org/api/addons.html) -build/Release - -# Dependency directories -node_modules -jspm_packages - -# Optional npm cache directory -.npm - -# Optional REPL history -.node_repl_history - -package-lock.json -bower_components -# Optional npm cache directory -.npmrc -.idea -.DS_Store -haraka-update.sh - -.github -.release -.codeclimate.yml -.editorconfig -.gitignore -.gitmodules -.lgtm.yml -appveyor.yml -codecov.yml -.travis.yml -.eslintrc.yaml -.eslintrc.json diff --git a/.prettierrc.yml b/.prettierrc.yml new file mode 100644 index 0000000..8ded5e0 --- /dev/null +++ b/.prettierrc.yml @@ -0,0 +1,2 @@ +singleQuote: true +semi: false diff --git a/.release b/.release index 0890e94..36bb27a 160000 --- a/.release +++ b/.release @@ -1 +1 @@ -Subproject commit 0890e945e4e061c96c7b2ab45017525904c17728 +Subproject commit 36bb27a93862517943e04f24fd67b0df2da6cbbe diff --git a/Changes.md b/CHANGELOG.md similarity index 64% rename from Changes.md rename to CHANGELOG.md index c8eb9c3..4ed4ab6 100644 --- a/Changes.md +++ b/CHANGELOG.md @@ -1,17 +1,27 @@ +# Changelog + +The format is based on [Keep a Changelog](https://keepachangelog.com/). ### Unreleased +### [2.0.7] - 2024-04-21 + +- populate [files] in package.json. Delete .npmignore. +- lint: remove duplicate / stale rules from .eslintrc +- ci: update to shared GHA workflows +- doc(CONTRIBUTORS): added +- doc: Changes -> CHANGELOG +- prettier ### [2.0.6] - 2023-12-12 - doc(README): '[socket]' is now '[server]' (#39) - chore(ci): add .release, updated dot files - ### 2.0.5 - 2022-05-26 - fix: backwards compatibility with legacy plugin config files -- fix: rename p\* methods -> * (required in redis v4) +- fix: rename p\* methods -> \* (required in redis v4) - fix: add `await client.connect()` as is now required, fixes #32 - fix: make redis_ping async - dep(redis): bump 4.0 -> 4.1 @@ -19,33 +29,28 @@ - chore(ci): added codeql config - test: added tests for init_redis_plugin - ### 2.0.0 - 2022-03-29 - dep(redis): bump major version 3 -> 4 - breaking API change: replaced callbacks with promises - config.ini - - opts.db -> opts.database (to match upstream) - + - opts.db -> opts.database (to match upstream) ### 1.0.13 - 2021-10-14 - chore(ci): switch CI from Travis to GitHub Actions - doc(README): update formatting with GFM - ### 1.0.12 - 2020-03-16 - chore(ci): replace nodeunit with mocha - dep(redis): update lib to v3 - appveyor: test on node 10 - ### 1.0.11 - 2019-04-11 - create custom connection only after: all 3 conditions match - ### 1.0.10 - 2019-04-09 - merge ALL of [opts] into [server] config (fixes #18) @@ -53,7 +58,6 @@ - include an empty config/redis.ini - add defaultOpts once, vs defaults in two places - ### 1.0.9 - 2019-02-19 - bump redis version to 2.8.0 @@ -61,34 +65,36 @@ - add 3s timeout for subscribe connects: minimize connections stalls - add es6 template literals - ### 1.0.8 - 2018-01-03 - upon punsubscribe, `quit()` (disconnect) redis client - ### 1.0.7 - 2017-07-31 - apply config [opts] to pubsub settings #7 - ### 1.0.6 - 2017-06-16 - eslint 4 compat - ### 1.0.5 - 2017-06-09 - disconnect per-connection redis client upon punsubscribe - ### 1.0.4 - 2017-02-06 - remove retry_strategy, redis client now does The Right Thing w/o it - ### 1.0.3 - 2017-02-06 - don't break when no [redis] config exists -[2.0.6]: https://github.com/haraka/haraka-plugin-redis/releases/tag/2.0.6 +[1.0.13]: https://github.com/haraka/haraka-plugin-redis/releases/tag/1.0.13 +[2.0.0]: https://github.com/haraka/haraka-plugin-redis/releases/tag/2.0.0 +[2.0.1]: https://github.com/haraka/haraka-plugin-redis/releases/tag/2.0.1 +[2.0.2]: https://github.com/haraka/haraka-plugin-redis/releases/tag/2.0.2 +[2.0.3]: https://github.com/haraka/haraka-plugin-redis/releases/tag/2.0.3 +[2.0.4]: https://github.com/haraka/haraka-plugin-redis/releases/tag/2.0.4 +[2.0.5]: https://github.com/haraka/haraka-plugin-redis/releases/tag/2.0.5 +[2.0.6]: https://github.com/haraka/haraka-plugin-redis/releases/tag/v2.0.6 +[2.0.7]: https://github.com/haraka/haraka-plugin-redis/releases/tag/2.0.7 diff --git a/CONTRIBUTORS.md b/CONTRIBUTORS.md new file mode 100644 index 0000000..6e24629 --- /dev/null +++ b/CONTRIBUTORS.md @@ -0,0 +1,8 @@ +# Contributors + +This handcrafted artisinal software is brought to you by: + +|
msimerson (57) |
zazapeta (1) | +| :--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------: | :-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------: | + +this file is maintained by [.release](https://github.com/msimerson/.release) diff --git a/README.md b/README.md index 59b82ac..bfec36f 100644 --- a/README.md +++ b/README.md @@ -72,32 +72,31 @@ optionally with a redis db ID. All redis config options must be listed in your p ```js exports.register = function () { - this.inherits('redis'); + this.inherits('redis') - this.cfg = this.config.get('my-plugin.ini'); + this.cfg = this.config.get('my-plugin.ini') - // populate plugin.cfg.redis with defaults from redis.ini - this.merge_redis_ini(); + // populate plugin.cfg.redis with defaults from redis.ini + this.merge_redis_ini() - // cluster aware redis connection(s) - this.register_hook('init_master', 'init_redis_plugin'); - this.register_hook('init_child', 'init_redis_plugin'); + // cluster aware redis connection(s) + this.register_hook('init_master', 'init_redis_plugin') + this.register_hook('init_child', 'init_redis_plugin') } ``` When a db ID is specified in the [redis] section of a redis inheriting plugin, log messages like these will be emitted when Haraka starts: -```` +``` [INFO] [-] [redis] connected to redis://172.16.15.16:6379 v3.2.6 [INFO] [-] [limit] connected to redis://172.16.15.16:6379/1 v3.2.6 [INFO] [-] [karma] connected to redis://172.16.15.16:6379/2 v3.2.6 [INFO] [-] [known-senders] connected to redis://172.16.15.16:6379/3 v3.2.6 -```` +``` Notice the database ID numbers appended to each plugins redis connection message. - [ci-img]: https://github.com/haraka/haraka-plugin-redis/actions/workflows/ci.yml/badge.svg [ci-url]: https://github.com/haraka/haraka-plugin-redis/actions/workflows/ci.yml [clim-img]: https://codeclimate.com/github/haraka/haraka-plugin-redis/badges/gpa.svg diff --git a/index.js b/index.js index 25efa01..8021aa8 100644 --- a/index.js +++ b/index.js @@ -1,251 +1,256 @@ -'use strict'; +'use strict' /* global server */ -const redis = require('redis'); +const redis = require('redis') exports.register = function () { - this.load_redis_ini(); + this.load_redis_ini() - // another plugin has called us with: inherits('haraka-plugin-redis') - if (this.name !== 'redis') return; + // another plugin has called us with: inherits('haraka-plugin-redis') + if (this.name !== 'redis') return - // register when 'redis' is declared in config/plugins - this.register_hook('init_master', 'init_redis_shared'); - this.register_hook('init_child', 'init_redis_shared'); + // register when 'redis' is declared in config/plugins + this.register_hook('init_master', 'init_redis_shared') + this.register_hook('init_child', 'init_redis_shared') } const defaultOpts = { socket: { host: '127.0.0.1', port: '6379' } } -const socketOpts = [ 'host', 'port', 'path', 'tls', 'connectTimeout', 'noDelay', 'keepAlive', 'reconnectStrategy' ] +const socketOpts = [ + 'host', + 'port', + 'path', + 'tls', + 'connectTimeout', + 'noDelay', + 'keepAlive', + 'reconnectStrategy', +] exports.load_redis_ini = function () { - const plugin = this; - - // store redis cfg at redisCfg, to avoid conflicting with plugins that - // inherit this plugin and have *their* config at plugin.cfg - plugin.redisCfg = plugin.config.get('redis.ini', function () { - plugin.load_redis_ini(); - }); - - // backwards compat - if (plugin.redisCfg?.server?.ip && !plugin.redisCfg?.server?.host) { - plugin.redisCfg.server.host = plugin.redisCfg.server.ip - delete plugin.redisCfg.server.ip - } - if (plugin.redisCfg.db && !plugin.redisCfg.database) { - plugin.redisCfg.database = plugin.redisCfg.db - delete plugin.redisCfg.db - } - - plugin.redisCfg.server = Object.assign({}, defaultOpts, plugin.redisCfg.opts, plugin.redisCfg.server); - plugin.redisCfg.pubsub = Object.assign({}, defaultOpts, plugin.redisCfg.opts, plugin.redisCfg.pubsub); - - // socket options. In redis < 4, the options like host and port were - // top level, now they're in socket.*. Permit legacy configs to still work - for (const s of [ 'server', 'pubsub' ]) { - for (const o of socketOpts) { - if (plugin.redisCfg[s][o]) plugin.redisCfg[s].socket[o] = plugin.redisCfg[s][o] - delete plugin.redisCfg[s][o] - } + const plugin = this + + // store redis cfg at redisCfg, to avoid conflicting with plugins that + // inherit this plugin and have *their* config at plugin.cfg + plugin.redisCfg = plugin.config.get('redis.ini', () => { + plugin.load_redis_ini() + }) + + // backwards compat + if (plugin.redisCfg?.server?.ip && !plugin.redisCfg?.server?.host) { + plugin.redisCfg.server.host = plugin.redisCfg.server.ip + delete plugin.redisCfg.server.ip + } + if (plugin.redisCfg.db && !plugin.redisCfg.database) { + plugin.redisCfg.database = plugin.redisCfg.db + delete plugin.redisCfg.db + } + + plugin.redisCfg.server = + { ...defaultOpts, ...plugin.redisCfg.opts, ...plugin.redisCfg.server }; + plugin.redisCfg.pubsub = + { ...defaultOpts, ...plugin.redisCfg.opts, ...plugin.redisCfg.pubsub }; + + // socket options. In redis < 4, the options like host and port were + // top level, now they're in socket.*. Permit legacy configs to still work + for (const s of ['server', 'pubsub']) { + for (const o of socketOpts) { + if (plugin.redisCfg[s][o]) + plugin.redisCfg[s].socket[o] = plugin.redisCfg[s][o] + delete plugin.redisCfg[s][o] } + } } exports.merge_redis_ini = function () { - - if (!this.cfg) this.cfg = {}; // no .ini loaded? - if (!this.cfg.redis) this.cfg.redis = {}; // no [redis] in .ini file - if (!this.redisCfg) this.load_redis_ini(); - - this.cfg.redis = Object.assign({}, this.redisCfg.server, this.cfg.redis); - - // backwards compatibility - for (const o of socketOpts) { - if (this.cfg.redis[o] === undefined) continue - this.cfg.redis.socket[o] = this.cfg.redis[o] - delete this.cfg.redis[o] - } - if (this.cfg.redis.db && !this.cfg.redis.database) { - this.cfg.redis.database = this.cfg.redis.db - delete this.cfg.redis.db - } + if (!this.cfg) this.cfg = {} // no .ini loaded? + if (!this.cfg.redis) this.cfg.redis = {} // no [redis] in .ini file + if (!this.redisCfg) this.load_redis_ini() + + this.cfg.redis = Object.assign({}, this.redisCfg.server, this.cfg.redis) + + // backwards compatibility + for (const o of socketOpts) { + if (this.cfg.redis[o] === undefined) continue + this.cfg.redis.socket[o] = this.cfg.redis[o] + delete this.cfg.redis[o] + } + if (this.cfg.redis.db && !this.cfg.redis.database) { + this.cfg.redis.database = this.cfg.redis.db + delete this.cfg.redis.db + } } exports.init_redis_shared = function (next, server) { + let calledNext = false + function nextOnce(e) { + if (e) this.logerror(`Redis error: ${e.message}`) + if (calledNext) return + calledNext = true + next() + } + + // this is the server-wide redis, shared by plugins that don't + // specify a db ID. + if (!server.notes.redis) { + this.get_redis_client(this.redisCfg.server).then((client) => { + server.notes.redis = client + nextOnce() + }) + return + } - let calledNext = false; - function nextOnce (e) { - if (e) this.logerror(`Redis error: ${e.message}`); - if (calledNext) return; - calledNext = true; - next(); - } - - // this is the server-wide redis, shared by plugins that don't - // specificy a db ID. - if (!server.notes.redis) { - this.get_redis_client(this.redisCfg.server).then(client => { - server.notes.redis = client - nextOnce() - }) - return - } - - server.notes.redis.ping((err, res) => { - if (err) return nextOnce(err); + server.notes.redis.ping((err) => { + if (err) return nextOnce(err) - this.loginfo('already connected'); - nextOnce(); // connection is good - }); + this.loginfo('already connected') + nextOnce() // connection is good + }) } exports.init_redis_plugin = function (next, server) { - const plugin = this; - - // this function is called by plugins at init_*, to establish their - // shared or unique redis db handle. - - let calledNext=false; - function nextOnce () { - if (calledNext) return; - calledNext = true; - next(); + const plugin = this + + // this function is called by plugins at init_*, to establish their + // shared or unique redis db handle. + + let calledNext = false + function nextOnce() { + if (calledNext) return + calledNext = true + next() + } + + // for tests that do not load a shared config + if (!plugin.cfg) { + plugin.cfg = { redis: {} } + if (plugin.redisCfg) + plugin.cfg.redis = JSON.parse(JSON.stringify(plugin.redisCfg)) + } + if (!server) server = { notes: {} } + + const pidb = plugin.cfg.redis.database + if (server.notes.redis) { + // server-wide redis is available + // and the DB not specified or is the same as server-wide + if (pidb === undefined || pidb === plugin.redisCfg.db) { + server.loginfo(plugin, 'using server.notes.redis') + plugin.db = server.notes.redis + nextOnce() + return } + } - // for tests that do not load a shared config - if (!plugin.cfg) { - plugin.cfg = { redis: {} }; - if (plugin.redisCfg) plugin.cfg.redis = JSON.parse(JSON.stringify(plugin.redisCfg)) - } - if (!server) server = { notes: {} }; - - const pidb = plugin.cfg.redis.database; - if (server.notes.redis) { // server-wide redis is available - // and the DB not specified or is the same as server-wide - if (pidb === undefined || pidb === plugin.redisCfg.db) { - server.loginfo(plugin, 'using server.notes.redis'); - plugin.db = server.notes.redis; - nextOnce(); - return; - } - } - - plugin.get_redis_client(plugin.cfg.redis).then(client => { - plugin.db = client - nextOnce() - }) + plugin.get_redis_client(plugin.cfg.redis).then((client) => { + plugin.db = client + nextOnce() + }) } exports.shutdown = function () { - if (this.db) this.db.quit(); + if (this.db) this.db.quit() - if (server && server.notes && server.notes.redis) { - server.notes.redis.quit(); - } + if (server && server.notes && server.notes.redis) { + server.notes.redis.quit() + } } exports.redis_ping = async function () { + this.redis_pings = false + if (!this.db) throw new Error('redis not initialized') - this.redis_pings=false; - if (!this.db) throw new Error('redis not initialized'); - - const r = await this.db.ping() - if (r !== 'PONG') throw new Error('not PONG'); - this.redis_pings=true + const r = await this.db.ping() + if (r !== 'PONG') throw new Error('not PONG') + this.redis_pings = true - return true + return true } -function getUriStr (client, opts) { - let msg = `redis://${opts?.socket?.host}:${opts?.socket?.port}`; - if (opts?.database) msg += `/${opts?.database}`; - if (client?.server_info?.redis_version) { - msg += `\tv${client?.server_info?.redis_version}`; - } - return msg; +function getUriStr(client, opts) { + let msg = `redis://${opts?.socket?.host}:${opts?.socket?.port}` + if (opts?.database) msg += `/${opts?.database}` + if (client?.server_info?.redis_version) { + msg += `\tv${client?.server_info?.redis_version}` + } + return msg } exports.get_redis_client = async function (opts) { + const client = redis.createClient(opts) - const client = redis.createClient(opts) - - let urlStr + let urlStr - client - .on('error', (err) => { - this.logerror(err.message); - }) - .on('end', () => { - this.loginfo(`Disconnected from ${urlStr}`); - }) + client + .on('error', (err) => { + this.logerror(err.message) + }) + .on('end', () => { + this.loginfo(`Disconnected from ${urlStr}`) + }) - try { - await client.connect() + try { + await client.connect() - if (opts?.database) client.dbid = opts?.database + if (opts?.database) client.dbid = opts?.database - client.server_info = await client.info() - urlStr = getUriStr(client, opts) - this.loginfo(`connected to ${urlStr}`); + client.server_info = await client.info() + urlStr = getUriStr(client, opts) + this.loginfo(`connected to ${urlStr}`) - return client - } - catch (e) { - console.error(e) - this.logerror(e); - } + return client + } catch (e) { + console.error(e) + this.logerror(e) + } } - exports.get_redis_pub_channel = function (conn) { - return `result-${conn.transaction ? conn.transaction.uuid : conn.uuid}`; + return `result-${conn.transaction ? conn.transaction.uuid : conn.uuid}` } exports.get_redis_sub_channel = function (conn) { - return `result-${conn.uuid}*`; + return `result-${conn.uuid}*` } // formerly used by pi-watch exports.redis_subscribe_pattern = async function (pattern, onMessage) { + if (this.redis) return // already subscribed? - if (this.redis) return // already subscribed? + this.redis = redis.createClient(this.redisCfg.pubsub) + await this.redis.connect() - this.redis = redis.createClient(this.redisCfg.pubsub) - await this.redis.connect() - - await this.redis.pSubscribe(pattern, onMessage); - this.logdebug(this, `pSubscribed to ${pattern}`); + await this.redis.pSubscribe(pattern, onMessage) + this.logdebug(this, `pSubscribed to ${pattern}`) } // the next two functions are use by pi-karma exports.redis_subscribe = async function (connection, onMessage) { + if (connection.notes.redis) { + connection.logdebug(this, `redis already subscribed`) + return // another plugin has already called this. + } - if (connection.notes.redis) { - connection.logdebug(this, `redis already subscribed`); - return; // another plugin has already called this. - } + const timer = setTimeout(() => { + connection.logerror('redis subscribe timed out') + }, 3 * 1000) - const timer = setTimeout(() => { - connection.logerror('redis subscribe timed out'); - }, 3 * 1000); + connection.notes.redis = redis.createClient(this.redisCfg.pubsub) + await connection.notes.redis.connect() - connection.notes.redis = redis.createClient(this.redisCfg.pubsub) - await connection.notes.redis.connect() + clearTimeout(timer) - clearTimeout(timer); - - const pattern = this.get_redis_sub_channel(connection) - connection.notes.redis.pSubscribe(pattern, onMessage); - connection.logdebug(this, `pSubscribed to ${pattern}`); + const pattern = this.get_redis_sub_channel(connection) + connection.notes.redis.pSubscribe(pattern, onMessage) + connection.logdebug(this, `pSubscribed to ${pattern}`) } exports.redis_unsubscribe = async function (connection) { - - if (!connection.notes.redis) { - connection.logerror(this, `redis_unsubscribe called when no redis`) - return; - } - - const pattern = this.get_redis_sub_channel(connection) - await connection.notes.redis.unsubscribe(pattern); - connection.logdebug(this, `unsubsubscribed from ${pattern}`); - connection.notes.redis.quit(); + if (!connection.notes.redis) { + connection.logerror(this, `redis_unsubscribe called when no redis`) + return + } + + const pattern = this.get_redis_sub_channel(connection) + await connection.notes.redis.unsubscribe(pattern) + connection.logdebug(this, `unsubsubscribed from ${pattern}`) + connection.notes.redis.quit() } diff --git a/package.json b/package.json index be2e86f..4eaa9dc 100644 --- a/package.json +++ b/package.json @@ -1,26 +1,30 @@ { "name": "haraka-plugin-redis", - "version": "2.0.6", + "version": "2.0.7", "description": "Redis plugin for Haraka & other plugins to inherit from", "main": "index.js", + "files": [ + "config" + ], "directories": { "test": "test" }, "dependencies": { - "redis": "4" + "redis": "^4.6.0" }, "devDependencies": { - "eslint": "8", - "eslint-plugin-haraka": "*", - "haraka-test-fixtures": "*", - "mocha": "9" + "@haraka/eslint-config": "^1.1.3", + "haraka-test-fixtures": "1.3.7" }, "scripts": { - "lint": "npx eslint *.js test", - "lintfix": "npx eslint --fix *.js test", - "cover": "NODE_ENV=cov npx nyc --reporter=lcovonly npm run test", + "format": "npm run prettier:fix && npm run lint:fix", + "lint": "npx eslint@^8 *.js test", + "lint:fix": "npx eslint@^8 *.js test --fix", + "prettier": "npx prettier . --check", + "prettier:fix": "npx prettier . --write --log-level=warn", + "test": "npx mocha@10", "versions": "npx dependency-version-checker check", - "test": "npx mocha" + "versions:fix": "npx dependency-version-checker update && npm run prettier:fix" }, "repository": { "type": "git", @@ -28,6 +32,7 @@ }, "keywords": [ "haraka", + "haraka-plugin", "mail", "smtp", "redis" diff --git a/test/redis.js b/test/redis.js index 3d1f97a..e6cbb4a 100644 --- a/test/redis.js +++ b/test/redis.js @@ -1,138 +1,141 @@ -'use strict'; +'use strict' const assert = require('assert') -const path = require('path') +const path = require('path') const fixtures = require('haraka-test-fixtures') -function retry (options) { - if (options.error) { - console.error(options.error); - } - return undefined; +function retry(options) { + if (options.error) { + console.error(options.error) + } + return undefined } describe('config', function () { - before(async function () { - this.plugin = new fixtures.plugin('index') - this.plugin.config = this.plugin.config.module_config(path.resolve('test')); + before(async function () { + this.plugin = new fixtures.plugin('index') + this.plugin.config = this.plugin.config.module_config(path.resolve('test')) + }) + + it('loads', async function () { + assert.equal(this.plugin.name, 'index') + }) + + it('config defaults', async function () { + this.plugin.load_redis_ini() + assert.equal(this.plugin.redisCfg.server.socket.host, '127.0.0.1') + assert.equal(this.plugin.redisCfg.server.socket.port, 6379) + }) + + it('merges [opts] into server config', async function () { + this.plugin.load_redis_ini() + assert.deepEqual(this.plugin.redisCfg, { + main: {}, + pubsub: { + socket: { + host: '127.0.0.1', + port: '6379', + }, + database: 5, + password: 'dontUseThisOne', + }, + opts: { database: 5, password: 'dontUseThisOne' }, + server: { + socket: { + host: '127.0.0.1', + port: '6379', + }, + database: 5, + password: 'dontUseThisOne', + }, }) - - it('loads', async function () { - assert.equal(this.plugin.name, 'index'); - }) - - it('config defaults', async function () { - this.plugin.load_redis_ini(); - assert.equal(this.plugin.redisCfg.server.socket.host, '127.0.0.1') - assert.equal(this.plugin.redisCfg.server.socket.port, 6379) - }) - - it('merges [opts] into server config', async function () { - this.plugin.load_redis_ini(); - assert.deepEqual(this.plugin.redisCfg, { - main: {}, - pubsub: { - socket: { - host: '127.0.0.1', - port: '6379', - }, - database: 5, - password: 'dontUseThisOne' - }, - opts: { database: 5, password: 'dontUseThisOne' }, - server: { - socket: { - host: '127.0.0.1', - port: '6379', - }, - database: 5, - password: 'dontUseThisOne' - } - }); - }) - - it('merges redis.ini [opts] into plugin config', async function () { - this.plugin.load_redis_ini(); - this.plugin.cfg = {}; - this.plugin.merge_redis_ini(); - assert.deepEqual(this.plugin.cfg.redis, { - socket: { - host: '127.0.0.1', - port: '6379', - }, - database: 5, - password: 'dontUseThisOne' - }) + }) + + it('merges redis.ini [opts] into plugin config', async function () { + this.plugin.load_redis_ini() + this.plugin.cfg = {} + this.plugin.merge_redis_ini() + assert.deepEqual(this.plugin.cfg.redis, { + socket: { + host: '127.0.0.1', + port: '6379', + }, + database: 5, + password: 'dontUseThisOne', }) + }) }) describe('connects', function () { - before(async function () { - this.plugin = new fixtures.plugin('index') - this.plugin.register() - }) - - it('loads', async function () { - assert.equal(this.plugin.name, 'index'); + before(async function () { + this.plugin = new fixtures.plugin('index') + this.plugin.register() + }) + + it('loads', async function () { + assert.equal(this.plugin.name, 'index') + }) + + it('connects', async function () { + const redis = await this.plugin.get_redis_client({ + socket: { + host: this.plugin.redisCfg.server.host, + port: this.plugin.redisCfg.server.port, + }, + retry_strategy: retry, }) - - it('connects', async function () { - const redis = await this.plugin.get_redis_client({ - socket: { - host: this.plugin.redisCfg.server.host, - port: this.plugin.redisCfg.server.port, - }, - retry_strategy: retry, - }) - assert.ok(redis); - await redis.quit() - }) - - it('populates plugin.cfg.redis when asked', async function () { - assert.equal(this.plugin.cfg, undefined); - this.plugin.merge_redis_ini(); - assert.deepEqual(this.plugin.cfg.redis, { socket: { host: '127.0.0.1', port: '6379' } }); - }) - - it('connects to a different redis db', async function () { - this.plugin.merge_redis_ini(); - this.plugin.cfg.redis.database = 2; - this.plugin.cfg.redis.retry_strategy = retry; - const client = await this.plugin.get_redis_client(this.plugin.cfg.redis) - const res = await client.ping() - assert.equal(res, 'PONG') - assert.ok(client) - await client.quit() + assert.ok(redis) + await redis.quit() + }) + + it('populates plugin.cfg.redis when asked', async function () { + assert.equal(this.plugin.cfg, undefined) + this.plugin.merge_redis_ini() + assert.deepEqual(this.plugin.cfg.redis, { + socket: { host: '127.0.0.1', port: '6379' }, }) + }) + + it('connects to a different redis db', async function () { + this.plugin.merge_redis_ini() + this.plugin.cfg.redis.database = 2 + this.plugin.cfg.redis.retry_strategy = retry + const client = await this.plugin.get_redis_client(this.plugin.cfg.redis) + const res = await client.ping() + assert.equal(res, 'PONG') + assert.ok(client) + await client.quit() + }) }) describe('init_redis_plugin', function () { - before(function () { - this.server = { notes: { } } - - this.plugin = new fixtures.plugin('index') - this.plugin.register() - this.plugin.merge_redis_ini() - }) - - after(function () { - this.plugin.db.quit() - }) - - it('connects to redis', function (done) { - this.plugin.init_redis_plugin(() => { - assert.ok(this.plugin.db?.server_info) - done() - }, this.server) - }) - - it('pings and gets PONG answer', function (done) { - this.plugin.redis_ping() - .then(r => { - assert.equal(r, true) - done() - }) - .catch(done) - }) -}) \ No newline at end of file + before(function () { + this.server = { notes: {} } + + this.plugin = new fixtures.plugin('index') + this.plugin.register() + this.plugin.merge_redis_ini() + }) + + after(function () { + this.plugin.db.quit() + }) + + it('connects to redis', function (done) { + this.plugin.init_redis_plugin(() => { + assert.ok(this.plugin.db?.server_info) + done() + }, this.server) + }) + + it('pings and gets PONG answer', function (done) { + this.plugin + .redis_ping() + .then((r) => { + assert.equal(r, true) + done() + }) + .catch(done) + }) +})