Commit 91a84412 authored by Tristan Cavelier's avatar Tristan Cavelier

Update ConflictManagerStorage and Jio tests

parent 36e09bbc
......@@ -30,90 +30,79 @@ var newConflictManagerStorage = function ( spec, my ) {
var cloned_option = command.cloneOption ();
cloned_option.metadata_only = false;
cloned_option.max_retry = command.getOption('max_retry') || 3;
cloned_option.error = error;
cloned_option.success = success;
var newcommand = that.newCommand(
'loadDocument',{path:path,
option:cloned_option});
that.addJob ( that.newStorage (priv.secondstorage_spec),
newcommand );
that.addJob ('get',priv.secondstorage_spec,path,cloned_option,
success, error);
};
priv.saveMetadataToDistant = function (command,path,content,success,error) {
var cloned_option = command.cloneOption ();
cloned_option.error = error;
cloned_option.success = success;
var newcommand = that.newCommand(
'saveDocument',{path:path,
content:JSON.stringify (content),
option:cloned_option});
// newcommand.setMaxRetry (0); // inf
that.addJob ( that.newStorage (priv.secondstorage_spec),
newcommand );
// max_retry:0 // inf
that.addJob ('put',priv.secondstorage_spec,
{_id:path,content:JSON.stringify (content)},
command.cloneOption(),success,error);
};
priv.saveNewRevision = function (command,path,content,success,error) {
var cloned_option = command.cloneOption ();
cloned_option.error = error;
cloned_option.success = success;
var newcommand = that.newCommand(
'saveDocument',{path:path,
content:content,
option:cloned_option});
that.addJob ( that.newStorage (priv.secondstorage_spec),
newcommand );
that.addJob ('put',priv.secondstorage_spec,{_id:path,content:content},
command.cloneOption(),success,error);
};
priv.loadRevision = function (command,path,success,error) {
var cloned_option = command.cloneOption ();
cloned_option.error = error;
cloned_option.success = success;
var newcommand = that.newCommand (
'loadDocument',{path:path,
option:cloned_option});
that.addJob ( that.newStorage (priv.secondstorage_spec),
newcommand );
that.addJob('get',priv.secondstorage_spec,path,command.cloneOption(),
success, error);
};
priv.deleteAFile = function (command,path,success,error) {
var cloned_option = command.cloneOption();
cloned_option.max_retry = 0; // inf
cloned_option.error = error;
cloned_option.success = success;
var newcommand = that.newCommand(
'removeDocument',{path:path,
option:cloned_option});
that.addJob ( that.newStorage (priv.secondstorage_spec),
newcommand );
that.addJob ('remove',priv.secondstorage_spec,{_id:path},
command.cloneOption(), success, error);
};
priv.chooseARevision = function (metadata) {
var tmp_last_modified = 0, ret_rev = '';
for (var rev in metadata) {
var tmp_last_modified = 0, ret_rev = '', rev;
for (rev in metadata) {
if (tmp_last_modified <
metadata[rev].last_modified) {
metadata[rev]._last_modified) {
tmp_last_modified =
metadata[rev].last_modified;
metadata[rev]._last_modified;
ret_rev = rev;
}
}
return ret_rev;
};
priv.solveConflict = function (path,content,option) {
priv._revs = function (metadata,revision) {
if (metadata[revision]) {
return {start:metadata[revision]._revisions.length,
ids:metadata[revision]._revisions};
} else {
return null;
}
};
priv._revs_info = function (metadata) {
var k, l = [];
for (k in metadata) {
l.push({
rev:k,status:(metadata[k]?(
metadata[k]._deleted?'deleted':'available'):'missing')
});
}
return l;
};
priv.solveConflict = function (doc,option,param) {
var o = {}, am = priv.newAsyncModule(),
command = option.command,
metadata_file_path = path + '.metadata',
command = param.command,
metadata_file_path = param.docid + '.metadata',
current_revision = '',
current_revision_file_path = '',
metadata_file_content = null,
on_conflict = false, conflict_object = {},
on_remove = option.deleted,
previous_revision = option.previous_revision,
previous_revision_object = option.revision_remove_object || {},
previous_revision_content_object = previous_revision_object[
previous_revision] || {},
on_conflict = false, conflict_object = {total_rows:0,rows:[]},
on_remove = param._deleted,
previous_revision = param.previous_revision,
previous_revision_content_object = null,
now = new Date(),
failerror;
......@@ -126,11 +115,13 @@ var newConflictManagerStorage = function ( spec, my ) {
metadata_file_content = JSON.parse (result.content);
// set current revision
current_revision = (previous_revision_number + 1) + '-' +
hex_sha256 ('' + content +
hex_sha256 ('' + doc.content +
previous_revision +
JSON.stringify (metadata_file_content));
current_revision_file_path = path + '.' +
current_revision_file_path = param.docid + '.' +
current_revision;
previous_revision_content_object = metadata_file_content[
previous_revision] || {};
if (!on_remove) {
am.wait(o,'saveMetadataOnDistant',1);
am.call(o,'saveNewRevision');
......@@ -143,7 +134,7 @@ var newConflictManagerStorage = function ( spec, my ) {
};
o.saveNewRevision = function (){
priv.saveNewRevision (
command, current_revision_file_path, content,
command, current_revision_file_path, doc.content,
function (result) {
am.call(o,'saveMetadataOnDistant');
}, function (error) {
......@@ -152,18 +143,20 @@ var newConflictManagerStorage = function ( spec, my ) {
);
};
o.previousUpdateMetadata = function () {
for (var prev_rev in previous_revision_object) {
delete metadata_file_content[prev_rev];
var i;
for (i = 0; i < param.key.length; i+= 1) {
delete metadata_file_content[param.key[i]];
}
am.call(o,'checkForConflicts');
};
o.checkForConflicts = function () {
for (var rev in metadata_file_content) {
var rev;
for (rev in metadata_file_content) {
var revision_index;
on_conflict = true;
failerror = {
status:20,
statusText:'Conflict',
status:409,error:'conflict',
statusText:'Conflict',reason:'document update conflict',
message:'There is one or more conflicts'
};
break;
......@@ -171,22 +164,29 @@ var newConflictManagerStorage = function ( spec, my ) {
am.call(o,'updateMetadata');
};
o.updateMetadata = function (){
var revision_history, id = '';
id = current_revision.split('-'); id.shift(); id = id.join('-');
revision_history = previous_revision_content_object._revisions;
revision_history.unshift(id);
metadata_file_content[current_revision] = {
creation_date: previous_revision_content_object.creation_date ||
_creation_date:previous_revision_content_object._creation_date||
now.getTime(),
last_modified: now.getTime(),
conflict: on_conflict,
deleted: on_remove
_last_modified: now.getTime(),
_revisions: revision_history,
_conflict: on_conflict,
_deleted: on_remove
};
if (on_conflict) {
conflict_object =
priv.createConflictObject(
command, metadata_file_content, current_revision
);
}
am.call(o,'saveMetadataOnDistant');
};
o.saveMetadataOnDistant = function (){
priv.saveMetadataToDistant(
command, metadata_file_path,metadata_file_content,
command, metadata_file_path, metadata_file_content,
function (result) {
am.call(o,'deleteAllConflictingRevision');
if (on_conflict) {
......@@ -200,58 +200,115 @@ var newConflictManagerStorage = function ( spec, my ) {
);
};
o.deleteAllConflictingRevision = function (){
for (var prev_rev in previous_revision_object) {
var i;
for (i = 0; i < param.key.length; i+= 1) {
priv.deleteAFile (
command, path+'.'+prev_rev, empty_fun, empty_fun );
command, param.docid+'.'+param.key[i], empty_fun,empty_fun);
}
};
o.success = function (){
var a = {ok:true,id:param.docid,rev:current_revision};
am.neverCall(o,'error');
am.neverCall(o,'success');
if (option.success) {option.success({revision:current_revision});}
if (option.revs) {
a.revisions = priv._revs(metadata_file_content,
current_revision);
}
if (option.revs_info) {
a.revs_info = priv._revs_info(metadata_file_content);
}
if (option.conflicts) {
a.conflicts = conflict_object;
}
param.success(a);
};
o.error = function (error){
var gooderror = error || failerror || {};
if (on_conflict) {
gooderror.conflict_object = conflict_object;
var err = error || failerror ||
{status:0,statusText:'Unknown',error:'unknown_error',
message:'Unknown error.',reason:'unknown error'};
if (current_revision) {
err.rev = current_revision;
}
if (option.revs) {
err.revisions = priv._revs(metadata_file_content,
current_revision);
}
if (option.revs_info) {
err.revs_info = priv._revs_info(metadata_file_content);
}
if (option.conflicts) {
err.conflicts = conflict_object;
}
am.neverCall(o,'error');
am.neverCall(o,'success');
if (option.error) {option.error(gooderror);}
param.error(err);
};
am.call(o,'getDistantMetadata');
};
priv.createConflictObject = function (command, metadata, revision) {
var cloned_command = command.clone();
var conflict_object = {
path: command.getPath(),
revision: revision,
revision_object: metadata,
getConflictRevisionList: function () {
return this.revision_object;
},
solveConflict: function (content,option) {
if (typeof content === 'undefined') {
option = option || {};
option.deleted = true;
} else if (typeof content === 'object') {
option = content;
option.deleted = true;
return {
total_rows:1,
rows:[priv.createConflictRow(command,command.getDocId(),
metadata,revision)]
};
};
priv.getParam = function (list) {
var param = {}, i = 0;
if (typeof list[i] === 'string') {
param.content = list[i];
i ++;
}
if (typeof list[i] === 'object') {
param.options = list[i];
i ++;
} else {
option = option || {};
option.deleted = false;
content = content || '';
param.options = {};
}
option.previous_revision = this.revision;
option.revision_remove_object = this.revision_object;
option.command = cloned_command;
param.callback = function (err,val){};
param.success = function (val) {
param.callback(undefined,val);
};
param.error = function (err) {
param.callback(err,undefined);
};
if (typeof list[i] === 'function') {
if (typeof list[i+1] === 'function') {
param.success = list[i];
param.error = list[i+1];
} else {
param.callback = list[i];
}
}
return param;
};
priv.createConflictRow = function (command, docid, metadata, revision) {
var row = {id:docid,key:[],value:{
_solveConflict: function (/*content, option, success, error*/) {
var param = {}, got = priv.getParam(arguments);
if (got.content === undefined) {
param._deleted = true;
} else {
param._deleted = false;
}
param.success = got.success;
param.error = got.error;
param.previous_revision = revision;
param.docid = docid;
param.key = row.key;
param.command = command.clone();
return priv.solveConflict (
this.path, content, option
{_id:docid,content:got.content,_rev:revision},
got.options,param
);
}
};
return conflict_object;
}}, k;
for (k in metadata) {
row.key.push(k);
}
return row;
};
priv.newAsyncModule = function () {
......@@ -282,31 +339,28 @@ var newConflictManagerStorage = function ( spec, my ) {
return async;
};
that.post = function (command) {
that.put (command);
};
/**
* Save a document and can manage conflicts.
* @method saveDocument
* @method put
*/
that.saveDocument = function (command) {
that.put = function (command) {
var o = {}, am = priv.newAsyncModule(),
metadata_file_path = command.getPath() + '.metadata',
metadata_file_path = command.getDocId() + '.metadata',
current_revision = '',
current_revision_file_path = '',
metadata_file_content = null,
on_conflict = false, conflict_object = {},
previous_revision = command.getOption('previous_revision'),
previous_revision_file_path = command.getPath() + '.' +
on_conflict = false, conflict_object = {total_rows:0,rows:[]},
previous_revision = command.getDocInfo('_rev') || '0',
previous_revision_file_path = command.getDocId() + '.' +
previous_revision,
now = new Date(),
failerror;
if (!previous_revision) {
return setTimeout(function () {
that.error({status:0,statusText:'Parameter missing',
message:'Need a previous revision.'});
});
}
o.getDistantMetadata = function (){
priv.getDistantMetadata (
command,metadata_file_path,
......@@ -316,10 +370,10 @@ var newConflictManagerStorage = function ( spec, my ) {
metadata_file_content = JSON.parse (result.content);
// set current revision
current_revision = (previous_revision_number + 1) + '-' +
hex_sha256 ('' + command.getContent() +
hex_sha256 ('' + command.getDocContent() +
previous_revision +
JSON.stringify (metadata_file_content));
current_revision_file_path = command.getPath() + '.' +
current_revision_file_path = command.getDocId() + '.' +
current_revision;
am.wait(o,'saveMetadataOnDistant',1);
am.call(o,'saveNewRevision');
......@@ -327,8 +381,8 @@ var newConflictManagerStorage = function ( spec, my ) {
},function (error) {
if (error.status === 404) {
current_revision = '1-' +
hex_sha256 (command.getContent());
current_revision_file_path = command.getPath() + '.' +
hex_sha256 (command.getDocContent());
current_revision_file_path = command.getDocId() + '.' +
current_revision;
am.wait(o,'saveMetadataOnDistant',1);
am.call(o,'saveNewRevision');
......@@ -341,7 +395,7 @@ var newConflictManagerStorage = function ( spec, my ) {
};
o.saveNewRevision = function (){
priv.saveNewRevision (
command,current_revision_file_path,command.getContent(),
command,current_revision_file_path,command.getDocContent(),
function (result) {
am.call(o,'saveMetadataOnDistant');
}, function (error) {
......@@ -350,13 +404,14 @@ var newConflictManagerStorage = function ( spec, my ) {
);
};
o.checkForConflicts = function () {
for (var rev in metadata_file_content) {
var rev;
for (rev in metadata_file_content) {
if (rev !== previous_revision) {
on_conflict = true;
failerror = {
status:20,
statusText:'Conflict',
message:'There is one or more conflicts'
status:409,error:'conflict',
statusText:'Conflict',reason:'document update conflict',
message:'Document update conflict.'
};
break;
}
......@@ -364,41 +419,47 @@ var newConflictManagerStorage = function ( spec, my ) {
am.call(o,'updateMetadata');
};
o.createMetadata = function (){
var id = current_revision;
id = id.split('-'); id.shift(); id = id.join('-');
metadata_file_content = {};
metadata_file_content[current_revision] = {
creation_date: now.getTime(),
last_modified: now.getTime(),
conflict: false,
deleted: false
_creation_date: now.getTime(),
_last_modified: now.getTime(),
_revisions: [id],
_conflict: false,
_deleted: false
};
am.call(o,'saveMetadataOnDistant');
};
o.updateMetadata = function (){
var previous_creation_date;
var previous_creation_date, revision_history = [], id = '';
if (metadata_file_content[previous_revision]) {
previous_creation_date = metadata_file_content[
previous_revision].creation_date;
previous_revision]._creation_date;
revision_history = metadata_file_content[
previous_revision]._revisions;
delete metadata_file_content[previous_revision];
}
id = current_revision.split('-'); id.shift(); id = id.join('-');
revision_history.unshift(id);
metadata_file_content[current_revision] = {
creation_date: previous_creation_date || now.getTime(),
last_modified: now.getTime(),
conflict: on_conflict,
deleted: false
_creation_date: previous_creation_date || now.getTime(),
_last_modified: now.getTime(),
_revisions: revision_history,
_conflict: on_conflict,
_deleted: false
};
if (on_conflict) {
conflict_object =
priv.createConflictObject(
command,
metadata_file_content,
current_revision
command, metadata_file_content, current_revision
);
}
am.call(o,'saveMetadataOnDistant');
};
o.saveMetadataOnDistant = function (){
priv.saveMetadataToDistant(
command,metadata_file_path,metadata_file_content,
command, metadata_file_path, metadata_file_content,
function (result) {
am.call(o,'deletePreviousRevision');
if (on_conflict) {
......@@ -418,44 +479,65 @@ var newConflictManagerStorage = function ( spec, my ) {
empty_fun,empty_fun);
}
};
o.success = function (){
o.success = function () {
var a = {ok:true,id:command.getDocId(),rev:current_revision};
am.neverCall(o,'error');
am.neverCall(o,'success');
that.success({revision:current_revision});
if (command.getOption('revs')) {
a.revisions = priv._revs(metadata_file_content,
current_revision);
}
if (command.getOption('revs_info')) {
a.revs_info = priv._revs_info(metadata_file_content);
}
if (command.getOption('conflicts')) {
a.conflicts = conflict_object;
}
that.success(a);
};
o.error = function (error){
var gooderror = error || failerror ||
{status:0,statusText:'Unknown',
message:'Unknown error.'};
if (on_conflict) {
gooderror.conflict_object = conflict_object;
o.error = function (error) {
var err = error || failerror ||
{status:0,statusText:'Unknown',error:'unknown_error',
message:'Unknown error.',reason:'unknown error'};
if (current_revision) {
err.rev = current_revision;
}
if (command.getOption('revs')) {
err.revisions = priv._revs(metadata_file_content,
current_revision);
}
if (command.getOption('revs_info')) {
err.revs_info = priv._revs_info(metadata_file_content);
}
if (command.getOption('conflicts')) {
err.conflicts = conflict_object;
}
am.neverCall(o,'error');
am.neverCall(o,'success');
that.error(gooderror);
that.error(err);
};
am.call(o,'getDistantMetadata');
};
}; // end put
/**
* Load a document from several storages, and send the first retreived
* document.
* @method loadDocument
* @method get
*/
that.loadDocument = function (command) {
that.get = function (command) {
var o = {}, am = priv.newAsyncModule(),
metadata_file_path = command.getPath() + '.metadata',
current_revision = command.getOption('revision') || '',
metadata_file_path = command.getDocId() + '.metadata',
current_revision = command.getOption('rev') || '',
metadata_file_content = null,
metadata_only = command.getOption('metadata_only'),
on_conflict = false, conflict_object = {},
on_conflict = false, conflict_object = {total_rows:0,rows:[]},
now = new Date(),
doc = {name:command.getPath()},
doc = {_id:command.getDocId()},
call404 = function (message) {
am.call(o,'error',[{
status:404,statusText:'Not Found',
message:message
status:404,statusText:'Not Found',error:'not_found',
message:message,reason:message
}]);
};
......@@ -482,12 +564,18 @@ var newConflictManagerStorage = function ( spec, my ) {
} else {
current_revision = priv.chooseARevision(metadata_file_content);
}
doc.last_modified =
metadata_file_content[current_revision].last_modified;
doc.creation_date =
metadata_file_content[current_revision].creation_date;
doc.revision = current_revision;
doc.revision_object = metadata_file_content;
doc._last_modified =
metadata_file_content[current_revision]._last_modified;
doc._creation_date =
metadata_file_content[current_revision]._creation_date;
doc._rev = current_revision;
if (command.getOption('revs')) {
doc._revisions = priv._revs(metadata_file_content,
current_revision);
}
if (command.getOption('revs_info')) {
doc._revs_info = priv._revs_info(metadata_file_content);
}
if (metadata_only) {
am.call(o,'success');
} else {
......@@ -496,11 +584,11 @@ var newConflictManagerStorage = function ( spec, my ) {
};
o.loadRevision = function (){
if (!current_revision ||
metadata_file_content[current_revision].deleted) {
metadata_file_content[current_revision]._deleted) {
return call404('Document has been removed.');
}
priv.loadRevision (
command, doc.name+'.'+current_revision,
command, doc._id+'.'+current_revision,
function (result) {
doc.content = result.content;
am.call(o,'success');
......@@ -518,7 +606,9 @@ var newConflictManagerStorage = function ( spec, my ) {
metadata_file_content,
current_revision
);
doc.conflict_object = conflict_object;
}
if (command.getOption('conflicts')) {
doc._conflicts = conflict_object;
}
am.call(o,'success');
};
......@@ -543,35 +633,30 @@ var newConflictManagerStorage = function ( spec, my ) {
/**
* Get a document list from several storages, and returns the first
* retreived document list.
* @method getDocumentList
* @method allDocs
*/
that.getDocumentList = function (command) {
that.allDocs = function (command) {
var o = {}, am = priv.newAsyncModule(),
metadata_only = command.getOption('metadata_only'),
result_list = [],
nb_loaded_file = 0,
success_count = 0, success_max = 0;
o.retreiveList = function () {
var cloned_option = command.cloneOption ();
cloned_option.metadata_only = true;
cloned_option.error = function (error) {
am.call(o,'error',[error]);
};
cloned_option.success = function (result) {
var cloned_option = command.cloneOption (),
success = function (result) {
am.call(o,'filterTheList',[result]);
},error = function (error) {
am.call(o,'error',[error]);
};
var newcommand = that.newCommand(
'getDocumentList',{
path:command.getPath(),option:cloned_option
});
that.addJob ( that.newStorage (priv.secondstorage_spec),
newcommand );
cloned_option.metadata_only = true;
that.addJob ('allDocs',priv.secondstorage_spec,null,cloned_option,
success,error);
};
o.filterTheList = function (result) {
var i;
success_max ++;
for (i = 0; i < result.length; i+= 1) {
var splitname = result[i].name.split('.') || [];
for (i = 0; i < result.total_rows; i+= 1) {
var splitname = result.rows[i].id.split('.') || [];
if (splitname.length > 0 &&
splitname[splitname.length-1] === 'metadata') {
success_max ++;
......@@ -587,7 +672,7 @@ var newConflictManagerStorage = function ( spec, my ) {
function (data) {
data = JSON.parse (data.content);
var revision = priv.chooseARevision(data);
if (!data[revision].deleted) {
if (!data[revision]._deleted) {
am.call(
o,'loadFile',
[path,revision,data]
......@@ -602,15 +687,22 @@ var newConflictManagerStorage = function ( spec, my ) {
};
o.loadFile = function (path,revision,data) {
var doc = {
name: path,
last_modified:data[revision].last_modified,
creation_date:data[revision].creation_date,
revision:revision,
revision_object:data
};
if (data[revision].conflict) {
doc.conflict_object = priv.createConflictObject(
id: path,key: path,value:{
_last_modified:data[revision]._last_modified,
_creation_date:data[revision]._creation_date,
_rev:revision
}
};
if (command.getOption('revs_info')) {
doc.value._revs_info = priv._revs_info(data,revision);
}
if (command.getOption('conflicts')) {
if (data[revision]._conflict) {
doc.value._conflicts = priv.createConflictObject(
command, data, revision );
} else {
doc.value._conflicts = {total_rows:0,rows:[]};
}
}
if (!metadata_only) {
priv.loadRevision (
......@@ -631,7 +723,7 @@ var newConflictManagerStorage = function ( spec, my ) {
success_count ++;
if (success_count >= success_max) {
am.end();
that.success(result_list);
that.success({total_rows:result_list.length,rows:result_list});
}
};
o.error = function (error){
......@@ -639,33 +731,26 @@ var newConflictManagerStorage = function ( spec, my ) {
that.error(error);
};
am.call(o,'retreiveList');
};
}; // end allDocs
/**
* Remove a document from several storages.
* @method removeDocument
* @method remove
*/
that.removeDocument = function (command) {
that.remove = function (command) {
var o = {}, am = priv.newAsyncModule(),
metadata_file_path = command.getPath() + '.metadata',
metadata_file_path = command.getDocId() + '.metadata',
current_revision = '',
current_revision_file_path = '',
metadata_file_content = null,
on_conflict = false, conflict_object = {},
previous_revision = command.getOption('revision'),
previous_revision_file_path = command.getPath() + '.' +
on_conflict = false, conflict_object = {total_rows:0,rows:[]},
previous_revision = command.getOption('rev') || '0',
previous_revision_file_path = command.getDocId() + '.' +
previous_revision,
now = new Date(),
failerror;
if (!previous_revision) {
return setTimeout(function () {
that.error({status:0,statusText:'Parameter missing',
message:'Need a revision.'});
});
}
o.getDistantMetadata = function (){
priv.getDistantMetadata (
command,metadata_file_path,
......@@ -674,21 +759,25 @@ var newConflictManagerStorage = function ( spec, my ) {
if (previous_revision === 'last') {
previous_revision =
priv.chooseARevision (metadata_file_content);
previous_revision_file_path = command.getPath() + '.' +
previous_revision_file_path = command.getDocId() + '.' +
previous_revision;
}
var previous_revision_number =
parseInt(previous_revision.split('-')[0],10);
parseInt(previous_revision.split('-')[0],10) || 0;
// set current revision
current_revision = (previous_revision_number + 1) + '-' +
hex_sha256 ('' + previous_revision +
JSON.stringify (metadata_file_content));
current_revision_file_path = command.getPath() + '.' +
current_revision_file_path = command.getDocId() + '.' +
current_revision;
am.call(o,'checkForConflicts');
},function (error) {
if (error.status === 404) {
am.call(o,'success',['0']);
am.call(o,'error',[{
status:404,statusText:'Not Found',
error:'not_found',reason:'missing',
message:'Document not found.'
}]);
} else {
am.call(o,'error',[error]);
}
......@@ -696,12 +785,13 @@ var newConflictManagerStorage = function ( spec, my ) {
);
};
o.checkForConflicts = function () {
for (var rev in metadata_file_content) {
var rev;
for (rev in metadata_file_content) {
if (rev !== previous_revision) {
on_conflict = true;
failerror = {
status:20,
statusText:'Conflict',
status:409,error:'conflict',
statusText:'Conflict',reason:'document update conflict',
message:'There is one or more conflicts'
};
break;
......@@ -710,31 +800,35 @@ var newConflictManagerStorage = function ( spec, my ) {
am.call(o,'updateMetadata');
};
o.updateMetadata = function (){
var previous_creation_date;
var previous_creation_date, revision_history = [], id = '';
if (metadata_file_content[previous_revision]) {
previous_creation_date = metadata_file_content[
previous_revision].creation_date;
previous_revision]._creation_date;
revision_history = metadata_file_content[
previous_revision]._revisions;
delete metadata_file_content[previous_revision];
}
id = current_revision;
id = id.split('-'); id.shift(); id = id.join('-');
revision_history.unshift(id);
metadata_file_content[current_revision] = {
creation_date: previous_creation_date || now.getTime(),
last_modified: now.getTime(),
conflict: on_conflict,
deleted: true
_creation_date: previous_creation_date || now.getTime(),
_last_modified: now.getTime(),
_revisions: revision_history,
_conflict: on_conflict,
_deleted: true
};
if (on_conflict) {
conflict_object =
priv.createConflictObject(
command,
metadata_file_content,
current_revision
command, metadata_file_content, current_revision
);
}
am.call(o,'saveMetadataOnDistant');
};
o.saveMetadataOnDistant = function (){
priv.saveMetadataToDistant(
command,metadata_file_path,metadata_file_content,
command, metadata_file_path, metadata_file_content,
function (result) {
am.call(o,'deletePreviousRevision');
if (on_conflict) {
......@@ -755,23 +849,45 @@ var newConflictManagerStorage = function ( spec, my ) {
}
};
o.success = function (revision){
var a = {ok:true,id:command.getDocId(),
rev:revision || current_revision};
am.neverCall(o,'error');
am.neverCall(o,'success');
that.success({revision:revision || current_revision});
if (command.getOption('revs')) {
a.revisions = priv._revs(metadata_file_content,
current_revision);
}
if (command.getOption('revs_info')) {
a.revs_info = priv._revs_info(metadata_file_content);
}
if (command.getOption('conflicts')) {
a.conflicts = conflict_object;
}
that.success(a);
};
o.error = function (error){
var gooderror = error || failerror ||
{status:0,statusText:'Unknown',
message:'Unknown error.'};
if (on_conflict) {
gooderror.conflict_object = conflict_object;
var err = error || failerror ||
{status:0,statusText:'Unknown',error:'unknown_error',
message:'Unknown error.',reason:'unknown error'};
if (current_revision) {
err.rev = current_revision;
}
if (command.getOption('revs')) {
err.revisions = priv._revs(metadata_file_content,
current_revision);
}
if (command.getOption('revs_info')) {
err.revs_info = priv._revs_info(metadata_file_content);
}
if (command.getOption('conflicts')) {
err.conflicts = conflict_object;
}
am.neverCall(o,'error');
am.neverCall(o,'success');
that.error(gooderror);
that.error(err);
};
am.call(o,'getDistantMetadata');
};
}; // end remove
return that;
};
......
......@@ -136,6 +136,56 @@ removeFileFromLocalStorage = function (user,appid,file) {
newarray);
LocalOrCookieStorage.deleteItem(
'jio/local/'+user+'/'+appid+'/'+file._id);
},
makeRevsAccordingToRevsInfo = function (revs,revs_info) {
var i, j;
for (i = 0; i < revs.start; i+= 1) {
for (j = 0; j < revs_info.length; j+= 1) {
var id = revs_info[j].rev.split('-'); id.shift(); id = id.join('-');
if (revs.ids[i] === id) {
revs.ids[i] = revs_info[j].rev.split('-')[0];
break;
}
}
}
},
checkRev = function (rev) {
if (typeof rev === 'string') {
if (parseInt(rev.split('-')[0],10) > 0) {
return rev;
}
}
return 'ERROR: not a good revision!';
},
checkConflictRow = function (row) {
var fun;
if (typeof row === 'object') {
if (row.value && typeof row.value._solveConflict === 'function') {
fun = row.value._solveConflict;
row.value._solveConflict = 'function';
}
}
return fun;
},
getHashFromRev = function (rev) {
var id = rev;
if (typeof id === 'string') {
id = id.split('-');
id.shift(); id = id.join('-');
}
return id;
},
revs_infoContains = function (revs_info, rev) {
var i;
if (typeof revs_info !== 'object') {
return undefined;
}
for (i = 0; i < revs_info.length || 0; i+= 1) {
if (revs_info[i].rev && revs_info[i].rev === rev) {
return true;
}
}
return false;
};
//// end tools
......@@ -1302,19 +1352,9 @@ test ('Simple methods', function () {
var o = {}; o.clock = this.sandbox.useFakeTimers(); o.t = this;
o.clock.tick(base_tick);
o.spy = function(res,value,message,before) {
o.f = function(result) {
if (res === 'status') {
if (result && result.conflict_object) {
result = 'conflict';
} else if (result && typeof result.status !== 'undefined') {
result = 'fail';
} else {
result = 'done';
}
}
if (before) { before (result); }
deepEqual (result,value,message);
o.spy = function(value,message) {
o.f = function(err,val) {
deepEqual (err || val,value,message);
};
o.t.spy(o,'f');
};
......@@ -1333,79 +1373,154 @@ test ('Simple methods', function () {
storage:{type:'local',
username:'conflictmethods',
applicationname:'jiotests'}});
o.spy('status','done','saving "file.doc".');
o.jio.saveDocument('file.doc','content1',{
previous_revision: '0',
success:function (result) {
o.new_rev = result.revision;
o.f (result);
},
error:o.f
// PUT
o.spy({ok:true,id:'file.doc',rev:'1'},'saving "file.doc".');
o.jio.put({_id:'file.doc',content:'content1'},function (err,val) {
if (val) {
o.rev1 = val.rev;
val.rev = val.rev.split('-')[0];
}
o.f (err,val);
});
o.tick();
o.spy('status','done','saving "file2.doc".');
o.jio.saveDocument('file2.doc','yes',{
previous_revision: '0',
success:o.f,
error:o.f
// PUT with options
o.spy({ok:true,id:'file2.doc',rev:'1',
conflicts:{total_rows:0,rows:[]},
revisions:{start:1,ids:['1']},
revs_info:[{rev:'1',status:'available'}]},
'saving "file2.doc".');
o.jio.put({_id:'file2.doc',content:'yes'},
{revs:true,revs_info:true,conflicts:true},
function (err,val) {
if (val) {
o.rev2 = val.rev;
val.rev = val.rev.split('-')[0];
if (val.revs_info) {
if (val.revisions) {
makeRevsAccordingToRevsInfo(
val.revisions,val.revs_info);
}
val.revs_info[0].rev =
val.revs_info[0].rev.split('-')[0];
}
}
o.f (err,val);
});
o.tick();
o.spy('value',{name:'file.doc',content:'content1',revision:'rev'},
'loading "file.doc".',function (o) {
if (!o) { return; }
if (o.revision) { o.revision = 'rev'; }
if (o.creation_date) { delete o.creation_date; }
else { ok(false, 'creation date missing!'); }
if (o.last_modified) { delete o.last_modified; }
else { ok(false, 'last modified missing!'); }
if (o.revision_object) { delete o.revision_object; }
else { ok(false, 'revision object missing!'); }
});
o.jio.loadDocument('file.doc',{success:o.f,error:o.f});
// GET
o.get_callback = function (err,val) {
if (val) {
val._rev = (val._rev?val._rev.split('-')[0]:'/');
val._creation_date = (val._creation_date?true:undefined);
val._last_modified = (val._last_modified?true:undefined);
}
o.f(err,val);
};
o.spy({_id:'file.doc',content:'content1',_rev:'1',
_creation_date:true,_last_modified:true},'loading "file.doc".');
o.jio.get('file.doc',o.get_callback);
o.tick();
// GET with options
o.get_callback = function (err,val) {
if (val) {
val._rev = (val._rev?val._rev.split('-')[0]:'/');
val._creation_date = (val._creation_date?true:undefined);
val._last_modified = (val._last_modified?true:undefined);
if (val._revs_info) {
if (val._revisions) {
makeRevsAccordingToRevsInfo(
val._revisions,val._revs_info);
}
val._revs_info[0].rev =
val._revs_info[0].rev.split('-')[0];
}
}
o.f(err,val);
};
o.spy({_id:'file2.doc',content:'yes',_rev:'1',
_creation_date:true,_last_modified:true,
_conflicts:{total_rows:0,rows:[]},
_revisions:{start:1,ids:['1']},
_revs_info:[{rev:'1',status:'available'}]},
'loading "file2.doc".');
o.jio.get('file2.doc',{revs:true,revs_info:true,conflicts:true},
o.get_callback);
o.tick();
o.spy('value',[{name:'file.doc',revision:'rev'},
{name:'file2.doc',revision:'rev'}],
'getting list.',function (a) {
// allDocs
o.spy({total_rows:2,rows:[{
id:'file.doc',key:'file.doc',
value:{_rev:'1',_creation_date:true,_last_modified:true}
},{
id:'file2.doc',key:'file2.doc',
value:{_rev:'1',_creation_date:true,_last_modified:true}
}]},'getting list.');
o.jio.allDocs(function (err,val) {
if (val) {
var i;
if (!a) { return; }
for (i = 0; i < a.length; i+= 1) {
if (a[i].revision) { a[i].revision = 'rev'; }
if (a[i].creation_date) { delete a[i].creation_date; }
else { ok(false, 'creation date missing!'); }
if (a[i].last_modified) { delete a[i].last_modified; }
else { ok(false, 'last modified missing!'); }
if (a[i].revision_object) { delete a[i].revision_object; }
else { ok(false, 'revision object missing!'); }
for (i = 0; i < val.total_rows; i+= 1) {
val.rows[i].value._creation_date =
val.rows[i].value._creation_date?
true:undefined;
val.rows[i].value._last_modified =
val.rows[i].value._last_modified?
true:undefined;
val.rows[i].value._rev = val.rows[i].value._rev.split('-')[0];
}
// because the result can be disordered
if (a.length === 2 && a[0].name === 'file2.doc') {
var tmp = a[0];
a[0] = a[1];
a[1] = tmp;
if (val.total_rows === 2 && val.rows[0].id === 'file2.doc') {
var tmp = val.rows[0];
val.rows[0] = val.rows[1];
val.rows[1] = tmp;
}
}
o.f(err,val);
});
o.jio.getDocumentList('.',{success:o.f,error:o.f});
o.tick();
o.spy('status','done','removing "file.doc"');
o.jio.removeDocument('file.doc',{
success:o.f,error:o.f,revision:o.new_rev
// remove
o.spy({ok:true,id:'file.doc',rev:'2'},
'removing "file.doc"');
o.jio.remove({_id:'file.doc'},{rev:o.rev1},function (err,val) {
if (val) {
val.rev = val.rev?val.rev.split('-')[0]:undefined;
}
o.f(err,val);
});
o.tick();
o.spy('status','fail','loading document fail.');
o.jio.loadDocument('file.doc',{
success:o.f,error:function (error) {
if (error.status === 404) {
o.f(error);
} else {
deepEqual (error, '{}', 'An 404 error was expected.');
// remove with options
o.spy({
ok:true,id:'file2.doc',rev:'2',
conflicts:{total_rows:0,rows:[]},
revisions:{start:2,ids:['2',getHashFromRev(o.rev2)]},
revs_info:[{rev:'2',status:'deleted'}]
},'removing "file2.doc"');
o.jio.remove(
{_id:'file2.doc'},
{rev:o.rev2,conflicts:true,revs:true,revs_info:true},
function (err,val) {
if (val) {
val.rev = val.rev?val.rev.split('-')[0]:undefined;
if (val.revs_info) {
if (val.revisions) {
makeRevsAccordingToRevsInfo(
val.revisions,val.revs_info);
}
val.revs_info[0].rev =
val.revs_info[0].rev.split('-')[0];
}
}
o.f(err,val);
});
o.tick();
o.spy(404,'loading document fail.');
o.jio.get('file.doc',function (err,val) {
if (err) {
err = err.status;
}
o.f(err,val);
});
o.tick();
......@@ -1417,33 +1532,9 @@ test ('Revision Conflict', function() {
var o = {}; o.clock = this.sandbox.useFakeTimers(); o.t = this;
o.clock.tick (base_tick);
o.spy = function(res,value,message,function_name) {
function_name = function_name || 'f';
o[function_name] = function(result) {
if (res === 'status') {
if (result && result.conflict_object) {
result = 'conflict';
} else if (result && typeof result.status !== 'undefined') {
result = 'fail';
} else {
result = 'done';
}
}
deepEqual (result,value,message);
};
o.t.spy(o,function_name);
};
o.tick = function (tick, function_name) {
function_name = function_name || 'f'
o.clock.tick(tick || 1000);
if (!o[function_name].calledOnce) {
if (o[function_name].called) {
ok(false, 'too much results');
} else {
ok(false, 'no response');
}
}
};
o.spy = basic_spy_function;
o.tick = basic_tick_function;
o.localNamespace = 'jio/local/revisionconflict/jiotests/';
o.rev={};
o.checkContent = function (string,message) {
......@@ -1461,76 +1552,136 @@ test ('Revision Conflict', function() {
o.jio = JIO.newJio({type:'conflictmanager',
storage:o.secondstorage_spec});
// create a new file
o.spy('status','done','new file "file.doc", revision: "0".');
o.jio.saveDocument(
'file.doc','content1',{
previous_revision:'0',
error:o.f,
success:function(value){
o.rev.first = value.revision;
o.f(value);
o.spy(o,'value',
{ok:true,id:'file.doc',rev:'1',conflicts:{total_rows:0,rows:[]},
revs_info:[{rev:'1',status:'available'}],
revisions:{start:1,ids:['1']}},
'new file "file.doc".');
o.jio.put(
{_id:'file.doc',content:'content1'},
{revs:true,revs_info:true,conflicts:true},
function (err,val) {
if (val) {
o.rev.first = val.rev;
val.rev = val.rev?val.rev.split('-')[0]:undefined;
if (val.revs_info) {
if (val.revisions) {
makeRevsAccordingToRevsInfo(
val.revisions,val.revs_info);
}
});
o.tick();
val.revs_info[0].rev =
val.revs_info[0].rev.split('-')[0];
}
}
o.f(err,val);
}
);
o.tick(o);
o.checkContent('file.doc.'+o.rev.first);
// modify the file
o.spy('status','done','modify "file.doc", revision: "'+
o.spy(o,'value',
{ok:true,id:'file.doc',rev:'2',
conflicts:{total_rows:0,rows:[]},
revisions:{start:2,ids:['2',getHashFromRev(o.rev.first)]},
revs_info:[{rev:'2',status:'available'}]},
'modify "file.doc", revision: "'+
o.rev.first+'".');
o.jio.saveDocument(
'file.doc','content2',{
previous_revision:o.rev.first,
error:o.f,
success:function(v) {
o.f(v);
o.rev.second = v.revision;
o.jio.put(
{_id:'file.doc',content:'content2',_rev:o.rev.first},
{revs:true,revs_info:true,conflicts:true},
function (err,val) {
if (val) {
o.rev.second = val.rev;
val.rev = val.rev?val.rev.split('-')[0]:undefined;
if (val.revs_info) {
if (val.revisions) {
makeRevsAccordingToRevsInfo(
val.revisions,val.revs_info);
}
});
o.tick();
val.revs_info[0].rev =
val.revs_info[0].rev.split('-')[0];
}
}
o.f(err,val);
}
);
o.tick(o);
o.checkContent('file.doc.'+o.rev.second);
o.checkNoContent('file.doc.'+o.rev.first);
// modify the file from the second revision instead of the third
o.spy('status','conflict','modify "file.doc", revision: "'+
o.rev.first+'" -> conflict!');
o.jio.saveDocument(
'file.doc','content3',{
previous_revision:o.rev.first,
success:o.f,
error: function (error) {
o.conflict_object = error.conflict_object;
o.f(error);
o.rev.third = '?';
if (o.conflict_object) {
o.rev.third = o.conflict_object.revision;
ok (!o.conflict_object.revision_object[o.new_rev],
o.test_message = 'modify "file.doc", revision: "'+
o.rev.first+'" -> conflict!';
o.f = o.t.spy();
o.jio.put(
{_id:'file.doc',content:'content3',_rev:o.rev.first},
{revs:true,revs_info:true,conflicts:true},function (err,val) {
o.f();
var k;
if (err) {
o.rev.third = err.rev;
err.rev = checkRev(err.rev);
if (err.conflicts && err.conflicts.rows) {
o.solveConflict = checkConflictRow (err.conflicts.rows[0]);
}
for (k in {'error':0,'message':0,'reason':0,'statusText':0}) {
if (err[k]) {
delete err[k];
} else {
err[k] = 'ERROR: ' + k + ' is missing !';
}
}
}
deepEqual(err||val,{
rev:o.rev.third,
conflicts:{total_rows:1,rows:[
{id:'file.doc',key:[o.rev.second,o.rev.third],
value:{_solveConflict:'function'}}]},
status:409,
// just one revision in the history, it does not keep older
// revisions because it is not a revision manager storage.
revisions:{start:1,ids:[getHashFromRev(o.rev.third)]},
revs_info:[{rev:o.rev.second,status:'available'},
{rev:o.rev.third,status:'available'}]
},o.test_message);
ok (!revs_infoContains(err.revs_info,o.rev.first),
'check if the first revision is not include to '+
'the conflict list.');
ok (o.conflict_object.revision_object[
o.conflict_object.revision],
ok (revs_infoContains(err.revs_info,err.rev),
'check if the new revision is include to '+
'the conflict list.');
}
}
});
o.tick();
o.tick(o);
o.checkContent ('file.doc.'+o.rev.third);
// loading test
o.spy('status','conflict','loading "file.doc" -> conflict!');
o.jio.loadDocument('file.doc',{
success:o.f,error:o.f
o.spy(o,'value',{_id:'file.doc',_rev:o.rev.third,content:'content3'},
'loading "file.doc" -> conflict!');
o.jio.get('file.doc',function (err,val) {
var k;
if (val) {
for (k in {'_creation_date':0,'_last_modified':0}) {
if (val[k]) {
delete val[k];
} else {
val[k] = 'ERROR: ' + k + ' is missing !';
}
}
}
o.f(err,val);
});
o.tick();
if (!o.conflict_object) { return ok(false,'Cannot to continue the tests'); }
o.tick(o);
if (!o.solveConflict) { return ok(false,'Cannot to continue the tests'); }
// solving conflict
o.spy('status','done','solve conflict "file.doc".');
o.conflict_object.solveConflict(
'content4',{
error:o.f,
success:function (r) {
o.f(r);
o.rev.forth = r.revision;
o.spy(o,'value',{ok:true,id:'file.doc',rev:'3'},
'solve conflict "file.doc".');
o.solveConflict(
'content4',function (err,val) {
if (val) {
o.rev.forth = val.rev;
val.rev = val.rev?val.rev.split('-')[0]:undefined;
}
o.f(err,val);
});
o.tick();
o.tick(o);
o.checkContent('file.doc.'+o.rev.forth);
o.checkNoContent('file.doc.'+o.rev.second);
o.checkNoContent('file.doc.'+o.rev.third);
......@@ -1540,33 +1691,9 @@ test ('Revision Conflict', function() {
test ('Conflict in a conflict solving', function () {
var o = {}; o.clock = this.sandbox.useFakeTimers(); o.t = this;
o.clock.tick (base_tick);
o.spy = function(res,value,message,function_name) {
function_name = function_name || 'f';
o[function_name] = function(result) {
if (res === 'status') {
if (result && result.conflict_object) {
result = 'conflict';
} else if (result && typeof result.status !== 'undefined') {
result = 'fail';
} else {
result = 'done';
}
}
deepEqual (result,value,message);
};
o.t.spy(o,function_name);
};
o.tick = function (tick, function_name) {
function_name = function_name || 'f'
o.clock.tick(tick || 1000);
if (!o[function_name].calledOnce) {
if (o[function_name].called) {
ok(false, 'too much results');
} else {
ok(false, 'no response');
}
}
};
o.spy = basic_spy_function;
o.tick = basic_tick_function;
o.localNamespace = 'jio/local/conflictconflict/jiotests/';
o.rev={};
o.checkContent = function (string,message) {
......@@ -1584,73 +1711,165 @@ test ('Conflict in a conflict solving', function () {
o.jio = JIO.newJio({type:'conflictmanager',
storage:o.secondstorage_spec});
// create a new file
o.spy('status','done','new file "file.doc", revision: "0".');
o.jio.saveDocument(
'file.doc','content1',{
previous_revision:'0',
error:o.f,
success:function(value){
o.rev.first = value.revision;
o.f(value);
}
o.test_message = 'new file "file.doc", revision: "0".'
o.f = o.t.spy();
o.jio.put(
{_id:'file.doc',content:'content1'},
{conflicts:true,revs:true,revs_info:true},
function(err,val) {
o.f();
if (val) {
o.rev.first = val.rev;
val.rev = checkRev(val.rev);
}
deepEqual(err||val,{
ok:true,id:'file.doc',rev:o.rev.first,
conflicts:{total_rows:0,rows:[]},
revisions:{start:1,ids:[getHashFromRev(o.rev.first)]},
revs_info:[{rev:o.rev.first,status:'available'}]
},o.test_message);
});
o.tick();
o.tick(o);
o.checkContent ('file.doc.'+o.rev.first);
// modify the file from the second revision instead of the third
o.spy('status','conflict','modify "file.doc", revision: "0" -> conflict!');
o.jio.saveDocument(
'file.doc','content2',{
previous_revision:"0",
success:o.f,
error: function (error) {
o.f(error);
o.conflict_object = error.conflict_object;
o.rev.second = o.conflict_object?o.conflict_object.revision:'?';
}
o.test_message = 'modify "file.doc", revision: "0" -> conflict!';
o.f = o.t.spy();
o.jio.put(
{_id:'file.doc',content:'content2'},
{conflicts:true,revs:true,revs_info:true},
function (err,val) {
o.f();
var k;
if (err) {
o.rev.second = err.rev;
err.rev = checkRev(err.rev);
if (err.conflicts && err.conflicts.rows) {
o.solveConflict = checkConflictRow (err.conflicts.rows[0]);
}
for (k in {'error':0,'message':0,'reason':0,'statusText':0}) {
if (err[k]) {
delete err[k];
} else {
err[k] = 'ERROR: ' + k + ' is missing !';
}
}
}
deepEqual(err||val,{
rev:o.rev.second,
conflicts:{total_rows:1,rows:[
{id:'file.doc',key:[o.rev.first,o.rev.second],
value:{_solveConflict:'function'}}]},
status:409,
// just one revision in the history, it does not keep older
// revisions because it is not a revision manager storage.
revisions:{start:1,ids:[getHashFromRev(o.rev.second)]},
revs_info:[{rev:o.rev.first,status:'available'},
{rev:o.rev.second,status:'available'}]
},o.test_message);
});
o.tick();
o.tick(o);
o.checkContent ('file.doc.'+o.rev.second);
if (!o.conflict_object) { return ok(false,'Cannot to continue the tests'); }
if (!o.solveConflict) { return ok(false,'Cannot to continue the tests'); }
// saving another time
o.spy('status','conflict','modify "file.doc" when solving, revision: "'+
o.rev.first+'" -> conflict!');
o.jio.saveDocument('file.doc','content3',{
previous_revision: o.rev.first,
error:function(e){
o.f(e);
o.rev.third = o.conflict_object?o.conflict_object.revision:'?';
},
success:o.f
o.test_message = 'modify "file.doc" when solving, revision: "'+
o.rev.first+'" -> conflict!';
o.f = o.t.spy();
o.jio.put(
{_id:'file.doc',content:'content3',_rev:o.rev.first},
{conflicts:true,revs:true,revs_info:true},
function(err,val){
o.f();
if (err) {
o.rev.third = err.rev;
err.rev = checkRev(err.rev);
if (err.conflicts && err.conflicts.rows) {
checkConflictRow (err.conflicts.rows[0]);
}
for (k in {'error':0,'message':0,'reason':0,'statusText':0}) {
if (err[k]) {
delete err[k];
} else {
err[k] = 'ERROR: ' + k + ' is missing !';
}
}
}
deepEqual(err||val,{
rev:o.rev.third,
conflicts:{total_rows:1,rows:[
{id:'file.doc',key:[o.rev.second,o.rev.third],
value:{_solveConflict:'function'}}]},
status:409,
// just one revision in the history, it does not keep older
// revisions because it is not a revision manager storage.
revisions:{start:2,ids:[getHashFromRev(o.rev.third),
getHashFromRev(o.rev.first)]},
revs_info:[{rev:o.rev.second,status:'available'},
{rev:o.rev.third,status:'available'}]
},o.test_message);
});
o.tick();
o.tick(o);
o.checkContent ('file.doc.'+o.rev.third);
o.checkNoContent ('file.doc.'+o.rev.first);
// solving first conflict
o.spy('status','conflict','solving conflict "file.doc" -> conflict!');
o.conflict_object.solveConflict('content4',{
success: o.f,
error: function (error) {
o.rev.forth = '?';
if (error.conflict_object) {
o.conflict_object = error.conflict_object;
o.rev.forth = o.conflict_object.revision;
}
o.f(error);
}
})
o.tick();
o.test_message = 'solving conflict "file.doc" -> conflict!';
o.f = o.t.spy();
o.solveConflict(
'content4',{conflicts:true,revs:true,revs_info:true},
function (err,val) {
o.f();
if (err) {
o.rev.forth = err.rev;
err.rev = checkRev(err.rev);
if (err.conflicts && err.conflicts.rows) {
o.solveConflict = checkConflictRow (err.conflicts.rows[0]);
}
for (k in {'error':0,'message':0,'reason':0,'statusText':0}) {
if (err[k]) {
delete err[k];
} else {
err[k] = 'ERROR: ' + k + ' is missing !';
}
}
}
deepEqual(err||val,{
rev:o.rev.forth,
conflicts:{total_rows:1,rows:[
{id:'file.doc',key:[o.rev.third,o.rev.forth],
value:{_solveConflict:'function'}}]},
status:409,
// just one revision in the history, it does not keep older
// revisions because it is not a revision manager storage.
revisions:{start:2,ids:[getHashFromRev(o.rev.forth),
getHashFromRev(o.rev.second)]},
revs_info:[{rev:o.rev.third,status:'available'},
{rev:o.rev.forth,status:'available'}]
},o.test_message);
});
o.tick(o);
o.checkContent ('file.doc.'+o.rev.forth);
o.checkNoContent ('file.doc.'+o.rev.second);
if (!o.solveConflict) { return ok(false,'Cannot to continue the tests'); }
// solving last conflict
o.spy('status','done','solving last conflict "file.doc".');
o.conflict_object.solveConflict('content5',{
error:o.f,
success:function (v) {
o.f(v);
o.rev.fith = v.revision;
}
o.test_message = 'solving last conflict "file.doc".';
o.f = o.t.spy();
o.solveConflict(
'content5',{conflicts:true,revs:true,revs_info:true},
function (err,val) {
if (val) {
o.rev.fith = val.rev;
val.rev = checkRev(val.rev);
}
deepEqual(err||val,{
ok:true,id:'file.doc',rev:o.rev.fith,
conflicts:{total_rows:0,rows:[]},
revisions:{start:3,ids:[getHashFromRev(o.rev.fith),
getHashFromRev(o.rev.forth),
getHashFromRev(o.rev.second)]},
revs_info:[{rev:o.rev.fith,status:'available'}]
},o.test_message);
o.f();
});
o.tick();
o.tick(o);
o.checkContent ('file.doc.'+o.rev.fith);
o.jio.stop();
......@@ -1659,33 +1878,9 @@ test ('Conflict in a conflict solving', function () {
test ('Remove revision conflict', function () {
var o = {}; o.clock = this.sandbox.useFakeTimers(); o.t = this;
o.clock.tick (base_tick);
o.spy = function(res,value,message,function_name) {
function_name = function_name || 'f';
o[function_name] = function(result) {
if (res === 'status') {
if (result && result.conflict_object) {
result = 'conflict';
} else if (result && typeof result.status !== 'undefined') {
result = 'fail';
} else {
result = 'done';
}
}
deepEqual (result,value,message);
};
o.t.spy(o,function_name);
};
o.tick = function (tick, function_name) {
function_name = function_name || 'f'
o.clock.tick(tick || 1000);
if (!o[function_name].calledOnce) {
if (o[function_name].called) {
ok(false, 'too much results');
} else {
ok(false, 'no response');
}
}
};
o.spy = basic_spy_function;
o.tick = basic_tick_function;
o.localNamespace = 'jio/local/removeconflict/jiotests/';
o.rev={};
o.checkContent = function (string,message) {
......@@ -1703,77 +1898,189 @@ test ('Remove revision conflict', function () {
o.jio = JIO.newJio({type:'conflictmanager',
storage:o.secondstorage_spec});
o.spy('status','done','new file "file.doc", revision: "0".');
o.jio.saveDocument(
'file.doc','content1',{
previous_revision:'0',
error:o.f,
success:function(value){
o.rev.first = value.revision;
o.f(value);
}
o.test_message = 'new file "file.doc", revision: "0".';
o.f = o.t.spy();
o.jio.put(
{_id:'file.doc',content:'content1'},
{conflicts:true,revs:true,revs_info:true},
function(err,val) {
o.f();
if (val) {
o.rev.first = val.rev;
val.rev = checkRev(val.rev);
}
deepEqual(err||val,{
ok:true,id:'file.doc',rev:o.rev.first,
conflicts:{total_rows:0,rows:[]},
revisions:{start:1,ids:[getHashFromRev(o.rev.first)]},
revs_info:[{rev:o.rev.first,status:'available'}]
},o.test_message);
});
o.tick();
o.tick(o);
o.checkContent ('file.doc.'+o.rev.first);
o.spy('status','fail','remove "file.doc", revision: "wrong" -> conflict!');
o.jio.removeDocument(
'file.doc',{
previous_revision:'wrong',
success:o.f,
error:function (e) {
o.f(e);
}
o.test_message = 'remove "file.doc", revision: "wrong" -> conflict!';
o.f = o.t.spy();
o.jio.remove(
{_id:'file.doc'},
{conflicts:true,revs:true,revs_info:true,rev:'wrong'},
function (err,val) {
o.f();
if (err) {
o.rev.second = err.rev;
err.rev = checkRev(err.rev);
if (err.conflicts && err.conflicts.rows) {
o.solveConflict = checkConflictRow (err.conflicts.rows[0]);
}
for (k in {'error':0,'message':0,'reason':0,'statusText':0}) {
if (err[k]) {
delete err[k];
} else {
err[k] = 'ERROR: ' + k + ' is missing !';
}
}
}
deepEqual(err||val,{
rev:o.rev.second,
conflicts:{total_rows:1,rows:[
{id:'file.doc',key:[o.rev.first,o.rev.second],
value:{_solveConflict:'function'}}]},
status:409,
// just one revision in the history, it does not keep older
// revisions because it is not a revision manager storage.
revisions:{start:1,ids:[getHashFromRev(o.rev.second)]},
revs_info:[{rev:o.rev.first,status:'available'},
{rev:o.rev.second,status:'deleted'}]
},o.test_message);
});
o.tick();
o.tick(o);
o.spy('status','conflict','new file again "file.doc", revision: "0".');
o.jio.saveDocument(
'file.doc','content2',{
previous_revision:'0',
success:o.f,
error:function (error) {
o.f(error);
o.rev.second = error.conflict_object ?
error.conflict_object.revision : '?';
}
o.test_message = 'new file again "file.doc".';
o.f = o.t.spy();
o.jio.put(
{_id:'file.doc',content:'content2'},
{conflicts:true,revs:true,revs_info:true},
function (err,val) {
o.f();
if (err) {
o.rev.third = err.rev;
err.rev = checkRev(err.rev);
if (err.conflicts && err.conflicts.rows) {
o.solveConflict = checkConflictRow (err.conflicts.rows[0]);
}
for (k in {'error':0,'message':0,'reason':0,'statusText':0}) {
if (err[k]) {
delete err[k];
} else {
err[k] = 'ERROR: ' + k + ' is missing !';
}
}
}
deepEqual(err||val,{
rev:o.rev.third,
conflicts:{total_rows:1,rows:[
{id:'file.doc',key:[o.rev.first,o.rev.second,o.rev.third],
value:{_solveConflict:'function'}}]},
status:409,
// just one revision in the history, it does not keep older
// revisions because it is not a revision manager storage.
revisions:{start:1,ids:[getHashFromRev(o.rev.third)]},
revs_info:[{rev:o.rev.first,status:'available'},
{rev:o.rev.second,status:'deleted'},
{rev:o.rev.third,status:'available'}]
},o.test_message);
});
o.tick();
o.checkContent ('file.doc.'+o.rev.second);
o.tick(o);
o.checkContent ('file.doc.'+o.rev.third);
o.spy('status','conflict','remove "file.doc", revision: "'+o.rev.first+
'" -> conflict!');
o.jio.removeDocument(
'file.doc',{
revision:o.rev.first,
success:o.f,
error:function (error) {
o.conflict_object = error.conflict_object;
o.f(error);
o.rev.third = o.conflict_object?o.conflict_object.revision:'?';
}
o.test_message = 'remove "file.doc", revision: "'+o.rev.first+
'" -> conflict!'
o.f = o.t.spy();
o.jio.remove(
{_id:'file.doc'},
{conflicts:true,revs:true,revs_info:true,rev:o.rev.first},
function (err,val) {
o.f();
if (err) {
o.rev.forth = err.rev;
err.rev = checkRev(err.rev);
if (err.conflicts && err.conflicts.rows) {
o.solveConflict = checkConflictRow (err.conflicts.rows[0]);
}
for (k in {'error':0,'message':0,'reason':0,'statusText':0}) {
if (err[k]) {
delete err[k];
} else {
err[k] = 'ERROR: ' + k + ' is missing !';
}
}
}
deepEqual(err||val,{
rev:o.rev.forth,
conflicts:{total_rows:1,rows:[
{id:'file.doc',key:[o.rev.second,o.rev.third,o.rev.forth],
value:{_solveConflict:'function'}}]},
status:409,
// just one revision in the history, it does not keep older
// revisions because it is not a revision manager storage.
revisions:{start:2,ids:[getHashFromRev(o.rev.forth),
getHashFromRev(o.rev.first)]},
revs_info:[{rev:o.rev.second,status:'deleted'},
{rev:o.rev.third,status:'available'},
{rev:o.rev.forth,status:'deleted'}]
},o.test_message);
});
o.tick();
o.tick(o);
o.checkNoContent ('file.doc.'+o.rev.first);
o.checkNoContent ('file.doc.'+o.rev.third);
o.checkNoContent ('file.doc.'+o.rev.forth);
if (!o.conflict_object) { return ok(false, 'Cannot continue the tests'); }
o.spy('status','done','solve "file.doc"');
o.conflict_object.solveConflict({
error:o.f,
success:function (v) {
o.f(v);
o.rev.forth = v.revision;
}
if (!o.solveConflict) { return ok(false, 'Cannot continue the tests'); }
o.test_message = 'solve "file.doc"';
o.f = o.t.spy();
o.solveConflict({conflicts:true,revs:true,revs_info:true},function(err,val){
o.f();
if (val) {
o.rev.fith = val.rev;
val.rev = checkRev(val.rev);
}
deepEqual(err||val,{
ok:true,id:'file.doc',rev:o.rev.fith,
conflicts:{total_rows:0,rows:[]},
revisions:{start:3,ids:[getHashFromRev(o.rev.fith),
getHashFromRev(o.rev.forth),
getHashFromRev(o.rev.first)]},
revs_info:[{rev:o.rev.fith,status:'deleted'}]
},o.test_message);
});
o.tick();
o.tick(o);
o.checkNoContent ('file.doc.'+o.rev.second);
o.checkNoContent ('file.doc.'+o.rev.third);
o.checkNoContent ('file.doc.'+o.rev.forth);
o.checkNoContent ('file.doc.'+o.rev.fith);
o.jio.stop();
});
test ('Load Revisions', function () {
var o = {}; o.clock = this.sandbox.useFakeTimers(); o.t = this;
o.clock.tick (base_tick);
o.spy = basic_spy_function;
o.tick = basic_tick_function;
o.secondstorage_spec = {type:'local',
username:'loadrevisions',
applicationname:'jiotests'}
//////////////////////////////////////////////////////////////////////
o.jio = JIO.newJio({type:'conflictmanager',
storage:o.secondstorage_spec});
o.spy(o,'status',404,'load file rev:1,','f'); // 12 === Replaced
o.spy(o,'status',404,'load file rev:2','g');
o.spy(o,'status',404,'and load file rev:3 at the same time','h');
o.jio.get('file',{rev:'1'},o.f);
o.jio.get('file',{rev:'2'},o.g);
o.jio.get('file',{rev:'3'},o.h);
o.tick(o,1000,'f'); o.tick(o,0,'g'); o.tick(o,0,'h');
o.jio.stop();
});
}; // end thisfun
if (window.requirejs) {
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment