diff --git a/platform/persistence/queue/test/PersistenceQueueImplSpec.js b/platform/persistence/queue/test/PersistenceQueueImplSpec.js index cf78221caa..8bc4687ea5 100644 --- a/platform/persistence/queue/test/PersistenceQueueImplSpec.js +++ b/platform/persistence/queue/test/PersistenceQueueImplSpec.js @@ -6,8 +6,128 @@ define( function (PersistenceQueueImpl) { "use strict"; - describe("The implemented persistence queue", function () { + var TEST_DELAY = 42; + describe("The implemented persistence queue", function () { + var mockQ, + mockTimeout, + mockHandler, + mockDeferred, + mockPromise, + queue; + + function makeMockDomainObject(id) { + var mockDomainObject = jasmine.createSpyObj( + 'domainObject-' + id, + [ 'getId' ] + ); + mockDomainObject.getId.andReturn(id); + return mockDomainObject; + } + + function makeMockPersistence(id) { + var mockPersistence = jasmine.createSpyObj( + 'persistence-' + id, + [ 'persist' ] + ); + return mockPersistence; + } + + beforeEach(function () { + mockQ = jasmine.createSpyObj('$q', ['when', 'defer']); + mockTimeout = jasmine.createSpy('$timeout'); + mockHandler = jasmine.createSpyObj('handler', ['persist']); + mockDeferred = jasmine.createSpyObj('deferred', ['resolve']); + mockDeferred.promise = jasmine.createSpyObj('promise', ['then']); + mockPromise = jasmine.createSpyObj('promise', ['then']); + mockQ.defer.andReturn(mockDeferred); + mockTimeout.andReturn({}); + mockHandler.persist.andReturn(mockPromise); + mockPromise.then.andReturn(mockPromise); + queue = new PersistenceQueueImpl( + mockQ, + mockTimeout, + mockHandler, + TEST_DELAY + ); + }); + + it("schedules a timeout to persist objects", function () { + expect(mockTimeout).not.toHaveBeenCalled(); + queue.put(makeMockDomainObject('a'), makeMockPersistence('a')); + expect(mockTimeout).toHaveBeenCalledWith( + jasmine.any(Function), + TEST_DELAY, + false + ); + }); + + it("does not schedule multiple timeouts for multiple objects", function () { + // Put three objects in without triggering the timeout; + // shouldn't schedule multiple timeouts + queue.put(makeMockDomainObject('a'), makeMockPersistence('a')); + queue.put(makeMockDomainObject('b'), makeMockPersistence('b')); + queue.put(makeMockDomainObject('c'), makeMockPersistence('c')); + expect(mockTimeout.calls.length).toEqual(1); + }); + + it("returns a promise", function () { + expect(queue.put(makeMockDomainObject('a'), makeMockPersistence('a'))) + .toEqual(mockDeferred.promise); + }); + + it("waits for quiescence to proceed", function () { + // Keep adding objects to the queue between timeouts. + // Should keep scheduling timeouts instead of resolving. + queue.put(makeMockDomainObject('a'), makeMockPersistence('a')); + expect(mockTimeout.calls.length).toEqual(1); + mockTimeout.mostRecentCall.args[0](); + queue.put(makeMockDomainObject('b'), makeMockPersistence('b')); + expect(mockTimeout.calls.length).toEqual(2); + mockTimeout.mostRecentCall.args[0](); + queue.put(makeMockDomainObject('c'), makeMockPersistence('c')); + expect(mockTimeout.calls.length).toEqual(3); + mockTimeout.mostRecentCall.args[0](); + expect(mockHandler.persist).not.toHaveBeenCalled(); + }); + + it("persists upon quiescence", function () { + // Add objects to the queue, but fire two timeouts afterward + queue.put(makeMockDomainObject('a'), makeMockPersistence('a')); + queue.put(makeMockDomainObject('b'), makeMockPersistence('b')); + queue.put(makeMockDomainObject('c'), makeMockPersistence('c')); + mockTimeout.mostRecentCall.args[0](); + mockTimeout.mostRecentCall.args[0](); + expect(mockHandler.persist).toHaveBeenCalled(); + }); + + it("waits on an active flush, while flushing", function () { + // Persist some objects + queue.put(makeMockDomainObject('a'), makeMockPersistence('a')); + queue.put(makeMockDomainObject('b'), makeMockPersistence('b')); + mockTimeout.mostRecentCall.args[0](); + mockTimeout.mostRecentCall.args[0](); + expect(mockTimeout.calls.length).toEqual(2); + // Adding a new object should not trigger a new timeout, + // because we haven't completed the previous flush + queue.put(makeMockDomainObject('c'), makeMockPersistence('c')); + expect(mockTimeout.calls.length).toEqual(2); + }); + + it("clears the active flush after it has completed", function () { + // Persist some objects + queue.put(makeMockDomainObject('a'), makeMockPersistence('a')); + queue.put(makeMockDomainObject('b'), makeMockPersistence('b')); + mockTimeout.mostRecentCall.args[0](); + mockTimeout.mostRecentCall.args[0](); + expect(mockTimeout.calls.length).toEqual(2); + // Resolve the promise from handler.persist + mockPromise.then.calls[0].args[0](true); + // Adding a new object should now trigger a new timeout, + // because we have completed the previous flush + queue.put(makeMockDomainObject('c'), makeMockPersistence('c')); + expect(mockTimeout.calls.length).toEqual(3); + }); }); } ); \ No newline at end of file