mirror of https://github.com/status-im/codimd.git
refactor(realtime): add test case for clean dangling user
Signed-off-by: BoHong Li <a60814billy@gmail.com>
This commit is contained in:
parent
d8b18ee241
commit
ab37a33e0b
|
@ -24,6 +24,7 @@ const ot = require('./ot')
|
|||
const { ProcessQueue } = require('./processQueue')
|
||||
const { RealtimeClientConnection } = require('./realtimeClientConnection')
|
||||
const { UpdateDirtyNoteJob } = require('./realtimeUpdateDirtyNoteJob')
|
||||
const { CleanDanglingUserJob } = require('./realtimeCleanDanglingUserJob')
|
||||
|
||||
// public
|
||||
const realtime = {
|
||||
|
@ -164,29 +165,8 @@ function finishUpdateNote (note, _note, callback) {
|
|||
})
|
||||
}
|
||||
|
||||
// clean when user not in any rooms or user not in connected list
|
||||
setInterval(function () {
|
||||
async.each(Object.keys(users), function (key, callback) {
|
||||
var socket = realtime.io.sockets.connected[key]
|
||||
if ((!socket && users[key]) ||
|
||||
(socket && (!socket.rooms || socket.rooms.length <= 0))) {
|
||||
if (config.debug) {
|
||||
logger.info('cleaner found redundant user: ' + key)
|
||||
}
|
||||
if (!socket) {
|
||||
socket = {
|
||||
id: key
|
||||
}
|
||||
}
|
||||
if (!disconnectProcessQueue.checkTaskIsInQueue(socket.id)) {
|
||||
exports.queueForDisconnect(socket)
|
||||
}
|
||||
}
|
||||
return callback(null, null)
|
||||
}, function (err) {
|
||||
if (err) return logger.error('cleaner error', err)
|
||||
})
|
||||
}, 60000)
|
||||
const cleanDanglingUserJob = new CleanDanglingUserJob(realtime)
|
||||
cleanDanglingUserJob.start()
|
||||
|
||||
var saverSleep = false
|
||||
// save note revision in interval
|
||||
|
|
|
@ -0,0 +1,49 @@
|
|||
'use strict'
|
||||
|
||||
const async = require('async')
|
||||
const config = require('./config')
|
||||
const logger = require('./logger')
|
||||
|
||||
/**
|
||||
* clean when user not in any rooms or user not in connected list
|
||||
*/
|
||||
class CleanDanglingUserJob {
|
||||
constructor (realtime) {
|
||||
this.realtime = realtime
|
||||
}
|
||||
|
||||
start () {
|
||||
if (this.timer) return
|
||||
this.timer = setInterval(this.cleanDanglingUser.bind(this), 60000)
|
||||
}
|
||||
|
||||
stop () {
|
||||
if (!this.timer) return
|
||||
clearInterval(this.timer)
|
||||
this.timer = undefined
|
||||
}
|
||||
|
||||
cleanDanglingUser () {
|
||||
const users = this.realtime.getUserPool()
|
||||
async.each(Object.keys(users), (key, callback) => {
|
||||
const socket = this.realtime.io.sockets.connected[key]
|
||||
if ((!socket && users[key]) ||
|
||||
(socket && (!socket.rooms || socket.rooms.length <= 0))) {
|
||||
if (config.debug) {
|
||||
logger.info('cleaner found redundant user: ' + key)
|
||||
}
|
||||
if (!socket) {
|
||||
return callback(null, null)
|
||||
}
|
||||
if (!this.realtime.disconnectProcessQueue.checkTaskIsInQueue(socket.id)) {
|
||||
this.realtime.queueForDisconnect(socket)
|
||||
}
|
||||
}
|
||||
return callback(null, null)
|
||||
}, function (err) {
|
||||
if (err) return logger.error('cleaner error', err)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
exports.CleanDanglingUserJob = CleanDanglingUserJob
|
|
@ -0,0 +1,68 @@
|
|||
/* eslint-env node, mocha */
|
||||
'use strict'
|
||||
|
||||
const assert = require('assert')
|
||||
const mock = require('mock-require')
|
||||
const sinon = require('sinon')
|
||||
const {removeModuleFromRequireCache, makeMockSocket} = require('./utils')
|
||||
|
||||
describe('cleanDanglingUser', function () {
|
||||
let clock
|
||||
beforeEach(() => {
|
||||
clock = sinon.useFakeTimers()
|
||||
mock('../../lib/processQueue', require('../testDoubles/ProcessQueueFake'))
|
||||
mock('../../lib/logger', {
|
||||
error: () => {},
|
||||
info: () => {}
|
||||
})
|
||||
mock('../../lib/history', {})
|
||||
mock('../../lib/models', {
|
||||
Revision: {
|
||||
saveAllNotesRevision: () => {
|
||||
}
|
||||
}
|
||||
})
|
||||
mock('../../lib/config', {
|
||||
debug: true
|
||||
})
|
||||
mock('../../lib/realtimeUpdateDirtyNoteJob', require('../testDoubles/realtimeUpdateDirtyNoteJobStub'))
|
||||
})
|
||||
|
||||
afterEach(() => {
|
||||
clock.restore()
|
||||
removeModuleFromRequireCache('../../lib/realtime')
|
||||
mock.stopAll()
|
||||
sinon.restore()
|
||||
})
|
||||
|
||||
it('should ', (done) => {
|
||||
const realtime = require('../../lib/realtime')
|
||||
const queueForDisconnectSpy = sinon.spy(realtime, 'queueForDisconnect')
|
||||
realtime.io = {
|
||||
to: sinon.stub().callsFake(function () {
|
||||
return {
|
||||
emit: sinon.fake()
|
||||
}
|
||||
}),
|
||||
sockets: {
|
||||
connected: {}
|
||||
}
|
||||
}
|
||||
let user1Socket = makeMockSocket()
|
||||
let user2Socket = makeMockSocket()
|
||||
|
||||
user1Socket.rooms.push('room1')
|
||||
|
||||
realtime.io.sockets.connected[user1Socket.id] = user1Socket
|
||||
realtime.io.sockets.connected[user2Socket.id] = user2Socket
|
||||
|
||||
realtime.users[user1Socket.id] = user1Socket
|
||||
realtime.users[user2Socket.id] = user2Socket
|
||||
clock.tick(60000)
|
||||
clock.restore()
|
||||
setTimeout(() => {
|
||||
assert(queueForDisconnectSpy.called)
|
||||
done()
|
||||
}, 50)
|
||||
})
|
||||
})
|
|
@ -66,7 +66,6 @@ describe('realtime#update note is dirty timer', function () {
|
|||
realtime.notes['note2'] = note2
|
||||
|
||||
clock.tick(1000)
|
||||
|
||||
setTimeout(() => {
|
||||
assert(note2.server.isDirty === false)
|
||||
done()
|
||||
|
@ -126,5 +125,4 @@ describe('realtime#update note is dirty timer', function () {
|
|||
done()
|
||||
}, 50)
|
||||
})
|
||||
|
||||
})
|
||||
|
|
|
@ -24,7 +24,8 @@ function makeMockSocket (headers, query) {
|
|||
return broadCastChannelCache[channel]
|
||||
}
|
||||
},
|
||||
disconnect: sinon.fake()
|
||||
disconnect: sinon.fake(),
|
||||
rooms: []
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,35 @@
|
|||
'use strict'
|
||||
|
||||
class ProcessQueueFake {
|
||||
constructor () {
|
||||
this.taskMap = new Map()
|
||||
this.queue = []
|
||||
}
|
||||
|
||||
start () {
|
||||
|
||||
}
|
||||
|
||||
stop () {
|
||||
|
||||
}
|
||||
|
||||
checkTaskIsInQueue (id) {
|
||||
return this.taskMap.has(id)
|
||||
}
|
||||
|
||||
push (id, processFunc) {
|
||||
this.queue.push({
|
||||
id: id,
|
||||
processFunc: processFunc
|
||||
})
|
||||
this.taskMap.set(id, true)
|
||||
}
|
||||
|
||||
process () {
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
exports.ProcessQueueFake = ProcessQueueFake
|
||||
exports.ProcessQueue = ProcessQueueFake
|
|
@ -0,0 +1,12 @@
|
|||
'use strict'
|
||||
|
||||
class UpdateDirtyNoteJobStub {
|
||||
start() {
|
||||
}
|
||||
|
||||
stop() {
|
||||
}
|
||||
}
|
||||
|
||||
exports.UpdateDirtyNoteJobStub = UpdateDirtyNoteJobStub
|
||||
exports.UpdateDirtyNoteJob = UpdateDirtyNoteJobStub
|
Loading…
Reference in New Issue