mirror of
https://github.com/zero-peak/ZeroOmega.git
synced 2025-01-23 07:18:13 -05:00
175 lines
5.4 KiB
CoffeeScript
175 lines
5.4 KiB
CoffeeScript
chai = require 'chai'
|
|
should = chai.should()
|
|
sinon = require 'sinon'
|
|
chai.use require('sinon-chai')
|
|
|
|
describe 'OptionsSync', ->
|
|
OptionsSync = require '../src/options_sync'
|
|
Storage = require '../src/storage'
|
|
Log = require '../src/log'
|
|
|
|
before ->
|
|
# Silence storage and sync logging.
|
|
sinon.stub(Log, 'log')
|
|
|
|
after ->
|
|
Log.log.restore()
|
|
|
|
# coffeelint: disable=missing_fat_arrows
|
|
hookPostBasic = (func, hook) -> ->
|
|
result = func.apply(this, arguments)
|
|
hook.apply(this, arguments)
|
|
return result
|
|
# coffeelint: enable=missing_fat_arrows
|
|
|
|
hookPost = (args...) ->
|
|
if args.length == 2
|
|
[func, hook] = args
|
|
hostPostBasic(func, hook)
|
|
else
|
|
[obj, method, hook] = args
|
|
obj[method] = hookPostBasic(obj[method], hook)
|
|
|
|
describe '#merge', ->
|
|
sync = new OptionsSync()
|
|
it 'should choose the one with newer revision', ->
|
|
newVal = {revision: '2'}
|
|
oldVal = {revision: '1'}
|
|
sync.merge('example', newVal, oldVal).should.equal(newVal)
|
|
it 'should favor oldVal when revisions are equal', ->
|
|
newVal = {revision: '1', is: 'newVal'}
|
|
oldVal = {revision: '1', is: 'oldVal'}
|
|
sync.merge('example', newVal, oldVal).should.equal(oldVal)
|
|
it 'should favor oldVal when newVal deeply equals oldVal', ->
|
|
newVal = {they: 'are', the: 'same'}
|
|
oldVal = {they: 'are', the: 'same'}
|
|
sync.merge('example', newVal, oldVal).should.equal(oldVal)
|
|
it 'should choose newVal when newVal is different', ->
|
|
newVal = {they: 'are', not: 'equal'}
|
|
oldVal = {they: 'are', not: 'identical'}
|
|
sync.merge('example', newVal, oldVal).should.equal(newVal)
|
|
|
|
describe '#requestPush', ->
|
|
unlimited = new OptionsSync.TokenBucket()
|
|
|
|
it 'should store pendingChanges', ->
|
|
sync = new OptionsSync()
|
|
sync.enabled = false
|
|
sync.requestPush({a: 1})
|
|
sync.pendingChanges().should.eql({a: 1})
|
|
it 'should schedule storage write', (done) ->
|
|
check = ->
|
|
return if storage.set.callCount == 0 or storage.remove.callCount == 0
|
|
storage.set.should.have.been.calledOnce.and.calledWith({b: 1})
|
|
storage.remove.should.have.been.calledOnce.and.calledWith(['a'])
|
|
done()
|
|
|
|
storage = new Storage()
|
|
storage.set({a: 1})
|
|
hookPost storage, 'set', check
|
|
hookPost storage, 'remove', check
|
|
|
|
sinon.spy(storage, 'set')
|
|
sinon.spy(storage, 'remove')
|
|
|
|
sync = new OptionsSync(storage, unlimited)
|
|
sync.debounce = 0
|
|
sync.requestPush({a: undefined, b: 1})
|
|
|
|
it 'should combine multiple write operations', (done) ->
|
|
check = ->
|
|
return if storage.set.callCount == 0 or storage.remove.callCount == 0
|
|
storage.set.should.have.been.calledOnce.and.calledWith({c: 1, d: 1})
|
|
storage.remove.should.have.been.calledOnce.and.calledWith(['a', 'b'])
|
|
done()
|
|
|
|
storage = new Storage()
|
|
storage.set({a: 1, b: 1})
|
|
hookPost storage, 'set', check
|
|
hookPost storage, 'remove', check
|
|
|
|
sinon.spy(storage, 'set')
|
|
sinon.spy(storage, 'remove')
|
|
|
|
sync = new OptionsSync(storage, unlimited)
|
|
sync.debounce = 0
|
|
sync.requestPush({a: undefined})
|
|
sync.requestPush({b: 2})
|
|
sync.requestPush({b: undefined})
|
|
sync.requestPush({c: 1})
|
|
sync.requestPush({d: 1})
|
|
sync.requestPush({e: 1})
|
|
sync.requestPush({e: undefined})
|
|
|
|
describe '#copyTo', ->
|
|
it 'should fetch all items from remote storage', (done) ->
|
|
remote = new Storage()
|
|
remote.set({a: 1, b: 2, c: 3})
|
|
|
|
storage = new Storage()
|
|
hookPost storage, 'set', ->
|
|
storage.set.should.have.been.calledOnce.and.calledWith(
|
|
{a: 1, b: 2, c: 3}
|
|
)
|
|
done()
|
|
|
|
sinon.spy(storage, 'set')
|
|
|
|
sync = new OptionsSync(remote)
|
|
sync.copyTo(storage)
|
|
|
|
it 'should merge with local as base', (done) ->
|
|
check = ->
|
|
return if storage.set.callCount == 0 or storage.remove.callCount == 0
|
|
storage.set.should.have.been.calledOnce.and.calledWith({b: 2, c: 3})
|
|
storage.remove.should.have.been.calledOnce.and.calledWith(['d'])
|
|
done()
|
|
|
|
remote = new Storage()
|
|
remote.set({a: 1, b: 2, c: 3, d: undefined})
|
|
|
|
storage = new Storage()
|
|
storage.set({a: 1, b: 0, d: 4})
|
|
|
|
hookPost storage, 'set', check
|
|
hookPost storage, 'remove', check
|
|
|
|
sinon.spy(storage, 'set')
|
|
sinon.spy(storage, 'remove')
|
|
|
|
sync = new OptionsSync(remote)
|
|
sync.copyTo(storage)
|
|
|
|
describe '#watchAndPull', ->
|
|
it 'should pull changes into local when remote changes', (done) ->
|
|
check = ->
|
|
return if storage.set.callCount == 0 or storage.remove.callCount == 0
|
|
remote.watch.should.have.been.calledOnce
|
|
storage.set.should.have.been.calledOnce.and.calledWith({b: 2, c: 3})
|
|
storage.remove.should.have.been.calledOnce.and.calledWith(['d'])
|
|
done()
|
|
|
|
remote = new Storage()
|
|
hookPost remote, 'watch', (_, callback) ->
|
|
setTimeout (->
|
|
callback({a: 1})
|
|
callback({b: 2})
|
|
callback({c: 3})
|
|
callback({d: undefined})
|
|
), 10
|
|
|
|
sinon.spy(remote, 'watch')
|
|
|
|
storage = new Storage()
|
|
storage.set({a: 1, b: 0, d: 4})
|
|
|
|
hookPost storage, 'set', check
|
|
hookPost storage, 'remove', check
|
|
|
|
sinon.spy(storage, 'set')
|
|
sinon.spy(storage, 'remove')
|
|
|
|
sync = new OptionsSync(remote)
|
|
sync.pullThrottle = 0
|
|
sync.watchAndPull(storage)
|