nubot-connect-mongo
Version:
Robot brain storage handler for MongoDB
235 lines (219 loc) • 7.4 kB
JavaScript
const chai = require('chai')
const testCollection = 'brain-testing'
process.env.BRAIN_COLLECTION = testCollection
const mongoose = require('mongoose')
chai.use(require('chai-subset'))
chai.use(require('sinon-chai'))
const should = chai.should()
const connectMongo = require('../lib')
const config = require('../lib/config')
const model = require('../lib/model')
const MockRobot = require('./mocks/robot')
const delay = (ms) => new Promise((resolve, reject) => setTimeout(resolve, ms))
let robot, connection, testPrivateData, testCollectionData
// TODO: update tests to use promise returns instead of manual delay, when
// brain is extended instead of listened to
describe('Connect Mongo', () => {
beforeEach(() => {
robot = new MockRobot()
testPrivateData = {
doors: [{ 'door 1': 'dead end' }, { 'door 2': 'win a prize' }],
favorites: [{ username: 'tim' }, { username: 'jento' }]
}
testCollectionData = [
{
key: 'doors',
type: '_private',
value: testPrivateData.doors
}, {
key: 'favorites',
type: '_private',
value: testPrivateData.favorites
}
]
})
afterEach(() => {
try {
connection.close() // close any created connections
} catch (err) {}
})
describe('constructor', () => {
it('returns a Mongoose connection', async () => {
connection = await connectMongo(robot)
connection.should.have.property('db')
})
it('resolves when connected', (done) => {
connectMongo(robot)
.then(() => done())
.catch((err) => {
throw err
})
})
})
describe('.save', () => {
beforeEach(async () => {
await mongoose.connect(config.url, config.connection)
await connectMongo(robot)
})
afterEach(() => {
// model.collection.drop().catch(() => null)
})
it('brain.save() stores in MongoDB', async () => {
robot.brain.data._private = Object.assign({ }, testPrivateData)
console.log(`private = ${JSON.stringify(robot.brain.data._private)}`)
robot.brain.save()
await delay(300)
})
it('brain.save() only updates modified', async () => {
robot.brain.data._private.doors.push({ 'door 3': 'you fall down' })
console.log(`private = ${JSON.stringify(robot.brain.data._private)}`)
await delay(300)
robot.brain.save()
let results = await model.find({ }).lean().exec()
let difference = results[0].updatedAt - results[1].updatedAt
console.log(`cunt - ${JSON.stringify(results)}`)
console.log(`ZZZ- ${JSON.stringify(results[0])}\nZZZ- ${JSON.stringify(results[1])}`)
difference.should.be.gt(100)
})
})
describe('.get', () => {
beforeEach(async () => {
await mongoose.connect(config.url, config.connection)
await model.create(...testCollectionData)
})
afterEach(() => {
model.collection.drop().catch(() => null)
})
it('brain has data from DB', async () => {
await connectMongo(robot)
robot.brain.get('doors').should.eql(testPrivateData.doors)
})
// TODO: Reinstate test when nubot brain.mergeData is recursive
// it('brain merged DB data with existing', async () => {
// robot.brain.data._private['doors'] = [{ 'door 3': 'you fall down' }]
// await connectMongo(robot)
// testPrivateData.doors.push({ 'door 3': 'you fall down' })
// robot.brain.get('doors').should.eql(testPrivateData.doors)
// })
})
describe('.set', () => {
afterEach(() => {
model.collection.drop().catch(() => null)
})
it('should set data in MongoDB', async () => {
await connectMongo(robot)
let testKey = 'test_key'
let testValue = 'test_value'
robot.brain.set(testKey, testValue)
robot.brain.save()
await delay(100)
let search = { key: testKey }
let results = await model.findOne(search).lean().exec()
results.should.containSubset({ 'value': testValue })
})
})
describe('.store', () => {
beforeEach(async () => {
await mongoose.connect(config.url, config.connection)
await connectMongo(robot)
})
afterEach(() => {
model.collection.drop().catch(() => null)
})
it('creates collection and value array if none exists', async () => {
let testKey = 'test_key'
let testValue = 'test_value'
robot.brain.store(testKey, testValue)
await delay(100)
let results = await model.findOne({
key: testKey,
type: '_stored'
}).lean().exec()
results.should.containSubset({
key: testKey,
type: '_stored',
value: [ testValue ]
})
})
it('pushes to end of array if collection exists', async () => {
let testKey = 'test_key'
let testValue = 'test_value'
await model.create({
key: testKey,
type: '_stored',
value: [ 'one', 'two' ]
})
robot.brain.store(testKey, testValue)
await delay(200)
let results = await model.findOne({
key: testKey,
type: '_stored'
}).lean().exec()
results.should.containSubset({
key: testKey,
type: '_stored',
value: [ 'one', 'two', testValue ]
})
})
})
describe('.retrieve', () => {
beforeEach(async () => {
await mongoose.connect(config.url, config.connection)
await connectMongo(robot)
})
it('returns null if nothing', async () => {
let result = await robot.brain.retrieve('test_key')
should.not.exist(result)
})
it('returns value from existing collection', async () => {
let testKey = 'test_key'
let testValue = [ 'one', 'two' ]
await model.create({
key: testKey,
type: '_stored',
value: testValue
})
let result = await robot.brain.retrieve(testKey)
result.should.eql(testValue)
})
})
describe('.find', () => {
beforeEach(async () => {
await mongoose.connect(config.url, config.connection)
await connectMongo(robot)
})
it('returns null if nothing', async () => {
let result = await robot.brain.find('test_key', { test: 'test' })
should.not.exist(result)
})
it('returns matching subset from existing collection', async () => {
let testKey = 'test_key'
let testValue = [{ foo: 'bar' }, { baz: 'qux' }]
await model.create({
key: testKey,
type: '_stored',
value: testValue
})
let result = await robot.brain.find(testKey, testValue[0])
result.should.eql(testValue[0])
})
it('returns full elemenent on partial match', async () => {
let testKey = 'test_key'
let testValue = [{ test: 'test', foo: 'bar', baz: 'qux' }]
await model.create({
key: testKey,
type: '_stored',
value: testValue
})
let result = await robot.brain.find(testKey, { test: 'test' })
result.should.eql(testValue[0])
})
})
describe('robot.close', () => {
it('closes DB connection', (done) => {
robot.brain.on('close', () => done())
robot.brain.emit('close')
})
})
})