From f41c235c0c17b08a92597987b3d2e5201c0b932c Mon Sep 17 00:00:00 2001 From: Matt Simerson Date: Wed, 10 Apr 2024 13:47:44 -0700 Subject: [PATCH] deps: bump versions --- .codeclimate.yml | 8 +- .github/PULL_REQUEST_TEMPLATE.md | 6 +- .github/workflows/ci.yml | 4 +- .github/workflows/codeql.yml | 4 +- .github/workflows/publish.yml | 2 +- .prettierrc.yml | 2 + CHANGELOG.md | 21 +- CONTRIBUTORS.md | 5 +- README.md | 84 +++---- index.js | 417 ++++++++++++++++--------------- package.json | 25 +- test/result_store.js | 350 ++++++++++++++------------ 12 files changed, 476 insertions(+), 452 deletions(-) create mode 100644 .prettierrc.yml diff --git a/.codeclimate.yml b/.codeclimate.yml index bff80e2..2ccb1e4 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: return-statements: @@ -16,5 +16,5 @@ checks: threshold: 20 ratings: - paths: - - "**.js" + paths: + - '**.js' 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 a1445e2..3bf878d 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -1,6 +1,6 @@ name: CI -on: [ push, pull_request ] +on: [push, pull_request] env: CI: true @@ -18,6 +18,6 @@ jobs: uses: haraka/.github/.github/workflows/ubuntu.yml@master windows: - if: ${{ false }} # needs redis server + if: ${{ false }} # needs redis server 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/.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/CHANGELOG.md b/CHANGELOG.md index d34da6e..be6e908 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,12 +6,14 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/). ### [2.2.4] - 2024-04-10 +- deps: bump versions - ci: updated ci.yml - doc(CHANGES): rename Changes.md -> CHANGELOG.md - doc(CONTRIBUTORS): added - populate [files] in package.json. Delete .npmignore. - dep: eslint-plugin-haraka -> @haraka/eslint-config - lint: remove duplicate / stale rules from .eslintrc +- prettier ### [2.2.3] - 2023-06-08 @@ -19,18 +21,15 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/). - dev: expand .gitignore - packaging: add .npmignore - #### 2.2.2 - 2022-05-28 - feat: add ignores keys with undefined values - add .release submodule - #### 2.2.1 - 2022-05-27 - chore(ci): depend on shared GHA workflows - #### 2.2.0 - 2022-05-23 - dep(node): require 14+ @@ -40,50 +39,44 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/). - doc(README): deprecate usage of 'plugin' - doc(README): update badges - #### 2.1.0 - 2021-10-14 -- bump redis dep 2.8.0 -> 3.1.2 +- bump redis dep 2.8.0 -> 3.1.2 - replace nodeunit with mocha - add github workflows, drop travis & appveyor CI - use es6 classes - es6: use "for item of array" syntax for array iterator - #### 2.0.3 - 2017-08-26 - add redis_publish boolean to disable redis results publishing - #### 2.0.2 - 2017-06-26 - revert #4, until a proper and tested fix is available - #### 2.0.1 - 2017-05-26 - eslint 4 compat - #### 2.0.0 - 2017-05-26 - Disable Redis pub/sub by default - #### 1.0.2 - 2017-02-13 - publish incr operations - update eslint to inherit eslint-plugin-haraka - added AppVeyor (windows) testing - -#### 1.0.1 - 2017-01-26 +#### 1.0.1 - 2017-01-26 - update eslint to inherit eslint-plugin-haraka + * depend on haraka-config - * vs ./config, which doesn't work for npm packaged plugin tests + - vs ./config, which doesn't work for npm packaged plugin tests -#### 1.0.0 - initial release +#### 1.0.0 - initial release [2.1.0]: https://github.com/haraka/haraka-results/releases/tag/2.1.0 [2.2.0]: https://github.com/haraka/haraka-results/releases/tag/2.2.0 diff --git a/CONTRIBUTORS.md b/CONTRIBUTORS.md index d337a4d..2777efa 100644 --- a/CONTRIBUTORS.md +++ b/CONTRIBUTORS.md @@ -1,9 +1,8 @@ - # Contributors This handcrafted artisinal software is brought to you by: -|
msimerson (29)|
PSSGCSim (2)|
lnedry (2)|
baudehlo (1)|
smfreegard (1)| -| :---: | :---: | :---: | :---: | :---: | +|
msimerson (29) |
PSSGCSim (2) |
lnedry (2) |
baudehlo (1) |
smfreegard (1) | +| :---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------: | :-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------: | :-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------: | :-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------: | :-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------: | this file is maintained by [.release](https://github.com/msimerson/.release) diff --git a/README.md b/README.md index 830564a..e6d9ad5 100644 --- a/README.md +++ b/README.md @@ -12,8 +12,8 @@ Add, log, retrieve, and share the results of plugin tests. Results is a structured way of storing results from plugins across a session, allowing those results to be retrieved later or by other plugins. -Results objects are present on every Haraka connection *and* transaction. When -in a SMTP transaction, results from *both* are applicable to that transaction. +Results objects are present on every Haraka connection _and_ transaction. When +in a SMTP transaction, results from _both_ are applicable to that transaction. ## Usage @@ -47,9 +47,9 @@ Store the results in the transaction (vs connection): Each plugin can have custom settings in results.ini to control results logging. There are three options available: hide, order, and debug. -* hide - a comma separated list of results to hide from the output -* order - a comman separated list, specifing the order of items in the output -* debug - log debug messages every time results are called +- hide - a comma separated list of results to hide from the output +- order - a comman separated list, specifing the order of items in the output +- debug - log debug messages every time results are called ```ini ; put this in config/results.ini @@ -93,46 +93,43 @@ In addition to appending values to the predefined lists, arbitrary results can be stored in the cache: ```js - results.add(this, {my_result: 'anything I want'}) +results.add(this, { my_result: 'anything I want' }) ``` When arbirary values are stored, they are listed first in the log output. Their display can be suppressed with the **hide** option in results.ini. - #### incr Increment counters. The argument to incr is an object with counter names and increment values. Examples: ```js - results.incr(this, {unrecognized_commands: 1}) +results.incr(this, { unrecognized_commands: 1 }) - results.incr(this, {karma: -1}) - results.incr(this, {karma: 2}) +results.incr(this, { karma: -1 }) +results.incr(this, { karma: 2 }) ``` - #### push Append items onto arrays. The argument to push is an object with array names and the new value to be appended to the array. Examples: ```js - results.push(this, {dns_recs: 'name1'}) - results.push(this, {dns_recs: 'name2'}) +results.push(this, { dns_recs: 'name1' }) +results.push(this, { dns_recs: 'name2' }) ``` #### collate ```js - const summary = results.collate(this) +const summary = results.collate(this) ``` Formats the contents of the result cache and returns them. This function is called internally by `add()` after each update. - #### get Retrieve the stored results as an object. The only argument is the name of the @@ -161,49 +158,48 @@ Check result contents for string or pattern matches. Syntax: ```js - results.has('plugin_name', 'result_name', 'search_term') +results.has('plugin_name', 'result_name', 'search_term') ``` -* result\_name: the name of an array or string in the result object -* search\_term: a string or RegExp object - +- result_name: the name of an array or string in the result object +- search_term: a string or RegExp object ### More Examples #### Store Results: ```js - results.add(this, {pass: 'some_test'}) - results.add(this, {pass: 'some_test(with reason)'}) +results.add(this, { pass: 'some_test' }) +results.add(this, { pass: 'some_test(with reason)' }) ``` #### Retrieve exact match with **get**: ```js - if (results.get('plugin_name').pass.indexOf('some_test') !== -1) { - // some_test passed (1x) - } +if (results.get('plugin_name').pass.indexOf('some_test') !== -1) { + // some_test passed (1x) +} ``` #### Retrieve a string match with **has** ```js - if (results.has('plugin_name', 'pass', 'some_test')) { - // some_test passed (1x) - } +if (results.has('plugin_name', 'pass', 'some_test')) { + // some_test passed (1x) +} ``` The syntax for using **has** is a little more pleasant. Both options require one to check for each reason which is unpleasant when -and all we really want to know is if some\_test passed or not. +and all we really want to know is if some_test passed or not. #### Retrieve a matching pattern: ```js - if (results.has('plugin_name', 'pass', /^some_test/)) { - // some_test passed (2x) - } +if (results.has('plugin_name', 'pass', /^some_test/)) { + // some_test passed (2x) +} ``` ### Private Results @@ -214,7 +210,7 @@ human_html output, prefix the name of the key with an underscore. Example: ```js - results.add(this, { _hidden: 'some data' }) +results.add(this, { _hidden: 'some data' }) ``` ## Redis Pub/Sub @@ -229,29 +225,27 @@ This is from the karma plugin subscribing on the `connect_init` hook: ```js exports.register = function (next, server) { - this.inherits('redis') + this.inherits('redis') - register_hook('connect_init', 'redis_subscribe'); - register_hook('disconnect', 'redis_unsubscribe'); + register_hook('connect_init', 'redis_subscribe') + register_hook('disconnect', 'redis_unsubscribe') } exports.redis_subscribe = function (next, connection) { - - this.redis_subscribe(connection, function () { - connection.notes.redis.on('pmessage', (pattern, channel, message) => { - // do stuff with messages that look like this - // {"plugin":"karma","result":{"fail":"spamassassin.hits"}} - // {"plugin":"geoip","result":{"country":"CN"}} - }) - next() + this.redis_subscribe(connection, function () { + connection.notes.redis.on('pmessage', (pattern, channel, message) => { + // do stuff with messages that look like this + // {"plugin":"karma","result":{"fail":"spamassassin.hits"}} + // {"plugin":"geoip","result":{"country":"CN"}} }) + next() + }) } exports.redis_unsubscribe = function (next, connection) { - this.redis_unsubscribe(connection) + this.redis_unsubscribe(connection) } ``` - [ci-img]: https://github.com/haraka/haraka-results/actions/workflows/ci.yml/badge.svg [ci-url]: https://github.com/haraka/haraka-results/actions/workflows/ci.yml [cov-img]: https://codecov.io/github/haraka/haraka-results/coverage.svg diff --git a/index.js b/index.js index 67e54f4..7c15f20 100644 --- a/index.js +++ b/index.js @@ -1,256 +1,259 @@ // results - programmatic handling of plugin results -'use strict'; +'use strict' -const config = require('haraka-config'); -const util = require('util'); +const config = require('haraka-config') +const util = require('util') // see docs in docs/Results.md -const append_lists = ['msg','pass','fail','skip','err']; -const overwrite_lists = ['hide','order']; -const log_opts = ['emit','human','human_html']; -const all_opts = append_lists.concat(overwrite_lists, log_opts); -let cfg; +const append_lists = ['msg', 'pass', 'fail', 'skip', 'err'] +const overwrite_lists = ['hide', 'order'] +const log_opts = ['emit', 'human', 'human_html'] +const all_opts = append_lists.concat(overwrite_lists, log_opts) +let cfg class ResultStore { - constructor (conn) { - this.conn = conn; - this.store = {}; - cfg = config.get('results.ini', { - booleans: [ - '+main.redis_publish', - ] - }); + constructor(conn) { + this.conn = conn + this.store = {} + cfg = config.get('results.ini', { + booleans: ['+main.redis_publish'], + }) + } + + has(plugin, list, search) { + const name = this.resolve_plugin_name(plugin) + const result = this.store[name] + if (!result || !result[list]) return false + + if (typeof result[list] === 'string') { + return this._has_string(result[list], search) } - has (plugin, list, search) { - const name = this.resolve_plugin_name(plugin); - const result = this.store[name]; - if (!result || !result[list]) return false; - - if (typeof result[list] === 'string') { - return this._has_string(result[list], search); - } - - if (Array.isArray(result[list])) { - return this._has_array(result[list], search); - } - - return false; + if (Array.isArray(result[list])) { + return this._has_array(result[list], search) } - _has_string (msg, search) { - if (typeof search === 'string' && search === msg) return true; - if (typeof search === 'object' && msg.match(search)) return true; - return false; + return false + } + + _has_string(msg, search) { + if (typeof search === 'string' && search === msg) return true + if (typeof search === 'object' && msg.match(search)) return true + return false + } + + _has_array(msg, search) { + for (const item of msg) { + switch (typeof search) { + case 'string': + case 'number': + case 'boolean': + if (search === item) return true + break + case 'object': + if (item.match(search)) return true + break + } } - - _has_array (msg, search) { - for (const item of msg) { - switch (typeof search) { - case 'string': - case 'number': - case 'boolean': - if (search === item) return true; - break; - case 'object': - if (item.match(search)) return true; - break; - } - } - return false; + return false + } + + redis_publish(name, obj) { + if (!cfg.main.redis_publish) return + if (!this.conn.server?.notes?.redis) return + + const channel = `result-${this.conn.transaction ? this.conn.transaction.uuid : this.conn.uuid}` + this.conn.server.notes.redis.publish( + channel, + JSON.stringify({ plugin: name, result: obj }), + ) + } + + add(plugin, obj) { + const name = this.resolve_plugin_name(plugin) + let result = this.store[name] + if (!result) { + result = default_result() + this.store[name] = result } - redis_publish (name, obj) { - if (!cfg.main.redis_publish) return; - if (!this.conn.server?.notes?.redis) return; + this.redis_publish(name, obj) - const channel = `result-${this.conn.transaction ? this.conn.transaction.uuid : this.conn.uuid}`; - this.conn.server.notes.redis.publish(channel, JSON.stringify({ plugin: name, result: obj })); + // these are arrays each invocation appends to + for (const key of append_lists) { + if (!obj[key]) continue + result[key] = this._append_to_array(result[key], obj[key]) } - add (plugin, obj) { - const name = this.resolve_plugin_name(plugin); - let result = this.store[name]; - if (!result) { - result = default_result(); - this.store[name] = result; - } - - this.redis_publish(name, obj); - - // these are arrays each invocation appends to - for (const key of append_lists) { - if (!obj[key]) continue; - result[key] = this._append_to_array(result[key], obj[key]) - } - - // these arrays are overwritten when passed - for (const key of overwrite_lists) { - if (!obj[key]) continue; - result[key] = obj[key]; - } - - // anything else is an arbitrary key/val to store - for (const key in obj) { - if (all_opts.includes(key)) continue; // weed out our keys - if (obj[key] === undefined) continue; // ignore keys w/undef value - result[key] = obj[key]; // save the rest - } - - return this._log(plugin, result, obj); + // these arrays are overwritten when passed + for (const key of overwrite_lists) { + if (!obj[key]) continue + result[key] = obj[key] } - _append_to_array (array, item) { - if (Array.isArray(item)) return array.concat(item); - - array.push(item); - return array; - } - - incr (plugin, obj) { - const name = this.resolve_plugin_name(plugin); - let result = this.store[name]; - if (!result) { - result = default_result(); - this.store[name] = result; - } - - const pub = {}; - - for (const key in obj) { - let val = parseFloat(obj[key]) || 0; - if (isNaN(val)) val = 0; - if (isNaN(result[key])) result[key] = 0; - result[key] = parseFloat(result[key]) + parseFloat(val); - pub[key] = result[key]; - } - - this.redis_publish(name, pub); + // anything else is an arbitrary key/val to store + for (const key in obj) { + if (all_opts.includes(key)) continue // weed out our keys + if (obj[key] === undefined) continue // ignore keys w/undef value + result[key] = obj[key] // save the rest } - push (plugin, obj) { - const name = this.resolve_plugin_name(plugin); - let result = this.store[name]; - if (!result) { - result = default_result(); - this.store[name] = result; - } + return this._log(plugin, result, obj) + } - this.redis_publish(name, obj); + _append_to_array(array, item) { + if (Array.isArray(item)) return array.concat(item) - for (const key in obj) { - if (!result[key]) result[key] = []; - result[key] = this._append_to_array(result[key], obj[key]) - } + array.push(item) + return array + } - return this._log(plugin, result, obj); + incr(plugin, obj) { + const name = this.resolve_plugin_name(plugin) + let result = this.store[name] + if (!result) { + result = default_result() + this.store[name] = result } - collate (plugin) { - const name = this.resolve_plugin_name(plugin); - const result = this.store[name]; - if (!result) return; - return this.private_collate(result, name).join(', '); - } + const pub = {} - get (plugin_or_name) { - return this.store[ this.resolve_plugin_name(plugin_or_name) ]; + for (const key in obj) { + let val = parseFloat(obj[key]) || 0 + if (isNaN(val)) val = 0 + if (isNaN(result[key])) result[key] = 0 + result[key] = parseFloat(result[key]) + parseFloat(val) + pub[key] = result[key] } - resolve_plugin_name (thing) { - if (typeof thing === 'string') return thing; - if (typeof thing === 'object' && thing.name) return thing.name; - return; + this.redis_publish(name, pub) + } + + push(plugin, obj) { + const name = this.resolve_plugin_name(plugin) + let result = this.store[name] + if (!result) { + result = default_result() + this.store[name] = result } - get_all () { - return this.store; + this.redis_publish(name, obj) + + for (const key in obj) { + if (!result[key]) result[key] = [] + result[key] = this._append_to_array(result[key], obj[key]) } - private_collate (result, name) { - const r = []; + return this._log(plugin, result, obj) + } - const order = this._get_order(cfg[name]); - const hide = this._get_hide(cfg[name]); + collate(plugin) { + const name = this.resolve_plugin_name(plugin) + const result = this.store[name] + if (!result) return + return this.private_collate(result, name).join(', ') + } - // anything not predefined in the result was purposeful, show it first - for (const key in result) { - if (!this._pre_defined(key, result[key], hide)) continue; - r.push(`${key}: ${result[key]}`); - } + get(plugin_or_name) { + return this.store[this.resolve_plugin_name(plugin_or_name)] + } - // and then supporting information - let array = append_lists; // default - if (order && order.length) array = order; // config file - if (result.order && result.order.length) array = result.order; // caller + resolve_plugin_name(thing) { + if (typeof thing === 'string') return thing + if (typeof thing === 'object' && thing.name) return thing.name + return + } - for (const key of array) { - if (!result[key]) continue; - if (!result[key].length) continue; - if (hide && hide.length && hide.indexOf(key) !== -1) continue; - r.push(`${key}:${result[key].join(', ')}`); - } + get_all() { + return this.store + } - return r; - } + private_collate(result, name) { + const r = [] + + const order = this._get_order(cfg[name]) + const hide = this._get_hide(cfg[name]) - _pre_defined (key, res, hide) { - if (key[0] === '_') return false; // 'private' keys - if (all_opts.indexOf(key) !== -1) return false; // these get shown later. - if (hide.length && hide.indexOf(key) !== -1) return false; - if (typeof res === 'object') { - if (Array.isArray(res)) { - if (res.length === 0) return false; - } - else { - return false; - } - } - return true; + // anything not predefined in the result was purposeful, show it first + for (const key in result) { + if (!this._pre_defined(key, result[key], hide)) continue + r.push(`${key}: ${result[key]}`) } - _get_order (c) { - if (!c || !c.order) return []; - return c.order.trim().split(/[,; ]+/); + // and then supporting information + let array = append_lists // default + if (order && order.length) array = order // config file + if (result.order && result.order.length) array = result.order // caller + + for (const key of array) { + if (!result[key]) continue + if (!result[key].length) continue + if (hide && hide.length && hide.indexOf(key) !== -1) continue + r.push(`${key}:${result[key].join(', ')}`) } - _get_hide (c) { - if (!c || !c.hide) return []; - return c.hide.trim().trim().split(/[,; ]+/); + return r + } + + _pre_defined(key, res, hide) { + if (key[0] === '_') return false // 'private' keys + if (all_opts.indexOf(key) !== -1) return false // these get shown later. + if (hide.length && hide.indexOf(key) !== -1) return false + if (typeof res === 'object') { + if (Array.isArray(res)) { + if (res.length === 0) return false + } else { + return false + } + } + return true + } + + _get_order(c) { + if (!c || !c.order) return [] + return c.order.trim().split(/[,; ]+/) + } + + _get_hide(c) { + if (!c || !c.hide) return [] + return c.hide + .trim() + .trim() + .split(/[,; ]+/) + } + + _log(plugin, result, obj) { + const name = plugin.name + + // collate results + result.human = obj.human + if (!result.human) { + const r = this.private_collate(result, name) + result.human = r.join(', ') + result.human_html = r.join(', \t ') } - _log (plugin, result, obj) { - const name = plugin.name; - - // collate results - result.human = obj.human; - if (!result.human) { - const r = this.private_collate(result, name); - result.human = r.join(', '); - result.human_html = r.join(', \t '); - } - - // logging results - if (obj.emit) this.conn.loginfo(plugin, result.human); // by request - if (obj.err) { - // Handle error objects by logging the message - if (util.isError(obj.err)) { - this.conn.logerror(plugin, obj.err.message); - } - else { - this.conn.logerror(plugin, obj.err); - } - } - if (!obj.emit && !obj.err) { // by config - const pic = cfg[name]; - if (pic && pic.debug) this.conn.logdebug(plugin, result.human); - } - return this.human; + // logging results + if (obj.emit) this.conn.loginfo(plugin, result.human) // by request + if (obj.err) { + // Handle error objects by logging the message + if (util.isError(obj.err)) { + this.conn.logerror(plugin, obj.err.message) + } else { + this.conn.logerror(plugin, obj.err) + } + } + if (!obj.emit && !obj.err) { + // by config + const pic = cfg[name] + if (pic && pic.debug) this.conn.logdebug(plugin, result.human) } + return this.human + } } -function default_result () { - return { pass: [], fail: [], msg: [], err: [], skip: [] }; +function default_result() { + return { pass: [], fail: [], msg: [], err: [], skip: [] } } -module.exports = ResultStore; +module.exports = ResultStore diff --git a/package.json b/package.json index 3b5336a..1c49695 100644 --- a/package.json +++ b/package.json @@ -9,12 +9,19 @@ "engines": { "node": ">=14" }, - "files": ["CHANGELOG.md", "config"], + "files": [ + "CHANGELOG.md", + "config" + ], "scripts": { - "cover": "npx istanbul cover npm run test", - "lint": "npx eslint *.js test/*.js", - "lintfix": "npx eslint --fix *.js test/*.js", - "test": "npx mocha" + "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 @msimerson/dependency-version-checker check", + "versions:fix": "npx @msimerson/dependency-version-checker update && npm run prettier:fix" }, "repository": { "type": "git", @@ -33,13 +40,13 @@ }, "homepage": "https://github.com/haraka/haraka-results#readme", "devDependencies": { - "@haraka/eslint-config": "^1.0.0", - "haraka-test-fixtures": "^1.0.0" + "@haraka/eslint-config": "^1.1.3", + "haraka-test-fixtures": "^1.3.6" }, "dependencies": { - "haraka-config": "^1.0.0" + "haraka-config": "^1.1.0" }, "optionalDependencies": { - "redis": "^4.1.0" + "redis": "^4.6.13" } } diff --git a/test/result_store.js b/test/result_store.js index 8b6a020..68044d5 100644 --- a/test/result_store.js +++ b/test/result_store.js @@ -1,196 +1,220 @@ +const assert = require('assert') -const assert = require('assert') +const redis = require('redis') -const redis = require('redis') - -const fixtures = require('haraka-test-fixtures'); -const Results = require('../index'); +const fixtures = require('haraka-test-fixtures') +const Results = require('../index') beforeEach(async function () { - this.connection = new fixtures.connection.createConnection() - this.connection.results = new Results(this.connection) + this.connection = new fixtures.connection.createConnection() + this.connection.results = new Results(this.connection) }) describe('default_result', function () { - - it('init add', async function () { - this.connection.results.add('test_plugin', { pass: 'test pass' }); - delete this.connection.results.store.test_plugin.human; - delete this.connection.results.store.test_plugin.human_html; - assert.deepEqual( - { pass: ['test pass'], fail: [], msg: [], err: [], skip: [] }, - this.connection.results.get('test_plugin') - ) - }) - - it('init add array', async function () { - this.connection.results.add('test_plugin', { pass: 1 }); - this.connection.results.add('test_plugin', { pass: [2,3] }); - delete this.connection.results.store.test_plugin.human; - delete this.connection.results.store.test_plugin.human_html; - assert.deepEqual( - { pass: [1,2,3], fail: [], msg: [], err: [], skip: [] }, - this.connection.results.get('test_plugin') - ); - }) - - it('init incr', async function () { - this.connection.results.incr('test_plugin', { counter: 1 }); - delete this.connection.results.store.test_plugin.human; - delete this.connection.results.store.test_plugin.human_html; - assert.deepEqual( - { pass: [], fail: [], msg: [], err: [], skip: [], counter: 1 }, - this.connection.results.get('test_plugin') - ); - }) - - it('init push', async function () { - this.connection.results.push('test_plugin', { pass: 'test1' }); - delete this.connection.results.store.test_plugin.human; - delete this.connection.results.store.test_plugin.human_html; - assert.deepEqual( - { pass: ['test1'], fail: [], msg: [], err: [], skip: [] }, - this.connection.results.get('test_plugin') - ); - }) - - it('init push array', async function () { - this.connection.results.push('test_plugin', { pass: 'test1' }); - this.connection.results.push('test_plugin', { pass: ['test2'] }); - delete this.connection.results.store.test_plugin.human; - delete this.connection.results.store.test_plugin.human_html; - assert.deepEqual( - { pass: ['test1','test2'], fail: [], msg: [], err: [], skip: [] }, - this.connection.results.get('test_plugin') - ); - }) - - it('init push, other', async function () { - this.connection.results.push('test_plugin', { other: 'test2' }); - delete this.connection.results.store.test_plugin.human; - delete this.connection.results.store.test_plugin.human_html; - assert.deepEqual({ - pass: [], other: ['test2'], fail: [], msg: [], - err: [], skip: [] - }, - this.connection.results.get('test_plugin') - ); - }) - + it('init add', async function () { + this.connection.results.add('test_plugin', { pass: 'test pass' }) + delete this.connection.results.store.test_plugin.human + delete this.connection.results.store.test_plugin.human_html + assert.deepEqual( + { pass: ['test pass'], fail: [], msg: [], err: [], skip: [] }, + this.connection.results.get('test_plugin'), + ) + }) + + it('init add array', async function () { + this.connection.results.add('test_plugin', { pass: 1 }) + this.connection.results.add('test_plugin', { pass: [2, 3] }) + delete this.connection.results.store.test_plugin.human + delete this.connection.results.store.test_plugin.human_html + assert.deepEqual( + { pass: [1, 2, 3], fail: [], msg: [], err: [], skip: [] }, + this.connection.results.get('test_plugin'), + ) + }) + + it('init incr', async function () { + this.connection.results.incr('test_plugin', { counter: 1 }) + delete this.connection.results.store.test_plugin.human + delete this.connection.results.store.test_plugin.human_html + assert.deepEqual( + { pass: [], fail: [], msg: [], err: [], skip: [], counter: 1 }, + this.connection.results.get('test_plugin'), + ) + }) + + it('init push', async function () { + this.connection.results.push('test_plugin', { pass: 'test1' }) + delete this.connection.results.store.test_plugin.human + delete this.connection.results.store.test_plugin.human_html + assert.deepEqual( + { pass: ['test1'], fail: [], msg: [], err: [], skip: [] }, + this.connection.results.get('test_plugin'), + ) + }) + + it('init push array', async function () { + this.connection.results.push('test_plugin', { pass: 'test1' }) + this.connection.results.push('test_plugin', { pass: ['test2'] }) + delete this.connection.results.store.test_plugin.human + delete this.connection.results.store.test_plugin.human_html + assert.deepEqual( + { pass: ['test1', 'test2'], fail: [], msg: [], err: [], skip: [] }, + this.connection.results.get('test_plugin'), + ) + }) + + it('init push, other', async function () { + this.connection.results.push('test_plugin', { other: 'test2' }) + delete this.connection.results.store.test_plugin.human + delete this.connection.results.store.test_plugin.human_html + assert.deepEqual( + { + pass: [], + other: ['test2'], + fail: [], + msg: [], + err: [], + skip: [], + }, + this.connection.results.get('test_plugin'), + ) + }) }) describe('has', () => { - it('has, list, string', async function () { - this.connection.results.add('test_plugin', { pass: 'test pass' }); - assert.equal(true, this.connection.results.has('test_plugin', 'pass', 'test pass')); - assert.equal(false, this.connection.results.has('test_plugin', 'pass', 'test miss')); - }) - - it('has, list, number', async function () { - this.connection.results.add('test_plugin', { msg: 1 }); - assert.equal(true, this.connection.results.has('test_plugin', 'msg', 1)); - assert.equal(false, this.connection.results.has('test_plugin', 'msg', 2)); - }) - - it('has, list, boolean', async function () { - this.connection.results.add('test_plugin', { msg: true }); - assert.equal(true, this.connection.results.has('test_plugin', 'msg', true)); - assert.equal(false, this.connection.results.has('test_plugin', 'msg', false)); - }) - - it('has, list, regexp', async function () { - this.connection.results.add('test_plugin', { pass: 'test pass' }); - assert.ok(this.connection.results.has('test_plugin', 'pass', /test/)); - assert.ok(this.connection.results.has('test_plugin', 'pass', / pass/)); - assert.equal(this.connection.results.has('test_plugin', 'pass', /not/), false); - }) - it('has, string, string', async function () { - this.connection.results.add('test_plugin', { random_key: 'string value' }); - assert.ok(this.connection.results.has('test_plugin', 'random_key', 'string value')); - assert.equal(false, this.connection.results.has('test_plugin', 'random_key', 'strings')); - }) - it('has, string, regex', async function () { - this.connection.results.add('test_plugin', { random_key: 'string value' }); - assert.ok(this.connection.results.has( 'test_plugin', 'random_key', /string/)); - assert.ok(this.connection.results.has( 'test_plugin', 'random_key', /value/)); - assert.equal(false, this.connection.results.has('test_plugin', 'random_key', /miss/)); - }) + it('has, list, string', async function () { + this.connection.results.add('test_plugin', { pass: 'test pass' }) + assert.equal( + true, + this.connection.results.has('test_plugin', 'pass', 'test pass'), + ) + assert.equal( + false, + this.connection.results.has('test_plugin', 'pass', 'test miss'), + ) + }) + + it('has, list, number', async function () { + this.connection.results.add('test_plugin', { msg: 1 }) + assert.equal(true, this.connection.results.has('test_plugin', 'msg', 1)) + assert.equal(false, this.connection.results.has('test_plugin', 'msg', 2)) + }) + + it('has, list, boolean', async function () { + this.connection.results.add('test_plugin', { msg: true }) + assert.equal(true, this.connection.results.has('test_plugin', 'msg', true)) + assert.equal( + false, + this.connection.results.has('test_plugin', 'msg', false), + ) + }) + + it('has, list, regexp', async function () { + this.connection.results.add('test_plugin', { pass: 'test pass' }) + assert.ok(this.connection.results.has('test_plugin', 'pass', /test/)) + assert.ok(this.connection.results.has('test_plugin', 'pass', / pass/)) + assert.equal( + this.connection.results.has('test_plugin', 'pass', /not/), + false, + ) + }) + it('has, string, string', async function () { + this.connection.results.add('test_plugin', { random_key: 'string value' }) + assert.ok( + this.connection.results.has('test_plugin', 'random_key', 'string value'), + ) + assert.equal( + false, + this.connection.results.has('test_plugin', 'random_key', 'strings'), + ) + }) + it('has, string, regex', async function () { + this.connection.results.add('test_plugin', { random_key: 'string value' }) + assert.ok( + this.connection.results.has('test_plugin', 'random_key', /string/), + ) + assert.ok(this.connection.results.has('test_plugin', 'random_key', /value/)) + assert.equal( + false, + this.connection.results.has('test_plugin', 'random_key', /miss/), + ) + }) }) describe('private_collate', () => { - it('collate, arrays are shown in output', async function () { - this.connection.results.push('test_plugin', { foo: 'bar' }); - // console.log(this.connection.results); - assert.equal(true, this.connection.results.has('test_plugin', 'foo', /bar/)); - assert.ok(/bar/.test(this.connection.results.get('test_plugin').human)); - }) + it('collate, arrays are shown in output', async function () { + this.connection.results.push('test_plugin', { foo: 'bar' }) + // console.log(this.connection.results); + assert.equal(true, this.connection.results.has('test_plugin', 'foo', /bar/)) + assert.ok(/bar/.test(this.connection.results.get('test_plugin').human)) + }) }) describe('get', () => { - beforeEach(async function () { - this.connection = new fixtures.connection.createConnection() - this.connection.results.add('test_plugin', { pass: 'foo' }) - }) - - it('has, plugin', async function () { - const cr = this.connection.results.get({ name: 'test_plugin' }); - assert.equal('foo', cr.pass[0]); - }) - - it('has, plugin name', async function () { - const cr = this.connection.results.get('test_plugin'); - assert.equal('foo', cr.pass[0]); - }) + beforeEach(async function () { + this.connection = new fixtures.connection.createConnection() + this.connection.results.add('test_plugin', { pass: 'foo' }) + }) + + it('has, plugin', async function () { + const cr = this.connection.results.get({ name: 'test_plugin' }) + assert.equal('foo', cr.pass[0]) + }) + + it('has, plugin name', async function () { + const cr = this.connection.results.get('test_plugin') + assert.equal('foo', cr.pass[0]) + }) }) describe('collate', () => { - it('string', async function () { - this.connection.results.add({name: 'pi'}, { pass: 'goob' }); - const collated = this.connection.results.collate('pi'); - assert.equal('pass:goob', collated); - }) + it('string', async function () { + this.connection.results.add({ name: 'pi' }, { pass: 'goob' }) + const collated = this.connection.results.collate('pi') + assert.equal('pass:goob', collated) + }) }) describe('resolve_plugin_name', () => { + it('string', async function () { + const name = this.connection.results.resolve_plugin_name('test_plugin') + assert.equal('test_plugin', name) + }) - it('string', async function () { - const name = this.connection.results.resolve_plugin_name('test_plugin'); - assert.equal('test_plugin', name); - }) - - it('object', async function () { - const name = this.connection.results.resolve_plugin_name({ name: 'test_plugin' }); - assert.equal('test_plugin', name); + it('object', async function () { + const name = this.connection.results.resolve_plugin_name({ + name: 'test_plugin', }) + assert.equal('test_plugin', name) + }) }) describe('redis_publish', () => { + beforeEach(async function () { + const server = { + notes: { + // this is the redis that will publish + redis: require('redis').createClient(), + }, + } + await server.notes.redis.connect() + this.connection = new fixtures.connection.createConnection(null, server) + this.connection.results = new Results(this.connection) + }) - beforeEach(async function () { - const server = { - notes: { - // this is the redis that will publish - redis: require('redis').createClient(), - } - }; - await server.notes.redis.connect() - this.connection = new fixtures.connection.createConnection(null, server); - this.connection.results = new Results(this.connection); - }) - - it('redis_publish', async function () { - const conn = this.connection; - - const sub_db = redis.createClient() + it('redis_publish', async function () { + const conn = this.connection - await sub_db.connect() + const sub_db = redis.createClient() - await sub_db.pSubscribe('*', (message, channel) => { - assert.equal(JSON.parse(message).result.pass, 'the test'); - conn.server.notes.redis.quit() - sub_db.quit() - }) + await sub_db.connect() - conn.results.add({ name: 'pi'}, { pass: 'the test'}) + await sub_db.pSubscribe('*', (message, channel) => { + assert.equal(JSON.parse(message).result.pass, 'the test') + conn.server.notes.redis.quit() + sub_db.quit() }) + + conn.results.add({ name: 'pi' }, { pass: 'the test' }) + }) })