UNPKG

makedrive

Version:
255 lines (209 loc) 9.3 kB
var expect = require('chai').expect; var util = require('../lib/util.js'); var Filer = require('../../lib/filer.js'); var conflict = require('../../lib/conflict.js'); var fsUtils = require('../../lib/fs-utils.js'); describe('MakeDrive Client - conflicted copy integration', function(){ var client1; var client2; var layout = {'/dir1/file1': 'data'}; // Modify both clients' filesystems, changing the same file but with // different changes, and assert that changes and unsynced attrib is set. function modifyClients(callback) { function modify(fs, data, callback) { fs.appendFile('/dir1/file1', data, function(err) { if(err) throw err; util.ensureFilesystem(fs, {'/dir1/file1': 'data' + data}, function(err) { if(err) throw err; fsUtils.isPathUnsynced(fs, '/dir1/file1', function(err, hasAttr) { if(err) throw err; expect(hasAttr).to.be.true; callback(); }); }); }); } modify(client1.fs, '+1', function(err) { if(err) throw err; modify(client2.fs, '+2', callback); }); } // Find a conflicted copy in set of 2 filenames by process of elimination. function findConflictedFilename(entries) { entries.splice(entries.indexOf('file1'), 1); return Filer.Path.join('/dir1', entries[0]); } // Create 2 sync clients, do downstream syncs, then dirty both filesystems beforeEach(function(done) { util.ready(function() { var username = util.username(); util.setupSyncClient({username: username, layout: layout, manual: true}, function(err, client) { if(err) throw err; client1 = client; util.setupSyncClient({username: username, manual: true}, function(err, client) { if(err) throw err; client2 = client; // Make sure the initial downstream sync produced the same layout as client1 util.ensureFilesystem(client2.fs, layout, function(err) { if(err) throw err; modifyClients(done); }); }); }); }); }); // Cleanly shut down both clients afterEach(function(done) { client1.sync.once('disconnected', function() { client1 = null; client2.sync.once('disconnected', function() { client2 = null; done(); }); client2.sync.disconnect(); }); client1.sync.disconnect(); }); /** * This test creates 2 simultaneous clients for the same user, and simulates * a situation where a conflicted copy should be made. It then makes sure that * this conflicted copy is created, and that it is not synced back to the server. */ it('should handle conflicted copy in downstream and upstream syncs', function(done) { client2.sync.once('completed', function() { // Make sure we have a confliced copy now + the new file. client2.fs.readdir('/dir1', function(err, entries) { if(err) throw err; expect(entries.length).to.equal(2); expect(entries).to.include('file1'); // Make sure this is a real conflicted copy, both in name // and also in terms of attributes on the file. var conflictedCopyFilename = findConflictedFilename(entries); expect(conflict.filenameContainsConflicted(conflictedCopyFilename)).to.be.true; conflict.isConflictedCopy(client2.fs, conflictedCopyFilename, function(err, conflicted) { if(err) throw err; expect(conflicted).to.be.true; // Make sure the conflicted copy has the changes we expect client2.fs.readFile(conflictedCopyFilename, 'utf8', function(err, data) { if(err) throw err; // Should have client2's modifications expect(data).to.equal('data+2'); // Now change the filesystem, sync back to the server, and make sure the // conflicted copy isn't synced to the server. client2.fs.writeFile('/dir1/file2', 'contents of file2', function(err) { if(err) throw err; client2.sync.once('completed', function() { // Our server's filesystem should now look like this: var newLayout = { // NOTE: /dir1/file1 should have client1's changes, not client2's, // which are in the conflicted copy instead. Also, the conflicted // copy we have locally with client2 shouldn't be on the server at all. '/dir1/file1': 'data+1', '/dir1/file2': 'contents of file2' }; util.ensureRemoteFilesystem(newLayout, client2.jar, function(err) { expect(err).not.to.exist; done(); }); }); client2.sync.request(); }); }); }); }); }); // Sync client1's change to server client1.sync.request(); }); /** * This test also causes a conflicted copy to be made, renames it, which should * clear the conflict, then does a sync back to the server, checking that it synced. */ it('should handle a rename to a conflicted copy in downstream and upstream syncs', function(done) { // Wait for client1 changes to sync to server client1.sync.once('completed', function() { client2.sync.once('completed', function() { // Make sure we have a confliced copy now + the new file. client2.fs.readdir('/dir1', function(err, entries) { if(err) throw err; expect(entries.length).to.equal(2); expect(entries).to.include('file1'); // Make sure this is a real conflicted copy, both in name // and also in terms of attributes on the file. var conflictedCopyFilename = findConflictedFilename(entries); expect(conflict.filenameContainsConflicted(conflictedCopyFilename)).to.be.true; conflict.isConflictedCopy(client2.fs, conflictedCopyFilename, function(err, conflicted) { if(err) throw err; expect(conflicted).to.be.true; // Make sure the conflicted copy has the changes we expect client2.fs.readFile(conflictedCopyFilename, 'utf8', function(err, data) { if(err) throw err; // Should have client2's modifications expect(data).to.equal('data+2'); // Rename the conflicted file and re-sync with server, making // sure that the file gets sent this time. client2.fs.rename(conflictedCopyFilename, '/dir1/resolved', function(err) { if(err) throw err; // Make sure the rename removed the conflict conflict.isConflictedCopy(client2.fs, '/dir1/resolved', function(err, conflicted) { if(err) throw err; expect(conflicted).to.be.false; client2.sync.once('completed', function() { // Our server's filesystem should now look like this: var newLayout = { // NOTE: /dir1/resolved should have client2's changes, not client1's. '/dir1/file1': 'data+1', '/dir1/resolved': 'data+2' }; util.ensureRemoteFilesystem(newLayout, client2.jar, function(err) { expect(err).not.to.exist; done(); }); }); client2.sync.request(); }); }); }); }); }); }); }); // Sync client1's change to server client1.sync.request(); }); it('should not fail a sync if the path modified is a conflicted copy', function(done) { var layout1 = {'/dir1/file1': layout['/dir1/file1'] + '+1'}; var layout2 = {'/dir1/file1': layout1['/dir1/file1']}; client1.sync.once('completed', function() { client2.sync.once('completed', function() { client2.fs.readdir('/dir1', function(err, entries) { if(err) throw err; expect(entries.length).to.equal(2); expect(entries).to.include('file1'); // Make sure this is a real conflicted copy, both in name // and also in terms of attributes on the file. var conflictedCopyFilename = findConflictedFilename(entries); expect(conflict.filenameContainsConflicted(conflictedCopyFilename)).to.be.true; // Add the conflicted copy to the layout layout2[conflictedCopyFilename] = 'Changed Data'; client2.fs.writeFile(conflictedCopyFilename, layout2[conflictedCopyFilename], function(err) { if(err) throw err; client2.sync.once('completed', function() { util.ensureFilesystem(client2.fs, layout2, function(err) { expect(err).not.to.exist; }); }); client1.sync.once('completed', function() { util.ensureFilesystem(client1.fs, layout1, function(err) { expect(err).not.to.exist; done(); }); }); client2.sync.request(); }); }); }); }); client1.sync.request(); }); });