From 42e0d1ca7bc4076315f028a7fa546271203c57a9 Mon Sep 17 00:00:00 2001 From: nioc Date: Sun, 20 Oct 2019 03:01:59 +0200 Subject: [PATCH] Add XMPP test --- .eslintrc.json | 3 +- package-lock.json | 126 ++++++++++++++++++++++++++++++++++++++++++++++ package.json | 4 +- test/config.json | 2 +- test/xmpp.js | 126 ++++++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 258 insertions(+), 3 deletions(-) create mode 100644 test/xmpp.js diff --git a/.eslintrc.json b/.eslintrc.json index 0f297fc..3d9a2d0 100644 --- a/.eslintrc.json +++ b/.eslintrc.json @@ -2,7 +2,8 @@ "env": { "commonjs": true, "es6": true, - "node": true + "node": true, + "mocha": true }, "extends": [ "standard" diff --git a/package-lock.json b/package-lock.json index 4b74f26..718b061 100644 --- a/package-lock.json +++ b/package-lock.json @@ -127,6 +127,42 @@ "to-fast-properties": "^2.0.0" } }, + "@sinonjs/commons": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-1.6.0.tgz", + "integrity": "sha512-w4/WHG7C4WWFyE5geCieFJF6MZkbW4VAriol5KlmQXpAQdxvV0p26sqNZOW6Qyw6Y0l9K4g+cHvvczR2sEEpqg==", + "dev": true, + "requires": { + "type-detect": "4.0.8" + } + }, + "@sinonjs/formatio": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/@sinonjs/formatio/-/formatio-3.2.2.tgz", + "integrity": "sha512-B8SEsgd8gArBLMD6zpRw3juQ2FVSsmdd7qlevyDqzS9WTCtvF55/gAL+h6gue8ZvPYcdiPdvueM/qm//9XzyTQ==", + "dev": true, + "requires": { + "@sinonjs/commons": "^1", + "@sinonjs/samsam": "^3.1.0" + } + }, + "@sinonjs/samsam": { + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/@sinonjs/samsam/-/samsam-3.3.3.tgz", + "integrity": "sha512-bKCMKZvWIjYD0BLGnNrxVuw4dkWCYsLqFOUWw8VgKF/+5Y+mE7LfHWPIYoDXowH+3a9LsWDMo0uAP8YDosPvHQ==", + "dev": true, + "requires": { + "@sinonjs/commons": "^1.3.0", + "array-from": "^2.1.1", + "lodash": "^4.17.15" + } + }, + "@sinonjs/text-encoding": { + "version": "0.7.1", + "resolved": "https://registry.npmjs.org/@sinonjs/text-encoding/-/text-encoding-0.7.1.tgz", + "integrity": "sha512-+iTbntw2IZPb/anVDbypzfQa+ay64MW0Zo8aJ8gZPWMMK6/OubMVb6lUPMagqjOPnmtauXnFCACVl3O7ogjeqQ==", + "dev": true + }, "@xmpp/jid": { "version": "0.0.2", "resolved": "https://registry.npmjs.org/@xmpp/jid/-/jid-0.0.2.tgz", @@ -293,6 +329,12 @@ "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz", "integrity": "sha1-ml9pkFGx5wczKPKgCJaLZOopVdI=" }, + "array-from": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/array-from/-/array-from-2.1.1.tgz", + "integrity": "sha1-z+nYwmYoudxa7MYqn12PHzUsEZU=", + "dev": true + }, "array-includes": { "version": "3.0.3", "resolved": "https://registry.npmjs.org/array-includes/-/array-includes-3.0.3.tgz", @@ -3316,6 +3358,12 @@ "verror": "1.10.0" } }, + "just-extend": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/just-extend/-/just-extend-4.0.2.tgz", + "integrity": "sha512-FrLwOgm+iXrPV+5zDU6Jqu4gCRXbWEQg2O3SKONsWE4w7AXFRkryS53bpWdaL9cNol+AmR3AEYz6kn+o0fCPnw==", + "dev": true + }, "kind-of": { "version": "6.0.2", "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.2.tgz", @@ -3415,6 +3463,12 @@ } } }, + "lolex": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/lolex/-/lolex-4.2.0.tgz", + "integrity": "sha512-gKO5uExCXvSm6zbF562EvM+rd1kQDnB9AZBbiQVzf1ZmdDpxUSvpnAaVOP83N/31mRK8Ml8/VE8DMvsAZQ+7wg==", + "dev": true + }, "lowercase-keys": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-1.0.1.tgz", @@ -3730,6 +3784,33 @@ } } }, + "mock-require": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/mock-require/-/mock-require-3.0.3.tgz", + "integrity": "sha512-lLzfLHcyc10MKQnNUCv7dMcoY/2Qxd6wJfbqCcVk3LDb8An4hF6ohk5AztrvgKhJCqj36uyzi/p5se+tvyD+Wg==", + "dev": true, + "requires": { + "get-caller-file": "^1.0.2", + "normalize-path": "^2.1.1" + }, + "dependencies": { + "get-caller-file": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-1.0.3.tgz", + "integrity": "sha512-3t6rVToeoZfYSGd8YoLFR2DJkiQrIiUrGcjvFX2mDw3bn6k2OtwHN0TNCLbBO+w8qTvimhDkv+LSscbJY1vE6w==", + "dev": true + }, + "normalize-path": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-2.1.1.tgz", + "integrity": "sha1-GrKLVW4Zg2Oowab35vogE3/mrtk=", + "dev": true, + "requires": { + "remove-trailing-separator": "^1.0.1" + } + } + } + }, "morgan": { "version": "1.9.1", "resolved": "https://registry.npmjs.org/morgan/-/morgan-1.9.1.tgz", @@ -3808,6 +3889,36 @@ "integrity": "sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ==", "dev": true }, + "nise": { + "version": "1.5.2", + "resolved": "https://registry.npmjs.org/nise/-/nise-1.5.2.tgz", + "integrity": "sha512-/6RhOUlicRCbE9s+94qCUsyE+pKlVJ5AhIv+jEE7ESKwnbXqulKZ1FYU+XAtHHWE9TinYvAxDUJAb912PwPoWA==", + "dev": true, + "requires": { + "@sinonjs/formatio": "^3.2.1", + "@sinonjs/text-encoding": "^0.7.1", + "just-extend": "^4.0.2", + "lolex": "^4.1.0", + "path-to-regexp": "^1.7.0" + }, + "dependencies": { + "isarray": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", + "integrity": "sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8=", + "dev": true + }, + "path-to-regexp": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-1.7.0.tgz", + "integrity": "sha1-Wf3g9DW62suhA6hOnTvGTpa5k30=", + "dev": true, + "requires": { + "isarray": "0.0.1" + } + } + } + }, "node-cleanup": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/node-cleanup/-/node-cleanup-2.1.2.tgz", @@ -4885,6 +4996,21 @@ "qbox": "0.1.x" } }, + "sinon": { + "version": "7.5.0", + "resolved": "https://registry.npmjs.org/sinon/-/sinon-7.5.0.tgz", + "integrity": "sha512-AoD0oJWerp0/rY9czP/D6hDTTUYGpObhZjMpd7Cl/A6+j0xBE+ayL/ldfggkBXUs0IkvIiM1ljM8+WkOc5k78Q==", + "dev": true, + "requires": { + "@sinonjs/commons": "^1.4.0", + "@sinonjs/formatio": "^3.2.1", + "@sinonjs/samsam": "^3.3.3", + "diff": "^3.5.0", + "lolex": "^4.2.0", + "nise": "^1.5.2", + "supports-color": "^5.5.0" + } + }, "slice-ansi": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-2.1.0.tgz", diff --git a/package.json b/package.json index eda1e32..dd4b84f 100644 --- a/package.json +++ b/package.json @@ -37,7 +37,9 @@ "eslint-plugin-promise": "^4.2.1", "eslint-plugin-standard": "^4.0.1", "mocha": "^6.2.1", + "mock-require": "^3.0.3", "nodemon": "^1.19.3", - "nyc": "^14.1.1" + "nyc": "^14.1.1", + "sinon": "^7.5.0" } } diff --git a/test/config.json b/test/config.json index a24dac3..29987d7 100644 --- a/test/config.json +++ b/test/config.json @@ -1,6 +1,6 @@ { "logger": { - "level": "debug", + "level": "error", "file": { "active": true, "pattern": "%d %p %m", diff --git a/test/xmpp.js b/test/xmpp.js new file mode 100644 index 0000000..7c264ac --- /dev/null +++ b/test/xmpp.js @@ -0,0 +1,126 @@ +process.env.NODE_ENV = 'production' + +const should = require('chai').should() +const sinon = require('sinon') +const EventEmitter = require('events').EventEmitter +const mock = require('mock-require') + +// create default logger +let logger = require('./../lib/logger')() + +// get configuration +let config = require('./../lib/config')(logger, './test/config.json') + +// update logger with configuration +logger.updateConfig(config.logger) + +// mock simple-xmpp module +const simpleXmppEvents = new EventEmitter() +let xmppJoinStub = sinon.stub() +mock('simple-xmpp', { + connect: () => {}, + join: xmppJoinStub, + on: (eventName, callback) => { + simpleXmppEvents.on(eventName, callback) + }, + getRoster: () => {} +}) + +// mock outgoing +let outgoingStub = sinon.stub() +mock('./../lib/outgoing', outgoingStub) + +describe('XMPP component', () => { + beforeEach('Reset outgoing stub history', function () { + outgoingStub.resetHistory() + }) + + describe('Connect to XMPP server', () => { + it('Should connect to XMPP server and join rooms when application start', (done) => { + require('./../lib/xmpp')(logger, config) + simpleXmppEvents.emit('online', { jid: { user: 'bot' } }) + sinon.assert.called(xmppJoinStub) + let roomsLength = config.xmpp.rooms.length + sinon.assert.callCount(xmppJoinStub, roomsLength) + for (let index = 0; index < roomsLength; index++) { + const args = xmppJoinStub.args[index] + args.should.have.length(2) + args[0].should.equal(config.xmpp.rooms[index].id + '/' + 'bot') + if (config.xmpp.rooms[index].password === null) { + should.equal(args[1], null) + } else { + args[1].should.equal(config.xmpp.rooms[index].password) + } + } + done() + }) + }) + + describe('Bot receive a message from someone', () => { + it('Should trigger outgoing webhook with valid arguments', (done) => { + simpleXmppEvents.emit('chat', 'someone', 'This is the message text') + sinon.assert.calledOnce(outgoingStub) + const args = outgoingStub.args[0] + args.should.have.length(8) + args[3].should.equal('someone') + args[4].should.equal('someone') + args[5].should.equal('This is the message text') + args[6].should.equal(false) + args[7].should.equal('w1') + done() + }) + }) + + describe('Bot receive a message from himself in a room', () => { + it('Should not trigger outgoing webhook', (done) => { + simpleXmppEvents.emit('groupchat', 'roomname@conference.domain-xmpp.ltd', 'bot', 'This is the message text', null) + sinon.assert.notCalled(outgoingStub) + done() + }) + }) + + describe('Bot receive a message in an unknown room', () => { + it('Should not trigger outgoing webhook', (done) => { + simpleXmppEvents.emit('groupchat', 'unknownroomname@conference.domain-xmpp.ltd', 'someone', 'This is the message text', null) + sinon.assert.notCalled(outgoingStub) + done() + }) + }) + + describe('Bot receive an old message in a room', () => { + it('Should not trigger outgoing webhook', (done) => { + simpleXmppEvents.emit('groupchat', 'roomname@conference.domain-xmpp.ltd', 'someone', 'This is the message text', 'stamp') + sinon.assert.notCalled(outgoingStub) + done() + }) + }) + + describe('Bot receive a message in a room', () => { + it('Should trigger outgoing webhook with valid arguments', (done) => { + simpleXmppEvents.emit('groupchat', 'roomname@conference.domain-xmpp.ltd', 'someone', 'This is the message text', null) + sinon.assert.calledOnce(outgoingStub) + const args = outgoingStub.args[0] + args.should.have.length(8) + args[3].should.equal('someone') + args[4].should.equal('roomname@conference.domain-xmpp.ltd') + args[5].should.equal('This is the message text') + args[6].should.equal(true) + args[7].should.equal('w1') + done() + }) + }) + + describe('XMPP server send an error', () => { + it('Should log error only', (done) => { + let error = 'This the error text' + simpleXmppEvents.emit('error', error) + require('fs').readFile(config.logger.file.path + config.logger.file.filename, 'utf8', (err, data) => { + if (err) { + throw err + } + data.should.match(new RegExp(error + '\n$')) + done() + }) + }) + }) +})