mirror of
https://github.com/Foundry376/Mailspring.git
synced 2024-11-11 18:32:20 +08:00
9d995ded67
Summary: Move sync workers and Edgehill token checks to work window Move the task queue and database setup to the work window Move ContactStore background refresh to work window Store the task queue in the database WIP The TaskQueue now puts tasks in the database instead of in a file, which also means it can be observed Move all delta sync and initial sync to a package, make NylasSyncStore which exposes read-only sync state DraftStore no longer reads task status. Once you set the "sending" bit on a draft, it never gets unset. But that's fine actually. If your package lists windowTypes, you *only* get loaded in those windowTypes. If you specify no windowTypes, you get loaded in the root window. This means that onboarding, worker-ui, worker-sync, etc. no longer get loaded into the main window ActivitySidebar has a special little store that observes the task queue since it's no longer in the window Move "toggle component regions" / "toggle react remote" to the Developer menu Move sync worker specs, update draft store specs to not rely on TaskQueue at all Test Plan: Run existing tests, all pass Reviewers: dillon, evan Reviewed By: evan Differential Revision: https://phab.nylas.com/D1936
140 lines
5.7 KiB
CoffeeScript
140 lines
5.7 KiB
CoffeeScript
_ = require 'underscore'
|
|
fs = require 'fs'
|
|
path = require 'path'
|
|
{NylasAPI, Thread, DatabaseStore, Actions} = require 'nylas-exports'
|
|
NylasSyncWorkerPool = require '../lib/nylas-sync-worker-pool'
|
|
|
|
fixturesPath = path.resolve(__dirname, 'fixtures')
|
|
|
|
describe "NylasSyncWorkerPool", ->
|
|
|
|
describe "handleDeltas", ->
|
|
beforeEach ->
|
|
@sampleDeltas = JSON.parse(fs.readFileSync("#{fixturesPath}/sample.json"))
|
|
@sampleClustered = JSON.parse(fs.readFileSync("#{fixturesPath}/sample-clustered.json"))
|
|
|
|
it "should immediately fire the received raw deltas event", ->
|
|
spyOn(Actions, 'longPollReceivedRawDeltas')
|
|
spyOn(NylasSyncWorkerPool, '_clusterDeltas').andReturn({create: {}, modify: {}, destroy: []})
|
|
NylasSyncWorkerPool._handleDeltas(@sampleDeltas)
|
|
expect(Actions.longPollReceivedRawDeltas).toHaveBeenCalled()
|
|
|
|
it "should call helper methods for all creates first, then modifications, then destroys", ->
|
|
spyOn(Actions, 'longPollProcessedDeltas')
|
|
|
|
handleDeltaDeletionPromises = []
|
|
resolveDeltaDeletionPromises = ->
|
|
fn() for fn in handleDeltaDeletionPromises
|
|
handleDeltaDeletionPromises = []
|
|
|
|
spyOn(NylasSyncWorkerPool, '_handleDeltaDeletion').andCallFake ->
|
|
new Promise (resolve, reject) ->
|
|
handleDeltaDeletionPromises.push(resolve)
|
|
|
|
handleModelResponsePromises = []
|
|
resolveModelResponsePromises = ->
|
|
fn() for fn in handleModelResponsePromises
|
|
handleModelResponsePromises = []
|
|
|
|
spyOn(NylasAPI, '_handleModelResponse').andCallFake ->
|
|
new Promise (resolve, reject) ->
|
|
handleModelResponsePromises.push(resolve)
|
|
|
|
spyOn(NylasSyncWorkerPool, '_clusterDeltas').andReturn(JSON.parse(JSON.stringify(@sampleClustered)))
|
|
NylasSyncWorkerPool._handleDeltas(@sampleDeltas)
|
|
|
|
createTypes = Object.keys(@sampleClustered['create'])
|
|
expect(NylasAPI._handleModelResponse.calls.length).toEqual(createTypes.length)
|
|
expect(NylasAPI._handleModelResponse.calls[0].args[0]).toEqual(_.values(@sampleClustered['create'][createTypes[0]]))
|
|
expect(NylasSyncWorkerPool._handleDeltaDeletion.calls.length).toEqual(0)
|
|
|
|
NylasAPI._handleModelResponse.reset()
|
|
resolveModelResponsePromises()
|
|
advanceClock()
|
|
|
|
modifyTypes = Object.keys(@sampleClustered['modify'])
|
|
expect(NylasAPI._handleModelResponse.calls.length).toEqual(modifyTypes.length)
|
|
expect(NylasAPI._handleModelResponse.calls[0].args[0]).toEqual(_.values(@sampleClustered['modify'][modifyTypes[0]]))
|
|
expect(NylasSyncWorkerPool._handleDeltaDeletion.calls.length).toEqual(0)
|
|
|
|
NylasAPI._handleModelResponse.reset()
|
|
resolveModelResponsePromises()
|
|
advanceClock()
|
|
|
|
destroyCount = @sampleClustered['destroy'].length
|
|
expect(NylasSyncWorkerPool._handleDeltaDeletion.calls.length).toEqual(destroyCount)
|
|
expect(NylasSyncWorkerPool._handleDeltaDeletion.calls[0].args[0]).toEqual(@sampleClustered['destroy'][0])
|
|
|
|
expect(Actions.longPollProcessedDeltas).not.toHaveBeenCalled()
|
|
|
|
resolveDeltaDeletionPromises()
|
|
advanceClock()
|
|
|
|
expect(Actions.longPollProcessedDeltas).toHaveBeenCalled()
|
|
|
|
describe "clusterDeltas", ->
|
|
beforeEach ->
|
|
@sampleDeltas = JSON.parse(fs.readFileSync("#{fixturesPath}/sample.json"))
|
|
@expectedClustered = JSON.parse(fs.readFileSync("#{fixturesPath}/sample-clustered.json"))
|
|
|
|
it "should collect create/modify events into a hash by model type", ->
|
|
{create, modify} = NylasSyncWorkerPool._clusterDeltas(@sampleDeltas)
|
|
expect(create).toEqual(@expectedClustered.create)
|
|
expect(modify).toEqual(@expectedClustered.modify)
|
|
|
|
it "should collect destroys into an array", ->
|
|
{destroy} = NylasSyncWorkerPool._clusterDeltas(@sampleDeltas)
|
|
expect(destroy).toEqual(@expectedClustered.destroy)
|
|
|
|
describe "handleDeltaDeletion", ->
|
|
beforeEach ->
|
|
@thread = new Thread(id: 'idhere')
|
|
@delta =
|
|
"cursor": "bb95ddzqtr2gpmvgrng73t6ih",
|
|
"object": "thread",
|
|
"event": "delete",
|
|
"id": @thread.id,
|
|
"timestamp": "2015-08-26T17:36:45.297Z"
|
|
|
|
it "should resolve if the object cannot be found", ->
|
|
spyOn(DatabaseStore, 'find').andCallFake (klass, id) =>
|
|
return Promise.resolve(null)
|
|
spyOn(DatabaseStore, 'unpersistModel')
|
|
waitsForPromise =>
|
|
NylasSyncWorkerPool._handleDeltaDeletion(@delta)
|
|
runs =>
|
|
expect(DatabaseStore.find).toHaveBeenCalledWith(Thread, 'idhere')
|
|
expect(DatabaseStore.unpersistModel).not.toHaveBeenCalled()
|
|
|
|
it "should call unpersistModel if the object exists", ->
|
|
spyOn(DatabaseStore, 'find').andCallFake (klass, id) =>
|
|
return Promise.resolve(@thread)
|
|
spyOn(DatabaseStore, 'unpersistModel')
|
|
waitsForPromise =>
|
|
NylasSyncWorkerPool._handleDeltaDeletion(@delta)
|
|
runs =>
|
|
expect(DatabaseStore.find).toHaveBeenCalledWith(Thread, 'idhere')
|
|
expect(DatabaseStore.unpersistModel).toHaveBeenCalledWith(@thread)
|
|
|
|
# These specs are on hold because this function is changing very soon
|
|
|
|
xdescribe "handleModelResponse", ->
|
|
it "should reject if no JSON is provided", ->
|
|
it "should resolve if an empty JSON array is provided", ->
|
|
|
|
describe "if JSON contains the same object more than once", ->
|
|
it "should warn", ->
|
|
it "should omit duplicates", ->
|
|
|
|
describe "if JSON contains objects which are of unknown types", ->
|
|
it "should warn and resolve", ->
|
|
|
|
describe "when the object type is `thread`", ->
|
|
it "should check that models are acceptable", ->
|
|
|
|
describe "when the object type is `draft`", ->
|
|
it "should check that models are acceptable", ->
|
|
|
|
it "should call persistModels to save all of the received objects", ->
|
|
|
|
it "should resolve with the objects", ->
|