diff --git a/config/resque.ini b/config/resque.ini index 6f7087b..31f1239 100644 --- a/config/resque.ini +++ b/config/resque.ini @@ -5,7 +5,12 @@ enabled=true # URL to send the email data to # Ex. https://example.com/captureEmail.php -url=https://example.com/captureEmail.php +url=http://localhost/test # the api key apikey=31be88ea-3412-4132-a529-07d01313391a + +[map] +# json body POST mapping +# map entire email message to eml property +message=eml diff --git a/index.js b/index.js index b1dcdc8..0e7172a 100644 --- a/index.js +++ b/index.js @@ -2,16 +2,16 @@ const axios = require('axios') function streamToString (stream) { - const chunks = []; + const chunks = [] return new Promise((resolve, reject) => { - stream.on('data', (chunk) => chunks.push(Buffer.from(chunk))); - stream.on('error', (err) => reject(err)); - stream.on('end', () => resolve(Buffer.concat(chunks).toString('utf8'))); + stream.on('data', (chunk) => chunks.push(Buffer.from(chunk))) + stream.on('error', (err) => reject(err)) + stream.on('end', () => resolve(Buffer.concat(chunks).toString('utf8'))) }) } exports.register = function () { - this.logdebug("initializing reque"); + this.logdebug("initializing resque.") this.load_resque_ini() // register hooks here. More info at https://haraka.github.io/core/Plugins/ @@ -30,7 +30,7 @@ exports.load_resque_ini = function () { }, function () { // plugin.load_example_ini() - this.logdebug("config loaded"); + plugin.logdebug("resque config loaded."); }) } @@ -38,21 +38,27 @@ exports.load_resque_ini = function () { exports.hook_queue = async function (next, connection) { const plugin = this const transaction = connection.transaction - const url = plugin.cfg.main.url - let eml = ''; + const data = { + "uuid": transaction.uuid + } try { - eml = await streamToString(transaction.message_stream) + const eml = await streamToString(transaction.message_stream) + + if (plugin.cfg.map.message) { + data[plugin.cfg.map.message] = eml + } } catch (err) { - return next(DENYSOFT, '458 – Unable to queue messages for node; ' . err); + transaction.results.add(plugin, `Error reading message_stream: '${err}'`) + + return next(DENYSOFT, `458 – Unable to queue messages for node: '${err}'`) } // https://oxylabs.io/blog/nodejs-fetch-api - const data = { - eml - } - const postData = JSON.stringify(data) + + const url = plugin.cfg.main.url + const customHeaders = { "accept": "application/json", "Content-Type": "application/json", @@ -65,18 +71,23 @@ exports.hook_queue = async function (next, connection) { } try { - const response = await axios.post(url, data, options) + transaction.loginfo(this, 'Posting message to resque.') + await axios.post(url, data, options) } catch (err) { if (err.response) { - plugin.logdebug(JSON.encode(err.response)); + transaction.logerror(plugin, `HTTP error posting message to resque: '${err.response.status}'`) + } else { + transaction.logerror(plugin, `Error posting message to resque: '${err}'`) } + transaction.results.add(this, {err}) // blackhole this message as deny - return next(DENYSOFT, '458 – Unable to queue messages for node resque'); + return next(DENYSOFT, '458 – Unable to queue messages for node resque.') } + transaction.results.add(this, { pass: 'message-queued' }) // successful POST, send next(OK) implies we blackhole this message from further processing. - return next(OK, "Your message has been resqued.") + return next(OK) } diff --git a/package.json b/package.json index 31e6224..9dd6c2b 100644 --- a/package.json +++ b/package.json @@ -27,8 +27,7 @@ }, "homepage": "https://github.com/niiknow/haraka-plugin-resque#readme", "devDependencies": { - "chai": "^5.0.0", - "eslint": "^8.55.0", + "eslint": "^8.56.0", "eslint-plugin-haraka": "*", "haraka-test-fixtures": "*", "mocha": "^10.2.0", diff --git a/test/index.js b/test/index.js index cdcbb28..2de2b9d 100644 --- a/test/index.js +++ b/test/index.js @@ -1,11 +1,13 @@ // node.js built-in modules -const assert = require('assert') +const assert = require('assert') +const { Readable } = require('stream') // npm modules const fixtures = require('haraka-test-fixtures') const nock = require('nock') const axios = require('axios') +const getRandomString = () => Math.random().toString(36).substring(4) // start of tests // assert: https://nodejs.org/api/assert.html @@ -14,53 +16,95 @@ const host = 'http://localhost'; axios.defaults.host = host; axios.defaults.baseURL = host; -beforeEach(function (done) { +beforeEach(function(done) { this.plugin = new fixtures.plugin('resque') done() // if a test hangs, assure you called done() }) -describe('resque', function () { - it('loads', function (done) { - assert.ok(this.plugin) +describe('resque', function() { + // this.timeout(10000) + let plugin, connection + + beforeEach(function() { + data = Buffer.from(getRandomString(), 'utf8') + plugin = this.plugin + plugin.register() + connection = plugin.connection = fixtures.connection.createConnection({}) + connection.transaction = fixtures.transaction.createTransaction({}) + connection.transaction.uuid = getRandomString() + connection.transaction.message_stream = Readable.from(data) + }) + + it('hook_queue message stream error', function(done) { + myStream = connection.transaction.message_stream + const expected = `458 – Unable to queue messages for node: 'OOPS'` + + plugin.hook_queue((code, msg) => { + assert.equal(expected, msg) + + // validate code is DENYSOFT + assert.equal(DENYSOFT, code) + done() + }, connection) + myStream.emit('error', 'OOPS') + myStream.emit('end') + }) + + it('hook_queue post with error', function(done) { nock(host) - .get('/test') - .reply(200, 'test data'); - - axios.get('/test').then(response => { - assert.ok(response.data == 'test data'); - // console.log(response.data); - done(); - }); - // done() + .post('/test') + .reply(422, 'test data') + + const expected = `458 – Unable to queue messages for node resque.` + + plugin.hook_queue((code, msg) => { + assert.equal(expected, msg) + + // validate code is DENYSOFT + assert.equal(DENYSOFT, code) + done() + }, connection) + }) + + it('hook_queue post with success', function(done) { + nock(host) + .post('/test') + .reply(202, 'test data') + + plugin.hook_queue((code) => { + // validate code is OK + assert.equal(OK, code) + done() + }, connection) }) }) -describe('load_resque_ini', function () { - it('loads resque.ini from config/resque.ini', function (done) { +describe('load_resque_ini', function() { + it('loads resque.ini from config/resque.ini', function(done) { this.plugin.load_resque_ini() assert.ok(this.plugin.cfg) done() }) - it('initializes enabled boolean', function (done) { + it('initializes enabled boolean', function(done) { this.plugin.load_resque_ini() assert.equal(this.plugin.cfg.main.enabled, true, this.plugin.cfg) done() }) }) -describe('uses text fixtures', function () { - it('sets up a connection', function (done) { +describe('uses test fixtures', function() { + it('sets up a connection', function(done) { this.connection = fixtures.connection.createConnection({}) assert.ok(this.connection.server) done() }) - it('sets up a transaction', function (done) { + it('sets up a transaction', function(done) { this.connection = fixtures.connection.createConnection({}) this.connection.transaction = fixtures.transaction.createTransaction({}) - // console.log(this.connection.transaction) + //console.log(this.connection.transaction) assert.ok(this.connection.transaction.header) done() }) -}) \ No newline at end of file +})