Commit 9cc2f37f authored by Tristan Cavelier's avatar Tristan Cavelier

indexstorage updated to JIO v2

parent 3a82fb20
...@@ -17,7 +17,7 @@ ...@@ -17,7 +17,7 @@
*/ */
/*jslint indent: 2, maxlen: 80, sloppy: true, nomen: true, regexp: true */ /*jslint indent: 2, maxlen: 80, sloppy: true, nomen: true, regexp: true */
/*global jIO, define, complex_queries */ /*global window, exports, require, define, jIO, RSVP, complex_queries */
/** /**
* JIO Index Storage. * JIO Index Storage.
...@@ -118,131 +118,23 @@ ...@@ -118,131 +118,23 @@
if (typeof define === 'function' && define.amd) { if (typeof define === 'function' && define.amd) {
return define(dependencies, module); return define(dependencies, module);
} }
module(jIO, complex_queries); if (typeof exports === 'object') {
}(['jio', 'complex_queries'], function (jIO, complex_queries) { return module(
"use strict"; exports,
require('jio'),
var error_dict = { require('rsvp'),
"Corrupted Index": { require('complex_queries')
"status": 24, );
"statusText": "Corrupt",
"error": "corrupt",
"reason": "corrupted index database"
},
"Corrupted Metadata": {
"status": 24,
"statusText": "Corrupt",
"error": "corrupt",
"reason": "corrupted document"
},
"Not Found": {
"status": 404,
"statusText": "Not Found",
"error": "not_found",
"reason": "missing document"
},
"Conflict": {
"status": 409,
"statusText": "Conflicts",
"error": "conflicts",
"reason": "already exist"
},
"Different Index": {
"status": 40,
"statusText": "Check failed",
"error": "check_failed",
"reason": "incomplete database"
}
};
/**
* Generate a JIO Error Object
*
* @method generateErrorObject
* @param {String} name The error name
* @param {String} message The error message
* @param {String} [reason] The error reason
* @return {Object} A jIO error object
*/
function generateErrorObject(name, message, reason) {
if (!error_dict[name]) {
return {
"status": 0,
"statusText": "Unknown",
"error": "unknown",
"message": message,
"reason": reason || "unknown"
};
}
return {
"status": error_dict[name].status,
"statusText": error_dict[name].statusText,
"error": error_dict[name].error,
"message": message,
"reason": reason || error_dict[name].reason
};
}
/**
* Get the real type of an object
* @method type
* @param {Any} value The value to check
* @return {String} The value type
*/
function type(value) {
// returns "String", "Object", "Array", "RegExp", ...
return (/^\[object ([a-zA-Z]+)\]$/).exec(
Object.prototype.toString.call(value)
)[1];
}
/**
* Generate a new uuid
* @method generateUuid
* @return {string} The new uuid
*/
function generateUuid() {
var S4 = function () {
var i, string = Math.floor(
Math.random() * 0x10000 /* 65536 */
).toString(16);
for (i = string.length; i < 4; i += 1) {
string = "0" + string;
}
return string;
};
return S4() + S4() + "-" +
S4() + "-" +
S4() + "-" +
S4() + "-" +
S4() + S4() + S4();
}
/**
* Tool to get the date in W3C date format "2011-12-13T14:15:16+01:00"
*
* @param {Any} date The new Date() parameter
* @return {String} The date in W3C date format
*/
function w3cDate(date) {
var d = new Date(date), offset = -d.getTimezoneOffset();
return (
d.getFullYear() + "-" +
(d.getMonth() + 1) + "-" +
d.getDate() + "T" +
d.getHours() + ":" +
d.getMinutes() + ":" +
d.getSeconds() +
(offset < 0 ? "-" : "+") +
(offset / 60) + ":" +
(offset % 60)
).replace(/[0-9]+/g, function (found) {
if (found.length < 2) {
return '0' + found;
}
return found;
});
} }
window.index_storage = {};
module(window.index_storage, jIO, RSVP, complex_queries);
}([
'exports',
'jio',
'rsvp',
'complex_queries'
], function (exports, jIO, RSVP, complex_queries) {
"use strict";
/** /**
* A JSON Index manipulator * A JSON Index manipulator
...@@ -314,7 +206,7 @@ ...@@ -314,7 +206,7 @@
*/ */
that.put = function (meta) { that.put = function (meta) {
var k, needed_meta = {}, ok = false; var k, needed_meta = {}, ok = false;
if (typeof meta._id !== "string" && meta._id !== "") { if (typeof meta._id !== "string" || meta._id === "") {
throw new TypeError("Corrupted Metadata"); throw new TypeError("Corrupted Metadata");
} }
for (k in meta) { for (k in meta) {
...@@ -359,7 +251,8 @@ ...@@ -359,7 +251,8 @@
throw new TypeError("Corrupted Metadata"); throw new TypeError("Corrupted Metadata");
} }
if (typeof that._location[meta._id] !== "number") { if (typeof that._location[meta._id] !== "number") {
throw new ReferenceError("Not Found"); // throw new ReferenceError("Not Found");
return;
} }
that._database[that._location[meta._id]] = null; that._database[that._location[meta._id]] = null;
that._free.push(that._location[meta._id]); that._free.push(that._location[meta._id]);
...@@ -388,7 +281,8 @@ ...@@ -388,7 +281,8 @@
for (id in that._location) { for (id in that._location) {
if (that._location.hasOwnProperty(id)) { if (that._location.hasOwnProperty(id)) {
database_meta = that._database[that._location[id]]; database_meta = that._database[that._location[id]];
if (type(database_meta) !== "Object" || if (typeof database_meta !== 'object' ||
Object.getPrototypeOf(database_meta || []) !== Object.prototype ||
database_meta._id !== id) { database_meta._id !== id) {
throw new TypeError("Corrupted Index"); throw new TypeError("Corrupted Index");
} }
...@@ -421,8 +315,11 @@ ...@@ -421,8 +315,11 @@
that.checkDocument = function (doc) { that.checkDocument = function (doc) {
var i, key, db_doc; var i, key, db_doc;
if (typeof that._location[doc._id] !== "number" || if (typeof that._location[doc._id] !== "number") {
(db_doc = that._database(that._location[doc._id])._id) !== doc._id) { throw new TypeError("Different Index");
}
db_doc = that._database(that._location[doc._id])._id;
if (db_doc !== doc._id) {
throw new TypeError("Different Index"); throw new TypeError("Different Index");
} }
for (i = 0; i < that._indexing.length; i += 1) { for (i = 0; i < that._indexing.length; i += 1) {
...@@ -442,12 +339,13 @@ ...@@ -442,12 +339,13 @@
var i = 0, meta; var i = 0, meta;
that._free = []; that._free = [];
that._location = {}; that._location = {};
if (type(that._database) !== "Array") { if (!Array.isArray(that._database)) {
that._database = []; that._database = [];
} }
while (i < that._database.length) { while (i < that._database.length) {
meta = that._database[i]; meta = that._database[i];
if (type(meta) === "Object" && if (typeof meta === 'object' &&
Object.getPrototypeOf(meta || []) === Object.prototype &&
typeof meta._id === "string" && meta._id !== "" && typeof meta._id === "string" && meta._id !== "" &&
!that._location[meta._id]) { !that._location[meta._id]) {
that._location[meta._id] = i; that._location[meta._id] = i;
...@@ -461,10 +359,10 @@ ...@@ -461,10 +359,10 @@
/** /**
* Returns the serialized version of this object (not cloned) * Returns the serialized version of this object (not cloned)
* *
* @method serialized * @method toJSON
* @return {Object} The serialized version * @return {Object} The serialized version
*/ */
that.serialized = function () { that.toJSON = function () {
return { return {
"indexing": that._indexing, "indexing": that._indexing,
"free": that._free, "free": that._free,
...@@ -480,46 +378,59 @@ ...@@ -480,46 +378,59 @@
}); });
} }
/**
* The JIO index storage constructor
*/
function indexStorage(spec, my) {
var that, priv = {};
that = my.basicStorage(spec, my);
priv.indices = spec.indices;
priv.sub_storage = spec.sub_storage;
// Overrides
that.specToStore = function () {
return {
"indices": priv.indices,
"sub_storage": priv.sub_storage
};
};
/** /**
* Return the similarity percentage (1 >= p >= 0) between two index lists. * Return the similarity percentage (1 >= p >= 0) between two index lists.
* *
* @method similarityPercentage
* @param {Array} list_a An index list * @param {Array} list_a An index list
* @param {Array} list_b Another index list * @param {Array} list_b Another index list
* @return {Number} The similarity percentage * @return {Number} The similarity percentage
*/ */
priv.similarityPercentage = function (list_a, list_b) { function similarityPercentage(list_a, list_b) {
var ai, bi, count = 0; var ai, bi, count = 0;
for (ai = 0; ai < list_a.length; ai += 1) { for (ai = 0; ai < list_a.length; ai += 1) {
for (bi = 0; bi < list_b.length; bi += 1) { for (bi = 0; bi < list_b.length; bi += 1) {
if (list_a[ai] === list_b[bi]) { if (list_a[ai] === list_b[bi]) {
count += 1; count += 1;
break;
} }
} }
} }
return count / (list_a.length > list_b.length ? return count / (list_a.length > list_b.length ?
list_a.length : list_b.length); list_a.length : list_b.length);
}; }
/**
* The JIO index storage constructor
*
* @class IndexStorage
* @constructor
*/
function IndexStorage(spec) {
var i;
if (!Array.isArray(spec.indices)) {
throw new TypeError("IndexStorage 'indices' must be an array of " +
"objects.");
}
this._indices = spec.indices;
if (typeof spec.sub_storage !== 'object' ||
Object.getPrototypeOf(spec.sub_storage || []) !== Object.prototype) {
throw new TypeError("IndexStorage 'sub_storage' must be a storage " +
"description.");
}
// check indices IDs
for (i = 0; i < this._indices.length; i += 1) {
if (typeof this._indices[i].id !== "string" ||
this._indices[i].id === "") {
throw new TypeError("IndexStorage " +
"'indices[x].id' must be a non empty string");
}
if (!Array.isArray(this._indices[i].index)) {
throw new TypeError("IndexStorage " +
"'indices[x].index' must be a string array");
}
}
this._sub_storage = spec.sub_storage;
}
/** /**
* Select the good index to use according to a select list. * Select the good index to use according to a select list.
...@@ -528,11 +439,10 @@ ...@@ -528,11 +439,10 @@
* @param {Array} select_list An array of strings * @param {Array} select_list An array of strings
* @return {Number} The index index * @return {Number} The index index
*/ */
priv.selectIndex = function (select_list) { IndexStorage.prototype.selectIndex = function (select_list) {
var i, tmp, selector = {"index": 0, "similarity": 0}; var i, tmp, selector = {"index": 0, "similarity": 0};
for (i = 0; i < priv.indices.length; i += 1) { for (i = 0; i < this._indices.length; i += 1) {
tmp = priv.similarityPercentage(select_list, tmp = similarityPercentage(select_list, this._indices[i].index);
priv.indices[i].index);
if (tmp > selector.similarity) { if (tmp > selector.similarity) {
selector.index = i; selector.index = i;
selector.similarity = tmp; selector.similarity = tmp;
...@@ -541,293 +451,233 @@ ...@@ -541,293 +451,233 @@
return selector.index; return selector.index;
}; };
/** IndexStorage.prototype.getIndexDatabase = function (command, index) {
* Get a database index = this._indices[index];
* function makeNewIndex() {
* @method getIndexDatabase return new JSONIndex({
* @param {Object} option The command option "_id": index.id,
* @param {Number} number The location in priv.indices "_attachment": index.attachment || "body",
* @param {Function} callback The callback "indexing": index.index
*/ });
priv.getIndexDatabase = function (option, number, callback) { }
that.addJob( return command.storage(
"getAttachment", index.sub_storage || this._sub_storage
priv.indices[number].sub_storage || priv.sub_storage, ).getAttachment({
{ "_id": index.id,
"_id": priv.indices[number].id, "_attachment": index.attachment || "body"
"_attachment": priv.indices[number].attachment || "body" }).then(function (response) {
}, return jIO.util.readBlobAsText(response.data);
option, }).then(function (e) {
function (response) {
try { try {
response = JSON.parse(response); e = JSON.parse(e.target.result);
response._id = priv.indices[number].id; e._id = index.id;
response._attachment = priv.indices[number].attachment || "body"; e._attachment = index.attachment || "body";
callback(new JSONIndex(response)); } catch (e1) {
} catch (e) { return makeNewIndex();
return that.error(generateErrorObject( }
e.message, return new JSONIndex(e);
"Repair is necessary", }, function (err) {
"corrupt"
));
}
},
function (err) {
if (err.status === 404) { if (err.status === 404) {
callback(new JSONIndex({ return makeNewIndex();
"_id": priv.indices[number].id, // go back to fulfillment channel
"_attachment": priv.indices[number].attachment || "body",
"indexing": priv.indices[number].index
}));
return;
} }
err.message = "Unable to get index database."; throw err;
that.error(err); // propagate err
});
};
IndexStorage.prototype.getIndexDatabases = function (command) {
var i, promises = [];
for (i = 0; i < this._indices.length; i += 1) {
promises[promises.length] = this.getIndexDatabase(command, i);
} }
); return RSVP.all(promises);
}; };
/** IndexStorage.prototype.storeIndexDatabase = function (command, database,
* Gets a list containing all the databases set in the storage description. index) {
* var that = this;
* @method getIndexDatabaseList index = this._indices[index];
* @param {Object} option The command option function putAttachment() {
* @param {Function} callback The result callback(database_list) return command.storage(
*/ index.sub_storage || that._sub_storage
priv.getIndexDatabaseList = function (option, callback) { ).putAttachment({
var i, count = 0, callbacks = {}, response_list = []; "_id": index.id,
callbacks.error = function (index) { "_attachment": index.attachment || "body",
return function (err) { "_data": JSON.stringify(database),
"_content_type": "application/json"
});
}
function createDatabaseAndPutAttachmentIfPossible(err) {
if (err.status === 404) { if (err.status === 404) {
response_list[index] = new JSONIndex({ return command.storage(
"_id": priv.indices[index].id, index.sub_storage || that._sub_storage
"_attachment": priv.indices[index].attachment || "body", ).post({
"indexing": priv.indices[index].index "_id": index.id
// XXX add metadata to document if necessary
}).then(putAttachment, null, function () {
throw null; // stop post progress propagation
}); });
count += 1;
if (count === priv.indices.length) {
callback(response_list);
} }
return; throw err;
} }
err.message = "Unable to get index database."; return putAttachment().
that.error(err); then(null, createDatabaseAndPutAttachmentIfPossible);
}; };
};
callbacks.success = function (index) { IndexStorage.prototype.storeIndexDatabases = function (command, databases) {
return function (response) { var i, promises = [];
try { for (i = 0; i < this._indices.length; i += 1) {
response = JSON.parse(response); if (databases[i] !== undefined) {
response._id = priv.indices[index].id; promises[promises.length] =
response._attachment = priv.indices[index].attachment || "body"; this.storeIndexDatabase(command, databases[i], i);
response_list[index] = new JSONIndex(response);
} catch (e) {
return that.error(generateErrorObject(
e.message,
"Repair is necessary",
"corrupt"
));
}
count += 1;
if (count === priv.indices.length) {
callback(response_list);
} }
};
};
for (i = 0; i < priv.indices.length; i += 1) {
that.addJob(
"getAttachment",
priv.indices[i].sub_storage || priv.sub_storage,
{
"_id": priv.indices[i].id,
"_attachment": priv.indices[i].attachment || "body"
},
option,
callbacks.success(i),
callbacks.error(i)
);
} }
return RSVP.all(promises);
}; };
/** /**
* Saves all the databases to the remote(s). * Generic method for 'post', 'put', 'get' and 'remove'. It delegates the
* command to the sub storage and update the databases.
* *
* @method storeIndexDatabaseList * @method genericCommand
* @param {Array} database_list The database list * @param {String} method The method to use
* @param {Object} command The JIO command
* @param {Object} metadata The metadata to post
* @param {Object} option The command option * @param {Object} option The command option
* @param {Function} callback The result callback(err, response)
*/ */
priv.storeIndexDatabaseList = function (database_list, option, callback) { IndexStorage.prototype.genericCommand = function (method, command,
var i, count = 0, count_max = 0; metadata, option) {
function onAttachmentResponse(response) { var that = this, generic_response;
count += 1; function updateAndStoreIndexDatabases(responses) {
if (count === count_max) { var i, database_list = responses[0];
callback({"ok": true}); generic_response = responses[1];
} if (method === 'get') {
} jIO.util.dictUpdate(metadata, generic_response.data);
function onAttachmentError(err) { }
err.message = "Unable to store index database."; metadata._id = generic_response.id;
that.error(err); if (method === 'remove') {
} for (i = 0; i < database_list.length; i += 1) {
function putAttachment(i) { database_list[i].remove(metadata);
that.addJob(
"putAttachment",
priv.indices[i].sub_storage || priv.sub_storage,
{
"_id": database_list[i]._id,
"_attachment": database_list[i]._attachment,
"_data": JSON.stringify(database_list[i].serialized()),
"_mimetype": "application/json"
},
option,
onAttachmentResponse,
onAttachmentError
);
}
function post(i) {
var doc = priv.indices[i].metadata || {};
doc._id = database_list[i]._id;
that.addJob(
"post", // with id
priv.indices[i].sub_storage || priv.sub_storage,
doc,
option,
function (response) {
putAttachment(i);
},
function (err) {
if (err.status === 409) {
return putAttachment(i);
}
err.message = "Unable to store index database.";
that.error(err);
} }
); } else {
for (i = 0; i < database_list.length; i += 1) {
database_list[i].put(metadata);
} }
for (i = 0; i < priv.indices.length; i += 1) {
if (database_list[i] !== undefined) {
count_max += 1;
post(i);
} }
return that.storeIndexDatabases(command, database_list);
} }
};
/** function allProgress(progress) {
* A generic request method which delegates the request to the sub storage. if (progress.index === 1) {
* On response, it will index the document from the request and update all progress.value.percentage *= 0.7; // 0 to 70%
* the databases. command.notify(progress.value);
*
* @method genericRequest
* @param {Command} command The JIO command
* @param {Function} method The request method
*/
priv.genericRequest = function (command, method) {
var doc = command.cloneDoc(), option = command.cloneOption();
that.addJob(
method,
priv.sub_storage,
doc,
option,
function (response) {
switch (method) {
case "post":
case "put":
case "remove":
doc._id = response.id;
priv.getIndexDatabaseList(option, function (database_list) {
var i;
switch (method) {
case "post":
case "put":
for (i = 0; i < database_list.length; i += 1) {
database_list[i].put(doc);
} }
break; throw null; // stop propagation
case "remove":
for (i = 0; i < database_list.length; i += 1) {
database_list[i].remove(doc);
} }
break;
default: function success() {
break; command.success(generic_response);
}
priv.storeIndexDatabaseList(database_list, option, function () {
that.success({"ok": true, "id": doc._id});
});
});
break;
default:
that.success(response);
break;
} }
},
function (err) { function storeProgress(progress) {
return that.error(err); progress.percentage = (0.3 * progress.percentage) + 70; // 70 to 100%
command.notify(progress);
} }
);
RSVP.all([
this.getIndexDatabases(command),
command.storage(this._sub_storage)[method](metadata, option)
]).then(updateAndStoreIndexDatabases, null, allProgress).
then(success, command.error, storeProgress);
}; };
/** /**
* Post the document metadata and update the index * Post the document metadata and update the index
*
* @method post * @method post
* @param {object} command The JIO command * @param {Object} command The JIO command
* @param {Object} metadata The metadata to post
* @param {Object} option The command option
*/ */
that.post = function (command) { IndexStorage.prototype.post = function (command, metadata, option) {
priv.genericRequest(command, 'post'); this.genericCommand('post', command, metadata, option);
}; };
/** /**
* Update the document metadata and update the index * Update the document metadata and update the index
*
* @method put * @method put
* @param {object} command The JIO command * @param {Object} command The JIO command
* @param {Object} metadata The metadata to put
* @param {Object} option The command option
*/ */
that.put = function (command) { IndexStorage.prototype.put = function (command, metadata, option) {
priv.genericRequest(command, 'put'); this.genericCommand('put', command, metadata, option);
}; };
/** /**
* Add an attachment to a document (no index modification) * Add an attachment to a document (no index modification)
*
* @method putAttachment * @method putAttachment
* @param {object} command The JIO command * @param {Object} command The JIO command
* @param {Object} param The command parameters
* @param {Object} option The command option
*/ */
that.putAttachment = function (command) { IndexStorage.prototype.putAttachment = function (command, param, option) {
priv.genericRequest(command, 'putAttachment'); command.storage(this._sub_storage).putAttachment(param, option).
then(command.success, command.error, command.notify);
}; };
/** /**
* Get the document metadata * Get the document metadata
*
* @method get * @method get
* @param {object} command The JIO command * @param {Object} command The JIO command
* @param {Object} param The command parameters
* @param {Object} option The command option
*/ */
that.get = function (command) { IndexStorage.prototype.get = function (command, param, option) {
priv.genericRequest(command, 'get'); this.genericCommand('get', command, param, option);
}; };
/** /**
* Get the attachment. * Get the attachment.
*
* @method getAttachment * @method getAttachment
* @param {object} command The JIO command * @param {Object} command The JIO command
* @param {Object} param The command parameters
* @param {Object} option The command option
*/ */
that.getAttachment = function (command) { IndexStorage.prototype.getAttachment = function (command, param, option) {
priv.genericRequest(command, 'getAttachment'); command.storage(this._sub_storage).getAttachment(param, option).
then(command.success, command.error, command.notify);
}; };
/** /**
* Remove document - removing documents updates index!. * Remove document - removing documents updates index!.
*
* @method remove * @method remove
* @param {object} command The JIO command * @param {Object} command The JIO command
* @param {Object} param The command parameters
* @param {Object} option The command option
*/ */
that.remove = function (command) { IndexStorage.prototype.remove = function (command, param, option) {
priv.genericRequest(command, 'remove'); this.genericCommand('remove', command, param, option);
}; };
/** /**
* Remove attachment * Remove attachment
*
* @method removeAttachment * @method removeAttachment
* @param {object} command The JIO command * @param {Object} command The JIO command
* @param {Object} param The command parameters
* @param {Object} option The command option
*/ */
that.removeAttachment = function (command) { IndexStorage.prototype.removeAttachment = function (command, param, option) {
priv.genericRequest(command, 'removeAttachment'); command.storage(this._sub_storage).removeAttachment(param, option).
then(command.success, command.error, command.notify);
}; };
/** /**
...@@ -837,146 +687,172 @@ ...@@ -837,146 +687,172 @@
* @method allDocs * @method allDocs
* @param {object} command The JIO command * @param {object} command The JIO command
*/ */
that.allDocs = function (command) { IndexStorage.prototype.allDocs = function (command, param, option) { // XXX
var option = command.cloneOption(), /*jslint unparam: true */
index = priv.selectIndex(option.select_list || []); var index = this.selectIndex(option.select_list || []), delete_id;
// Include docs option is ignored, if you want to get all the document, // Include docs option is ignored, if you want to get all the document,
// don't use index storage! // don't use index storage!
option.select_list = option.select_list || []; option.select_list = (
Array.isArray(option.select_list) ? option.select_list : []
);
if (option.select_list.indexOf("_id") === -1) {
option.select_list.push("_id"); option.select_list.push("_id");
priv.getIndexDatabase(option, index, function (db) { delete_id = true;
}
this.getIndexDatabase(command, index).then(function (db) {
var i, id; var i, id;
db = db._database; db = db._database;
complex_queries.QueryFactory.create(option.query || ''). complex_queries.QueryFactory.create(option.query || '').
exec(db, option); exec(db, option);
for (i = 0; i < db.length; i += 1) { for (i = 0; i < db.length; i += 1) {
id = db[i]._id; id = db[i]._id;
if (delete_id) {
delete db[i]._id; delete db[i]._id;
}
db[i] = { db[i] = {
"id": id, "id": id,
"key": id, "value": db[i]
"value": db[i],
};
}
that.success({"total_rows": db.length, "rows": db});
});
}; };
that.check = function (command) {
that.repair(command, true);
};
priv.repairIndexDatabase = function (command, index, just_check) {
var i, option = command.cloneOption();
that.addJob(
'allDocs',
priv.sub_storage,
{},
{'include_docs': true},
function (response) {
var db_list = [], db = new JSONIndex({
"_id": command.getDocId(),
"_attachment": priv.indices[index].attachment || "body",
"indexing": priv.indices[index].index
});
for (i = 0; i < response.rows.length; i += 1) {
db.put(response.rows[i].doc);
}
db_list[index] = db;
if (just_check) {
priv.getIndexDatabase(option, index, function (current_db) {
if (db.equals(current_db)) {
return that.success({"ok": true, "id": command.getDocId()});
}
return that.error(generateErrorObject(
"Different Index",
"Check failed",
"corrupt index database"
));
});
} else {
priv.storeIndexDatabaseList(db_list, {}, function () {
that.success({"ok": true, "id": command.getDocId()});
});
}
},
function (err) {
err.message = "Unable to repair the index database";
that.error(err);
} }
); command.success(200, {"data": {"total_rows": db.length, "rows": db}});
}; }, function (err) {
if (err.status === 404) {
priv.repairDocument = function (command, just_check) { return command.success(200, {"data": {"total_rows": 0, "rows": []}});
var i, option = command.cloneOption();
that.addJob(
"get",
priv.sub_storage,
command.cloneDoc(),
{},
function (response) {
response._id = command.getDocId();
priv.getIndexDatabaseList(option, function (database_list) {
if (just_check) {
for (i = 0; i < database_list.length; i += 1) {
try {
database_list[i].checkDocument(response);
} catch (e) {
return that.error(generateErrorObject(
e.message,
"Check failed",
"corrupt index database"
));
}
}
that.success({"_id": command.getDocId(), "ok": true});
} else {
for (i = 0; i < database_list.length; i += 1) {
database_list[i].put(response);
}
priv.storeIndexDatabaseList(database_list, option, function () {
that.success({"ok": true, "id": command.getDocId()});
});
} }
command.error(err);
}); });
},
function (err) {
err.message = "Unable to repair document";
return that.error(err);
}
);
}; };
that.repair = function (command, just_check) { // IndexStorage.prototype.check = function (command, param, option) { // XXX
var database_index = -1, i; // this.repair(command, true, param, option);
for (i = 0; i < priv.indices.length; i += 1) { // };
if (priv.indices[i].id === command.getDocId()) {
database_index = i; // IndexStorage.prototype.repairIndexDatabase = function (
break; // command,
} // index,
} // just_check,
that.addJob( // param,
"repair", // option
priv.sub_storage, // ) { // XXX
command.cloneDoc(), // var i, that = this;
command.cloneOption(), // command.storage(this._sub_storage).allDocs({'include_docs': true}).then(
function (response) { // function (response) {
if (database_index !== -1) { // var db_list = [], db = new JSONIndex({
priv.repairIndexDatabase(command, database_index, just_check); // "_id": param._id,
} else { // "_attachment": that._indices[index].attachment || "body",
priv.repairDocument(command, just_check); // "indexing": that._indices[index].index
} // });
}, // for (i = 0; i < response.rows.length; i += 1) {
function (err) { // db.put(response.rows[i].doc);
err.message = "Could not repair sub storage"; // }
that.error(err); // db_list[index] = db;
} // if (just_check) {
); // this.getIndexDatabase(command, option, index, function (current_db) {
// if (db.equals(current_db)) {
// return command.success({"ok": true, "id": param._id});
// }
// return command.error(
// "conflict",
// "corrupted",
// "Database is not up to date"
// );
// });
// } else {
// that.storeIndexDatabaseList(command, db_list, {}, function () {
// command.success({"ok": true, "id": param._id});
// });
// }
// },
// function (err) {
// err.message = "Unable to repair the index database";
// command.error(err);
// }
// );
// };
// IndexStorage.prototype.repairDocument = function (
// command,
// just_check,
// param,
// option
// ) { // XXX
// var i, that = this;
// command.storage(this._sub_storage).get(param, {}).then(
// function (response) {
// response._id = param._id;
// that.getIndexDatabaseList(command, option, function (database_list) {
// if (just_check) {
// for (i = 0; i < database_list.length; i += 1) {
// try {
// database_list[i].checkDocument(response);
// } catch (e) {
// return command.error(
// "conflict",
// e.message,
// "Corrupt index database"
// );
// }
// }
// command.success({"_id": param._id, "ok": true});
// } else {
// for (i = 0; i < database_list.length; i += 1) {
// database_list[i].put(response);
// }
// that.storeIndexDatabaseList(
// command,
// database_list,
// option,
// function () {
// command.success({"ok": true, "id": param._id});
// }
// );
// }
// });
// },
// function (err) {
// err.message = "Unable to repair document";
// return command.error(err);
// }
// );
// };
// IndexStorage.prototype.repair = function (command, just_check, param,
// option) { // XXX
// var database_index = -1, i, that = this;
// for (i = 0; i < this._indices.length; i += 1) {
// if (this._indices[i].id === param._id) {
// database_index = i;
// break;
// }
// }
// command.storage(this._sub_storage).repair(param, option).then(
// function () {
// if (database_index !== -1) {
// that.repairIndexDatabase(
// command,
// database_index,
// just_check,
// param,
// option
// );
// } else {
// that.repairDocument(command, just_check, param, option);
// }
// },
// function (err) {
// err.message = "Could not repair sub storage";
// command.error(err);
// }
// );
// };
jIO.addStorage("indexed", IndexStorage);
exports.createDescription = function () {
// XXX
return;
}; };
return that;
}
jIO.addStorageType("indexed", indexStorage);
})); }));
/*jslint indent: 2, maxlen: 80, nomen: true */ /*jslint indent: 2, maxlen: 80, nomen: true */
/*global define, jIO, jio_tests, test, ok, deepEqual, sinon */ /*global define, module, test_util, RSVP, jIO, local_storage, test, ok,
deepEqual, stop, start */
// define([module_name], [dependencies], module); // define([module_name], [dependencies], module);
(function (dependencies, module) { (function (dependencies, module) {
...@@ -7,1108 +8,621 @@ ...@@ -7,1108 +8,621 @@
if (typeof define === 'function' && define.amd) { if (typeof define === 'function' && define.amd) {
return define(dependencies, module); return define(dependencies, module);
} }
module(jIO, jio_tests); module(test_util, RSVP, jIO, local_storage);
}(['jio', 'jio_tests', 'localstorage', 'indexstorage'], function (jIO, util) { }([
'test_util',
'rsvp',
'jio',
'localstorage',
'indexstorage'
], function (util, RSVP, jIO, local_storage) {
"use strict"; "use strict";
function generateTools() { function success(promise) {
return { return new RSVP.Promise(function (resolve, reject, notify) {
clock: sinon.useFakeTimers(), /*jslint unparam: true*/
spy: util.ospy, promise.then(resolve, resolve, notify);
tick: util.otick }, function () {
}; promise.cancel();
});
} }
module("IndexStorage"); /**
* sequence(thens): Promise
test("Post", function () { *
* Executes a sequence of *then* callbacks. It acts like
var o = generateTools(); * `smth().then(callback).then(callback)...`. The first callback is called
* with no parameter.
o.jio = jIO.newJio({ *
"type": "indexed", * Elements of `thens` array can be a function or an array contaning at most
"indices": [ * three *then* callbacks: *onFulfilled*, *onRejected*, *onNotified*.
{"id": "A", "index": ["title"]}, *
{"id": "B", "index": ["title", "year"]} * When `cancel()` is executed, each then promises are cancelled at the same
], * time.
"sub_storage": { *
"type": "local", * @param {Array} thens An array of *then* callbacks
"username": "ipost", * @return {Promise} A new promise
"application_name": "ipost" */
} function sequence(thens) {
var promises = [];
return new RSVP.Promise(function (resolve, reject, notify) {
var i;
promises[0] = new RSVP.Promise(function (resolve) {
resolve();
}); });
for (i = 0; i < thens.length; i += 1) {
o.getAttachmentCallback = function (err, response) { if (Array.isArray(thens[i])) {
if (response) { promises[i + 1] = promises[i].
try { then(thens[i][0], thens[i][1], thens[i][2]);
response = JSON.parse(response); } else {
} catch (e) { promises[i + 1] = promises[i].then(thens[i]);
response = "PARSE ERROR " + response;
} }
} }
o.f(err, response); promises[i].then(resolve, reject, notify);
}; }, function () {
var i;
// post without id for (i = 0; i < promises.length; i += 1) {
o.spy(o, "jobstatus", "done", "Post without id"); promises[i].cancel();
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 module("IndexStorage");
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 () { test("Scenario", function () {
var o = generateTools(), i;
o.jio = jIO.newJio({ var LOCAL_STORAGE_SPEC = local_storage.createDescription(
'indexstorage tests',
'scenario',
'memory'
), INDEX_STORAGE_SPEC = {
"type": "indexed", "type": "indexed",
"indices": [ "indices": [
{"id": "A", "index": ["director"]}, {"id": "A", "index": ["contributor"]},
{"id": "B", "index": ["year"]} {"id": "B", "index": ["author"]},
{"id": "C", "index": ["title"]},
{"id": "D", "index": ["title", "year"]}
], ],
"sub_storage": { "sub_storage": LOCAL_STORAGE_SPEC
"type": "local", }, option = {"workspace": {}}, shared = {}, jio_index, jio_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 = { jio_index = jIO.createJIO(INDEX_STORAGE_SPEC, option);
"indexing": ["director"], jio_local = jIO.createJIO(LOCAL_STORAGE_SPEC, option);
"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; function postNewDocument() {
o.fakeIndexA.database[o.tmp] = {"_id": "id" + i, "director": "D" + i}; return jio_index.post({"title": "Unique ID"});
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({ function postNewDocumentTest(answer) {
"type": "indexed", var uuid = answer.id;
"indices": [ answer.id = "<uuid>";
{"id": "A", "index": ["author"]}, deepEqual(answer, {
{"id": "B", "index": ["year"]} "id": "<uuid>",
], "method": "post",
"sub_storage": { "result": "success",
"type": "local", "status": 201,
"username": "iputatt", "statusText": "Created"
"application_name": "iputatt" }, "Post a new document");
ok(util.isUuid(uuid), "New document id should look like " +
"xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx : " + uuid);
shared.created_document_id = uuid;
} }
});
// 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 function getCreatedDocument() {
o.doc = {"_id": "putattmt1", "title": "myPutAttmt1"}; return jio_index.get({"_id": shared.created_document_id});
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 function getCreatedDocumentTest(answer) {
deepEqual(util.jsonlocalstorage.getItem( deepEqual(answer, {
"jio/localstorage/iputatt/iputatt/putattmt1/putattmt2" "data": {
), "", "Check attachment"); "_id": shared.created_document_id,
"title": "Unique ID"
// update attachment },
o.spy(o, "value", "id": shared.created_document_id,
{"ok": true, "id": "putattmt1", "attachment": "putattmt2"}, "method": "get",
"Update Attachment, with data"); "result": "success",
o.jio.putAttachment({ "status": 200,
"_id": "putattmt1", "statusText": "Ok"
"_attachment": "putattmt2", }, "Get new document");
"_data": "abc" }
}, o.f);
o.tick(o); // function postSpecificDocuments() {
// return success(RSVP.all([
// check document // jio_index.post({"_id": "b", "title": "Bee", "year": 2013}),
deepEqual(util.jsonlocalstorage.getItem( // jio_index.post({"_id": "ce", "contributor": "DCee"}),
"jio/localstorage/iputatt/iputatt/putattmt1" // jio_index.post({"_id": "dee", "format": "text/plain"})
), { // ]));
"_id": "putattmt1", // }
"title": "myPutAttmt1",
"_attachments": { // function postSpecificDocumentsTest(answers) {
"putattmt2": { // deepEqual(answers[0], {
"length": 3, // "id": "b",
// md5("abc") // "method": "post",
"digest": "md5-900150983cd24fb0d6963f7d28e17f72" // "result": "success",
// "status": 201,
// "statusText": "Created"
// }, "Post specific document 'b'");
// deepEqual(answers[1], {
// "id": "ce",
// "method": "post",
// "result": "success",
// "status": 201,
// "statusText": "Created"
// }, "Post specific document 'ce'");
// deepEqual(answers[2], {
// "id": "dee",
// "method": "post",
// "result": "success",
// "status": 201,
// "statusText": "Created"
// }, "Post specific document 'dee'");
// }
// XXX the 2 following functions should be replaced by the 2 commented
// previous ones (which don't work yet)
function postSpecificDocuments() {
return sequence([function () {
return jio_index.post({"_id": "b", "title": "Bee", "year": 2013});
}, function () {
return jio_index.post({"_id": "ce", "contributor": "DCee"});
}, function () {
return jio_index.post({"_id": "dee", "format": "text/plain"});
}]);
}
function postSpecificDocumentsTest(last_answer) {
deepEqual(last_answer, {
"id": "dee",
"method": "post",
"result": "success",
"status": 201,
"statusText": "Created"
}, "Post documents: 'b', 'ce', 'dee' (testing 'dee' response only)");
}
function listDocumentsFromIndexContributor() {
return jio_index.allDocs({"select_list": ["contributor"]});
}
function listDocumentsFromIndexContributorTest(answer) {
if (answer && answer.data && Array.isArray(answer.data.rows)) {
answer.data.rows.sort(function (a, b) {
return a.id.length < b.id.length ? -1 : (
a.id.length > b.id.length ? 1 : 0
);
});
} }
deepEqual(answer, {
"data": {
"total_rows": 1,
"rows": [{
"id": "ce",
"value": {"contributor": "DCee"}
}]
},
"method": "allDocs",
"result": "success",
"status": 200,
"statusText": "Ok"
}, "List 1 document from 'contributor'");
} }
}, "Check document");
// check attachment
deepEqual(util.jsonlocalstorage.getItem(
"jio/localstorage/iputatt/iputatt/putattmt1/putattmt2"
), "abc", "Check attachment");
util.closeAndcleanUpJio(o.jio);
});
test("Get", function () { function listDocumentsFromIndexTitleYear() {
return jio_index.allDocs({"select_list": ["year", "title"]});
// 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 function listDocumentsFromIndexTitleYearTest(answer) {
o.spy(o, "status", 404, "Get inexistent document"); if (answer && answer.data && Array.isArray(answer.data.rows)) {
o.jio.get({"_id": "get1"}, o.f); answer.data.rows.sort(function (a, b) {
o.tick(o); return a.id.length < b.id.length ? -1 : (
a.id.length > b.id.length ? 1 : 0
// 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;
} }
deepEqual(answer, {
"data": {
"total_rows": 2,
"rows": [{
"id": "b",
"value": {"title": "Bee", "year": 2013}
}, {
"id": shared.created_document_id,
"value": {"title": "Unique ID"}
}]
},
"method": "allDocs",
"result": "success",
"status": 200,
"statusText": "Ok"
}, "List 2 documents from 'year' and 'title'");
} }
o.f(err, response);
};
// remove inexistent document function listDocumentsFromIndexTitle() {
o.spy(o, "status", 404, "Remove inexistent document"); return jio_index.allDocs({"select_list": ["title"]});
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 function listDocumentsFromIndexTitleTest(answer) {
o.jio.put({"_id": "removeAlso", "title": "myRemove2", if (answer && answer.data && Array.isArray(answer.data.rows)) {
"author": "Martin Mustermann", "year": "2525" answer.data.rows.sort(function (a, b) {
return a.id.length < b.id.length ? -1 : (
a.id.length > b.id.length ? 1 : 0
);
}); });
o.tick(o); }
deepEqual(answer, {
// remove document "data": {
o.spy(o, "value", {"ok": true, "id": "remove1"}, "Remove document"); "total_rows": 2,
o.jio.remove({"_id": "remove1"}, o.f); "rows": [{
o.tick(o); "id": "b",
"value": {"title": "Bee"}
// check index }, {
o.fakeIndexA = { "id": shared.created_document_id,
"indexing": ["author"], "value": {"title": "Unique ID"}
"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"}] "method": "allDocs",
}; "result": "success",
o.spy(o, "value", o.fakeIndexB, "Check index file"); "status": 200,
o.jio.getAttachment({ "statusText": "Ok"
"_id": "B", }, "List 2 documents from 'title'");
"_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) { function listDocumentsFromIndexAuthor() {
if (response) { return jio_index.allDocs({"select_list": ["author"]});
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({ function listDocumentsFromIndexAuthorTest(answer) {
"type": "indexed", if (answer && answer.data && Array.isArray(answer.data.rows)) {
"indices": [ answer.data.rows.sort(function (a, b) {
{"id": "A", "index": ["director"]}, return a.id.length < b.id.length ? -1 : (
{"id": "B", "index": ["title", "year"]} a.id.length > b.id.length ? 1 : 0
], );
"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;
} }
deepEqual(answer, {
"data": {
"total_rows": 0,
"rows": []
},
"method": "allDocs",
"result": "success",
"status": 200,
"statusText": "Ok"
}, "List 0 document from 'author'");
} }
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; function listDocumentsFromNothing() {
o.fakeIndexA.database[o.tmp] = { return jio_index.allDocs();
"_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"); function listDocumentsFromNothingTest(answer) {
o.jio.getAttachment({ if (answer && answer.data && Array.isArray(answer.data.rows)) {
"_id": "B", answer.data.rows.sort(function (a, b) {
"_attachment": "body" return a.id.length < b.id.length ? -1 : (
}, o.getAttachmentCallback); a.id.length > b.id.length ? 1 : 0
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]
}
}); });
} }
deepEqual(answer, {
o.response = JSON.parse(JSON.stringify(o.allDocsResponse)); "data": {
for (i = 0; i < o.response.rows.length; i += 1) { "total_rows": 1,
delete o.response.rows[i].doc; "rows": [{
"id": "ce",
"value": {}
}]
},
"method": "allDocs",
"result": "success",
"status": 200,
"statusText": "Ok"
}, "List 1 document from first index (`allDocs()`)");
} }
// alldocs function listDocumentsFromLocal() {
o.spy(o, "value", o.response, "AllDocs response generated from index"); return jio_local.allDocs();
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 function listDocumentsFromLocalTest(answer) {
o.spy(o, "value", {"total_rows": 0, "rows": []}, if (answer && answer.data && Array.isArray(answer.data.rows)) {
"allDocs (complex queries year >= 1980, can't use index)"); answer.data.rows.sort(function (a, b) {
o.jio.allDocs({ return a.id.length < b.id.length ? -1 : (
// "query":'(year: >= "1980" AND year: < "2000")', a.id.length > b.id.length ? 1 : (
"query": '(year: >= "1980")', a.id < b.id ? -1 : a.id > b.id ? 1 : 0
"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)"); deepEqual(answer, {
o.jio.allDocs({ "data": {
"sort_on": [['title', 'descending']], "total_rows": 8,
"select_list": ['title'] "rows": [{
}, o.f); "id": "A",
o.tick(o); "key": "A",
"value": {}
}, {
"id": "B",
"key": "B",
"value": {}
}, {
"id": "C",
"key": "C",
"value": {}
}, {
"id": "D",
"key": "D",
"value": {}
}, {
"id": "b",
"key": "b",
"value": {}
}, {
"id": "ce",
"key": "ce",
"value": {}
}, {
"id": "dee",
"key": "dee",
"value": {}
}, {
"id": shared.created_document_id,
"key": shared.created_document_id,
"value": {}
}]
},
"method": "allDocs",
"result": "success",
"status": 200,
"statusText": "Ok"
}, "List 8 documents from local (4 document + 4 databases)");
}
// function removeCreatedDocuments() {
// return success(RSVP.all([
// jio_index.remove({"_id": shared.created_document_id}),
// jio_index.remove({"_id": "b"}),
// jio_index.remove({"_id": "ce"}),
// jio_index.remove({"_id": "dee"})
// ]));
// }
// function removeCreatedDocumentsTest(answers) {
// deepEqual(answers[0], {
// "id": shared.created_document_id,
// "method": "remove",
// "result": "success",
// "status": 204,
// "statusText": "No Content"
// }, "Remove first document");
// deepEqual(answers[1], {
// "id": "b",
// "method": "remove",
// "result": "success",
// "status": 204,
// "statusText": "No Content"
// }, "Remove document 'b'");
// deepEqual(answers[2], {
// "id": "ce",
// "method": "remove",
// "result": "success",
// "status": 204,
// "statusText": "No Content"
// }, "Remove document 'ce'");
// deepEqual(answers[3], {
// "id": "dee",
// "method": "remove",
// "result": "success",
// "status": 204,
// "statusText": "No Content"
// }, "Remove document 'dee'");
// }
// XXX the 2 following functions should be replaced by the 2 commented
// previous ones (which don't work yet)
function removeCreatedDocuments() {
return sequence([function () {
return jio_index.remove({"_id": shared.created_document_id});
}, function () {
return jio_index.remove({"_id": "b"});
}, function () {
return jio_index.remove({"_id": "ce"});
}, function () {
return jio_index.remove({"_id": "dee"});
}]);
}
function removeCreatedDocumentsTest(last_answer) {
deepEqual(last_answer, {
"id": "dee",
"method": "remove",
"result": "success",
"status": 204,
"statusText": "No Content"
}, "Remove first document, 'b', 'ce' and 'dee' (testing 'dee' only)");
}
function listEmptyIndexes() {
return RSVP.all([
success(jio_index.allDocs({"select_list": ["contributor"]})),
success(jio_index.allDocs({"select_list": ["title"]})),
success(jio_index.allDocs({"select_list": ["title", "year"]})),
success(jio_index.allDocs({"select_list": ["author"]})),
success(jio_index.allDocs())
]);
}
function listEmptyIndexesTest(answers) {
deepEqual(answers[0], {
"data": {
"total_rows": 7000,
"rows": []
},
"method": "allDocs",
"result": "success",
"status": 200,
"statusText": "Ok"
}, "List empty indexes 'contributor'");
deepEqual(answers[1], {
"data": {
"total_rows": 7000,
"rows": []
},
"method": "allDocs",
"result": "success",
"status": 204,
"statusText": "No Content"
}, "List empty indexes 'title'");
deepEqual(answers[2], {
"data": {
"total_rows": 7000,
"rows": []
},
"method": "allDocs",
"result": "success",
"status": 204,
"statusText": "No Content"
}, "List empty indexes 'title', 'year'");
deepEqual(answers[3], {
"data": {
"total_rows": 7000,
"rows": []
},
"method": "allDocs",
"result": "success",
"status": 204,
"statusText": "No Content"
}, "List empty indexes 'author'");
deepEqual(answers[4], {
"data": {
"total_rows": 7000,
"rows": []
},
"method": "allDocs",
"result": "success",
"status": 204,
"statusText": "No Content"
}, "List default empty indexes");
}
// // XXX the 2 following functions should be replaced by the 2 commented
// // previous ones (which don't work yet)
// function removeCreatedDocuments() {
// return sequence([function () {
// return jio_index.remove({"_id": shared.created_document_id});
// }, function () {
// return jio_index.remove({"_id": "b"});
// }, function () {
// return jio_index.remove({"_id": "ce"});
// }, function () {
// return jio_index.remove({"_id": "dee"});
// }]);
// }
// function removeCreatedDocumentsTest(last_answer) {
// deepEqual(last_answer, {
// "id": "dee",
// "method": "remove",
// "result": "success",
// "status": 204,
// "statusText": "No Content"
// }, "Remove first document, 'b', 'ce' and 'dee' (testing 'dee' only)");
// }
function unexpectedError(error) {
if (error instanceof Error) {
deepEqual([
error.name + ": " + error.message,
error
], "UNEXPECTED ERROR", "Unexpected error");
} else {
deepEqual(error, "UNEXPECTED ERROR", "Unexpected error");
}
}
stop();
// # Post new documents, list them and remove them
// post a 201
postNewDocument().then(postNewDocumentTest).
// get 200
then(getCreatedDocument).then(getCreatedDocumentTest).
// post b ce dee 201
then(postSpecificDocuments).then(postSpecificDocumentsTest).
// allD 200 1 documents from index contributor
then(listDocumentsFromIndexContributor).
then(listDocumentsFromIndexContributorTest).
// allD 200 2 documents from index title
then(listDocumentsFromIndexTitle).
then(listDocumentsFromIndexTitleTest).
// allD 200 2 documents from index title year
then(listDocumentsFromIndexTitleYear).
then(listDocumentsFromIndexTitleYearTest).
// allD 200 0 documents from index author
then(listDocumentsFromIndexAuthor).
then(listDocumentsFromIndexAuthorTest).
// allD 200 0 documents from nothing (no select_list option)
then(listDocumentsFromNothing).
then(listDocumentsFromNothingTest).
// allD 200 8 documents from local
then(listDocumentsFromLocal).then(listDocumentsFromLocalTest).
// remove a b ce dee 204
then(removeCreatedDocuments).then(removeCreatedDocumentsTest).
// allD 200 empty indexes
then(listEmptyIndexes).then(listEmptyIndexesTest).
// // # Create and update documents, and some attachment and remove them
// // put 201
// then(putNewDocument).then(putNewDocumentTest).
// // get 200
// then(getCreatedDocument2).then(getCreatedDocument2Test).
// // post 409
// then(postSameDocument).then(postSameDocumentTest).
// // putA a 204
// then(createAttachment).then(createAttachmentTest).
// // putA a 204
// then(updateAttachment).then(updateAttachmentTest).
// // putA b 204
// then(createAnotherAttachment).then(createAnotherAttachmentTest).
// // put 204
// then(updateLastDocument).then(updateLastDocumentTest).
// // getA a 200
// then(getFirstAttachment).then(getFirstAttachmentTest).
// // getA b 200
// then(getSecondAttachment).then(getSecondAttachmentTest).
// // get 200
// then(getLastDocument).then(getLastDocumentTest).
// // removeA b 204
// then(removeSecondAttachment).then(removeSecondAttachmentTest).
// // getA b 404
// then(getInexistentSecondAttachment).
// then(getInexistentSecondAttachmentTest).
// // get 200
// then(getOneAttachmentDocument).then(getOneAttachmentDocumentTest).
// // removeA b 404
//then(removeSecondAttachmentAgain).then(removeSecondAttachmentAgainTest).
// // remove 204
// then(removeDocument).then(removeDocumentTest).
// // getA a 404
//then(getInexistentFirstAttachment)
//.then(getInexistentFirstAttachmentTest).
// // get 404
// then(getInexistentDocument).then(getInexistentDocumentTest).
// // remove 404
// then(removeInexistentDocument).then(removeInexistentDocumentTest).
// // check 204
// //then(checkDocument).done(checkDocumentTest).
// //then(checkStorage).done(checkStorageTest).
fail(unexpectedError).
always(start);
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