diff --git a/core/sync/index.js b/core/sync/index.js index 8592323a8..979e79008 100644 --- a/core/sync/index.js +++ b/core/sync/index.js @@ -464,13 +464,15 @@ class Sync { return new Promise((resolve, reject) => { let feedObserver + let onWillStop const done = (result, err) => { if (feedObserver) feedObserver.cancel() - this.lifecycle.off('will-stop', done) + if (onWillStop) this.lifecycle.off('will-stop', onWillStop) if (err) reject(err) else resolve(result) } - this.lifecycle.once('will-stop', () => done(false)) + onWillStop = () => done(false) + this.lifecycle.once('will-stop', onWillStop) feedObserver = this.pouch.db .changes(opts) diff --git a/test/integration/add.js b/test/integration/add.js index 222ac1660..f69aeeb9d 100644 --- a/test/integration/add.js +++ b/test/integration/add.js @@ -323,7 +323,7 @@ describe('Add', () => { }) context('and the directory is updated after its content is added', () => { - it('creates the directory and its content on the remote Cozy without errors', async () => { + it('creates the directory and its content on the remote Cozy without errors', async function() { // Create directory and its content const dir = await createDoc('local', 'dir', parent) const subdir = await createDoc('local', 'subdir', dir) diff --git a/test/integration/differential_sync.js b/test/integration/differential_sync.js index ea26d77cd..c2c7ba552 100644 --- a/test/integration/differential_sync.js +++ b/test/integration/differential_sync.js @@ -182,16 +182,15 @@ describe('Differential synchronization', () => { // `Photos/My Image.png` too many times and ends up recreating its // missing parent (i.e. `Photos/`), thus triggering an uncaught // `ExcludedDir` error. - const localScanDone = async () => { - await new Promise(resolve => { - helpers.local.side.events.on('local-end', resolve) + const waitForLocalEnd = () => + new Promise(resolve => { + helpers.local.side.events.once('local-end', resolve) }) - } await helpers.local.side.start() - await localScanDone() + const localChangesDone = waitForLocalEnd() await helpers.local.syncDir.ensureDir('Photos') await helpers.local.syncDir.ensureFile('Photos/My Image.png') - await localScanDone() + await localChangesDone await helpers.syncAll() should(await helpers.local.treeWithoutTrash()).deepEqual([ diff --git a/test/integration/move.js b/test/integration/move.js index af5532a2b..f317cbce8 100644 --- a/test/integration/move.js +++ b/test/integration/move.js @@ -7,6 +7,7 @@ const _ = require('lodash') const should = require('should') const { TRASH_DIR_ID } = require('../../core/remote/constants') +const { MAX_SYNC_RETRIES } = require('../../core/sync') const { logger } = require('../../core/utils/logger') const Builders = require('../support/builders') const dbBuilders = require('../support/builders/db') @@ -1158,6 +1159,19 @@ describe('Move', () => { await helpers.local.syncDir.move('dir', 'renamed') await helpers.local.scan() } + const exhaustMissingDocumentRetries = async dirPath => { + const docs = [ + await helpers.docByPath(dirPath), + ...(await pouch.byRecursivePath(dirPath)) + ] + + await pouch.bulkDocs( + docs.map(doc => ({ + ...doc, + errors: MAX_SYNC_RETRIES - 1 + })) + ) + } context('overwritting existing remote directory', () => { let existing, overwritten @@ -1218,10 +1232,11 @@ describe('Move', () => { await helpers.remote.ignorePreviousChanges() }) - // We should be retrying a few times and then finally skip the change to - // avoid looping over it. + // Start from exhausted retries to validate the recovery without waiting + // for every auto-retry in this integration test. it('ends up replacing the overwritten file', async () => { await moveDir() + await exhaustMissingDocumentRetries('renamed') await helpers.syncAll() should(await helpers.trees()).deepEqual({ @@ -1260,10 +1275,11 @@ describe('Move', () => { await helpers.remote.ignorePreviousChanges() }) - // We should be retrying a few times and then finally skip the change to - // avoid looping over it. + // Start from exhausted retries to validate the recovery without waiting + // for every auto-retry in this integration test. it('ends up re-uploading the file at the destination', async () => { await moveDir() + await exhaustMissingDocumentRetries('renamed') await helpers.syncAll() should(await helpers.trees()).deepEqual({ diff --git a/test/unit/sync/index.js b/test/unit/sync/index.js index b75cb34f7..506903cef 100644 --- a/test/unit/sync/index.js +++ b/test/unit/sync/index.js @@ -76,6 +76,19 @@ describe('Sync', function() { builders = new Builders(this) }) + describe('hasChangesToSync', () => { + it('removes its stop listener once it resolves', async function() { + await builders + .metafile() + .path('file') + .sides({ local: 1 }) + .create() + + should(await this.sync.hasChangesToSync()).be.true() + should(this.sync.lifecycle.listenerCount('will-stop')).eql(0) + }) + }) + describe('start', function() { beforeEach('instanciate sync', function() { const events = new EventEmitter()