Commit dd360f2f authored by Tristan Cavelier's avatar Tristan Cavelier

storages tests remove except localstorage

parent 555c679b
/*jslint indent: 2, maxlen: 80, nomen: true */
/*global define, jIO, jio_tests, window, test, ok, deepEqual, sinon, expect */
// define([module_name], [dependencies], module);
(function (dependencies, module) {
"use strict";
if (typeof define === 'function' && define.amd) {
return define(dependencies, module);
}
module(jIO, jio_tests);
}(['jio', 'jio_tests', 'davstorage'], function (jIO, util) {
"use strict";
function generateTools() {
return {
clock: sinon.useFakeTimers(),
spy: util.ospy,
tick: util.otick
};
}
module("DAVStorage");
test("Post", function () {
var o = generateTools(this);
o.jio = jIO.newJio({
"type": "dav",
"url": "https://ca-davstorage:8080",
"auth_type": "basic",
"username": "admin",
"password": "pwd"
});
// post without id
o.server = sinon.fakeServer.create();
o.server.respondWith(
"GET",
new RegExp("https://ca-davstorage:8080/[0-9a-fA-F]{4}"),
[
404,
{"Content-Type": "text/html"},
"<h1>Document not found</h1>"
]
);
o.server.respondWith(
"PUT",
new RegExp("https://ca-davstorage:8080/[0-9a-fA-F]{4}"),
[
200,
{"Content-Type": "text/html"},
"<h1>Document updated!</h1>"
]
);
o.spy(o, "jobstatus", "done", "Post without id");
o.jio.post({}, {"max_retry": 1}, function (err, response) {
o.f.apply(arguments);
if (response) {
ok(util.isUuid(response.id), "Uuid should look like " +
"xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx : " + response.id);
}
});
o.clock.tick(1000);
o.server.respond();
o.tick(o);
o.server.restore();
// post document with id
o.server = sinon.fakeServer.create();
o.server.respondWith(
"GET",
new RegExp("https://ca-davstorage:8080/http:%252F%252F100%2525_\\.json"),
[
404,
{"Content-Type": "text/html"},
"<h1>Document not found</h1>"
]
);
o.server.respondWith(
"PUT",
new RegExp("https://ca-davstorage:8080/http:%252F%252F100%2525_\\.json"),
[
200,
{"Content-Type": "text/html"},
"<h1>Document updated!</h1>"
]
);
o.spy(o, "value", {"id": "http://100%.json", "ok": true},
"Create document with an id");
o.jio.post({
"_id": "http://100%.json",
"title": "Hello There"
}, {"max_retry": 1}, o.f);
o.clock.tick(1000);
o.server.respond();
o.tick(o);
o.server.restore();
// post already existant file
o.server = sinon.fakeServer.create();
o.server.respondWith(
"GET",
new RegExp("https://ca-davstorage:8080/http:%252F%252F100%2525_\\.json"),
[
200,
{"Content-Type": "text/plain"},
'{"_id":"doc1","title":"Hello There"}'
]
);
o.spy(o, "status", 405, "Update document previous -> 405");
o.jio.post({
"_id": "http://100%.json",
"title": "Hello There Again"
}, {"max_retry": 1}, o.f);
o.clock.tick(1000);
o.server.respond();
o.tick(o);
o.server.restore();
util.closeAndcleanUpJio(o.jio);
});
test("Put", function () {
var o = generateTools(this);
o.jio = jIO.newJio({
"type": "dav",
"url": "https://ca-davstorage:8080",
"auth_type": "basic",
"username": "admin",
"password": "pwd"
});
// put without id => 20 Id Required
o.spy(o, "status", 20, "Put without id -> 20");
o.jio.put({}, o.f);
o.tick(o);
// put non empty document
o.server = sinon.fakeServer.create();
o.server.respondWith(
"PUT",
new RegExp("https://ca-davstorage:8080/http:%252F%252F100%2525_\\.json"),
[
200,
{"Content-Type": "text/html"},
"<h1>OK1</h1>"
]
);
o.spy(o, "value", {"ok": true, "id": "http://100%.json"},
"Create document");
o.jio.put({
"_id": "http://100%.json",
"title": "Hi There"
}, {"max_retry": 1}, o.f);
o.clock.tick(1000);
o.server.respond();
o.tick(o);
o.server.restore();
// update document
o.server = sinon.fakeServer.create();
o.server.respondWith(
"PUT",
new RegExp("https://ca-davstorage:8080/http:%252F%252F100%2525_\\.json"),
[
200,
{"Content-Type": "text/html"},
"<h1>OK!</h1>"
]
);
o.spy(o, "value", {"ok": true, "id": "http://100%.json"},
"Update document");
o.jio.put({
"_id": "http://100%.json",
"title": "Hi There Again"
}, {"max_retry": 1}, o.f);
o.clock.tick(1000);
o.server.respond();
o.tick(o);
o.server.restore();
// putAttachment without document id => 20 Id Required
o.spy(o, "status", 20, "PutAttachment without doc id -> 20");
o.jio.putAttachment({"_attachment": "body.html"}, o.f);
o.tick(o);
// putAttachment without attachment id => 22 Attachment Id Required
o.spy(o, "status", 22, "PutAttachment without attachment id -> 22");
o.jio.putAttachment({"_id": "http://100%.json"}, o.f);
o.tick(o);
// putAttachment without underlying document => 404 Not Found
o.server = sinon.fakeServer.create();
o.server.respondWith(
"GET",
new RegExp("https://ca-davstorage:8080/http:%252F%252F100%2525_\\.json"),
[
404,
{"Content-Type": "text/html"},
"<h1>Not Found</h1>"
]
);
o.spy(o, "status", 404, "PutAttachment without document -> 404");
o.jio.putAttachment({
"_id": "http://100%.json",
"_attachment": "putattmt2"
}, {"max_retry": 1}, o.f);
o.clock.tick(1000);
o.server.respond();
o.tick(o);
o.server.restore();
// upload attachment
o.server = sinon.fakeServer.create();
o.server.respondWith(
"GET",
new RegExp("https://ca-davstorage:8080/http:%252F%252F100%2525_\\.json"),
[
200,
{"Content-Type": "text/plain"},
'{"_id":"http://100%.json","title":"Hi There!"}'
]
);
o.server.respondWith(
"PUT",
new RegExp("https://ca-davstorage:8080/" +
"http:%252F%252F100%2525_\\.json.body_\\.html"),
[
200,
{"Content-Type": "text/html"},
"<h1>OK!</h1>"
]
);
o.server.respondWith(
"PUT",
new RegExp("https://ca-davstorage:8080/http:%252F%252F100%2525_\\.json"),
[
200,
{"Content-Type": "text/html"},
"<h1>OK!</h1>"
]
);
o.spy(o, "value", {
"ok": true,
"id": "http://100%.json",
"attachment": "body.html"
}, "Upload attachment");
o.jio.putAttachment({
"_id": "http://100%.json",
"_attachment": "body.html",
"_mimetype": "text/html",
"_data": "<h1>Hi There!!</h1><p>How are you?</p>"
}, {"max_retry": 1}, o.f);
o.clock.tick(1000);
o.server.respond();
o.tick(o);
o.server.restore();
util.closeAndcleanUpJio(o.jio);
});
test("Get", function () {
var o = generateTools(this);
o.jio = jIO.newJio({
"type": "dav",
"url": "https://ca-davstorage:8080",
"auth_type": "basic",
"username": "admin",
"password": "pwd"
});
// get inexistent document
o.server = sinon.fakeServer.create();
o.server.respondWith(
"GET",
new RegExp("https://ca-davstorage:8080/http:%252F%252F100%2525_\\.json"),
[
404,
{"Content-Type": "text/html"},
"<h1>Not Found</h1>"
]
);
o.spy(o, "status", 404, "Get non existing document -> 404");
o.jio.get({"_id": "http://100%.json"}, {"max_retry": 1}, o.f);
o.clock.tick(1000);
o.server.respond();
o.tick(o);
o.server.restore();
// get document
o.server = sinon.fakeServer.create();
o.server.respondWith(
"GET",
new RegExp("https://ca-davstorage:8080/http:%252F%252F100%2525_\\.json"),
[
200,
{"Content-Type": "text/html"},
'{"_id":"http://100%.json","title":"Hi There!"}'
]
);
o.spy(o, "value", {"_id": "http://100%.json", "title": "Hi There!"},
"Get document");
o.jio.get({"_id": "http://100%.json"}, {"max_retry": 1}, o.f);
o.clock.tick(1000);
o.server.respond();
o.tick(o);
o.server.restore();
// get inexistent attachment
o.server = sinon.fakeServer.create();
o.server.respondWith(
"GET",
new RegExp("https://ca-davstorage:8080/" +
"http:%252F%252F100%2525_\\.json\\.body_\\.html"),
[
404,
{"Content-Type": "text/html"},
"<h1>Not Found</h1>"
]
);
o.spy(o, "status", 404, "Get inexistent attachment -> 404");
o.jio.getAttachment({
"_id": "http://100%.json",
"_attachment": "body.html"
}, {"max_retry": 1}, o.f);
o.clock.tick(1000);
o.server.respond();
o.tick(o);
o.server.restore();
// get attachment
o.server = sinon.fakeServer.create();
o.server.respondWith(
"GET",
new RegExp("https://ca-davstorage:8080/" +
"http:%252F%252F100%2525_\\.json\\.body_\\.html"),
[
200,
{"Content-Type": "text/plain"},
"My Attachment Content"
]
);
o.spy(o, "value", "My Attachment Content", "Get attachment");
o.jio.getAttachment({
"_id": "http://100%.json",
"_attachment": "body.html"
}, {"max_retry": 1}, o.f);
o.clock.tick(1000);
o.server.respond();
o.tick(o);
o.server.restore();
util.closeAndcleanUpJio(o.jio);
});
test("Remove", function () {
var o = generateTools(this);
o.jio = jIO.newJio({
"type": "dav",
"url": "https://ca-davstorage:8080",
"auth_type": "basic",
"username": "admin",
"password": "pwd"
});
// remove inexistent document
o.server = sinon.fakeServer.create();
o.server.respondWith(
"GET",
new RegExp("https://ca-davstorage:8080/http:%252F%252F100%2525_\\.json"),
[
404,
{"Content-Type": "text/html"},
"<h1>Not Found</h1>"
]
);
o.spy(o, "status", 404, "Remove inexistent document -> 404");
o.jio.remove({"_id": "http://100%.json"}, {"max_retry": 1}, o.f);
o.clock.tick(1000);
o.server.respond();
o.tick(o);
o.server.restore();
// remove document
o.server = sinon.fakeServer.create();
o.server.respondWith(
"GET",
new RegExp("https://ca-davstorage:8080/http:%252F%252F100%2525_\\.json"),
[
200,
{"Content-Type": "text/html"},
"{My corrupted document}"
]
);
o.server.respondWith(
"DELETE",
new RegExp("https://ca-davstorage:8080/http:%252F%252F100%2525_\\.json"),
[
200,
{"Content-Type": "text/plain"},
"<h1>Deleted</h1>"
]
);
o.spy(o, "value", {"ok": true, "id": "http://100%.json"},
"Remove document");
o.jio.remove({"_id": "http://100%.json"}, {"max_retry": 1}, o.f);
o.clock.tick(1000);
o.server.respond();
o.tick(o);
o.server.restore();
// remove inexistent attachment
o.server = sinon.fakeServer.create();
o.server.respondWith(
"GET",
new RegExp("https://ca-davstorage:8080/http:%252F%252F100%2525_\\.json"),
[
200,
{"Content-Type": "text/plain"},
"{}"
]
);
o.spy(o, "status", 404, "Remove inexistent attachment -> 404");
o.jio.removeAttachment({
"_id": "http://100%.json",
"_attachment": "body.html"
}, {"max_retry": 1}, o.f);
o.clock.tick(1000);
o.server.respond();
o.tick(o);
// o.server.respond();
// o.server.respond();
o.server.restore();
// remove attachment
o.server = sinon.fakeServer.create();
o.server.respondWith(
"GET",
new RegExp("https://ca-davstorage:8080/http:%252F%252F100%2525_\\.json"),
[
200,
{"Content-Type": "text/plain"},
JSON.stringify({
"_attachments": {
"body.html": {
"length": 32,
"digest": "md5-dontcare",
"content_type": "text/html"
}
}
})
]
);
o.server.respondWith(
"PUT",
new RegExp("https://ca-davstorage:8080/http:%252F%252F100%2525_\\.json"),
[
200,
{"Content-Type": "text/html"},
"<h1>OK</h1>"
]
);
o.server.respondWith(
"DELETE",
new RegExp("https://ca-davstorage:8080/" +
"http:%252F%252F100%2525_\\.json.body_\\.html"),
[
200,
{"Content-Type": "text/html"},
"<h1>OK</h1>"
]
);
o.spy(o, "value", {
"ok": true,
"id": "http://100%.json",
"attachment": "body.html"
}, "Remove attachment");
o.jio.removeAttachment({
"_id": "http://100%.json",
"_attachment": "body.html"
}, {"max_retry": 1}, o.f);
o.clock.tick(1000);
o.server.respond();
o.tick(o);
o.server.restore();
// remove document with multiple attachments
o.server = sinon.fakeServer.create();
o.server.respondWith(
"GET",
new RegExp("https://ca-davstorage:8080/http:%252F%252F100%2525_\\.json"),
[
200,
{"Content-Type": "text/html"},
JSON.stringify({
"_attachments": {
"body.html": {
"length": 32,
"digest": "md5-dontcare",
"content_type": "text/html"
},
"other": {
"length": 3,
"digest": "md5-dontcare-again",
"content_type": "text/plain"
}
}
})
]
);
o.server.respondWith(
"DELETE",
new RegExp("https://ca-davstorage:8080/http:%252F%252F100%2525_\\.json"),
[
200,
{"Content-Type": "text/plain"},
"<h1>Deleted</h1>"
]
);
o.server.respondWith(
"DELETE",
new RegExp("https://ca-davstorage:8080/" +
"http:%252F%252F100%2525_\\.json\\.body_\\.html"),
[
200,
{"Content-Type": "text/plain"},
"<h1>Deleted</h1>"
]
);
o.server.respondWith(
"DELETE",
new RegExp("https://ca-davstorage:8080/" +
"http:%252F%252F100%2525_\\.json\\.other"),
[
200,
{"Content-Type": "text/plain"},
"<h1>Deleted</h1>"
]
);
o.spy(o, "value", {"ok": true, "id": "http://100%.json"},
"Remove document containing multiple attachments");
o.jio.remove({"_id": "http://100%.json"}, {"max_retry": 1}, o.f);
o.clock.tick(1000);
o.server.respond();
o.tick(o);
o.server.restore();
util.closeAndcleanUpJio(o.jio);
});
test("AllDocs", function () {
// need to make server requests before activating fakeServer
var davlist, o = generateTools();
davlist = "<?xml version=\"1.0\" encoding=\"utf-8\"?> <D:multist" +
"atus xmlns:D=\"DAV:\"> <D:response xmlns:lp1=\"DAV:\" xmlns:lp2" +
"=\"http://apache.org/dav/props/\"> <D:href>/some/path/</D:href>" +
" <D:propstat> <D:prop> <lp1:resourcetype><D:collection/></lp1:r" +
"esourcetype> <lp1:creationdate>2012-05-02T12:48:33Z</lp1:creati" +
"ondate> <lp1:getlastmodified>Wed, 02 May 2012 12:48:33 GMT</lp1" +
":getlastmodified> <lp1:getetag>\"1000-4bf0d1aeb9e43\"</lp1:gete" +
"tag> <D:supportedlock> <D:lockentry> <D:lockscope><D:exclusive/" +
"></D:lockscope> <D:locktype><D:write/></D:locktype> </D:lockent" +
"ry> <D:lockentry> <D:lockscope><D:shared/></D:lockscope> <D:loc" +
"ktype><D:write/></D:locktype> </D:lockentry> </D:supportedlock>" +
" <D:lockdiscovery/> <D:getcontenttype>httpd/unix-directory</D:g" +
"etcontenttype> </D:prop> <D:status>HTTP/1.1 200 OK</D:status> <" +
"/D:propstat> </D:response> <D:response xmlns:lp1=\"DAV:\" xmlns" +
":lp2=\"http://apache.org/dav/props/\"> <D:href>/some/path/http:" +
"%252F%252F100%2525_.json</D:href> <D:propstat> <D:prop> <lp1:re" +
"sourcetype/> <lp1:creationdate>2012-05-02T12:48:31Z</lp1:creati" +
"ondate> <lp1:getcontentlength>201</lp1:getcontentlength> <lp1:g" +
"etlastmodified>Wed, 02 May 2012 12:48:27 GMT</lp1:getlastmodifi" +
"ed> <lp1:getetag>\"c9-4bf0d1a845df9\"</lp1:getetag> <lp2:execut" +
"able>F</lp2:executable> <D:supportedlock> <D:lockentry> <D:lock" +
"scope><D:exclusive/></D:lockscope> <D:locktype><D:write/></D:lo" +
"cktype> </D:lockentry> <D:lockentry> <D:lockscope><D:shared/></" +
"D:lockscope> <D:locktype><D:write/></D:locktype> </D:lockentry>" +
" </D:supportedlock> <D:lockdiscovery/> </D:prop> <D:status>HTTP" +
"/1.1 200 OK</D:status> </D:propstat> </D:response> <D:response " +
"xmlns:lp1=\"DAV:\" xmlns:lp2=\"http://apache.org/dav/props/\"> " +
"<D:href>/some/path/ISBN:1038729410372</D:href> <D:propstat> <D:" +
"prop> <lp1:resourcetype/> <lp1:creationdate>2012-05-01T17:41:13" +
"Z</lp1:creationdate> <lp1:getcontentlength>223</lp1:getcontentl" +
"ength> <lp1:getlastmodified>Wed, 02 May 2012 10:48:33 GMT</lp1:" +
"getlastmodified> <lp1:getetag>\"c9-4bf0d1aeb9e43\"</lp1:getetag" +
"> <lp2:executable>F</lp2:executable> <D:supportedlock> <D:locke" +
"ntry> <D:lockscope><D:exclusive/></D:lockscope> <D:locktype><D:" +
"write/></D:locktype> </D:lockentry> <D:lockentry> <D:lockscope>" +
"<D:shared/></D:lockscope> <D:locktype><D:write/></D:locktype> <" +
"/D:lockentry> </D:supportedlock> <D:lockdiscovery/> </D:prop> <" +
"D:status>HTTP/1.1 200 OK</D:status> </D:propstat> </D:response>" +
" <D:response xmlns:lp1=\"DAV:\" xmlns:lp2=\"http://apache.org/d" +
"av/props/\"> <D:href>/some/path/http:%252F%252F100%2525_.json.b" +
"ody_.html</D:href> <D:propstat> <D:prop> <lp1:resourcetype/> <l" +
"p1:creationdate>2012-05-01T17:41:13Z</lp1:creationdate> <lp1:ge" +
"tcontentlength>223</lp1:getcontentlength> <lp1:getlastmodified>" +
"Wed, 02 May 2012 10:48:33 GMT</lp1:getlastmodified> <lp1:geteta" +
"g>\"c9-4bf0d1aeb9e43\"</lp1:getetag> <lp2:executable>F</lp2:exe" +
"cutable> <D:supportedlock> <D:lockentry> <D:lockscope><D:exclus" +
"ive/></D:lockscope> <D:locktype><D:write/></D:locktype> </D:loc" +
"kentry> <D:lockentry> <D:lockscope><D:shared/></D:lockscope> <D" +
":locktype><D:write/></D:locktype> </D:lockentry> </D:supportedl" +
"ock> <D:lockdiscovery/> </D:prop> <D:status>HTTP/1.1 200 OK</D:" +
"status> </D:propstat> </D:response> </D:multistatus>";
o.jio = jIO.newJio({
"type": "dav",
"url": "https://ca-davstorage:8080",
"auth_type": "basic",
"username": "admin",
"password": "pwd"
});
// get all documents
o.server = sinon.fakeServer.create();
o.server.respondWith(
"PROPFIND",
new RegExp("https://ca-davstorage:8080/"),
[
200,
{"Content-Type": "text/xml"},
davlist
]
);
o.spy(o, "value", {
"rows": [
{"id": "http://100%.json", "key": "http://100%.json", "value": {}},
{"id": "ISBN:1038729410372", "key": "ISBN:1038729410372", "value": {}}
],
"total_rows": 2
}, "allDocs");
o.jio.allDocs(o.f);
o.clock.tick(1000);
o.server.respond();
o.tick(o);
o.server.restore();
// allDocs with option include_docs
o.server = sinon.fakeServer.create();
o.server.respondWith(
"PROPFIND",
new RegExp("https://ca-davstorage:8080/"),
[
200,
{"Content-Type": "text/xml"},
davlist
]
);
o.doc1 = {"_id": "http://100%.json", "_attachments": {
"body.html": {
"length": 32,
"digest": "md5-doncare",
"content_type": "text/html"
}
}};
o.doc2 = {"_id": "ISBN:1038729410372", "title": "Book Title"};
o.server.respondWith(
"GET",
new RegExp("https://ca-davstorage:8080/http:%252F%252F100%2525_\\.json"),
[
200,
{"Content-Type": "text/plain"},
JSON.stringify(o.doc1)
]
);
o.server.respondWith(
"GET",
new RegExp("https://ca-davstorage:8080/ISBN:1038729410372"),
[
200,
{"Content-Type": "text/plain"},
JSON.stringify(o.doc2)
]
);
o.spy(o, "value", {
"rows": [{
"id": "http://100%.json",
"key": "http://100%.json",
"value": {},
"doc": o.doc1
}, {
"id": "ISBN:1038729410372",
"key": "ISBN:1038729410372",
"value": {},
"doc": o.doc2
}],
"total_rows": 2
}, "allDocs (include_docs)");
o.jio.allDocs({"include_docs": true}, o.f);
o.clock.tick(1000);
o.server.respond();
o.tick(o);
o.server.restore();
util.closeAndcleanUpJio(o.jio);
});
}));
/*jslint indent: 2, maxlen: 80, nomen: true */
/*global define, jIO, jio_tests, test, ok, deepEqual, sinon */
// define([module_name], [dependencies], module);
(function (dependencies, module) {
"use strict";
if (typeof define === 'function' && define.amd) {
return define(dependencies, module);
}
module(jIO, jio_tests);
}(['jio', 'jio_tests', 'localstorage', 'gidstorage'], function (jIO, util) {
"use strict";
function generateTools() {
return {
clock: sinon.useFakeTimers(),
spy: util.ospy,
tick: util.otick
};
}
module("GID Storage");
test("Post", function () {
var o = generateTools(this);
o.localstorage_spec = {
"type": "local",
"username": "one",
"application_name": "gid storage post test"
};
// local jio is going to help us to prepare localstorage for gid tests
o.local_jio = jIO.newJio(o.localstorage_spec);
o.jio = jIO.newJio({
"type": "gid",
"sub_storage": o.localstorage_spec,
"constraints": {
"default": {
"creator": "list"
}
}
});
// preparing localstorage with documents
o.local_jio.put({"_id": "blue", "creator": "a", "title": "earth"});
o.local_jio.put({"_id": "green", "creator": ["ac", "b"], "title": "wind"});
o.clock.tick(2000);
util.closeAndcleanUpJio(o.local_jio);
// Fail to post a document because metadata doesn't respect constraints
// XXX check reason
o.spy(o, 'status', 400, 'Post document without respecting constraints ' +
'-> bad request');
o.jio.post({}, o.f);
o.tick(o);
// Fail to post a document but a document already exists
o.spy(o, 'status', 409, 'Post existent document -> conflict');
o.jio.post({"creator": "a", "title": "water"}, o.f);
o.tick(o);
// Succeed to post because no document with the same gid has been found
o.spy(o, 'value', {
"id": "{\"creator\":[\"a%\"]}",
"ok": true
}, 'Post respecting constraints');
o.jio.post({"creator": "a%", "title": "fire"}, o.f);
o.tick(o);
// Fail to post because this document has been uploaded right before
o.spy(o, 'status', 409, 'Post same document respecting constraints ' +
'-> conflicts');
o.jio.post({"creator": "a%", "title": "space"}, o.f);
o.tick(o);
util.closeAndcleanUpJio(o.jio);
});
test("Get", function () {
var o = generateTools(this);
o.localstorage_spec = {
"type": "local",
"username": "one",
"application_name": "gid storage get test"
};
// local jio is going to help us to prepare localstorage for gid tests
o.local_jio = jIO.newJio(o.localstorage_spec);
o.jio = jIO.newJio({
"type": "gid",
"sub_storage": o.localstorage_spec,
"constraints": {
"default": {
"creator": "list"
}
}
});
// preparing localstorage with documents
o.local_jio.put({"_id": "blue", "creator": "a", "title": "earth"});
o.local_jio.put({"_id": "red", "creator": ["ac", "b"], "title": "wind"});
o.clock.tick(2000);
util.closeAndcleanUpJio(o.local_jio);
// Fail to get document because _id doesn't respect constraints
o.spy(o, 'status', 400, 'Get document without respecting constraints ' +
'-> bad request');
o.jio.get({"_id": "a"}, o.f);
o.tick(o);
// Fail to get because no document with the same gid has been found
o.spy(o, 'status', 404, 'Get inexistent document');
o.jio.get({"_id": "{\"creator\":[\"c\"]}"}, o.f);
o.tick(o);
// Succeed to get, gid is good, document found
o.spy(o, 'value', {
"_id": "{\"creator\":[\"b\"]}",
"creator": ["ac", "b"],
"title": "wind"
}, 'Get document');
o.jio.get({"_id": "{\"creator\":[\"b\"]}"}, o.f);
o.tick(o);
util.closeAndcleanUpJio(o.jio);
});
test("AllDocs", function () {
var o = generateTools(this);
o.localstorage_spec = {
"type": "local",
"username": "one",
"application_name": "gid storage allDocs test"
};
// local jio is going to help us to prepare localstorage for gid tests
o.local_jio = jIO.newJio(o.localstorage_spec);
o.jio = jIO.newJio({
"type": "gid",
"sub_storage": o.localstorage_spec,
"constraints": {
"default": {
"creator": "list"
}
}
});
// preparing localstorage with documents
o.local_jio.put({"_id": "green", "creator": ["a"], "title": "earth"});
o.local_jio.put({"_id": "red", "creator": ["a", "b"], "title": "water"});
o.local_jio.put({"_id": "yellow", "creator": ["c", "d"], "title": "wind"});
o.local_jio.put({"_id": "purple", "creator": ["s", "d"], "title": "fire"});
o.local_jio.put({"_id": "blue", "title": "space"});
o.clock.tick(3000);
util.closeAndcleanUpJio(o.local_jio);
// Get all document and sort to make comparison easier
o.spy(o, 'value', {
"rows": [{
"id": "{\"creator\":[\"a\"]}",
"value": {}
}, {
"id": "{\"creator\":[\"a\",\"b\"]}",
"value": {}
}, {
"id": "{\"creator\":[\"c\",\"d\"]}",
"value": {}
}, {
"id": "{\"creator\":[\"s\",\"d\"]}",
"value": {}
}],
"total_rows": 4
}, 'Get all docs');
o.jio.allDocs({
"sort_on": [["creator", "ascending"]]
}, o.f);
o.tick(o);
// Get all document with complex queries
o.spy(o, 'value', {
"rows": [{
"id": "{\"creator\":[\"s\",\"d\"]}",
"value": {"creator": ["s", "d"]}
}],
"total_rows": 1
}, 'Get all docs with complex query');
o.jio.allDocs({
"query": 'creator: "d"',
"select_list": ["creator"],
"limit": [1, 1],
"sort_on": [["creator", "ascending"]]
}, o.f);
o.tick(o);
util.closeAndcleanUpJio(o.jio);
});
test("Put", function () {
var o = generateTools(this);
o.localstorage_spec = {
"type": "local",
"username": "one",
"application_name": "gid storage put test"
};
// local jio is going to help us to prepare localstorage for gid tests
o.local_jio = jIO.newJio(o.localstorage_spec);
o.jio = jIO.newJio({
"type": "gid",
"sub_storage": o.localstorage_spec,
"constraints": {
"default": {
"creator": "list"
}
}
});
// preparing localstorage with documents
o.local_jio.put({"_id": "blue", "creator": "a", "title": "earth"});
o.local_jio.put({"_id": "green", "creator": ["ac", "b"], "title": "wind"});
o.clock.tick(2000);
// Fail to put document because id does not respect constraints
o.spy(o, 'status', 400, 'Put document without respecting constraints ' +
'-> bad request');
o.jio.put({"_id": "a", "creator": "a", "title": "fire"}, o.f);
o.tick(o);
// Fail to put because gid given != gid generated by the constraints
o.spy(o, 'status', 400, 'Put document without respecting constraints ' +
'-> bad request');
o.jio.put({
"_id": "{\"creator\":[\"a\"]}",
"creator": "b",
"title": "water"
}, o.f);
o.tick(o);
// Succeed to update a document with its gid
o.spy(o, 'value', {
"ok": true,
"id": "{\"creator\":[\"a\"]}"
}, 'Update document');
o.jio.put({
"_id": "{\"creator\":[\"a\"]}",
"creator": "a",
"title": "space"
}, o.f);
o.tick(o);
// Succeed to create a document, the gid given is good
o.spy(o, 'value', {
"ok": true,
"id": "{\"creator\":[\"c\"]}"
}, 'Create document');
o.jio.put({
"_id": "{\"creator\":[\"c\"]}",
"creator": "c",
"title": "magma"
}, o.f);
o.tick(o);
// Check if the local storage document is well updated to make sure the
// second put did not update the wrong document.
o.spy(o, 'value', {
"_id": "blue",
"creator": "a",
"title": "space"
}, "Check sub documents");
o.local_jio.get({"_id": "blue"}, o.f);
o.tick(o);
util.closeAndcleanUpJio(o.local_jio);
util.closeAndcleanUpJio(o.jio);
});
test("Remove", function () {
var o = generateTools(this);
o.localstorage_spec = {
"type": "local",
"username": "one",
"application_name": "gid storage remove test"
};
// local jio is going to help us to prepare localstorage for gid tests
o.local_jio = jIO.newJio(o.localstorage_spec);
o.jio = jIO.newJio({
"type": "gid",
"sub_storage": o.localstorage_spec,
"constraints": {
"default": {
"creator": "list"
}
}
});
// preparing localstorage with documents
o.local_jio.put({"_id": "blue", "creator": "a", "title": "earth"});
o.local_jio.put({"_id": "green", "creator": ["ac", "b"], "title": "wind"});
o.clock.tick(2000);
util.closeAndcleanUpJio(o.local_jio);
// Fail to remove document because given gid does not respect constraints
o.spy(o, 'status', 400, 'Remove document without respecting constraints ' +
'-> bad request');
o.jio.remove({"_id": "a"}, o.f);
o.tick(o);
// Succeed to remove
o.spy(o, 'value', {
"ok": true,
"id": "{\"creator\":[\"b\"]}"
}, 'Remove document');
o.jio.remove({
"_id": "{\"creator\":[\"b\"]}"
}, o.f);
o.tick(o);
// Fail to remove the same document. This test checks also that only one
// document matches the gid constraints
o.spy(o, 'status', 404, 'Remove inexistent document');
o.jio.remove({
"_id": "{\"creator\":[\"b\"]}"
}, o.f);
o.tick(o);
util.closeAndcleanUpJio(o.jio);
});
test("putAttachment", function () {
var o = generateTools(this);
o.localstorage_spec = {
"type": "local",
"username": "one",
"application_name": "gid storage put attachment test"
};
// local jio is going to help us to prepare localstorage for gid tests
o.local_jio = jIO.newJio(o.localstorage_spec);
o.jio = jIO.newJio({
"type": "gid",
"sub_storage": o.localstorage_spec,
"constraints": {
"default": {
"creator": "list"
}
}
});
// preparing localstorage with documents
o.local_jio.put({"_id": "blue", "creator": "a", "title": "earth"});
o.local_jio.put({"_id": "green", "creator": ["ac", "b"], "title": "wind"});
o.clock.tick(2000);
// Fail to put attachment because given gid doesn't respect constraints
o.spy(o, 'status', 400, 'put attachment without respecting constraints ' +
'-> bad request');
o.jio.putAttachment({
"_id": "a",
"_attachment": "body",
"_data": "abc",
"_mimetype": "text/plain"
}, o.f);
o.tick(o);
// Succeed to put an attachment to a document
o.spy(o, 'value', {
"ok": true,
"id": "{\"creator\":[\"b\"]}",
"attachment": "body"
}, 'put attachment');
o.jio.putAttachment({
"_id": "{\"creator\":[\"b\"]}",
"_attachment": "body",
"_data": "abc",
"_mimetype": "text/plain"
}, o.f);
o.tick(o);
// Check if the local storage document really have the new attachment
o.spy(o, 'value', "abc", "Check attachment");
o.local_jio.getAttachment({"_id": "green", "_attachment": "body"}, o.f);
o.tick(o);
// Succeed to update an attachment
o.spy(o, 'value', {
"ok": true,
"id": "{\"creator\":[\"b\"]}",
"attachment": "body"
}, 'put attachment');
o.jio.putAttachment({
"_id": "{\"creator\":[\"b\"]}",
"_attachment": "body",
"_data": "def",
"_mimetype": "text/plain"
}, o.f);
o.tick(o);
// Check if the local storage attachment really changed
o.spy(o, 'value', "def", "Check attachment");
o.local_jio.getAttachment({"_id": "green", "_attachment": "body"}, o.f);
o.tick(o);
util.closeAndcleanUpJio(o.local_jio);
util.closeAndcleanUpJio(o.jio);
});
test("getAttachment", function () {
var o = generateTools(this);
o.localstorage_spec = {
"type": "local",
"username": "one",
"application_name": "gid storage get attachment test"
};
// local jio is going to help us to prepare localstorage for gid tests
o.local_jio = jIO.newJio(o.localstorage_spec);
o.jio = jIO.newJio({
"type": "gid",
"sub_storage": o.localstorage_spec,
"constraints": {
"default": {
"creator": "list"
}
}
});
// preparing localstorage with documents
o.local_jio.put({"_id": "blue", "creator": "a", "title": "earth"});
o.local_jio.put({"_id": "green", "creator": ["ac", "b"], "title": "wind"});
o.clock.tick(2000);
// Fail to get attachment because given gid doesn't respect constraints
o.spy(o, 'status', 400, 'get attachment without respecting constraints ' +
'-> bad request');
o.jio.getAttachment({
"_id": "a",
"_attachment": "body"
}, o.f);
o.tick(o);
// Fail to get an inexistent attachment from a document
o.spy(o, 'status', 404, 'Get inexistent attachment');
o.jio.getAttachment({
"_id": "{\"creator\":[\"a\"]}",
"_attachment": "body"
}, o.f);
o.tick(o);
// Add an attachment manually to the document 'blue'
o.local_jio.putAttachment({
"_id": "blue",
"_attachment": "body",
"_data": "lol",
"_mimetype": "text/plain"
});
o.clock.tick(2000);
util.closeAndcleanUpJio(o.local_jio);
// Succeed to get the previous attachment
o.spy(o, 'value', "lol", 'Get attachment');
o.jio.getAttachment({
"_id": "{\"creator\":[\"a\"]}",
"_attachment": "body"
}, o.f);
o.tick(o);
util.closeAndcleanUpJio(o.jio);
});
test("removeAttachment", function () {
var o = generateTools(this);
o.localstorage_spec = {
"type": "local",
"username": "one",
"application_name": "gid storage remove attachment test"
};
// local jio is going to help us to prepare localstorage for gid tests
o.local_jio = jIO.newJio(o.localstorage_spec);
o.jio = jIO.newJio({
"type": "gid",
"sub_storage": o.localstorage_spec,
"constraints": {
"default": {
"creator": "list"
}
}
});
// preparing localstorage with documents
o.local_jio.put({"_id": "blue", "creator": "a", "title": "earth"});
o.local_jio.put({"_id": "green", "creator": ["ac", "b"], "title": "wind"});
o.clock.tick(2000);
o.local_jio.putAttachment({
"_id": "blue",
"_attachment": "body",
"_data": "lol",
"_mimetype": "text/plain"
});
o.clock.tick(2000);
// Fail to remove attachment because given gid doesn't respect constraints
o.spy(o, 'status', 400, 'Remove attachment without respecting ' +
'constraints -> bad request');
o.jio.removeAttachment({
"_id": "a",
"_attachment": "body",
"_data": "abc",
"_mimetype": "text/plain"
}, o.f);
o.tick(o);
// Succeed to remove an attachment from a document
o.spy(o, 'value', {
"ok": true,
"id": "{\"creator\":[\"a\"]}",
"attachment": "body"
}, 'Remove attachment');
o.jio.removeAttachment({
"_id": "{\"creator\":[\"a\"]}",
"_attachment": "body"
}, o.f);
o.tick(o);
// Check if the local storage document doesn't have attachment anymore
o.spy(o, 'status', 404, "Check attachment");
o.local_jio.getAttachment({"_id": "green", "_attachment": "body"}, o.f);
o.tick(o);
// Fail to remove the same attachment because it's already removed
o.spy(o, 'status', 404, 'Remove attachment');
o.jio.removeAttachment({
"_id": "{\"creator\":[\"b\"]}",
"_attachment": "body",
"_data": "def",
"_mimetype": "text/plain"
}, o.f);
o.tick(o);
util.closeAndcleanUpJio(o.local_jio);
util.closeAndcleanUpJio(o.jio);
});
test("More Constraints", function () {
// This test will use gid storage in a 'real case'
var o = generateTools(this);
o.localstorage_spec = {
"type": "local",
"username": "one",
"application_name": "gid storage more constraints test"
};
o.jio = jIO.newJio({
"type": "gid",
"sub_storage": o.localstorage_spec,
"constraints": {
"default": {
"type": "DCMIType",
"title": "string"
},
"Text": {
"date": "date",
"language": "string"
},
"Image": {
"format": "contentType"
}
}
});
// Post a text document. This test also checks if the gid is well
// created. Indeed, the json string "id" of the response is a dict with keys
// inserted in alphabetic order, so that a gid is universal. It also checks
// document types list management. It checks 'string', 'DCMIType' and 'date'
// metadata types.
o.spy(o, 'value', {
"ok": true,
"id": "{\"date\":\"2012-12-12\",\"language\":\"fr\"," +
"\"title\":\"Texte pour ce test\",\"type\":\"Text\"}"
}, 'Post a text document');
o.jio.post({
"type": ["Text", "web page"],
"title": {"lang": "fr", "content": "Texte pour ce test"},
"date": "2012-12-12",
"modified": "2012-12-12",
"format": "text/html",
"language": "fr"
}, o.f);
o.tick(o);
// Put the associated attachment
o.spy(o, 'value', {
"ok": true,
"id": "{\"date\":\"2012-12-12\",\"language\":\"fr\"," +
"\"title\":\"Texte pour ce test\",\"type\":\"Text\"}",
"attachment": "body"
}, 'Put text content as body');
o.jio.putAttachment({
"_id": "{\"date\":\"2012-12-12\",\"language\":\"fr\"," +
"\"title\":\"Texte pour ce test\",\"type\":\"Text\"}",
"_attachment": "body",
"_data": "<h1>Mon document html.</h1>",
"_mimetype": "text/html"
}, o.f);
o.tick(o);
// Post an image. It checks 'string', 'DCMIType' and 'contentType' metadata
// types.
o.spy(o, 'value', {
"ok": true,
"id": "{\"format\":\"text/svg+xml\"," +
"\"title\":\"My image title\",\"type\":\"Image\"}"
}, 'Post an image document');
o.jio.post({
"type": "Image",
"title": "My image title",
"date": "2012-12-13",
"modified": "2012-12-13",
"format": "text/svg+xml"
}, o.f);
o.tick(o);
// Put the associated attachment
o.spy(o, 'value', {
"ok": true,
"id": "{\"format\":\"text/svg+xml\"," +
"\"title\":\"My image title\",\"type\":\"Image\"}",
"attachment": "body"
}, 'Put text content as body');
o.jio.putAttachment({
"_id": "{\"format\":\"text/svg+xml\"," +
"\"title\":\"My image title\",\"type\":\"Image\"}",
"_attachment": "body",
"_data": "<svg/>",
"_mimetype": "text/svg+xml"
}, o.f);
o.tick(o);
// Get the html document
o.spy(o, 'value', {
"_id": "{\"date\":\"2012-12-12\",\"language\":\"fr\"," +
"\"title\":\"Texte pour ce test\",\"type\":\"Text\"}",
"type": ["Text", "web page"],
"title": {"lang": "fr", "content": "Texte pour ce test"},
"date": "2012-12-12",
"modified": "2012-12-12",
"format": "text/html",
"language": "fr",
"_attachments": {
"body": {
"length": 27,
"digest": "md5-6f40c762ca7a8fac52567f12ce5441ef",
"content_type": "text/html"
}
}
}, "Get html metadata");
o.jio.get({
"_id": "{\"date\":\"2012-12-12\",\"language\":\"fr\"," +
"\"title\":\"Texte pour ce test\",\"type\":\"Text\"}",
}, o.f);
o.tick(o);
// Get a list of documents
o.spy(o, 'value', {
"rows": [{
"id": "{\"format\":\"text/svg+xml\"," +
"\"title\":\"My image title\",\"type\":\"Image\"}",
"value": {}
}, {
"id": "{\"date\":\"2012-12-12\",\"language\":\"fr\"," +
"\"title\":\"Texte pour ce test\",\"type\":\"Text\"}",
"value": {}
}],
"total_rows": 2
}, 'Get a document list');
o.jio.allDocs({"sort_on": [["title", "ascending"]]}, o.f);
o.tick(o);
util.closeAndcleanUpJio(o.jio);
});
}));
/*jslint indent: 2, maxlen: 80, nomen: true */
/*global define, jIO, jio_tests, test, ok, deepEqual, sinon */
// define([module_name], [dependencies], module);
(function (dependencies, module) {
"use strict";
if (typeof define === 'function' && define.amd) {
return define(dependencies, module);
}
module(jIO, jio_tests);
}(['jio', 'jio_tests', 'localstorage', 'indexstorage'], function (jIO, util) {
"use strict";
function generateTools() {
return {
clock: sinon.useFakeTimers(),
spy: util.ospy,
tick: util.otick
};
}
module("IndexStorage");
test("Post", function () {
var o = generateTools();
o.jio = jIO.newJio({
"type": "indexed",
"indices": [
{"id": "A", "index": ["title"]},
{"id": "B", "index": ["title", "year"]}
],
"sub_storage": {
"type": "local",
"username": "ipost",
"application_name": "ipost"
}
});
o.getAttachmentCallback = function (err, response) {
if (response) {
try {
response = JSON.parse(response);
} catch (e) {
response = "PARSE ERROR " + response;
}
}
o.f(err, response);
};
// post without id
o.spy(o, "jobstatus", "done", "Post without id");
o.jio.post({}, function (err, response) {
o.id = (response || {}).id;
o.f(err, response);
});
o.tick(o);
// post non empty document
o.doc = {"_id": "some_id", "title": "My Title",
"year": 2000, "hey": "def"};
o.spy(o, "value", {"ok": true, "id": "some_id"}, "Post document");
o.jio.post(o.doc, o.f);
o.tick(o);
// check document
o.fakeIndexA = {
"indexing": ["title"],
"free": [],
"location": {
"some_id": 0
},
"database": [
{"_id": "some_id", "title": "My Title"}
]
};
o.spy(o, "value", o.fakeIndexA, "Check index file");
o.jio.getAttachment({
"_id": "A",
"_attachment": "body"
}, o.getAttachmentCallback);
o.tick(o);
o.fakeIndexB = {
"indexing": ["title", "year"],
"free": [],
"location": {
"some_id": 0
},
"database": [
{"_id": "some_id", "title": "My Title", "year": 2000}
]
};
o.spy(o, "value", o.fakeIndexB, "Check index file");
o.jio.getAttachment({
"_id": "B",
"_attachment": "body"
}, o.getAttachmentCallback);
o.tick(o);
// post with escapable characters
o.doc = {
"_id": "other_id",
"title": "myPost2",
"findMeA": "keyword_*§$%&/()=?",
"findMeB": "keyword_|ð@ł¶đæðſæðæſ³"
};
o.spy(o, "value", {"ok": true, "id": "other_id"},
"Post with escapable characters");
o.jio.post(o.doc, o.f);
o.tick(o);
// post and document already exists
o.doc = {
"_id": "some_id",
"title": "myPost3",
"findMeA": "keyword_ghi",
"findMeB": "keyword_jkl"
};
o.spy(o, "status", 409, "Post and document already exists");
o.jio.post(o.doc, o.f);
o.tick(o);
util.closeAndcleanUpJio(o.jio);
});
test("Put", function () {
var o = generateTools();
o.jio = jIO.newJio({
"type": "indexed",
"indices": [
{"id": "A", "index": ["author"]},
{"id": "B", "index": ["year"]}
],
"sub_storage": {
"type": "local",
"username": "iput",
"application_name": "iput"
}
});
o.getAttachmentCallback = function (err, response) {
if (response) {
try {
response = JSON.parse(response);
} catch (e) {
response = "PARSE ERROR " + response;
}
}
o.f(err, response);
};
// put without id
// error 20 -> document id required
o.spy(o, "status", 20, "Put without id");
o.jio.put({}, o.f);
o.tick(o);
// put non empty document
o.doc = {"_id": "put1", "title": "myPut1", "author": "John Doe"};
o.spy(o, "value", {"ok": true, "id": "put1"}, "Put-create document");
o.jio.put(o.doc, o.f);
o.tick(o);
// check index file
o.fakeIndexA = {
"indexing": ["author"],
"free": [],
"location": {
"put1": 0
},
"database": [{"_id": "put1", "author": "John Doe"}]
};
o.spy(o, "value", o.fakeIndexA, "Check index file");
o.jio.getAttachment({
"_id": "A",
"_attachment": "body"
}, o.getAttachmentCallback);
o.tick(o);
o.fakeIndexB = {
"indexing": ["year"],
"free": [],
"location": {},
"database": []
};
o.spy(o, "value", o.fakeIndexB, "Check index file");
o.jio.getAttachment({
"_id": "B",
"_attachment": "body"
}, o.getAttachmentCallback);
o.tick(o);
// modify document - modify keyword on index!
o.doc = {"_id": "put1", "title": "myPuttter1", "author": "Jane Doe"};
o.spy(o, "value", {"ok": true, "id": "put1"}, "Modify existing document");
o.jio.put(o.doc, o.f);
o.tick(o);
// check index file
o.fakeIndexA.database[0].author = "Jane Doe";
o.spy(o, "value", o.fakeIndexA, "Check index file");
o.jio.getAttachment({
"_id": "A",
"_attachment": "body"
}, o.getAttachmentCallback);
o.tick(o);
// add new document with same keyword!
o.doc = {"_id": "new_doc", "title": "myPut2", "author": "Jane Doe"};
o.spy(o, "value", {"ok": true, "id": "new_doc"},
"Add new document with same keyword");
o.jio.put(o.doc, o.f);
o.tick(o);
// check index file
o.fakeIndexA.location.new_doc = 1;
o.fakeIndexA.database.push({"_id": "new_doc", "author": "Jane Doe"});
o.spy(o, "value", o.fakeIndexA, "Check index file");
o.jio.getAttachment({
"_id": "A",
"_attachment": "body"
}, o.getAttachmentCallback);
o.tick(o);
// add second keyword to index file
o.doc = {"_id": "put1", "title": "myPut2", "author": "Jane Doe",
"year": "1912"};
o.spy(o, "value", {"ok": true, "id": "put1"},
"add second keyword to index file");
o.jio.put(o.doc, o.f);
o.tick(o);
// check index file
o.spy(o, "value", o.fakeIndexA, "Check index file");
o.jio.getAttachment({
"_id": "A",
"_attachment": "body"
}, o.getAttachmentCallback);
o.tick(o);
o.fakeIndexB.location.put1 = 0;
o.fakeIndexB.database.push({"_id": "put1", "year": "1912"});
o.spy(o, "value", o.fakeIndexB, "Check index file");
o.jio.getAttachment({
"_id": "B",
"_attachment": "body"
}, o.getAttachmentCallback);
o.tick(o);
// remove a keyword from an existing document
o.doc = {"_id": "new_doc", "title": "myPut2"};
o.spy(o, "value", {"ok": true, "id": "new_doc"},
"Remove keyword from existing document");
o.jio.put(o.doc, o.f);
o.tick(o);
// check index file
delete o.fakeIndexA.location.new_doc;
o.fakeIndexA.database[1] = null;
o.fakeIndexA.free.push(1);
o.spy(o, "value", o.fakeIndexA, "Check index file");
o.jio.getAttachment({
"_id": "A",
"_attachment": "body"
}, o.getAttachmentCallback);
o.tick(o);
util.closeAndcleanUpJio(o.jio);
});
test("Check & Repair", function () {
var o = generateTools(), i;
o.jio = jIO.newJio({
"type": "indexed",
"indices": [
{"id": "A", "index": ["director"]},
{"id": "B", "index": ["year"]}
],
"sub_storage": {
"type": "local",
"username": "indexstoragerepair"
}
});
o.getAttachmentCallback = function (err, response) {
if (response) {
try {
response = JSON.parse(response);
} catch (e) {
response = "PARSE ERROR " + response;
}
delete response.location;
response.database.sort(function (a, b) {
return a._id < b._id ? -1 : a._id > b._id ? 1 : 0;
});
}
o.f(err, response);
};
o.fakeIndexA = {
"indexing": ["director"],
"free": [],
"database": []
};
o.fakeIndexB = {
"indexing": ["year"],
"free": [],
"database": []
};
for (i = 0; i < 10; i += 1) {
o.jio.put({
"_id": "id" + i,
"director": "D" + i,
"year": i,
"title": "T" + i
});
o.tmp = o.fakeIndexA.free.pop() || o.fakeIndexA.database.length;
o.fakeIndexA.database[o.tmp] = {"_id": "id" + i, "director": "D" + i};
o.tmp = o.fakeIndexB.free.pop() || o.fakeIndexB.database.length;
o.fakeIndexB.database[o.tmp] = {"_id": "id" + i, "year": i};
}
o.clock.tick(5000);
o.spy(o, "status", 40, "Check database");
o.jio.check({"_id": "A"}, o.f);
o.tick(o);
o.spy(o, "status", 40, "Check database");
o.jio.check({"_id": "B"}, o.f);
o.tick(o);
o.spy(o, "value", {"id": "A", "ok": true}, "Repair database");
o.jio.repair({"_id": "A"}, o.f);
o.tick(o);
o.spy(o, "value", {"id": "B", "ok": true}, "Repair database");
o.jio.repair({"_id": "B"}, o.f);
o.tick(o);
o.spy(o, "value", {"id": "A", "ok": true}, "Check database again");
o.jio.check({"_id": "A"}, o.f);
o.tick(o);
o.spy(o, "value", {"id": "B", "ok": true}, "Check database again");
o.jio.check({"_id": "B"}, o.f);
o.tick(o);
// check index file
o.spy(o, "value", o.fakeIndexA, "Manually check index file");
o.jio.getAttachment({
"_id": "A",
"_attachment": "body"
}, o.getAttachmentCallback);
o.tick(o);
o.spy(o, "value", o.fakeIndexB, "Manually check index file");
o.jio.getAttachment({
"_id": "B",
"_attachment": "body"
}, o.getAttachmentCallback);
o.tick(o);
o.jio2 = jIO.newJio({"type": "local", "username": "indexstoragerepair"});
o.jio2.put({"_id": "blah", "title": "t", "year": "y", "director": "d"});
o.clock.tick(1000);
util.closeAndcleanUpJio(o.jio2);
o.fakeIndexA.database.unshift({"_id": "blah", "director": "d"});
o.fakeIndexB.database.unshift({"_id": "blah", "year": "y"});
o.spy(o, "status", 40, "Check Document");
o.jio.check({"_id": "blah"}, o.f);
o.tick(o);
o.spy(o, "value", {"id": "blah", "ok": true}, "Repair Document");
o.jio.repair({"_id": "blah"}, o.f);
o.tick(o);
o.spy(o, "value", {"id": "blah", "ok": true}, "Check Document again");
o.jio.repair({"_id": "blah"}, o.f);
o.tick(o);
// check index file
o.spy(o, "value", o.fakeIndexA, "Manually check index file");
o.jio.getAttachment({
"_id": "A",
"_attachment": "body"
}, o.getAttachmentCallback);
o.tick(o);
o.spy(o, "value", o.fakeIndexB, "Manually check index file");
o.jio.getAttachment({
"_id": "B",
"_attachment": "body"
}, o.getAttachmentCallback);
o.tick(o);
util.closeAndcleanUpJio(o.jio);
});
test("PutAttachment", function () {
// not sure these need to be run, because the index does not change
// and only small modifications have been made to handle putAttachment
// tests are from localStorage putAttachment
var o = generateTools();
o.jio = jIO.newJio({
"type": "indexed",
"indices": [
{"id": "A", "index": ["author"]},
{"id": "B", "index": ["year"]}
],
"sub_storage": {
"type": "local",
"username": "iputatt",
"application_name": "iputatt"
}
});
// putAttachment without doc id
// error 20 -> document id required
o.spy(o, "status", 20, "PutAttachment without doc id");
o.jio.putAttachment({}, o.f);
o.tick(o);
// putAttachment without attachment id
// error 22 -> attachment id required
o.spy(o, "status", 22, "PutAttachment without attachment id");
o.jio.putAttachment({"_id": "putattmt1"}, o.f);
o.tick(o);
// putAttachment without document
// error 404 -> not found
o.spy(o, "status", 404, "PutAttachment without document");
o.jio.putAttachment({"_id": "putattmt1", "_attachment": "putattmt2"}, o.f);
o.tick(o);
// putAttachment with document
o.doc = {"_id": "putattmt1", "title": "myPutAttmt1"};
o.spy(o, "value", {"ok": true, "id": "putattmt1"},
"Put underlying document");
o.jio.put(o.doc, o.f);
o.tick(o);
o.spy(o, "value", {
"ok": true,
"id": "putattmt1",
"attachment": "putattmt2"
}, "PutAttachment with document, without data");
o.jio.putAttachment({"_id": "putattmt1", "_attachment": "putattmt2"}, o.f);
o.tick(o);
// check document
deepEqual(util.jsonlocalstorage.getItem(
"jio/localstorage/iputatt/iputatt/putattmt1"
), {
"_id": "putattmt1",
"title": "myPutAttmt1",
"_attachments": {
"putattmt2": {
"length": 0,
// md5("")
"digest": "md5-d41d8cd98f00b204e9800998ecf8427e"
}
}
}, "Check document");
// check attachment
deepEqual(util.jsonlocalstorage.getItem(
"jio/localstorage/iputatt/iputatt/putattmt1/putattmt2"
), "", "Check attachment");
// update attachment
o.spy(o, "value",
{"ok": true, "id": "putattmt1", "attachment": "putattmt2"},
"Update Attachment, with data");
o.jio.putAttachment({
"_id": "putattmt1",
"_attachment": "putattmt2",
"_data": "abc"
}, o.f);
o.tick(o);
// check document
deepEqual(util.jsonlocalstorage.getItem(
"jio/localstorage/iputatt/iputatt/putattmt1"
), {
"_id": "putattmt1",
"title": "myPutAttmt1",
"_attachments": {
"putattmt2": {
"length": 3,
// md5("abc")
"digest": "md5-900150983cd24fb0d6963f7d28e17f72"
}
}
}, "Check document");
// check attachment
deepEqual(util.jsonlocalstorage.getItem(
"jio/localstorage/iputatt/iputatt/putattmt1/putattmt2"
), "abc", "Check attachment");
util.closeAndcleanUpJio(o.jio);
});
test("Get", function () {
// not sure these need to be run, because the index does not change
// and only small modifications have been made to handle putAttachment
// tests are from localStorage putAttachment
var o = generateTools();
o.jio = jIO.newJio({
"type": "indexed",
"indices": [
{"id": "A", "index": ["author"]},
{"id": "B", "index": ["year"]}
],
"sub_storage": {
"type": "local",
"username": "iget",
"application_name": "iget"
}
});
// get inexistent document
o.spy(o, "status", 404, "Get inexistent document");
o.jio.get({"_id": "get1"}, o.f);
o.tick(o);
// get inexistent attachment
o.spy(o, "status", 404, "Get inexistent attachment");
o.jio.getAttachment({"_id": "get1", "_attachment": "get2"}, o.f);
o.tick(o);
// adding a document
o.doc_get1 = {
"_id": "get1",
"title": "myGet1"
};
util.jsonlocalstorage.setItem(
"jio/localstorage/iget/iget/get1",
o.doc_get1
);
// get document
o.spy(o, "value", o.doc_get1, "Get document");
o.jio.get({"_id": "get1"}, o.f);
o.tick(o);
// get inexistent attachment (document exists)
o.spy(o, "status", 404, "Get inexistent attachment (document exists)");
o.jio.getAttachment({"_id": "get1", "_attachment": "get2"}, o.f);
o.tick(o);
// adding an attachment
o.doc_get1._attachments = {
"get2": {
"length": 2,
// md5("de")
"digest": "md5-5f02f0889301fd7be1ac972c11bf3e7d"
}
};
util.jsonlocalstorage.setItem(
"jio/localstorage/iget/iget/get1",
o.doc_get1
);
util.jsonlocalstorage.setItem("jio/localstorage/iget/iget/get1/get2", "de");
// get attachment
o.spy(o, "value", "de", "Get attachment");
o.jio.getAttachment({"_id": "get1", "_attachment": "get2"}, o.f);
o.tick(o);
util.closeAndcleanUpJio(o.jio);
});
test("Remove", function () {
// not sure these need to be run, because the index does not change
// and only small modifications have been made to handle putAttachment
// tests are from localStorage putAttachment
var o = generateTools();
o.jio = jIO.newJio({
"type": "indexed",
"indices": [
{"id": "A", "index": ["author"]},
{"id": "B", "index": ["year"]}
],
"sub_storage": {
"type": "local",
"username": "irem",
"application_name": "irem"
}
});
o.getAttachmentCallback = function (err, response) {
if (response) {
try {
response = JSON.parse(response);
} catch (e) {
response = "PARSE ERROR " + response;
}
}
o.f(err, response);
};
// remove inexistent document
o.spy(o, "status", 404, "Remove inexistent document");
o.jio.remove({"_id": "remove1"}, o.f);
o.tick(o);
// remove inexistent document/attachment
o.spy(o, "status", 404, "Remove inexistent attachment");
o.jio.removeAttachment({"_id": "remove1", "_attachment": "remove2"}, o.f);
o.tick(o);
// adding a document
o.jio.put({"_id": "remove1", "title": "myRemove1",
"author": "Mr. President", "year": "2525"
});
o.tick(o);
// adding a 2nd document with same keywords
o.jio.put({"_id": "removeAlso", "title": "myRemove2",
"author": "Martin Mustermann", "year": "2525"
});
o.tick(o);
// remove document
o.spy(o, "value", {"ok": true, "id": "remove1"}, "Remove document");
o.jio.remove({"_id": "remove1"}, o.f);
o.tick(o);
// check index
o.fakeIndexA = {
"indexing": ["author"],
"free": [0],
"location": {
"removeAlso": 1
},
"database": [null, {"_id": "removeAlso", "author": "Martin Mustermann"}]
};
o.spy(o, "value", o.fakeIndexA, "Check index file");
o.jio.getAttachment({
"_id": "A",
"_attachment": "body"
}, o.getAttachmentCallback);
o.tick(o);
o.fakeIndexB = {
"indexing": ["year"],
"free": [0],
"location": {
"removeAlso": 1
},
"database": [null, {"_id": "removeAlso", "year": "2525"}]
};
o.spy(o, "value", o.fakeIndexB, "Check index file");
o.jio.getAttachment({
"_id": "B",
"_attachment": "body"
}, o.getAttachmentCallback);
o.tick(o);
// check document
o.spy(o, "status", 404, "Check if document has been removed");
o.jio.get({"_id": "remove1"}, o.f);
o.tick(o);
// adding a new document
o.jio.put({"_id": "remove3",
"title": "myRemove1",
"author": "Mrs Sunshine",
"year": "1234"
});
o.tick(o);
// adding an attachment
o.jio.putAttachment({
"_id": "remove3",
"_attachment": "removeAtt",
"_mimetype": "text/plain",
"_data": "hello"
});
o.tick(o);
// add another attachment
o.jio.putAttachment({
"_id": "remove3",
"_attachment": "removeAtt2",
"_mimetype": "text/plain",
"_data": "hello2"
});
o.tick(o);
// remove attachment
o.spy(o, "value", {"ok": true, "id": "remove3", "attachment": "removeAtt2"},
"Remove one of multiple attachment");
o.jio.removeAttachment({
"_id": "remove3",
"_attachment": "removeAtt2"
}, o.f);
o.tick(o);
// check index
o.fakeIndexA.free = [];
o.fakeIndexA.location.remove3 = 0;
o.fakeIndexA.database[0] = {"_id": "remove3", "author": "Mrs Sunshine"};
o.spy(o, "value", o.fakeIndexA, "Check index file");
o.jio.getAttachment({
"_id": "A",
"_attachment": "body"
}, o.getAttachmentCallback);
o.tick(o);
o.fakeIndexB.free = [];
o.fakeIndexB.location.remove3 = 0;
o.fakeIndexB.database[0] = {"_id": "remove3", "year": "1234"};
o.spy(o, "value", o.fakeIndexB, "Check index file");
o.jio.getAttachment({
"_id": "B",
"_attachment": "body"
}, o.getAttachmentCallback);
o.tick(o);
// remove document and attachment together
o.spy(o, "value", {"ok": true, "id": "remove3"},
"Remove one document and attachment together");
o.jio.remove({"_id": "remove3"}, o.f);
o.tick(o);
// check index
o.fakeIndexA.free = [0];
delete o.fakeIndexA.location.remove3;
o.fakeIndexA.database[0] = null;
o.spy(o, "value", o.fakeIndexA, "Check index file");
o.jio.getAttachment({
"_id": "A",
"_attachment": "body"
}, o.getAttachmentCallback);
o.tick(o);
o.fakeIndexB.free = [0];
delete o.fakeIndexB.location.remove3;
o.fakeIndexB.database[0] = null;
o.spy(o, "value", o.fakeIndexB, "Check index file");
o.jio.getAttachment({
"_id": "B",
"_attachment": "body"
}, o.getAttachmentCallback);
o.tick(o);
// check attachment
o.spy(o, "status", 404, "Check if attachment has been removed");
o.jio.getAttachment({"_id": "remove3", "_attachment": "removeAtt"}, o.f);
o.tick(o);
// check document
o.spy(o, "status", 404, "Check if document has been removed");
o.jio.get({"_id": "remove3"}, o.f);
o.tick(o);
util.closeAndcleanUpJio(o.jio);
});
test("AllDocs", function () {
var o = generateTools();
o.jio = jIO.newJio({
"type": "indexed",
"indices": [
{"id": "A", "index": ["author"]},
{"id": "B", "index": ["year"]}
],
"sub_storage": {
"type": "local",
"username": "iall",
"application_name": "iall"
}
});
o.getAttachmentCallback = function (err, response) {
if (response) {
try {
response = JSON.parse(response);
} catch (e) {
response = "PARSE ERROR " + response;
}
}
o.f(err, response);
};
// adding documents
o.all1 = { "_id": "dragon.doc",
"title": "some title", "author": "Dr. No", "year": "1968"
};
o.spy(o, "value", {"ok": true, "id": "dragon.doc"}, "Put 1");
o.jio.put(o.all1, o.f);
o.tick(o);
o.all2 = {
"_id": "timemachine",
"title": "hello world",
"author": "Dr. Who",
"year": "1968"
};
o.spy(o, "value", {"ok": true, "id": "timemachine"}, "Put 2");
o.jio.put(o.all2, o.f);
o.tick(o);
o.all3 = {
"_id": "rocket.ppt",
"title": "sunshine.",
"author": "Dr. Snuggles",
"year": "1985"
};
o.spy(o, "value", {"ok": true, "id": "rocket.ppt"}, "Put 3");
o.jio.put(o.all3, o.f);
o.tick(o);
o.all4 = {
"_id": "stick.jpg",
"title": "clouds",
"author": "Dr. House",
"year": "2005"
};
o.spy(o, "value", {"ok": true, "id": "stick.jpg"}, "Put 4");
o.jio.put(o.all4, o.f);
o.tick(o);
// check index
o.fakeIndexA = {
"indexing": ["author"],
"free": [],
"location": {
"dragon.doc": 0,
"timemachine": 1,
"rocket.ppt": 2,
"stick.jpg": 3
},
"database": [
{"_id": "dragon.doc", "author": "Dr. No"},
{"_id": "timemachine", "author": "Dr. Who"},
{"_id": "rocket.ppt", "author": "Dr. Snuggles"},
{"_id": "stick.jpg", "author": "Dr. House"}
]
};
o.spy(o, "value", o.fakeIndexA, "Check index file");
o.jio.getAttachment({
"_id": "A",
"_attachment": "body"
}, o.getAttachmentCallback);
o.tick(o);
o.thisShouldBeTheAnswer = {
"rows": [
{"id": "dragon.doc", "key": "dragon.doc", "value": {} },
{"id": "timemachine", "key": "timemachine", "value": {} },
{"id": "rocket.ppt", "key": "rocket.ppt", "value": {} },
{"id": "stick.jpg", "key": "stick.jpg", "value": {} }
],
"total_rows": 4
};
o.spy(o, "value", o.thisShouldBeTheAnswer, "allDocs (served by index)");
o.jio.allDocs(o.f);
o.tick(o);
util.closeAndcleanUpJio(o.jio);
});
test("AllDocs Complex Queries", function () {
var o = generateTools(), i, m = 15;
o.jio = jIO.newJio({
"type": "indexed",
"indices": [
{"id": "A", "index": ["director"]},
{"id": "B", "index": ["title", "year"]}
],
"sub_storage": {
"type": "local",
"username": "icomplex",
"application_name": "acomplex"
}
});
o.localpath = "jio/localstorage/icomplex/acomplex";
o.getAttachmentCallback = function (err, response) {
if (response) {
try {
response = JSON.parse(response);
} catch (e) {
response = "PARSE ERROR " + response;
}
}
o.f(err, response);
};
// sample data
o.titles = [
"Shawshank Redemption",
"Godfather",
"Godfather 2",
"Pulp Fiction",
"The Good, The Bad and The Ugly",
"12 Angry Men",
"The Dark Knight",
"Schindlers List",
"Lord of the Rings - Return of the King",
"Fight Club",
"Star Wars Episode V",
"Lord Of the Rings - Fellowship of the Ring",
"One flew over the Cuckoo's Nest",
"Inception", "Godfellas"
];
o.years = [
1994,
1972,
1974,
1994,
1966,
1957,
2008,
1993,
2003,
1999,
1980,
2001,
1975,
2010,
1990
];
o.director = [
"Frank Darabont",
"Francis Ford Coppola",
"Francis Ford Coppola",
"Quentin Tarantino",
"Sergio Leone",
"Sidney Lumet",
"Christopher Nolan",
"Steven Spielberg",
"Peter Jackson",
"David Fincher",
"Irvin Kershner",
"Peter Jackson",
"Milos Forman",
"Christopher Nolan",
" Martin Scorsese"
];
o.fakeIndexA = {
"indexing": ["director"],
"free": [],
"location": {},
"database": []
};
o.fakeIndexB = {
"indexing": ["title", "year"],
"free": [],
"location": {},
"database": []
};
for (i = 0; i < m; i += 1) {
o.jio.put({
"_id": i.toString(),
"director": o.director[i],
"year": o.years[i],
"title": o.titles[i]
});
o.tmp = o.fakeIndexA.free.pop() || o.fakeIndexA.database.length;
o.fakeIndexA.database[o.tmp] = {
"_id": i.toString(),
"director": o.director[i]
};
o.fakeIndexA.location[i] = o.tmp;
o.tmp = o.fakeIndexB.free.pop() || o.fakeIndexB.database.length;
o.fakeIndexB.database[o.tmp] = {
"_id": i.toString(),
"year": o.years[i],
"title": o.titles[i]
};
o.fakeIndexB.location[i] = o.tmp;
o.clock.tick(1000);
}
// o.clock.tick(1000);
// check index file
o.spy(o, "value", o.fakeIndexA, "Check index file");
o.jio.getAttachment({
"_id": "A",
"_attachment": "body"
}, o.getAttachmentCallback);
o.tick(o);
o.spy(o, "value", o.fakeIndexB, "Check index file");
o.jio.getAttachment({
"_id": "B",
"_attachment": "body"
}, o.getAttachmentCallback);
o.tick(o);
// response
o.allDocsResponse = {};
o.allDocsResponse.rows = [];
o.allDocsResponse.total_rows = m;
for (i = 0; i < m; i += 1) {
o.allDocsResponse.rows.push({
"id": i.toString(),
"key": i.toString(),
"value": {},
"doc": {
"_id": i.toString(),
"title": o.titles[i],
"year": o.years[i],
"director": o.director[i]
}
});
}
o.response = JSON.parse(JSON.stringify(o.allDocsResponse));
for (i = 0; i < o.response.rows.length; i += 1) {
delete o.response.rows[i].doc;
}
// alldocs
o.spy(o, "value", o.response, "AllDocs response generated from index");
o.jio.allDocs(o.f);
o.tick(o, 1000);
// complex queries
o.response = JSON.parse(JSON.stringify(o.allDocsResponse));
i = 0;
while (i < o.response.rows.length) {
if (o.response.rows[i].year < 1980) {
o.response.rows.splice(i, 1);
} else {
o.response.rows[i].value = {
"year": o.response.rows[i].doc.year,
"title": o.response.rows[i].doc.title
};
delete o.response.rows[i].doc;
i += 1;
}
}
o.response.rows.sort(function (a, b) {
return (a.value.year > b.value.year ? -1 :
a.value.year < b.value.year ? 1 : 0);
});
o.response.rows.length = 5;
o.response.total_rows = 5;
o.spy(o, "value", o.response,
"allDocs (complex queries year >= 1980, index used to do query)");
o.jio.allDocs({
// "query":'(year: >= "1980" AND year: < "2000")',
"query": '(year: >= "1980")',
"limit": [0, 5],
"sort_on": [['year', 'descending']],
"select_list": ['title', 'year']
}, o.f);
o.tick(o);
// complex queries
o.spy(o, "value", {"total_rows": 0, "rows": []},
"allDocs (complex queries year >= 1980, can't use index)");
o.jio.allDocs({
// "query":'(year: >= "1980" AND year: < "2000")',
"query": '(year: >= "1980")',
"limit": [0, 5],
"sort_on": [['year', 'descending']],
"select_list": ['director', 'year']
}, o.f);
o.tick(o);
// empty query returns all
o.response = JSON.parse(JSON.stringify(o.allDocsResponse));
i = 0;
while (i < o.response.rows.length) {
o.response.rows[i].value.title =
o.response.rows[i].doc.title;
delete o.response.rows[i].doc;
i += 1;
}
o.response.rows.sort(function (a, b) {
return (a.value.title > b.value.title ? -1 :
a.value.title < b.value.title ? 1 : 0);
});
o.spy(o, "value", o.response,
"allDocs (empty query in complex query)");
o.jio.allDocs({
"sort_on": [['title', 'descending']],
"select_list": ['title']
}, o.f);
o.tick(o);
util.closeAndcleanUpJio(o.jio);
});
}));
/*jslint indent: 2, maxlen: 80, nomen: true */
/*global define, jIO, jio_tests, hex_sha256, test, ok, deepEqual, sinon,
expect */
// define([module_name], [dependencies], module);
(function (dependencies, module) {
"use strict";
if (typeof define === 'function' && define.amd) {
return define(dependencies, module);
}
module(jIO, jio_tests, {hex_sha256: hex_sha256});
}([
'jio',
'jio_tests',
'sha256',
'localstorage',
'revisionstorage',
'replicaterevisionstorage'
], function (jIO, util, sha256) {
"use strict";
//////////////////////////////////////////////////////////////////////////////
// Tools
/**
* Clones all native object in deep. Managed types: Object, Array, String,
* Number, Boolean, Function, null.
*
* @param {A} object The object to clone
* @return {A} The cloned object
*/
function deepClone(object) {
var i, cloned;
if (Array.isArray(object)) {
cloned = [];
for (i = 0; i < object.length; i += 1) {
cloned[i] = deepClone(object[i]);
}
return cloned;
}
if (typeof object === "object") {
cloned = {};
for (i in object) {
if (object.hasOwnProperty(i)) {
cloned[i] = deepClone(object[i]);
}
}
return cloned;
}
return object;
}
function generateTools() {
return {
clock: sinon.useFakeTimers(),
spy: util.ospy,
tick: util.otick
};
}
function generateRevisionHash(doc, revisions, deleted_flag) {
var string;
doc = deepClone(doc);
delete doc._rev;
delete doc._revs;
delete doc._revs_info;
string = JSON.stringify(doc) + JSON.stringify(revisions) +
JSON.stringify(deleted_flag ? true : false);
return sha256.hex_sha256(string);
}
//////////////////////////////////////////////////////////////////////////////
// Tests
module("Replicate Revision Storage");
var testReplicateRevisionStorage = function (sinon, jio_description) {
var o = generateTools(), leavesAction, generateLocalPath;
o.jio = jIO.newJio(jio_description);
generateLocalPath = function (storage_description) {
return "jio/localstorage/" + storage_description.username + "/" +
storage_description.application_name;
};
leavesAction = function (action, storage_description, param) {
var i;
if (param === undefined) {
param = {};
} else {
param = deepClone(param);
}
if (storage_description.storage_list !== undefined) {
// it is the replicate revision storage tree
for (i = 0; i < storage_description.storage_list.length; i += 1) {
leavesAction(action, storage_description.storage_list[i], param);
}
} else if (storage_description.sub_storage !== undefined) {
// it is the revision storage tree
param.revision = true;
leavesAction(action, storage_description.sub_storage, param);
} else {
// it is the storage tree leaf
param[storage_description.type] = true;
action(storage_description, param);
}
};
o.leavesAction = function (action) {
leavesAction(action, jio_description);
};
// post a new document without id
o.doc = {"title": "post document without id"};
o.spy(o, "status", undefined, "Post document (without id)");
o.jio.post(o.doc, function (err, response) {
o.f.apply(arguments);
o.response_rev = (err || response).rev;
if (util.isUuid((err || response).id)) {
ok(true, "Uuid format");
o.uuid = (err || response).id;
} else {
deepEqual((err || response).id,
"xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx", "Uuid format");
}
});
o.tick(o);
// check document
o.doc._id = o.uuid;
o.revisions = {"start": 0, "ids": []};
o.rev_hash = generateRevisionHash(o.doc, o.revisions);
o.rev = "1-" + o.rev_hash;
o.leavesAction(function (storage_description, param) {
var suffix = "", doc = deepClone(o.doc);
if (param.revision) {
deepEqual(o.response_rev, o.rev, "Check revision");
doc._id += "." + o.rev;
suffix = "." + o.rev;
}
deepEqual(util.jsonlocalstorage.getItem(
generateLocalPath(storage_description) + "/" + o.uuid + suffix
), doc, "Check document");
});
// get the post document without revision
o.spy(o, "value", {
"_id": o.uuid,
"title": "post document without id",
"_rev": o.rev,
"_revisions": {"start": 1, "ids": [o.rev_hash]},
"_revs_info": [{"rev": o.rev, "status": "available"}]
}, "Get the generated document, the winner");
o.jio.get({"_id": o.uuid}, {
"conflicts": true,
"revs": true,
"revs_info": true
}, o.f);
o.tick(o);
// post a new document with id
o.doc = {"_id": "doc1", "title": "post new doc with id"};
o.rev1_1_hash = generateRevisionHash(o.doc, o.revisions);
o.rev1_1 = "1-" + o.rev1_1_hash;
o.rev1_1_history = {"start": 1, "ids": [o.rev1_1_hash]};
o.rev1_1_revs_info = [{"rev": o.rev1_1, "status": "available"}];
o.spy(o, "value", {"ok": true, "id": "doc1", "rev": o.rev1_1},
"Post new document with an id");
o.jio.post(o.doc, o.f);
o.tick(o);
// /
// |
// 1-1
// check document
o.leavesAction(function (storage_description, param) {
var suffix = "", doc = deepClone(o.doc);
if (param.revision) {
doc._id += "." + o.rev1_1;
suffix = "." + o.rev1_1;
}
deepEqual(util.jsonlocalstorage.getItem(
generateLocalPath(storage_description) + "/doc1" + suffix
), doc, "Check document");
});
// get the post document without revision
o.spy(o, "value", {
"_id": "doc1",
"title": "post new doc with id",
"_rev": o.rev1_1,
"_revisions": {"start": 1, "ids": [o.rev1_1_hash]},
"_revs_info": [{"rev": o.rev1_1, "status": "available"}]
}, "Get the previous document (without revision)");
o.jio.get({"_id": "doc1"}, {
"conflicts": true,
"revs": true,
"revs_info": true
}, o.f);
o.tick(o);
// post same document without revision
o.doc = {"_id": "doc1", "title": "post same document without revision"};
o.rev1_2_hash = generateRevisionHash(o.doc, o.revisions);
o.rev1_2 = "1-" + o.rev1_2_hash;
o.rev1_2_history = {"start": 1, "ids": [o.rev1_2_hash]};
o.rev1_2_revs_info = [{"rev": o.rev1_2, "status": "available"}];
o.spy(o, "value", {"ok": true, "id": "doc1", "rev": o.rev1_2},
"Post same document (without revision)");
o.jio.post(o.doc, o.f);
o.tick(o);
// /
// / \
// 1-1 1-2
// check document
o.leavesAction(function (storage_description, param) {
var suffix = "", doc = deepClone(o.doc);
if (param.revision) {
doc._id += "." + o.rev1_2;
suffix = "." + o.rev1_2;
}
deepEqual(util.jsonlocalstorage.getItem(
generateLocalPath(storage_description) + "/doc1" + suffix
), doc, "Check document");
});
// post a new revision
o.doc = {"_id": "doc1", "title": "post new revision", "_rev": o.rev1_2};
o.revisions.start += 1;
o.revisions.ids.unshift(o.rev1_2_hash);
o.rev2_3_hash = generateRevisionHash(o.doc, o.revisions);
o.rev2_3 = "2-" + o.rev2_3_hash;
o.rev2_3_history = deepClone(o.rev1_2_history);
o.rev2_3_history.start += 1;
o.rev2_3_history.ids.unshift(o.rev2_3_hash);
o.rev2_3_revs_info = deepClone(o.rev1_2_revs_info);
o.rev2_3_revs_info.unshift({"rev": o.rev2_3, "status": "available"});
o.spy(o, "value", {"ok": true, "id": "doc1", "rev": o.rev2_3},
"Post document (with revision)");
o.jio.post(o.doc, o.f);
o.tick(o);
// /
// / \
// 1-1 1-2
// |
// 2-3
// check document
o.leavesAction(function (storage_description, param) {
var suffix = "", doc = deepClone(o.doc);
delete doc._rev;
if (param.revision) {
doc._id += "." + o.rev2_3;
suffix = "." + o.rev2_3;
}
deepEqual(util.jsonlocalstorage.getItem(
generateLocalPath(storage_description) + "/doc1" + suffix
), doc, "Check document");
});
// get the post document with revision
o.spy(o, "value", {
"_id": "doc1",
"title": "post same document without revision",
"_rev": o.rev1_2,
"_revisions": {"start": 1, "ids": [o.rev1_2_hash]},
"_revs_info": [{"rev": o.rev1_2, "status": "available"}],
"_conflicts": [o.rev1_1]
}, "Get the previous document (with revision)");
o.jio.get({"_id": "doc1", "_rev": o.rev1_2}, {
"conflicts": true,
"revs": true,
"revs_info": true
}, o.f);
o.tick(o);
// put document without id
o.spy(o, "status", 20, "Put document without id");
o.jio.put({}, o.f);
o.tick(o);
// put document without rev
o.doc = {"_id": "doc1", "title": "put new document"};
o.rev1_4_hash = generateRevisionHash(o.doc, {"start": 0, "ids": []});
o.rev1_4 = "1-" + o.rev1_4_hash;
o.rev1_4_history = {"start": 1, "ids": [o.rev1_4_hash]};
o.rev1_4_revs_info = [{"rev": o.rev1_4, "status": "available"}];
o.spy(o, "value", {"id": "doc1", "ok": true, "rev": o.rev1_4},
"Put document without rev");
o.jio.put(o.doc, o.f);
o.tick(o);
// __/__
// / | \
// 1-1 1-2 1-4
// |
// 2-3
// put new revision
o.doc = {"_id": "doc1", "title": "put new revision", "_rev": o.rev1_4};
o.rev2_5_hash = generateRevisionHash(o.doc, o.rev1_4_history);
o.rev2_5 = "2-" + o.rev2_5_hash;
o.rev2_5_history = {"start": 2, "ids": [o.rev2_5_hash, o.rev1_4_hash]};
o.rev2_5_revs_info = deepClone(o.rev1_4_revs_info);
o.rev2_5_revs_info.unshift({"rev": o.rev2_5, "status": "available"});
o.spy(o, "value", {"id": "doc1", "ok": true, "rev": o.rev2_5},
"Put new revision");
o.jio.put(o.doc, o.f);
o.tick(o);
// __/__
// / | \
// 1-1 1-2 1-4
// | |
// 2-3 2-5
// putAttachment to inexistent document
o.doc = {
"_id": "doc2",
"_mimetype": "text/plain",
"_data": "doc 2 - attachment 1",
"_attachment": "attachment1"
};
o.rev_hash = generateRevisionHash(o.doc, {"start": 0, "ids": []});
o.rev = "1-" + o.rev_hash;
o.spy(o, "value",
{"ok": true, "id": "doc2", "attachment": "attachment1", "rev": o.rev},
"Put an attachment to an inexistent document");
o.jio.putAttachment(o.doc, o.f);
o.tick(o);
// putAttachment
o.doc = {
"_id": "doc1",
"_mimetype": "text/plain",
"_data": "doc 1 - attachment 1",
"_attachment": "attachment1",
"_rev": o.rev2_5
};
o.rev3_6_hash = generateRevisionHash(o.doc, o.rev2_5_history);
o.rev3_6 = "3-" + o.rev3_6_hash;
o.rev3_6_history = deepClone(o.rev2_5_history);
o.rev3_6_history.start += 1;
o.rev3_6_history.ids.unshift(o.rev3_6_hash);
o.rev3_6_revs_info = deepClone(o.rev2_5_revs_info);
o.rev3_6_revs_info.unshift({"rev": o.rev3_6, "status": "available"});
o.spy(o, "value", {
"ok": true,
"id": "doc1",
"attachment": "attachment1",
"rev": o.rev3_6
}, "Put an attachment to the first document");
o.jio.putAttachment(o.doc, o.f);
o.tick(o);
// __/__
// / | \
// 1-1 1-2 1-4
// | |
// 2-3 2-5
// |
// 3-6+a1
// get document
o.doc = {
"_id": "doc1",
"_rev": o.rev3_6,
"_revisions": o.rev3_6_history,
"_revs_info": o.rev3_6_revs_info,
"_conflicts": [o.rev2_3, o.rev1_1],
"_attachments": {
"attachment1": {
"length": "doc 1 - attachment 1".length,
"content_type": "text/plain",
"digest": "md5-0505c1fb6aae02dd1695d33841726564"
}
},
"title": "put new revision"
};
o.spy(o, "value", o.doc, "Get document, the winner");
o.jio.get({"_id": "doc1"}, {
"conflicts": true,
"revs": true,
"revs_info": true
}, o.f);
o.tick(o);
// get attachment
o.doc = {
"_id": "doc1",
"_attachment": "attachment1"
};
o.spy(o, "value", "doc 1 - attachment 1", "Get the winner's attachment");
o.jio.getAttachment(o.doc, o.f);
o.tick(o);
// put document
o.doc = {
"_id": "doc1",
"_rev": o.rev3_6,
"title": "Put revision, attachment must be copied"
};
o.rev4_7_hash = generateRevisionHash(o.doc, o.rev3_6_history);
o.rev4_7 = "4-" + o.rev4_7_hash;
o.rev4_7_history = deepClone(o.rev3_6_history);
o.rev4_7_history.start += 1;
o.rev4_7_history.ids.unshift(o.rev4_7_hash);
o.rev4_7_revs_info = deepClone(o.rev3_6_revs_info);
o.rev4_7_revs_info.unshift({"rev": o.rev4_7, "status": "available"});
o.spy(o, "value", {"ok": true, "id": "doc1", "rev": o.rev4_7},
"Update document, attachment should be copied");
o.jio.put(o.doc, o.f);
o.tick(o);
// __/__
// / | \
// 1-1 1-2 1-4
// | |
// 2-3 2-5
// |
// 3-6+a1
// |
// 4-7+a1
// get document, attachment must be copied
o.doc = {
"_id": "doc1",
"_rev": o.rev4_7,
"title": o.doc.title,
"_attachments": {
"attachment1": {
"length": "doc 1 - attachment 1".length,
"content_type": "text/plain",
"digest": "md5-0505c1fb6aae02dd1695d33841726564"
}
},
"_conflicts": [o.rev2_3, o.rev1_1],
"_revisions": o.rev4_7_history,
"_revs_info": o.rev4_7_revs_info
};
o.spy(o, "value", o.doc,
"Get the new winner document and its attachment metadata");
o.jio.get({"_id": "doc1"}, {
"conflicts": true,
"revs": true,
"revs_info": true
}, o.f);
o.tick(o);
// get attachment
o.doc = {
"_id": "doc1",
"_attachment": "attachment1"
};
o.spy(o, "value", "doc 1 - attachment 1",
"Get the winner's attachment again");
o.jio.getAttachment(o.doc, o.f);
o.tick(o);
// remove attachment
o.doc = {
"_id": "doc1",
"_attachment": "attachment1",
"_rev": o.rev4_7
};
o.rev5_8_hash = generateRevisionHash(o.doc, o.rev4_7_history);
o.rev5_8 = "5-" + o.rev5_8_hash;
o.rev5_8_history = deepClone(o.rev4_7_history);
o.rev5_8_history.start += 1;
o.rev5_8_history.ids.unshift(o.rev5_8_hash);
o.rev5_8_revs_info = deepClone(o.rev4_7_revs_info);
o.rev5_8_revs_info.unshift({"rev": o.rev5_8, "status": "available"});
o.spy(o, "value", {
"ok": true,
"id": "doc1",
"attachment": "attachment1",
"rev": o.rev5_8
}, "Remove attachment");
o.jio.removeAttachment(o.doc, o.f);
o.tick(o);
// __/__
// / | \
// 1-1 1-2 1-4
// | |
// 2-3 2-5
// |
// 3-6+a1
// |
// 4-7+a1
// |
// 5-8
// get document to check attachment existence
o.doc = {
"_id": "doc1",
"_rev": o.rev5_8,
"title": "Put revision, attachment must be copied",
"_conflicts": [o.rev2_3, o.rev1_1],
"_revisions": o.rev5_8_history,
"_revs_info": o.rev5_8_revs_info
};
o.spy(o, "value", o.doc,
"Get the new winner document, no attachment must be provided");
o.jio.get({"_id": "doc1"}, {
"conflicts": true,
"revs": true,
"revs_info": true
}, o.f);
o.tick(o);
// get specific document
o.doc = {
"_id": "doc1",
"_rev": o.rev4_7,
"title": o.doc.title,
"_attachments": {
"attachment1": {
"length": "doc 1 - attachment 1".length,
"content_type": "text/plain",
"digest": "md5-0505c1fb6aae02dd1695d33841726564"
}
},
"_conflicts": [o.rev2_3, o.rev1_1],
"_revisions": o.rev4_7_history,
"_revs_info": o.rev4_7_revs_info
};
o.spy(o, "value", o.doc,
"Get the new winner document and its attachment metadata");
o.jio.get({"_id": "doc1", "_rev": o.rev4_7}, {
"conflicts": true,
"revs": true,
"revs_info": true
}, o.f);
o.tick(o);
// get inexistent attachment
o.spy(o, "status", 404, "Get inexistent winner attachment" +
" -> 404 Not Found");
o.jio.get({"_id": "doc1/attachment1"}, o.f);
o.tick(o);
// get specific attachment
o.doc = {
"_id": "doc1",
"_attachment": "attachment1",
"_rev": o.rev3_6
};
o.spy(o, "value", "doc 1 - attachment 1", "Get a specific attachment");
o.jio.getAttachment(o.doc, o.f);
o.tick(o);
// remove specific document and conflict
o.doc = {"_id": "doc1", "_rev": o.rev1_1};
// generate with deleted_flag
o.rev2_9_hash = generateRevisionHash(o.doc, o.rev1_1_history, true);
o.rev2_9 = "2-" + o.rev2_9_hash;
o.rev2_9_history = deepClone(o.rev1_1_history);
o.rev2_9_history.start += 1;
o.rev2_9_history.ids.unshift(o.rev2_9_hash);
o.rev2_9_revs_info = deepClone(o.rev1_1_revs_info);
o.rev2_9_revs_info.unshift({"rev": o.rev2_9, "status": "deleted"});
o.spy(o, "value", {"ok": true, "id": "doc1", "rev": o.rev2_9},
"Remove specific document, and one conflict");
o.jio.remove(o.doc, o.f);
o.tick(o);
// __/___
// / | \
// 1-1 1-2 1-4
// | | |
// D2-9 2-3 2-5
// |
// 3-6+a1
// |
// 4-7+a1
// |
// 5-8
// remove specific document and conflict
o.doc = {"_id": "doc1", "_rev": o.rev2_3};
o.rev3_10_hash = generateRevisionHash(o.doc, o.rev2_3_history, true);
o.rev3_10 = "3-" + o.rev3_10_hash;
o.rev3_10_history = deepClone(o.rev2_3_history);
o.rev3_10_history.start += 1;
o.rev3_10_history.ids.unshift(o.rev3_10_hash);
o.rev3_10_revs_info = deepClone(o.rev2_3_revs_info);
o.rev3_10_revs_info.unshift({"rev": o.rev3_10, "status": "deleted"});
o.spy(o, "value", {"ok": true, "id": "doc1", "rev": o.rev3_10},
"Remove specific document, and one conflict");
o.jio.remove(o.doc, o.f);
o.tick(o);
// ___/____
// / | \
// 1-1 1-2 1-4
// | | |
// D2-9 2-3 2-5
// | |
// D3-10 3-6+a1
// |
// 4-7+a1
// |
// 5-8
// get document no more conflict
o.doc = {
"_id": "doc1",
"_rev": o.rev5_8,
"title": "Put revision, attachment must be copied",
"_revisions": o.rev5_8_history,
"_revs_info": o.rev5_8_revs_info
};
o.spy(o, "value", o.doc,
"Get the new winner document, no more conflicts");
o.jio.get({"_id": "doc1"}, {
"conflicts": true,
"revs": true,
"revs_info": true
}, o.f);
o.tick(o);
// remove document
o.doc = {
"_id": "doc1",
"_rev": o.rev5_8
};
o.rev6_11_hash = generateRevisionHash(o.doc, o.rev5_8_history, true);
o.rev6_11 = "6-" + o.rev6_11_hash;
o.spy(o, "value", {"ok": true, "id": "doc1", "rev": o.rev6_11},
"Remove the last document");
o.jio.remove(o.doc, o.f);
o.tick(o);
// ___/____
// / | \
// 1-1 1-2 1-4
// | | |
// D2-9 2-3 2-5
// | |
// D3-10 3-6+a1
// |
// 4-7+a1
// |
// 5-8
// |
// D6-11
// get inexistent document
o.spy(o, "status", 404, "Get inexistent document -> 404 Not Found");
o.jio.get({"_id": "doc3"}, {
"conflicts": true,
"revs": true,
"revisions": true
}, o.f);
o.tick(o);
// get specific deleted document
o.spy(o, "status", 404, "Get deleted document -> 404 Not Found");
o.jio.get({"_id": "doc1", "rev": o.rev3_10}, {
"conflicts": true,
"revs": true,
"revs_info": true
}, o.f);
o.tick(o);
// get specific deleted document
o.spy(o, "status", 404, "Get deleted document -> 404 Not Found");
o.jio.get({"_id": "doc1"}, {
"conflicts": true,
"revs": true,
"revs_info": true
}, o.f);
o.tick(o);
util.closeAndcleanUpJio(o.jio);
};
test("[Revision + Local Storage] Scenario", function () {
testReplicateRevisionStorage(this, {
"type": "replicaterevision",
"storage_list": [{
"type": "revision",
"sub_storage": {
"type": "local",
"username": "ureprevloc",
"application_name": "areprevloc"
}
}]
});
});
test("[Replicate Revision + Revision + Local Storage] Scenario", function () {
testReplicateRevisionStorage(this, {
"type": "replicaterevision",
"storage_list": [{
"type": "replicaterevision",
"storage_list": [{
"type": "revision",
"sub_storage": {
"type": "local",
"username": "urepreprevloc",
"application_name": "arepreprevloc"
}
}]
}]
});
});
test("2x [Revision + Local Storage] Scenario", function () {
testReplicateRevisionStorage(this, {
"type": "replicaterevision",
"storage_list": [{
"type": "revision",
"sub_storage": {
"type": "local",
"username": "ureprevlocloc1",
"application_name": "areprevlocloc1"
}
}, {
"type": "revision",
"sub_storage": {
"type": "local",
"username": "ureprevlocloc2",
"application_name": "areprevlocloc2"
}
}]
});
});
test("2x [Replicate Rev + 2x [Rev + Local]] Scenario", function () {
testReplicateRevisionStorage(this, {
"type": "replicaterevision",
"storage_list": [{
"type": "replicaterevision",
"storage_list": [{
"type": "revision",
"sub_storage": {
"type": "local",
"username": "urepreprevloc1",
"application_name": "arepreprevloc1"
}
}, {
"type": "revision",
"sub_storage": {
"type": "local",
"username": "urepreprevloc2",
"application_name": "arepreprevloc2"
}
}]
}, {
"type": "replicaterevision",
"storage_list": [{
"type": "revision",
"sub_storage": {
"type": "local",
"username": "urepreprevloc3",
"application_name": "arepreprevloc3"
}
}, {
"type": "revision",
"sub_storage": {
"type": "local",
"username": "urepreprevloc4",
"application_name": "arepreprevloc4"
}
}]
}]
});
});
function replicateStorageSynchronisationGenerator(
that,
description,
index
) {
var o = generateTools();
o.jio = jIO.newJio(description);
o.localpath1 = "jio/localstorage/usyncreprevlocloc1/" + index;
o.localpath2 = "jio/localstorage/usyncreprevlocloc2/" + index;
o.localpath3 = "jio/localstorage/usyncreprevlocloc3/" + index;
o.localpath4 = "jio/localstorage/usyncreprevlocloc4/" + index;
// add documents to localstorage
o.doctree1_1 = {
"_id": "doc1.revision_tree.json",
"children": [{
"rev": "1-111",
"status": "available",
"children": [],
}]
};
o.doc1_1 = {"_id": "doc1.1-111", "title": "A"};
util.jsonlocalstorage.setItem(o.localpath1 + "/doc1.revision_tree.json",
o.doctree1_1);
util.jsonlocalstorage.setItem(o.localpath2 + "/doc1.revision_tree.json",
o.doctree1_1);
util.jsonlocalstorage.setItem(o.localpath3 + "/doc1.revision_tree.json",
o.doctree1_1);
util.jsonlocalstorage.setItem(o.localpath4 + "/doc1.revision_tree.json",
o.doctree1_1);
util.jsonlocalstorage.setItem(o.localpath1 + "/" + o.doc1_1._id, o.doc1_1);
util.jsonlocalstorage.setItem(o.localpath2 + "/" + o.doc1_1._id, o.doc1_1);
util.jsonlocalstorage.setItem(o.localpath3 + "/" + o.doc1_1._id, o.doc1_1);
util.jsonlocalstorage.setItem(o.localpath4 + "/" + o.doc1_1._id, o.doc1_1);
// no synchronisation
o.spy(o, "value", {"ok": true, "id": "doc1"},
"Check document");
o.jio.check({"_id": "doc1"}, o.f);
o.tick(o);
o.spy(o, "value", {"ok": true, "id": "doc1", "rev": "1-111"},
"Check document with revision");
o.jio.check({"_id": "doc1", "_rev": "1-111"}, o.f);
o.tick(o);
o.spy(o, "value", {"ok": true, "id": "doc1"},
"Repair document");
o.jio.repair({"_id": "doc1"}, o.f);
o.tick(o);
// check documents from localstorage
deepEqual(
util.jsonlocalstorage.getItem(o.localpath1 + "/doc1.revision_tree.json"),
o.doctree1_1,
"Check revision tree 1, no synchro done"
);
deepEqual(
util.jsonlocalstorage.getItem(o.localpath2 + "/doc1.revision_tree.json"),
o.doctree1_1,
"Check revision tree 2, no synchro done"
);
deepEqual(
util.jsonlocalstorage.getItem(o.localpath3 + "/doc1.revision_tree.json"),
o.doctree1_1,
"Check revision tree 3, no synchro done"
);
deepEqual(
util.jsonlocalstorage.getItem(o.localpath4 + "/doc1.revision_tree.json"),
o.doctree1_1,
"Check revision tree 4, no synchro done"
);
// add documents to localstorage
o.doctree2_2 = deepClone(o.doctree1_1);
o.doctree2_2.children[0].children.push({
"rev": "2-222",
"status": "available",
"children": []
});
o.doc2_2 = {
"_id": "doc1.2-222",
"title": "B",
"_attachments": {
"haha": {
"length": 3,
"digest": "md5-900150983cd24fb0d6963f7d28e17f72",
"content_type": "text/plain"
}
}
};
util.jsonlocalstorage.setItem(o.localpath1 + "/doc1.revision_tree.json",
o.doctree2_2);
util.jsonlocalstorage.setItem(o.localpath1 + "/" + o.doc2_2._id, o.doc2_2);
util.jsonlocalstorage.setItem(o.localpath1 + "/" + o.doc2_2._id +
"/haha", "abc");
// document synchronisation without conflict
o.spy(o, "status", 41, "Check document");
o.jio.check({"_id": "doc1"}, o.f);
o.tick(o, 50000);
o.spy(o, "value", {"ok": true, "id": "doc1"},
"Repair document");
o.jio.repair({"_id": "doc1"}, o.f);
o.tick(o, 50000);
// check documents from localstorage
deepEqual(
util.jsonlocalstorage.getItem(o.localpath1 + "/doc1.revision_tree.json"),
o.doctree2_2,
"Check revision tree 1, no synchro done"
);
deepEqual(
util.jsonlocalstorage.getItem(o.localpath2 + "/doc1.revision_tree.json"),
o.doctree2_2,
"Check revision tree 2, revision synchro done"
);
deepEqual(
util.jsonlocalstorage.getItem(o.localpath3 + "/doc1.revision_tree.json"),
o.doctree2_2,
"Check revision tree 3, revision synchro done"
);
deepEqual(
util.jsonlocalstorage.getItem(o.localpath3 + "/doc1.2-222"),
o.doc2_2,
"Check document 3"
);
deepEqual(
util.jsonlocalstorage.getItem(o.localpath3 + "/doc1.2-222/haha"),
"abc",
"Check attachment 3"
);
deepEqual(
util.jsonlocalstorage.getItem(o.localpath4 + "/doc1.revision_tree.json"),
o.doctree2_2,
"Check revision tree 4, revision synchro done"
);
// add documents to localstorage
o.doctree2_3 = deepClone(o.doctree2_2);
o.doctree2_3.children[0].children.unshift({
"rev": "2-223",
"status": "available",
"children": []
});
o.doc2_3 = {"_id": "doc1.2-223", "title": "C"};
util.jsonlocalstorage.setItem(o.localpath1 + "/doc1.revision_tree.json",
o.doctree2_3);
util.jsonlocalstorage.setItem(o.localpath1 + "/" + o.doc2_3._id, o.doc2_3);
// document synchronisation with conflict
o.spy(o, "status", 41, "Check document");
o.jio.check({"_id": "doc1"}, o.f);
o.tick(o, 50000);
o.spy(o, "value", {"ok": true, "id": "doc1"},
"Repair document");
o.jio.repair({"_id": "doc1"}, o.f);
o.tick(o, 50000);
// check documents from localstorage
deepEqual(
util.jsonlocalstorage.getItem(o.localpath1 + "/doc1.revision_tree.json"),
o.doctree2_3,
"Check revision tree 1, rev synchro"
);
deepEqual(
util.jsonlocalstorage.getItem(o.localpath2 + "/doc1.revision_tree.json"),
o.doctree2_3,
"Check revision tree 2, rev synchro"
);
deepEqual(
util.jsonlocalstorage.getItem(o.localpath3 + "/doc1.revision_tree.json"),
o.doctree2_3,
"Check revision tree 3, rev synchro"
);
deepEqual(
util.jsonlocalstorage.getItem(o.localpath3 + "/doc1.2-223"),
o.doc2_3,
"Check document 3"
);
deepEqual(
util.jsonlocalstorage.getItem(o.localpath4 + "/doc1.revision_tree.json"),
o.doctree2_3,
"Check revision tree 4, rev synchro"
);
util.closeAndcleanUpJio(o.jio);
}
test("Storage Synchronisation (Repair) 4x [Rev + Local]", function () {
replicateStorageSynchronisationGenerator(this, {
"type": "replicaterevision",
"storage_list": [{
"type": "revision",
"sub_storage": {
"type": "local",
"username": "usyncreprevlocloc1",
"application_name": "1"
}
}, {
"type": "revision",
"sub_storage": {
"type": "local",
"username": "usyncreprevlocloc2",
"application_name": "1"
}
}, {
"type": "revision",
"sub_storage": {
"type": "local",
"username": "usyncreprevlocloc3",
"application_name": "1"
}
}, {
"type": "revision",
"sub_storage": {
"type": "local",
"username": "usyncreprevlocloc4",
"application_name": "1"
}
}]
}, "1");
});
test(
"Storage Synchronisation (Repair) 2x [Rep 2x [Rev + Local]]",
function () {
replicateStorageSynchronisationGenerator(this, {
"type": "replicaterevision",
"storage_list": [{
"type": "replicaterevision",
"storage_list": [{
"type": "revision",
"sub_storage": {
"type": "local",
"username": "usyncreprevlocloc1",
"application_name": "2"
}
}, {
"type": "revision",
"sub_storage": {
"type": "local",
"username": "usyncreprevlocloc2",
"application_name": "2"
}
}]
}, {
"type": "replicaterevision",
"storage_list": [{
"type": "revision",
"sub_storage": {
"type": "local",
"username": "usyncreprevlocloc3",
"application_name": "2"
}
}, {
"type": "revision",
"sub_storage": {
"type": "local",
"username": "usyncreprevlocloc4",
"application_name": "2"
}
}]
}]
}, "2");
}
);
}));
/*jslint indent: 2, maxlen: 80, nomen: true */
/*global define, jIO, jio_tests, hex_sha256, window, test, ok, deepEqual, sinon,
expect */
// define([module_name], [dependencies], module);
(function (dependencies, module) {
"use strict";
if (typeof define === 'function' && define.amd) {
return define(dependencies, module);
}
module(jIO, jio_tests, {hex_sha256: hex_sha256});
}(['jio', 'jio_tests', 'sha256', 'localstorage', 'revisionstorage'], function (
jIO,
util,
sha256
) {
"use strict";
//////////////////////////////////////////////////////////////////////////////
// Tools
/**
* Clones all native object in deep. Managed types: Object, Array, String,
* Number, Boolean, Function, null.
*
* @param {A} object The object to clone
* @return {A} The cloned object
*/
function deepClone(object) {
var i, cloned;
if (Array.isArray(object)) {
cloned = [];
for (i = 0; i < object.length; i += 1) {
cloned[i] = deepClone(object[i]);
}
return cloned;
}
if (typeof object === "object") {
cloned = {};
for (i in object) {
if (object.hasOwnProperty(i)) {
cloned[i] = deepClone(object[i]);
}
}
return cloned;
}
return object;
}
function generateTools() {
return {
clock: sinon.useFakeTimers(),
spy: util.ospy,
tick: util.otick
};
}
function generateRevisionHash(doc, revisions, deleted_flag) {
var string;
doc = deepClone(doc);
delete doc._rev;
delete doc._revs;
delete doc._revs_info;
string = JSON.stringify(doc) + JSON.stringify(revisions) +
JSON.stringify(deleted_flag ? true : false);
return sha256.hex_sha256(string);
}
//////////////////////////////////////////////////////////////////////////////
// Tests
module("Revision Storage + Local Storage");
test("Post", function () {
var o = generateTools();
o.jio = jIO.newJio({
"type": "revision",
"sub_storage": {
"type": "local",
"username": "urevpost",
"application_name": "arevpost"
}
});
o.localpath = "jio/localstorage/urevpost/arevpost";
// post without id
o.revisions = {"start": 0, "ids": []};
o.spy(o, "status", undefined, "Post without id");
o.jio.post({}, function (err, response) {
o.f.apply(arguments);
o.uuid = (err || response).id;
ok(util.isUuid(o.uuid), "Uuid should look like " +
"xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx : " + o.uuid);
});
o.tick(o);
o.rev = "1-" + generateRevisionHash({"_id": o.uuid}, o.revisions);
// check document
deepEqual(
util.jsonlocalstorage.getItem(o.localpath + "/" + o.uuid + "." + o.rev),
{"_id": o.uuid + "." + o.rev},
"Check document"
);
// check document tree
o.doc_tree = {
"_id": o.uuid + ".revision_tree.json",
"children": [{
"rev": o.rev,
"status": "available",
"children": []
}]
};
deepEqual(
util.jsonlocalstorage.getItem(
o.localpath + "/" + o.uuid + ".revision_tree.json"
),
o.doc_tree,
"Check document tree"
);
// post non empty document
o.doc = {"_id": "post1", "title": "myPost1"};
o.rev = "1-" + generateRevisionHash(o.doc, o.revisions);
o.spy(o, "value", {"ok": true, "id": "post1", "rev": o.rev}, "Post");
o.jio.post(o.doc, o.f);
o.tick(o);
// check document
o.doc._id = "post1." + o.rev;
deepEqual(
util.jsonlocalstorage.getItem(o.localpath + "/post1." + o.rev),
o.doc,
"Check document"
);
// check document tree
o.doc_tree._id = "post1.revision_tree.json";
o.doc_tree.children[0] = {
"rev": o.rev,
"status": "available",
"children": []
};
deepEqual(
util.jsonlocalstorage.getItem(
o.localpath + "/post1.revision_tree.json"
),
o.doc_tree,
"Check document tree"
);
// post and document already exists
o.doc = {"_id": "post1", "title": "myPost2"};
o.rev = "1-" + generateRevisionHash(o.doc, o.revisions);
o.spy(o, "value", {
"ok": true,
"id": "post1",
"rev": o.rev
}, "Post and document already exists");
o.jio.post(o.doc, o.f);
o.tick(o);
// check document
o.doc._id = "post1." + o.rev;
deepEqual(
util.jsonlocalstorage.getItem(o.localpath + "/post1." + o.rev),
o.doc,
"Check document"
);
// check document tree
o.doc_tree._id = "post1.revision_tree.json";
o.doc_tree.children.unshift({
"rev": o.rev,
"status": "available",
"children": []
});
deepEqual(
util.jsonlocalstorage.getItem(
o.localpath + "/post1.revision_tree.json"
),
o.doc_tree,
"Check document tree"
);
// post + revision
o.doc = {"_id": "post1", "_rev": o.rev, "title": "myPost2"};
o.revisions = {"start": 1, "ids": [o.rev.split('-')[1]]};
o.rev = "2-" + generateRevisionHash(o.doc, o.revisions);
o.spy(o, "value", {"ok": true, "id": "post1", "rev": o.rev},
"Post + revision");
o.jio.post(o.doc, o.f);
o.tick(o);
// // keep_revision_history
// ok (false, "keep_revision_history Option Not Implemented");
// check document
o.doc._id = "post1." + o.rev;
delete o.doc._rev;
deepEqual(
util.jsonlocalstorage.getItem(o.localpath + "/post1." + o.rev),
o.doc,
"Check document"
);
// check document tree
o.doc_tree._id = "post1.revision_tree.json";
o.doc_tree.children[0].children.unshift({
"rev": o.rev,
"status": "available",
"children": []
});
deepEqual(
util.jsonlocalstorage.getItem(
o.localpath + "/post1.revision_tree.json"
),
o.doc_tree,
"Check document tree"
);
// add attachment
o.doc._attachments = {
"attachment_test": {
"length": 35,
"digest": "A",
"content_type": "oh/yeah"
}
};
util.jsonlocalstorage.setItem(o.localpath + "/post1." + o.rev, o.doc);
util.jsonlocalstorage.setItem(
o.localpath + "/post1." + o.rev + "/attachment_test",
"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
);
// post + attachment copy
o.doc = {"_id": "post1", "_rev": o.rev, "title": "myPost2"};
o.revisions = {
"start": 2,
"ids": [o.rev.split('-')[1], o.revisions.ids[0]]
};
o.rev = "3-" + generateRevisionHash(o.doc, o.revisions);
o.spy(o, "value", {"ok": true, "id": "post1", "rev": o.rev},
"Post + attachment copy");
o.jio.post(o.doc, o.f);
o.tick(o);
// check attachment
deepEqual(
util.jsonlocalstorage.getItem(o.localpath + "/post1." + o.rev +
"/attachment_test"),
"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
"Check Attachment"
);
// check document tree
o.doc_tree._id = "post1.revision_tree.json";
o.doc_tree.children[0].children[0].children.unshift({
"rev": o.rev,
"status": "available",
"children": []
});
deepEqual(
util.jsonlocalstorage.getItem(
o.localpath + "/post1.revision_tree.json"
),
o.doc_tree,
"Check document tree"
);
// post + wrong revision
o.doc = {"_id": "post1", "_rev": "3-wr3", "title": "myPost3"};
o.revisions = {"start": 3, "ids": ["wr3"]};
o.rev = "4-" + generateRevisionHash(o.doc, o.revisions);
o.spy(o, "value", {"id": "post1", "ok": true, "rev": o.rev},
"Post + wrong revision");
o.jio.post(o.doc, o.f);
o.tick(o);
// check document
deepEqual(
util.jsonlocalstorage.getItem(o.localpath + "/post1.3-wr3"),
null,
"Check document"
);
// check document
o.doc._id = "post1." + o.rev;
delete o.doc._rev;
deepEqual(
util.jsonlocalstorage.getItem(o.localpath + "/post1." + o.rev),
o.doc,
"Check document"
);
// check document tree
o.doc_tree._id = "post1.revision_tree.json";
o.doc_tree.children.unshift({
"rev": "3-wr3",
"status": "missing",
"children": [{
"rev": o.rev,
"status": "available",
"children": []
}]
});
deepEqual(
util.jsonlocalstorage.getItem(
o.localpath + "/post1.revision_tree.json"
),
o.doc_tree,
"Check document tree"
);
util.closeAndcleanUpJio(o.jio);
});
test("Put", function () {
var o = generateTools();
o.jio = jIO.newJio({
"type": "revision",
"sub_storage": {
"type": "local",
"username": "urevput",
"application_name": "arevput"
}
});
o.localpath = "jio/localstorage/urevput/arevput";
// put without id
// error 20 -> document id required
o.spy(o, "status", 20, "Put without id");
o.jio.put({}, o.f);
o.tick(o);
// put non empty document
o.doc = {"_id": "put1", "title": "myPut1"};
o.revisions = {"start": 0, "ids": []};
o.rev = "1-" + generateRevisionHash(o.doc, o.revisions);
o.spy(o, "value", {"ok": true, "id": "put1", "rev": o.rev},
"Creates a document");
o.jio.put(o.doc, o.f);
o.tick(o);
// check document
o.doc._id = "put1." + o.rev;
deepEqual(
util.jsonlocalstorage.getItem(o.localpath + "/put1." + o.rev),
o.doc,
"Check document"
);
// check document tree
o.doc_tree = {
"_id": "put1.revision_tree.json",
"children": [{
"rev": o.rev,
"status": "available",
"children": []
}]
};
deepEqual(
util.jsonlocalstorage.getItem(
o.localpath + "/put1.revision_tree.json"
),
o.doc_tree,
"Check document tree"
);
// put without rev and document already exists
o.doc = {"_id": "put1", "title": "myPut2"};
o.rev = "1-" + generateRevisionHash(o.doc, o.revisions);
o.spy(o, "value", {"ok": true, "id": "put1", "rev": o.rev},
"Put same document without revision");
o.jio.put(o.doc, o.f);
o.tick(o);
o.doc_tree.children.unshift({
"rev": o.rev,
"status": "available",
"children": []
});
// put + revision
o.doc = {"_id": "put1", "_rev": o.rev, "title": "myPut2"};
o.revisions = {"start": 1, "ids": [o.rev.split('-')[1]]};
o.rev = "2-" + generateRevisionHash(o.doc, o.revisions);
o.spy(o, "value", {"id": "put1", "ok": true, "rev": o.rev},
"Put + revision");
o.jio.put(o.doc, o.f);
o.tick(o);
// check document
o.doc._id = "put1." + o.rev;
delete o.doc._rev;
deepEqual(
util.jsonlocalstorage.getItem(o.localpath + "/put1." + o.rev),
o.doc,
"Check document"
);
// check document tree
o.doc_tree.children[0].children.unshift({
"rev": o.rev,
"status": "available",
"children": []
});
deepEqual(
util.jsonlocalstorage.getItem(
o.localpath + "/put1.revision_tree.json"
),
o.doc_tree,
"Check document tree"
);
// put + wrong revision
o.doc = {"_id": "put1", "_rev": "3-wr3", "title": "myPut3"};
o.revisions = {"start": 3, "ids": ["wr3"]};
o.rev = "4-" + generateRevisionHash(o.doc, o.revisions);
o.spy(o, "value", {"id": "put1", "ok": true, "rev": o.rev},
"Put + wrong revision");
o.jio.put(o.doc, o.f);
o.tick(o);
// check document
o.doc._id = "put1." + o.rev;
delete o.doc._rev;
deepEqual(
util.jsonlocalstorage.getItem(o.localpath + "/put1." + o.rev),
o.doc,
"Check document"
);
// check document tree
o.doc_tree.children.unshift({
"rev": "3-wr3",
"status": "missing",
"children": [{
"rev": o.rev,
"status": "available",
"children": []
}]
});
deepEqual(
util.jsonlocalstorage.getItem(
o.localpath + "/put1.revision_tree.json"
),
o.doc_tree,
"Check document tree"
);
// put + revision history
o.doc = {
"_id": "put1",
//"_revs": ["3-rh3", "2-rh2", "1-rh1"], // same as below
"_revs": {"start": 3, "ids": ["rh3", "rh2", "rh1"]},
"title": "myPut3"
};
o.spy(o, "value", {"id": "put1", "ok": true, "rev": "3-rh3"},
"Put + revision history");
o.jio.put(o.doc, o.f);
o.tick(o);
// check document
o.doc._id = "put1.3-rh3";
delete o.doc._revs;
deepEqual(
util.jsonlocalstorage.getItem(o.localpath + "/put1.3-rh3"),
o.doc,
"Check document"
);
// check document tree
o.doc_tree.children.unshift({
"rev": "1-rh1",
"status": "missing",
"children": [{
"rev": "2-rh2",
"status": "missing",
"children": [{
"rev": "3-rh3",
"status": "available",
"children": []
}]
}]
});
deepEqual(
util.jsonlocalstorage.getItem(
o.localpath + "/put1.revision_tree.json"
),
o.doc_tree,
"Check document tree"
);
// add attachment
o.doc._attachments = {
"att1": {
"length": 1,
"content_type": "text/plain",
"digest": "md5-0cc175b9c0f1b6a831c399e269772661"
},
"att2": {
"length": 2,
"content_type": "dont/care",
"digest": "md5-5360af35bde9ebd8f01f492dc059593c"
}
};
util.jsonlocalstorage.setItem(o.localpath + "/put1.3-rh3", o.doc);
util.jsonlocalstorage.setItem(o.localpath + "/put1.3-rh3/att1", "a");
util.jsonlocalstorage.setItem(o.localpath + "/put1.3-rh3/att2", "bc");
// put + revision with attachment
o.attachments = o.doc._attachments;
o.doc = {"_id": "put1", "_rev": "3-rh3", "title": "myPut4"};
o.revisions = {"start": 3, "ids": ["rh3", "rh2", "rh1"]};
o.rev = "4-" + generateRevisionHash(o.doc, o.revisions);
o.spy(o, "value", {"id": "put1", "ok": true, "rev": o.rev},
"Put + revision (document contains attachments)");
o.jio.put(o.doc, o.f);
o.tick(o);
// check document
o.doc._id = "put1." + o.rev;
o.doc._attachments = o.attachments;
delete o.doc._rev;
deepEqual(
util.jsonlocalstorage.getItem(o.localpath + "/put1." + o.rev),
o.doc,
"Check document"
);
// check attachments
deepEqual(
util.jsonlocalstorage.getItem(o.localpath + "/put1." + o.rev + "/att1"),
"a",
"Check Attachment"
);
deepEqual(
util.jsonlocalstorage.getItem(o.localpath + "/put1." + o.rev + "/att2"),
"bc",
"Check Attachment"
);
// check document tree
o.doc_tree.children[0].children[0].children[0].children.unshift({
"rev": o.rev,
"status": "available",
"children": []
});
deepEqual(
util.jsonlocalstorage.getItem(
o.localpath + "/put1.revision_tree.json"
),
o.doc_tree,
"Check document tree"
);
util.closeAndcleanUpJio(o.jio);
});
test("Put Attachment", function () {
var o = generateTools();
o.jio = jIO.newJio({
"type": "revision",
"sub_storage": {
"type": "local",
"username": "urevputattmt",
"application_name": "arevputattmt"
}
});
// putAttachment without doc id
// error 20 -> document id required
o.spy(o, "status", 20, "PutAttachment without doc id" +
" -> 20 document id required");
o.jio.putAttachment({}, o.f);
o.tick(o);
// putAttachment without attachment id
// erorr 22 -> attachment id required
o.spy(o, "status", 22, "PutAttachment without attachment id" +
" -> 22 attachment id required");
o.jio.putAttachment({"_id": "putattmt1"}, o.f);
o.tick(o);
// putAttachment without document
o.revisions = {"start": 0, "ids": []};
o.rev_hash = generateRevisionHash({"_id": "doc1", "_attachment": "attmt1"},
o.revisions);
o.rev = "1-" + o.rev_hash;
o.spy(o, "value",
{"ok": true, "id": "doc1", "attachment": "attmt1", "rev": o.rev},
"PutAttachment without document, without data");
o.jio.putAttachment({"_id": "doc1", "_attachment": "attmt1"}, o.f);
o.tick(o);
// check document
deepEqual(
util.jsonlocalstorage.getItem(
"jio/localstorage/urevputattmt/arevputattmt/doc1." + o.rev
),
{
"_id": "doc1." + o.rev,
"_attachments": {
"attmt1": {
"length": 0,
// md5("")
"digest": "md5-d41d8cd98f00b204e9800998ecf8427e"
}
}
},
"Check document"
);
// check attachment
deepEqual(util.jsonlocalstorage.getItem(
"jio/localstorage/urevputattmt/arevputattmt/doc1." + o.rev
+ "/attmt1"
), "", "Check attachment");
// adding a metadata to the document
o.doc = util.jsonlocalstorage.getItem(
"jio/localstorage/urevputattmt/arevputattmt/doc1." + o.rev
);
o.doc.title = "My Title";
util.jsonlocalstorage.setItem(
"jio/localstorage/urevputattmt/arevputattmt/doc1." + o.rev,
o.doc
);
// update attachment
o.prev_rev = o.rev;
o.revisions = {"start": 1, "ids": [o.rev_hash]};
o.rev_hash = generateRevisionHash({
"_id": "doc1",
"_data": "abc",
"_attachment": "attmt1",
}, o.revisions);
o.rev = "2-" + o.rev_hash;
o.spy(o, "value",
{"ok": true, "id": "doc1", "attachment": "attmt1", "rev": o.rev},
"Update Attachment, with data");
o.jio.putAttachment({
"_id": "doc1",
"_data": "abc",
"_attachment": "attmt1",
"_rev": o.prev_rev
}, o.f);
o.tick(o);
// check document
deepEqual(
util.jsonlocalstorage.getItem(
"jio/localstorage/urevputattmt/arevputattmt/doc1." + o.rev
),
{
"_id": "doc1." + o.rev,
"title": "My Title",
"_attachments": {
"attmt1": {
"length": 3,
// md5("abc")
"digest": "md5-900150983cd24fb0d6963f7d28e17f72"
}
}
},
"Check document"
);
// check attachment
deepEqual(util.jsonlocalstorage.getItem(
"jio/localstorage/urevputattmt/arevputattmt/doc1." + o.rev +
"/attmt1"
), "abc", "Check attachment");
// putAttachment new attachment
o.prev_rev = o.rev;
o.revisions = {"start": 2, "ids": [o.rev_hash, o.revisions.ids[0]]};
o.rev_hash = generateRevisionHash({
"_id": "doc1",
"_data": "def",
"_attachment": "attmt2",
}, o.revisions);
o.rev = "3-" + o.rev_hash;
o.spy(o, "value",
{"ok": true, "id": "doc1", "attachment": "attmt2", "rev": o.rev},
"PutAttachment without document, without data");
o.jio.putAttachment({
"_id": "doc1",
"_data": "def",
"_attachment": "attmt2",
"_rev": o.prev_rev
}, o.f);
o.tick(o);
// check document
deepEqual(
util.jsonlocalstorage.getItem(
"jio/localstorage/urevputattmt/arevputattmt/doc1." + o.rev
),
{
"_id": "doc1." + o.rev,
"title": "My Title",
"_attachments": {
"attmt1": {
"length": 3,
"digest": "md5-900150983cd24fb0d6963f7d28e17f72"
},
"attmt2": {
"length": 3,
// md5("def")
"digest": "md5-4ed9407630eb1000c0f6b63842defa7d"
}
}
},
"Check document"
);
// check attachment
deepEqual(util.jsonlocalstorage.getItem(
"jio/localstorage/urevputattmt/arevputattmt/doc1." + o.rev +
"/attmt2"
), "def", "Check attachment");
util.closeAndcleanUpJio(o.jio);
});
test("Get", function () {
var o = generateTools();
o.jio = jIO.newJio({
"type": "revision",
"sub_storage": {
"type": "local",
"username": "urevget",
"application_name": "arevget"
}
});
o.localpath = "jio/localstorage/urevget/arevget";
// get inexistent document
o.spy(o, "status", 404, "Get inexistent document (winner)" +
" -> 404 Not Found");
o.jio.get({"_id": "get1"}, o.f);
o.tick(o);
// get inexistent attachment
o.spy(o, "status", 404, "Get inexistent attachment (winner)" +
" -> 404 Not Found");
o.jio.getAttachment({"_id": "get1", "_attachment": "get2"}, o.f);
o.tick(o);
// adding a document
o.doctree = {"children": [{
"rev": "1-rev1",
"status": "available",
"children": []
}]};
o.doc_myget1 = {"_id": "get1.1-rev1", "title": "myGet1"};
util.jsonlocalstorage.setItem(
o.localpath + "/get1.revision_tree.json",
o.doctree
);
util.jsonlocalstorage.setItem(o.localpath + "/get1.1-rev1", o.doc_myget1);
// get document
o.doc_myget1_cloned = deepClone(o.doc_myget1);
o.doc_myget1_cloned._id = "get1";
o.doc_myget1_cloned._rev = "1-rev1";
o.doc_myget1_cloned._revisions = {"start": 1, "ids": ["rev1"]};
o.doc_myget1_cloned._revs_info = [{
"rev": "1-rev1",
"status": "available"
}];
o.spy(o, "value", o.doc_myget1_cloned, "Get document (winner)");
o.jio.get({"_id": "get1"}, {
"revs_info": true,
"revs": true,
"conflicts": true
}, o.f);
o.tick(o);
// adding two documents
o.doctree = {"children": [{
"rev": "1-rev1",
"status": "available",
"children": []
}, {
"rev": "1-rev2",
"status": "available",
"children": [{
"rev": "2-rev3",
"status": "available",
"children": []
}]
}]};
o.doc_myget2 = {"_id": "get1.1-rev2", "title": "myGet2"};
o.doc_myget3 = {"_id": "get1.2-rev3", "title": "myGet3"};
util.jsonlocalstorage.setItem(
o.localpath + "/get1.revision_tree.json",
o.doctree
);
util.jsonlocalstorage.setItem(o.localpath + "/get1.1-rev2", o.doc_myget2);
util.jsonlocalstorage.setItem(o.localpath + "/get1.2-rev3", o.doc_myget3);
// get document
o.doc_myget3_cloned = deepClone(o.doc_myget3);
o.doc_myget3_cloned._id = "get1";
o.doc_myget3_cloned._rev = "2-rev3";
o.doc_myget3_cloned._revisions = {"start": 2, "ids": ["rev3", "rev2"]};
o.doc_myget3_cloned._revs_info = [{
"rev": "2-rev3",
"status": "available"
}, {
"rev": "1-rev2",
"status": "available"
}];
o.doc_myget3_cloned._conflicts = ["1-rev1"];
o.spy(o, "value", o.doc_myget3_cloned,
"Get document (winner, after posting another one)");
o.jio.get({"_id": "get1"},
{"revs_info": true, "revs": true, "conflicts": true},
o.f);
o.tick(o);
// get inexistent specific document
o.spy(o, "status", 404, "Get document (inexistent specific revision)" +
" -> 404 Not Found");
o.jio.get({"_id": "get1", "_rev": "1-rev0"}, {
"revs_info": true,
"revs": true,
"conflicts": true,
}, o.f);
o.tick(o);
// get specific document
o.doc_myget2_cloned = deepClone(o.doc_myget2);
o.doc_myget2_cloned._id = "get1";
o.doc_myget2_cloned._rev = "1-rev2";
o.doc_myget2_cloned._revisions = {"start": 1, "ids": ["rev2"]};
o.doc_myget2_cloned._revs_info = [{
"rev": "1-rev2",
"status": "available"
}];
o.doc_myget2_cloned._conflicts = ["1-rev1"];
o.spy(o, "value", o.doc_myget2_cloned, "Get document (specific revision)");
o.jio.get({"_id": "get1", "_rev": "1-rev2"}, {
"revs_info": true,
"revs": true,
"conflicts": true,
}, o.f);
o.tick(o);
// adding an attachment
o.attmt_myget3 = {
"get2": {
"length": 3,
"digest": "md5-dontcare",
"content_type": "oh/yeah"
}
};
o.doc_myget3._attachments = o.attmt_myget3;
util.jsonlocalstorage.setItem(o.localpath + "/get1.2-rev3", o.doc_myget3);
util.jsonlocalstorage.setItem(o.localpath + "/get1.2-rev3/get2", "abc");
// get attachment winner
o.spy(o, "value", "abc", "Get attachment (winner)");
o.jio.getAttachment({"_id": "get1", "_attachment": "get2"}, o.f);
o.tick(o);
// get inexistent attachment specific rev
o.spy(o, "status", 404, "Get inexistent attachment (specific revision)" +
" -> 404 Not Found");
o.jio.getAttachment({
"_id": "get1",
"_attachment": "get2",
"_rev": "1-rev1"
}, {
"revs_info": true,
"revs": true,
"conflicts": true,
}, o.f);
o.tick(o);
// get attachment specific rev
o.spy(o, "value", "abc", "Get attachment (specific revision)");
o.jio.getAttachment({
"_id": "get1",
"_attachment": "get2",
"_rev": "2-rev3"
}, {
"revs_info": true,
"revs": true,
"conflicts": true,
}, o.f);
o.tick(o);
// get document with attachment (specific revision)
delete o.doc_myget2_cloned._attachments;
o.spy(o, "value", o.doc_myget2_cloned,
"Get document which have an attachment (specific revision)");
o.jio.get({"_id": "get1", "_rev": "1-rev2"}, {
"revs_info": true,
"revs": true,
"conflicts": true
}, o.f);
o.tick(o);
// get document with attachment (winner)
o.doc_myget3_cloned._attachments = o.attmt_myget3;
o.spy(o, "value", o.doc_myget3_cloned,
"Get document which have an attachment (winner)");
o.jio.get({"_id": "get1"},
{"revs_info": true, "revs": true, "conflicts": true},
o.f);
o.tick(o);
util.closeAndcleanUpJio(o.jio);
});
test("Remove", function () {
var o = generateTools();
o.jio = jIO.newJio({
"type": "revision",
"sub_storage": {
"type": "local",
"username": "urevrem",
"application_name": "arevrem"
}
});
o.localpath = "jio/localstorage/urevrem/arevrem";
// 1. remove document without revision
o.spy(o, "status", 409, "Remove document without revision " +
"-> 409 Conflict");
o.jio.remove({"_id": "remove1"}, o.f);
o.tick(o);
// 2. remove attachment without revision
o.spy(o, "status", 409, "Remove attachment without revision " +
"-> 409 Conflict");
o.jio.removeAttachment({"_id": "remove1", "_attachment": "remove2"}, o.f);
o.tick(o);
// adding a document with attachments
o.doc_myremove1 = {
"_id": "remove1.1-veryoldrev",
"title": "myRemove1"
};
util.jsonlocalstorage.setItem(o.localpath + "/remove1.1-veryoldrev",
o.doc_myremove1);
o.doc_myremove1._id = "remove1.2-oldrev";
o.attachment_remove2 = {
"length": 3,
"digest": "md5-dontcare",
"content_type": "oh/yeah"
};
o.attachment_remove3 = {
"length": 5,
"digest": "md5-865f5cc7fbd7854902eae9d8211f178a",
"content_type": "he/ho"
};
o.doc_myremove1._attachments = {
"remove2": o.attachment_remove2,
"remove3": o.attachment_remove3
};
util.jsonlocalstorage.setItem(o.localpath + "/remove1.2-oldrev",
o.doc_myremove1);
util.jsonlocalstorage.setItem(
o.localpath + "/remove1.2-oldrev/remove2",
"abc"
);
util.jsonlocalstorage.setItem(
o.localpath + "/remove1.2-oldrev/remove3",
"defgh"
);
// add document tree
o.doctree = {
"children": [{
"rev": "1-veryoldrev",
"status": "available",
"children": [{
"rev": "2-oldrev",
"status": "available",
"children": []
}]
}]
};
util.jsonlocalstorage.setItem(o.localpath + "/remove1.revision_tree.json",
o.doctree);
// 3. remove inexistent attachment
o.spy(o, "status", 404, "Remove inexistent attachment -> 404 Not Found");
o.jio.removeAttachment({
"_id": "remove1",
"_attachment": "remove0",
"_rev": "2-oldrev"
}, o.f);
o.tick(o);
// 4. remove existing attachment
o.rev_hash = generateRevisionHash({
"_id": "remove1",
"_attachment": "remove2",
}, {"start": 2, "ids": ["oldrev", "veryoldrev"]});
o.spy(o, "value", {
"ok": true,
"id": "remove1",
"attachment": "remove2",
"rev": "3-" + o.rev_hash
}, "Remove existing attachment");
o.jio.removeAttachment({
"_id": "remove1",
"_attachment": "remove2",
"_rev": "2-oldrev"
}, o.f);
o.tick(o);
o.doctree = {
"_id": "remove1.revision_tree.json",
"children": [{
"rev": "1-veryoldrev",
"status": "available",
"children": [{
"rev": "2-oldrev",
"status": "available",
"children": [{
"rev": "3-" + o.rev_hash,
"status": "available",
"children": []
}]
}]
}]
};
// 5. check if document tree has been updated correctly
deepEqual(util.jsonlocalstorage.getItem(
o.localpath + "/remove1.revision_tree.json"
), o.doctree, "Check document tree");
// 6. check if the attachment still exists
deepEqual(util.jsonlocalstorage.getItem(
o.localpath + "/remove1.2-oldrev/remove2"
), "abc", "Check attachment -> still exists");
// 7. check if document is updated
deepEqual(util.jsonlocalstorage.getItem(
o.localpath + "/remove1.3-" + o.rev_hash
), {
"_id": "remove1.3-" + o.rev_hash,
"title": "myRemove1",
"_attachments": {"remove3": o.attachment_remove3}
}, "Check document");
// 8. remove document with wrong revision
o.spy(o, "status", 409, "Remove document with wrong revision " +
"-> 409 Conflict");
o.jio.remove({"_id": "remove1", "_rev": "1-a"}, o.f);
o.tick(o);
// 9. remove attachment wrong revision
o.spy(o, "status", 409, "Remove attachment with wrong revision " +
"-> 409 Conflict");
o.jio.removeAttachment({
"_id": "remove1",
"_attachment": "remove2",
"_rev": "1-a"
}, o.f);
o.tick(o);
// 10. remove document
o.last_rev = "3-" + o.rev_hash;
o.rev_hash = generateRevisionHash(
{"_id": "remove1"},
{"start": 3, "ids": [o.rev_hash, "oldrev", "veryoldrev"]},
true
);
o.spy(o, "value", {"ok": true, "id": "remove1", "rev": "4-" + o.rev_hash},
"Remove document");
o.jio.remove({"_id": "remove1", "_rev": o.last_rev}, o.f);
o.tick(o);
// 11. check document tree
o.doctree.children[0].children[0].children[0].children.unshift({
"rev": "4-" + o.rev_hash,
"status": "deleted",
"children": []
});
deepEqual(util.jsonlocalstorage.getItem(
o.localpath + "/remove1.revision_tree.json"
), o.doctree, "Check document tree");
util.closeAndcleanUpJio(o.jio);
});
test("allDocs", function () {
var o = generateTools();
o.jio = jIO.newJio({
"type": "revision",
"sub_storage": {
"type": "local",
"username": "urevad1",
"application_name": "arevad1"
}
});
o.localpath = "jio/localstorage/urevad1/arevad1";
// adding 3 documents
o.jio.put({"_id": "yes"}, function (err, response) {
o.rev1 = (response || {}).rev;
});
o.jio.put({"_id": "no"}, function (err, response) {
o.rev2 = (response || {}).rev;
});
o.jio.put({"_id": "maybe"}, function (err, response) {
o.rev3 = (response || {}).rev;
});
o.clock.tick(1000);
// adding conflicts
o.jio.put({"_id": "maybe"});
// adding 2 attachments
o.jio.putAttachment({
"_id": "yes",
"_attachment": "blue",
"_mimetype": "text/plain",
"_rev": o.rev1,
"_data": "sky"
}, function (err, response) {
o.rev1 = (response || {}).rev;
});
o.jio.putAttachment({
"_id": "no",
"_attachment": "Heeeee!",
"_mimetype": "text/plain",
"_rev": o.rev2,
"_data": "Hooooo!"
}, function (err, response) {
o.rev2 = (response || {}).rev;
});
o.clock.tick(1000);
o.rows = {
"total_rows": 3,
"rows": [{
"id": "maybe",
"key": "maybe",
"value": {
"rev": o.rev3
}
}, {
"id": "no",
"key": "no",
"value": {
"rev": o.rev2
}
}, {
"id": "yes",
"key": "yes",
"value": {
"rev": o.rev1
}
}]
};
o.spy(o, "value", o.rows, "allDocs");
o.jio.allDocs(function (err, response) {
if (response && response.rows) {
response.rows.sort(function (a, b) {
return a.id > b.id ? 1 : a.id < b.id ? -1 : 0;
});
}
o.f(err, response);
});
o.tick(o);
o.rows.rows[0].doc = {
"_id": "maybe",
"_rev": o.rev3
};
o.rows.rows[1].doc = {
"_id": "no",
"_rev": o.rev2,
"_attachments": {
"Heeeee!": {
"content_type": "text/plain",
"digest": "md5-2686969b0bc0fd9bc186146a1ecb09a7",
"length": 7
}
},
};
o.rows.rows[2].doc = {
"_id": "yes",
"_rev": o.rev1,
"_attachments": {
"blue": {
"content_type": "text/plain",
"digest": "md5-900bc885d7553375aec470198a9514f3",
"length": 3
}
},
};
o.spy(o, "value", o.rows, "allDocs + include docs");
o.jio.allDocs({"include_docs": true}, function (err, response) {
if (response && response.rows) {
response.rows.sort(function (a, b) {
return a.id > b.id ? 1 : a.id < b.id ? -1 : 0;
});
}
o.f(err, response);
});
o.tick(o);
util.closeAndcleanUpJio(o.jio);
});
test("Scenario", function () {
var o = generateTools();
o.jio = jIO.newJio({
"type": "revision",
"sub_storage": {
"type": "local",
"username": "usam1",
"application_name": "asam1"
}
});
o.localpath = "jio/localstorage/usam1/asam1";
// new application
ok(o.jio, "I open my application with revision and localstorage");
// put non empty document A-1
o.doc = {"_id": "sample1", "title": "mySample1"};
o.revisions = {"start": 0, "ids": []};
o.hex = generateRevisionHash(o.doc, o.revisions);
o.rev = "1-" + o.hex;
o.spy(o, "value", {"ok": true, "id": "sample1", "rev": o.rev},
"Then, I create a new document (no attachment), my application " +
"keep the revision in memory");
o.jio.put(o.doc, o.f);
o.tick(o);
// open new tab (JIO)
o.jio2 = jIO.newJio({
"type": "revision",
"sub_storage": {
"type": "local",
"username": "usam1",
"application_name": "asam1"
}
});
o.localpath = "jio/localstorage/usam1/asam1";
// Create a new JIO in a new tab
ok(o.jio2, "Now, I am opening a new tab, with the same application" +
" and the same storage tree");
// Get the document from the first storage
o.doc._rev = o.rev;
o.doc._revisions = {"ids": [o.hex], "start": 1};
o.doc._revs_info = [{"rev": o.rev, "status": "available"}];
o.spy(o, "value", o.doc, "And, on this new tab, I load the document," +
"and my application keep the revision in memory");
o.jio2.get({"_id": "sample1", "_rev": o.rev}, {
"revs_info": true,
"revs": true,
"conflicts": true,
}, o.f);
o.tick(o);
// MODIFY the 2nd version
o.doc_2 = {"_id": "sample1", "_rev": o.rev,
"title": "mySample2_modified"};
o.revisions_2 = {"start": 1, "ids": [o.hex]};
o.hex_2 = generateRevisionHash(o.doc_2, o.revisions_2);
o.rev_2 = "2-" + o.hex_2;
o.spy(o, "value", {"id": "sample1", "ok": true, "rev": o.rev_2},
"So, I can modify and update it");
o.jio2.put(o.doc_2, o.f);
o.tick(o);
// MODIFY first version
o.doc_1 = {
"_id": "sample1",
"_rev": o.rev,
"title": "mySample1_modified"
};
o.revisions_1 = {"start": 1, "ids": [o.rev.split('-')[1]]};
o.hex_1 = generateRevisionHash(o.doc_1, o.revisions_1);
o.rev_1 = "2-" + o.hex_1;
o.spy(o, "value", {"id": "sample1", "ok": true, "rev": o.rev_1},
"Back to the first tab, I update the document.");
o.jio.put(o.doc_1, o.f);
o.tick(o);
// Close 1st tab
o.jio.close();
// Close 2nd tab
o.jio2.close();
ok(o.jio2, "I close tab both tabs");
// Reopen JIO
o.jio = jIO.newJio({
"type": "revision",
"sub_storage": {
"type": "local",
"username": "usam1",
"application_name": "asam1"
}
});
o.localpath = "jio/localstorage/usam1/asam1";
ok(o.jio, "Later, I open my application again");
// GET document without revision = winner & conflict!
o.mydocSample3 = {"_id": "sample1", "title": "mySample1_modified",
"_rev": o.rev_1};
o.mydocSample3._conflicts = [o.rev_2];
o.mydocSample3._revs_info = [{"rev": o.rev_1, "status": "available"}, {
"rev": o.rev,
"status": "available"
}];
o.mydocSample3._revisions = {"ids": [o.hex_1, o.hex], "start": 2};
o.spy(o, "value", o.mydocSample3, "I load the same document as before" +
", and a popup shows that there is a conflict");
o.jio.get({"_id": "sample1"}, {
"revs_info": true,
"revs": true,
"conflicts": true
}, o.f);
o.tick(o);
// REMOVE one of the two conflicting versions
o.revisions = {"start": 2, "ids": [
o.rev_1.split('-')[1],
o.rev.split('-')[1]
]};
o.doc_myremove3 = {"_id": "sample1", "_rev": o.rev_1};
o.rev_3 = "3-" + generateRevisionHash(o.doc_myremove3, o.revisions, true);
o.spy(o, "value", {"ok": true, "id": "sample1", "rev": o.rev_3},
"I choose one of the document and close the application.");
o.jio.remove({"_id": "sample1", "_rev": o.rev_1}, o.f);
o.tick(o);
// check to see if conflict still exists
o.mydocSample4 = {
"_id": "sample1",
"title": "mySample2_modified",
"_rev": o.rev_2
};
o.mydocSample4._revs_info = [{"rev": o.rev_2, "status": "available"}, {
"rev": o.rev,
"status": "available"
}];
o.mydocSample4._revisions = {"ids": [o.hex_2, o.hex], "start": 2};
o.spy(o, "value", o.mydocSample4, "Test if conflict still exists");
o.jio.get({"_id": "sample1"}, {
"revs_info": true,
"revs": true,
"conflicts": true
}, o.f);
o.tick(o);
// END
util.closeAndcleanUpJio(o.jio);
});
}));
/*jslint indent: 2, maxlen: 80, nomen: true */
/*global define, jIO, jio_tests, window, test, ok, deepEqual, sinon, expect */
// define([module_name], [dependencies], module);
(function (dependencies, module) {
"use strict";
if (typeof define === 'function' && define.amd) {
return define(dependencies, module);
}
module(jIO, jio_tests);
}(['jio', 'jio_tests', 's3storage'], function (jIO, util) {
"use strict";
function generateTools() {
return {
clock: sinon.useFakeTimers(),
spy: util.ospy,
tick: util.otick
};
}
module("Amazon S3 Storage");
/*
Post without id
Create = POST non empty document
Post but document already exists
*/
test("Post", function () {
var o = generateTools(this);
o.jio = jIO.newJio({
"type": "s3",
"AWSIdentifier": "dontcare",
"password": "dontcare",
"server": "jiobucket",
"url": "https://jiobucket.s3.amazonaws.com"
});
o.server = sinon.fakeServer.create();
//Post without ID (ID is generated by storage)
o.server.respondWith("GET",
"https://jiobucket.s3.amazonaws.com/",
[404, {}, "HTML Response"]
);
o.server.respondWith("POST",
"https://jiobucket.s3.amazonaws.com/",
[204, {}, "HTML Response"]
);
//o.spy(o, "status", 405, "Post without id");
o.spy(o, "jobstatus", "done", "Post without ID");
o.jio.post({}, o.f);
o.clock.tick(1000);
o.server.respond();
o.tick(o);
o.server.restore();
//Post with ID
o.server = sinon.fakeServer.create();
o.server.respondWith("GET",
"https://jiobucket.s3.amazonaws.com/post1",
[404, {}, "HTML Response"]
);
o.server.respondWith("POST",
"https://jiobucket.s3.amazonaws.com/",
[204, {}, "HTML Response"]
);
o.spy(o, "value", {'ok': true, 'id': 'post1'}, "Post with ID");
o.jio.post({"_id": "post1", "title": "myPost1"}, o.f);
o.clock.tick(1000);
o.server.respond();
o.tick(o);
o.server.restore();
//Post but document already exists (update)
o.server = sinon.fakeServer.create();
o.server.respondWith("GET",
"http://s3.amazonaws.com/jiobucket/post2",
[200, {}, "HTML Response"]
);
o.spy(o, "status", 409, "Post but document already exists (update)");
//o.spy(o, "jobstatus", "done", "Post without ID");
o.jio.post({"_id": "post2", "title": "myPost2"}, o.f);
o.clock.tick(1000);
o.server.respond();
o.tick(o);
o.server.restore();
util.closeAndcleanUpJio(o.jio);
});
/*
Put without id
Create = PUT non empty document
Updated the document
*/
test("Put", function () {
var o = generateTools(this);
o.jio = jIO.newJio({
"type": "s3",
"AWSIdentifier": "dontcare",
"password": "dontcare",
"server": "jiobucket",
"url": "http://s3.amazonaws.com/jiobucket/put1"
});
// put without id => id required
o.server = sinon.fakeServer.create();
o.spy(o, "status", 20, "Put without id");
o.jio.put({}, o.f);
o.clock.tick(5000);
o.server.respond();
o.tick(o);
o.server.restore();
//Put non empty document
o.server = sinon.fakeServer.create();
o.server.respondWith(
"GET",
"http://s3.amazonaws.com/jiobucket/http:%252F%252F100%2525_.json",
[404, {}, "HTML Response"]
);
o.server.respondWith(
"PUT",
"http://s3.amazonaws.com/jiobucket/http:%252F%252F100%2525_.json",
[200, {}, "HTML Response"]
);
o.spy(o, "value", {"ok": true, "id": "http://100%.json"},
"PUT non empty document");
o.jio.put({"_id": "http://100%.json", "title": "myPut1"}, o.f);
o.clock.tick(5000);
o.server.respond();
o.tick(o);
o.server.restore();
//Put an existing document (update)
o.server = sinon.fakeServer.create();
o.server.respondWith(
"GET",
"http://s3.amazonaws.com/jiobucket/http:%252F%252F100%2525_.json",
[200, {}, "HTML Response"]
);
o.server.respondWith(
"PUT",
"http://s3.amazonaws.com/jiobucket/http:%252F%252F100%2525_.json",
[200, {}, "HTML Response"]
);
o.spy(o, "value", {"ok": true, "id": "http://100%.json"},
"PUT non empty document");
o.jio.put({"_id": "http://100%.json", "title": "myPut1"}, o.f);
o.clock.tick(1000);
o.server.respond();
o.tick(o);
o.server.restore();
util.closeAndcleanUpJio(o.jio);
});
test("PutAttachment", function () {
var o = generateTools(this);
o.jio = jIO.newJio({
"type": "s3",
"AWSIdentifier": "dontcare",
"password": "dontcare",
"server": "jiobucket",
"url": "https://jiobucket.s3.amazonaws.com"
});
//PutAttachment without document ID (document ID is required)
o.server = sinon.fakeServer.create();
//PutAttachment without attachment ID (attachment ID is required)
o.spy(o, "status", 20, "PutAttachment without doc id -> 20");
o.jio.putAttachment({"_attachment": "putattmt1"}, o.f);
o.tick(o);
// putAttachment without attachment id => 22 Attachment Id Required
o.spy(o, "status", 22, "PutAttachment without attachment id -> 22");
o.jio.putAttachment({"_id": "http://100%.json"}, o.f);
o.tick(o);
//PutAttachment without underlying document (document is required)
o.server = sinon.fakeServer.create();
o.server.respondWith(
"GET",
"http://s3.amazonaws.com/jiobucket/http:%252F%252F100%2525_.json",
[404, {}, "HTML Response"]
);
o.spy(o, "status", 404, "PutAttachment without document -> 404");
o.jio.putAttachment({
"_id": "http://100%.json",
"_attachment": "putattmt2"
}, {"max_retry": 1}, o.f);
o.clock.tick(1000);
o.server.respond();
o.tick(o);
o.server.restore();
//PutAttachment
o.server = sinon.fakeServer.create();
o.server.respondWith(
"GET",
"http://s3.amazonaws.com/jiobucket/http:%252F%252F100%2525_.json",
[
200,
{"Content-Type": "text/plain"},
'{"_id":"http://100%.json","title":"Hi There!"}'
]
);
o.server.respondWith(
"PUT",
"http://s3.amazonaws.com/jiobucket/http:%252F%252F100%2525_.json",
[200, {}, "HTML Response"]
);
o.server.respondWith(
"PUT",
"http://s3.amazonaws.com/jiobucket" +
"/http:%252F%252F100%2525_.json.body_.html",
[200, {}, "HTML Response"]
);
o.spy(o, "value", {
"ok": true,
"id": "http://100%.json",
"attachment": "body.html"
}, "PutAttachment");
o.jio.putAttachment({
"_id": "http://100%.json",
"_attachment": "body.html",
"_mimetype": "text/html",
"_data": "<h1>Hi There!!</h1><p>How are you?</p>"
}, {"max_retry": 1}, o.f);
o.clock.tick(1000);
o.server.respond();
o.tick(o);
o.server.restore();
util.closeAndcleanUpJio(o.jio);
});
/*
Get non existing document
Get non existing attachment
Get document
Get non existing attachment (doc exists)
Get attachment
*/
test("Get", function () {
var o = generateTools(this);
o.jio = jIO.newJio({
"type": "s3",
"AWSIdentifier": "dontcare",
"password": "dontcare",
"server": "jiobucket",
"url": "https://jiobucket.s3.amazonaws.com"
});
//Get non existing document
o.server = sinon.fakeServer.create();
o.server.respondWith("GET",
"https://jiobucket.s3.amazonaws.com/doc",
[404, {}, "HTML Response"]
);
o.spy(o, "status", 404, "Get non existing document");
o.jio.get("doc", {"max_retry": 1}, o.f);
o.clock.tick(5000);
o.server.respond();
o.tick(o);
o.server.restore();
//Get document
o.server = sinon.fakeServer.create();
o.server.respondWith(
"GET",
"http://s3.amazonaws.com/jiobucket/http:%252F%252F100%2525_.json",
[
200,
{"Content-Type": "text/plain"},
'{"_id":"http://100%.json","title":"Hi There!"}'
]
);
o.spy(o, "value", {"_id": "http://100%.json", "title": "Hi There!"},
"Get document");
o.jio.get({"_id": "http://100%.json"}, {"max_retry": 1}, o.f);
o.clock.tick(5000);
o.server.respond();
o.tick(o);
o.server.restore();
util.closeAndcleanUpJio(o.jio);
});
test("GetAttachment", function () {
var o = generateTools(this);
o.jio = jIO.newJio({
"type": "s3",
"AWSIdentifier": "dontcare",
"password": "dontcare",
"server": "jiobucket",
"url": "https://jiobucket.s3.amazonaws.com"
});
//Get non existing attachment
o.server = sinon.fakeServer.create();
o.server.respondWith(
"GET",
"http://s3.amazonaws.com/jiobucket" +
"/http:%252F%252F100%2525_.json.body_.html",
[404, {}, "HTML Response"]
);
o.spy(o, "status", 404, "Get non existing attachment");
o.jio.getAttachment({
"_id": "http://100%.json",
"_attachment": "body.html"
}, {"max_retry": 1}, o.f);
o.clock.tick(5000);
o.server.respond();
o.tick(o);
o.server.restore();
//Get attachment
o.server = sinon.fakeServer.create();
o.server.respondWith(
"GET",
"http://s3.amazonaws.com/jiobucket" +
"/http:%252F%252F100%2525_.json.body_.html",
[200, {"Content-Type": "text/plain"}, "My Attachment Content"]
);
o.spy(o, "value", "My Attachment Content", "Get attachment");
o.jio.getAttachment({
"_id": "http://100%.json",
"_attachment": "body.html"
}, {"max_retry": 1}, o.f);
o.clock.tick(5000);
o.server.respond();
o.tick(o);
o.server.restore();
util.closeAndcleanUpJio(o.jio);
});
//begins the remove tests
/*
Remove inexistent document
Remove inexistent document/attachment
Remove document
Check index file
Check if document has been removed
Remove one of multiple attachment
Check index file
Remove one document and attachment together
Check index file
Check if attachment has been removed
Check if document has been removed
*/
test("Remove", function () {
var o = generateTools(this);
o.jio = jIO.newJio({
"type": "s3",
"AWSIdentifier": "dontcare",
"password": "dontcare",
"server": "jiobucket",
"url": "https://jiobucket.s3.amazonaws.com/"
});
//Remove non-existing document
o.server = sinon.fakeServer.create();
o.server.respondWith(
"DELETE",
"http://s3.amazonaws.com/jiobucket/http:%252F%252F100%2525_.json",
[404, {}, "HTML RESPONSE"]
);
o.spy(o, "status", 404, "Remove non existing document");
o.jio.remove({"_id": "http://100%.json"}, o.f);
o.clock.tick(5000);
o.server.respond();
o.server.restore();
//Remove document
o.server = sinon.fakeServer.create();
o.server.respondWith(
"DELETE",
"http://s3.amazonaws.com/jiobucket/http:%252F%252F100%2525_.json",
[200, {"Content-Type": "text/plain"}, "My Attachment Content"]
);
o.spy(o, "value", {"ok": true, "id": "http://100%.json"},
"Remove document");
o.jio.remove({"_id": "http://100%.json"}, o.f);
o.clock.tick(5000);
o.server.respond();
o.tick(o);
o.server.restore();
//Remove document with multiple attachments
o.server = sinon.fakeServer.create();
o.server.respondWith(
"GET",
"http://s3.amazonaws.com/jiobucket/http:%252F%252F100%2525_.json",
[
200,
{"Content-Type": "text/html"},
JSON.stringify({
"_attachments": {
"body.html": {
"length": 32,
"digest": "md5-dontcare",
"content_type": "text/html"
},
"other": {
"length": 3,
"digest": "md5-dontcare-again",
"content_type": "text/plain"
}
}
})
]
);
o.server.respondWith(
"DELETE",
"http://s3.amazonaws.com/jiobucket/http:%252F%252F100%2525_.json",
[200, {"Content-Type": "text/plain"}, "<h1>Deleted</h1>"]
);
o.server.respondWith(
"DELETE",
"http://s3.amazonaws.com/jiobucket" +
"/http:%252F%252F100%2525_.json.body_.html",
[200, {"Content-Type": "text/plain"}, "<h1>Deleted</h1>"]
);
o.server.respondWith(
"DELETE",
"http://s3.amazonaws.com/jiobucket/http:%252F%252F100%2525_.json.other",
[200, {"Content-Type": "text/plain"}, "<h1>Deleted</h1>"]
);
o.spy(o, "value", {"ok": true, "id": "http://100%.json"},
"Remove document containing multiple attachments");
o.jio.remove({"_id": "http://100%.json"}, {"max_retry": 1}, o.f);
o.clock.tick(1000);
o.server.respond();
o.tick(o);
o.server.restore();
util.closeAndcleanUpJio(o.jio);
});
test("RemoveAttachment", function () {
var o = generateTools(this);
o.jio = jIO.newJio({
"type": "s3",
"AWSIdentifier": "dontcare",
"password": "dontcare",
"server": "jiobucket",
"url": "https://jiobucket.s3.amazonaws.com/"
});
//Remove non-existing attachment
o.server = sinon.fakeServer.create();
o.server.respondWith(
"DELETE",
"http://s3.amazonaws.com/jiobucket" +
"/http:%252F%252F100%2525_.json.body_.html",
[404, {}, "HTML RESPONSE"]
);
o.spy(o, "status", 404, "Remove non existing attachment");
o.jio.removeAttachment({
"_id": "http://100%.json",
"_attachment": "body.html"
}, {"max_retry": 1}, o.f);
o.clock.tick(5000);
o.server.respond();
o.server.restore();
//Remove attachment
o.server = sinon.fakeServer.create();
o.server.respondWith(
"GET",
"http://s3.amazonaws.com/jiobucket/http:%252F%252F100%2525_.json",
[
200,
{"Content-Type": "text/plain"},
'{"_id":"http://100%.json","title":"Hi There!"}'
]
);
o.server.respondWith(
"PUT",
"http://s3.amazonaws.com/jiobucket/http:%252F%252F100%2525_.json",
[
200,
{"Content-Type": "text/plain"},
'{"_id":"http://100%.json","title":"Hi There!"}'
]
);
o.server.respondWith(
"DELETE",
"http://s3.amazonaws.com/jiobucket" +
"/http:%252F%252F100%2525_.json.body_.html",
[200, {"Content-Type": "text/plain"}, "My Attachment Content"]
);
o.spy(o, "value", {
"ok": true,
"id": "http://100%.json",
"attachment": "body.html"
}, "Remove attachment");
o.jio.removeAttachment({
"_id": "http://100%.json",
"_attachment": "body.html"
}, {"max_retry": 1}, o.f);
o.clock.tick(5000);
o.server.respond();
o.tick(o);
o.server.restore();
util.closeAndcleanUpJio(o.jio);
});
test("AllDocs", function () {
var o = generateTools(this);
o.jio = jIO.newJio({
"type": "s3",
"AWSIdentifier": "dontcare",
"password": "dontcare",
"server": "jiobucket",
"url": "https://jiobucket.s3.amazonaws.com/"
});
//allDocs without option
o.server = sinon.fakeServer.create();
o.server.respondWith(
"GET",
"http://s3.amazonaws.com/jiobucket/",
[
204,
{},
'<?xml version="1.0" encoding="UTF-8"?><ListBucketResult xml' +
'ns="http://s3.amazonaws.com/doc/2006-03-01/"><Name>jiobucke' +
't</Name><Prefix></Prefix><Marker></Marker><MaxKeys>1000</Ma' +
'xKeys><IsTruncated>false</IsTruncated><Contents><Key>docume' +
'ntONE</Key><LastModified>2013-05-03T15:32:01.000Z</LastModi' +
'fied><ETag>&quot;8a65389818768e1f5e6530a949233581&quot;</ET' +
'ag><Size>163</Size><Owner><ID>5d09e586ab92acad85e9d053f769c' +
'ce65f82178e218d9ac9b0473f3ce7f89606</ID><DisplayName>jonath' +
'an.rivalan</DisplayName></Owner><StorageClass>STANDARD</Sto' +
'rageClass></Contents><Contents><Key>documentONE.1st_Attachm' +
'ent_manual</Key><LastModified>2013-05-03T15:32:02.000Z</Las' +
'tModified><ETag>&quot;f391dec65366d2b470406bc7b9595dea&quot' +
';</ETag><Size>35</Size><Owner><ID>5d09e586ab92acad85e9d053f' +
'769cce65f82178e218d9ac9b0473f3ce7f89606</ID><DisplayName>jo' +
'nathan.rivalan</DisplayName></Owner><StorageClass>STANDARD<' +
'/StorageClass></Contents></ListBucketResult>'
]
);
o.spy(o, "jobstatus", "done", "AllDocs without include docs");
o.jio.allDocs(o.f);
o.clock.tick(5000);
o.server.respond();
o.tick(o);
o.server.restore();
//allDocs with the include docs option
o.server = sinon.fakeServer.create();
o.server.respondWith(
"GET",
"http://s3.amazonaws.com/jiobucket/",
[
204,
{},
'<?xml version="1.0" encoding="UTF-8"?><ListBucketResult xml' +
'ns="http://s3.amazonaws.com/doc/2006-03-01/"><Name>jiobucke' +
't</Name><Prefix></Prefix><Marker></Marker><MaxKeys>1000</Ma' +
'xKeys><IsTruncated>false</IsTruncated><Contents><Key>docume' +
'ntONE</Key><LastModified>2013-05-03T15:32:01.000Z</LastModi' +
'fied><ETag>&quot;8a65389818768e1f5e6530a949233581&quot;</ET' +
'ag><Size>163</Size><Owner><ID>5d09e586ab92acad85e9d053f769c' +
'ce65f82178e218d9ac9b0473f3ce7f89606</ID><DisplayName>jonath' +
'an.rivalan</DisplayName></Owner><StorageClass>STANDARD</Sto' +
'rageClass></Contents><Contents><Key>documentONE.1st_Attachm' +
'ent_manual</Key><LastModified>2013-05-03T15:32:02.000Z</Las' +
'tModified><ETag>&quot;f391dec65366d2b470406bc7b9595dea&quot' +
';</ETag><Size>35</Size><Owner><ID>5d09e586ab92acad85e9d053f' +
'769cce65f82178e218d9ac9b0473f3ce7f89606</ID><DisplayName>jo' +
'nathan.rivalan</DisplayName></Owner><StorageClass>STANDARD<' +
'/StorageClass></Contents></ListBucketResult>'
]
);
o.server.respondWith(
"GET",
"http://jiobucket.s3.amazonaws.com/documentONE",
[
200,
{"Content-Type": "text/html"},
JSON.stringify({
"_attachments": {
"body.html": {
"length": 32,
"digest": "md5-dontcare",
"content_type": "text/html"
},
"other": {
"length": 3,
"digest": "md5-dontcare-again",
"content_type": "text/plain"
}
}
})
]
);
o.spy(o, "jobstatus", "done", "AllDocs with include docs");
o.jio.allDocs({"include_docs": true}, o.f);
o.clock.tick(5000);
o.server.respond();
o.tick(o);
o.server.restore();
util.closeAndcleanUpJio(o.jio);
});
}));
/*jslint indent: 2, maxlen: 80, nomen: true */
/*global define, jIO, jio_tests, test, ok, deepEqual, sinon */
// define([module_name], [dependencies], module);
(function (dependencies, module) {
"use strict";
if (typeof define === 'function' && define.amd) {
return define(dependencies, module);
}
module(jIO, jio_tests);
}(['jio', 'jio_tests', 'localstorage', 'splitstorage'], function (jIO, util) {
"use strict";
function generateTools() {
return {
clock: sinon.useFakeTimers(),
spy: util.ospy,
tick: util.otick
};
}
module("SplitStorage + LocalStorage");
test("Post", function () {
var o = generateTools();
o.jio = jIO.newJio({
"type": "split",
"storage_list": [{
"type": "local",
"username": "splitstorage",
"application_name": "post1"
}, {
"type": "local",
"username": "splitstorage",
"application_name": "post2"
}]
});
// post without id
o.spy(o, "jobstatus", "done", "Post document without id");
o.jio.post({
"_underscored_meta": "uvalue",
"meta": "data"
}, function (err, response) {
o.f(err, response);
o.uuid = (err || response).id;
ok(util.isUuid(o.uuid), "Uuid should look like " +
"xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx : " + o.uuid);
});
o.tick(o);
// check uploaded documents
deepEqual(util.jsonlocalstorage.getItem(
'jio/localstorage/splitstorage/post1/' + o.uuid
), {
"_id": o.uuid,
"_underscored_meta": "uvalue",
"data": "{\"meta\""
}, "Check uploaded document in sub storage 1");
deepEqual(util.jsonlocalstorage.getItem(
'jio/localstorage/splitstorage/post2/' + o.uuid
), {
"_id": o.uuid,
"_underscored_meta": "uvalue",
"data": ":\"data\"}"
}, "Check uploaded document in sub storage 2");
// post with id
o.spy(o, "value", {"ok": true, "id": "one"}, "Post document with id");
o.jio.post({
"_id": "one",
"_underscored_meta": "uvalue",
"meta": "data",
"hello": "world"
}, o.f);
o.tick(o);
// check uploaded documents
deepEqual(util.jsonlocalstorage.getItem(
'jio/localstorage/splitstorage/post1/one'
), {
"_id": "one",
"_underscored_meta": "uvalue",
"data": "{\"meta\":\"data\","
}, "Check uploaded document in sub storage 1");
deepEqual(util.jsonlocalstorage.getItem(
'jio/localstorage/splitstorage/post2/one'
), {
"_id": "one",
"_underscored_meta": "uvalue",
"data": "\"hello\":\"world\"}"
}, "Check uploaded document in sub storage 2");
// post with id
o.spy(o, "status", 409, "Post document with same id");
o.jio.post({
"_id": "one",
"_underscored_meta": "uvalue",
"meta": "data",
"hello": "world"
}, o.f);
o.tick(o);
util.closeAndcleanUpJio(o.jio);
});
test("PutAttachment", function () {
var o = generateTools();
o.jio = jIO.newJio({
"type": "split",
"storage_list": [{
"type": "local",
"username": "splitstorage",
"application_name": "putAttachment1"
}, {
"type": "local",
"username": "splitstorage",
"application_name": "putAttachment2"
}]
});
o.spy(o, "status", 404, "Put attachment on a inexistent document");
o.jio.putAttachment({
"_id": "one",
"_attachment": "my_attachment",
"_data": "My Data",
"_mimetype": "text/plain"
}, o.f);
o.tick(o);
o.jio.post({"_id": "one", "_underscored_meta": "uvalue", "meta": "data"});
o.clock.tick(1000);
o.spy(o, "value", {
"ok": true,
"id": "one",
"attachment": "my_attachment"
}, "Put attachment");
o.jio.putAttachment({
"_id": "one",
"_attachment": "my_attachment",
"_data": "My Data",
"_mimetype": "text/plain"
}, o.f);
o.tick(o);
// check uploaded documents
deepEqual(util.jsonlocalstorage.getItem(
'jio/localstorage/splitstorage/putAttachment1/one'
), {
"_id": "one",
"_underscored_meta": "uvalue",
"data": "{\"meta\"",
"_attachments": {
"my_attachment": {
"length": 3,
"digest": "md5-1b4686bc8ca15befdccb1da1dcb8c271", // md5("My ")
"content_type": "text/plain"
}
}
}, "Check uploaded document in sub storage 1");
deepEqual(util.jsonlocalstorage.getItem(
'jio/localstorage/splitstorage/putAttachment2/one'
), {
"_id": "one",
"_underscored_meta": "uvalue",
"data": ":\"data\"}",
"_attachments": {
"my_attachment": {
"length": 4,
"digest": "md5-f6068daa29dbb05a7ead1e3b5a48bbee", // md5("Data")
"content_type": "text/plain"
}
}
}, "Check uploaded document in sub storage 2");
deepEqual(util.jsonlocalstorage.getItem(
'jio/localstorage/splitstorage/putAttachment1/one/my_attachment'
), "My ", "Check uploaded document in sub storage 1");
deepEqual(util.jsonlocalstorage.getItem(
'jio/localstorage/splitstorage/putAttachment2/one/my_attachment'
), "Data", "Check uploaded document in sub storage 2");
util.closeAndcleanUpJio(o.jio);
});
test("Get", function () {
var o = generateTools();
o.jio = jIO.newJio({
"type": "split",
"storage_list": [{
"type": "local",
"username": "splitstorage",
"application_name": "get1"
}, {
"type": "local",
"username": "splitstorage",
"application_name": "get2"
}]
});
o.spy(o, "status", 404, "Get missing document");
o.jio.get({"_id": "one"}, o.f);
o.tick(o);
o.jio.post({"_id": "one", "_underscored_meta": "uvalue", "meta": "data"});
o.clock.tick(1000);
o.spy(o, "value", {
"_id": "one",
"_underscored_meta": "uvalue",
"meta": "data"
}, "Get posted document");
o.jio.get({"_id": "one"}, o.f);
o.tick(o);
o.jio.putAttachment({
"_id": "one",
"_attachment": "my_attachment",
"_data": "My Data",
"_mimetype": "text/plain"
});
o.clock.tick(1000);
o.spy(o, "value", {
"_id": "one",
"_underscored_meta": "uvalue",
"meta": "data",
"_attachments": {
"my_attachment": {
"length": 7,
"content_type": "text/plain"
}
}
}, "Get document with attachment informations");
o.jio.get({"_id": "one"}, o.f);
o.tick(o);
util.closeAndcleanUpJio(o.jio);
});
test("GetAttachment", function () {
var o = generateTools();
o.jio = jIO.newJio({
"type": "split",
"storage_list": [{
"type": "local",
"username": "splitstorage",
"application_name": "getAttachment1"
}, {
"type": "local",
"username": "splitstorage",
"application_name": "getAttachment2"
}]
});
o.spy(o, "status", 404, "Get attachment from missing document");
o.jio.getAttachment({"_id": "one", "_attachment": "my_attachment"}, o.f);
o.tick(o);
o.jio.post({"_id": "one", "_underscored_meta": "uvalue", "meta": "data"});
o.clock.tick(1000);
o.spy(o, "status", 404, "Get missing attachment from document");
o.jio.getAttachment({"_id": "one", "_attachment": "my_attachment"}, o.f);
o.tick(o);
o.jio.putAttachment({
"_id": "one",
"_attachment": "my_attachment",
"_data": "My Data",
"_mimetype": "text/plain"
});
o.clock.tick(1000);
o.spy(o, "value", "My Data", "Get attachment");
o.jio.getAttachment({"_id": "one", "_attachment": "my_attachment"}, o.f);
o.tick(o);
util.closeAndcleanUpJio(o.jio);
});
test("removeAttachment", function () {
var o = generateTools();
o.jio = jIO.newJio({
"type": "split",
"storage_list": [{
"type": "local",
"username": "splitstorage",
"application_name": "removeAttachment1"
}, {
"type": "local",
"username": "splitstorage",
"application_name": "removeAttachment2"
}]
});
o.spy(o, "status", 404, "Remove attachment from inexistent document");
o.jio.removeAttachment({"_id": "one", "_attachment": "my_attachment"}, o.f);
o.tick(o);
o.jio.post({"_id": "one", "_underscored_meta": "uvalue", "meta": "data"});
o.clock.tick(1000);
o.spy(o, "status", 404, "Remove inexistent attachment");
o.jio.removeAttachment({"_id": "one", "_attachment": "my_attachment"}, o.f);
o.tick(o);
o.jio.putAttachment({
"_id": "one",
"_attachment": "my_attachment",
"_data": "My Data",
"_mimetype": "text/plain"
});
o.clock.tick(1000);
o.spy(o, "value", {
"ok": true,
"id": "one",
"attachment": "my_attachment"
}, "Remove attachment");
o.jio.removeAttachment({"_id": "one", "_attachment": "my_attachment"}, o.f);
o.tick(o);
o.spy(o, "value", {
"_id": "one",
"_underscored_meta": "uvalue",
"meta": "data"
}, "Get document for check");
o.jio.get({"_id": "one"}, o.f);
o.tick(o);
o.spy(o, "status", 404, "Get attachment for check");
o.jio.getAttachment({"_id": "one", "_attachment": "my_attachment"}, o.f);
o.tick(o);
util.closeAndcleanUpJio(o.jio);
});
test("remove", function () {
var o = generateTools();
o.jio = jIO.newJio({
"type": "split",
"storage_list": [{
"type": "local",
"username": "splitstorage",
"application_name": "remove1"
}, {
"type": "local",
"username": "splitstorage",
"application_name": "remove2"
}]
});
o.spy(o, "status", 404, "Remove missing document");
o.jio.remove({"_id": "one"}, o.f);
o.tick(o);
o.jio.post({"_id": "one", "_underscored_meta": "uvalue", "meta": "data"});
o.clock.tick(1000);
o.jio.putAttachment({
"_id": "one",
"_attachment": "my_attachment",
"_data": "My Data",
"_mimetype": "text/plain"
});
o.clock.tick(1000);
o.spy(o, "value", {"ok": true, "id": "one"}, "Remove document");
o.jio.remove({"_id": "one"}, o.f);
o.tick(o);
o.spy(o, "status", 404, "Get attachment for check");
o.jio.getAttachment({"_id": "one", "_attachment": "my_attachment"}, o.f);
o.tick(o);
o.spy(o, "status", 404, "Get document for check");
o.jio.get({"_id": "one"}, o.f);
o.tick(o);
util.closeAndcleanUpJio(o.jio);
});
test("Put", function () {
var o = generateTools();
o.jio = jIO.newJio({
"type": "split",
"storage_list": [{
"type": "local",
"username": "splitstorage",
"application_name": "put1"
}, {
"type": "local",
"username": "splitstorage",
"application_name": "put2"
}]
});
o.spy(o, "value", {"ok": true, "id": "one"}, "Put document");
o.jio.put({
"_id": "one",
"_underscored_meta": "uvalue",
"meta": "data"
}, o.f);
o.tick(o);
o.spy(o, "value", {
"_id": "one",
"_underscored_meta": "uvalue",
"meta": "data"
}, "Get document for check");
o.jio.get({"_id": "one"}, o.f);
o.tick(o);
o.spy(o, "value", {"ok": true, "id": "one"}, "Put document again");
o.jio.put({
"_id": "one",
"_underscored_meta": "uvalue",
"meow": "dog"
}, o.f);
o.tick(o);
o.spy(o, "value", {
"_id": "one",
"_underscored_meta": "uvalue",
"meow": "dog"
}, "Get document for check");
o.jio.get({"_id": "one"}, o.f);
o.tick(o);
util.closeAndcleanUpJio(o.jio);
});
test("AllDocs", function () {
var o = generateTools();
o.jio = jIO.newJio({
"type": "split",
"storage_list": [{
"type": "local",
"username": "splitstorage",
"application_name": "alldocs1"
}, {
"type": "local",
"username": "splitstorage",
"application_name": "alldocs2"
}]
});
for (o.i = 0; o.i < 5; o.i += 1) {
o.jio.post({
"_id": "doc" + o.i,
"_underscored_meta": "uvalue" + o.i,
"meta": "data" + o.i
});
o.clock.tick(1000);
}
for (o.i = 0; o.i < 2; o.i += 1) {
o.jio.putAttachment({
"_id": "doc" + o.i,
"_attachment": "my_attachment" + o.i,
"_data": "My Data" + o.i,
"_mimetype": "text/plain"
});
o.clock.tick(1000);
}
o.spy(o, "value", {
"_id": "doc1",
"_underscored_meta": "uvalue1",
"meta": "data1",
"_attachments": {
"my_attachment1": {
"length": 8,
"content_type": "text/plain"
}
}
}, "Get document for check");
o.jio.get({"_id": "doc1"}, o.f);
o.tick(o);
o.spy(o, "value", {
"total_rows": 5,
"rows": [{
"id": "doc0",
"key": "doc0",
"value": {}
}, {
"id": "doc1",
"key": "doc1",
"value": {}
}, {
"id": "doc2",
"key": "doc2",
"value": {}
}, {
"id": "doc3",
"key": "doc3",
"value": {}
}, {
"id": "doc4",
"key": "doc4",
"value": {}
}]
}, "AllDocs with document ids only");
o.jio.allDocs(function (err, response) {
if (response && Array.isArray(response.rows)) {
response.rows.sort(function (a, b) {
return a.id < b.id ? -1 : a.id > b.id ? 1 : 0;
});
}
o.f(err, response);
});
o.tick(o);
util.closeAndcleanUpJio(o.jio);
});
}));
/*jslint indent: 2, maxlen: 80, nomen: true */
/*global define, jIO, jio_tests, test, ok, sinon */
// define([module_name], [dependencies], module);
(function (dependencies, module) {
"use strict";
if (typeof define === 'function' && define.amd) {
return define(dependencies, module);
}
module(jIO, jio_tests);
}(['jio', 'jio_tests', 'xwikistorage'], function (jIO, util) {
"use strict";
function generateTools() {
var o = {
clock: sinon.useFakeTimers(),
spy: util.ospy,
tick: util.otick
};
function addFakeServerResponse(type, method, path, status, response) {
o.server.respondWith(method, new RegExp(path), [
status,
{"Content-Type": 'application/xml'},
response
]);
}
o.addFakeServerResponse = addFakeServerResponse;
return o;
}
module('XWikiStorage');
function setUp(that, liveTest) {
var o = generateTools(that);
o.server = sinon.fakeServer.create();
o.jio = jIO.newJio({type: 'xwiki', formTokenPath: 'form_token'});
o.addFakeServerResponse("xwiki", "GET", "form_token", 200,
'<meta name="form_token" content="OMGHAX"/>');
o._addFakeServerResponse = o.addFakeServerResponse;
o.expectedRequests = [];
o.addFakeServerResponse = function (a, b, c, d, e) {
o._addFakeServerResponse(a, b, c, d, e);
o.expectedRequests.push([b, c]);
};
o.assertReqs = function (count, message) {
var i, j, req, expected, ex;
o.requests = (o.requests || 0) + count;
ok(o.server.requests.length === o.requests,
message + "[expected [" + count + "] got [" +
(o.server.requests.length - (o.requests - count)) + "]]");
for (i = 1; i <= count; i += 1) {
req = o.server.requests[o.server.requests.length - i];
if (!req) {
break;
}
for (j = o.expectedRequests.length - 1; j >= 0; j -= 1) {
expected = o.expectedRequests[j];
if (req.method === expected[0] &&
req.url.indexOf(expected[1]) !== 0) {
o.expectedRequests.splice(j, 1);
}
}
}
ex = o.expectedRequests.pop();
if (ex) {
ok(0, "expected [" + ex[0] + "] request for [" + ex[1] + "]");
}
};
return o;
}
test("Post", function () {
var o = setUp(this);
// post without id
o.spy(o, "status", 405, "Post without id");
o.jio.post({}, o.f);
o.clock.tick(5000);
o.assertReqs(0, "no id -> no request");
// post non empty document
o.addFakeServerResponse("xwiki", "POST", "myFile", 201, "HTML RESPONSE");
o.spy(o, "value", {"id": "myFile", "ok": true},
"Create = POST non empty document");
o.jio.post({"_id": "myFile", "title": "hello there"}, o.f);
o.clock.tick(5000);
o.server.respond();
o.assertReqs(
3,
"put -> 1 request to get csrf token, 1 to get doc and 1 to post data"
);
// post but document already exists (post = error!, put = ok)
o.answer = '<?xml version="1.0" encoding="UTF-8" standalone="yes"?>' +
'<page xmlns="http://www.xwiki.org"><title>hello there</title></page>';
o.addFakeServerResponse("xwiki", "GET", "myFile2", 200, o.answer);
o.spy(o, "status", 409, "Post but document already exists");
o.jio.post({"_id": "myFile2", "title": "hello again"}, o.f);
o.clock.tick(5000);
o.server.respond();
o.assertReqs(1, "post w/ existing doc -> 1 request to get doc then fail");
util.closeAndcleanUpJio(o.jio);
});
test("Put", function () {
var o = setUp(this);
// put without id => id required
o.spy(o, "status", 20, "Put without id");
o.jio.put({}, o.f);
o.clock.tick(5000);
o.assertReqs(0, "put w/o id -> 0 requests");
// put non empty document
o.addFakeServerResponse("xwiki", "POST", "put1", 201, "HTML RESPONSE");
o.spy(o, "value", {"ok": true, "id": "put1"},
"Create = PUT non empty document");
o.jio.put({"_id": "put1", "title": "myPut1"}, o.f);
o.clock.tick(5000);
o.server.respond();
o.assertReqs(
3,
"put normal doc -> 1 req to get doc, 1 for csrf token, 1 to post"
);
// put but document already exists = update
o.answer = '<?xml version="1.0" encoding="UTF-8" standalone="yes"?>' +
'<page xmlns="http://www.xwiki.org"><title>mtPut1</title></page>';
o.addFakeServerResponse("xwiki", "GET", "put2", 200, o.answer);
o.addFakeServerResponse("xwiki", "POST", "put2", 201, "HTML RESPONSE");
o.spy(o, "value", {"ok": true, "id": "put2"}, "Updated the document");
o.jio.put({"_id": "put2", "title": "myPut2abcdedg"}, o.f);
o.clock.tick(5000);
o.server.respond();
o.assertReqs(
3,
"put update doc -> 1 req to get doc, 1 for csrf token, 1 to post"
);
util.closeAndcleanUpJio(o.jio);
});
test("PutAttachment", function () {
var o = setUp(this);
// putAttachment without doc id => id required
o.spy(o, "status", 20, "PutAttachment without doc id");
o.jio.putAttachment({}, o.f);
o.clock.tick(5000);
o.assertReqs(0, "put attach w/o doc id -> 0 requests");
// putAttachment without attachment id => attachment id required
o.spy(o, "status", 22, "PutAttachment without attachment id");
o.jio.putAttachment({"_id": "putattmt1"}, o.f);
o.clock.tick(5000);
o.assertReqs(0, "put attach w/o attach id -> 0 requests");
// putAttachment without underlying document => not found
o.addFakeServerResponse("xwiki", "GET", "putattmtx", 404, "HTML RESPONSE");
o.spy(o, "status", 404, "PutAttachment without document");
o.jio.putAttachment({"_id": "putattmtx", "_attachment": "putattmt2"}, o.f);
o.clock.tick(5000);
o.server.respond();
o.assertReqs(1, "put attach w/o existing document -> 1 request to get doc");
// putAttachment with document without data
o.answer = '<?xml version="1.0" encoding="UTF-8" standalone="yes"?>' +
'<page xmlns="http://www.xwiki.org"><title>myPutAttm</title></page>';
o.addFakeServerResponse("xwiki", "GET", "putattmt1", 200, o.answer);
o.addFakeServerResponse(
"xwiki",
"POST",
"putattmt1/putattmt2",
201,
"HTML RESPONSE"
);
o.spy(o, "value", {"ok": true, "id": "putattmt1/putattmt2"},
"PutAttachment with document, without data");
o.jio.putAttachment({"_id": "putattmt1", "_attachment": "putattmt2"}, o.f);
o.clock.tick(5000);
o.server.respond();
o.assertReqs(3, "put attach -> 1 request to get document, 1 to put " +
"attach, 1 to get csrf token");
util.closeAndcleanUpJio(o.jio);
});
test("Get", function () {
var o = setUp(this);
// get inexistent document
o.spy(o, "status", 404, "Get non existing document");
o.jio.get("get1", o.f);
o.clock.tick(5000);
o.server.respond();
o.assertReqs(1, "try to get nonexistent doc -> 1 request");
// get inexistent attachment
o.spy(o, "status", 404, "Get non existing attachment");
o.jio.get("get1/get2", o.f);
o.clock.tick(5000);
o.server.respond();
o.assertReqs(1, "try to get nonexistent attach -> 1 request");
// get document
o.answer = '<?xml version="1.0" encoding="UTF-8" standalone="yes"?>' +
'<page xmlns="http://www.xwiki.org"><title>some title</title></page>';
o.addFakeServerResponse("xwiki", "GET", "get3", 200, o.answer);
o.spy(o, "value", {"_id": "get3", "title": "some title"}, "Get document");
o.jio.get("get3", o.f);
o.clock.tick(5000);
o.server.respond();
o.assertReqs(1, "get document -> 1 request");
// get inexistent attachment (document exists)
o.spy(o, "status", 404, "Get non existing attachment (doc exists)");
o.jio.get({"_id": "get3", "_attachment": "getx"}, o.f);
o.clock.tick(5000);
o.server.respond();
o.assertReqs(1, "get nonexistant attachment -> 1 request");
// get attachment
o.answer = JSON.stringify({"_id": "get4", "title": "some attachment"});
o.addFakeServerResponse("xwiki", "GET", "get3/get4", 200, o.answer);
o.spy(o, "value", {"_id": "get4", "title": "some attachment"},
"Get attachment");
o.jio.get({"_id": "get3", "_attachment": "get4"}, o.f);
o.clock.tick(5000);
o.server.respond();
o.assertReqs(1, "get attachment -> 1 request");
util.closeAndcleanUpJio(o.jio);
});
test("Remove", function () {
var o = setUp(this);
// remove inexistent document
o.addFakeServerResponse("xwiki", "GET", "remove1", 404, "HTML RESPONSE");
o.spy(o, "status", 404, "Remove non existening document");
o.jio.remove({"_id": "remove1"}, o.f);
o.clock.tick(5000);
o.server.respond();
o.assertReqs(
2,
"remove nonexistent doc -> 1 request for csrf and 1 for doc"
);
// remove inexistent document/attachment
o.addFakeServerResponse("xwiki", "GET", "remove1/remove2", 404, "HTML" +
"RESPONSE");
o.spy(o, "status", 404, "Remove inexistent document/attachment");
o.jio.removeAttachment({"_id": "remove1", "_attachment": "remove2"}, o.f);
o.clock.tick(5000);
o.server.respond();
o.assertReqs(
2,
"remove nonexistant attach -> 1 request for csrf and 1 for doc"
);
// remove document
//o.answer = '<?xml version="1.0" encoding="UTF-8" standalone="yes"?>' +
// '<page xmlns="http://www.xwiki.org"><title>some doc</title></page>';
//o.addFakeServerResponse("xwiki", "GET", "remove3", 200, o.answer);
o.addFakeServerResponse("xwiki", "POST", "bin/delete/Main/remove3",
200, "HTML RESPONSE");
o.spy(o, "value", {"ok": true, "id": "remove3"}, "Remove document");
o.jio.remove({"_id": "remove3"}, o.f);
o.clock.tick(5000);
o.server.respond();
o.assertReqs(
2,
"remove document -> 1 request for csrf and 1 for deleting doc"
);
o.answer = JSON.stringify({
"_id": "remove4",
"title": "some doc",
"_attachments": {
"remove5": {
"length": 4,
"digest": "md5-d41d8cd98f00b204e9800998ecf8427e"
}
}
});
// remove attachment
o.addFakeServerResponse(
"xwiki",
"POST",
"delattachment/Main/remove4/remove5",
200,
"HTML RESPONSE"
);
o.spy(o, "value", {"ok": true, "id": "remove4/remove5"},
"Remove attachment");
o.jio.removeAttachment({"_id": "remove4", "_attachment": "remove5"}, o.f);
o.clock.tick(5000);
o.server.respond();
o.assertReqs(2, "remove attach -> 1 request for csrf and 1 for deletion");
util.closeAndcleanUpJio(o.jio);
});
}));
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