Commit fdb950be authored by Sven Franck's avatar Sven Franck

revisionstorage get/remove

parent 0c109099
...@@ -117,13 +117,6 @@ jIO.addStorageType('revision', function (spec, my) { ...@@ -117,13 +117,6 @@ jIO.addStorageType('revision', function (spec, my) {
return {"rev":revision,"status":status,"children":children || []}; return {"rev":revision,"status":status,"children":children || []};
}; };
/**
* Gets the winner revision from a document tree.
* The winner is the deeper revision on the left.
* @method getWinnerRevisionFromDocumentTree
* @param {object} document_tree The document tree
* @return {array} The winner revs info array
*/
/** /**
* Gets the winner revision from a document tree. * Gets the winner revision from a document tree.
* The winner is the deeper revision on the left. * The winner is the deeper revision on the left.
...@@ -163,7 +156,11 @@ jIO.addStorageType('revision', function (spec, my) { ...@@ -163,7 +156,11 @@ jIO.addStorageType('revision', function (spec, my) {
} }
}; };
search(document_tree, 0); search(document_tree, 0);
return result; // xxx shouldn't this return only a single revision
// from the document tree? Currently multiple revisions
// are passed back
// return result;
return [result[0]];
}; };
/** /**
...@@ -171,12 +168,19 @@ jIO.addStorageType('revision', function (spec, my) { ...@@ -171,12 +168,19 @@ jIO.addStorageType('revision', function (spec, my) {
* @method postToDocumentTree * @method postToDocumentTree
* @param {object} doctree The document tree object * @param {object} doctree The document tree object
* @param {object} doc The document object * @param {object} doc The document object
* @param {boolean} set_node_to_deleted true/false
* @return {array} The added document revs_info * @return {array} The added document revs_info
*/ */
priv.postToDocumentTree = function (doctree, doc) { priv.postToDocumentTree = function (doctree, doc, set_node_to_deleted) {
var i, revs_info, next_rev, next_rev_str, selectNode, selected_node; var i, revs_info, next_rev, next_rev_str, next_rev_status,
revs_info = []; selectNode, selected_node,
selected_node = doctree; revs_info = [],
selected_node = doctree;
if (doc._rev === undefined && priv.missing_revision){
doc._rev = priv.missing_revision;
}
selectNode = function (node) { selectNode = function (node) {
var i; var i;
if (typeof node.rev !== "undefined") { if (typeof node.rev !== "undefined") {
...@@ -214,15 +218,17 @@ jIO.addStorageType('revision', function (spec, my) { ...@@ -214,15 +218,17 @@ jIO.addStorageType('revision', function (spec, my) {
next_rev = priv.generateNextRevision( next_rev = priv.generateNextRevision(
doc._rev || 0, JSON.stringify(doc) + JSON.stringify(revs_info)); doc._rev || 0, JSON.stringify(doc) + JSON.stringify(revs_info));
next_rev_str = next_rev.join("-"); next_rev_str = next_rev.join("-");
next_rev_status = set_node_to_deleted === true ? "deleted" : "available";
// don't add if the next rev already exists // don't add if the next rev already exists
for (i = 0; i < selected_node.children.length; i += 1) { for (i = 0; i < selected_node.children.length; i += 1) {
if (selected_node.children[i].rev === next_rev_str) { if (selected_node.children[i].rev === next_rev_str) {
revs_info.unshift({ revs_info.unshift({
"rev": next_rev_str, "rev": next_rev_str,
"status": "available" "status": next_rev_status
}); });
if (selected_node.children[i].status !== "available") { if (selected_node.children[i].status !== next_rev_status) {
selected_node.children[i].status = "available"; selected_node.children[i].status = next_rev_status;
} }
return revs_info; return revs_info;
} }
...@@ -270,6 +276,23 @@ jIO.addStorageType('revision', function (spec, my) { ...@@ -270,6 +276,23 @@ jIO.addStorageType('revision', function (spec, my) {
return result; return result;
}; };
/**
* Check if revision is a leaf
* @method isRevisionALeaf
* @param {string} revision revision to check
* @param {array} leaves all leaves on tree
* @return {boolean} true/false
*/
priv.isRevisionALeaf = function (revision, leaves) {
var i;
for (i = 0; i < leaves.length; i+=1) {
if (leaves[i] === revision){
return true;
}
}
return false;
};
/** /**
* Convert revs_info to a simple revisions history * Convert revs_info to a simple revisions history
* @method revsInfoToHistory * @method revsInfoToHistory
...@@ -299,6 +322,7 @@ jIO.addStorageType('revision', function (spec, my) { ...@@ -299,6 +322,7 @@ jIO.addStorageType('revision', function (spec, my) {
var f = {}, doctree, revs_info, doc, docid; var f = {}, doctree, revs_info, doc, docid;
doc = command.cloneDoc(); doc = command.cloneDoc();
docid = command.getDocId(); docid = command.getDocId();
if (typeof doc._rev === "string" && if (typeof doc._rev === "string" &&
!priv.checkRevisionFormat(doc._rev)) { !priv.checkRevisionFormat(doc._rev)) {
that.error({ that.error({
...@@ -329,6 +353,7 @@ jIO.addStorageType('revision', function (spec, my) { ...@@ -329,6 +353,7 @@ jIO.addStorageType('revision', function (spec, my) {
docid+priv.doctree_suffix, docid+priv.doctree_suffix,
option, option,
function (response) { function (response) {
doctree = response; doctree = response;
if (priv.update_doctree_allowed) { if (priv.update_doctree_allowed) {
f.postDocument("put"); f.postDocument("put");
...@@ -356,8 +381,12 @@ jIO.addStorageType('revision', function (spec, my) { ...@@ -356,8 +381,12 @@ jIO.addStorageType('revision', function (spec, my) {
); );
}; };
f.postDocument = function (doctree_update_method) { f.postDocument = function (doctree_update_method) {
revs_info = priv.postToDocumentTree(doctree, doc); revs_info = priv.postToDocumentTree(doctree, doc,
priv.update_doctree_on_remove);
// I don't understand why?
doc._id = docid+"."+revs_info[0].rev; doc._id = docid+"."+revs_info[0].rev;
that.addJob( that.addJob(
"post", "post",
priv.substorage, priv.substorage,
...@@ -365,7 +394,8 @@ jIO.addStorageType('revision', function (spec, my) { ...@@ -365,7 +394,8 @@ jIO.addStorageType('revision', function (spec, my) {
command.cloneOption(), command.cloneOption(),
function (response) { function (response) {
f.sendDocumentTree (doctree_update_method); f.sendDocumentTree (doctree_update_method);
}, function (err) { },
function (err) {
switch(err.status) { switch(err.status) {
case 409: case 409:
// file already exists // file already exists
...@@ -387,12 +417,14 @@ jIO.addStorageType('revision', function (spec, my) { ...@@ -387,12 +417,14 @@ jIO.addStorageType('revision', function (spec, my) {
doctree, doctree,
command.cloneOption(), command.cloneOption(),
function (response) { function (response) {
that.success({ that.success({
"ok":true, "ok":true,
"id":docid, "id":docid,
"rev":revs_info[0].rev "rev":revs_info[0].rev
}) });
}, function (err) { },
function (err) {
// xxx do we try to delete the posted document ? // xxx do we try to delete the posted document ?
err.message = "Cannot save document revision tree"; err.message = "Cannot save document revision tree";
that.error(err); that.error(err);
...@@ -427,7 +459,7 @@ jIO.addStorageType('revision', function (spec, my) { ...@@ -427,7 +459,7 @@ jIO.addStorageType('revision', function (spec, my) {
* @param {object} command The JIO command * @param {object} command The JIO command
*/ */
that.get = function (command) { that.get = function (command) {
var f = {}, doctree, revs_info, prev_rev, revs_info, option; var f = {}, doctree, revs_info, prev_rev, rev_path, option;
option = command.cloneOption(); option = command.cloneOption();
if (option["max_retry"] === 0) { if (option["max_retry"] === 0) {
option["max_retry"] = 3; option["max_retry"] = 3;
...@@ -479,7 +511,6 @@ jIO.addStorageType('revision', function (spec, my) { ...@@ -479,7 +511,6 @@ jIO.addStorageType('revision', function (spec, my) {
docid, docid,
option, option,
function (response) { function (response) {
var i, conflict_array;
if (typeof response !== "string") { if (typeof response !== "string") {
response._id = command.getDocId(); response._id = command.getDocId();
response._rev = prev_rev; response._rev = prev_rev;
...@@ -506,11 +537,218 @@ jIO.addStorageType('revision', function (spec, my) { ...@@ -506,11 +537,218 @@ jIO.addStorageType('revision', function (spec, my) {
); );
}; };
if (command.getAttachmentId()) { if (command.getAttachmentId()) {
f.getDocument(command.getDocId()+"/"+command.getAttachmentId()); // xxx: no revision passed = get tree and winning revision
if ( prev_rev === undefined ){
that.addJob(
"get",
priv.substorage,
command.getDocId()+priv.doctree_suffix,
option,
function (response) {
rev_path = "."+priv.getWinnerRevisionFromDocumentTree(
response)[0].rev;
f.getDocument(command.getDocId()+
rev_path+"/"+command.getAttachmentId());
},
function (err) {
that.error({
"status": 404,
"statusText": "Not Found",
"error": "not_found",
"message": "Document tree not found, please check document ID",
"reason": "Incorrect document ID"
});
return;
}
);
} else {
f.getDocument(command.getDocId()+"."+
prev_rev+"/"+command.getAttachmentId());
}
} else { } else {
f.getDocumentTree(); f.getDocumentTree();
} }
}; };
/**
* Remove document or attachment.
* Options:
* - {boolean} keep_revision_history To keep the previous revisions
* @method remove
* @param {object} command The JIO command
*/
that.remove = function (command) {
var f = {}, del_rev, option, i,
revision_found = false, revision_count = 0, correct_revision;
option = command.cloneOption();
if (option["max_retry"] === 0) {
option["max_retry"] = 3;
}
del_rev = command.getDoc()._rev;
f.removeDocument = function (docid) {
if (command.getOption("keep_revision_history") !== true) {
that.addJob(
"remove",
priv.substorage,
docid,
option,
function (response) {
if ( command.getAttachmentId() === undefined ) {
priv.update_doctree_on_remove = true;
} else {
priv.update_doctree_on_remove = false;
}
that.post(command);
},
function (err) {
that.error({
"status": 404,
"statusText": "Not Found",
"error": "not_found",
"message": "File not found",
"reason": "Document was not found"
});
return;
}
);
} else {
// keep history = update document tree only
if (command.getAttachmentId() === undefined ) {
priv.update_doctree_on_remove = true;
} else {
priv.update_doctree_on_remove = false;
}
that.post(command);
}
};
if (typeof del_rev === "string") {
if (!priv.checkRevisionFormat(del_rev)) {
that.error({
"status": 31,
"statusText": "Wrong Revision Format",
"error": "wrong_revision_format",
"message": "The document previous revision does not match "+
"[0-9]+-[0-9a-zA-Z]+",
"reason": "Previous revision is wrong"
});
return;
}
}
// get doctree
that.addJob(
"get",
priv.substorage,
command.getDocId()+priv.doctree_suffix,
option,
function (response) {
response._conflicts = priv.getLeavesFromDocumentTree(response);
// really necessary...?
if (del_rev === undefined) {
// single leaf = can be deleted
if (response._conflicts.length === 1) {
f.removeDocument(command.getDocId()+"."+
response._conflicts[0]);
delete response._conflicts;
} else {
// multiple leaves = only if deleting attachment,
// because unique document.revision/attachment
if (typeof command.getAttachmentId() === "string"){
for (i = 0; i < response._conflicts.length; i += 1){
del_rev = response._conflicts[i];
that.addJob(
"get",
priv.substorage,
command.getDocId()+"."+response._conflicts[i],
option,
function (nested_response) {
if (typeof nested_response._attachments === "object") {
if (nested_response._attachments[command.getAttachmentId()] !== undefined){
revision_found = true;
correct_revision = del_rev;
}
}
if ( revision_count === response._conflicts.length-1 &&
revision_found !== true ){
that.error({
"status": 404,
"statusText": "Not Found",
"error": "not_found",
"message": "Attachment not found, please check attachment ID",
"reason": "Incorrect Attachment ID"
});
return;
}
if (revision_found === true ){
priv.missing_revision = correct_revision;
delete response._conflicts;
f.removeDocument(command.getDocId()+"."+
correct_revision+"/"+command.getAttachmentId());
}
revision_count += 1;
},
function (err) {
that.error({
"status": 404,
"statusText": "Not Found",
"error": "not_found",
"message": "Attachment not found, please check document ID",
"reason": "Incorrect document ID"
});
}
);
}
} else {
// conflict
// return conflict message here, so user can pick a document version
that.error({
"status": 409,
"statusText": "Conflict",
"error": "conflict",
"message": "Document update conflict.",
"reason": "Cannot delete a document without revision when multiple versions exist"
});
return;
}
}
} else {
// revision provided
if (typeof command.getAttachmentId() === "string"){
f.removeDocument(command.getDocId()+"."+del_rev+"/"+
command.getAttachmentId());
} else {
if (priv.isRevisionALeaf(del_rev, response._conflicts)){
f.removeDocument(command.getDocId()+"."+del_rev);
} else {
that.error({
"status": 409,
"statusText": "Conflict",
"error": "conflict",
"message": "Document update conflict.",
"reason": "Trying to remove an outdated revision"
});
return;
}
}
}
},
function (err) {
that.error({
"status": 404,
"statusText": "Not Found",
"error": "not_found",
"message": "Document tree not found, please check document ID",
"reason": "Incorrect document ID"
});
return;
}
);
};
return that; return that;
}); });
...@@ -1228,11 +1228,11 @@ test ("Get", function(){ ...@@ -1228,11 +1228,11 @@ test ("Get", function(){
// adding two documents // adding two documents
o.doctree = {"children":[{ o.doctree = {"children":[{
"rev": "1-rev1", "status": "available", "children": [] "rev": "1-rev1", "status": "available", "children": [{
},{
"rev": "1-rev2", "status": "available", "children": [{
"rev": "2-rev3", "status": "available", "children": [] "rev": "2-rev3", "status": "available", "children": []
}] }]
},{
"rev": "1-rev2", "status": "available", "children": []
}]}; }]};
o.doc_myget2 = {"_id": "get1", "title": "myGet2"}; o.doc_myget2 = {"_id": "get1", "title": "myGet2"};
o.doc_myget3 = {"_id": "get1", "title": "myGet3"}; o.doc_myget3 = {"_id": "get1", "title": "myGet3"};
...@@ -1260,16 +1260,8 @@ test ("Get", function(){ ...@@ -1260,16 +1260,8 @@ test ("Get", function(){
o.tick(o); o.tick(o);
delete o.doc_myget2["_rev"]; delete o.doc_myget2["_rev"];
// adding an attachment // localstorage.setItem(o.localpath+"/get1.1-rev2/get2", "abc");
o.attmt_myget2 = { localstorage.setItem(o.localpath+"/get1.2-rev3/get2", "abc");
"get2": {
"length": 3,
"digest": "md5-dontcare"
}
};
o.doctree["children"][1]["attachment"] = o.attmt_myget2;
localstorage.setItem(o.localpath+"/get1.1-rev2", o.doc_myget2);
localstorage.setItem(o.localpath+"/get1.1-rev2/get2", "abc");
// get attachment winner // get attachment winner
o.spy(o, "value", "abc", "Get attachment (winner)"); o.spy(o, "value", "abc", "Get attachment (winner)");
...@@ -1283,13 +1275,24 @@ test ("Get", function(){ ...@@ -1283,13 +1275,24 @@ test ("Get", function(){
// get attachment specific rev // get attachment specific rev
o.spy(o, "value", "abc", "Get attachment (specific revision)"); o.spy(o, "value", "abc", "Get attachment (specific revision)");
o.jio.get("get1/get2", {"rev": "1-rev2"}, o.f); o.jio.get("get1/get2", {"rev": "2-rev3"}, o.f);
o.tick(o); o.tick(o);
// get document with attachment (specific revision) // adding an attachment
o.attmt_myget2["get2"]["revpos"] = 1; o.attmt_myget2 = {
"get2": {
"length": 3,
"digest": "md5-dontcare"
},
"revpos":1,
};
o.doc_myget2["_rev"] = "1-rev2"; o.doc_myget2["_rev"] = "1-rev2";
o.doc_myget2["_attachments"] = o.attmt_myget2; o.doc_myget2["_attachments"] = o.attmt_myget2;
o.doctree["children"][1]["attachment"] = o.attmt_myget2;
localstorage.setItem(o.localpath+"/get1.1-rev2", o.doc_myget2);
// get document with attachment (specific revision)
o.spy(o, "value", o.doc_myget2, o.spy(o, "value", o.doc_myget2,
"Get document attachment (specific revision)"); "Get document attachment (specific revision)");
o.jio.get("get1", {"rev": "1-rev2"}, o.f); o.jio.get("get1", {"rev": "1-rev2"}, o.f);
...@@ -1300,6 +1303,10 @@ test ("Get", function(){ ...@@ -1300,6 +1303,10 @@ test ("Get", function(){
// get document with attachment (winner) // get document with attachment (winner)
o.doc_myget3["_rev"] = "2-rev3"; o.doc_myget3["_rev"] = "2-rev3";
o.doc_myget3["_attachments"] = o.attmt_myget2; o.doc_myget3["_attachments"] = o.attmt_myget2;
o.doctree["children"][1]["attachment"] = o.attmt_myget3;
localstorage.setItem(o.localpath+"/get1.2-rev3", o.doc_myget3);
o.spy(o, "value", o.doc_myget3, "Get document attachment (winner)"); o.spy(o, "value", o.doc_myget3, "Get document attachment (winner)");
o.jio.get("get1", o.f); o.jio.get("get1", o.f);
o.tick(o); o.tick(o);
...@@ -1311,6 +1318,250 @@ test ("Get", function(){ ...@@ -1311,6 +1318,250 @@ test ("Get", function(){
}); });
test ("Remove", function(){
var o = generateTools(this);
o.jio = JIO.newJio({
"type": "revision",
"secondstorage": {
"type": "local",
"username": "urevrem",
"applicationname": "arevrem"
}
});
o.localpath = "jio/localstorage/urevrem/arevrem";
// adding two documents
o.doc_myremove1 = {"_id": "remove1", "title": "myRemove1"};
o.doc_myremove2 = {"_id": "remove1", "title": "myRemove2"};
// revs_info 1-rev1 document version
o.revs_info = [];
o.very_old_rev = "1-"+hex_sha256(JSON.stringify(o.doc_myremove1)+JSON.stringify(o.revs_info));
localstorage.setItem(o.localpath+"/remove1."+o.very_old_rev, o.doc_myremove1);
localstorage.setItem(o.localpath+"/remove1.1-rev2", o.doc_myremove1);
// add attachment
o.attmt_myremove1 = {
"remove2": {
"length": 3,
"digest": "md5-dontcare"
},
"revpos":1
};
o.doc_myremove1 = {"_id": "remove1", "title": "myRemove1",
"_rev":o.very_old_rev, "_attachments":o.attmt_myremove1};
o.revs_info = [{"rev": o.very_old_rev, "status": "available"}];
o.old_rev = "2-"+hex_sha256(JSON.stringify(o.doc_myremove1)+JSON.stringify(o.revs_info));
localstorage.setItem(o.localpath+"/remove1."+o.old_rev, o.doc_myremove1);
localstorage.setItem(o.localpath+"/remove1."+o.old_rev+"/remove2", "xyz");
o.doctree = {"children":[{
"rev": o.very_old_rev, "status": "available", "children": [{
"rev": o.old_rev, "status": "available", "children": []
}]
},{
"rev": "1-rev2", "status": "available", "children": []
}]};
localstorage.setItem(o.localpath+"/remove1.revision_tree.json", o.doctree);
// 1. remove non existing attachment with revision
o.spy(o, "status", 404, "Remove non existing attachment (with revision)");
o.jio.remove({"_id":"remove1.1-rev2/remove0","_rev":o.old_rev}, o.f);
o.tick(o);
o.revs_info = [
{"rev": o.old_rev, "status": "available"},
{"rev": o.very_old_rev, "status": "available"}
];
// xxx on remove, doc only includes the parameters passed in the remove callback
// to generate correct hash, need to modify here
o.doc_myremove1 = {"_id":"remove1/remove2","_rev":o.old_rev};
o.rev = "3-"+hex_sha256(JSON.stringify(o.doc_myremove1)+JSON.stringify(o.revs_info));
o.doctree = {"children":[{
"rev": o.very_old_rev, "status": "available", "children": [{
"rev": o.old_rev, "status": "available", "children": [{
"rev": o.rev, "status": "available", "children":[]
}]
}]
},{
"rev": "1-rev2", "status": "available", "children": []
}]};
localstorage.setItem(o.localpath+"/remove1.revision_tree.json", o.doctree);
// 2. remove existing attachment with revision
o.spy (o, "value", {"ok": true, "id": "remove1", "rev": o.rev},
"Remove attachment (with revision)");
o.jio.remove({"_id":"remove1/remove2","_rev":o.old_rev}, o.f);
o.tick(o);
// add another attachment
o.attmt_myremove2 = {
"remove3": {
"length": 3,
"digest": "md5-hello123"
},
"revpos":1
};
o.doc_myremove2 = {"_id": "remove1", "title": "myRemove2",
"_rev":"1-rev2", "_attachments":o.attmt_myremove2};
o.second_old_rev = "2-"+hex_sha256(JSON.stringify(o.doc_myremove1)+JSON.stringify(o.revs_info));
o.revs_info = [
{"rev":o.second_old_rev, "status":"available"},
{"rev": "1-rev2", "status": "available"}
];
localstorage.setItem(o.localpath+"/remove1."+o.second_old_rev, o.doc_myremove2);
localstorage.setItem(o.localpath+"/remove1."+o.second_old_rev+"/remove3", "stu");
o.doctree = {"children":[{
"rev": o.very_old_rev, "status": "available", "children": [{
"rev": o.old_rev, "status": "available", "children": [{
"rev": o.rev, "status": "available", "children":[]
}]
}]
},{
"rev": "1-rev2", "status": "available", "children": [{
"rev": o.second_old_rev, "status": "available", "children":[]
}]
}]};
localstorage.setItem(o.localpath+"/remove1.revision_tree.json", o.doctree);
// 3. remove non existing attachment without revision
o.spy (o,"status", 404, "Remove non existing attachment (without revision)")
o.jio.remove({"_id":"remove1/remove0"}, o.f);
o.tick(o);
o.revs_info = [
{"rev": o.second_old_rev, "status": "available"},
{"rev": "1-rev2", "status": "available"}
];
o.doc_myremove3 = {"_id":"remove1/remove3","_rev":o.second_old_rev};
o.second_rev = "3-"+hex_sha256(JSON.stringify(o.doc_myremove3)+JSON.stringify(o.revs_info));
// 4. remove existing attachment without revision
o.spy (o, "value", {"ok": true, "id": "remove1", "rev": o.second_rev},
"Remove attachment (without revision)");
o.jio.remove({"_id":"remove1/remove3"}, o.f);
o.tick(o);
// 5. remove wrong revision
o.spy (o,"status", 409, "Removing wrong revision (not latest)");
o.jio.remove({"_id":"remove1","_rev":o.second_old_rev}, o.f);
o.tick(o);
o.revs_info = [
{"rev": o.second_rev, "status":"available"},
{"rev": o.second_old_rev, "status": "available"},
{"rev": "1-rev2", "status": "available"}
];
o.doc_myremove4 = {"_id":"remove1","_rev":o.second_rev};
o.second_new_rev = "4-"+hex_sha256(JSON.stringify(o.doc_myremove4)+JSON.stringify(o.revs_info));
// 6. remove revision
o.spy (o, "value", {"ok": true, "id": "remove1", "rev": o.second_new_rev},
"Remove attachment (with revision)");
o.jio.remove({"_id":"remove1", "_rev":o.second_rev}, o.f);
o.tick(o);
// 7. remove document without revision
o.spy (o,"status", 409, "Removing document without revision and multiple existing versions");
o.jio.remove({"_id":"remove1"}, o.f);
o.tick(o);
o.jio.stop();
});
module ( "Test Revisionstorage + Localstorage" );
test ("sample", function(){
var o = generateTools(this);
o.jio = JIO.newJio({
"type": "revision",
"secondstorage": {
"type": "local",
"username": "usam1",
"applicationname": "asam1"
}
});
o.localpath = "jio/localstorage/usam1/asam1";
// 1. put non empty document A-1
o.doc = {"_id": "sample1", "title": "mySample1"};
o.revs_info = [];
o.rev = "1-"+hex_sha256(JSON.stringify(o.doc)+JSON.stringify(o.revs_info));
o.spy (o, "value", {"ok": true, "id": "sample1", "rev": o.rev}, "Put non empty document A-1");
o.jio.put(o.doc, o.f);
o.tick(o);
// 2. put non empty document A-2
o.doc_b = {"_id": "sample1", "title": "mySample2"};
o.revs_info_b = [];
o.rev_b = "1-"+hex_sha256(JSON.stringify(o.doc)+JSON.stringify(o.revs_info));
o.spy (o,"status", 409, "409 Try to put non empty document A-2");
o.jio.put(o.doc, o.f);
o.tick(o);
// 3. FAKE IT
o.doc_f = {"_id": "sample1", "title": "mySample2"};
o.revs_info_f = [];
o.rev_f = "1-"+hex_sha256(JSON.stringify(o.doc_f)+JSON.stringify(o.revs_info_f));
o.doc_f2 = {"_id": "sample1."+o.rev_f, "title": "mySample2"};
localstorage.setItem(o.localpath+"/sample1."+o.rev_f, o.doc_f2);
o.doctree = {"children":[
{ "rev": o.rev, "status": "available", "children": []},
{ "rev": o.rev_f, "status": "available", "children": []}
]};
localstorage.setItem(o.localpath+"/sample1.revision_tree.json", o.doctree);
// 3. GET first version
o.spy(o, "value", {"_id": "sample1", "title": "mySample1", "_rev": o.rev},
"Get first document (using revison)");
o.jio.get("sample1", {"rev": o.rev}, o.f);
o.tick(o);
// 4. MODFIY first version
o.doc_2 = {"_id": "sample1", "_rev": o.rev, "title": "mySample1_modified"};
o.revs_info_2 = [{"rev": o.rev, "status": "available"}];
o.rev_2 = "2-"+hex_sha256(JSON.stringify(o.doc_2)+JSON.stringify(o.revs_info_2));
o.spy (o, "value", {"id":"sample1", "ok":true, "rev": o.rev_2}, "Modify first document");
o.jio.put(o.doc_2, o.f);
o.tick(o);
// 5. GET second version
o.spy(o, "value", {"_id": "sample1", "title": "mySample2", "_rev": o.rev_f},
"Get second document (using revison)");
o.jio.get("sample1", {"rev": o.rev_f}, o.f);
o.tick(o);
// 6. MODFIY second version
o.doc_f2 = {"_id": "sample1", "_rev": o.rev_f, "title": "mySample2_modified"};
o.revs_info_f2 = [{"rev": o.rev_f, "status": "available"}];
o.rev_f2 = "2-"+hex_sha256(JSON.stringify(o.doc_f2)+JSON.stringify(o.revs_info_f2));
o.spy (o, "value", {"id":"sample1", "ok":true, "rev": o.rev_f2}, "Modify second document");
o.jio.put(o.doc_f2, o.f);
o.tick(o);
// 7. GET document with conflict!
o.spy(o, "value", {"_id": "sample1", "title": "mySample2", "_rev": o.rev_f},
"Get second document (using revison)");
o.jio.get("sample1", o.f);
o.tick(o);
o.jio.stop();
});
/* /*
module ('Jio DAVStorage'); module ('Jio DAVStorage');
......
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