Commit 3d97883d authored by Alain Takoudjou's avatar Alain Takoudjou

replicated opml now check signature and use new parser storage

parent 134f4eda
......@@ -182,11 +182,7 @@ module.exports = function (grunt) {
'src/jio.storage/localstorage.js',
'src/jio.storage/indexeddbstorage.js',
'src/jio.storage/cryptstorage.js',
'src/jio.storage/websqlstorage.js',
'src/jio.storage/rssfeedstorage.js',
'src/jio.storage/opmlstorage.js',
'src/jio.storage/replicatedopmltreestorage.js',
'src/jio.storage/webhttpstorage.js'
'src/jio.storage/websqlstorage.js'
],
dest: 'dist/<%= pkg.name %>-<%= pkg.version %>.js'
// dest: 'jio.js'
......
......@@ -7,6 +7,8 @@
<script src="../node_modules/rsvp/dist/rsvp-2.0.4.js"></script>
<script src="../dist/jio-latest.js"></script>
<script src="../src/jio.storage/replicatedopmltreestorage.js"></script>
<script src="../src/jio.storage/webhttpstorage.js"></script>
<link rel="stylesheet" href="../node_modules/grunt-contrib-qunit/test/libs/qunit.css" type="text/css" media="screen"/>
<script src="../node_modules/grunt-contrib-qunit/test/libs/qunit.js" type="text/javascript"></script>
......
......@@ -12,6 +12,10 @@
module = QUnit.module,
rusha = new Rusha(),
i,
opml_mock_options,
rss_mock_options,
opml_mock_options2 = {},
rss_mock_options2 = {},
name_list = ['get', 'put', 'remove', 'buildQuery',
'putAttachment', 'getAttachment', 'allAttachments'];
......@@ -24,66 +28,41 @@
}
}
function RSSMockStorage(spec) {
this._rss_storage = jIO.createJIO({
type: "rss",
url: "http://example.com/rss.xml"
function ParserMockStorage(spec) {
this._sub_storage = jIO.createJIO({
type: "parser",
document_id: spec.document_id,
attachment_id: spec.attachment_id,
parser: spec.parser,
sub_storage: spec.sub_storage
});
this._options = spec.options;
resetCount(spec.options.count);
}
RSSMockStorage.prototype.hasCapacity = function (name) {
return this._rss_storage.hasCapacity(name);
};
function WEBMockStorage(spec) {
this._web_storage = jIO.createJIO({
type: "webhttp",
url: "http://example.com/"
});
this._options = spec.options;
resetCount(spec.options.count);
}
WEBMockStorage.prototype.hasCapacity = function (name) {
return this._web_storage.hasCapacity(name);
};
function OPMLMockStorage(spec) {
this._opml_storage = jIO.createJIO({
type: "opml",
url: "http://example.com/opml.xml"
});
this._options = spec.options;
resetCount(spec.options.count);
if (spec.parser === "opml") {
if (spec.document_id === "http://example2.com/opml.xml") {
this._options = opml_mock_options2;
} else {
this._options = opml_mock_options;
}
} else if (spec.parser === "rss") {
if (spec.document_id === "http://example2.com/rss.xml") {
this._options = rss_mock_options2;
} else {
this._options = rss_mock_options;
}
}
resetCount(this._options.count);
}
OPMLMockStorage.prototype.hasCapacity = function (name) {
return this._opml_storage.hasCapacity(name);
ParserMockStorage.prototype.hasCapacity = function (name) {
return this._sub_storage.hasCapacity(name);
};
function mockFunction(name) {
WEBMockStorage.prototype[name] = function () {
ParserMockStorage.prototype[name] = function () {
this._options.count[name] += 1;
if (this._options.mock.hasOwnProperty(name)) {
return this._options.mock[name].apply(this, arguments);
}
return this._web_storage[name].apply(this._web_storage, arguments);
};
RSSMockStorage.prototype[name] = function () {
this._options.count[name] += 1;
if (this._options.mock.hasOwnProperty(name)) {
return this._options.mock[name].apply(this, arguments);
}
return this._rss_storage[name].apply(this._rss_storage, arguments);
};
OPMLMockStorage.prototype[name] = function () {
this._options.count[name] += 1;
if (this._options.mock.hasOwnProperty(name)) {
return this._options.mock[name].apply(this, arguments);
}
return this._opml_storage[name].apply(this._opml_storage, arguments);
return this._sub_storage[name].apply(this._sub_storage, arguments);
};
}
......@@ -91,9 +70,7 @@
mockFunction(name_list[i]);
}
jIO.addStorage('opmlmock', OPMLMockStorage);
jIO.addStorage('rssmock', RSSMockStorage);
jIO.addStorage('webmock', WEBMockStorage);
jIO.addStorage('parsermock', ParserMockStorage);
///////////////////////////////////////////////////////
// Helpers
......@@ -110,9 +87,7 @@
for (i = 0; i < result.data.rows.length; i += 1) {
promise_list.push(RSVP.all([
result.data.rows[i].id,
storage.get(result.data.rows[i].id),
storage.getAttachment(result.data.rows[i].id,
result.data.rows[i].doc.name)
storage.get(result.data.rows[i].id)
]));
}
return RSVP.all(promise_list);
......@@ -146,82 +121,9 @@
this.server.autoRespond = true;
this.server.autoRespondAfter = 5;
this.rss_mock_options = {
mock: {
remove: function () {
throw new Error('remove not supported');
},
removeAttachment: function () {
throw new Error('removeAttachment not supported');
},
allAttachments: function () {
return {data: null};
},
putAttachment: function () {
throw new Error('putAttachment not supported');
}
},
count: {}
};
this.opml_mock_options = {
mock: {
remove: function () {
throw new Error('remove not supported');
},
removeAttachment: function () {
throw new Error('removeAttachment not supported');
},
allAttachments: function () {
return {data: null};
},
putAttachment: function () {
throw new Error('putAttachment not supported');
}
},
count: {}
};
this.web_mock_options = {
mock: {
remove: function () {
throw new Error('remove not supported');
},
removeAttachment: function () {
throw new Error('removeAttachment not supported');
},
allAttachments: function () {
return {data: null};
},
putAttachment: function () {
throw new Error('putAttachment not supported');
}
},
count: {}
};
this.sub_opml_storage = {
type: "opmlmock",
options: this.opml_mock_options,
url: "http://example.com/opml.xml",
sub_storage_list: [
{
type: "rssmock",
url: "http://example.com/rss.xml",
has_include_docs: true,
options: this.rss_mock_options
},
{
type: "webmock",
url: "http://example.com/",
has_include_docs: true,
options: this.web_mock_options
}
],
basic_login: "YWRtaW46endfEzrJUZGw="
};
this.jio = jIO.createJIO({
type: "replicatedopml",
opml_storage_list: [
this.sub_opml_storage
],
remote_parser_storage_type: "parsermock",
local_sub_storage: {
type: "query",
sub_storage: {
......@@ -243,9 +145,28 @@
'</head>' +
'<body>' +
'<outline text="OPML Item List">' +
'<outline text="instance foo" type="link" url="http://example.com/' +
'<outline text="instance foo" xmlUrl="http://example.com/' +
'rss.xml" dateCreated="Thu, 12 Sep 2003 23:35:52 GMT" ' +
'htmlUrl="http://example.com/" title="opml item foo" type="link"/>' +
'</outline>' +
'</body>' +
'</opml>'
]);
this.server.respondWith("GET", "http://example2.com/opml.xml", [200,
{ "Content-Type": "text/xml" },
'<?xml version="1.0" encoding="ISO-8859-1"?>' +
'<opml version="1.0">' +
'<head>' +
'<title>opml foo</title>' +
'<dateCreated>Thu, 12 Sep 2003 23:35:52 GMT</dateCreated>' +
'<dateModified>Fri, 12 Sep 2003 23:45:37 GMT</dateModified>' +
'</head>' +
'<body>' +
'<outline text="OPML Item List">' +
'<outline text="instance foo" xmlUrl="http://example2.com/' +
'rss.xml" dateCreated="Thu, 12 Sep 2003 23:35:52 GMT" ' +
'htmlUrl="http://example.com/" title="opml item foo" />' +
'htmlUrl="http://example2.com/" title="opml item foo" type="link"/>' +
'</outline>' +
'</body>' +
'</opml>'
......@@ -273,21 +194,64 @@
'</rss>'
]);
this.server.respondWith("GET", "http://example.com/_document_list", [200,
{ "Content-Type": "text/plain" },
'monitor.status'
this.server.respondWith("GET", "http://example2.com/rss.xml", [200,
{ "Content-Type": "text/xml" },
'<?xml version="1.0" encoding="UTF-8" ?>' +
'<rss version="2.0">' +
'<channel>' +
'<title>instance foo</title>' +
'<description>This is an example of an RSS feed</description>' +
'<link>http://www.domain.com/link.htm</link>' +
'<lastBuildDate>Mon, 28 Aug 2006 11:12:55 -0400 </lastBuildDate>' +
'<pubDate>Tue, 29 Aug 2006 09:00:00 -0400</pubDate>' +
'<item>' +
'<title>Item Example</title>' +
'<category>ERROR</category>' +
'<description>This is an example of an Item</description>' +
'<link>http://www.domain.com/link.htm</link>' +
'<guid isPermaLink="false">11026875</guid>' +
'<pubDate>Tue, 29 Aug 2006 09:00:00 -0400</pubDate>' +
'</item>' +
'</channel>' +
'</rss>'
]);
this.server.respondWith(
"GET",
"http://example.com/monitor.status.json",
[200,
{ "Content-Type": "application/json" },
'{"title": "document fooo", "status": "ERROR",' +
'"date": "Tue, 29 Aug 2006 09:00:00 -0400",' +
'"type": "global", "foo_p": "fooo parameter",' +
'"bar_p": "bar parameter", "total_error": 12345}']
);
opml_mock_options = {
mock: {
remove: function () {
throw new Error('remove not supported');
},
removeAttachment: function () {
throw new Error('removeAttachment not supported');
},
allAttachments: function () {
return {data: null};
},
putAttachment: function () {
throw new Error('putAttachment not supported');
}
},
count: {}
};
rss_mock_options = {
mock: {
remove: function () {
throw new Error('remove not supported');
},
removeAttachment: function () {
throw new Error('removeAttachment not supported');
},
allAttachments: function () {
return {data: null};
},
putAttachment: function () {
throw new Error('putAttachment not supported');
}
},
count: {}
};
console.log(new Blob([JSON.stringify({toto: ""})]));
},
teardown: function () {
this.server.restore();
......@@ -303,24 +267,19 @@
stop();
var test = this;
test.opml_mock_options.mock.buildQuery = function () {
return [];
};
this.jio.repair()
.then(function () {
return RSVP.all([
isEmptyStorage(test.jio),
deepEqual(test.jio.__storage._remote_storage_dict,
{},
'SubStorage empty'),
equalsubStorageCallCount(
test.opml_mock_options.count,
{buildQuery: 1}
),
equalsubStorageCallCount(
test.rss_mock_options.count,
opml_mock_options.count,
{}
),
equalsubStorageCallCount(
test.web_mock_options.count,
rss_mock_options.count,
{}
)
]);
......@@ -333,113 +292,90 @@
});
});
///////////////////////////////////////////////////////
// complete sync - one opml, 2 sub storages
// complete sync - one opml, one sub storages
///////////////////////////////////////////////////////
test("complete storage sync", function () {
expect(4);
expect(3);
stop();
var test = this,
doc_id = "http://example.com/rss.xml",
doc = {
opml_doc = {
title: "opml item foo",
htmlurl: "http://example.com/",
url: "http://example.com/rss.xml",
url: "http://example.com/opml.xml",
portal_type: "opml",
basic_login: "cred foo",
active: true
},
opml_id = generateHash(opml_doc.url),
opml_outline_id = "/1/0/0",
opml_outline = {
opml_title: "opml foo",
dateCreated: "Thu, 12 Sep 2003 23:35:52 GMT",
dateModified: "Fri, 12 Sep 2003 23:45:37 GMT",
text: "instance foo",
type: "link",
opml_title: "opml foo",
created_date: "Thu, 12 Sep 2003 23:35:52 GMT",
modified_date: "Fri, 12 Sep 2003 23:45:37 GMT"
},
parent_id = generateHash(test.sub_opml_storage.url),
opml_item_id = generateHash(parent_id + doc_id),
opml_item = {
name: doc_id,
opml_title: doc.opml_title,
parent_id: parent_id,
reference: generateHash(parent_id + doc_id),
creation_date: doc.created_date,
title: doc.title,
type: "opml-item",
url: test.sub_opml_storage.url,
signature: generateHash(JSON.stringify(doc))
htmlUrl: "http://example.com/",
xmlUrl: "http://example.com/rss.xml",
title: "opml item foo",
portal_type: "opml-outline",
parent_id: opml_id,
parent_url: opml_doc.url,
reference: generateHash(opml_id + opml_outline_id),
active: true
},
full_opml = new Blob([JSON.stringify(doc)]),
rss_id = "1102345",
rss_doc = {
"link": "http://www.domain.com/link.htm",
"date": "Tue, 29 Aug 2006 09:00:00 -0400",
"title": "Item Example",
"category": "ERROR",
"description": "This is an example of an Item",
"guid": "1102345",
"siteTitle": "instance foo",
"reference": "This is an example of an RSS feed",
"siteLink": "http://www.domain.com/link.htm",
"lastBuildDate": "Mon, 28 Aug 2006 11:12:55 -0400 "
promise_id = generateHash(opml_outline.reference + opml_outline.xmlUrl +
"/0/0"),
promise_item = {
link: "http://www.domain.com/link.htm",
title: "Item Example",
category: "ERROR",
description: "This is an example of an Item",
guid: "1102345",
guid_isPermaLink: "false",
pubDate: "Tue, 29 Aug 2006 09:00:00 -0400",
lastBuildDate: "Mon, 28 Aug 2006 11:12:55 -0400 ",
channel: "This is an example of an RSS feed",
channel_item: "instance foo",
parent_id: opml_outline.reference,
reference: promise_id,
status: "ERROR",
portal_type: "promise",
active: true
},
// Sub OPML document (rss)
rss_feed_url = "http://example.com/rss.xml",
rss_item_id = generateHash(opml_item.reference + rss_feed_url + rss_id),
rss_item_id = generateHash(opml_outline.reference + opml_outline.xmlUrl +
"/0"),
rss_item = {
name: rss_id,
opml_title: opml_item.opml_title,
parent_title: opml_item.title,
parent_id: opml_item.reference,
title: "instance foo",
description: "This is an example of an RSS feed",
link: "http://www.domain.com/link.htm",
lastBuildDate: "Mon, 28 Aug 2006 11:12:55 -0400 ",
pubDate: "Tue, 29 Aug 2006 09:00:00 -0400",
parent_id: opml_outline.reference,
reference: rss_item_id,
title: rss_doc.title,
type: rss_doc.type || "rssmock-item",
url: rss_feed_url,
status: rss_doc.category,
creation_date: rss_doc.date,
signature: generateHash(JSON.stringify(rss_doc))
},
full_rss = new Blob([JSON.stringify(rss_doc)]),
json_id = "monitor.status",
json_doc = {
title: "document fooo",
status: "ERROR",
date: "Tue, 29 Aug 2006 09:00:00 -0400",
type: "global",
foo_p: "fooo parameter",
bar_p: "bar parameter",
total_error: 12345
},
// Sub OPML document (webhttp)
http_url = "http://example.com/",
json_item_id = generateHash(opml_item.reference + http_url + json_id),
json_item = {
name: json_id,
opml_title: opml_item.opml_title,
parent_title: opml_item.title,
parent_id: opml_item.reference,
reference: json_item_id,
title: json_doc.title,
type: json_doc.type,
url: http_url,
status: json_doc.status,
creation_date: json_doc.date,
signature: generateHash(JSON.stringify(json_doc))
},
full_json = new Blob([JSON.stringify(json_doc)]);
portal_type: "rss",
active: true
};
test.jio.repair()
test.jio.put(opml_doc.url, opml_doc)
.then(function () {
return test.jio.repair();
})
.then(function () {
return RSVP.all([
equalStorage(test.jio, [[opml_item_id, opml_item, full_opml],
[rss_item_id, rss_item, full_rss],
[json_item_id, json_item, full_json]]),
equalStorage(test.jio, [
[opml_doc.url, opml_doc],
[opml_outline.reference, opml_outline],
[rss_item_id, rss_item],
[promise_id, promise_item]
]),
equalsubStorageCallCount(
test.opml_mock_options.count,
opml_mock_options.count,
{buildQuery: 1}
),
equalsubStorageCallCount(
test.rss_mock_options.count,
{buildQuery: 1}
),
equalsubStorageCallCount(
test.web_mock_options.count,
rss_mock_options.count,
{buildQuery: 1}
)
]);
......@@ -453,130 +389,125 @@
});
///////////////////////////////////////////////////////
// document update
// remote document update
///////////////////////////////////////////////////////
test("remote document modified", function () {
expect(4);
expect(3);
stop();
var test = this,
doc_id = "http://example.com/rss.xml",
doc = {
opml_doc = {
title: "opml item foo",
htmlurl: "http://example.com/",
url: "http://example.com/rss.xml",
url: "http://example.com/opml.xml",
portal_type: "opml",
basic_login: "cred foo",
active: true
},
opml_id = generateHash(opml_doc.url),
opml_outline_id = "/1/0/0",
opml_outline = {
opml_title: "opml foo",
dateCreated: "Thu, 12 Sep 2003 23:35:52 GMT",
dateModified: "Fri, 12 Sep 2003 23:45:37 GMT",
text: "instance foo",
type: "link",
opml_title: "opml foo",
created_date: "Thu, 12 Sep 2003 23:35:52 GMT",
modified_date: "Fri, 12 Sep 2003 23:45:37 GMT"
},
parent_id = generateHash(test.sub_opml_storage.url),
opml_item_id = generateHash(parent_id + doc_id),
opml_item = {
name: doc_id,
opml_title: doc.opml_title,
parent_id: parent_id,
reference: generateHash(parent_id + doc_id),
creation_date: doc.created_date,
title: doc.title,
type: "opml-item",
url: test.sub_opml_storage.url,
signature: generateHash(JSON.stringify(doc))
},
full_opml = new Blob([JSON.stringify(doc)]),
rss_id = "1102345",
rss_doc = {
"link": "http://www.domain.com/link.htm",
"date": "Tue, 29 Aug 2006 09:00:00 -0400",
"title": "Item Example",
"category": "ERROR",
"description": "This is an example of an Item",
"guid": "1102345",
"siteTitle": "instance foo",
"reference": "This is an example of an RSS feed",
"siteLink": "http://www.domain.com/link.htm",
"lastBuildDate": "Mon, 28 Aug 2006 11:12:55 -0400 "
},
// Sub OPML document (rss)
rss_feed_url = test.sub_opml_storage.sub_storage_list[0].url,
rss_item_id = generateHash(opml_item.reference + rss_feed_url + rss_id),
rss_item2 = {
name: rss_id,
opml_title: opml_item.opml_title,
parent_title: opml_item.title,
parent_id: opml_item.reference,
reference: rss_item_id,
title: rss_doc.title,
type: rss_doc.type || "rssmock-item",
url: rss_feed_url,
status: rss_doc.category,
creation_date: rss_doc.date
htmlUrl: "http://example.com/",
xmlUrl: "http://example.com/rss.xml",
title: "opml item foo",
portal_type: "opml-outline",
parent_id: opml_id,
parent_url: opml_doc.url,
reference: generateHash(opml_id + opml_outline_id),
active: true
},
rss_doc2 = JSON.parse(JSON.stringify(rss_doc)),
full_rss2,
json_id = "monitor.status",
json_doc = {
title: "document fooo",
promise_id = generateHash(opml_outline.reference + opml_outline.xmlUrl +
"/0/0"),
promise_item = {
link: "http://www.domain.com/link.htm",
title: "Item Example",
category: "ERROR",
description: "This is an example of an Item",
guid: "1102345",
guid_isPermaLink: "false",
pubDate: "Tue, 29 Aug 2006 09:00:00 -0400",
lastBuildDate: "Mon, 28 Aug 2006 11:12:55 -0400 ",
channel: "This is an example of an RSS feed",
channel_item: "instance foo",
parent_id: opml_outline.reference,
reference: promise_id,
status: "ERROR",
date: "Tue, 29 Aug 2006 09:00:00 -0400",
type: "global",
foo_p: "fooo parameter",
bar_p: "bar parameter",
total_error: 12345
portal_type: "promise",
active: true
},
// Sub OPML document (webhttp)
http_url = "http://example.com/",
json_item_id = generateHash(opml_item.reference + http_url + json_id),
json_item = {
name: json_id,
opml_title: opml_item.opml_title,
parent_title: opml_item.title,
parent_id: opml_item.reference,
reference: json_item_id,
title: json_doc.title,
type: json_doc.type,
url: http_url,
status: json_doc.status,
creation_date: json_doc.date,
signature: generateHash(JSON.stringify(json_doc))
rss_item_id = generateHash(opml_outline.reference + opml_outline.xmlUrl +
"/0"),
rss_item = {
title: "instance foo",
description: "This is an example of an RSS feed",
link: "http://www.domain.com/link.htm",
lastBuildDate: "Mon, 28 Aug 2006 11:12:55 -0400 ",
pubDate: "Tue, 29 Aug 2006 09:00:00 -0400",
parent_id: opml_outline.reference,
reference: rss_item_id,
portal_type: "rss",
active: true
},
full_json = new Blob([JSON.stringify(json_doc)]);
updated_promise = JSON.parse(JSON.stringify(promise_item));
/* Update rss document */
rss_doc2.date = "new rss date";
// new signature
rss_item2.signature = generateHash(JSON.stringify(rss_doc2));
// modified date
rss_item2.creation_date = rss_doc2.date;
// get the full rss item
full_rss2 = new Blob([JSON.stringify(rss_doc2)]);
test.jio.repair()
test.jio.put(opml_doc.url, opml_doc)
.then(function () {
test.rss_mock_options.mock.buildQuery = function () {
return [{id: rss_id, doc: rss_doc2, value: {}}];
return test.jio.repair();
})
.then(function () {
rss_mock_options.mock.buildQuery = function () {
return [
{
"id": "/0",
"value": {},
"doc": {
"title": "instance foo",
"description": "This is an example of an RSS feed",
"link": "http://www.domain.com/link.htm",
"lastBuildDate": "Mon, 28 Aug 2006 11:12:55 -0400 ",
"pubDate": "Tue, 29 Aug 2006 09:00:00 -0400"
}
},
{
"id": "/0/0",
"value": {},
"doc": {
"link": "http://www.domain.com/link.htm",
"pubDate": "Tue, 29 Aug 2006 10:00:00 -0400", //Changed